- Integrated multi-language functionality across various user management components, including user list, roles list, and user authorization pages, enhancing accessibility for diverse users. - Updated UI elements to utilize translation keys, ensuring that all text is dynamically translated based on user preferences. - Improved error handling messages to be localized, providing a better user experience in case of issues. These changes significantly enhance the usability and internationalization of the user management features, making the application more inclusive.
165 lines
5.3 KiB
TypeScript
165 lines
5.3 KiB
TypeScript
import { Edit, Trash2, HardDrive, FileText, Users } from "lucide-react";
|
|
import { Company } from "@/types/company";
|
|
import { Button } from "@/components/ui/button";
|
|
import { ResponsiveDataView, RDVColumn, RDVCardField } from "@/components/common/ResponsiveDataView";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
interface CompanyTableProps {
|
|
companies: Company[];
|
|
isLoading: boolean;
|
|
onEdit: (company: Company) => void;
|
|
onDelete: (company: Company) => void;
|
|
t?: (key: string, params?: Record<string, string | number>) => string;
|
|
}
|
|
|
|
/**
|
|
* 회사 목록 테이블 컴포넌트
|
|
*/
|
|
export function CompanyTable({ companies, isLoading, onEdit, onDelete, t }: CompanyTableProps) {
|
|
const _t = t || ((key: string, params?: Record<string, string | number>) => {
|
|
const defaults: Record<string, string> = {
|
|
"company.table.companyCode": "회사코드",
|
|
"company.table.companyName": "회사명",
|
|
"company.table.writer": "등록자",
|
|
"company.table.diskUsage": "디스크 사용량",
|
|
"company.table.diskNoInfo": "정보 없음",
|
|
"company.table.fileCount": "{count}개 파일",
|
|
"company.table.actions": "작업",
|
|
"company.table.empty": "등록된 회사가 없습니다.",
|
|
"company.table.cardWriter": "작성자",
|
|
"company.table.cardDiskUsage": "디스크 사용량",
|
|
"company.table.actionDept": "부서관리",
|
|
"company.table.actionEdit": "수정",
|
|
"company.table.actionDelete": "삭제",
|
|
};
|
|
let text = defaults[key] || key;
|
|
if (params) {
|
|
Object.entries(params).forEach(([k, v]) => {
|
|
text = text.replace(`{${k}}`, String(v));
|
|
});
|
|
}
|
|
return text;
|
|
});
|
|
const router = useRouter();
|
|
|
|
// 부서 관리 페이지로 이동
|
|
const handleManageDepartments = (company: Company) => {
|
|
router.push(`/admin/userMng/companyList/${company.company_code}/departments`);
|
|
};
|
|
|
|
// 디스크 사용량 포맷팅 함수
|
|
const formatDiskUsage = (company: Company) => {
|
|
if (!company.diskUsage) {
|
|
return (
|
|
<div className="text-muted-foreground flex items-center gap-1">
|
|
<HardDrive className="h-3 w-3" />
|
|
<span className="text-xs">{_t("company.table.diskNoInfo")}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const { fileCount, totalSizeMB } = company.diskUsage;
|
|
|
|
return (
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-1">
|
|
<FileText className="text-primary h-3 w-3" />
|
|
<span className="text-xs font-medium">{_t("company.table.fileCount", { count: fileCount })}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<HardDrive className="text-primary h-3 w-3" />
|
|
<span className="text-xs">{totalSizeMB.toFixed(1)} MB</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// 데스크톱 테이블 컬럼 정의
|
|
const columns: RDVColumn<Company>[] = [
|
|
{
|
|
key: "company_code",
|
|
label: _t("company.table.companyCode"),
|
|
width: "12%",
|
|
render: (value) => <span className="font-mono">{value}</span>,
|
|
},
|
|
{
|
|
key: "company_name",
|
|
label: _t("company.table.companyName"),
|
|
render: (value) => <span className="font-medium">{value}</span>,
|
|
},
|
|
{
|
|
key: "writer",
|
|
label: _t("company.table.writer"),
|
|
width: "15%",
|
|
},
|
|
{
|
|
key: "diskUsage",
|
|
label: _t("company.table.diskUsage"),
|
|
width: "15%",
|
|
hideOnMobile: true,
|
|
render: (_value, row) => formatDiskUsage(row),
|
|
},
|
|
];
|
|
|
|
// 모바일 카드 필드 정의
|
|
const cardFields: RDVCardField<Company>[] = [
|
|
{
|
|
label: _t("company.table.cardWriter"),
|
|
render: (company) => <span className="font-medium">{company.writer}</span>,
|
|
},
|
|
{
|
|
label: _t("company.table.cardDiskUsage"),
|
|
render: (company) => formatDiskUsage(company),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<ResponsiveDataView<Company>
|
|
data={companies}
|
|
columns={columns}
|
|
keyExtractor={(c) => c.regdate + c.company_code}
|
|
isLoading={isLoading}
|
|
emptyMessage={_t("company.table.empty")}
|
|
skeletonCount={10}
|
|
cardTitle={(c) => c.company_name}
|
|
cardSubtitle={(c) => <span className="font-mono">{c.company_code}</span>}
|
|
cardFields={cardFields}
|
|
actionsLabel={_t("company.table.actions")}
|
|
actionsWidth="12%"
|
|
tableContainerClassName="!block"
|
|
cardContainerClassName="!hidden"
|
|
renderActions={(company) => (
|
|
<>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => handleManageDepartments(company)}
|
|
className="h-8 w-8"
|
|
aria-label={_t("company.table.actionDept")}
|
|
>
|
|
<Users className="h-4 w-4" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onEdit(company)}
|
|
className="h-8 w-8"
|
|
aria-label={_t("company.table.actionEdit")}
|
|
>
|
|
<Edit className="h-4 w-4" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onDelete(company)}
|
|
className="text-destructive hover:bg-destructive/10 hover:text-destructive h-8 w-8"
|
|
aria-label={_t("company.table.actionDelete")}
|
|
>
|
|
<Trash2 className="h-4 w-4" />
|
|
</Button>
|
|
</>
|
|
)}
|
|
/>
|
|
);
|
|
}
|