diff --git a/pages/items/[itemId].tsx b/pages/items/[itemId].tsx
new file mode 100644
index 0000000..b6ff963
--- /dev/null
+++ b/pages/items/[itemId].tsx
@@ -0,0 +1,19 @@
+import ItemSearchPageToolbar from "../../src/app/components/ItemSearchPageToolbar";
+import ItemPage from "../../src/app/ItemPage";
+import PageLayout from "../../src/app/PageLayout";
+import type { NextPageWithLayout } from "../_app";
+
+const ItemPageWrapper: NextPageWithLayout = () => {
+ return ;
+};
+
+ItemPageWrapper.layoutComponent = ({ children }) => {
+ return (
+
+
+ {children}
+
+ );
+};
+
+export default ItemPageWrapper;
diff --git a/src/app/App.js b/src/app/App.js
index 4ac5e0e..1c43968 100644
--- a/src/app/App.js
+++ b/src/app/App.js
@@ -13,7 +13,6 @@ import { loadable } from "./util";
const HomePage = loadable(() => import("./HomePage"));
const ItemSearchPage = loadable(() => import("./ItemSearchPage"));
-const ItemPage = loadable(() => import("./ItemPage"));
const ItemTradesOfferingPage = loadable(() =>
import("./ItemTradesPage").then((m) => m.ItemTradesOfferingPage)
);
@@ -67,12 +66,6 @@ function App() {
-
-
-
-
-
-
diff --git a/src/app/GlobalFooter.js b/src/app/GlobalFooter.js
index 259ec07..e9ae882 100644
--- a/src/app/GlobalFooter.js
+++ b/src/app/GlobalFooter.js
@@ -114,11 +114,11 @@ function ColorModeButton() {
function useClassicDTIUrl() {
const { pathname, query } = useRouter();
- if (pathname === "/items/:itemId") {
+ if (pathname === "/items/[itemId]") {
return `https://impress.openneo.net/items/${query.itemId}`;
}
- if (pathname === "/user/:userId/lists") {
+ if (pathname === "/user/[userId]/lists") {
return `https://impress.openneo.net/user/${query.userId}/closet`;
}
diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js
index ae6e6b7..8584b7b 100644
--- a/src/app/ItemPage.js
+++ b/src/app/ItemPage.js
@@ -33,7 +33,7 @@ import {
import { MdPause, MdPlayArrow } from "react-icons/md";
import gql from "graphql-tag";
import { useQuery, useMutation } from "@apollo/client";
-import { Link, useParams } from "react-router-dom";
+import Link from "next/link";
import ItemPageLayout, { SubtleSkeleton } from "./ItemPageLayout";
import {
@@ -58,10 +58,11 @@ import useCurrentUser from "./components/useCurrentUser";
import SpeciesFacesPicker, {
colorIsBasic,
} from "./ItemPage/SpeciesFacesPicker";
+import { useRouter } from "next/router";
function ItemPage() {
- const { itemId } = useParams();
- return ;
+ const { query } = useRouter();
+ return ;
}
/**
@@ -69,7 +70,7 @@ function ItemPage() {
* entry point for ItemPageDrawer! When embedded in ItemPageDrawer, the
* `isEmbedded` prop is true, so we know not to e.g. set the page title.
*/
-export function ItemPageContent({ itemId, isEmbedded }) {
+export function ItemPageContent({ itemId, isEmbedded = false }) {
const { isLoggedIn } = useCurrentUser();
const { error, data } = useQuery(
@@ -706,30 +707,31 @@ function ItemPageTradeLinks({ itemId, isEmbedded }) {
function ItemPageTradeLink({ href, count, label, colorScheme, isEmbedded }) {
return (
-
+
+
);
}
@@ -1149,9 +1151,8 @@ function CustomizeMoreButton({ speciesId, colorId, pose, itemId, isDisabled }) {
const backgroundColorHover = useColorModeValue(undefined, "blackAlpha.900");
return (
-
Customize more
-
+
);
}
+function LinkOrButton({ href, ...props }) {
+ if (href != null) {
+ return (
+
+
+
+ );
+ } else {
+ return ;
+ }
+}
+
/**
* ExpandOnGroupHover starts at width=0, and expands to full width when a
* parent with role="group" gains hover or focus state.
diff --git a/src/app/ItemPageLayout.js b/src/app/ItemPageLayout.js
index e393a89..24911ba 100644
--- a/src/app/ItemPageLayout.js
+++ b/src/app/ItemPageLayout.js
@@ -113,11 +113,11 @@ function ItemPageBadges({ item, isEmbedded }) {
{
// If the createdAt date is null (loaded and empty), hide the badge.
- item.createdAt !== null && (
+ item?.createdAt !== null && (
- {item.createdAt && }
+ {item?.createdAt && }
)
}
Classic DTI
@@ -142,7 +142,7 @@ function ItemPageBadges({ item, isEmbedded }) {
- {item.isNc && (
+ {item?.isNc && (
- {item.ncTradeValueText && (
+ {item?.ncTradeValueText && (
- OWLS: {item.ncTradeValueText}
+ OWLS: {item?.ncTradeValueText}
)}
@@ -170,7 +170,7 @@ function ItemPageBadges({ item, isEmbedded }) {
@@ -183,7 +183,7 @@ function ItemPageBadges({ item, isEmbedded }) {
@@ -196,7 +196,7 @@ function ItemPageBadges({ item, isEmbedded }) {
@@ -209,7 +209,7 @@ function ItemPageBadges({ item, isEmbedded }) {
@@ -228,7 +228,7 @@ function ItemKindBadgeWithSupportTools({ item }) {
const ncRef = React.useRef(null);
const isNcAutoDetectedFromRarity =
- item.rarityIndex === 500 || item.rarityIndex === 0;
+ item?.rarityIndex === 500 || item?.rarityIndex === 0;
const [mutate, { loading }] = useMutation(gql`
mutation ItemPageSupportSetIsManuallyNc(
@@ -248,7 +248,11 @@ function ItemKindBadgeWithSupportTools({ item }) {
}
`);
- if (isSupportUser && item.rarityIndex != null && item.isManuallyNc != null) {
+ if (
+ isSupportUser &&
+ item?.rarityIndex != null &&
+ item?.isManuallyNc != null
+ ) {
// TODO: Could code-split this into a SupportOnly file...
return (
@@ -329,7 +333,7 @@ function ItemKindBadgeWithSupportTools({ item }) {
);
}
- return ;
+ return ;
}
const LinkBadge = React.forwardRef(
diff --git a/src/app/components/ItemCard.js b/src/app/components/ItemCard.js
index 310782f..faa0461 100644
--- a/src/app/components/ItemCard.js
+++ b/src/app/components/ItemCard.js
@@ -164,13 +164,16 @@ export function ItemThumbnail({
},
])}
>
-
+ {/* If the item is still loading, wait with an empty box. */}
+ {item && (
+
+ )}
)}
diff --git a/src/app/components/ItemSearchPageToolbar.js b/src/app/components/ItemSearchPageToolbar.js
index f3ea319..e6ff37a 100644
--- a/src/app/components/ItemSearchPageToolbar.js
+++ b/src/app/components/ItemSearchPageToolbar.js
@@ -1,7 +1,7 @@
import React from "react";
-import { useHistory, useLocation, useParams } from "react-router-dom";
import { useCommonStyles } from "../util";
import SearchToolbar from "../WardrobePage/SearchToolbar";
+import { useRouter } from "next/router";
function ItemSearchPageToolbar({ ...props }) {
const { query, setQuery } = useSearchQueryInUrl();
@@ -24,27 +24,30 @@ function ItemSearchPageToolbar({ ...props }) {
* query in the URL! It also parses out the offset for us.
*/
export function useSearchQueryInUrl() {
- const history = useHistory();
-
- const { query: value } = useParams();
- const { pathname, search } = useLocation();
+ const {
+ pathname,
+ query: queryParams,
+ push: pushHistory,
+ replace: replaceHistory,
+ } = useRouter();
+ const value = queryParams.query;
// Parse the query from the location. (We memoize this because we use it as a
// dependency in the query-saving hook below.)
const parsedQuery = React.useMemo(() => {
- const searchParams = new URLSearchParams(search);
return {
value: decodeURIComponent(value || ""),
- filterToZoneLabel: searchParams.get("zone") || null,
- filterToItemKind: searchParams.get("kind") || null,
- filterToCurrentUserOwnsOrWants: searchParams.get("user") || null,
+ filterToZoneLabel: queryParams.zone || null,
+ filterToItemKind: queryParams.kind || null,
+ filterToCurrentUserOwnsOrWants: queryParams.user || null,
};
- }, [search, value]);
+ }, [queryParams.zone, queryParams.kind, queryParams.user, value]);
- const offset = parseInt(new URLSearchParams(search).get("offset")) || 0;
+ const offset = parseInt(queryParams.offset) || 0;
// While on the search page, save the most recent parsed query in state.
- const isSearchPage = pathname.startsWith("/items/search");
+ const isSearchPage =
+ pathname === "/items/search" || pathname === "/items/search/[query]";
const [savedQuery, setSavedQuery] = React.useState(parsedQuery);
React.useEffect(() => {
if (isSearchPage) {
@@ -88,14 +91,14 @@ export function useSearchQueryInUrl() {
// navigation, like if they see the results and decide it's the wrong
// thing.
if (isSearchPage) {
- history.replace(url);
+ replaceHistory(url);
} else {
// When you use the search toolbar from the item page, treat it as a
// full navigation!
- history.push(url);
+ pushHistory(url);
}
},
- [history, isSearchPage]
+ [replaceHistory, pushHistory, isSearchPage]
);
// NOTE: We don't provide a `setOffset`, because that's handled via