Skip to content

Commit

Permalink
Stubbed out excerpt and copy request pages
Browse files Browse the repository at this point in the history
  • Loading branch information
pookmish committed May 6, 2024
1 parent e00d526 commit be7d717
Show file tree
Hide file tree
Showing 21 changed files with 1,167 additions and 649 deletions.
21 changes: 16 additions & 5 deletions app/[...slug]/metadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Maybe, NodeStanfordEvent, NodeStanfordNews, NodeStanfordPage, NodeStanfo
import {Metadata} from "next";
import {decode} from "html-entities";

export const getNodeMetadata = (node: NodeUnion): Metadata => {
export const getNodeMetadata = (node: NodeUnion, page: "excerpt" | "copy-requests" | "detail" = "detail"): Metadata => {
const defaultData = {
title: node.title + " | Stanford University Press",
other: {}
Expand Down Expand Up @@ -40,19 +40,30 @@ export const getNodeMetadata = (node: NodeUnion): Metadata => {

case "NodeSupBook":
return {
...getBookMetaData(node),
...defaultData
...defaultData,
...getBookMetaData(node, page),
}
}

return defaultData;
}

const getBookMetaData = (node: NodeSupBook) => {
const getBookMetaData = (node: NodeSupBook, page: "excerpt" | "copy-requests" | "detail") => {
const image = node.supBookImage?.mediaImage;
const description = getCleanDescription(node.supBookDescription?.processed);
let description = getCleanDescription(node.supBookDescription?.processed);

let title = node.title;
if (page === "excerpt") {
title += ": Excerpt & More"
description = getFirstText(node.supBookExcerpts);
}
if (page === "copy-requests") {
title += ": Copy Requests"
description = `Instructions to get copy requests of the book "${node.title}"`
}

return {
title: title,
description: description,
openGraph: {
type: "book",
Expand Down
34 changes: 31 additions & 3 deletions app/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,39 @@ import {getAllNodes, getEntityFromPath} from "@lib/gql/gql-queries";
import {getNodeMetadata} from "./metadata";
import {notFound, redirect} from "next/navigation";
import {getPathFromContext, PageProps} from "@lib/drupal/utils";
import SupBookExcerptPage from "@components/nodes/pages/sup-book/sup-book-excerpt-page";
import SupBookDeskExaminationPage from "@components/nodes/pages/sup-book/sup-book-desk-examination-page";

// https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config
export const revalidate = false;
export const dynamic = "force-static";

const Page = async ({params}: PageProps) => {
const {redirect: redirectPath, entity, error} = await getEntityFromPath<NodeUnion>(getPathFromContext({params}))
const {path, page} = getBookPageRequested(getPathFromContext({params}))

const {redirect: redirectPath, entity, error} = await getEntityFromPath<NodeUnion>(path)

if (error) throw new Error(error);
if (redirectPath?.url) redirect(redirectPath.url)
if (!entity) notFound();

if (entity.__typename === "NodeSupBook") {
if (page === "excerpt") return entity.supBookExcerpts ? <SupBookExcerptPage node={entity}/> : notFound();
if (page === "copy-requests") return <SupBookDeskExaminationPage node={entity}/>
}

return <NodePage node={entity}/>
}

export const generateMetadata = async ({params}: PageProps): Promise<Metadata> => {
const path = getPathFromContext({params})
const {path, page} = getBookPageRequested(getPathFromContext({params}))
const {entity} = await getEntityFromPath<NodeUnion>(path)
return entity ? getNodeMetadata(entity) : {};

if (entity?.__typename === "NodeSupBook" && (page === "excerpt" || page === "copy-requests")) {
return getNodeMetadata(entity, page)
}

return entity ? getNodeMetadata(entity, "detail") : {};
}

export const generateStaticParams = async (): Promise<PageProps["params"][]> => {
Expand All @@ -32,4 +46,18 @@ export const generateStaticParams = async (): Promise<PageProps["params"][]> =>
return nodePaths.map(node => ({slug: node.path.split("/").filter(part => !!part)}));
}


// Auxiliary pages for the book pages.
const getBookPageRequested = (path: string): { path: string, page: "excerpt" | "copy-requests" | "detail" } => {
if (path.endsWith("/excerpts")) {
return {path: path.replace(/\/excerpts$/, ""), page: "excerpt"}
}

if (path.endsWith("/desk-examination-copy-requests")) {
return {path: path.replace(/\/desk-examination-copy-requests$/, ""), page: "copy-requests"}
}

return {path, page: "detail"}
}

export default Page;
12 changes: 12 additions & 0 deletions app/books/awards/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {notFound, redirect} from "next/navigation";
import {getBookFromWorkId} from "../getBookFromWorkId";

const LegacyAwardPage = async ({searchParams}: { searchParams?: { [_key: string]: string } }) => {
if (!searchParams || !searchParams.id) notFound();
const bookNode = await getBookFromWorkId(parseInt(searchParams.id))

if (bookNode) redirect(bookNode.path);
notFound();
}

export default LegacyAwardPage;
12 changes: 12 additions & 0 deletions app/books/comp/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {notFound, redirect} from "next/navigation";
import {getBookFromWorkId} from "../getBookFromWorkId";

const LegacyBookPage = async ({searchParams}: { searchParams?: { [_key: string]: string } }) => {
if (!searchParams || !searchParams.id) notFound();
const bookNode = await getBookFromWorkId(parseInt(searchParams.id))

if (bookNode) redirect(`${bookNode.path}/desk-examination-copy-requests`);
notFound();
}

export default LegacyBookPage;
18 changes: 18 additions & 0 deletions app/books/getBookFromWorkId.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {BooksQuery, NodeSupBook} from "@lib/gql/__generated__/drupal";
import {graphqlClient} from "@lib/gql/gql-client";

export const getBookFromWorkId = async (workId: number): Promise<NodeSupBook | undefined> => {
let fetchMore = true;
let query: BooksQuery;
let afterCursor = null;
let desiredNode: NodeSupBook | undefined;
while (fetchMore) {
query = await graphqlClient({next: {tags: ["views:sup_books"]}}).Books({after: afterCursor})

desiredNode = query.nodeSupBooks.nodes.find(node => node.supBookWorkIdNumber === workId) as NodeSupBook | undefined;

fetchMore = query.nodeSupBooks.pageInfo.hasNextPage && !desiredNode
afterCursor = query.nodeSupBooks.pageInfo.endCursor;
}
return desiredNode;
}
21 changes: 3 additions & 18 deletions app/books/title/page.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
import {BooksQuery} from "@lib/gql/__generated__/drupal";
import {graphqlClient} from "@lib/gql/gql-client";
import {notFound, redirect} from "next/navigation";
import {getBookFromWorkId} from "../getBookFromWorkId";

const LegacyBookPage = async ({searchParams}: { searchParams?: { [_key: string]: string } }) => {
// Fetch all the books, sort by authors, and then build pagination and side alpha selection.
let fetchMore = true;
let query: BooksQuery;
let afterCursor = null;
let destinationUrl: string | undefined;

if (!searchParams || !searchParams.id) notFound();
const workId = parseInt(searchParams.id);

while (fetchMore) {
query = await graphqlClient({next: {tags: ["views:sup_books"]}}).Books({after: afterCursor})

destinationUrl = query.nodeSupBooks.nodes.find(node => node.supBookWorkIdNumber && node.supBookWorkIdNumber === workId)?.path;
const bookNode = await getBookFromWorkId(parseInt(searchParams.id))

fetchMore = query.nodeSupBooks.pageInfo.hasNextPage && !destinationUrl
afterCursor = query.nodeSupBooks.pageInfo.endCursor;
}
if (destinationUrl) redirect(destinationUrl);
if (bookNode) redirect(bookNode.path);
notFound();
}

Expand Down
24 changes: 18 additions & 6 deletions app/sitemap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,24 @@ const Sitemap = async (): Promise<MetadataRoute.Sitemap> => {

const sitemap: MetadataRoute.Sitemap = [];

nodes.map(node => sitemap.push({
url: `https://sup.org${node.path}`,
lastModified: new Date(node.changed.time),
priority: node.__typename === "NodeStanfordPage" ? 1 : .8,
changeFrequency: node.__typename === "NodeStanfordPage" ? "weekly": "monthly"
}));
nodes.map(node => {
sitemap.push({
url: `https://sup.org${node.path}`,
lastModified: new Date(node.changed.time),
priority: node.__typename === "NodeStanfordPage" ? 1 : .8,
changeFrequency: node.__typename === "NodeStanfordPage" ? "weekly" : "monthly"
})

// Add excerpts page for each book as appropriate.
if (node.__typename === "NodeSupBook" && node.supBookExcerpts) {
sitemap.push({
url: `https://sup.org${node.path}/excerpts`,
lastModified: new Date(node.changed.time),
priority: .8,
changeFrequency: "monthly"
})
}
});

return sitemap;
}
Expand Down
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"@formkit/auto-animate": "^0.8.2",
"@heroicons/react": "^2.1.3",
"@js-temporal/polyfill": "^0.4.4",
"@mui/base": "^5.0.0-beta.42",
"@mui/base": "^5.0.0-beta.43",
"@next/third-parties": "^14.2.3",
"@tailwindcss/container-queries": "^0.1.1",
"@types/node": "^20.12.7",
"@types/node": "^20.12.10",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"algoliasearch": "^4.23.3",
Expand All @@ -37,6 +37,7 @@
"html-react-parser": "^5.1.10",
"next": "^14.2.3",
"next-drupal": "^1.6.0",
"plaiceholder": "^3.0.0",
"postcss": "^8.4.38",
"qs": "^6.12.1",
"react": "^18.3.1",
Expand All @@ -59,13 +60,13 @@
"@graphql-codegen/typescript-graphql-request": "^6.2.0",
"@graphql-codegen/typescript-operations": "^4.2.0",
"@next/bundle-analyzer": "^14.2.3",
"@storybook/addon-essentials": "^8.0.9",
"@storybook/addon-interactions": "^8.0.9",
"@storybook/addon-links": "^8.0.9",
"@storybook/addon-essentials": "^8.0.10",
"@storybook/addon-interactions": "^8.0.10",
"@storybook/addon-links": "^8.0.10",
"@storybook/addon-styling": "^1.3.7",
"@storybook/blocks": "^8.0.9",
"@storybook/nextjs": "^8.0.9",
"@storybook/react": "^8.0.9",
"@storybook/blocks": "^8.0.10",
"@storybook/nextjs": "^8.0.10",
"@storybook/react": "^8.0.10",
"@storybook/testing-library": "^0.2.2",
"@types/react-slick": "^0.23.13",
"concurrently": "^8.2.2",
Expand All @@ -74,7 +75,7 @@
"eslint-plugin-storybook": "^0.8.0",
"eslint-plugin-unused-imports": "^3.2.0",
"react-docgen": "^7.0.3",
"storybook": "^8.0.9",
"storybook": "^8.0.10",
"tsconfig-paths-webpack-plugin": "^4.1.0"
},
"packageManager": "yarn@4.1.1"
Expand Down
25 changes: 0 additions & 25 deletions src/components/elements/location-selection.tsx

This file was deleted.

36 changes: 22 additions & 14 deletions src/components/elements/select-list.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import {JSX} from "react";
import {useSelect, SelectOptionDefinition, SelectProvider, SelectValue} from "@mui/base/useSelect";
import {useOption} from "@mui/base/useOption";
import {
Expand Down Expand Up @@ -97,6 +98,7 @@ type Props = {
emptyLabel?: Maybe<string>
name?: Maybe<string>
borderless?: boolean
downIcon?: JSX.Element
}

const SelectList = ({
Expand All @@ -110,6 +112,7 @@ const SelectList = ({
emptyValue,
emptyLabel = "- None -",
borderless = false,
downIcon,
...props
}: Props) => {
const labelId = useId();
Expand Down Expand Up @@ -150,22 +153,27 @@ const SelectList = ({
className={clsx("w-full text-left p-5", {"border border-black-40 rounded": !borderless})}
aria-labelledby={labeledBy}
>
<div className="flex justify-between flex-wrap">
{label &&
<div className={clsx("relative", {"text-m0 top-[-15px] w-full": optionChosen, "text-m1": !optionChosen})}>
<div id={labelId} className="bg-white w-fit px-5">
{label}
</div>
{label &&
<div className={clsx("relative max-w-[calc(100%-30px)]", {
"text-m0 top-[-15px] w-full": optionChosen,
"text-m1": !optionChosen
})}>
<div id={labelId} className={clsx("bg-white w-fit px-5", {"bg-black-20": props.disabled})}>
{label}
</div>
}
{optionChosen &&
<div className="overflow-hidden max-w-[calc(100%-30px)]">
{renderSelectedValue(value, options)}
</div>
}
</div>
}


{optionChosen &&
<div className="overflow-hidden max-w-[calc(100%-30px)]">
{renderSelectedValue(value, options)}
</div>
}

<ChevronDownIcon width={20} className="ml-auto flex-shrink-0"/>
</div>
<span className="absolute top-0 right-5 h-full flex items-center">
{downIcon || <ChevronDownIcon width={20}/>}
</span>
</button>

<div ref={listboxContainerRef} className={clsx("absolute z-[10] w-full top-full left-0 max-h-[300px] pb-5 overflow-y-scroll shadow-lg border border-black-20 bg-white", {"hidden": !listboxVisible})}>
Expand Down
Loading

0 comments on commit be7d717

Please sign in to comment.