New admin section.

This commit is contained in:
Mike Cao 2025-07-08 18:40:47 -07:00
parent b78ff3b477
commit ce1f6c3618
44 changed files with 515 additions and 157 deletions

View file

@ -1,13 +1,15 @@
import { ReactNode, useState } from 'react';
import { ReactNode, useState, useCallback } from 'react';
import { SearchField, Row, Column } from '@umami/react-zen';
import { UseQueryResult } from '@tanstack/react-query';
import { useMessages, useNavigation } from '@/components/hooks';
import { Pager } from '@/components/common/Pager';
import { LoadingPanel } from '@/components/common/LoadingPanel';
import { PageResult } from '@/lib/types';
const DEFAULT_SEARCH_DELAY = 600;
export interface DataGridProps {
queryResult: any;
query: UseQueryResult<PageResult<any>, any>;
searchDelay?: number;
allowSearch?: boolean;
allowPaging?: boolean;
@ -17,7 +19,7 @@ export interface DataGridProps {
}
export function DataGrid({
queryResult,
query,
searchDelay = 600,
allowSearch,
allowPaging = true,
@ -26,20 +28,23 @@ export function DataGrid({
children,
}: DataGridProps) {
const { formatMessage, labels } = useMessages();
const { data, error, isLoading, isFetching, setParams } = queryResult;
const { router, updateParams } = useNavigation();
const [search, setSearch] = useState('');
const { data, error, isLoading, isFetching } = query;
const { router, updateParams, query: queryParams } = useNavigation();
const [search, setSearch] = useState(queryParams?.saerch || data?.search || '');
const handleSearch = (search: string) => {
setSearch(search);
setParams(params => ({ ...params, search }));
router.push(updateParams({ search }));
const handleSearch = (value: string) => {
if (value !== search) {
setSearch(value);
router.push(updateParams({ search: value, page: 1 }));
}
};
const handlePageChange = (page: number) => {
setParams(params => ({ ...params, page }));
router.push(updateParams({ page }));
};
const handlePageChange = useCallback(
(page: number) => {
router.push(updateParams({ search, page }));
},
[search],
);
return (
<Column gap="4" minHeight="300px">

View file

@ -17,13 +17,20 @@ export function LinkButton({
scroll = true,
target,
children,
isDisabled,
...props
}: LinkButtonProps) {
const { dir } = useLocale();
return (
<Button {...props} variant={variant} asChild>
<Link href={href} dir={dir} scroll={scroll} target={target}>
<Button {...props} variant={variant} isDisabled={isDisabled} asChild>
<Link
href={href}
dir={dir}
scroll={scroll}
target={target}
style={{ pointerEvents: isDisabled ? 'none' : undefined }}
>
{children}
</Link>
</Button>

View file

@ -34,9 +34,14 @@ export function Pager({ page, pageSize, count, onPageChange }: PagerProps) {
return (
<Row alignItems="center" justifyContent="space-between" gap="3" flexGrow={1}>
<Text>{formatMessage(labels.numberOfRecords, { x: count })}</Text>
<Text>{formatMessage(labels.numberOfRecords, { x: count.toLocaleString() })}</Text>
<Row alignItems="center" justifyContent="flex-end" gap="3">
<Text>{formatMessage(labels.pageOf, { current: page, total: maxPage })}</Text>
<Text>
{formatMessage(labels.pageOf, {
current: page.toLocaleString(),
total: maxPage.toLocaleString(),
})}
</Text>
<Button onPress={() => handlePageChange(-1)} isDisabled={firstPage}>
<Icon size="sm" rotate={180}>
<Chevron />