diff --git a/app/javascript/wardrobe-2020/WardrobePage/ItemsPanel.js b/app/javascript/wardrobe-2020/WardrobePage/ItemsPanel.js index e2b3c385..6da13cf3 100644 --- a/app/javascript/wardrobe-2020/WardrobePage/ItemsPanel.js +++ b/app/javascript/wardrobe-2020/WardrobePage/ItemsPanel.js @@ -36,19 +36,13 @@ import { } from "@chakra-ui/icons"; import { CSSTransition, TransitionGroup } from "react-transition-group"; -import { - Delay, - ErrorMessage, - getGraphQLErrorMessage, - Heading1, - Heading2, -} from "../util"; +import { Delay, ErrorMessage, Heading1, Heading2 } from "../util"; import Item, { ItemListContainer, ItemListSkeleton } from "./Item"; import { BiRename } from "react-icons/bi"; import { IoCloudUploadOutline } from "react-icons/io5"; import { MdMoreVert } from "react-icons/md"; import { buildOutfitUrl } from "./useOutfitState"; -import { gql, useMutation } from "@apollo/client"; +import { useDeleteOutfitMutation } from "../loaders/outfits"; /** * ItemsPanel shows the items in the current outfit, and lets the user toggle @@ -455,25 +449,7 @@ function DeleteOutfitMenuItem({ outfitState }) { const { id, name } = outfitState; const { isOpen, onOpen, onClose } = useDisclosure(); - const [sendDeleteOutfitMutation, { loading, error }] = useMutation( - gql` - mutation DeleteOutfitMenuItem($id: ID!) { - deleteOutfit(id: $id) - } - `, - { - context: { sendAuth: true }, - update(cache) { - // Once this is deleted, evict it from the local cache, and "garbage - // collect" to force all queries referencing this outfit to reload the - // next time we see them. (This is especially important since we're - // about to redirect to the user outfits page, which shouldn't show - // the outfit anymore!) - cache.evict(`Outfit:${id}`); - cache.gc(); - }, - }, - ); + const { status, error, mutateAsync } = useDeleteOutfitMutation(); return ( <> @@ -489,10 +465,9 @@ function DeleteOutfitMenuItem({ outfitState }) { We'll delete this data and remove it from your list of outfits. Links and image embeds pointing to this outfit will break. Is that okay? - {error && ( + {status === "error" && ( - Error deleting outfit: "{getGraphQLErrorMessage(error)}". Try - again? + Error deleting outfit: "{error.message}". Try again? )} @@ -502,7 +477,7 @@ function DeleteOutfitMenuItem({ outfitState }) { diff --git a/app/javascript/wardrobe-2020/WardrobePage/useOutfitSaving.js b/app/javascript/wardrobe-2020/WardrobePage/useOutfitSaving.js index 9ceb5551..f0ae2c71 100644 --- a/app/javascript/wardrobe-2020/WardrobePage/useOutfitSaving.js +++ b/app/javascript/wardrobe-2020/WardrobePage/useOutfitSaving.js @@ -3,8 +3,6 @@ import { useToast } from "@chakra-ui/react"; import { useLocation, useNavigate } from "react-router-dom"; import { useDebounce } from "../util"; import useCurrentUser from "../components/useCurrentUser"; -import gql from "graphql-tag"; -import { useMutation } from "@apollo/client"; import { outfitStatesAreEqual } from "./useOutfitState"; import { useSaveOutfitMutation } from "../loaders/outfits"; diff --git a/app/javascript/wardrobe-2020/loaders/outfits.js b/app/javascript/wardrobe-2020/loaders/outfits.js index 09a111c9..ac73ab6c 100644 --- a/app/javascript/wardrobe-2020/loaders/outfits.js +++ b/app/javascript/wardrobe-2020/loaders/outfits.js @@ -8,7 +8,7 @@ export function useSavedOutfit(id, options) { }); } -export function useSaveOutfitMutation(options) { +export function useSaveOutfitMutation(options = {}) { const queryClient = useQueryClient(); return useMutation({ @@ -16,7 +16,24 @@ export function useSaveOutfitMutation(options) { mutationFn: saveOutfit, onSuccess: (outfit) => { queryClient.setQueryData(["outfits", outfit.id], outfit); - options.onSuccess(outfit); + if (options.onSuccess) { + options.onSuccess(outfit); + } + }, + }); +} + +export function useDeleteOutfitMutation(options = {}) { + const queryClient = useQueryClient(); + + return useMutation({ + ...options, + mutationFn: deleteOutfit, + onSuccess: (emptyData, id, context) => { + queryClient.invalidateQueries({ queryKey: ["outfits", String(id)] }); + if (options.onSuccess) { + options.onSuccess(emptyData, id, context); + } }, }); } @@ -80,6 +97,19 @@ async function saveOutfit({ return res.json().then(normalizeOutfit); } +async function deleteOutfit(id) { + const res = await fetch(`/outfits/${encodeURIComponent(id)}.json`, { + method: "DELETE", + headers: { + "X-CSRF-Token": getCSRFToken(), + }, + }); + + if (!res.ok) { + throw new Error(`deleting outfit failed: ${res.status} ${res.statusText}`); + } +} + function normalizeOutfit(outfit) { return { id: String(outfit.id),