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

191 lines
5.5 KiB
TypeScript
Raw Normal View History

2025-10-27 16:40:59 +09:00
"use client";
import React from "react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Shield, ShieldCheck, User as UserIcon, Users, Building2 } from "lucide-react";
import { ResponsiveDataView, RDVColumn, RDVCardField } from "@/components/common/ResponsiveDataView";
2025-10-27 16:40:59 +09:00
interface UserAuthTableProps {
users: any[];
isLoading: boolean;
paginationInfo: {
currentPage: number;
pageSize: number;
totalItems: number;
totalPages: number;
};
onEditAuth: (user: any) => void;
onPageChange: (page: number) => void;
}
/**
*
*
*
*/
export function UserAuthTable({ users, isLoading, paginationInfo, onEditAuth, onPageChange }: UserAuthTableProps) {
// 권한 레벨 표시
const getUserTypeInfo = (userType: string) => {
switch (userType) {
case "SUPER_ADMIN":
return {
label: "최고 관리자",
icon: <ShieldCheck className="h-3 w-3" />,
className: "bg-primary/20 text-primary border-primary/30",
2025-10-27 16:40:59 +09:00
};
case "COMPANY_ADMIN":
return {
label: "회사 관리자",
icon: <Building2 className="h-3 w-3" />,
className: "bg-primary/20 text-primary border-primary/30",
2025-10-27 16:40:59 +09:00
};
case "USER":
return {
label: "일반 사용자",
icon: <UserIcon className="h-3 w-3" />,
className: "bg-muted/50 text-muted-foreground border-border",
2025-10-27 16:40:59 +09:00
};
case "GUEST":
return {
label: "게스트",
icon: <Users className="h-3 w-3" />,
className: "bg-success/20 text-success border-success/30",
2025-10-27 16:40:59 +09:00
};
case "PARTNER":
return {
label: "협력업체",
icon: <Shield className="h-3 w-3" />,
className: "bg-warning/20 text-warning border-warning/30",
2025-10-27 16:40:59 +09:00
};
default:
return {
label: userType || "미지정",
icon: <UserIcon className="h-3 w-3" />,
className: "bg-muted/50 text-muted-foreground border-border",
2025-10-27 16:40:59 +09:00
};
}
};
// 행 번호 계산
const getRowNumber = (index: number) => {
return (paginationInfo.currentPage - 1) * paginationInfo.pageSize + index + 1;
};
// 데스크톱 테이블 컬럼 정의
const columns: RDVColumn<any>[] = [
{
key: "no",
label: "No",
width: "80px",
className: "text-center",
render: (_value, _row, index) => <span>{getRowNumber(index)}</span>,
},
{
key: "userId",
label: "사용자 ID",
render: (value) => <span className="font-mono">{value}</span>,
},
{
key: "userName",
label: "사용자명",
},
{
key: "companyName",
label: "회사",
hideOnMobile: true,
render: (_value, row) => <span>{row.companyName || row.companyCode}</span>,
},
{
key: "deptName",
label: "부서",
hideOnMobile: true,
render: (value) => <span>{value || "-"}</span>,
},
{
key: "userType",
label: "현재 권한",
className: "text-center",
render: (_value, row) => {
const typeInfo = getUserTypeInfo(row.userType);
return (
<Badge variant="outline" className={`gap-1 ${typeInfo.className}`}>
{typeInfo.icon}
{typeInfo.label}
</Badge>
);
},
},
];
2025-10-27 16:40:59 +09:00
// 모바일 카드 필드 정의
const cardFields: RDVCardField<any>[] = [
{
label: "회사",
render: (user) => <span>{user.companyName || user.companyCode}</span>,
},
{
label: "부서",
render: (user) => <span>{user.deptName || "-"}</span>,
},
];
2025-10-27 16:40:59 +09:00
return (
<div className="space-y-4">
<ResponsiveDataView<any>
data={users}
columns={columns}
keyExtractor={(u) => u.userId}
isLoading={isLoading}
emptyMessage="등록된 사용자가 없습니다."
skeletonCount={10}
cardTitle={(u) => u.userName}
cardSubtitle={(u) => <span className="font-mono">{u.userId}</span>}
cardHeaderRight={(u) => {
const typeInfo = getUserTypeInfo(u.userType);
2025-10-27 16:40:59 +09:00
return (
<Badge variant="outline" className={`gap-1 ${typeInfo.className}`}>
{typeInfo.icon}
{typeInfo.label}
</Badge>
2025-10-27 16:40:59 +09:00
);
}}
cardFields={cardFields}
actionsLabel="액션"
actionsWidth="120px"
renderActions={(user) => (
<Button variant="outline" size="sm" onClick={() => onEditAuth(user)} className="h-8 gap-1 text-sm">
<Shield className="h-3 w-3" />
</Button>
)}
/>
2025-10-27 16:40:59 +09:00
{/* 페이지네이션 */}
{paginationInfo.totalPages > 1 && (
<div className="flex items-center justify-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(paginationInfo.currentPage - 1)}
disabled={paginationInfo.currentPage === 1}
>
</Button>
<span className="text-muted-foreground text-sm">
{paginationInfo.currentPage} / {paginationInfo.totalPages}
</span>
<Button
variant="outline"
size="sm"
onClick={() => onPageChange(paginationInfo.currentPage + 1)}
disabled={paginationInfo.currentPage === paginationInfo.totalPages}
>
</Button>
</div>
)}
</div>
);
}