|
@@ -1,6 +1,6 @@
|
|
|
import clsx from "clsx";
|
|
import clsx from "clsx";
|
|
|
import Link from "next/link";
|
|
import Link from "next/link";
|
|
|
-import { useContext, useMemo } from "react";
|
|
|
|
|
|
|
+import { FormEvent, useContext, useMemo } from "react";
|
|
|
import { useRouter } from "next/router";
|
|
import { useRouter } from "next/router";
|
|
|
import { GetServerSideProps } from "next";
|
|
import { GetServerSideProps } from "next";
|
|
|
|
|
|
|
@@ -12,18 +12,42 @@ import NovelItem from "components/NovelItem";
|
|
|
import styles from "styles/genre.module.scss";
|
|
import styles from "styles/genre.module.scss";
|
|
|
import useStore from "libs/hooks/useStore";
|
|
import useStore from "libs/hooks/useStore";
|
|
|
import { SeoHead, SeoHeadConfig } from "components/SeoHead";
|
|
import { SeoHead, SeoHeadConfig } from "components/SeoHead";
|
|
|
|
|
+import Pagination from "components/Pagination";
|
|
|
|
|
+import PaginationItem from "components/Pagination/PaginationItem";
|
|
|
|
|
+import SearchForm from "components/common/SearchForm";
|
|
|
|
|
+import EmptyResult from "components/EmptyResult";
|
|
|
|
|
+
|
|
|
|
|
+interface Query {
|
|
|
|
|
+ genre?: string;
|
|
|
|
|
+ page?: string;
|
|
|
|
|
+ q?: string;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getKey(query: Query = {}) {
|
|
|
|
|
+ const queryString = `?page=${
|
|
|
|
|
+ isNaN(Number(query.page)) ? "1" : query.page
|
|
|
|
|
+ }&size=20`;
|
|
|
|
|
+
|
|
|
|
|
+ return query.q
|
|
|
|
|
+ ? `/api/search${queryString}${
|
|
|
|
|
+ query.genre ? `&genre=${query.genre}` : ""
|
|
|
|
|
+ }&name=${query.q}`
|
|
|
|
|
+ : query.genre
|
|
|
|
|
+ ? `/api/genre/${query.genre}${queryString}`
|
|
|
|
|
+ : `/api/all${queryString}`;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
const Genre = () => {
|
|
const Genre = () => {
|
|
|
- const { query } = useRouter();
|
|
|
|
|
- const { siteConfig } = useStore();
|
|
|
|
|
- const { data } = useGet<ListItem[]>(
|
|
|
|
|
- query.genre ? `/api/genre/${query.genre}` : "/api/list"
|
|
|
|
|
- );
|
|
|
|
|
- const store = useContext(Context);
|
|
|
|
|
|
|
+ const { query, asPath } = useRouter();
|
|
|
|
|
+ const { genre, siteConfig } = useStore();
|
|
|
|
|
+ const { data } = useGet<NovelList>(getKey(query));
|
|
|
const currentName = useMemo(() => {
|
|
const currentName = useMemo(() => {
|
|
|
- const item = store.genre.find((item) => item.uri === query.genre);
|
|
|
|
|
|
|
+ const item = genre.find((item) => item.uri === query.genre);
|
|
|
return item ? item.name : "All";
|
|
return item ? item.name : "All";
|
|
|
- }, [query.genre, store.genre]);
|
|
|
|
|
|
|
+ }, [query.genre, genre]);
|
|
|
|
|
+ const pashName = useMemo(() => {
|
|
|
|
|
+ return asPath.split("?")[0];
|
|
|
|
|
+ }, [asPath]);
|
|
|
|
|
|
|
|
const seoConfig: SeoHeadConfig = useMemo(() => {
|
|
const seoConfig: SeoHeadConfig = useMemo(() => {
|
|
|
// const genreName =
|
|
// const genreName =
|
|
@@ -40,6 +64,31 @@ const Genre = () => {
|
|
|
url: `https://${siteConfig.host}/novels${
|
|
url: `https://${siteConfig.host}/novels${
|
|
|
query.genre ? `/${query.genre}` : ""
|
|
query.genre ? `/${query.genre}` : ""
|
|
|
}`,
|
|
}`,
|
|
|
|
|
+ canonical: `https://${siteConfig.host}/novels${
|
|
|
|
|
+ query.genre ? `/${query.genre}` : ""
|
|
|
|
|
+ }`,
|
|
|
|
|
+ ...(data?.data.pageIndex && data.data.pageIndex > 1
|
|
|
|
|
+ ? {
|
|
|
|
|
+ pre: `https://${siteConfig.host}/novels${
|
|
|
|
|
+ query.genre ? `/${query.genre}` : ""
|
|
|
|
|
+ }${query.q ? `?q=${query.q}` : ""}${
|
|
|
|
|
+ data.data.pageIndex - 1 === 1
|
|
|
|
|
+ ? ""
|
|
|
|
|
+ : `${query.q ? `&` : "?"}page=${data.data.pageIndex - 1}`
|
|
|
|
|
+ }`,
|
|
|
|
|
+ }
|
|
|
|
|
+ : {}),
|
|
|
|
|
+ ...(data?.data.pageSize &&
|
|
|
|
|
+ data?.data.pageIndex &&
|
|
|
|
|
+ data.data.pageSize > data.data.pageIndex
|
|
|
|
|
+ ? {
|
|
|
|
|
+ next: `https://${siteConfig.host}/novels${
|
|
|
|
|
+ query.genre ? `/${query.genre}` : ""
|
|
|
|
|
+ }${query.q ? `?q=${query.q}` : ""}${`${query.q ? `&` : "?"}page=${
|
|
|
|
|
+ data.data.pageIndex + 1
|
|
|
|
|
+ }`}`,
|
|
|
|
|
+ }
|
|
|
|
|
+ : {}),
|
|
|
jsonLd: JSON.stringify([
|
|
jsonLd: JSON.stringify([
|
|
|
{
|
|
{
|
|
|
"@context": "https://schema.org",
|
|
"@context": "https://schema.org",
|
|
@@ -72,7 +121,7 @@ const Genre = () => {
|
|
|
{
|
|
{
|
|
|
"@context": "https://schema.org",
|
|
"@context": "https://schema.org",
|
|
|
"@type": "ItemList",
|
|
"@type": "ItemList",
|
|
|
- itemListElement: (data?.data || []).map((item, idx) => ({
|
|
|
|
|
|
|
+ itemListElement: (data?.data.rows || []).map((item, idx) => ({
|
|
|
"@type": "ListItem",
|
|
"@type": "ListItem",
|
|
|
position: idx + 1,
|
|
position: idx + 1,
|
|
|
url: `https://${siteConfig.host}/novel/${item.uri}`,
|
|
url: `https://${siteConfig.host}/novel/${item.uri}`,
|
|
@@ -88,7 +137,7 @@ const Genre = () => {
|
|
|
};
|
|
};
|
|
|
}, [
|
|
}, [
|
|
|
currentName,
|
|
currentName,
|
|
|
- data?.data,
|
|
|
|
|
|
|
+ data?.data.rows,
|
|
|
query.genre,
|
|
query.genre,
|
|
|
siteConfig.host,
|
|
siteConfig.host,
|
|
|
siteConfig.jsonLd,
|
|
siteConfig.jsonLd,
|
|
@@ -110,7 +159,7 @@ const Genre = () => {
|
|
|
>
|
|
>
|
|
|
All
|
|
All
|
|
|
</Link>
|
|
</Link>
|
|
|
- {store.genre.map((item) => (
|
|
|
|
|
|
|
+ {genre.map((item) => (
|
|
|
<Link
|
|
<Link
|
|
|
href={`/novels/${item.uri}`}
|
|
href={`/novels/${item.uri}`}
|
|
|
key={item.uri}
|
|
key={item.uri}
|
|
@@ -123,26 +172,52 @@ const Genre = () => {
|
|
|
</Link>
|
|
</Link>
|
|
|
))}
|
|
))}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <h3 className="novel-title">Search</h3>
|
|
|
|
|
+ <SearchForm />
|
|
|
<h2 className="novel-title">{`${currentName} Novels`}</h2>
|
|
<h2 className="novel-title">{`${currentName} Novels`}</h2>
|
|
|
- <ul className="novel-list">
|
|
|
|
|
- {(data?.data || []).map((item) => (
|
|
|
|
|
- <NovelItem
|
|
|
|
|
- key={item.uri}
|
|
|
|
|
- slug={item.uri}
|
|
|
|
|
- img={item.img}
|
|
|
|
|
- name={item.name}
|
|
|
|
|
- />
|
|
|
|
|
- ))}
|
|
|
|
|
- </ul>
|
|
|
|
|
|
|
+ {data?.data.rows && data.data.rows.length > 0 ? (
|
|
|
|
|
+ <ul className="novel-list">
|
|
|
|
|
+ {(data?.data.rows || []).map((item) => (
|
|
|
|
|
+ <NovelItem
|
|
|
|
|
+ key={item.uri}
|
|
|
|
|
+ slug={item.uri}
|
|
|
|
|
+ img={item.img}
|
|
|
|
|
+ name={item.name}
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <EmptyResult
|
|
|
|
|
+ icon="autoStories"
|
|
|
|
|
+ title={`Couldn't find books${
|
|
|
|
|
+ query.q ? ` matching "${query.q}"` : ""
|
|
|
|
|
+ }.`}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+ {data?.data.total_pages && data.data.total_pages > 1 ? (
|
|
|
|
|
+ <Pagination
|
|
|
|
|
+ className="mt-5"
|
|
|
|
|
+ count={data?.data.total_pages}
|
|
|
|
|
+ page={data?.data.pageIndex}
|
|
|
|
|
+ renderItem={(item) => (
|
|
|
|
|
+ <PaginationItem
|
|
|
|
|
+ component={Link}
|
|
|
|
|
+ href={`${pashName}${query.q ? `?q=${query.q}` : ""}${
|
|
|
|
|
+ item.page === 1 ? "" : `${query.q ? `&` : "?"}page=${item.page}`
|
|
|
|
|
+ }`}
|
|
|
|
|
+ {...item}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+ />
|
|
|
|
|
+ ) : null}
|
|
|
</main>
|
|
</main>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-export const getServerSideProps: GetServerSideProps<
|
|
|
|
|
- { fallback: Docs },
|
|
|
|
|
- { genre: string }
|
|
|
|
|
-> = async ({ params }) => {
|
|
|
|
|
- const key = params?.genre ? `/api/genre/${params.genre}` : `/api/list`;
|
|
|
|
|
|
|
+export const getServerSideProps: GetServerSideProps<{
|
|
|
|
|
+ fallback: Docs;
|
|
|
|
|
+}> = async ({ query }) => {
|
|
|
|
|
+ const key = getKey(query);
|
|
|
const data = await get(key);
|
|
const data = await get(key);
|
|
|
|
|
|
|
|
return {
|
|
return {
|