impress/app/javascript/wardrobe-2020/loaders/outfits.js

139 lines
3.2 KiB
JavaScript
Raw Permalink Normal View History

import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
export function useSavedOutfit(id, options = {}) {
return useQuery({
...options,
queryKey: ["outfits", String(id)],
queryFn: () => loadSavedOutfit(id),
});
}
export function useSaveOutfitMutation(options = {}) {
const queryClient = useQueryClient();
return useMutation({
...options,
mutationFn: saveOutfit,
onSuccess: (outfit) => {
queryClient.setQueryData(["outfits", outfit.id], 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);
}
},
});
}
async function loadSavedOutfit(id) {
const res = await fetch(`/outfits/${encodeURIComponent(id)}.json`);
if (!res.ok) {
throw new Error(`loading outfit failed: ${res.status} ${res.statusText}`);
}
return res.json().then(normalizeOutfit);
}
async function saveOutfit({
id, // optional, null when creating a new outfit
name, // optional, server may fill in a placeholder
speciesId,
colorId,
pose,
appearanceId,
altStyleId,
wornItemIds,
closetedItemIds,
}) {
const params = {
outfit: {
name: name,
biology: {
species_id: speciesId,
color_id: colorId,
pose: pose,
pet_state_id: appearanceId,
},
alt_style_id: altStyleId,
item_ids: { worn: wornItemIds, closeted: closetedItemIds },
},
};
let res;
if (id == null) {
res = await fetch(`/outfits.json`, {
method: "POST",
body: JSON.stringify(params),
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": getCSRFToken(),
},
});
} else {
res = await fetch(`/outfits/${encodeURIComponent(id)}.json`, {
method: "PUT",
body: JSON.stringify(params),
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": getCSRFToken(),
},
});
}
if (!res.ok) {
throw new Error(`saving outfit failed: ${res.status} ${res.statusText}`);
}
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),
name: outfit.name,
speciesId: String(outfit.species_id),
colorId: String(outfit.color_id),
pose: outfit.pose,
appearanceId: String(outfit.pet_state_id),
altStyleId: outfit.alt_style_id ? String(outfit.alt_style_id) : null,
wornItemIds: (outfit.item_ids?.worn || []).map((id) => String(id)),
closetedItemIds: (outfit.item_ids?.closeted || []).map((id) => String(id)),
creator: outfit.user ? { id: String(outfit.user.id) } : null,
createdAt: outfit.created_at,
updatedAt: outfit.updated_at,
};
}
function getCSRFToken() {
return document.querySelector("meta[name=csrf-token]")?.content;
}