Use new page title syntax for list pages

I'm not gonna do SSR here, the pages aren't really designed for partial loading state yet. It could be done, but I'm too sleepy! And it's too much refactor at once.
This commit is contained in:
Emi Matchu 2022-09-15 03:38:42 -07:00
parent 70fc8cdefe
commit e42f39f49b
2 changed files with 181 additions and 170 deletions

View file

@ -31,13 +31,14 @@ import {
WindowScroller,
} from "react-virtualized";
import { Heading1, Heading3, MajorErrorMessage, usePageTitle } from "./util";
import { Heading1, Heading3, MajorErrorMessage } from "./util";
import HangerSpinner from "./components/HangerSpinner";
import MarkdownAndSafeHTML from "./components/MarkdownAndSafeHTML";
import ItemCard from "./components/ItemCard";
import useCurrentUser from "./components/useCurrentUser";
import useSupport from "./WardrobePage/support/useSupport";
import WIPCallout from "./components/WIPCallout";
import Head from "next/head";
function UserItemListPage() {
const { query } = useRouter();
@ -74,8 +75,6 @@ function UserItemListPage() {
const closetList = data?.closetList;
usePageTitle(closetList?.name);
if (loading) {
return (
<Center>
@ -111,35 +110,42 @@ function UserItemListPage() {
}
return (
<Box>
<Breadcrumb
fontSize="sm"
opacity="0.8"
separator={<ChevronRightIcon marginTop="-2px" />}
>
<BreadcrumbItem>
<Link href={`/user/${creator.id}/lists`} passHref>
<BreadcrumbLink>{creator.username}'s lists</BreadcrumbLink>
</Link>
</BreadcrumbItem>
{/* TODO: The "wants" version of this link doesn't always scroll down
* the page properly, now that we're not using the
* react-router-hash-link library. Oh well for now!
* Would be nice to fix by having Next.js eliminate the loading
* spinner perhaps?...*/}
<BreadcrumbItem>
<Link href={linkBackPath} passHref>
<BreadcrumbLink>{linkBackText}</BreadcrumbLink>
</Link>
</BreadcrumbItem>
</Breadcrumb>
<Box height="1" />
<ClosetList
closetList={closetList}
isCurrentUser={isCurrentUser}
headingVariant="top-level"
/>
</Box>
<>
<Head>
{closetList?.name && (
<title>{closetList?.name} | Dress to Impress</title>
)}
</Head>
<Box>
<Breadcrumb
fontSize="sm"
opacity="0.8"
separator={<ChevronRightIcon marginTop="-2px" />}
>
<BreadcrumbItem>
<Link href={`/user/${creator.id}/lists`} passHref>
<BreadcrumbLink>{creator.username}'s lists</BreadcrumbLink>
</Link>
</BreadcrumbItem>
{/* TODO: The "wants" version of this link doesn't always scroll down
* the page properly, now that we're not using the
* react-router-hash-link library. Oh well for now!
* Would be nice to fix by having Next.js eliminate the loading
* spinner perhaps?...*/}
<BreadcrumbItem>
<Link href={linkBackPath} passHref>
<BreadcrumbLink>{linkBackText}</BreadcrumbLink>
</Link>
</BreadcrumbItem>
</Breadcrumb>
<Box height="1" />
<ClosetList
closetList={closetList}
isCurrentUser={isCurrentUser}
headingVariant="top-level"
/>
</Box>
</>
);
}

View file

@ -33,11 +33,12 @@ import { useRouter } from "next/router";
import { useQuery, useLazyQuery, useMutation } from "@apollo/client";
import HangerSpinner from "./components/HangerSpinner";
import { Heading1, Heading2, usePageTitle } from "./util";
import { Heading1, Heading2 } from "./util";
import SupportOnly from "./WardrobePage/support/SupportOnly";
import useSupport from "./WardrobePage/support/useSupport";
import useCurrentUser from "./components/useCurrentUser";
import { ClosetList, NeopetsStarIcon } from "./UserItemListPage";
import Head from "next/head";
const BadgeButton = React.forwardRef((props, ref) => (
<Badge as="button" ref={ref} {...props} />
@ -90,7 +91,6 @@ function UserItemListsIndexPage() {
} else {
pageTitleText = null;
}
usePageTitle(pageTitleText);
if (loading) {
return (
@ -151,118 +151,155 @@ function UserItemListsIndexPage() {
).size;
return (
<ClassNames>
{({ css }) => (
<Box>
<Flex align="center" wrap="wrap-reverse">
<Box>
<Heading1>{pageTitleText}</Heading1>
<Wrap spacing="2" opacity="0.7">
{data.user.contactNeopetsUsername && (
<WrapItem>
<Badge
as="a"
href={`http://www.neopets.com/userlookup.phtml?user=${data.user.contactNeopetsUsername}`}
display="flex"
alignItems="center"
>
<NeopetsStarIcon marginRight="1" />
{data.user.contactNeopetsUsername}
</Badge>
</WrapItem>
)}
{data.user.contactNeopetsUsername && (
<WrapItem>
<Badge
as="a"
href={`http://www.neopets.com/neomessages.phtml?type=send&recipient=${data.user.contactNeopetsUsername}`}
display="flex"
alignItems="center"
>
<EmailIcon marginRight="1" />
Neomail
</Badge>
</WrapItem>
)}
<SupportOnly>
<WrapItem>
<UserSupportMenu user={data.user}>
<MenuButton
as={BadgeButton}
<>
<Head>
<title>{pageTitleText} | Dress to Impress</title>
</Head>
<ClassNames>
{({ css }) => (
<Box>
<Flex align="center" wrap="wrap-reverse">
<Box>
<Heading1>{pageTitleText}</Heading1>
<Wrap spacing="2" opacity="0.7">
{data.user.contactNeopetsUsername && (
<WrapItem>
<Badge
as="a"
href={`http://www.neopets.com/userlookup.phtml?user=${data.user.contactNeopetsUsername}`}
display="flex"
alignItems="center"
>
<EditIcon marginRight="1" />
Support
</MenuButton>
</UserSupportMenu>
</WrapItem>
</SupportOnly>
{/* Usually I put "Own" before "Want", but this matches the natural
* order on the page: the _matches_ for things you want are things
* _this user_ owns, so they come first. I think it's also probably a
* more natural train of thought: you come to someone's list _wanting_
* something, and _then_ thinking about what you can offer. */}
{!isCurrentUser && numItemsTheyOwnThatYouWant > 0 && (
<WrapItem>
<Badge
as="a"
href="#owned-items"
colorScheme="blue"
display="flex"
alignItems="center"
>
<StarIcon marginRight="1" />
{numItemsTheyOwnThatYouWant > 1
? `${numItemsTheyOwnThatYouWant} items you want`
: "1 item you want"}
</Badge>
</WrapItem>
)}
{!isCurrentUser && numItemsTheyWantThatYouOwn > 0 && (
<WrapItem>
<Badge
as="a"
href="#wanted-items"
colorScheme="green"
display="flex"
alignItems="center"
>
<CheckIcon marginRight="1" />
{numItemsTheyWantThatYouOwn > 1
? `${numItemsTheyWantThatYouOwn} items you own`
: "1 item you own"}
</Badge>
</WrapItem>
)}
</Wrap>
</Box>
<Box flex="1 0 auto" width="2" />
<Box marginBottom="1">
<UserSearchForm />
</Box>
</Flex>
<NeopetsStarIcon marginRight="1" />
{data.user.contactNeopetsUsername}
</Badge>
</WrapItem>
)}
{data.user.contactNeopetsUsername && (
<WrapItem>
<Badge
as="a"
href={`http://www.neopets.com/neomessages.phtml?type=send&recipient=${data.user.contactNeopetsUsername}`}
display="flex"
alignItems="center"
>
<EmailIcon marginRight="1" />
Neomail
</Badge>
</WrapItem>
)}
<SupportOnly>
<WrapItem>
<UserSupportMenu user={data.user}>
<MenuButton
as={BadgeButton}
display="flex"
alignItems="center"
>
<EditIcon marginRight="1" />
Support
</MenuButton>
</UserSupportMenu>
</WrapItem>
</SupportOnly>
{/* Usually I put "Own" before "Want", but this matches the natural
* order on the page: the _matches_ for things you want are things
* _this user_ owns, so they come first. I think it's also probably a
* more natural train of thought: you come to someone's list _wanting_
* something, and _then_ thinking about what you can offer. */}
{!isCurrentUser && numItemsTheyOwnThatYouWant > 0 && (
<WrapItem>
<Badge
as="a"
href="#owned-items"
colorScheme="blue"
display="flex"
alignItems="center"
>
<StarIcon marginRight="1" />
{numItemsTheyOwnThatYouWant > 1
? `${numItemsTheyOwnThatYouWant} items you want`
: "1 item you want"}
</Badge>
</WrapItem>
)}
{!isCurrentUser && numItemsTheyWantThatYouOwn > 0 && (
<WrapItem>
<Badge
as="a"
href="#wanted-items"
colorScheme="green"
display="flex"
alignItems="center"
>
<CheckIcon marginRight="1" />
{numItemsTheyWantThatYouOwn > 1
? `${numItemsTheyWantThatYouOwn} items you own`
: "1 item you own"}
</Badge>
</WrapItem>
)}
</Wrap>
</Box>
<Box flex="1 0 auto" width="2" />
<Box marginBottom="1">
<UserSearchForm />
</Box>
</Flex>
<Box marginTop="4">
<Heading2 id="owned-items" marginBottom="2">
<Box marginTop="4">
<Heading2 id="owned-items" marginBottom="2">
{isCurrentUser
? "Items you own"
: `Items ${data.user.username} owns`}
</Heading2>
<VStack
spacing="8"
alignItems="stretch"
className={css`
clear: both;
`}
>
{listsOfOwnedItems.map((closetList) => (
<ClosetList
key={closetList.id}
closetList={closetList}
isCurrentUser={isCurrentUser}
headingVariant={
closetList.isDefaultList && listsOfOwnedItems.length === 1
? "hidden"
: "list-item"
}
// For default lists, we don't have a separate page, we just
// inline them all here. This is a less-nice experience, but it
// simplifies the single-list page a lot to not have to care,
// and for now we just kinda expect that people who care about
// trade lists enough will group them into lists so it's nbd!
maxNumItemsToShow={!closetList.isDefaultList ? 14 : null}
/>
))}
</VStack>
</Box>
<Box
borderTop="1px solid currentColor"
marginTop="16"
marginBottom="6"
/>
<Heading2 id="wanted-items" marginBottom="2">
{isCurrentUser
? "Items you own"
: `Items ${data.user.username} owns`}
? "Items you want"
: `Items ${data.user.username} wants`}
</Heading2>
<VStack
spacing="8"
alignItems="stretch"
className={css`
clear: both;
`}
>
{listsOfOwnedItems.map((closetList) => (
<VStack spacing="4" alignItems="stretch">
{listsOfWantedItems.map((closetList) => (
<ClosetList
key={closetList.id}
closetList={closetList}
isCurrentUser={isCurrentUser}
headingVariant={
closetList.isDefaultList && listsOfOwnedItems.length === 1
closetList.isDefaultList && listsOfWantedItems.length === 1
? "hidden"
: "list-item"
}
@ -276,41 +313,9 @@ function UserItemListsIndexPage() {
))}
</VStack>
</Box>
<Box
borderTop="1px solid currentColor"
marginTop="16"
marginBottom="6"
/>
<Heading2 id="wanted-items" marginBottom="2">
{isCurrentUser
? "Items you want"
: `Items ${data.user.username} wants`}
</Heading2>
<VStack spacing="4" alignItems="stretch">
{listsOfWantedItems.map((closetList) => (
<ClosetList
key={closetList.id}
closetList={closetList}
isCurrentUser={isCurrentUser}
headingVariant={
closetList.isDefaultList && listsOfWantedItems.length === 1
? "hidden"
: "list-item"
}
// For default lists, we don't have a separate page, we just
// inline them all here. This is a less-nice experience, but it
// simplifies the single-list page a lot to not have to care,
// and for now we just kinda expect that people who care about
// trade lists enough will group them into lists so it's nbd!
maxNumItemsToShow={!closetList.isDefaultList ? 14 : null}
/>
))}
</VStack>
</Box>
)}
</ClassNames>
)}
</ClassNames>
</>
);
}