refactor: UI 컴포넌트 추상화 및 입금/출금 등록 버튼 추가

- 입금관리, 출금관리 리스트에 등록 버튼 추가
- skeleton, confirm-dialog, empty-state, status-badge UI 컴포넌트 추가
- document-system 컴포넌트 추상화 (ApprovalLine, DocumentHeader 등)
- 여러 페이지 컴포넌트 리팩토링 및 코드 정리

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-22 17:21:42 +09:00
parent 777dccc7bd
commit 269b901e64
86 changed files with 3761 additions and 2614 deletions

View File

@@ -7,16 +7,7 @@ import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { TableRow, TableCell } from '@/components/ui/table';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
import {
UniversalListPage,
type UniversalListConfig,
@@ -379,29 +370,21 @@ export function CardManagement({ initialData }: CardManagementProps) {
},
renderDialogs: () => (
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription>
&quot;{cardToDelete?.cardName}&quot; ?
<br />
<span className="text-destructive">
.
</span>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
onClick={handleDeleteCard}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<DeleteConfirmDialog
open={deleteDialogOpen}
onOpenChange={setDeleteDialogOpen}
onConfirm={handleDeleteCard}
title="카드 삭제"
description={
<>
&quot;{cardToDelete?.cardName}&quot; ?
<br />
<span className="text-destructive">
.
</span>
</>
}
/>
),
}), [
cards,

View File

@@ -8,16 +8,7 @@ import { DepartmentStats } from './DepartmentStats';
import { DepartmentToolbar } from './DepartmentToolbar';
import { DepartmentTree } from './DepartmentTree';
import { DepartmentDialog } from './DepartmentDialog';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
import type { Department } from './types';
import { countAllDepartments, getAllDepartmentIds, findDepartmentById } from './types';
import {
@@ -318,29 +309,23 @@ export function DepartmentManagement() {
/>
{/* 삭제 확인 다이얼로그 */}
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription>
{isBulkDelete
? `선택한 부서 ${selectedIds.size}개를 삭제하시겠습니까?`
: `"${departmentToDelete?.name}" 부서를 삭제하시겠습니까?`
}
<br />
<span className="text-destructive">
() .
</span>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction onClick={confirmDelete} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<DeleteConfirmDialog
open={deleteDialogOpen}
onOpenChange={setDeleteDialogOpen}
description={
<>
{isBulkDelete
? `선택한 부서 ${selectedIds.size}개를 삭제하시겠습니까?`
: `"${departmentToDelete?.name}" 부서를 삭제하시겠습니까?`
}
<br />
<span className="text-destructive">
() .
</span>
</>
}
onConfirm={confirmDelete}
/>
</PageLayout>
);
}

View File

@@ -8,16 +8,7 @@ import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { TableRow, TableCell } from '@/components/ui/table';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
import {
UniversalListPage,
type UniversalListConfig,
@@ -726,37 +717,22 @@ export function EmployeeManagement() {
/>
{/* 삭제 확인 다이얼로그 */}
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription>
&quot;{employeeToDelete?.name}&quot; ?
<br />
<span className="text-destructive">
.
</span>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={isDeleting}></AlertDialogCancel>
<AlertDialogAction
onClick={handleDeleteEmployee}
disabled={isDeleting}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{isDeleting ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
...
</>
) : (
'삭제'
)}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<DeleteConfirmDialog
open={deleteDialogOpen}
onOpenChange={setDeleteDialogOpen}
onConfirm={handleDeleteEmployee}
title="사원 삭제"
description={
<>
&quot;{employeeToDelete?.name}&quot; ?
<br />
<span className="text-destructive">
.
</span>
</>
}
loading={isDeleting}
/>
</>
),
}), [

View File

@@ -28,16 +28,7 @@ import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Badge } from '@/components/ui/badge';
import { TableRow, TableCell } from '@/components/ui/table';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { ConfirmDialog } from '@/components/ui/confirm-dialog';
import {
UniversalListPage,
type UniversalListConfig,
@@ -793,43 +784,26 @@ export function VacationManagement() {
/>
{/* 승인 확인 다이얼로그 */}
<AlertDialog open={approveDialogOpen} onOpenChange={setApproveDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription>
{selectedItems.size} ?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction onClick={handleApproveConfirm}>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<ConfirmDialog
open={approveDialogOpen}
onOpenChange={setApproveDialogOpen}
title="휴가 승인"
description={`정말 ${selectedItems.size}건을 승인하시겠습니까?`}
confirmText="승인"
variant="success"
onConfirm={handleApproveConfirm}
/>
{/* 거절 확인 다이얼로그 */}
<AlertDialog open={rejectDialogOpen} onOpenChange={setRejectDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription>
{selectedItems.size} ?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
onClick={handleRejectConfirm}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<ConfirmDialog
open={rejectDialogOpen}
onOpenChange={setRejectDialogOpen}
title="휴가 거절"
description={`정말 ${selectedItems.size}건을 거절하시겠습니까?`}
confirmText="거절"
variant="destructive"
onConfirm={handleRejectConfirm}
/>
</>
),
}), [