Skip to content

Commit 001d7f3

Browse files
authored
fix(next): add static generation for the list (#359)
1 parent 271f654 commit 001d7f3

File tree

11 files changed

+135
-70
lines changed

11 files changed

+135
-70
lines changed

src/generators/NextGenerator.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default class NextGenerator extends BaseGenerator {
1515
"components/common/Pagination.tsx",
1616
"components/common/ReferenceLinks.tsx",
1717
"components/foo/List.tsx",
18+
"components/foo/PageList.tsx",
1819
"components/foo/Show.tsx",
1920
"components/foo/Form.tsx",
2021

@@ -26,6 +27,7 @@ export default class NextGenerator extends BaseGenerator {
2627
// pages
2728
"pages/foos/[id]/index.tsx",
2829
"pages/foos/[id]/edit.tsx",
30+
"pages/foos/page/[page].tsx",
2931
"pages/foos/index.tsx",
3032
"pages/foos/create.tsx",
3133
"pages/_app.tsx",
@@ -81,15 +83,18 @@ export default class NextGenerator extends BaseGenerator {
8183
this.createDir(`${dir}/components/${context.lc}`);
8284
this.createDir(`${dir}/pages/${context.lc}s`);
8385
this.createDir(`${dir}/pages/${context.lc}s/[id]`);
86+
this.createDir(`${dir}/pages/${context.lc}s/page`);
8487
[
8588
// components
8689
"components/%s/List.tsx",
90+
"components/%s/PageList.tsx",
8791
"components/%s/Show.tsx",
8892
"components/%s/Form.tsx",
8993

9094
// pages
9195
"pages/%ss/[id]/index.tsx",
9296
"pages/%ss/[id]/edit.tsx",
97+
"pages/%ss/page/[page].tsx",
9398
"pages/%ss/index.tsx",
9499
"pages/%ss/create.tsx",
95100
].forEach((pattern) =>

src/generators/NextGenerator.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ describe("generate", () => {
4545
[
4646
"/config/entrypoint.ts",
4747
"/components/abc/List.tsx",
48+
"/components/abc/PageList.tsx",
4849
"/components/abc/Show.tsx",
4950
"/components/abc/Form.tsx",
5051
"/components/common/Layout.tsx",
@@ -55,6 +56,7 @@ describe("generate", () => {
5556
"/types/item.ts",
5657
"/pages/abcs/[id]/index.tsx",
5758
"/pages/abcs/[id]/edit.tsx",
59+
"/pages/abcs/page/[page].tsx",
5860
"/pages/abcs/index.tsx",
5961
"/pages/abcs/create.tsx",
6062
"/pages/_app.tsx",

templates/next/components/common/Pagination.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { PagedCollection } from "../../types/collection";
33

44
interface Props {
55
collection: PagedCollection<unknown>;
6+
// eslint-disable-next-line no-unused-vars
7+
getPagePath: (path: string) => string;
68
}
79

8-
const Pagination = ({ collection }: Props) => {
10+
const Pagination = ({ collection, getPagePath }: Props) => {
911
const view = collection && collection['{{{hydraPrefix}}}view'];
1012
if (!view) return null;
1113

@@ -23,7 +25,7 @@ const Pagination = ({ collection }: Props) => {
2325
aria-label="Page navigation"
2426
>
2527
<Link
26-
href={first ? first : "#"}
28+
href={first ? getPagePath(first) : "#"}
2729
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
2830
previous ? "" : " text-gray-500 pointer-events-none"
2931
}`}
@@ -32,7 +34,7 @@ const Pagination = ({ collection }: Props) => {
3234
<span aria-hidden="true">&lArr;</span> First
3335
</Link>
3436
<Link
35-
href={previous ? previous : "#"}
37+
href={previous ? getPagePath(previous) : "#"}
3638
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
3739
previous ? "" : " text-gray-500 pointer-events-none"
3840
}`}
@@ -41,7 +43,7 @@ const Pagination = ({ collection }: Props) => {
4143
<span aria-hidden="true">&larr;</span> Previous
4244
</Link>
4345
<Link
44-
href={next ? next : "#"}
46+
href={next ? getPagePath(next) : "#"}
4547
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
4648
next ? "" : " text-gray-500 pointer-events-none"
4749
}`}
@@ -50,7 +52,7 @@ const Pagination = ({ collection }: Props) => {
5052
Next <span aria-hidden="true">&rarr;</span>
5153
</Link>
5254
<Link
53-
href={last ? last : "#"}
55+
href={last ? getPagePath(last) : "#"}
5456
className={`text-black p-3 hover:text-cyan-500 hover:bg-cyan-50 ${
5557
next ? "" : "text-gray-500 pointer-events-none"
5658
}`}

templates/next/components/foo/List.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FunctionComponent } from "react";
22
import Link from "next/link";
33

44
import ReferenceLinks from "../common/ReferenceLinks";
5-
import { getPath } from "../../utils/dataAccess";
5+
import { getItemPath } from "../../utils/dataAccess";
66
import { {{{ucf}}} } from '../../types/{{{ucf}}}';
77

88
interface Props {
@@ -35,18 +35,18 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
3535
{{{lc}}}['@id'] &&
3636
<tr className="py-2" key={ {{{lc}}}['@id'] }>
3737
<th scope="row">
38-
<ReferenceLinks items={ { href: getPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]'), name: {{{lc}}}['@id'] } } />
38+
<ReferenceLinks items={ { href: getItemPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]'), name: {{{lc}}}['@id'] } } />
3939
</th>
4040
{{#each fields}}
4141
<td>
4242
{{#if isReferences}}
43-
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
43+
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getItemPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
4444
{{else if reference}}
45-
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
45+
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
4646
{{else if isEmbeddeds}}
47-
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
47+
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getItemPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
4848
{{else if embedded}}
49-
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
49+
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
5050
{{else if (compare type "==" "Date") }}
5151
{ {{{../lc}}}['{{{name}}}']?.toLocaleString() }
5252
{{else}}
@@ -56,7 +56,7 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
5656
{{/each}}
5757
<td className="w-8">
5858
<Link
59-
href={ getPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]') }
59+
href={ getItemPath({{{lc}}}['@id'], '/{{{lc}}}s/[id]') }
6060
className="text-cyan-500"
6161
>
6262
Show
@@ -68,7 +68,7 @@ export const List: FunctionComponent<Props> = ({ {{{lc}}}s }) => (
6868
</td>
6969
<td className="w-8">
7070
<Link
71-
href={ getPath({{{lc}}}["@id"], '/{{{lc}}}s/[id]/edit') }
71+
href={ getItemPath({{{lc}}}["@id"], '/{{{lc}}}s/[id]/edit') }
7272
className="text-cyan-500"
7373
>
7474
Edit
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { NextComponentType, NextPageContext } from "next";
2+
import { useRouter } from "next/router";
3+
import Head from "next/head";
4+
import { useQuery } from "react-query";
5+
6+
import Pagination from "../common/Pagination";
7+
import { List } from "./List";
8+
import { PagedCollection } from "../../types/collection";
9+
import { {{{ucf}}} } from "../../types/{{{ucf}}}";
10+
import { fetch, FetchResponse, parsePage } from "../../utils/dataAccess";
11+
import { useMercure } from "../../utils/mercure";
12+
13+
export const get{{{ucf}}}sPath = (page?: string | string[] | undefined) => `/{{{name}}}${typeof page === 'string' ? `?page=${page}` : ''}`;
14+
export const get{{{ucf}}}s = (page?: string | string[] | undefined) => async () => await fetch<PagedCollection<{{{ucf}}}>>(get{{{ucf}}}sPath(page));
15+
const getPagePath = (path: string) => `/{{{lc}}}s/page/${parsePage("{{{name}}}", path)}`;
16+
17+
export const PageList: NextComponentType<NextPageContext> = () => {
18+
const { query: { page } } = useRouter();
19+
const { data: { data: {{lc}}s, hubURL } = { hubURL: null } } =
20+
useQuery<FetchResponse<PagedCollection<{{{ucf}}}>> | undefined>(get{{{ucf}}}sPath(page), get{{{ucf}}}s(page));
21+
const collection = useMercure({{lc}}s, hubURL);
22+
23+
if (!collection || !collection["{{{hydraPrefix}}}member"]) return null;
24+
25+
return (
26+
<div>
27+
<div>
28+
<Head>
29+
<title>{{{ucf}}} List</title>
30+
</Head>
31+
</div>
32+
<List {{{lc}}}s={collection["{{{hydraPrefix}}}member"]} />
33+
<Pagination collection={collection} getPagePath={getPagePath} />
34+
</div>
35+
);
36+
};

templates/next/components/foo/Show.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useRouter } from "next/router";
44
import Head from "next/head";
55

66
{{#if hasRelations}}import ReferenceLinks from "../common/ReferenceLinks";{{/if}}
7-
import { fetch, getPath } from "../../utils/dataAccess";
7+
import { fetch, getItemPath } from "../../utils/dataAccess";
88
import { {{{ucf}}} } from "../../types/{{{ucf}}}";
99

1010
interface Props {
@@ -55,13 +55,13 @@ export const Show: FunctionComponent<Props> = ({ {{{lc}}}, text }) => {
5555
<th scope="row">{{name}}</th>
5656
<td>
5757
{{#if isReferences}}
58-
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
58+
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((ref: any) => ({ href: getItemPath(ref, '/{{{lowercase reference.title}}}s/[id]'), name: ref })) } />
5959
{{else if reference}}
60-
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
60+
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}'], '/{{{lowercase reference.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}'] } } />
6161
{{else if isEmbeddeds}}
62-
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
62+
<ReferenceLinks items={ {{{../lc}}}['{{{name}}}'].map((emb: any) => ({ href: getItemPath(emb['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: emb['@id'] })) } />
6363
{{else if embedded}}
64-
<ReferenceLinks items={ { href: getPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
64+
<ReferenceLinks items={ { href: getItemPath({{{../lc}}}['{{{name}}}']['@id'], '/{{{lowercase embedded.title}}}s/[id]'), name: {{{../lc}}}['{{{name}}}']['@id'] } } />
6565
{{else if (compare type "==" "Date") }}
6666
{ {{{../lc}}}['{{{name}}}']?.toLocaleString() }
6767
{{else}}
@@ -79,7 +79,7 @@ export const Show: FunctionComponent<Props> = ({ {{{lc}}}, text }) => {
7979
)}
8080
<div className="flex space-x-2 mt-4 items-center justify-end">
8181
<Link
82-
href={getPath({{{lc}}}["@id"], "/{{{lc}}}s/[id]/edit")}
82+
href={getItemPath({{{lc}}}["@id"], "/{{{lc}}}s/[id]/edit")}
8383
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"
8484
>
8585
Edit

templates/next/pages/foos/[id]/edit.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { dehydrate, QueryClient, useQuery } from "react-query";
77
import { Form } from "../../../components/{{{lc}}}/Form";
88
import { PagedCollection } from "../../../types/collection";
99
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
10-
import { fetch, FetchResponse, getPaths } from "../../../utils/dataAccess";
10+
import { fetch, FetchResponse, getItemPaths } from "../../../utils/dataAccess";
1111

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

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

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

5353
return {
5454
paths,

templates/next/pages/foos/[id]/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { dehydrate, QueryClient, useQuery } from "react-query";
77
import { Show } from "../../../components/{{{lc}}}/Show";
88
import { PagedCollection } from "../../../types/collection";
99
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
10-
import { fetch, FetchResponse, getPaths } from "../../../utils/dataAccess";
10+
import { fetch, FetchResponse, getItemPaths } from "../../../utils/dataAccess";
1111
import { useMercure } from "../../../utils/mercure";
1212

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

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

5656
return {
5757
paths,

templates/next/pages/foos/index.tsx

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,18 @@
1-
import { GetServerSideProps, NextComponentType, NextPageContext } from "next";
2-
import Head from "next/head";
3-
import { dehydrate, QueryClient, useQuery } from "react-query";
1+
import { GetStaticProps } from "next";
2+
import { dehydrate, QueryClient } from "react-query";
43

5-
import Pagination from "../../components/common/Pagination";
6-
import { List } from "../../components/{{{lc}}}/List";
7-
import { PagedCollection } from "../../types/collection";
8-
import { {{{ucf}}} } from "../../types/{{{ucf}}}";
9-
import { fetch, FetchResponse } from "../../utils/dataAccess";
10-
import { useMercure } from "../../utils/mercure";
4+
import { PageList, get{{{ucf}}}s, get{{{ucf}}}sPath } from "../../components/{{{lc}}}/PageList";
115

12-
const get{{{ucf}}}s = async () => await fetch<PagedCollection<{{{ucf}}}>>('/{{{name}}}');
13-
14-
const Page: NextComponentType<NextPageContext> = () => {
15-
const { data: { data: {{lc}}s, hubURL } = { hubURL: null } } =
16-
useQuery<FetchResponse<PagedCollection<{{{ucf}}}>> | undefined>('{{{name}}}', get{{{ucf}}}s);
17-
const collection = useMercure({{lc}}s, hubURL);
18-
19-
if (!collection || !collection["{{{hydraPrefix}}}member"]) return null;
20-
21-
return (
22-
<div>
23-
<div>
24-
<Head>
25-
<title>{{{ucf}}} List</title>
26-
</Head>
27-
</div>
28-
<List {{{lc}}}s={collection["{{{hydraPrefix}}}member"]} />
29-
<Pagination collection={collection} />
30-
</div>
31-
);
32-
};
33-
34-
export const getServerSideProps: GetServerSideProps = async () => {
6+
export const getStaticProps: GetStaticProps = async () => {
357
const queryClient = new QueryClient();
36-
await queryClient.prefetchQuery('{{{name}}}', get{{{ucf}}}s);
8+
await queryClient.prefetchQuery(get{{{ucf}}}sPath(), get{{{ucf}}}s());
379

3810
return {
3911
props: {
4012
dehydratedState: dehydrate(queryClient),
4113
},
14+
revalidate: 1,
4215
};
43-
}
16+
};
4417

45-
export default Page;
18+
export default PageList;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { GetStaticPaths, GetStaticProps } from "next";
2+
import { dehydrate, QueryClient } from "react-query";
3+
4+
import { PageList, get{{{ucf}}}s, get{{{ucf}}}sPath } from "../../../components/{{{lc}}}/PageList";
5+
import { PagedCollection } from "../../../types/collection";
6+
import { {{{ucf}}} } from "../../../types/{{{ucf}}}";
7+
import { fetch, getCollectionPaths } from "../../../utils/dataAccess";
8+
9+
export const getStaticProps: GetStaticProps = async ({ params: { page } = {} }) => {
10+
const queryClient = new QueryClient();
11+
await queryClient.prefetchQuery(get{{{ucf}}}sPath(page), get{{{ucf}}}s(page));
12+
13+
return {
14+
props: {
15+
dehydratedState: dehydrate(queryClient),
16+
},
17+
revalidate: 1,
18+
};
19+
};
20+
21+
export const getStaticPaths: GetStaticPaths = async () => {
22+
const response = await fetch<PagedCollection<{{{ucf}}}>>("/{{{name}}}");
23+
const paths = await getCollectionPaths(response, "{{{name}}}", "/{{{lc}}}s/page/[page]");
24+
25+
return {
26+
paths,
27+
fallback: true,
28+
};
29+
};
30+
31+
export default PageList;

0 commit comments

Comments
 (0)