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:
parent
70fc8cdefe
commit
e42f39f49b
2 changed files with 181 additions and 170 deletions
|
@ -31,13 +31,14 @@ import {
|
||||||
WindowScroller,
|
WindowScroller,
|
||||||
} from "react-virtualized";
|
} from "react-virtualized";
|
||||||
|
|
||||||
import { Heading1, Heading3, MajorErrorMessage, usePageTitle } from "./util";
|
import { Heading1, Heading3, MajorErrorMessage } from "./util";
|
||||||
import HangerSpinner from "./components/HangerSpinner";
|
import HangerSpinner from "./components/HangerSpinner";
|
||||||
import MarkdownAndSafeHTML from "./components/MarkdownAndSafeHTML";
|
import MarkdownAndSafeHTML from "./components/MarkdownAndSafeHTML";
|
||||||
import ItemCard from "./components/ItemCard";
|
import ItemCard from "./components/ItemCard";
|
||||||
import useCurrentUser from "./components/useCurrentUser";
|
import useCurrentUser from "./components/useCurrentUser";
|
||||||
import useSupport from "./WardrobePage/support/useSupport";
|
import useSupport from "./WardrobePage/support/useSupport";
|
||||||
import WIPCallout from "./components/WIPCallout";
|
import WIPCallout from "./components/WIPCallout";
|
||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
function UserItemListPage() {
|
function UserItemListPage() {
|
||||||
const { query } = useRouter();
|
const { query } = useRouter();
|
||||||
|
@ -74,8 +75,6 @@ function UserItemListPage() {
|
||||||
|
|
||||||
const closetList = data?.closetList;
|
const closetList = data?.closetList;
|
||||||
|
|
||||||
usePageTitle(closetList?.name);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Center>
|
<Center>
|
||||||
|
@ -111,35 +110,42 @@ function UserItemListPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<>
|
||||||
<Breadcrumb
|
<Head>
|
||||||
fontSize="sm"
|
{closetList?.name && (
|
||||||
opacity="0.8"
|
<title>{closetList?.name} | Dress to Impress</title>
|
||||||
separator={<ChevronRightIcon marginTop="-2px" />}
|
)}
|
||||||
>
|
</Head>
|
||||||
<BreadcrumbItem>
|
<Box>
|
||||||
<Link href={`/user/${creator.id}/lists`} passHref>
|
<Breadcrumb
|
||||||
<BreadcrumbLink>{creator.username}'s lists</BreadcrumbLink>
|
fontSize="sm"
|
||||||
</Link>
|
opacity="0.8"
|
||||||
</BreadcrumbItem>
|
separator={<ChevronRightIcon marginTop="-2px" />}
|
||||||
{/* TODO: The "wants" version of this link doesn't always scroll down
|
>
|
||||||
* the page properly, now that we're not using the
|
<BreadcrumbItem>
|
||||||
* react-router-hash-link library. Oh well for now!
|
<Link href={`/user/${creator.id}/lists`} passHref>
|
||||||
* Would be nice to fix by having Next.js eliminate the loading
|
<BreadcrumbLink>{creator.username}'s lists</BreadcrumbLink>
|
||||||
* spinner perhaps?...*/}
|
</Link>
|
||||||
<BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
<Link href={linkBackPath} passHref>
|
{/* TODO: The "wants" version of this link doesn't always scroll down
|
||||||
<BreadcrumbLink>{linkBackText}</BreadcrumbLink>
|
* the page properly, now that we're not using the
|
||||||
</Link>
|
* react-router-hash-link library. Oh well for now!
|
||||||
</BreadcrumbItem>
|
* Would be nice to fix by having Next.js eliminate the loading
|
||||||
</Breadcrumb>
|
* spinner perhaps?...*/}
|
||||||
<Box height="1" />
|
<BreadcrumbItem>
|
||||||
<ClosetList
|
<Link href={linkBackPath} passHref>
|
||||||
closetList={closetList}
|
<BreadcrumbLink>{linkBackText}</BreadcrumbLink>
|
||||||
isCurrentUser={isCurrentUser}
|
</Link>
|
||||||
headingVariant="top-level"
|
</BreadcrumbItem>
|
||||||
/>
|
</Breadcrumb>
|
||||||
</Box>
|
<Box height="1" />
|
||||||
|
<ClosetList
|
||||||
|
closetList={closetList}
|
||||||
|
isCurrentUser={isCurrentUser}
|
||||||
|
headingVariant="top-level"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,12 @@ import { useRouter } from "next/router";
|
||||||
import { useQuery, useLazyQuery, useMutation } from "@apollo/client";
|
import { useQuery, useLazyQuery, useMutation } from "@apollo/client";
|
||||||
|
|
||||||
import HangerSpinner from "./components/HangerSpinner";
|
import HangerSpinner from "./components/HangerSpinner";
|
||||||
import { Heading1, Heading2, usePageTitle } from "./util";
|
import { Heading1, Heading2 } from "./util";
|
||||||
import SupportOnly from "./WardrobePage/support/SupportOnly";
|
import SupportOnly from "./WardrobePage/support/SupportOnly";
|
||||||
import useSupport from "./WardrobePage/support/useSupport";
|
import useSupport from "./WardrobePage/support/useSupport";
|
||||||
import useCurrentUser from "./components/useCurrentUser";
|
import useCurrentUser from "./components/useCurrentUser";
|
||||||
import { ClosetList, NeopetsStarIcon } from "./UserItemListPage";
|
import { ClosetList, NeopetsStarIcon } from "./UserItemListPage";
|
||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
const BadgeButton = React.forwardRef((props, ref) => (
|
const BadgeButton = React.forwardRef((props, ref) => (
|
||||||
<Badge as="button" ref={ref} {...props} />
|
<Badge as="button" ref={ref} {...props} />
|
||||||
|
@ -90,7 +91,6 @@ function UserItemListsIndexPage() {
|
||||||
} else {
|
} else {
|
||||||
pageTitleText = null;
|
pageTitleText = null;
|
||||||
}
|
}
|
||||||
usePageTitle(pageTitleText);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
|
@ -151,118 +151,155 @@ function UserItemListsIndexPage() {
|
||||||
).size;
|
).size;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClassNames>
|
<>
|
||||||
{({ css }) => (
|
<Head>
|
||||||
<Box>
|
<title>{pageTitleText} | Dress to Impress</title>
|
||||||
<Flex align="center" wrap="wrap-reverse">
|
</Head>
|
||||||
<Box>
|
<ClassNames>
|
||||||
<Heading1>{pageTitleText}</Heading1>
|
{({ css }) => (
|
||||||
<Wrap spacing="2" opacity="0.7">
|
<Box>
|
||||||
{data.user.contactNeopetsUsername && (
|
<Flex align="center" wrap="wrap-reverse">
|
||||||
<WrapItem>
|
<Box>
|
||||||
<Badge
|
<Heading1>{pageTitleText}</Heading1>
|
||||||
as="a"
|
<Wrap spacing="2" opacity="0.7">
|
||||||
href={`http://www.neopets.com/userlookup.phtml?user=${data.user.contactNeopetsUsername}`}
|
{data.user.contactNeopetsUsername && (
|
||||||
display="flex"
|
<WrapItem>
|
||||||
alignItems="center"
|
<Badge
|
||||||
>
|
as="a"
|
||||||
<NeopetsStarIcon marginRight="1" />
|
href={`http://www.neopets.com/userlookup.phtml?user=${data.user.contactNeopetsUsername}`}
|
||||||
{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"
|
display="flex"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
>
|
>
|
||||||
<EditIcon marginRight="1" />
|
<NeopetsStarIcon marginRight="1" />
|
||||||
Support
|
{data.user.contactNeopetsUsername}
|
||||||
</MenuButton>
|
</Badge>
|
||||||
</UserSupportMenu>
|
</WrapItem>
|
||||||
</WrapItem>
|
)}
|
||||||
</SupportOnly>
|
{data.user.contactNeopetsUsername && (
|
||||||
{/* Usually I put "Own" before "Want", but this matches the natural
|
<WrapItem>
|
||||||
* order on the page: the _matches_ for things you want are things
|
<Badge
|
||||||
* _this user_ owns, so they come first. I think it's also probably a
|
as="a"
|
||||||
* more natural train of thought: you come to someone's list _wanting_
|
href={`http://www.neopets.com/neomessages.phtml?type=send&recipient=${data.user.contactNeopetsUsername}`}
|
||||||
* something, and _then_ thinking about what you can offer. */}
|
display="flex"
|
||||||
{!isCurrentUser && numItemsTheyOwnThatYouWant > 0 && (
|
alignItems="center"
|
||||||
<WrapItem>
|
>
|
||||||
<Badge
|
<EmailIcon marginRight="1" />
|
||||||
as="a"
|
Neomail
|
||||||
href="#owned-items"
|
</Badge>
|
||||||
colorScheme="blue"
|
</WrapItem>
|
||||||
display="flex"
|
)}
|
||||||
alignItems="center"
|
<SupportOnly>
|
||||||
>
|
<WrapItem>
|
||||||
<StarIcon marginRight="1" />
|
<UserSupportMenu user={data.user}>
|
||||||
{numItemsTheyOwnThatYouWant > 1
|
<MenuButton
|
||||||
? `${numItemsTheyOwnThatYouWant} items you want`
|
as={BadgeButton}
|
||||||
: "1 item you want"}
|
display="flex"
|
||||||
</Badge>
|
alignItems="center"
|
||||||
</WrapItem>
|
>
|
||||||
)}
|
<EditIcon marginRight="1" />
|
||||||
{!isCurrentUser && numItemsTheyWantThatYouOwn > 0 && (
|
Support
|
||||||
<WrapItem>
|
</MenuButton>
|
||||||
<Badge
|
</UserSupportMenu>
|
||||||
as="a"
|
</WrapItem>
|
||||||
href="#wanted-items"
|
</SupportOnly>
|
||||||
colorScheme="green"
|
{/* Usually I put "Own" before "Want", but this matches the natural
|
||||||
display="flex"
|
* order on the page: the _matches_ for things you want are things
|
||||||
alignItems="center"
|
* _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_
|
||||||
<CheckIcon marginRight="1" />
|
* something, and _then_ thinking about what you can offer. */}
|
||||||
{numItemsTheyWantThatYouOwn > 1
|
{!isCurrentUser && numItemsTheyOwnThatYouWant > 0 && (
|
||||||
? `${numItemsTheyWantThatYouOwn} items you own`
|
<WrapItem>
|
||||||
: "1 item you own"}
|
<Badge
|
||||||
</Badge>
|
as="a"
|
||||||
</WrapItem>
|
href="#owned-items"
|
||||||
)}
|
colorScheme="blue"
|
||||||
</Wrap>
|
display="flex"
|
||||||
</Box>
|
alignItems="center"
|
||||||
<Box flex="1 0 auto" width="2" />
|
>
|
||||||
<Box marginBottom="1">
|
<StarIcon marginRight="1" />
|
||||||
<UserSearchForm />
|
{numItemsTheyOwnThatYouWant > 1
|
||||||
</Box>
|
? `${numItemsTheyOwnThatYouWant} items you want`
|
||||||
</Flex>
|
: "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">
|
<Box marginTop="4">
|
||||||
<Heading2 id="owned-items" marginBottom="2">
|
<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
|
{isCurrentUser
|
||||||
? "Items you own"
|
? "Items you want"
|
||||||
: `Items ${data.user.username} owns`}
|
: `Items ${data.user.username} wants`}
|
||||||
</Heading2>
|
</Heading2>
|
||||||
<VStack
|
<VStack spacing="4" alignItems="stretch">
|
||||||
spacing="8"
|
{listsOfWantedItems.map((closetList) => (
|
||||||
alignItems="stretch"
|
|
||||||
className={css`
|
|
||||||
clear: both;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{listsOfOwnedItems.map((closetList) => (
|
|
||||||
<ClosetList
|
<ClosetList
|
||||||
key={closetList.id}
|
key={closetList.id}
|
||||||
closetList={closetList}
|
closetList={closetList}
|
||||||
isCurrentUser={isCurrentUser}
|
isCurrentUser={isCurrentUser}
|
||||||
headingVariant={
|
headingVariant={
|
||||||
closetList.isDefaultList && listsOfOwnedItems.length === 1
|
closetList.isDefaultList && listsOfWantedItems.length === 1
|
||||||
? "hidden"
|
? "hidden"
|
||||||
: "list-item"
|
: "list-item"
|
||||||
}
|
}
|
||||||
|
@ -276,41 +313,9 @@ function UserItemListsIndexPage() {
|
||||||
))}
|
))}
|
||||||
</VStack>
|
</VStack>
|
||||||
</Box>
|
</Box>
|
||||||
|
)}
|
||||||
<Box
|
</ClassNames>
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue