impress/app/javascript/wardrobe-2020/loaders/outfits.js
Emi Matchu c60e222faa Add Alt Style support to outfit saving
Pretty straightforward, just add the field to the record, and wire it
all up! I'm glad this seemed to work out pretty well all-in-all 😅
2024-02-01 05:55:19 -08:00

143 lines
3.1 KiB
JavaScript

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,
altStyleId,
wornItemIds,
closetedItemIds,
}) {
const params = {
outfit: {
name: name,
biology: {
species_id: speciesId,
color_id: colorId,
pose: pose,
},
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,
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;
}