load correct pet for species-specific items
uses the new canonical appearance GQL stuff :) there's still an extra reload, we're not using the apollo cache correctly!
This commit is contained in:
parent
1b59b9631b
commit
a6761a2403
4 changed files with 97 additions and 38 deletions
|
@ -105,6 +105,8 @@ function StartOutfitForm({ onChange }) {
|
|||
colorId={colorId}
|
||||
idealPose={idealPose}
|
||||
showPlaceholders
|
||||
colorPlaceholderText="Blue"
|
||||
speciesPlaceholderText="Acara"
|
||||
onChange={(species, color, isValid, closestPose) => {
|
||||
setSpeciesId(species.id);
|
||||
setColorId(color.id);
|
||||
|
|
|
@ -443,41 +443,64 @@ function ItemPageOutfitPreview({ itemId }) {
|
|||
[]
|
||||
);
|
||||
const [petState, setPetState] = React.useState({
|
||||
// Start by looking up Acara appearance data.
|
||||
speciesId: "1",
|
||||
colorId: "8",
|
||||
pose: idealPose,
|
||||
// We'll fill this in once the canonical appearance data arrives.
|
||||
speciesId: null,
|
||||
colorId: null,
|
||||
pose: null,
|
||||
});
|
||||
|
||||
// Start by loading the "canonical" pet and item appearance for the outfit
|
||||
// preview. We'll use this to initialize both the preview and the picker.
|
||||
const { loading, error, data } = useQuery(gql`
|
||||
query ItemPageOutfitPreview($itemId: ID!) {
|
||||
item(id: $itemId) {
|
||||
id
|
||||
canonicalAppearance {
|
||||
const { loading, error } = useQuery(
|
||||
gql`
|
||||
query ItemPageOutfitPreview($itemId: ID!) {
|
||||
item(id: $itemId) {
|
||||
id
|
||||
...ItemAppearanceFragment
|
||||
body {
|
||||
canonicalAppearance {
|
||||
id
|
||||
canonicalAppearance {
|
||||
...ItemAppearanceForOutfitPreview
|
||||
body {
|
||||
id
|
||||
...PetAppearanceFragment
|
||||
canonicalAppearance {
|
||||
id
|
||||
species {
|
||||
id
|
||||
}
|
||||
color {
|
||||
id
|
||||
}
|
||||
pose
|
||||
|
||||
...PetAppearanceForOutfitPreview
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${itemAppearanceFragment}
|
||||
${petAppearanceFragment}
|
||||
`);
|
||||
${itemAppearanceFragment}
|
||||
${petAppearanceFragment}
|
||||
`,
|
||||
{
|
||||
variables: { itemId },
|
||||
onCompleted: (data) => {
|
||||
const canonicalBody = data?.item?.canonicalAppearance?.body;
|
||||
const canonicalPetAppearance = canonicalBody?.canonicalAppearance;
|
||||
|
||||
setPetState({
|
||||
speciesId: canonicalPetAppearance?.species?.id,
|
||||
colorId: canonicalPetAppearance?.color?.id,
|
||||
pose: canonicalPetAppearance?.pose,
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// To check whether the item is compatible with this pet, query for the
|
||||
// appearance, but only against the cache. That way, we don't send a
|
||||
// redundant network request just for this (the OutfitPreview component will
|
||||
// handle it!), but we'll get an update once it arrives in the cache.
|
||||
const { cachedData } = useQuery(
|
||||
const { data: cachedData } = useQuery(
|
||||
gql`
|
||||
query ItemPageOutfitPreview_CacheOnly(
|
||||
$itemId: ID!
|
||||
|
@ -500,17 +523,29 @@ function ItemPageOutfitPreview({ itemId }) {
|
|||
colorId: petState.colorId,
|
||||
},
|
||||
fetchPolicy: "cache-only",
|
||||
onCompleted: (data) => console.log("data", data),
|
||||
}
|
||||
);
|
||||
|
||||
const borderColor = useColorModeValue("green.700", "green.400");
|
||||
const errorColor = useColorModeValue("red.600", "red.400");
|
||||
|
||||
if (error) {
|
||||
return <Box color="red.400">{error.message}</Box>;
|
||||
}
|
||||
|
||||
// If the layers are null-y, then we're still loading. Otherwise, if the
|
||||
// layers are an empty array, then we're incomaptible. Or, if they're a
|
||||
// non-empty array, then we're compatible!
|
||||
const layers = cachedData?.item?.appearanceOn?.layers;
|
||||
const isIncompatible = Array.isArray(layers) && layers.length === 0;
|
||||
|
||||
const borderColor = useColorModeValue("green.700", "green.400");
|
||||
const errorColor = useColorModeValue("red.600", "red.400");
|
||||
console.log(
|
||||
petState.speciesId,
|
||||
petState.colorId,
|
||||
itemId,
|
||||
layers,
|
||||
isIncompatible
|
||||
);
|
||||
|
||||
return (
|
||||
<VStack spacing="3" width="100%">
|
||||
|
@ -531,6 +566,7 @@ function ItemPageOutfitPreview({ itemId }) {
|
|||
colorId={petState.colorId}
|
||||
pose={petState.pose}
|
||||
wornItemIds={[itemId]}
|
||||
isLoading={loading}
|
||||
spinnerVariant="corner"
|
||||
loadingDelayMs={2000}
|
||||
/>
|
||||
|
|
|
@ -27,6 +27,7 @@ function OutfitPreview({
|
|||
pose,
|
||||
wornItemIds,
|
||||
appearanceId = null,
|
||||
isLoading = false,
|
||||
placeholder,
|
||||
loadingDelayMs,
|
||||
spinnerVariant,
|
||||
|
@ -57,7 +58,7 @@ function OutfitPreview({
|
|||
|
||||
return (
|
||||
<OutfitLayers
|
||||
loading={loading || loading2}
|
||||
loading={isLoading || loading || loading2}
|
||||
visibleLayers={loadedLayers}
|
||||
placeholder={placeholder}
|
||||
loadingDelayMs={loadingDelayMs}
|
||||
|
|
|
@ -21,6 +21,8 @@ function SpeciesColorPicker({
|
|||
colorId,
|
||||
idealPose,
|
||||
showPlaceholders = false,
|
||||
colorPlaceholderText = "",
|
||||
speciesPlaceholderText = "",
|
||||
stateMustAlwaysBeValid = false,
|
||||
isDisabled = false,
|
||||
size = "md",
|
||||
|
@ -84,7 +86,12 @@ function SpeciesColorPicker({
|
|||
_hover={{
|
||||
borderColor: "green.400",
|
||||
}}
|
||||
isInvalid={valids && !pairIsValid(valids, speciesId, colorId)}
|
||||
isInvalid={
|
||||
valids &&
|
||||
speciesId &&
|
||||
colorId &&
|
||||
!pairIsValid(valids, speciesId, colorId)
|
||||
}
|
||||
isDisabled={isDisabled || isLoading}
|
||||
errorBorderColor="red.300"
|
||||
{...props}
|
||||
|
@ -165,7 +172,7 @@ function SpeciesColorPicker({
|
|||
// supported colors for a species makes sense, but the other way around feels
|
||||
// confusing and restrictive.)
|
||||
let visibleColors = allColors;
|
||||
if (stateMustAlwaysBeValid && valids) {
|
||||
if (stateMustAlwaysBeValid && valids && speciesId) {
|
||||
visibleColors = visibleColors.filter(
|
||||
(c) => getValidPoses(valids, speciesId, c.id).size > 0
|
||||
);
|
||||
|
@ -180,13 +187,19 @@ function SpeciesColorPicker({
|
|||
isDisabled={isDisabled}
|
||||
onChange={onChangeColor}
|
||||
>
|
||||
{allColors.length === 0 && (
|
||||
<>
|
||||
{/* The default case, and a long name for sizing! */}
|
||||
<option>Blue</option>
|
||||
<option>Dimensional</option>
|
||||
</>
|
||||
)}
|
||||
{
|
||||
// If the selected color isn't in the set we have here, show the
|
||||
// placeholder. (Can happen during loading, or if an invalid color ID
|
||||
// like null is intentionally provided while the real value loads.)
|
||||
!visibleColors.some((c) => c.id === colorId) && (
|
||||
<option>{colorPlaceholderText}</option>
|
||||
)
|
||||
}
|
||||
{
|
||||
// A long name for sizing! Should appear below the placeholder, out
|
||||
// of view.
|
||||
visibleColors.length === 0 && <option>Dimensional</option>
|
||||
}
|
||||
{visibleColors.map((color) => (
|
||||
<option key={color.id} value={color.id}>
|
||||
{color.name}
|
||||
|
@ -201,13 +214,20 @@ function SpeciesColorPicker({
|
|||
isDisabled={isDisabled}
|
||||
onChange={onChangeSpecies}
|
||||
>
|
||||
{allSpecies.length === 0 && (
|
||||
<>
|
||||
{/* The default case, and a long name for sizing! */}
|
||||
<option>Acara</option>
|
||||
<option>Tuskaninny</option>
|
||||
</>
|
||||
)}
|
||||
{
|
||||
// If the selected species isn't in the set we have here, show the
|
||||
// placeholder. (Can happen during loading, or if an invalid species
|
||||
// ID like null is intentionally provided while the real value
|
||||
// loads.)
|
||||
!allSpecies.some((s) => s.id === speciesId) && (
|
||||
<option>{speciesPlaceholderText}</option>
|
||||
)
|
||||
}
|
||||
{
|
||||
// A long name for sizing! Should appear below the placeholder, out
|
||||
// of view.
|
||||
allSpecies.length === 0 && <option>Tuskaninny</option>
|
||||
}
|
||||
{allSpecies.map((species) => (
|
||||
<option key={species.id} value={species.id}>
|
||||
{species.name}
|
||||
|
|
Loading…
Reference in a new issue