feat(WEB): 전체 페이지 ?mode= URL 네비게이션 패턴 적용
- 등록(?mode=new), 상세(?mode=view), 수정(?mode=edit) URL 패턴 일괄 적용
- 중복 패턴 제거: /edit?mode=edit → ?mode=edit (16개 파일)
- 제목 일관성: {기능} 등록/상세/수정 패턴 적용
- 검수 체크리스트 문서 추가 (79개 페이지)
- UniversalListPage, IntegratedDetailTemplate 공통 컴포넌트 개선
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -123,7 +123,7 @@ export default function BiddingDetailForm({
|
||||
const result = await updateBidding(biddingId, formData);
|
||||
if (result.success) {
|
||||
toast.success('수정이 완료되었습니다.');
|
||||
router.push(`/ko/construction/project/bidding/${biddingId}`);
|
||||
router.push(`/ko/construction/project/bidding/${biddingId}?mode=view`);
|
||||
router.refresh();
|
||||
return { success: true };
|
||||
} else {
|
||||
@@ -524,9 +524,10 @@ export default function BiddingDetailForm({
|
||||
);
|
||||
|
||||
// 템플릿 동적 설정
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '상세'/'수정' 자동 추가
|
||||
const dynamicConfig = {
|
||||
...biddingConfig,
|
||||
title: isViewMode ? '입찰 상세' : '입찰 수정',
|
||||
title: '입찰',
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -114,14 +114,14 @@ export default function BiddingListClient({ initialData = [], initialStats }: Bi
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Bidding) => {
|
||||
router.push(`/ko/construction/project/bidding/${item.id}`);
|
||||
router.push(`/ko/construction/project/bidding/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Bidding) => {
|
||||
router.push(`/ko/construction/project/bidding/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -114,7 +114,7 @@ export default function ContractDetailForm({
|
||||
const result = await createContract(formData);
|
||||
if (result.success && result.data) {
|
||||
toast.success(isChangeContract ? '변경 계약서가 생성되었습니다.' : '계약이 생성되었습니다.');
|
||||
router.push(`/ko/construction/project/contract/${result.data.id}`);
|
||||
router.push(`/ko/construction/project/contract/${result.data.id}?mode=view`);
|
||||
router.refresh();
|
||||
return { success: true };
|
||||
}
|
||||
@@ -124,7 +124,7 @@ export default function ContractDetailForm({
|
||||
const result = await updateContract(contractId, formData);
|
||||
if (result.success) {
|
||||
toast.success('수정이 완료되었습니다.');
|
||||
router.push(`/ko/construction/project/contract/${contractId}`);
|
||||
router.push(`/ko/construction/project/contract/${contractId}?mode=view`);
|
||||
router.refresh();
|
||||
return { success: true };
|
||||
}
|
||||
@@ -212,11 +212,12 @@ export default function ContractDetailForm({
|
||||
}, []);
|
||||
|
||||
// 모드별 config 타이틀 동적 설정
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '등록'/'상세' 자동 추가
|
||||
const dynamicConfig = useMemo(() => {
|
||||
if (isCreateMode) {
|
||||
return {
|
||||
...contractConfig,
|
||||
title: isChangeContract ? '변경 계약서 생성' : '계약 등록',
|
||||
title: isChangeContract ? '변경 계약서' : '계약',
|
||||
actions: {
|
||||
...contractConfig.actions,
|
||||
showDelete: false, // create 모드에서는 삭제 버튼 없음
|
||||
@@ -512,7 +513,7 @@ export default function ContractDetailForm({
|
||||
<>
|
||||
<IntegratedDetailTemplate
|
||||
config={dynamicConfig}
|
||||
mode={mode === 'create' ? 'new' : mode}
|
||||
mode={mode}
|
||||
initialData={{}}
|
||||
itemId={contractId}
|
||||
isLoading={false}
|
||||
|
||||
@@ -122,14 +122,14 @@ export default function ContractListClient({ initialData = [], initialStats }: C
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Contract) => {
|
||||
router.push(`/ko/construction/project/contract/${item.id}`);
|
||||
router.push(`/ko/construction/project/contract/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Contract) => {
|
||||
router.push(`/ko/construction/project/contract/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/contract/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -97,7 +97,7 @@ export default function EstimateDetailForm({
|
||||
}, [router]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}?mode=edit`);
|
||||
}, [router, estimateId]);
|
||||
|
||||
// ===== 저장/삭제 핸들러 =====
|
||||
@@ -123,7 +123,7 @@ export default function EstimateDetailForm({
|
||||
if (result.success) {
|
||||
toast.success('수정이 완료되었습니다.');
|
||||
setShowSaveDialog(false);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}`);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}?mode=view`);
|
||||
router.refresh();
|
||||
} else {
|
||||
toast.error(result.error || '저장에 실패했습니다.');
|
||||
@@ -191,7 +191,7 @@ export default function EstimateDetailForm({
|
||||
toast.success('입찰이 등록되었습니다.');
|
||||
setShowBiddingDialog(false);
|
||||
// 입찰 상세 페이지로 이동
|
||||
router.push(`/ko/construction/project/bidding/${result.data.id}`);
|
||||
router.push(`/ko/construction/project/bidding/${result.data.id}?mode=view`);
|
||||
} else {
|
||||
toast.error(result.error || '입찰 등록에 실패했습니다.');
|
||||
}
|
||||
@@ -668,11 +668,12 @@ export default function EstimateDetailForm({
|
||||
]);
|
||||
|
||||
// Edit 모드용 config (타이틀 변경)
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '상세'/'수정' 자동 추가
|
||||
const currentConfig = useMemo(() => {
|
||||
if (isEditMode) {
|
||||
return {
|
||||
...estimateConfig,
|
||||
title: '견적 수정',
|
||||
title: '견적',
|
||||
description: '견적 정보를 수정합니다',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,14 +104,14 @@ export default function EstimateListClient({ initialData = [], initialStats }: E
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Estimate) => {
|
||||
router.push(`/ko/construction/project/bidding/estimates/${item.id}`);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Estimate) => {
|
||||
router.push(`/ko/construction/project/bidding/estimates/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -50,7 +50,7 @@ export function EstimateDocumentModal({
|
||||
const handleEdit = useCallback(() => {
|
||||
if (estimateId) {
|
||||
onClose();
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/estimates/${estimateId}?mode=edit`);
|
||||
}
|
||||
}, [estimateId, onClose, router]);
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ export default function HandoverReportDetailForm({
|
||||
const result = await updateHandoverReport(reportId, formData);
|
||||
if (result.success) {
|
||||
toast.success('수정이 완료되었습니다.');
|
||||
router.push(`/ko/construction/project/contract/handover-report/${reportId}`);
|
||||
router.push(`/ko/construction/project/contract/handover-report/${reportId}?mode=view`);
|
||||
router.refresh();
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -129,14 +129,14 @@ export default function HandoverReportListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(report: HandoverReport) => {
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}`);
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(report: HandoverReport) => {
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}/edit`);
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -49,7 +49,7 @@ export function HandoverReportDocumentModal({
|
||||
// 수정
|
||||
const handleEdit = () => {
|
||||
onOpenChange(false);
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}/edit`);
|
||||
router.push(`/ko/construction/project/contract/handover-report/${report.id}?mode=edit`);
|
||||
};
|
||||
|
||||
// 삭제
|
||||
|
||||
@@ -604,10 +604,11 @@ export default function IssueDetailForm({ issue, mode = 'view' }: IssueDetailFor
|
||||
);
|
||||
|
||||
// 템플릿 모드 및 동적 설정
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '등록'/'상세' 자동 추가
|
||||
const templateMode = isCreateMode ? 'create' : mode;
|
||||
const dynamicConfig = {
|
||||
...issueConfig,
|
||||
title: isCreateMode ? '이슈 등록' : '이슈 상세',
|
||||
title: isViewMode ? '이슈 상세' : '이슈',
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -107,20 +107,20 @@ export default function IssueManagementListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Issue) => {
|
||||
router.push(`/ko/construction/project/issue-management/${item.id}`);
|
||||
router.push(`/ko/construction/project/issue-management/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Issue) => {
|
||||
router.push(`/ko/construction/project/issue-management/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/issue-management/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/project/issue-management/new');
|
||||
router.push('/ko/construction/project/issue-management?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// 철회 다이얼로그 열기
|
||||
|
||||
@@ -58,8 +58,8 @@ export default function ItemDetailClient({
|
||||
}: ItemDetailClientProps) {
|
||||
const router = useRouter();
|
||||
|
||||
// 모드 계산
|
||||
const mode = isNewMode ? 'new' : isEditMode ? 'edit' : 'view';
|
||||
// 모드 계산 (IntegratedDetailTemplate은 'create'를 기대)
|
||||
const mode = isNewMode ? 'create' : isEditMode ? 'edit' : 'view';
|
||||
const isViewMode = mode === 'view';
|
||||
|
||||
// 폼 데이터
|
||||
@@ -161,17 +161,16 @@ export default function ItemDetailClient({
|
||||
);
|
||||
|
||||
// 동적 config (mode에 따라 title 변경)
|
||||
// Note: IntegratedDetailTemplate 제목 로직:
|
||||
// - create 모드: ${config.title} 등록
|
||||
// - view 모드: config.title (접미사 없음)
|
||||
// - edit 모드: ${config.title} 수정
|
||||
const dynamicConfig = useMemo(() => {
|
||||
const titleMap: Record<string, string> = {
|
||||
new: '품목 등록',
|
||||
edit: '품목 수정',
|
||||
view: '품목 상세',
|
||||
};
|
||||
return {
|
||||
...itemConfig,
|
||||
title: titleMap[mode] || itemConfig.title,
|
||||
title: isViewMode ? '품목 상세' : '품목',
|
||||
};
|
||||
}, [mode]);
|
||||
}, [isViewMode]);
|
||||
|
||||
// onSubmit 핸들러 (Promise 반환)
|
||||
const handleFormSubmit = useCallback(async () => {
|
||||
@@ -187,11 +186,11 @@ export default function ItemDetailClient({
|
||||
|
||||
setIsSaving(true);
|
||||
try {
|
||||
if (mode === 'new') {
|
||||
if (mode === 'create') {
|
||||
const result = await createItem(formData);
|
||||
if (result.success && result.data) {
|
||||
toast.success('품목이 등록되었습니다.');
|
||||
router.push(`/ko/construction/order/base-info/items/${result.data.id}`);
|
||||
router.push(`/ko/construction/order/base-info/items/${result.data.id}?mode=view`);
|
||||
return { success: true };
|
||||
} else {
|
||||
toast.error(result.error || '품목 등록에 실패했습니다.');
|
||||
@@ -201,7 +200,7 @@ export default function ItemDetailClient({
|
||||
const result = await updateItem(itemId, formData);
|
||||
if (result.success) {
|
||||
toast.success('품목이 수정되었습니다.');
|
||||
router.push(`/ko/construction/order/base-info/items/${itemId}`);
|
||||
router.push(`/ko/construction/order/base-info/items/${itemId}?mode=view`);
|
||||
return { success: true };
|
||||
} else {
|
||||
toast.error(result.error || '품목 수정에 실패했습니다.');
|
||||
|
||||
@@ -210,13 +210,13 @@ export default function ItemManagementClient({
|
||||
|
||||
const handleRowClick = useCallback(
|
||||
(item: Item) => {
|
||||
router.push(`/ko/construction/order/base-info/items/${item.id}`);
|
||||
router.push(`/ko/construction/order/base-info/items/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/order/base-info/items/new');
|
||||
router.push('/ko/construction/order/base-info/items?mode=new');
|
||||
}, [router]);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
|
||||
@@ -181,7 +181,7 @@ export default function LaborDetailClient({
|
||||
const result = await createLabor(formData);
|
||||
if (result.success && result.data) {
|
||||
toast.success('노임이 등록되었습니다.');
|
||||
router.push(`/ko/construction/order/base-info/labor/${result.data.id}`);
|
||||
router.push(`/ko/construction/order/base-info/labor/${result.data.id}?mode=view`);
|
||||
} else {
|
||||
toast.error(result.error || '노임 등록에 실패했습니다.');
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function LaborManagementClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(labor: Labor) => {
|
||||
router.push(`/ko/construction/order/base-info/labor/${labor.id}`);
|
||||
router.push(`/ko/construction/order/base-info/labor/${labor.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
@@ -111,7 +111,7 @@ export default function LaborManagementClient({
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/order/base-info/labor/new');
|
||||
router.push('/ko/construction/order/base-info/labor?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// ===== UniversalListPage Config =====
|
||||
|
||||
@@ -582,7 +582,7 @@ export default function ConstructionDetailClient({ id, mode }: ConstructionDetai
|
||||
{/* 이슈 보고 카드 */}
|
||||
<Card
|
||||
className="cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => router.push(`/ko/construction/project/issue-management/new?orderId=${detail.orderId}`)}
|
||||
onClick={() => router.push(`/ko/construction/project/issue-management?mode=new&orderId=${detail.orderId}`)}
|
||||
>
|
||||
<CardContent className="pt-6 pb-6">
|
||||
<div className="space-y-2">
|
||||
@@ -694,10 +694,18 @@ export default function ConstructionDetailClient({ id, mode }: ConstructionDetai
|
||||
</div>
|
||||
);
|
||||
|
||||
// 동적 config 설정
|
||||
// IntegratedDetailTemplate: create → "{title} 등록", view → "{title}", edit → "{title} 수정"
|
||||
// view 모드에서 "시공 상세"로 표시하려면 직접 설정 필요
|
||||
const dynamicConfig = {
|
||||
...constructionConfig,
|
||||
title: isViewMode ? '시공 상세' : '시공',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IntegratedDetailTemplate
|
||||
config={constructionConfig}
|
||||
config={dynamicConfig}
|
||||
mode={mode}
|
||||
initialData={{}}
|
||||
itemId={id}
|
||||
|
||||
@@ -161,14 +161,14 @@ export default function ConstructionManagementListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: ConstructionManagement) => {
|
||||
router.push(`/ko/construction/project/construction-management/${item.id}`);
|
||||
router.push(`/ko/construction/project/construction-management/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: ConstructionManagement) => {
|
||||
router.push(`/ko/construction/project/construction-management/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/construction-management/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
@@ -184,7 +184,7 @@ export default function ConstructionManagementListClient({
|
||||
|
||||
const handleCalendarEventClick = useCallback((event: ScheduleEvent) => {
|
||||
if (event.data) {
|
||||
router.push(`/ko/construction/project/construction-management/${event.id}`);
|
||||
router.push(`/ko/construction/project/construction-management/${event.id}?mode=view`);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useMemo, useCallback, useEffect, Fragment } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { FolderKanban, Pencil, ClipboardList, PlayCircle, CheckCircle2 } from 'lucide-react';
|
||||
import { FolderKanban, ClipboardList, PlayCircle, CheckCircle2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
@@ -240,22 +240,14 @@ export default function ProjectListClient({ initialData = [], initialStats }: Pr
|
||||
|
||||
const handleRowClick = useCallback(
|
||||
(project: Project) => {
|
||||
router.push(`/ko/construction/project/management/${project.id}`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(e: React.MouseEvent, projectId: string) => {
|
||||
e.stopPropagation();
|
||||
router.push(`/ko/construction/project/management/${projectId}/edit`);
|
||||
router.push(`/ko/construction/project/execution-management/${project.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleGanttProjectClick = useCallback(
|
||||
(project: Project) => {
|
||||
router.push(`/ko/construction/project/management/${project.id}`);
|
||||
router.push(`/ko/construction/project/execution-management/${project.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
@@ -510,13 +502,12 @@ export default function ProjectListClient({ initialData = [], initialStats }: Pr
|
||||
<TableHead className="w-[120px] text-right">누계 기성</TableHead>
|
||||
<TableHead className="w-[180px] text-center">프로젝트 기간</TableHead>
|
||||
<TableHead className="w-[80px] text-center">상태</TableHead>
|
||||
<TableHead className="w-[80px] text-center">작업</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="[&_tr]:h-14 [&_tr]:min-h-[56px] [&_tr]:max-h-[56px]">
|
||||
{paginatedData.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={14} className="h-24 text-center">
|
||||
<TableCell colSpan={13} className="h-24 text-center">
|
||||
검색 결과가 없습니다.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -553,18 +544,6 @@ export default function ProjectListClient({ initialData = [], initialStats }: Pr
|
||||
<TableCell className="text-center">
|
||||
{getStatusBadge(project.status, project.hasUrgentIssue)}
|
||||
</TableCell>
|
||||
<TableCell className="text-center">
|
||||
{isSelected && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={(e) => handleEdit(e, project.id)}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -20,8 +20,8 @@ import { OrderDialogs } from './dialogs/OrderDialogs';
|
||||
import { OrderDocumentModal } from './modals/OrderDocumentModal';
|
||||
|
||||
interface OrderDetailFormProps {
|
||||
mode: 'view' | 'edit';
|
||||
orderId: string;
|
||||
mode: 'view' | 'edit' | 'create';
|
||||
orderId?: string;
|
||||
initialData?: OrderDetail;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function OrderDetailForm({
|
||||
const result = await updateOrder(orderId, formData);
|
||||
if (result.success) {
|
||||
toast.success('수정이 완료되었습니다.');
|
||||
router.push(`/ko/construction/order/order-management/${orderId}`);
|
||||
router.push(`/ko/construction/order/order-management/${orderId}?mode=view`);
|
||||
router.refresh();
|
||||
return { success: true };
|
||||
}
|
||||
@@ -225,10 +225,18 @@ export default function OrderDetailForm({
|
||||
</div>
|
||||
);
|
||||
|
||||
// 동적 config 설정
|
||||
// IntegratedDetailTemplate: create → "{title} 등록", view → "{title}", edit → "{title} 수정"
|
||||
// view 모드에서 "발주 상세"로 표시하려면 직접 설정 필요
|
||||
const dynamicConfig = {
|
||||
...orderConfig,
|
||||
title: isViewMode ? '발주 상세' : '발주',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IntegratedDetailTemplate
|
||||
config={orderConfig}
|
||||
config={dynamicConfig}
|
||||
mode={mode}
|
||||
initialData={{}}
|
||||
itemId={orderId}
|
||||
|
||||
@@ -113,6 +113,13 @@ export default function OrderManagementListClient({
|
||||
const calendarEvents: ScheduleEvent[] = useMemo(() => {
|
||||
return allOrders
|
||||
.filter((order) => {
|
||||
// 유효한 날짜가 있는 항목만 달력에 표시
|
||||
// periodStart/periodEnd가 빈 문자열이면 parseISO가 Invalid Date를 반환하여
|
||||
// 모든 이벤트가 일요일(0번 컬럼)에 표시되는 버그 방지
|
||||
if (!order.periodStart || !order.periodEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현장 필터 (달력용)
|
||||
if (calendarSiteFilters.length > 0) {
|
||||
const matchingSite = MOCK_SITES.find((s) => order.siteName.includes(s.label.split(' ')[0]));
|
||||
@@ -152,20 +159,20 @@ export default function OrderManagementListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(order: Order) => {
|
||||
router.push(`/ko/construction/order/order-management/${order.id}`);
|
||||
router.push(`/ko/construction/order/order-management/${order.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(order: Order) => {
|
||||
router.push(`/ko/construction/order/order-management/${order.id}/edit`);
|
||||
router.push(`/ko/construction/order/order-management/${order.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/order/order-management/new');
|
||||
router.push('/ko/construction/order/order-management?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// 달력 이벤트 핸들러
|
||||
@@ -179,7 +186,7 @@ export default function OrderManagementListClient({
|
||||
|
||||
const handleCalendarEventClick = useCallback((event: ScheduleEvent) => {
|
||||
if (event.data) {
|
||||
router.push(`/ko/construction/order/order-management/${event.id}`);
|
||||
router.push(`/ko/construction/order/order-management/${event.id}?mode=view`);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
@@ -366,6 +373,10 @@ export default function OrderManagementListClient({
|
||||
|
||||
// 달력 날짜 필터
|
||||
if (selectedCalendarDate) {
|
||||
// periodStart/periodEnd가 빈 문자열이면 필터링에서 제외
|
||||
if (!item.periodStart || !item.periodEnd) {
|
||||
return false;
|
||||
}
|
||||
const orderStart = startOfDay(parseISO(item.periodStart));
|
||||
const orderEnd = startOfDay(parseISO(item.periodEnd));
|
||||
const selected = startOfDay(selectedCalendarDate);
|
||||
|
||||
@@ -155,7 +155,7 @@ export function OrderManagementUnified({ initialData }: OrderManagementUnifiedPr
|
||||
|
||||
const handleCalendarEventClick = useCallback((event: ScheduleEvent) => {
|
||||
if (event.data) {
|
||||
router.push(`/ko/construction/order/order-management/${event.id}`);
|
||||
router.push(`/ko/construction/order/order-management/${event.id}?mode=view`);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
|
||||
@@ -136,8 +136,11 @@ function transformOrder(apiOrder: ApiOrder): Order {
|
||||
plannedDeliveryDate: apiOrder.delivery_date || '',
|
||||
actualDeliveryDate: apiOrder.actual_delivery_date || null,
|
||||
status: transformStatus(apiOrder.status_code),
|
||||
periodStart: apiOrder.received_at || '',
|
||||
periodEnd: apiOrder.delivery_date || '',
|
||||
// 달력 표시용 기간: received_at ~ delivery_date
|
||||
// received_at이 없으면 delivery_date를 시작일로 사용 (단일 날짜 이벤트)
|
||||
// delivery_date도 없으면 created_at을 사용
|
||||
periodStart: apiOrder.received_at || apiOrder.delivery_date || apiOrder.created_at.split('T')[0],
|
||||
periodEnd: apiOrder.delivery_date || apiOrder.received_at || apiOrder.created_at.split('T')[0],
|
||||
createdAt: apiOrder.created_at,
|
||||
updatedAt: apiOrder.updated_at,
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ export function useOrderDetailForm({
|
||||
}, [router]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
router.push(`/ko/construction/order/order-management/${orderId}/edit`);
|
||||
router.push(`/ko/construction/order/order-management/${orderId}?mode=edit`);
|
||||
}, [router, orderId]);
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
@@ -239,7 +239,7 @@ export function useOrderDetailForm({
|
||||
const result = await duplicateOrder(orderId);
|
||||
if (result.success && result.newId) {
|
||||
toast.success('발주가 복제되었습니다.');
|
||||
router.push(`/ko/construction/order/order-management/${result.newId}/edit`);
|
||||
router.push(`/ko/construction/order/order-management/${result.newId}?mode=edit`);
|
||||
} else {
|
||||
toast.error(result.error || '복제에 실패했습니다.');
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export function OrderDocumentModal({
|
||||
// 수정
|
||||
const handleEdit = () => {
|
||||
onOpenChange(false);
|
||||
router.push(`/ko/construction/order/order-management/${order.id}/edit`);
|
||||
router.push(`/ko/construction/order/order-management/${order.id}?mode=edit`);
|
||||
};
|
||||
|
||||
// 삭제
|
||||
|
||||
@@ -541,7 +541,9 @@ export function orderDetailToFormData(detail: OrderDetail): OrderDetailFormData
|
||||
// orderItems를 카테고리별로 그룹핑
|
||||
const categoryMap = new Map<string, OrderDetailCategory>();
|
||||
|
||||
detail.orderItems.forEach((item) => {
|
||||
// orderItems가 없거나 undefined일 경우 빈 배열로 처리
|
||||
const orderItems = detail.orderItems || [];
|
||||
orderItems.forEach((item) => {
|
||||
// 임시로 'default' 카테고리 사용 (실제로는 item에 categoryId가 있어야 함)
|
||||
const categoryId = 'default';
|
||||
const categoryName = '기본 카테고리';
|
||||
@@ -558,27 +560,27 @@ export function orderDetailToFormData(detail: OrderDetail): OrderDetailFormData
|
||||
});
|
||||
|
||||
return {
|
||||
orderNumber: detail.orderNumber,
|
||||
orderCompanyId: detail.orderCompanyId,
|
||||
orderType: detail.orderType,
|
||||
status: detail.status,
|
||||
orderManager: detail.orderManager,
|
||||
deliveryAddress: detail.deliveryAddress,
|
||||
partnerId: detail.partnerId,
|
||||
partnerName: detail.partnerName,
|
||||
siteName: detail.siteName,
|
||||
contractNumber: detail.contractNumber,
|
||||
contractId: detail.contractId,
|
||||
constructionPMId: detail.constructionPMId,
|
||||
constructionPM: detail.constructionPM,
|
||||
constructionManagers: detail.constructionManagers,
|
||||
workTeamLeader: detail.workTeamLeader,
|
||||
constructionStartDate: detail.constructionStartDate,
|
||||
orderNumber: detail.orderNumber || '',
|
||||
orderCompanyId: detail.orderCompanyId || '',
|
||||
orderType: detail.orderType || 'steel_bar',
|
||||
status: detail.status || 'waiting',
|
||||
orderManager: detail.orderManager || '',
|
||||
deliveryAddress: detail.deliveryAddress || '',
|
||||
partnerId: detail.partnerId || '',
|
||||
partnerName: detail.partnerName || '',
|
||||
siteName: detail.siteName || '',
|
||||
contractNumber: detail.contractNumber || '',
|
||||
contractId: detail.contractId || '',
|
||||
constructionPMId: detail.constructionPMId || '',
|
||||
constructionPM: detail.constructionPM || '',
|
||||
constructionManagers: detail.constructionManagers || [],
|
||||
workTeamLeader: detail.workTeamLeader || '',
|
||||
constructionStartDate: detail.constructionStartDate || '',
|
||||
constructionEndDate: '', // Order 인터페이스에는 없으므로 빈 값
|
||||
orderCategories: Array.from(categoryMap.values()),
|
||||
memo: detail.memo,
|
||||
periodStart: detail.periodStart,
|
||||
periodEnd: detail.periodEnd,
|
||||
memo: detail.memo || '',
|
||||
periodStart: detail.periodStart || '',
|
||||
periodEnd: detail.periodEnd || '',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -233,18 +233,19 @@ export default function PartnerForm({ mode, partnerId, initialData }: PartnerFor
|
||||
}, []);
|
||||
|
||||
// 동적 Config (모드별 타이틀/설명)
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '등록'/'수정' 자동 추가
|
||||
const dynamicConfig = useMemo(() => {
|
||||
if (isNewMode) {
|
||||
return {
|
||||
...partnerConfig,
|
||||
title: '거래처 등록',
|
||||
title: '거래처',
|
||||
description: '새로운 거래처를 등록합니다',
|
||||
};
|
||||
}
|
||||
if (isEditMode) {
|
||||
return {
|
||||
...partnerConfig,
|
||||
title: '거래처 수정',
|
||||
title: '거래처',
|
||||
description: '거래처 정보를 수정합니다',
|
||||
};
|
||||
}
|
||||
@@ -628,7 +629,7 @@ export default function PartnerForm({ mode, partnerId, initialData }: PartnerFor
|
||||
return (
|
||||
<IntegratedDetailTemplate
|
||||
config={dynamicConfig}
|
||||
mode={mode}
|
||||
mode={mode === 'new' ? 'create' : mode}
|
||||
initialData={{}}
|
||||
itemId={partnerId}
|
||||
isLoading={false}
|
||||
|
||||
@@ -70,18 +70,18 @@ export default function PartnerListClient({ initialData = [], initialStats }: Pa
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Partner) => {
|
||||
router.push(`/ko/construction/project/bidding/partners/${item.id}`);
|
||||
router.push(`/ko/construction/project/bidding/partners/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/project/bidding/partners/new');
|
||||
router.push('/ko/construction/project/bidding/partners?mode=new');
|
||||
}, [router]);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Partner) => {
|
||||
router.push(`/ko/construction/project/bidding/partners/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/partners/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -173,7 +173,7 @@ export default function PricingDetailClient({ id, mode }: PricingDetailClientPro
|
||||
|
||||
if (result.success) {
|
||||
toast.success('단가가 수정되었습니다.');
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}?mode=view`);
|
||||
} else {
|
||||
toast.error(result.error || '수정에 실패했습니다.');
|
||||
}
|
||||
@@ -209,7 +209,7 @@ export default function PricingDetailClient({ id, mode }: PricingDetailClientPro
|
||||
// 수정 페이지로 이동
|
||||
const handleEdit = useCallback(() => {
|
||||
if (id) {
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}/edit`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}?mode=edit`);
|
||||
}
|
||||
}, [id, router]);
|
||||
|
||||
@@ -218,7 +218,7 @@ export default function PricingDetailClient({ id, mode }: PricingDetailClientPro
|
||||
if (isCreateMode) {
|
||||
router.push('/ko/construction/order/base-info/pricing');
|
||||
} else if (isEditMode && id) {
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${id}?mode=view`);
|
||||
}
|
||||
}, [isCreateMode, isEditMode, id, router]);
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ export default function PricingDetailClientV2({
|
||||
(newMode: DetailMode) => {
|
||||
if (newMode === 'edit' && pricingId) {
|
||||
// edit 모드로 변경 시 별도 페이지로 이동 (기존 라우트 구조 유지)
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricingId}/edit`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricingId}?mode=edit`);
|
||||
} else {
|
||||
setMode(newMode);
|
||||
}
|
||||
|
||||
@@ -99,20 +99,20 @@ export default function PricingListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(pricing: Pricing) => {
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricing.id}`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricing.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(pricing: Pricing) => {
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricing.id}/edit`);
|
||||
router.push(`/ko/construction/order/base-info/pricing/${pricing.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/order/base-info/pricing/new');
|
||||
router.push('/ko/construction/order/base-info/pricing?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// ===== UniversalListPage Config =====
|
||||
|
||||
@@ -146,10 +146,18 @@ export default function ProgressBillingDetailForm({
|
||||
</div>
|
||||
);
|
||||
|
||||
// 동적 config 설정
|
||||
// IntegratedDetailTemplate: create → "{title} 등록", view → "{title}", edit → "{title} 수정"
|
||||
// view 모드에서 "기성청구 상세"로 표시하려면 직접 설정 필요
|
||||
const dynamicConfig = {
|
||||
...progressBillingConfig,
|
||||
title: isViewMode ? '기성청구 상세' : '기성청구',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IntegratedDetailTemplate
|
||||
config={progressBillingConfig}
|
||||
config={dynamicConfig}
|
||||
mode={mode}
|
||||
initialData={{}}
|
||||
itemId={billingId}
|
||||
|
||||
@@ -90,14 +90,14 @@ export default function ProgressBillingManagementListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: ProgressBilling) => {
|
||||
router.push(`/ko/construction/billing/progress-billing-management/${item.id}`);
|
||||
router.push(`/ko/construction/billing/progress-billing-management/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: ProgressBilling) => {
|
||||
router.push(`/ko/construction/billing/progress-billing-management/${item.id}/edit`);
|
||||
router.push(`/ko/construction/billing/progress-billing-management/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -63,7 +63,7 @@ export function useProgressBillingDetailForm({
|
||||
}, [router]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
router.push('/construction/billing/progress-billing-management/' + billingId + '/edit');
|
||||
router.push('/construction/billing/progress-billing-management/' + billingId + '?mode=edit');
|
||||
}, [router, billingId]);
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
|
||||
@@ -395,11 +395,12 @@ export default function SiteBriefingForm({ mode, briefingId, initialData }: Site
|
||||
}, []);
|
||||
|
||||
// 동적 config (모드에 따른 title 변경)
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '등록'/'수정' 자동 추가
|
||||
const dynamicConfig = useMemo(() => {
|
||||
if (isNewMode) {
|
||||
return {
|
||||
...siteBriefingConfig,
|
||||
title: '현장설명회 등록',
|
||||
title: '현장설명회',
|
||||
description: '새로운 현장설명회를 등록합니다',
|
||||
actions: {
|
||||
...siteBriefingConfig.actions,
|
||||
@@ -410,7 +411,7 @@ export default function SiteBriefingForm({ mode, briefingId, initialData }: Site
|
||||
if (isEditMode) {
|
||||
return {
|
||||
...siteBriefingConfig,
|
||||
title: '현장설명회 수정',
|
||||
title: '현장설명회',
|
||||
description: '현장설명회 정보를 수정합니다',
|
||||
};
|
||||
}
|
||||
@@ -901,7 +902,7 @@ export default function SiteBriefingForm({ mode, briefingId, initialData }: Site
|
||||
<>
|
||||
<IntegratedDetailTemplate
|
||||
config={dynamicConfig}
|
||||
mode={mode}
|
||||
mode={mode === 'new' ? 'create' : mode}
|
||||
initialData={{}}
|
||||
itemId={briefingId}
|
||||
isLoading={false}
|
||||
|
||||
@@ -101,20 +101,20 @@ export default function SiteBriefingListClient({ initialData = [] }: SiteBriefin
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: SiteBriefing) => {
|
||||
router.push(`/ko/construction/project/bidding/site-briefings/${item.id}`);
|
||||
router.push(`/ko/construction/project/bidding/site-briefings/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: SiteBriefing) => {
|
||||
router.push(`/ko/construction/project/bidding/site-briefings/${item.id}/edit`);
|
||||
router.push(`/ko/construction/project/bidding/site-briefings/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/project/bidding/site-briefings/new');
|
||||
router.push('/ko/construction/project/bidding/site-briefings?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// ===== UniversalListPage Config (최소 버전) =====
|
||||
|
||||
@@ -83,14 +83,14 @@ export default function SiteManagementListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(site: Site) => {
|
||||
router.push(`/ko/construction/order/site-management/${site.id}`);
|
||||
router.push(`/ko/construction/order/site-management/${site.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(site: Site) => {
|
||||
router.push(`/ko/construction/order/site-management/${site.id}/edit`);
|
||||
router.push(`/ko/construction/order/site-management/${site.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
@@ -129,15 +129,11 @@ export default function StructureReviewDetailForm({
|
||||
}, []);
|
||||
|
||||
// 동적 config (mode에 따라 title 변경)
|
||||
// Note: IntegratedDetailTemplate이 모드에 따라 '등록'/'수정'/'상세' 자동 추가
|
||||
const dynamicConfig = useMemo(() => {
|
||||
const titleMap: Record<string, string> = {
|
||||
new: '구조검토 등록',
|
||||
edit: '구조검토 수정',
|
||||
view: '구조검토 상세',
|
||||
};
|
||||
return {
|
||||
...structureReviewConfig,
|
||||
title: titleMap[mode] || structureReviewConfig.title,
|
||||
title: '구조검토',
|
||||
};
|
||||
}, [mode]);
|
||||
|
||||
|
||||
@@ -97,20 +97,20 @@ export default function StructureReviewListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: StructureReview) => {
|
||||
router.push(`/ko/construction/order/structure-review/${item.id}`);
|
||||
router.push(`/ko/construction/order/structure-review/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: StructureReview) => {
|
||||
router.push(`/ko/construction/order/structure-review/${item.id}/edit`);
|
||||
router.push(`/ko/construction/order/structure-review/${item.id}?mode=edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
router.push('/ko/construction/order/structure-review/new');
|
||||
router.push('/ko/construction/order/structure-review?mode=new');
|
||||
}, [router]);
|
||||
|
||||
// ===== UniversalListPage Config =====
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
* - 삭제 기능 (deleteConfirmMessage로 AlertDialog 대체)
|
||||
*/
|
||||
|
||||
import { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Zap, Pencil, Trash2, FileText, CheckCircle, Clock } from 'lucide-react';
|
||||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { Zap, Trash2, FileText, CheckCircle, Clock } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { TableCell, TableRow } from '@/components/ui/table';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
@@ -80,8 +79,6 @@ export default function UtilityManagementListClient({
|
||||
initialData = [],
|
||||
initialStats,
|
||||
}: UtilityManagementListClientProps) {
|
||||
const router = useRouter();
|
||||
|
||||
// ===== 외부 상태 (UniversalListPage 외부에서 관리) =====
|
||||
const [activeStatTab, setActiveStatTab] = useState<'all' | 'waiting' | 'complete'>('all');
|
||||
const [startDate, setStartDate] = useState<string>('');
|
||||
@@ -99,21 +96,6 @@ export default function UtilityManagementListClient({
|
||||
}
|
||||
}, [initialStats]);
|
||||
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: Utility) => {
|
||||
router.push(`/ko/construction/project/utility-management/${item.id}`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(item: Utility) => {
|
||||
router.push(`/ko/construction/project/utility-management/${item.id}/edit`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
// ===== UniversalListPage Config =====
|
||||
const config: UniversalListConfig<Utility> = useMemo(
|
||||
() => ({
|
||||
@@ -349,10 +331,9 @@ export default function UtilityManagementListClient({
|
||||
) => (
|
||||
<TableRow
|
||||
key={item.id}
|
||||
className="cursor-pointer hover:bg-muted/50"
|
||||
onClick={() => handleRowClick(item)}
|
||||
className="hover:bg-muted/50"
|
||||
>
|
||||
<TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
|
||||
<TableCell className="text-center">
|
||||
<Checkbox checked={handlers.isSelected} onCheckedChange={handlers.onToggle} />
|
||||
</TableCell>
|
||||
<TableCell className="text-center text-muted-foreground">{globalIndex}</TableCell>
|
||||
@@ -372,30 +353,14 @@ export default function UtilityManagementListClient({
|
||||
</TableCell>
|
||||
<TableCell className="text-center">
|
||||
{handlers.isSelected && (
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleEdit(item);
|
||||
}}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-destructive hover:text-destructive"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlers.onDelete?.(item);
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-destructive hover:text-destructive"
|
||||
onClick={() => handlers.onDelete?.(item)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -416,7 +381,6 @@ export default function UtilityManagementListClient({
|
||||
badgeVariant="secondary"
|
||||
isSelected={handlers.isSelected}
|
||||
onToggle={handlers.onToggle}
|
||||
onClick={() => handleRowClick(item)}
|
||||
details={[
|
||||
{ label: '거래처', value: item.partnerName },
|
||||
{ label: '공사PM', value: item.constructionPM },
|
||||
@@ -425,7 +389,7 @@ export default function UtilityManagementListClient({
|
||||
/>
|
||||
),
|
||||
}),
|
||||
[startDate, endDate, activeStatTab, stats, handleRowClick, handleEdit]
|
||||
[startDate, endDate, activeStatTab, stats]
|
||||
);
|
||||
|
||||
return <UniversalListPage config={config} initialData={initialData} />;
|
||||
|
||||
@@ -99,14 +99,14 @@ export default function WorkerStatusListClient({
|
||||
// ===== 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
(item: WorkerStatus) => {
|
||||
router.push(`/ko/construction/project/worker-status/${item.id}`);
|
||||
router.push(`/ko/construction/project/worker-status/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const handleViewDetail = useCallback(
|
||||
(item: WorkerStatus) => {
|
||||
router.push(`/ko/construction/project/worker-status/${item.id}`);
|
||||
router.push(`/ko/construction/project/worker-status/${item.id}?mode=view`);
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user