diff --git a/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx b/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx
index c605c683..07fbbe00 100644
--- a/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx
+++ b/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx
@@ -17,11 +17,9 @@
import { useState, useRef, useEffect, useCallback, useTransition, useMemo } from "react";
import { useRouter, useSearchParams } from "next/navigation";
-import { ClientDetailClientV2 } from '@/components/clients/ClientDetailClientV2';
import { useClientList, Client } from "@/hooks/useClientList";
import {
Building2,
- Plus,
Users,
CheckCircle,
Loader2,
@@ -43,7 +41,7 @@ import {
} from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { ListMobileCard, InfoField } from "@/components/organisms/MobileCard";
-import { DeleteConfirmDialog } from "@/components/ui/confirm-dialog";
+// DeleteConfirmDialog 제거 — 판매관리 거래처는 읽기 전용
import { sendNewClientNotification } from "@/lib/actions/fcm";
import { isNextRedirectError } from "@/lib/utils/redirect-error";
@@ -359,9 +357,11 @@ export default function CustomerAccountManagementPage() {
});
}, []);
- // mode=new 처리 (모든 훅 호출 후에 조건부 return - React 훅 규칙 준수)
+ // mode=new 차단 — 등록은 회계관리>거래처관리에서만 가능
if (mode === 'new') {
- return ;
+ toast.error('거래처 등록은 회계관리 > 거래처관리에서 가능합니다.');
+ router.push('/sales/client-management-sales-admin');
+ return null;
}
// 상태 뱃지
@@ -588,53 +588,13 @@ export default function CustomerAccountManagementPage() {
신규업체
-
),
renderTableRow,
renderMobileCard,
- renderDialogs: () => (
- <>
- {/* 삭제 확인 다이얼로그 */}
-
- {deleteTargetId
- ? `거래처: ${clients.find((c) => c.id === deleteTargetId)?.name || deleteTargetId}`
- : ""}
-
- 이 거래처를 삭제하시겠습니까? 삭제된 데이터는 복구할 수 없습니다.
- >
- }
- />
-
- {/* 일괄 삭제 확인 다이얼로그 */}
-
- 선택한 {selectedItems.size}개의 거래처를 삭제하시겠습니까?
-
-
- 삭제된 데이터는 복구할 수 없습니다.
-
- >
- }
- />
- >
- ),
+ // 판매관리 거래처는 읽기 전용 — 삭제 다이얼로그 불필요
};
return (
diff --git a/src/components/clients/ClientDetailClientV2.tsx b/src/components/clients/ClientDetailClientV2.tsx
index c333dd1f..a17d7703 100644
--- a/src/components/clients/ClientDetailClientV2.tsx
+++ b/src/components/clients/ClientDetailClientV2.tsx
@@ -7,62 +7,39 @@
* 클라이언트 사이드 데이터 페칭 (useClientList 훅 활용)
*/
-import { useState, useEffect, useCallback, useRef } from 'react';
-import { useRouter, useSearchParams } from 'next/navigation';
+import { useState, useEffect, useCallback } from 'react';
+import { useRouter } from 'next/navigation';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
-import type { DetailMode, IntegratedDetailTemplateRef } from '@/components/templates/IntegratedDetailTemplate/types';
-import type { Client, ClientFormData } from '@/hooks/useClientList';
+import type { DetailMode } from '@/components/templates/IntegratedDetailTemplate/types';
+import type { Client } from '@/hooks/useClientList';
import { useClientList } from '@/hooks/useClientList';
import { clientDetailConfig } from './clientDetailConfig';
import { toast } from 'sonner';
-import { useDevFillContext } from '@/components/dev/DevFillContext';
-import { generateClientData } from '@/components/dev/generators/clientData';
interface ClientDetailClientV2Props {
clientId?: string;
initialMode?: DetailMode;
}
-// 8자리 영문+숫자 코드 생성
-function generateCode(): string {
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
- let result = '';
- for (let i = 0; i < 8; i++) {
- result += chars.charAt(Math.floor(Math.random() * chars.length));
- }
- return result;
-}
-
-export function ClientDetailClientV2({ clientId, initialMode }: ClientDetailClientV2Props) {
+export function ClientDetailClientV2({ clientId }: ClientDetailClientV2Props) {
const router = useRouter();
- const searchParams = useSearchParams();
- const { fetchClient, createClient, updateClient, deleteClient } = useClientList();
- const templateRef = useRef(null);
- const { isEnabled, registerFillForm, unregisterFillForm } = useDevFillContext();
+ const { fetchClient } = useClientList();
- // URL 쿼리에서 모드 결정
- const modeFromQuery = searchParams.get('mode') as DetailMode | null;
const isNewMode = !clientId || clientId === 'new';
- const [mode, setMode] = useState(() => {
- if (isNewMode) return 'create';
- if (initialMode) return initialMode;
- if (modeFromQuery === 'edit') return 'edit';
- return 'view';
- });
+ // 판매관리 거래처는 읽기 전용 — 수정/등록은 회계관리>거래처관리에서만 가능
+ const [mode] = useState('view');
const [clientData, setClientData] = useState(null);
const [isLoading, setIsLoading] = useState(!isNewMode);
- const [generatedCode, setGeneratedCode] = useState('');
// 데이터 로드
useEffect(() => {
const loadData = async () => {
+ // 신규 등록 차단 — 회계관리>거래처관리에서만 가능
if (isNewMode) {
- // 신규 등록 시 코드 생성
- const code = generateCode();
- setGeneratedCode(code);
- setIsLoading(false);
+ toast.error('거래처 등록은 회계관리 > 거래처관리에서 가능합니다.');
+ router.push(clientDetailConfig.basePath);
return;
}
@@ -87,164 +64,32 @@ export function ClientDetailClientV2({ clientId, initialMode }: ClientDetailClie
loadData();
}, [clientId, isNewMode, router, fetchClient]);
- // URL 쿼리 변경 감지
- useEffect(() => {
- if (!isNewMode && modeFromQuery === 'edit') {
- setMode('edit');
- } else if (!isNewMode && !modeFromQuery) {
- setMode('view');
- }
- }, [modeFromQuery, isNewMode]);
-
- // DevFill 등록 (신규 등록 모드일 때만)
- useEffect(() => {
- if (!isEnabled || !isNewMode) return;
-
- const handleDevFill = () => {
- const data = generateClientData();
- if (templateRef.current) {
- templateRef.current.setFormData(data as unknown as Record);
- }
- };
-
- registerFillForm('client', handleDevFill);
-
- return () => {
- unregisterFillForm('client');
- };
- }, [isEnabled, isNewMode, registerFillForm, unregisterFillForm]);
-
- // 모드 변경 핸들러
+ // 모드 변경 차단 — 읽기 전용
const handleModeChange = useCallback(
- (newMode: DetailMode) => {
- setMode(newMode);
- if (newMode === 'edit' && clientId) {
- router.push(`${clientDetailConfig.basePath}/${clientId}?mode=edit`);
- } else if (newMode === 'view' && clientId) {
- router.push(`${clientDetailConfig.basePath}/${clientId}?mode=view`);
- }
+ (_newMode: DetailMode) => {
+ toast.info('거래처 수정은 회계관리 > 거래처관리에서 가능합니다.');
},
- [router, clientId]
+ []
);
- // 저장 핸들러
- const handleSubmit = useCallback(
- async (formData: Record) => {
- try {
- // formData를 ClientFormData로 변환
- const clientFormData: ClientFormData = {
- clientCode: (formData.clientCode as string) || generatedCode,
- name: formData.name as string,
- businessNo: formData.businessNo as string,
- representative: formData.representative as string,
- phone: formData.phone as string,
- address: formData.address as string,
- email: formData.email as string,
- businessType: formData.businessType as string,
- businessItem: formData.businessItem as string,
- isActive: formData.isActive === 'true',
- clientType: (formData.clientType as ClientFormData['clientType']) || '매입',
- mobile: formData.mobile as string,
- fax: formData.fax as string,
- managerName: formData.managerName as string,
- managerTel: formData.managerTel as string,
- systemManager: formData.systemManager as string,
- accountId: formData.accountId as string || '',
- accountPassword: formData.accountPassword as string || '',
- purchasePaymentDay: '말일',
- salesPaymentDay: '말일',
- taxAgreement: false,
- taxAmount: '',
- taxStartDate: '',
- taxEndDate: '',
- badDebt: false,
- badDebtAmount: '',
- badDebtReceiveDate: '',
- badDebtEndDate: '',
- badDebtProgress: '',
- memo: formData.memo as string || '',
- };
-
- if (isNewMode) {
- const result = await createClient(clientFormData);
- if (result) {
- toast.success('거래처가 등록되었습니다.');
- router.push(clientDetailConfig.basePath);
- return { success: true };
- }
- return { success: false, error: '거래처 등록에 실패했습니다.' };
- } else {
- const result = await updateClient(clientId!, clientFormData);
- if (result) {
- toast.success('거래처가 수정되었습니다.');
- router.push(`${clientDetailConfig.basePath}/${clientId}?mode=view`);
- return { success: true };
- }
- return { success: false, error: '거래처 수정에 실패했습니다.' };
- }
- } catch (error) {
- console.error('저장 실패:', error);
- return { success: false, error: error instanceof Error ? error.message : '저장 중 오류가 발생했습니다.' };
- }
- },
- [isNewMode, clientId, generatedCode, router, createClient, updateClient]
- );
-
- // 삭제 핸들러
- const handleDelete = useCallback(
- async (id: string | number) => {
- try {
- const result = await deleteClient(String(id));
- if (result) {
- toast.success('거래처가 삭제되었습니다.');
- router.push(clientDetailConfig.basePath);
- return { success: true };
- }
- return { success: false, error: '거래처 삭제에 실패했습니다.' };
- } catch (error) {
- console.error('삭제 실패:', error);
- return { success: false, error: error instanceof Error ? error.message : '삭제 중 오류가 발생했습니다.' };
- }
- },
- [router, deleteClient]
- );
-
- // 취소 핸들러
+ // 취소(목록으로) 핸들러
const handleCancel = useCallback(() => {
- if (isNewMode) {
- router.push(clientDetailConfig.basePath);
- } else {
- setMode('view');
- router.push(`${clientDetailConfig.basePath}/${clientId}?mode=view`);
- }
- }, [router, clientId, isNewMode]);
-
- // 초기 데이터 (신규 등록 시 코드 포함)
- const initialData = isNewMode
- ? ({ code: generatedCode } as Client)
- : clientData || undefined;
+ router.push(clientDetailConfig.basePath);
+ }, [router]);
// 타이틀 동적 설정
const dynamicConfig = {
...clientDetailConfig,
- title:
- mode === 'create'
- ? '거래처'
- : mode === 'edit'
- ? clientData?.name || '거래처'
- : clientData?.name || '거래처 상세',
+ title: clientData?.name || '거래처 상세',
};
return (
| undefined}
+ initialData={clientData as unknown as Record | undefined}
itemId={clientId}
isLoading={isLoading}
- onSubmit={handleSubmit}
- onDelete={handleDelete}
onCancel={handleCancel}
onModeChange={handleModeChange}
/>
diff --git a/src/components/clients/clientDetailConfig.ts b/src/components/clients/clientDetailConfig.ts
index ffcb080d..a43fe825 100644
--- a/src/components/clients/clientDetailConfig.ts
+++ b/src/components/clients/clientDetailConfig.ts
@@ -202,16 +202,12 @@ export const clientDetailConfig: DetailConfig = {
actions: {
submitLabel: '저장',
cancelLabel: '취소',
- showDelete: true,
+ showDelete: false,
deleteLabel: '삭제',
- showEdit: true,
+ showEdit: false,
editLabel: '수정',
showBack: true,
backLabel: '목록',
- deleteConfirmMessage: {
- title: '거래처 삭제',
- description: '이 거래처를 삭제하시겠습니까? 삭제된 데이터는 복구할 수 없습니다.',
- },
},
transformInitialData: (data: Client) => ({
businessNo: data.businessNo || '',