Hook up compatibility data for SpeciesFacesPicker
It looks really nice!! :3
This commit is contained in:
parent
93c00c5e79
commit
cdff51dfef
3 changed files with 65 additions and 14 deletions
|
@ -513,11 +513,15 @@ function ItemPageOutfitPreview({ itemId }) {
|
||||||
// query after this loads, because our Apollo cache can't detect the
|
// query after this loads, because our Apollo cache can't detect the
|
||||||
// shared item appearance. (For standard colors though, our logic to
|
// shared item appearance. (For standard colors though, our logic to
|
||||||
// cover standard-color switches works for this preloading too.)
|
// cover standard-color switches works for this preloading too.)
|
||||||
const { loading, error } = useQuery(
|
const { loading, error, data } = useQuery(
|
||||||
gql`
|
gql`
|
||||||
query ItemPageOutfitPreview($itemId: ID!) {
|
query ItemPageOutfitPreview($itemId: ID!) {
|
||||||
item(id: $itemId) {
|
item(id: $itemId) {
|
||||||
id
|
id
|
||||||
|
compatibleBodies {
|
||||||
|
id
|
||||||
|
representsAllBodies
|
||||||
|
}
|
||||||
canonicalAppearance {
|
canonicalAppearance {
|
||||||
id
|
id
|
||||||
...ItemAppearanceForOutfitPreview
|
...ItemAppearanceForOutfitPreview
|
||||||
|
@ -559,6 +563,8 @@ function ItemPageOutfitPreview({ itemId }) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const compatibleBodies = data?.item?.compatibleBodies || [];
|
||||||
|
|
||||||
// To check whether the item is compatible with this pet, query for the
|
// 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
|
// appearance, but only against the cache. That way, we don't send a
|
||||||
// redundant network request just for this (the OutfitPreview component will
|
// redundant network request just for this (the OutfitPreview component will
|
||||||
|
@ -688,7 +694,7 @@ function ItemPageOutfitPreview({ itemId }) {
|
||||||
</VStack>
|
</VStack>
|
||||||
<SpeciesFacesPicker
|
<SpeciesFacesPicker
|
||||||
selectedSpeciesId={petState.speciesId}
|
selectedSpeciesId={petState.speciesId}
|
||||||
compatibleBodyIds={["180"]}
|
compatibleBodies={compatibleBodies}
|
||||||
onChange={({ speciesId, colorId }) =>
|
onChange={({ speciesId, colorId }) =>
|
||||||
setPetState({
|
setPetState({
|
||||||
speciesId,
|
speciesId,
|
||||||
|
@ -754,10 +760,15 @@ function PlayPauseButton({ isPaused, onClick }) {
|
||||||
|
|
||||||
function SpeciesFacesPicker({
|
function SpeciesFacesPicker({
|
||||||
selectedSpeciesId,
|
selectedSpeciesId,
|
||||||
compatibleBodyIds,
|
compatibleBodies,
|
||||||
onChange,
|
onChange,
|
||||||
isLoading,
|
isLoading,
|
||||||
}) {
|
}) {
|
||||||
|
const allBodiesAreCompatible = compatibleBodies.some(
|
||||||
|
(body) => body.representsAllBodies
|
||||||
|
);
|
||||||
|
const compatibleBodyIds = compatibleBodies.map((body) => body.id);
|
||||||
|
|
||||||
const allSpeciesFaces = speciesFaces.sort((a, b) =>
|
const allSpeciesFaces = speciesFaces.sort((a, b) =>
|
||||||
a.speciesName.localeCompare(b.speciesName)
|
a.speciesName.localeCompare(b.speciesName)
|
||||||
);
|
);
|
||||||
|
@ -791,7 +802,10 @@ function SpeciesFacesPicker({
|
||||||
speciesName={speciesFace.speciesName}
|
speciesName={speciesFace.speciesName}
|
||||||
colorId={speciesFace.colorId}
|
colorId={speciesFace.colorId}
|
||||||
neopetsImageHash={speciesFace.neopetsImageHash}
|
neopetsImageHash={speciesFace.neopetsImageHash}
|
||||||
isCompatible={compatibleBodyIds.includes(speciesFace.bodyId)}
|
isCompatible={
|
||||||
|
allBodiesAreCompatible ||
|
||||||
|
compatibleBodyIds.includes(speciesFace.bodyId)
|
||||||
|
}
|
||||||
isSelected={speciesFace.speciesId === selectedSpeciesId}
|
isSelected={speciesFace.speciesId === selectedSpeciesId}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
@ -833,23 +847,32 @@ function SpeciesFaceOption({
|
||||||
const isHappy = isLoading || isCompatible;
|
const isHappy = isLoading || isCompatible;
|
||||||
const emotionId = isHappy ? "1" : "2";
|
const emotionId = isHappy ? "1" : "2";
|
||||||
|
|
||||||
const tooltipLabel = isCompatible ? (
|
const tooltipLabel =
|
||||||
speciesName
|
isCompatible || isLoading ? (
|
||||||
) : (
|
speciesName
|
||||||
<div style={{ textAlign: "center" }}>
|
) : (
|
||||||
{speciesName}
|
<div style={{ textAlign: "center" }}>
|
||||||
<div style={{ fontStyle: "italic", fontSize: "0.75em" }}>
|
{speciesName}
|
||||||
(Not compatible yet)
|
<div style={{ fontStyle: "italic", fontSize: "0.75em" }}>
|
||||||
|
(Not compatible yet)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
|
|
||||||
const cursor = isLoading ? "wait" : !isCompatible ? "not-allowed" : "pointer";
|
const cursor = isLoading ? "wait" : !isCompatible ? "not-allowed" : "pointer";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClassNames>
|
<ClassNames>
|
||||||
{({ css }) => (
|
{({ css }) => (
|
||||||
<Tooltip label={tooltipLabel} placement="top" gutter={-12}>
|
<Tooltip
|
||||||
|
label={tooltipLabel}
|
||||||
|
placement="top"
|
||||||
|
// TODO: This looks great visually, but disrupts the hover state and
|
||||||
|
// causes flicker. I couldn't figure out how to apply
|
||||||
|
// `pointer-events: none` to the portal container, which I
|
||||||
|
// think is intercepting the hover even if the label doesn't.
|
||||||
|
gutter={-12}
|
||||||
|
>
|
||||||
<Box as="label" cursor={cursor}>
|
<Box as="label" cursor={cursor}>
|
||||||
<VisuallyHidden
|
<VisuallyHidden
|
||||||
as="input"
|
as="input"
|
||||||
|
|
|
@ -66,6 +66,10 @@ const typeDefs = gql`
|
||||||
# a union of zones for all of its appearances! We use this for overview
|
# a union of zones for all of its appearances! We use this for overview
|
||||||
# info about the item.
|
# info about the item.
|
||||||
allOccupiedZones: [Zone!]!
|
allOccupiedZones: [Zone!]!
|
||||||
|
|
||||||
|
# All bodies that this item is compatible with. Note that this might return
|
||||||
|
# the special representsAllPets body, e.g. if this is just a Background!
|
||||||
|
compatibleBodies: [Body!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ItemAppearance {
|
type ItemAppearance {
|
||||||
|
@ -330,6 +334,24 @@ const resolvers = {
|
||||||
const zones = zoneIds.map((id) => ({ id }));
|
const zones = zoneIds.map((id) => ({ id }));
|
||||||
return zones;
|
return zones;
|
||||||
},
|
},
|
||||||
|
compatibleBodies: async ({ id }, _, { db }) => {
|
||||||
|
const [rows, __] = await db.query(
|
||||||
|
`
|
||||||
|
SELECT DISTINCT swf_assets.body_id
|
||||||
|
FROM items
|
||||||
|
INNER JOIN parents_swf_assets ON
|
||||||
|
items.id = parents_swf_assets.parent_id AND
|
||||||
|
parents_swf_assets.parent_type = "Item"
|
||||||
|
INNER JOIN swf_assets ON
|
||||||
|
parents_swf_assets.swf_asset_id = swf_assets.id
|
||||||
|
WHERE items.id = ?
|
||||||
|
`,
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
const bodyIds = rows.map((row) => row.body_id);
|
||||||
|
const bodies = bodyIds.map((id) => ({ id }));
|
||||||
|
return bodies;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
ItemAppearance: {
|
ItemAppearance: {
|
||||||
|
|
|
@ -44,6 +44,9 @@ const typeDefs = gql`
|
||||||
|
|
||||||
# A PetAppearance that has this body. Prefers Blue and happy poses.
|
# A PetAppearance that has this body. Prefers Blue and happy poses.
|
||||||
canonicalAppearance: PetAppearance
|
canonicalAppearance: PetAppearance
|
||||||
|
|
||||||
|
# Whether this is the special body type that represents fitting _all_ pets.
|
||||||
|
representsAllBodies: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cache for 1 week (unlikely to change)
|
# Cache for 1 week (unlikely to change)
|
||||||
|
@ -131,6 +134,9 @@ const resolvers = {
|
||||||
"don't have a direct query for it yet, oops!"
|
"don't have a direct query for it yet, oops!"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
representsAllBodies: ({ id }) => {
|
||||||
|
return id == "0";
|
||||||
|
},
|
||||||
canonicalAppearance: async (
|
canonicalAppearance: async (
|
||||||
{ id },
|
{ id },
|
||||||
_,
|
_,
|
||||||
|
|
Loading…
Reference in a new issue