Add zone restrict to item page, too

I knew I was forgetting something! lol
This commit is contained in:
Emi Matchu 2021-02-12 18:15:45 -08:00
parent 7421f41e58
commit 7183f0725c
3 changed files with 91 additions and 31 deletions

View file

@ -7,7 +7,7 @@ describe("ItemZonesInfo", () => {
cy.visit("/items/37375"); cy.visit("/items/37375");
cy.get("[data-test-id='item-zones-info']", networkTimeout).should( cy.get("[data-test-id='item-zones-info']", networkTimeout).should(
"have.text", "have.text",
"Zone: Background" "Occupies: Background" + "Restricts: N/A"
); );
}); });
@ -15,7 +15,7 @@ describe("ItemZonesInfo", () => {
cy.visit("/items/34985"); cy.visit("/items/34985");
cy.get("[data-test-id='item-zones-info']", networkTimeout).should( cy.get("[data-test-id='item-zones-info']", networkTimeout).should(
"have.text", "have.text",
"Zone: Hat" "Occupies: Hat" + "Restricts: N/A"
); );
}); });
@ -23,7 +23,9 @@ describe("ItemZonesInfo", () => {
cy.visit("/items/43397"); cy.visit("/items/43397");
cy.get("[data-test-id='item-zones-info']", networkTimeout).should( cy.get("[data-test-id='item-zones-info']", networkTimeout).should(
"have.text", "have.text",
"Zones: Right-hand Item (52 species)" + "Left-hand Item (2 species)" "Occupies: Right-hand Item (52 species)" +
"Left-hand Item (2 species)" +
"Restricts: N/A"
); );
cy.contains("(52 species)").focus(); cy.contains("(52 species)").focus();
@ -39,7 +41,15 @@ describe("ItemZonesInfo", () => {
cy.visit("/items/70564"); cy.visit("/items/70564");
cy.get("[data-test-id='item-zones-info']", networkTimeout).should( cy.get("[data-test-id='item-zones-info']", networkTimeout).should(
"have.text", "have.text",
"Zone: Shirt/Dress" "Occupies: Shirt/Dress" + "Restricts: N/A"
);
});
it("shows zone restrict data for a simple hood", () => {
cy.visit("/items/38911");
cy.get("[data-test-id='item-zones-info']", networkTimeout).should(
"have.text",
"Occupies: Hat" + "Restricts: Hair Front" + "Head Transient Biology"
); );
}); });
}); });

View file

