Files
sam-react-prod/src/components/accounting/DepositManagement/DepositDetailClientV2.tsx
유병철 7d369d1404 feat: 계정과목 공통화 및 회계 모듈 전반 개선
- 계정과목 관리를 accounting/common/으로 통합 (AccountSubjectSettingModal 이동)
- GeneralJournalEntry: 계정과목 actions/types 분리, 모달 import 경로 변경
- CardTransactionInquiry: JournalEntryModal/ManualInputModal 개선
- TaxInvoiceManagement: actions/types 리팩토링
- DepositManagement/WithdrawalManagement: 소폭 개선
- ExpectedExpenseManagement: UI 개선
- GiftCertificateManagement: 상세/목록 개선
- BillManagement: BillDetail/Client/index 소폭 추가
- PurchaseManagement/SalesManagement: 상세뷰 개선
- CEO 대시보드: dashboard-invalidation 유틸 추가, useCEODashboard 확장
- OrderRegistration/OrderSalesDetailView 소폭 수정
- claudedocs: 계정과목 통합 계획/분석/체크리스트, 대시보드 검증 문서 추가
2026-03-08 12:44:36 +09:00

145 lines
5.0 KiB
TypeScript

'use client';
import { useState, useCallback, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { toast } from 'sonner';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
import type { DetailMode } from '@/components/templates/IntegratedDetailTemplate/types';
import { depositDetailConfig } from './depositDetailConfig';
import type { DepositRecord } from './types';
import {
getDepositById,
createDeposit,
updateDeposit,
deleteDeposit,
getVendors,
getBankAccounts,
} from './actions';
import { useDevFill, generateDepositData } from '@/components/dev';
import { invalidateDashboard } from '@/lib/dashboard-invalidation';
// ===== Props =====
interface DepositDetailClientV2Props {
depositId?: string;
initialMode?: DetailMode;
}
export default function DepositDetailClientV2({
depositId,
initialMode = 'view',
}: DepositDetailClientV2Props) {
const router = useRouter();
const [mode, setMode] = useState<DetailMode>(initialMode);
const [deposit, setDeposit] = useState<DepositRecord | null>(null);
const [isLoading, setIsLoading] = useState(initialMode !== 'create');
// ===== DevFill: 자동 입력 기능 =====
useDevFill('deposit', useCallback(async () => {
if (initialMode === 'create') {
// 거래처 및 계좌 목록 가져오기
const [vendorResult, bankAccountResult] = await Promise.all([
getVendors(),
getBankAccounts(),
]);
const vendors = vendorResult.success ? vendorResult.data : undefined;
const bankAccounts = bankAccountResult.success ? bankAccountResult.data : undefined;
const mockData = generateDepositData({ vendors, bankAccounts });
setDeposit(mockData as unknown as DepositRecord);
toast.success('입금 데이터가 자동 입력되었습니다.');
}
}, [initialMode]));
// ===== 데이터 로드 =====
useEffect(() => {
const loadDeposit = async () => {
if (depositId && initialMode !== 'create') {
setIsLoading(true);
const result = await getDepositById(depositId);
if (result.success && result.data) {
setDeposit(result.data);
} else {
toast.error(result.error || '입금 내역을 불러오는데 실패했습니다.');
}
setIsLoading(false);
}
};
loadDeposit();
}, [depositId, initialMode]);
// ===== 저장/등록 핸들러 =====
// IntegratedDetailTemplate이 config.transformSubmitData를 이미 적용한 데이터를 전달함
const handleSubmit = useCallback(
async (submitData: Record<string, unknown>): Promise<{ success: boolean; error?: string }> => {
if (!submitData.vendorId) {
toast.error('거래처를 선택해주세요.');
return { success: false, error: '거래처를 선택해주세요.' };
}
const result =
mode === 'create'
? await createDeposit(submitData as Partial<DepositRecord>)
: await updateDeposit(depositId!, submitData as Partial<DepositRecord>);
if (result.success && mode === 'create') {
invalidateDashboard('deposit');
toast.success('등록되었습니다.');
router.push('/ko/accounting/deposits');
return { success: false, error: '' }; // 템플릿의 중복 토스트/리다이렉트 방지
}
if (result.success) {
invalidateDashboard('deposit');
return { success: true };
}
return { success: false, error: result.error };
},
[mode, depositId, router]
);
// ===== 삭제 핸들러 (결과만 반환, 토스트/리다이렉트는 IntegratedDetailTemplate에 위임) =====
const handleDelete = useCallback(async (): Promise<{ success: boolean; error?: string }> => {
if (!depositId) return { success: false, error: 'ID가 없습니다.' };
const result = await deleteDeposit(depositId);
if (result.success) {
invalidateDashboard('deposit');
return { success: true };
}
return { success: false, error: result.error };
}, [depositId]);
// ===== 모드 변경 핸들러 =====
const handleModeChange = useCallback(
(newMode: DetailMode) => {
if (newMode === 'edit' && depositId) {
router.push(`/ko/accounting/deposits/${depositId}?mode=edit`);
} else {
setMode(newMode);
}
},
[depositId, router]
);
// 타이틀 동적 설정
// IntegratedDetailTemplate: create → "{title} 등록", view → "{title}", edit → "{title} 수정"
// view 모드에서 "입금 상세"로 표시하려면 직접 설정 필요
const dynamicConfig = {
...depositDetailConfig,
title: mode === 'view' ? '입금 상세' : '입금',
};
return (
<IntegratedDetailTemplate
config={dynamicConfig as Parameters<typeof IntegratedDetailTemplate>[0]['config']}
mode={mode}
initialData={deposit as unknown as Record<string, unknown> | undefined}
itemId={depositId}
isLoading={isLoading}
onSubmit={handleSubmit}
onDelete={handleDelete}
onModeChange={handleModeChange}
/>
);
}