diff --git a/src/app/UserItemListPage.js b/src/app/UserItemListPage.js
index 75f7911..21216c5 100644
--- a/src/app/UserItemListPage.js
+++ b/src/app/UserItemListPage.js
@@ -5,25 +5,34 @@ import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
+ Button,
Center,
Flex,
+ HStack,
+ Input,
+ Textarea,
+ useToast,
Wrap,
WrapItem,
} from "@chakra-ui/react";
import {
ArrowForwardIcon,
+ CheckIcon,
ChevronRightIcon,
+ EditIcon,
EmailIcon,
} from "@chakra-ui/icons";
-import { Heading1, MajorErrorMessage, usePageTitle } from "./util";
-import { gql, useQuery } from "@apollo/client";
+import { gql, useMutation, useQuery } from "@apollo/client";
import { Link, useParams } from "react-router-dom";
import { HashLink } from "react-router-hash-link";
+import { Heading1, Heading3, MajorErrorMessage, usePageTitle } 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";
function UserItemListPage() {
const { listId } = useParams();
@@ -112,42 +121,240 @@ function UserItemListPage() {
- {closetList.name}
-
- {closetList.creator?.contactNeopetsUsername && (
-
-
+
+ );
+}
+
+export function ClosetList({
+ closetList,
+ isCurrentUser,
+ headingVariant = "list-item",
+}) {
+ const { isSupportUser, supportSecret } = useSupport();
+ const toast = useToast();
+
+ // When this mounts, scroll it into view if it matches the location hash.
+ // This works around the fact that, while the browser tries to do this
+ // natively on page load, the list might not be mounted yet!
+ const anchorId = `list-${closetList.id}`;
+ React.useEffect(() => {
+ if (document.location.hash === "#" + anchorId) {
+ document.getElementById(anchorId).scrollIntoView();
+ }
+ }, [anchorId]);
+
+ const [
+ sendSaveChangesMutation,
+ { loading: loadingSaveChanges },
+ ] = useMutation(
+ gql`
+ mutation ClosetList_Edit(
+ $closetListId: ID!
+ $name: String!
+ $description: String!
+ # Support users can edit any list, if they provide the secret. If you're
+ # editing your own list, this will be empty, and that's okay.
+ $supportSecret: String
+ ) {
+ editClosetList(
+ closetListId: $closetListId
+ name: $name
+ description: $description
+ supportSecret: $supportSecret
+ ) {
+ id
+ name
+ description
+ }
+ }
+ `,
+ { context: { sendAuth: true } }
+ );
+
+ const [isEditing, setIsEditing] = React.useState(false);
+ const [editableName, setEditableName] = React.useState(closetList.name);
+ const [editableDescription, setEditableDescription] = React.useState(
+ closetList.description
+ );
+ const hasChanges =
+ editableName !== closetList.name ||
+ editableDescription !== closetList.description;
+ const onSaveChanges = () => {
+ if (!hasChanges) {
+ setIsEditing(false);
+ return;
+ }
+
+ sendSaveChangesMutation({
+ variables: {
+ closetListId: closetList.id,
+ name: editableName,
+ description: editableDescription,
+ supportSecret,
+ },
+ })
+ .then(() => {
+ setIsEditing(false);
+ toast({
+ status: "success",
+ title: "Changes saved!",
+ });
+ })
+ .catch((err) => {
+ console.error(err);
+ toast({
+ status: "error",
+ title: "Sorry, we couldn't save this list 😖",
+ description: "Check your connection and try again.",
+ });
+ });
+ };
+
+ const Heading = headingVariant === "top-level" ? Heading1 : Heading3;
+
+ return (
+
+
+ {headingVariant !== "hidden" &&
+ (isEditing ? (
+ setEditableName(e.target.value)}
+ maxWidth="20ch"
+ // Shift left by our own padding/border, for alignment with the
+ // original title
+ paddingX="0.75rem"
+ marginLeft="calc(-0.75rem - 1px)"
+ boxShadow="sm"
+ lineHeight="1.2"
+ // HACK: Idk, the height stuff is really getting away from me,
+ // this is close enough :/
+ height="1.2em"
+ />
+ ) : (
+
-
- {closetList.creator.contactNeopetsUsername}
-
-
- )}
- {closetList.creator?.contactNeopetsUsername && (
-
-
+ {closetList.name}
+
+ )}
+
+ ))}
+
+ {(isCurrentUser || isSupportUser) &&
+ !closetList.isDefaultList &&
+ (isEditing ? (
+ <>
+
+ WIP: Can only edit text for now!
+
+
+
+
+
+
+ >
+ ) : (
+
-
- )}
-
-
+
+ Edit
+
+ ))}
+
+ {headingVariant === "top-level" && (
+
+ {closetList.creator?.contactNeopetsUsername && (
+
+
+
+ {closetList.creator.contactNeopetsUsername}
+
+
+ )}
+ {closetList.creator?.contactNeopetsUsername && (
+
+
+
+ Neomail
+
+
+ )}
+
+ )}
+
{closetList.description && (
- {closetList.description}
+
+ {isEditing ? (
+
)}
);
diff --git a/src/app/UserItemListsIndexPage.js b/src/app/UserItemListsIndexPage.js
index a05d4c9..e1a6b12 100644
--- a/src/app/UserItemListsIndexPage.js
+++ b/src/app/UserItemListsIndexPage.js
@@ -19,9 +19,6 @@ import {
WrapItem,
VStack,
useToast,
- Button,
- Textarea,
- HStack,
} from "@chakra-ui/react";
import {
ArrowForwardIcon,
@@ -32,21 +29,15 @@ import {
StarIcon,
} from "@chakra-ui/icons";
import gql from "graphql-tag";
-import { Link, useHistory, useParams } from "react-router-dom";
+import { useHistory, useParams } from "react-router-dom";
import { useQuery, useLazyQuery, useMutation } from "@apollo/client";
import HangerSpinner from "./components/HangerSpinner";
-import { Heading1, Heading2, Heading3, usePageTitle } from "./util";
-import MarkdownAndSafeHTML from "./components/MarkdownAndSafeHTML";
+import { Heading1, Heading2, usePageTitle } from "./util";
import SupportOnly from "./WardrobePage/support/SupportOnly";
import useSupport from "./WardrobePage/support/useSupport";
import useCurrentUser from "./components/useCurrentUser";
-import WIPCallout from "./components/WIPCallout";
-import {
- ClosetListContents,
- NeopetsStarIcon,
- buildClosetListPath,
-} from "./UserItemListPage";
+import { ClosetList, NeopetsStarIcon } from "./UserItemListPage";
const BadgeButton = React.forwardRef((props, ref) => (
@@ -269,7 +260,11 @@ function UserItemListsIndexPage() {
key={closetList.id}
closetList={closetList}
isCurrentUser={isCurrentUser}
- showHeading={listsOfOwnedItems.length > 1}
+ headingVariant={
+ closetList.isDefaultList && listsOfOwnedItems.length === 1
+ ? "hidden"
+ : "list-item"
+ }
/>
))}
@@ -292,7 +287,11 @@ function UserItemListsIndexPage() {
key={closetList.id}
closetList={closetList}
isCurrentUser={isCurrentUser}
- showHeading={listsOfWantedItems.length > 1}
+ headingVariant={
+ closetList.isDefaultList && listsOfWantedItems.length === 1
+ ? "hidden"
+ : "list-item"
+ }
/>
))}
@@ -430,195 +429,6 @@ function UserSearchForm() {
);
}
-function ClosetList({ closetList, isCurrentUser, showHeading }) {
- const { isSupportUser, supportSecret } = useSupport();
- const toast = useToast();
-
- // When this mounts, scroll it into view if it matches the location hash.
- // This works around the fact that, while the browser tries to do this
- // natively on page load, the list might not be mounted yet!
- const anchorId = `list-${closetList.id}`;
- React.useEffect(() => {
- if (document.location.hash === "#" + anchorId) {
- document.getElementById(anchorId).scrollIntoView();
- }
- }, [anchorId]);
-
- const [
- sendSaveChangesMutation,
- { loading: loadingSaveChanges },
- ] = useMutation(
- gql`
- mutation ClosetList_Edit(
- $closetListId: ID!
- $name: String!
- $description: String!
- # Support users can edit any list, if they provide the secret. If you're
- # editing your own list, this will be empty, and that's okay.
- $supportSecret: String
- ) {
- editClosetList(
- closetListId: $closetListId
- name: $name
- description: $description
- supportSecret: $supportSecret
- ) {
- id
- name
- description
- }
- }
- `,
- { context: { sendAuth: true } }
- );
-
- const [isEditing, setIsEditing] = React.useState(false);
- const [editableName, setEditableName] = React.useState(closetList.name);
- const [editableDescription, setEditableDescription] = React.useState(
- closetList.description
- );
- const hasChanges =
- editableName !== closetList.name ||
- editableDescription !== closetList.description;
- const onSaveChanges = () => {
- if (!hasChanges) {
- setIsEditing(false);
- return;
- }
-
- sendSaveChangesMutation({
- variables: {
- closetListId: closetList.id,
- name: editableName,
- description: editableDescription,
- supportSecret,
- },
- })
- .then(() => {
- setIsEditing(false);
- toast({
- status: "success",
- title: "Changes saved!",
- });
- })
- .catch((err) => {
- console.error(err);
- toast({
- status: "error",
- title: "Sorry, we couldn't save this list 😖",
- description: "Check your connection and try again.",
- });
- });
- };
-
- return (
-
-
- {showHeading &&
- (isEditing ? (
- setEditableName(e.target.value)}
- maxWidth="20ch"
- // Shift left by our own padding/border, for alignment with the
- // original title
- paddingX="0.75rem"
- marginLeft="calc(-0.75rem - 1px)"
- boxShadow="sm"
- />
- ) : (
-
- {closetList.isDefaultList ? (
- closetList.name
- ) : (
-
- {closetList.name}
-
- )}
-
- ))}
-
- {(isCurrentUser || isSupportUser) &&
- !closetList.isDefaultList &&
- (isEditing ? (
- <>
-
- WIP: Can only edit text for now!
-
-
-
-
-
-
- >
- ) : (
-
- ))}
-
- {closetList.description && (
-
- {isEditing ? (
-
- )}
-
-
- );
-}
-
function UserSupportMenu({ children, user }) {
const { supportSecret } = useSupport();
const toast = useToast();