mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-02-15 12:51:11 -05:00
111 lines
3.8 KiB
TypeScript
111 lines
3.8 KiB
TypeScript
'use client';
|
|
|
|
import { ProList } from '@/components/pro-list';
|
|
import { queryDocumentDetail, queryDocumentList } from '@/services/user/document';
|
|
import { Markdown } from '@repo/ui/markdown';
|
|
import { formatDate } from '@repo/ui/utils';
|
|
import { Button } from '@shadcn/ui/button';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@shadcn/ui/card';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { ChevronLeft } from 'lucide-react';
|
|
import { useTranslations } from 'next-intl';
|
|
import { Fragment, useState } from 'react';
|
|
|
|
export default function Page() {
|
|
const t = useTranslations('document');
|
|
const [tags, setTags] = useState<string[]>([]);
|
|
const [selected, setSelected] = useState<number>();
|
|
|
|
const { data } = useQuery({
|
|
enabled: !!selected,
|
|
queryKey: ['queryDocumentDetail', selected],
|
|
queryFn: async () => {
|
|
const { data } = await queryDocumentDetail({
|
|
id: selected!,
|
|
});
|
|
return data.data;
|
|
},
|
|
});
|
|
|
|
return (
|
|
<Fragment>
|
|
{selected ? (
|
|
<Card>
|
|
<CardHeader className='pb-2'>
|
|
<div className='flex items-center justify-between'>
|
|
<Button variant='outline' onClick={() => setSelected(undefined)}>
|
|
<ChevronLeft className='size-4' />
|
|
{t('back')}
|
|
</Button>
|
|
<CardTitle className='font-medium'>{data?.title}</CardTitle>
|
|
<CardDescription>{formatDate(data?.updated_at)}</CardDescription>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Markdown>{data?.content || ''}</Markdown>
|
|
</CardContent>
|
|
</Card>
|
|
) : (
|
|
<ProList<API.DocumentItem, { tag: string }>
|
|
params={[
|
|
{
|
|
key: 'tag',
|
|
placeholder: t('category'),
|
|
options: tags.map((item) => ({
|
|
label: item,
|
|
value: item,
|
|
})),
|
|
},
|
|
]}
|
|
request={async (_, filter) => {
|
|
const response = await queryDocumentList();
|
|
const list = response.data.data?.list || [];
|
|
setTags(
|
|
Array.from(new Set(list.reduce((acc: string[], item) => acc.concat(item.tags), []))),
|
|
);
|
|
const filterList = list.filter((item) =>
|
|
filter.tag ? item.tags.includes(filter.tag) : true,
|
|
);
|
|
return {
|
|
list: filterList,
|
|
total: filterList.length || 0,
|
|
};
|
|
}}
|
|
renderItem={(item) => {
|
|
return (
|
|
<Card className='overflow-hidden'>
|
|
<CardHeader className='bg-muted/50 flex flex-row items-center justify-between gap-2 space-y-0 p-3'>
|
|
<CardTitle>{item.title}</CardTitle>
|
|
<CardDescription>
|
|
<Button
|
|
size='sm'
|
|
onClick={() => {
|
|
setSelected(item.id);
|
|
}}
|
|
>
|
|
{t('read')}
|
|
</Button>
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<CardContent className='p-3 text-sm'>
|
|
<ul className='grid gap-3 *:flex *:flex-col lg:grid-cols-2'>
|
|
<li>
|
|
<span className='text-muted-foreground'>{t('tags')}</span>
|
|
<span>{item.tags.join(', ')}</span>
|
|
</li>
|
|
<li className='font-semibold'>
|
|
<span className='text-muted-foreground'>{t('updatedAt')}</span>
|
|
<time>{formatDate(item.updated_at)}</time>
|
|
</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}}
|
|
/>
|
|
)}
|
|
</Fragment>
|
|
);
|
|
}
|