2023-08-10 15:56:36 -07:00
|
|
|
import React from "react";
|
|
|
|
import { Box, Center, DarkMode } from "@chakra-ui/react";
|
|
|
|
import gql from "graphql-tag";
|
|
|
|
import { useQuery } from "@apollo/client";
|
|
|
|
import * as Sentry from "@sentry/react";
|
|
|
|
|
|
|
|
import OutfitThumbnail from "../components/OutfitThumbnail";
|
|
|
|
import { useOutfitPreview } from "../components/OutfitPreview";
|
|
|
|
import { loadable, MajorErrorMessage, TestErrorSender } from "../util";
|
|
|
|
|
|
|
|
const OutfitControls = loadable(() => import("./OutfitControls"));
|
|
|
|
|
|
|
|
function WardrobePreviewAndControls({
|
2024-09-09 16:10:45 -07:00
|
|
|
isLoading,
|
|
|
|
outfitState,
|
|
|
|
dispatchToOutfit,
|
2023-08-10 15:56:36 -07:00
|
|
|
}) {
|
2024-09-09 16:10:45 -07:00
|
|
|
// Whether the current outfit preview has animations. Determines whether we
|
|
|
|
// show the play/pause button.
|
|
|
|
const [hasAnimations, setHasAnimations] = React.useState(false);
|
2023-08-10 15:56:36 -07:00
|
|
|
|
2024-09-09 16:10:45 -07:00
|
|
|
const { appearance, preview } = useOutfitPreview({
|
|
|
|
isLoading: isLoading,
|
|
|
|
speciesId: outfitState.speciesId,
|
|
|
|
colorId: outfitState.colorId,
|
|
|
|
pose: outfitState.pose,
|
|
|
|
altStyleId: outfitState.altStyleId,
|
|
|
|
appearanceId: outfitState.appearanceId,
|
|
|
|
wornItemIds: outfitState.wornItemIds,
|
|
|
|
onChangeHasAnimations: setHasAnimations,
|
|
|
|
placeholder: <OutfitThumbnailIfCached outfitId={outfitState.id} />,
|
|
|
|
"data-test-id": "wardrobe-outfit-preview",
|
|
|
|
});
|
2023-08-10 15:56:36 -07:00
|
|
|
|
2024-09-09 16:10:45 -07:00
|
|
|
return (
|
|
|
|
<Sentry.ErrorBoundary fallback={MajorErrorMessage}>
|
|
|
|
<TestErrorSender />
|
|
|
|
<Center position="absolute" top="0" bottom="0" left="0" right="0">
|
|
|
|
<DarkMode>{preview}</DarkMode>
|
|
|
|
</Center>
|
|
|
|
<Box position="absolute" top="0" bottom="0" left="0" right="0">
|
|
|
|
<OutfitControls
|
|
|
|
outfitState={outfitState}
|
|
|
|
dispatchToOutfit={dispatchToOutfit}
|
|
|
|
showAnimationControls={hasAnimations}
|
|
|
|
appearance={appearance}
|
|
|
|
/>
|
|
|
|
</Box>
|
|
|
|
</Sentry.ErrorBoundary>
|
|
|
|
);
|
2023-08-10 15:56:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* OutfitThumbnailIfCached will render an OutfitThumbnail as a placeholder for
|
|
|
|
* the outfit preview... but only if we already have the data to generate the
|
|
|
|
* thumbnail stored in our local Apollo GraphQL cache.
|
|
|
|
*
|
|
|
|
* This means that, when you come from the Your Outfits page, we can show the
|
|
|
|
* outfit thumbnail instantly while everything else loads. But on direct
|
|
|
|
* navigation, this does nothing, and we just wait for the preview to load in
|
|
|
|
* like usual!
|
|
|
|
*/
|
|
|
|
function OutfitThumbnailIfCached({ outfitId }) {
|
2024-09-09 16:10:45 -07:00
|
|
|
const { data } = useQuery(
|
|
|
|
gql`
|
|
|
|
query OutfitThumbnailIfCached($outfitId: ID!) {
|
|
|
|
outfit(id: $outfitId) {
|
|
|
|
id
|
|
|
|
updatedAt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
{
|
|
|
|
variables: {
|
|
|
|
outfitId,
|
|
|
|
},
|
|
|
|
skip: outfitId == null,
|
|
|
|
fetchPolicy: "cache-only",
|
|
|
|
onError: (e) => console.error(e),
|
|
|
|
},
|
|
|
|
);
|
2023-08-10 15:56:36 -07:00
|
|
|
|
2024-09-09 16:10:45 -07:00
|
|
|
if (!data?.outfit) {
|
|
|
|
return null;
|
|
|
|
}
|
2023-08-10 15:56:36 -07:00
|
|
|
|
2024-09-09 16:10:45 -07:00
|
|
|
return (
|
|
|
|
<OutfitThumbnail
|
|
|
|
outfitId={data.outfit.id}
|
|
|
|
updatedAt={data.outfit.updatedAt}
|
|
|
|
alt=""
|
|
|
|
objectFit="contain"
|
|
|
|
width="100%"
|
|
|
|
height="100%"
|
|
|
|
filter="blur(2px)"
|
|
|
|
/>
|
|
|
|
);
|
2023-08-10 15:56:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export default WardrobePreviewAndControls;
|