Skip to content
Snippets Groups Projects
Commit 36d0ca64 authored by 한동현's avatar 한동현
Browse files

feat: 대시보드 페이지 API 연동

parent 95266fab
No related branches found
No related tags found
No related merge requests found
import { useEffect, useState } from 'react';
import { Link } from 'react-router';
import { Split, ShieldCheck, Server, ArrowRight } from 'lucide-react';
import { toast } from 'sonner';
import { useAuthStore } from '@/stores/authStore';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { Badge } from '@/components/ui/badge';
import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardDescription } from '@/components/ui/card';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Log, LogListResponse } from '@/types/log';
const logs = [
{
id: 1,
timestamp: '2021-09-01 12:00:00',
action: '웹 라우팅 설정 변경 (console.ajou.app)',
username: 'admin',
},
{
id: 2,
timestamp: '2021-09-01 12:01:00',
action: 'SSL 인증서 발급 (*.ajou.app)',
username: 'admin',
},
{
id: 3,
timestamp: '2021-09-01 13:00:00',
action: 'SSH 포트포워딩 설정 변경 (10.16.1.10)',
username: 'admin',
},
{
id: 4,
timestamp: '2021-09-02 12:00:00',
action: '웹 라우팅 설정 변경 (blog.ajou.app)',
username: 'hando1220',
},
];
interface ProjectInfo {
routing: number;
forwarding: number;
certificate: number;
}
const ACTION = {
CREATE: '생성',
UPDATE: '수정',
DELETE: '삭제',
};
const TYPE = {
ROUTING: '라우팅',
CERTIFICATE: '인증서',
FORWARDING: '포워딩',
};
export default function Home() {
const { authFetch, selectedProject } = useAuthStore();
const [logs, setLogs] = useState<Log[] | null>(null);
const [projectInfo, setProjectInfo] = useState<ProjectInfo | null>(null);
useEffect(() => {
authFetch(`/api/main?projectId=${selectedProject?.id}`)
.then((response) => {
if (!response.ok) throw new Error(`프로젝트 정보 조회 실패: (${response.status})`);
return response.json();
})
.then((data) => {
setProjectInfo(data);
})
.catch((error) => {
console.error(error);
toast.error('프로젝트 정보를 조회할 수 없습니다.');
});
}, [authFetch, selectedProject]);
useEffect(() => {
authFetch(`/api/logs?projectId=${selectedProject?.id}&size=5`)
.then((response): Promise<LogListResponse> => {
if (!response.ok) throw new Error(`로그 목록 조회 실패: (${response.status})`);
return response.json();
})
.then(({ contents }) => {
setLogs(contents);
})
.catch((error) => {
console.error(error);
toast.error('로그 정보를 조회할 수 없습니다.');
});
}, [authFetch, selectedProject]);
return (
<div className="flex flex-1 flex-col gap-4 p-6">
<h1 className="scroll-m-20 text-3xl font-semibold first:mt-0 mb-2">Aolda Proxy Manager</h1>
......@@ -40,14 +74,22 @@ export default function Home() {
<CardTitle className="text-xl">웹 라우팅</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-row justify-center items-center gap-2 font-bold text-4xl">
<Split className="size-8" /> 0
<div className="flex flex-row justify-center items-center gap-4 font-bold text-4xl">
{projectInfo === null ? (
<Skeleton className="w-22 h-10 rounded-full" />
) : (
<>
<Split className="size-8" /> {projectInfo.routing}
</>
)}
</div>
</CardContent>
<CardFooter>
<Button variant="ghost" className="ml-auto">
관리하기 <ArrowRight />
</Button>
<Link className="ml-auto" to="/routing">
<Button variant="ghost">
관리하기 <ArrowRight />
</Button>
</Link>
</CardFooter>
</Card>
<Card>
......@@ -55,14 +97,22 @@ export default function Home() {
<CardTitle className="text-xl">SSL 인증서</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-row justify-center items-center gap-2 font-bold text-4xl">
<ShieldCheck className="size-8" /> 0
<div className="flex flex-row justify-center items-center gap-4 font-bold text-4xl">
{projectInfo === null ? (
<Skeleton className="w-22 h-10 rounded-full" />
) : (
<>
<ShieldCheck className="size-8" /> {projectInfo.certificate}
</>
)}
</div>
</CardContent>
<CardFooter>
<Button variant="ghost" className="ml-auto">
관리하기 <ArrowRight />
</Button>
<Link className="ml-auto" to="/certificate">
<Button variant="ghost">
관리하기 <ArrowRight />
</Button>
</Link>
</CardFooter>
</Card>
<Card>
......@@ -70,14 +120,22 @@ export default function Home() {
<CardTitle className="text-xl">SSH 포트포워딩</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-row justify-center items-center gap-2 font-bold text-4xl">
<Server className="size-8" /> 0
<div className="flex flex-row justify-center items-center gap-4 font-bold text-4xl">
{projectInfo === null ? (
<Skeleton className="w-22 h-10 rounded-full" />
) : (
<>
<Server className="size-8" /> {projectInfo.certificate}
</>
)}
</div>
</CardContent>
<CardFooter>
<Button variant="ghost" className="ml-auto">
관리하기 <ArrowRight />
</Button>
<Link className="ml-auto" to="/forwarding">
<Button variant="ghost">
관리하기 <ArrowRight />
</Button>
</Link>
</CardFooter>
</Card>
</div>
......@@ -96,20 +154,54 @@ export default function Home() {
</TableRow>
</TableHeader>
<TableBody>
{logs.map((log) => (
<TableRow key={log.id}>
<TableCell className="font-medium">{log.timestamp}</TableCell>
<TableCell>{log.action}</TableCell>
<TableCell className="text-center">{log.username}</TableCell>
{logs === null ? (
<>
<TableRow>
<TableCell colSpan={3}>
<Skeleton className="w-full h-[1rem] my-2 rounded-full" />
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>
<Skeleton className="w-full h-[1rem] my-2 rounded-full" />
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={3}>
<Skeleton className="w-full h-[1rem] my-2 rounded-full" />
</TableCell>
</TableRow>
</>
) : logs.length === 0 ? (
<TableRow>
<TableCell colSpan={3} className="text-center text-muted-foreground">
조회된 로그가 없습니다.
</TableCell>
</TableRow>
))}
) : (
logs.map((log) => (
<TableRow key={log.id}>
<TableCell>{log.createdAt}</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Badge variant="default">{TYPE[log.type]}</Badge>
<Badge variant="secondary">{ACTION[log.action]}</Badge>
<div>{log.description.split('\n').join(' / ')}</div>
</div>
</TableCell>
<TableCell className="truncate max-w-32 text-center">{log.user.name}</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</CardContent>
<CardFooter>
<Button variant="ghost" className="ml-auto">
모든 기록 보기 <ArrowRight />
</Button>
<Link className="ml-auto" to="/log">
<Button variant="ghost">
모든 기록 보기 <ArrowRight />
</Button>
</Link>
</CardFooter>
</Card>
</div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment