-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSearchPagination.tsx
100 lines (89 loc) · 2.9 KB
/
SearchPagination.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import type { GroupProps } from "@mantine/core";
import { ActionIcon, Group, Text } from "@mantine/core";
import { Link } from "@remix-run/react";
import { useCallback, useMemo, useState } from "react";
import { getQuery, withQuery } from "ufo";
import type { z } from "zod";
import Fa6SolidAngleLeft from "~icons/fa6-solid/angle-left";
import Fa6SolidAngleRight from "~icons/fa6-solid/angle-right";
import type { PaginationMeta } from "../../../generated/api/schemas/paginationMeta";
import { buildPaginationMeta } from "../pagination";
import type { noteSearchParamSchema } from "../validation";
type PaginationProps = {
meta: PaginationMeta;
currentQuery: z.infer<typeof noteSearchParamSchema>;
loading?: boolean;
/**
* 検索結果として表示している現在のページに表示しているデータの件数
*/
visibleItemCount: number;
} & GroupProps;
export const SearchPagination = ({
currentQuery,
meta,
loading,
visibleItemCount,
...groupProps
}: PaginationProps) => {
const pagination = buildPaginationMeta(meta, currentQuery);
const pageFirstItemIndex = currentQuery.offset + 1;
const totalDisplayedItems = currentQuery.offset + visibleItemCount;
const prevTo = useMemo(
() => (pagination?.prev ? withQuery("/", getQuery(pagination.prev)) : null),
[pagination?.prev],
);
const nextTo = useMemo(
() => (pagination?.next ? withQuery("/", getQuery(pagination.next)) : null),
[pagination?.next],
);
const [clickedButton, setClickedButton] = useState<"prev" | "next">();
const prevLoading = (loading && clickedButton === "prev") ?? false;
const nextLoading = (loading && clickedButton === "next") ?? false;
const handlePrevClick = useCallback(() => {
setClickedButton("prev");
}, []);
const handleNextClick = useCallback(() => {
setClickedButton("next");
}, []);
return (
<Group {...groupProps}>
<Text>
{pageFirstItemIndex} ~ {totalDisplayedItems} 件目を表示中
</Text>
{prevTo ? (
<ActionIcon
aria-label="前のページへ移動する"
color="pink"
component={Link}
loading={prevLoading}
onClick={handlePrevClick}
to={prevTo}
variant="light"
>
<Fa6SolidAngleLeft />
</ActionIcon>
) : (
<ActionIcon aria-hidden color="pink" disabled variant="light">
<Fa6SolidAngleLeft />
</ActionIcon>
)}
{nextTo ? (
<ActionIcon
aria-label="次のページへ移動する"
color="pink"
component={Link}
loading={nextLoading}
onClick={handleNextClick}
to={nextTo}
variant="light"
>
<Fa6SolidAngleRight />
</ActionIcon>
) : (
<ActionIcon aria-hidden color="pink" disabled variant="light">
<Fa6SolidAngleRight />
</ActionIcon>
)}
</Group>
);
};