100 lines
2.7 KiB
TypeScript
100 lines
2.7 KiB
TypeScript
// src/pages/IssueViewerPage.tsx
|
|
import { useState, useEffect } from "react";
|
|
import { useParams } from "react-router-dom";
|
|
import { getIssues, type Issue } from "@/services/issue";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { ErrorDisplay } from "@/components/ErrorDisplay";
|
|
|
|
// 테이블 헤더 정의
|
|
const issueTableHeaders = [
|
|
{ key: "title", label: "Title" },
|
|
{ key: "feedbackCount", label: "Feedback Count" },
|
|
{ key: "description", label: "Description" },
|
|
{ key: "status", label: "Status" },
|
|
{ key: "createdAt", label: "Created" },
|
|
{ key: "updatedAt", label: "Updated" },
|
|
{ key: "category", label: "Category" },
|
|
];
|
|
|
|
export function IssueViewerPage() {
|
|
const { projectId } = useParams<{ projectId: string }>();
|
|
const [issues, setIssues] = useState<Issue[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!projectId) return;
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
getIssues(projectId)
|
|
.then(setIssues)
|
|
.catch((err) => setError((err as Error).message))
|
|
.finally(() => setLoading(false));
|
|
}, [projectId]);
|
|
|
|
return (
|
|
<div className="container mx-auto p-4 md:p-8">
|
|
<header className="mb-8">
|
|
<h1 className="text-3xl font-bold tracking-tight">이슈 뷰어</h1>
|
|
<p className="text-muted-foreground mt-1">
|
|
프로젝트: {projectId}
|
|
</p>
|
|
</header>
|
|
|
|
{error && <ErrorDisplay message={error} />}
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>이슈 목록</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{loading && <p className="text-center">로딩 중...</p>}
|
|
{!loading && (
|
|
<div className="border rounded-md">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
{issueTableHeaders.map((header) => (
|
|
<TableHead key={header.key}>{header.label}</TableHead>
|
|
))}
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{issues.length > 0 ? (
|
|
issues.map((issue) => (
|
|
<TableRow key={issue.id}>
|
|
{issueTableHeaders.map((header) => (
|
|
<TableCell key={`${issue.id}-${header.key}`}>
|
|
{String(issue[header.key] ?? "")}
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={issueTableHeaders.length}
|
|
className="h-24 text-center"
|
|
>
|
|
표시할 이슈가 없습니다.
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
} |