impress/app/javascript/wardrobe-2020/components/useOutfitAppearance.js
Emi Matchu fc71f5b5a5 Filter by Alt Style in item search and item appearance API calls
I'm not planning to port full Alt Style support over to the 2020
frontend, I really am winding that down, but adding a couple lil API
parameters are *by far* the easiest way to get Alt Styles working in
the main app because of how it calls the 2020 API. So here we are, just
using new parameters for DTI 2020 that I'm gonna deploy to impress-2020
first!
2024-02-01 04:58:30 -08:00

210 lines
5.4 KiB
JavaScript

import React from "react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/client";
import getVisibleLayers, {
itemAppearanceFragmentForGetVisibleLayers,
petAppearanceFragmentForGetVisibleLayers,
} from "./getVisibleLayers";
import { useAltStyle } from "../loaders/alt-styles";
/**
* useOutfitAppearance downloads the outfit's appearance data, and returns
* visibleLayers for rendering.
*/
export default function useOutfitAppearance(outfitState) {
const { wornItemIds, speciesId, colorId, pose, altStyleId, appearanceId } =
outfitState;
// We split this query out from the other one, so that we can HTTP cache it.
//
// While Apollo gives us fine-grained caching during the page session, we can
// only HTTP a full query at a time.
//
// This is a minor optimization with respect to keeping the user's cache
// populated with their favorite species/color combinations. Once we start
// caching the items by body instead of species/color, this could make color
// changes really snappy!
//
// The larger optimization is that this enables the CDN to edge-cache the
// most popular species/color combinations, for very fast previews on the
// HomePage. At time of writing, Vercel isn't actually edge-caching these, I
// assume because our traffic isn't enough - so let's keep an eye on this!
const {
loading: loading1,
error: error1,
data: data1,
} = useQuery(
appearanceId == null
? gql`
query OutfitPetAppearance(
$speciesId: ID!
$colorId: ID!
$pose: Pose!
) {
petAppearance(
speciesId: $speciesId
colorId: $colorId
pose: $pose
) {
...PetAppearanceForOutfitPreview
}
}
${petAppearanceFragment}
`
: gql`
query OutfitPetAppearanceById($appearanceId: ID!) {
petAppearance: petAppearanceById(id: $appearanceId) {
...PetAppearanceForOutfitPreview
}
}
${petAppearanceFragment}
`,
{
variables: {
speciesId,
colorId,
pose,
appearanceId,
},
skip:
speciesId == null ||
colorId == null ||
(pose == null && appearanceId == null),
},
);
const {
loading: loading2,
error: error2,
data: data2,
} = useQuery(
gql`
query OutfitItemsAppearance(
$speciesId: ID!
$colorId: ID!
$altStyleId: ID
$wornItemIds: [ID!]!
) {
items(ids: $wornItemIds) {
id
name # HACK: This is for HTML5 detection UI in OutfitControls!
appearance: appearanceOn(
speciesId: $speciesId
colorId: $colorId
altStyleId: $altStyleId
) {
...ItemAppearanceForOutfitPreview
}
}
}
${itemAppearanceFragment}
`,
{
variables: {
speciesId,
colorId,
altStyleId,
wornItemIds,
},
skip: speciesId == null || colorId == null || wornItemIds.length === 0,
},
);
const {
isLoading: loading3,
error: error3,
data: altStyle,
} = useAltStyle(altStyleId, speciesId);
const petAppearance = altStyle?.appearance ?? data1?.petAppearance;
const items = data2?.items;
const itemAppearances = React.useMemo(
() => (items || []).map((i) => i.appearance),
[items],
);
const visibleLayers = React.useMemo(
() => getVisibleLayers(petAppearance, itemAppearances),
[petAppearance, itemAppearances],
);
const bodyId = petAppearance?.bodyId;
return {
loading: loading1 || loading2 || loading3,
error: error1 || error2 || error3,
petAppearance,
items: items || [],
itemAppearances,
visibleLayers,
bodyId,
};
}
export const appearanceLayerFragment = gql`
fragment AppearanceLayerForOutfitPreview on AppearanceLayer {
id
svgUrl
canvasMovieLibraryUrl
imageUrl: imageUrlV2(idealSize: SIZE_600)
bodyId
knownGlitches # For HTML5 & Known Glitches UI
zone {
id
depth
label
}
swfUrl # For the layer info modal
}
`;
export const appearanceLayerFragmentForSupport = gql`
fragment AppearanceLayerForSupport on AppearanceLayer {
id
remoteId # HACK: This is for Support tools, but other views don't need it
swfUrl # HACK: This is for Support tools, but other views don't need it
zone {
id
label # HACK: This is for Support tools, but other views don't need it
}
}
`;
export const itemAppearanceFragment = gql`
fragment ItemAppearanceForOutfitPreview on ItemAppearance {
id
layers {
id
...AppearanceLayerForOutfitPreview
...AppearanceLayerForSupport # HACK: Most users don't need this!
}
...ItemAppearanceForGetVisibleLayers
}
${appearanceLayerFragment}
${appearanceLayerFragmentForSupport}
${itemAppearanceFragmentForGetVisibleLayers}
`;
export const petAppearanceFragment = gql`
fragment PetAppearanceForOutfitPreview on PetAppearance {
id
bodyId
pose # For Known Glitches UI
isGlitched # For Known Glitches UI
species {
id # For Known Glitches UI
}
color {
id # For Known Glitches UI
}
layers {
id
...AppearanceLayerForOutfitPreview
}
...PetAppearanceForGetVisibleLayers
}
${appearanceLayerFragment}
${petAppearanceFragmentForGetVisibleLayers}
`;