Skip to content

Commit

Permalink
fix(next): add static generation for the list (api-platform#359)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanpoulain authored Jan 20, 2023
1 parent 271f654 commit 001d7f3
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 70 deletions.
5 changes: 5 additions & 0 deletions src/generators/NextGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class NextGenerator extends BaseGenerator {
"components/common/Pagination.tsx",
"components/common/ReferenceLinks.tsx",
"components/foo/List.tsx",
"components/foo/PageList.tsx",
"components/foo/Show.tsx",
"components/foo/Form.tsx",

Expand All @@ -26,6 +27,7 @@ export default class NextGenerator extends BaseGenerator {
// pages
"pages/foos/[id]/index.tsx",
"pages/foos/[id]/edit.tsx",
"pages/foos/page/[page].tsx",
"pages/foos/index.tsx",
"pages/foos/create.tsx",
"pages/_app.tsx",
Expand Down Expand Up @@ -81,15 +83,18 @@ export default class NextGenerator extends BaseGenerator {
this.createDir(`${dir}/components/${context.lc}`);
this.createDir(`${dir}/pages/${context.lc}s`);
this.createDir(`${dir}/pages/${context.lc}s/[id]`);
this.createDir(`${dir}/pages/${context.lc}s/page`);
[
// components
"components/%s/List.tsx",
"components/%s/PageList.tsx",
"components/%s/Show.tsx",
"components/%s/Form.tsx",

// pages
"pages/%ss/[id]/index.tsx",
"pages/%ss/[id]/edit.tsx",
"pages/%ss/page/[page].tsx",
"pages/%ss/index.tsx",
"pages/%ss/create.tsx",
].forEach((pattern) =>
Expand Down
2 changes: 2 additions & 0 deletions src/generators/NextGenerator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("generate", () => {
[
"/config/entrypoint.ts",
"/components/abc/List.tsx",
"/components/abc/PageList.tsx",
"/components/abc/Show.tsx",
"/components/abc/Form.tsx",
"/components/common/Layout.tsx",
Expand All @@ -55,6 +56,7 @@ describe("generate", () => {
"/types/item.ts",
"/pages/abcs/[id]/index.tsx",
"/pages/abcs/[id]/edit.tsx",
"/pages/abcs/page/[page].tsx",
"/pages/abcs/index.tsx",
"/pages/abcs/create.tsx",
"/pages/_app.tsx",
Expand Down
12 changes: 7 additions & 5 deletions templates/next/components/common/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { PagedCollection } from "../../types/collection";

interface Props {
collection: PagedCollection<unknown>;
// eslint-disable-next-line no-unused-vars
getPagePath: (path: string) => string;
}

const Pagination = ({ collection }: Props) => {
const Pagination = ({ collection, getPagePath }: Props) => {
const view = collection && collection['{{{hydraPrefix}}}view'];
if (!view) return null;

Expand All @@ -23,7 +25,7 @@ const Pagination = ({ collection }: Props) => {
aria-label="Page navigation"
>
<Link
href={first ? first : "#"}
href={first ? getPagePath(first) : "#"}
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
previous ? "" : " text-gray-500 pointer-events-none"
}`}
Expand All @@ -32,7 +34,7 @@ const Pagination = ({ collection }: Props) => {
<span aria-hidden="true">&lArr;</span> First
</Link>
<Link
href={previous ? previous : "#"}
href={previous ? getPagePath(previous) : "#"}
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
previous ? "" : " text-gray-500 pointer-events-none"
}`}
Expand All @@ -41,7 +43,7 @@ const Pagination = ({ collection }: Props) => {
<span aria-hidden="true">&larr;</span> Previous
</Link>
<Link
href={next ? next : "#"}
href={next ? getPagePath(next) : "#"}
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
next ? "" : " text-gray-500 pointer-events-none"
}`}
Expand All @@ -50,7 +52,7 @@ const Pagination = ({ collection }: Props) => {
Next <span aria-hidden="true">&rarr;</span>
</Link>
<Link
href={last ? last : "#"}
href={last ? getPagePath(last) : "#"}
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
next ? "" : "text-gray-500 pointer-events-none"
}`}
Expand Down
16 changes: 8 additions & 8 deletions templates/next/components/foo/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FunctionComponent } from "react";
import Link from "next/link";

import ReferenceLinks from "../common/ReferenceLinks";
import { getPath } from "../../utils/dataAccess";
import { getItemPath } from "../../utils/dataAccess";
import { {{{ucf}}} } from '../../types/{{{ucf}}}';

interface Props {
Expand Down Expand Up @@ -35,18 +35,18 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
{{{lc}}}['@id'] &&
<tr className="py-2" key={ {{{lc}}}['@id'] }>
<th scope="row">
<ReferenceLinks items={ { href: getPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]'), name: {{{lc}}}['@id'] } } />
<ReferenceLinks items={ { href: getItemPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]'), name: {{{lc}}}['@id'] } } />
</th>
{{#each fields}}
<td>
{{#if isReferences}}
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getItemPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
{{else if reference}}
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
{{else if isEmbeddeds}}
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getItemPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
{{else if embedded}}
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
{{else if (compare type "==" "Date") }}
{ {{{../lc}}}['{{{name}}}']?.toLocaleString() }
{{else}}
Expand All @@ -56,7 +56,7 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
{{/each}}
<td className="w-8">
<Link
href={ getPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]') }
href={ getItemPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]') }
className="text-cyan-500"
>
Show
Expand All @@ -68,7 +68,7 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
</td>
<td className="w-8">
<Link
href={ getPath({{{lc}}}["@id"], '/{{{lc}}}s/[id]/edit') }
href={ getItemPath({{{lc}}}["@id"], '/{{{lc}}}s/[id]/edit') }
className="text-cyan-500"
>
Edit
Expand Down
36 changes: 36 additions & 0 deletions templates/next/components/foo/PageList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NextComponentType, NextPageContext } from "next";
import { useRouter } from "next/router";
import Head from "next/head";
import { useQuery } from "react-query";

import Pagination from "../common/Pagination";
import { List } from "./List";
import { PagedCollection } from "../../types/collection";
import { {{{ucf}}} } from "../../types/{{{ucf}}}";
import { fetch, FetchResponse, parsePage } from "../../utils/dataAccess";
import { useMercure } from "../../utils/mercure";

export const get{{{ucf}}}sPath = (page?: string | string[] | undefined) => `/{{{name}}}${typeof page === 'string' ? `?page=${page}` : ''}`;
export const get{{{ucf}}}s = (page?: string | string[] | undefined) => async () => await fetch<PagedCollection<{{{ucf}}}>>(get{{{ucf}}}sPath(page));
const getPagePath = (path: string) => `/{{{lc}}}s/page/${parsePage("{{{name}}}", path)}`;

export const PageList: NextComponentType<NextPageContext> = () => {
const { query: { page } } = useRouter();
const { data: { data: {{lc}}s, hubURL } = { hubURL: null } } =
useQuery<FetchResponse<PagedCollection<{{{ucf}}}>> | undefined>(get{{{ucf}}}sPath(page), get{{{ucf}}}s(page));
const collection = useMercure({{lc}}s, hubURL);

if (!collection || !collection["{{{hydraPrefix}}}member"]) return null;

return (
<div>
<div>
<Head>
<title>{{{ucf}}} List</title>
</Head>
</div>
<List {{{lc}}}s={collection["{{{hydraPrefix}}}member"]} />
<Pagination collection={collection} getPagePath={getPagePath} />
</div>
);
};
12 changes: 6 additions & 6 deletions templates/next/components/foo/Show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import Head from "next/head";

{{#if hasRelations}}import ReferenceLinks from "../common/ReferenceLinks";{{/if}}
import { fetch, getPath } from "../../utils/dataAccess";
import { fetch, getItemPath } from "../../utils/dataAccess";
import { {{{ucf}}} } from "../../types/{{{ucf}}}";

interface Props {
Expand Down Expand Up @@ -55,13 +55,13 @@ export const Show: FunctionComponent<Props> = ({ {{{lc}}}, text }) => {
<th scope="row">{{name}}</th>
<td>
{{#if isReferences}}
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getItemPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
{{else if reference}}
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
{{else if isEmbeddeds}}
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getItemPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
{{else if embedded}}
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
{{else if (compare type "==" "Date") }}
{ {{{../lc}}}['{{{name}}}']?.toLocaleString() }
{{else}}
Expand All @@ -79,7 +79,7 @@ export const Show: FunctionComponent<Props> = ({ {{{lc}}}, text }) => {
)}
<div className="flex space-x-2 mt-4 items-center justify-end">
<Link
href={getPath({{{lc}}}["@id"], "/{{{lc}}}s/[id]/edit")}
href={getItemPath({{{lc}}}["@id"], "/{{{lc}}}s/[id]/edit")}
className="inline-block mt-2 border-2 border-cyan-500 bg-cyan-500 hover:border-cyan-700 hover:bg-cyan-700 text-xs text-white font-bold py-2 px-4 rounded"
>
Edit
Expand Down
4 changes: 2 additions & 2 deletions templates/next/pages/foos/[id]/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { dehydrate, QueryClient, useQuery } from "react-query";
import { Form } from "../../../components/{{{lc}}}/Form";
import { PagedCollection } from "../../../types/collection";
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
import { fetch, FetchResponse, getPaths } from "../../../utils/dataAccess";
import { fetch, FetchResponse, getItemPaths } from "../../../utils/dataAccess";

const get{{{ucf}}} = async (id: string|string[]|undefined) => id ? await fetch<{{{ucf}}}>(`/{{{name}}}/${id}`) : Promise.resolve(undefined);

Expand Down Expand Up @@ -48,7 +48,7 @@ export const getStaticProps: GetStaticProps = async ({ params: { id } = {} }) =>

export const getStaticPaths: GetStaticPaths = async () => {
const response = await fetch<PagedCollection<{{{ucf}}}>>("/{{{name}}}");
const paths = await getPaths(response, "{{{name}}}", '/{{{lc}}}s/[id]/edit');
const paths = await getItemPaths(response, "{{{name}}}", '/{{{lc}}}s/[id]/edit');

return {
paths,
Expand Down
4 changes: 2 additions & 2 deletions templates/next/pages/foos/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { dehydrate, QueryClient, useQuery } from "react-query";
import { Show } from "../../../components/{{{lc}}}/Show";
import { PagedCollection } from "../../../types/collection";
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
import { fetch, FetchResponse, getPaths } from "../../../utils/dataAccess";
import { fetch, FetchResponse, getItemPaths } from "../../../utils/dataAccess";
import { useMercure } from "../../../utils/mercure";

const get{{{ucf}}} = async (id: string|string[]|undefined) => id ? await fetch<{{{ucf}}}>(`/{{{name}}}/${id}`) : Promise.resolve(undefined);
Expand Down Expand Up @@ -51,7 +51,7 @@ export const getStaticProps: GetStaticProps = async ({ params: { id } = {} }) =>

export const getStaticPaths: GetStaticPaths = async () => {
const response = await fetch<PagedCollection<{{{ucf}}}>>("/{{{name}}}");
const paths = await getPaths(response, "{{{name}}}", '/{{{lc}}}s/[id]');
const paths = await getItemPaths(response, "{{{name}}}", '/{{{lc}}}s/[id]');

return {
paths,
Expand Down
43 changes: 8 additions & 35 deletions templates/next/pages/foos/index.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,18 @@
import { GetServerSideProps, NextComponentType, NextPageContext } from "next";
import Head from "next/head";
import { dehydrate, QueryClient, useQuery } from "react-query";
import { GetStaticProps } from "next";
import { dehydrate, QueryClient } from "react-query";

import Pagination from "../../components/common/Pagination";
import { List } from "../../components/{{{lc}}}/List";
import { PagedCollection } from "../../types/collection";
import { {{{ucf}}} } from "../../types/{{{ucf}}}";
import { fetch, FetchResponse } from "../../utils/dataAccess";
import { useMercure } from "../../utils/mercure";
import { PageList, get{{{ucf}}}s, get{{{ucf}}}sPath } from "../../components/{{{lc}}}/PageList";

const get{{{ucf}}}s = async () => await fetch<PagedCollection<{{{ucf}}}>>('/{{{name}}}');

const Page: NextComponentType<NextPageContext> = () => {
const { data: { data: {{lc}}s, hubURL } = { hubURL: null } } =
useQuery<FetchResponse<PagedCollection<{{{ucf}}}>> | undefined>('{{{name}}}', get{{{ucf}}}s);
const collection = useMercure({{lc}}s, hubURL);

if (!collection || !collection["{{{hydraPrefix}}}member"]) return null;

return (
<div>
<div>
<Head>
<title>{{{ucf}}} List</title>
</Head>
</div>
<List {{{lc}}}s={collection["{{{hydraPrefix}}}member"]} />
<Pagination collection={collection} />
</div>
);
};

export const getServerSideProps: GetServerSideProps = async () => {
export const getStaticProps: GetStaticProps = async () => {
const queryClient = new QueryClient();
await queryClient.prefetchQuery('{{{name}}}', get{{{ucf}}}s);
await queryClient.prefetchQuery(get{{{ucf}}}sPath(), get{{{ucf}}}s());

return {
props: {
dehydratedState: dehydrate(queryClient),
},
revalidate: 1,
};
}
};

export default Page;
export default PageList;
31 changes: 31 additions & 0 deletions templates/next/pages/foos/page/[page].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { GetStaticPaths, GetStaticProps } from "next";
import { dehydrate, QueryClient } from "react-query";

import { PageList, get{{{ucf}}}s, get{{{ucf}}}sPath } from "../../../components/{{{lc}}}/PageList";
import { PagedCollection } from "../../../types/collection";
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
import { fetch, getCollectionPaths } from "../../../utils/dataAccess";

export const getStaticProps: GetStaticProps = async ({ params: { page } = {} }) => {
const queryClient = new QueryClient();
await queryClient.prefetchQuery(get{{{ucf}}}sPath(page), get{{{ucf}}}s(page));

return {
props: {
dehydratedState: dehydrate(queryClient),
},
revalidate: 1,
};
};

export const getStaticPaths: GetStaticPaths = async () => {
const response = await fetch<PagedCollection<{{{ucf}}}>>("/{{{name}}}");
const paths = await getCollectionPaths(response, "{{{name}}}", "/{{{lc}}}s/page/[page]");

return {
paths,
fallback: true,
};
};

export default PageList;
Loading

0 comments on commit 001d7f3

Please sign in to comment.