ERP-node/frontend/components/admin/UserTable.tsx

249 lines
8.1 KiB
TypeScript
Raw Normal View History

2025-08-26 09:56:45 +09:00
import { Key, History } from "lucide-react";
2025-08-21 09:41:46 +09:00
import { useState } from "react";
import { User } from "@/types/user";
import { USER_TABLE_COLUMNS } from "@/constants/user";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { PaginationInfo } from "@/components/common/Pagination";
import { UserStatusConfirmDialog } from "./UserStatusConfirmDialog";
import { UserHistoryModal } from "./UserHistoryModal";
interface UserTableProps {
users: User[];
isLoading: boolean;
paginationInfo: PaginationInfo;
onStatusToggle: (user: User, newStatus: string) => void;
onPasswordReset: (userId: string, userName: string) => void;
}
/**
*
*/
export function UserTable({ users, isLoading, paginationInfo, onStatusToggle, onPasswordReset }: UserTableProps) {
// 확인 모달 상태 관리
const [confirmDialog, setConfirmDialog] = useState<{
isOpen: boolean;
user: User | null;
newStatus: string;
}>({
isOpen: false,
user: null,
newStatus: "",
});
// 히스토리 모달 상태 관리
const [historyModal, setHistoryModal] = useState<{
isOpen: boolean;
userId: string;
userName: string;
}>({
isOpen: false,
userId: "",
userName: "",
});
// NO 컬럼 계산 함수 (페이지네이션 고려)
const getRowNumber = (index: number) => {
return paginationInfo.startItem + index;
};
// 날짜 포맷팅 함수
const formatDate = (dateString: string) => {
if (!dateString) return "-";
return dateString.split(" ")[0]; // "2024-01-15 14:30:00" -> "2024-01-15"
};
// 상태 토글 핸들러 (확인 모달 표시)
const handleStatusToggle = (user: User, checked: boolean) => {
const newStatus = checked ? "active" : "inactive";
setConfirmDialog({
isOpen: true,
user,
newStatus,
});
};
// 상태 변경 확인
const handleConfirmStatusChange = () => {
if (confirmDialog.user) {
onStatusToggle(confirmDialog.user, confirmDialog.newStatus);
}
setConfirmDialog({ isOpen: false, user: null, newStatus: "" });
};
// 상태 변경 취소
const handleCancelStatusChange = () => {
setConfirmDialog({ isOpen: false, user: null, newStatus: "" });
};
// 변경이력 모달 열기
const handleOpenHistoryModal = (user: User) => {
setHistoryModal({
isOpen: true,
2025-08-25 18:30:07 +09:00
userId: user.userId,
userName: user.userName || user.userId,
2025-08-21 09:41:46 +09:00
});
};
// 변경이력 모달 닫기
const handleCloseHistoryModal = () => {
setHistoryModal({
isOpen: false,
userId: "",
userName: "",
});
};
// 로딩 상태 렌더링
if (isLoading) {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
{USER_TABLE_COLUMNS.map((column) => (
<TableHead key={column.key} style={{ width: column.width }}>
{column.label}
</TableHead>
))}
<TableHead className="w-[200px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{Array.from({ length: 10 }).map((_, index) => (
<TableRow key={index}>
{USER_TABLE_COLUMNS.map((column) => (
<TableCell key={column.key}>
<div className="bg-muted h-4 animate-pulse rounded"></div>
</TableCell>
))}
<TableCell>
<div className="flex gap-1">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="bg-muted h-8 w-8 animate-pulse rounded"></div>
))}
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
// 데이터가 없을 때
if (users.length === 0) {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
{USER_TABLE_COLUMNS.map((column) => (
<TableHead key={column.key} style={{ width: column.width }}>
{column.label}
</TableHead>
))}
<TableHead className="w-[200px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell colSpan={USER_TABLE_COLUMNS.length + 1} className="h-24 text-center">
<div className="text-muted-foreground flex flex-col items-center justify-center">
<p> .</p>
</div>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
);
}
// 실제 데이터 렌더링
return (
<div className="rounded-md border">
<Table>
<TableHeader className="bg-muted">
<TableRow>
{USER_TABLE_COLUMNS.map((column) => (
<TableHead key={column.key} style={{ width: column.width }}>
{column.label}
</TableHead>
))}
<TableHead className="w-[200px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user, index) => (
2025-08-25 18:30:07 +09:00
<TableRow key={`${user.userId}-${index}`} className="hover:bg-muted/50">
2025-08-21 09:41:46 +09:00
<TableCell className="font-mono text-sm font-medium">{getRowNumber(index)}</TableCell>
2025-08-25 13:12:17 +09:00
<TableCell className="font-mono text-sm">{user.sabun || "-"}</TableCell>
<TableCell className="font-medium">{user.companyCode || "-"}</TableCell>
<TableCell className="font-medium">{user.deptName || "-"}</TableCell>
<TableCell className="font-medium">{user.positionName || "-"}</TableCell>
<TableCell className="font-mono">{user.userId}</TableCell>
<TableCell className="font-medium">{user.userName}</TableCell>
<TableCell>{user.tel || user.cellPhone || "-"}</TableCell>
2025-08-21 09:41:46 +09:00
<TableCell className="max-w-[200px] truncate" title={user.email}>
{user.email || "-"}
</TableCell>
2025-08-25 18:30:07 +09:00
<TableCell>{formatDate(user.regDate || "")}</TableCell>
2025-08-21 09:41:46 +09:00
<TableCell>
<div className="flex items-center gap-2">
<Switch
checked={user.status === "active"}
onCheckedChange={(checked) => handleStatusToggle(user, checked)}
2025-08-25 13:12:17 +09:00
aria-label={`${user.userName} 상태 토글`}
2025-08-21 09:41:46 +09:00
/>
</div>
</TableCell>
<TableCell>
<div className="flex gap-1">
<Button
variant="ghost"
size="sm"
2025-08-25 13:12:17 +09:00
onClick={() => onPasswordReset(user.userId, user.userName || user.userId)}
2025-08-21 09:41:46 +09:00
className="h-8 w-8 p-0"
title="비밀번호 초기화"
>
<Key className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => handleOpenHistoryModal(user)}
className="h-8 w-8 p-0"
title="변경이력 조회"
>
<History className="h-4 w-4" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{/* 상태 변경 확인 모달 */}
<UserStatusConfirmDialog
user={confirmDialog.user}
newStatus={confirmDialog.newStatus}
isOpen={confirmDialog.isOpen}
onConfirm={handleConfirmStatusChange}
onCancel={handleCancelStatusChange}
/>
{/* 사용자 변경이력 모달 */}
<UserHistoryModal
isOpen={historyModal.isOpen}
onClose={handleCloseHistoryModal}
userId={historyModal.userId}
userName={historyModal.userName}
/>
</div>
);
}