fix : show 25 item per page in admin glossary

This commit is contained in:
2026-09-27 15:24:35 +07:00 Unverified
parent d9dcf1a3f8
commit 69b00f50ab
+78 -2
View File
@@ -15,6 +15,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import { FuzzyCombobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList } from "@/components/ui/combobox";
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Spinner } from "@/components/ui/spinner";
import type { GlossaryKind } from "@/lib/glossary";
@@ -24,6 +25,15 @@ import { cn } from "@/lib/utils";
type CatalogItem = { key: string; name: string; imageUrl: string; rarity?: number | null };
type Alias = { id: string; kind: string; catalogKey: string; alias: string };
const PAGE_SIZE = 25;
function paginationItems(currentPage: number, totalPages: number) {
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);
if (currentPage <= 4) return [1, 2, 3, 4, 5, "end-ellipsis", totalPages] as const;
if (currentPage >= totalPages - 3) return [1, "start-ellipsis", totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages] as const;
return [1, "start-ellipsis", currentPage - 1, currentPage, currentPage + 1, "end-ellipsis", totalPages] as const;
}
const kindLabels: Record<GlossaryKind, string> = {
character: "Character",
weapon: "Weapon",
@@ -43,6 +53,7 @@ export function GlossaryManager({
const [item, setItem] = useState<CatalogItem | null>(null);
const [alias, setAlias] = useState("");
const [query, setQuery] = useState("");
const [page, setPage] = useState(1);
const itemsByKey = useMemo(() => new Map(
Object.entries(catalogs).flatMap(([catalogKind, items]) =>
items.map((catalogItem) => [`${catalogKind}:${catalogItem.key}`, catalogItem] as const),
@@ -52,6 +63,10 @@ export function GlossaryManager({
(entry) => `${entry.alias} ${itemsByKey.get(`${entry.kind}:${entry.catalogKey}`)?.name ?? entry.catalogKey}`,
(entry) => [entry.alias, itemsByKey.get(`${entry.kind}:${entry.catalogKey}`)?.name ?? ""]);
const visibleAliases = search.items;
const totalPages = Math.max(1, Math.ceil(visibleAliases.length / PAGE_SIZE));
const currentPage = Math.min(page, totalPages);
const paginatedAliases = visibleAliases.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);
const pages = paginationItems(currentPage, totalPages);
const submit = () => startTransition(async () => {
const result = await addGlossaryAlias({ kind, catalogKey: item?.key, alias });
@@ -142,11 +157,14 @@ export function GlossaryManager({
<FieldLabel htmlFor="glossary-search">ค้นหา</FieldLabel>
<div className="relative">
<SearchIcon className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
<Input id="glossary-search" className="pl-9" value={query} onChange={(event) => setQuery(event.target.value)} />
<Input id="glossary-search" className="pl-9" value={query} onChange={(event) => {
setQuery(event.target.value);
setPage(1);
}} />
</div>
</Field>
{visibleAliases.map((entry) => {
{paginatedAliases.map((entry) => {
const catalogItem = itemsByKey.get(`${entry.kind}:${entry.catalogKey}`);
const name = catalogItem?.name;
return (
@@ -175,6 +193,64 @@ export function GlossaryManager({
</div>
);
})}
{totalPages > 1 ? (
<Pagination className="pt-2">
<PaginationContent className="grid w-full grid-cols-[1fr_auto_1fr]">
<PaginationItem className="justify-self-start">
<PaginationPrevious
href="#"
text="ก่อนหน้า"
aria-disabled={currentPage === 1}
tabIndex={currentPage === 1 ? -1 : undefined}
className={cn(currentPage === 1 && "pointer-events-none opacity-50")}
onClick={(event) => {
event.preventDefault();
setPage(currentPage - 1);
}}
/>
</PaginationItem>
<PaginationItem>
<ul className="flex items-center gap-0.5">
{pages.map((pageItem) => (
typeof pageItem === "number" ? (
<PaginationItem key={pageItem}>
<PaginationLink
href="#"
isActive={pageItem === currentPage}
aria-label={`ไปหน้า ${pageItem}`}
onClick={(event) => {
event.preventDefault();
setPage(pageItem);
}}
>
{pageItem}
</PaginationLink>
</PaginationItem>
) : (
<PaginationItem key={pageItem}>
<PaginationEllipsis />
</PaginationItem>
)
))}
</ul>
</PaginationItem>
<PaginationItem className="justify-self-end">
<PaginationNext
href="#"
text="ถัดไป"
aria-disabled={currentPage === totalPages}
tabIndex={currentPage === totalPages ? -1 : undefined}
className={cn(currentPage === totalPages && "pointer-events-none opacity-50")}
onClick={(event) => {
event.preventDefault();
setPage(currentPage + 1);
}}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
) : null}
</CardContent>
</Card>
</div>