@ -574,6 +574,10 @@ function ItemPageOutfitPreview({ itemId }) {
item(id: $itemId) { item(id: $itemId) {
id id
name name
restrictedZones {
id
label @client
}
compatibleBodiesAndTheirZones { compatibleBodiesAndTheirZones {
body { body {
id id
@ -751,7 +755,7 @@ function ItemPageOutfitPreview({ itemId }) {
)} )}
</Box> </Box>
</AspectRatio> </AspectRatio>
<Box gridArea="speciesColorPicker" display="flex" alignItems="center"> <Flex gridArea="speciesColorPicker" alignSelf="start" align="center">
<Box <Box
// This box grows at the same rate as the box on the right, so the // This box grows at the same rate as the box on the right, so the
// middle box will be centered, if there's space! // middle box will be centered, if there's space!
@ -803,7 +807,7 @@ function ItemPageOutfitPreview({ itemId }) {
) )
} }
</Box> </Box>
</Box> </Flex>
<Box <Box
gridArea="speciesFacesPicker" gridArea="speciesFacesPicker"
paddingTop="2" paddingTop="2"
@ -833,9 +837,10 @@ function ItemPageOutfitPreview({ itemId }) {
{compatibleBodiesAndTheirZones.length > 0 && ( {compatibleBodiesAndTheirZones.length > 0 && (
<ItemZonesInfo <ItemZonesInfo
compatibleBodiesAndTheirZones={compatibleBodiesAndTheirZones} compatibleBodiesAndTheirZones={compatibleBodiesAndTheirZones}
restrictedZones={data?.item?.restrictedZones || []}
/> />
)} )}
<Box width="4" /> <Box width="6" />
<Flex <Flex
// Avoid layout shift while loading // Avoid layout shift while loading
minWidth="54px" minWidth="54px"
@ -1276,7 +1281,7 @@ function SpeciesFaceOption({
); );
} }
function ItemZonesInfo({ compatibleBodiesAndTheirZones }) { function ItemZonesInfo({ compatibleBodiesAndTheirZones, restrictedZones }) {
// Reorganize the body-and-zones data, into zone-and-bodies data. Also, we're // Reorganize the body-and-zones data, into zone-and-bodies data. Also, we're
// merging zones with the same label, because that's how user-facing zone UI // merging zones with the same label, because that's how user-facing zone UI
// generally works! // generally works!
@ -1300,6 +1305,10 @@ function ItemZonesInfo({ compatibleBodiesAndTheirZones }) {
) )
); );
const restrictedZoneLabels = [
...new Set(restrictedZones.map((z) => z.label)),
].sort();
// We only show body info if there's more than one group of bodies to talk // We only show body info if there's more than one group of bodies to talk
// about. If they all have the same zones, it's clear from context that any // about. If they all have the same zones, it's clear from context that any
// preview available in the list has the zones listed here. // preview available in the list has the zones listed here.
@ -1311,27 +1320,61 @@ function ItemZonesInfo({ compatibleBodiesAndTheirZones }) {
const showBodyInfo = bodyGroups.size > 1; const showBodyInfo = bodyGroups.size > 1;
return ( return (
<Box fontSize="sm" textAlign="center" data-test-id="item-zones-info"> <Flex
<Box as="header" fontWeight="bold" display="inline"> fontSize="sm"
{sortedZonesAndTheirBodies.length > 1 ? "Zones" : "Zone"}: textAlign="center"
</Box>{" "} // If the text gets too long, wrap Restricts onto another line, and center
<Box as="ul" listStyleType="none" display="inline"> // them relative to each other.
{sortedZonesAndTheirBodies.map(({ zoneLabel, bodies }) => ( wrap="wrap"
<Box justify="center"
key={zoneLabel} data-test-id="item-zones-info"
as="li" >
display="inline" <Box flex="0 0 auto" maxWidth="100%">
_notLast={{ _after: { content: '", "' } }} <Box as="header" fontWeight="bold" display="inline">
> Occupies:
<ItemZonesInfoListItem </Box>{" "}
zoneLabel={zoneLabel} <Box as="ul" listStyleType="none" display="inline">
bodies={bodies} {sortedZonesAndTheirBodies.map(({ zoneLabel, bodies }) => (
showBodyInfo={showBodyInfo} <Box
/> key={zoneLabel}
</Box> as="li"
))} display="inline"
_notLast={{ _after: { content: '", "' } }}
>
<ItemZonesInfoListItem
zoneLabel={zoneLabel}
bodies={bodies}
showBodyInfo={showBodyInfo}
/>
</Box>
))}
</Box>
</Box> </Box>
</Box> <Box width="4" flex="0 0 auto" />
<Box flex="0 0 auto" maxWidth="100%">
<Box as="header" fontWeight="bold" display="inline">
Restricts:
</Box>{" "}
{restrictedZoneLabels.length > 0 ? (
<Box as="ul" listStyleType="none" display="inline">
{restrictedZoneLabels.map((zoneLabel) => (
<Box
key={zoneLabel}
as="li"
display="inline"
_notLast={{ _after: { content: '", "' } }}
>
{zoneLabel}
</Box>
))}
</Box>
) : (
<Box as="span" fontStyle="italic" opacity="0.8">
N/A
</Box>
)}
</Box>
</Flex>
); );
} }
@ -1385,9 +1428,6 @@ function buildSortKeyForZoneLabelsAndTheirBodies({ zoneLabel, bodies }) {
// Hacky but solid! // Hacky but solid!
const inverseBodyCount = (9999 - bodies.length).toString().padStart(4, "0"); const inverseBodyCount = (9999 - bodies.length).toString().padStart(4, "0");
console.log(
`${representsAllBodies ? "A" : "Z"}-${inverseBodyCount}-${zoneLabel}`
);
return `${representsAllBodies ? "A" : "Z"}-${inverseBodyCount}-${zoneLabel}`; return `${representsAllBodies ? "A" : "Z"}-${inverseBodyCount}-${zoneLabel}`;
} }

View file

@ -83,6 +83,10 @@ const typeDefs = gql`
# info about the item. # info about the item.
allOccupiedZones: [Zone!]! @cacheControl(maxAge: ${oneHour}) allOccupiedZones: [Zone!]! @cacheControl(maxAge: ${oneHour})
# The zones this item restricts. Turns out, even though we offer this on
# ItemAppearance for consistency, this is static across all appearances.
restrictedZones: [Zone!]! @cacheControl(maxAge: ${oneHour}, staleWhileRevalidate: ${oneWeek})
# All bodies that this item is compatible with. Note that this might return # 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! # the special representsAllPets body, e.g. if this is just a Background!
# Deprecated: Impress 2020 now uses compatibleBodiesAndTheirZones. # Deprecated: Impress 2020 now uses compatibleBodiesAndTheirZones.
@ -397,6 +401,12 @@ const resolvers = {
const zones = zoneIds.map((id) => ({ id })); const zones = zoneIds.map((id) => ({ id }));
return zones; return zones;
}, },
restrictedZones: async ({ id }, _, { itemLoader }) => {
const item = await itemLoader.load(id);
return getRestrictedZoneIds(item.zonesRestrict).map((zoneId) => ({
id: zoneId,
}));
},
compatibleBodies: async ({ id }, _, { db }) => { compatibleBodies: async ({ id }, _, { db }) => {
const [rows, __] = await db.query( const [rows, __] = await db.query(
` `