From 2b954db854f54020a2aacb5dfe99160b2ba77962 Mon Sep 17 00:00:00 2001 From: Johngreen Date: Tue, 28 Apr 2026 07:52:38 +0900 Subject: [PATCH] =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=97=90=EC=84=9C=20=EC=B0=A8=EB=9F=89/=EC=9A=B4?= =?UTF-8?q?=EC=A0=84=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=84=B9=EC=85=98=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProfileModal 의 isDriver 토글 섹션 + 새 차량 등록 모달 + DriverInfo /DriverFormData 타입 + 관련 props 모두 제거. 호출부(AppLayout) 와 useProfile 훅의 driver/vehicle 상태 관리 로직도 함께 정리. 차량/운전자 메뉴 화면(components/vehicle/*) 과 대시보드 위젯 (VehicleListWidget, DriverManagementWidget 등) 은 그대로 유지. 3 files changed, 525 deletions(-). Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/components/layout/AppLayout.tsx | 28 --- frontend/components/layout/ProfileModal.tsx | 259 +------------------- frontend/hooks/useProfile.ts | 242 +----------------- 3 files changed, 4 insertions(+), 525 deletions(-) diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index f046d74a..a4f7f6fb 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -414,20 +414,6 @@ function AppLayoutInner({ children }: AppLayoutProps) { selectImage, removeImage, saveProfile, - isDriver, - hasVehicle, - driverInfo, - driverFormData, - updateDriverFormData, - handleDriverStatusChange, - handleDriverAccountDelete, - handleDeleteVehicle, - openVehicleRegisterModal, - closeVehicleRegisterModal, - isVehicleRegisterModalOpen, - newVehicleData, - updateNewVehicleData, - handleRegisterVehicle, } = useProfile(user, refreshUserData, refreshMenus); const tabMode = useTabStore((s) => s.mode); @@ -1177,20 +1163,6 @@ function AppLayoutInner({ children }: AppLayoutProps) { isSaving={isSaving} departments={departments} alertModal={alertModal} - isDriver={isDriver} - hasVehicle={hasVehicle} - driverInfo={driverInfo} - driverFormData={driverFormData} - onDriverFormChange={updateDriverFormData} - onDriverStatusChange={handleDriverStatusChange} - onDriverAccountDelete={handleDriverAccountDelete} - onDeleteVehicle={handleDeleteVehicle} - onOpenVehicleRegisterModal={openVehicleRegisterModal} - isVehicleRegisterModalOpen={isVehicleRegisterModalOpen} - newVehicleData={newVehicleData} - onCloseVehicleRegisterModal={closeVehicleRegisterModal} - onNewVehicleDataChange={updateNewVehicleData} - onRegisterVehicle={handleRegisterVehicle} onClose={closeProfileModal} onFormChange={updateFormData} onImageSelect={selectImage} diff --git a/frontend/components/layout/ProfileModal.tsx b/frontend/components/layout/ProfileModal.tsx index 9146ea69..0bb88b05 100644 --- a/frontend/components/layout/ProfileModal.tsx +++ b/frontend/components/layout/ProfileModal.tsx @@ -4,18 +4,14 @@ import { DialogContent, DialogHeader, DialogTitle, - DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Camera, X, Car, Wrench, Clock, Plus, Trash2 } from "lucide-react"; +import { Camera, X } from "lucide-react"; import { ProfileFormData } from "@/types/profile"; -import { Separator } from "@/components/ui/separator"; -import { VehicleRegisterData } from "@/lib/api/driver"; import { apiClient } from "@/lib/api/client"; // 언어 정보 타입 @@ -25,16 +21,6 @@ interface LanguageInfo { langNative: string; } -// 운전자 정보 타입 -export interface DriverInfo { - vehicleNumber: string; - vehicleType: string | null; - licenseNumber: string; - phoneNumber: string; - vehicleStatus: string | null; - branchName: string | null; -} - // 알림 모달 컴포넌트 interface AlertModalProps { isOpen: boolean; @@ -75,15 +61,6 @@ function AlertModal({ isOpen, onClose, title, message, type = "info" }: AlertMod ); } -// 운전자 폼 데이터 타입 -export interface DriverFormData { - vehicleNumber: string; - vehicleType: string; - licenseNumber: string; - phoneNumber: string; - branchName: string; -} - interface ProfileModalProps { isOpen: boolean; user: any; @@ -100,23 +77,6 @@ interface ProfileModalProps { message: string; type: "success" | "error" | "info"; }; - // 운전자 관련 props (선택적) - isDriver?: boolean; - hasVehicle?: boolean; - driverInfo?: DriverInfo | null; - driverFormData?: DriverFormData; - onDriverFormChange?: (field: keyof DriverFormData, value: string) => void; - onDriverStatusChange?: (status: "off" | "maintenance") => void; - onDriverAccountDelete?: () => void; - // 차량 삭제/등록 관련 props - onDeleteVehicle?: () => void; - onOpenVehicleRegisterModal?: () => void; - // 새 차량 등록 모달 관련 props - isVehicleRegisterModalOpen?: boolean; - newVehicleData?: VehicleRegisterData; - onCloseVehicleRegisterModal?: () => void; - onNewVehicleDataChange?: (field: keyof VehicleRegisterData, value: string) => void; - onRegisterVehicle?: () => void; onClose: () => void; onFormChange: (field: keyof ProfileFormData, value: string) => void; onImageSelect: (event: React.ChangeEvent) => void; @@ -136,20 +96,6 @@ export function ProfileModal({ isSaving, departments, alertModal, - isDriver = false, - hasVehicle = false, - driverInfo, - driverFormData, - onDriverFormChange, - onDriverStatusChange, - onDriverAccountDelete, - onDeleteVehicle, - onOpenVehicleRegisterModal, - isVehicleRegisterModalOpen = false, - newVehicleData, - onCloseVehicleRegisterModal, - onNewVehicleDataChange, - onRegisterVehicle, onClose, onFormChange, onImageSelect, @@ -197,21 +143,6 @@ export function ProfileModal({ } }, [isOpen]); - // 차량 상태 한글 변환 - const getStatusLabel = (status: string | null) => { - switch (status) { - case "off": - return "대기"; - case "active": - return "운행중"; - case "inactive": - return "공차"; - case "maintenance": - return "정비"; - default: - return status || "-"; - } - }; return ( <> @@ -356,151 +287,6 @@ export function ProfileModal({ - {/* 운전자 정보 섹션 (공차중계 사용자만) */} - {isDriver && ( - <> - -
-
-
- -

차량/운전자 정보

-
- {/* 차량 유무에 따른 버튼 표시 */} - {hasVehicle ? ( - - ) : ( - - )} -
- - {/* 운전자 정보 (항상 수정 가능) */} - {driverFormData && onDriverFormChange && ( - <> - {/* 차량 정보 - 차량이 있을 때만 수정 가능 */} - {hasVehicle ? ( -
-
- - onDriverFormChange("vehicleNumber", e.target.value)} - placeholder="12가1234" - /> -
-
- - onDriverFormChange("vehicleType", e.target.value)} - placeholder="1톤 카고" - /> -
-
- ) : ( - /* 차량이 없는 경우: 안내 메시지 */ -
- -

등록된 차량이 없습니다.

-

새 차량 등록 버튼을 눌러 차량을 등록하세요.

-
- )} - - {/* 운전자 개인 정보 - 항상 수정 가능 */} -
-
- - onDriverFormChange("phoneNumber", e.target.value)} - placeholder="010-1234-5678" - /> -
-
- - onDriverFormChange("licenseNumber", e.target.value)} - placeholder="12-34-567890-12" - /> -
-
- -
- - onDriverFormChange("branchName", e.target.value)} - placeholder="서울 본점" - /> -
- - {/* 차량 상태 - 차량이 있을 때만 표시 */} - {hasVehicle && driverInfo && onDriverStatusChange && ( -
- -
- - {getStatusLabel(driverInfo.vehicleStatus)} - -
- - -
-
-

- * 운행/공차 상태는 공차등록 화면에서 변경하세요 -

-
- )} - - )} -
- - )} @@ -523,49 +309,6 @@ export function ProfileModal({ type={alertModal.type} /> - {/* 새 차량 등록 모달 */} - {isVehicleRegisterModalOpen && newVehicleData && onNewVehicleDataChange && onRegisterVehicle && onCloseVehicleRegisterModal && ( - - - - 새 차량 등록 - - 새로운 차량 정보를 입력해주세요. - - - -
-
- - onNewVehicleDataChange("vehicleNumber", e.target.value)} - placeholder="12가1234" - /> -
-
- - onNewVehicleDataChange("vehicleType", e.target.value)} - placeholder="1톤 카고" - /> -
-
- - - - - -
-
- )} ); } diff --git a/frontend/hooks/useProfile.ts b/frontend/hooks/useProfile.ts index b3956d4f..ab2acf3b 100644 --- a/frontend/hooks/useProfile.ts +++ b/frontend/hooks/useProfile.ts @@ -1,20 +1,9 @@ "use client"; -import { useState, useCallback, useEffect } from "react"; +import { useState, useCallback } from "react"; import { ProfileFormData, ProfileModalState } from "@/types/profile"; import { LAYOUT_CONFIG, MESSAGES } from "@/constants/layout"; import { apiCall } from "@/lib/api/client"; -import { - getDriverProfile, - updateDriverProfile, - updateDriverStatus, - deleteDriverAccount, - deleteDriverVehicle, - registerDriverVehicle, - DriverProfile, - VehicleRegisterData, -} from "@/lib/api/driver"; -import { DriverInfo, DriverFormData } from "@/components/layout/ProfileModal"; // 알림 모달 상태 타입 interface AlertModalState { @@ -59,26 +48,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr }> >([]); - // 운전자 정보 상태 - const [isDriver, setIsDriver] = useState(false); - const [hasVehicle, setHasVehicle] = useState(false); // 차량 보유 여부 - const [driverInfo, setDriverInfo] = useState(null); - const [driverFormData, setDriverFormData] = useState({ - vehicleNumber: "", - vehicleType: "", - licenseNumber: "", - phoneNumber: "", - branchName: "", - }); - - // 새 차량 등록 모달 상태 - const [isVehicleRegisterModalOpen, setIsVehicleRegisterModalOpen] = useState(false); - const [newVehicleData, setNewVehicleData] = useState({ - vehicleNumber: "", - vehicleType: "", - branchName: "", - }); - // 알림 모달 표시 함수 const showAlert = useCallback((title: string, message: string, type: "success" | "error" | "info" = "info") => { setAlertModal({ @@ -106,41 +75,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr } }, []); - // 운전자 정보 로드 함수 - const loadDriverInfo = useCallback(async () => { - try { - const response = await getDriverProfile(); - if (response.success && response.data) { - setIsDriver(true); - // 차량 보유 여부 확인 - const vehicleExists = !!response.data.vehicleNumber; - setHasVehicle(vehicleExists); - setDriverInfo({ - vehicleNumber: response.data.vehicleNumber, - vehicleType: response.data.vehicleType, - licenseNumber: response.data.licenseNumber, - phoneNumber: response.data.phoneNumber, - vehicleStatus: response.data.vehicleStatus, - branchName: response.data.branchName, - }); - setDriverFormData({ - vehicleNumber: response.data.vehicleNumber || "", - vehicleType: response.data.vehicleType || "", - licenseNumber: response.data.licenseNumber || "", - phoneNumber: response.data.phoneNumber || "", - branchName: response.data.branchName || "", - }); - } else { - setIsDriver(false); - setHasVehicle(false); - setDriverInfo(null); - } - } catch (error) { - console.error("운전자 정보 로드 실패:", error); - setIsDriver(false); - } - }, []); - /** * 프로필 모달 열기 */ @@ -148,8 +82,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr if (user) { // 부서 목록 로드 loadDepartments(); - // 운전자 정보 로드 - loadDriverInfo(); setModalState((prev) => ({ ...prev, @@ -166,7 +98,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr isSaving: false, })); } - }, [user, loadDepartments, loadDriverInfo]); + }, [user, loadDepartments]); /** * 프로필 모달 닫기 @@ -193,138 +125,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr })); }, []); - /** - * 운전자 폼 데이터 변경 - */ - const updateDriverFormData = useCallback((field: keyof DriverFormData, value: string) => { - setDriverFormData((prev) => ({ - ...prev, - [field]: value, - })); - }, []); - - /** - * 차량 상태 변경 (대기/정비) - */ - const handleDriverStatusChange = useCallback( - async (status: "off" | "maintenance") => { - try { - const response = await updateDriverStatus(status); - if (response.success) { - showAlert("상태 변경", response.message || "차량 상태가 변경되었습니다.", "success"); - // 운전자 정보 새로고침 - await loadDriverInfo(); - } else { - showAlert("상태 변경 실패", response.message || "상태 변경에 실패했습니다.", "error"); - } - } catch (error) { - console.error("차량 상태 변경 실패:", error); - showAlert("오류", "상태 변경 중 오류가 발생했습니다.", "error"); - } - }, - [showAlert, loadDriverInfo] - ); - - /** - * 회원 탈퇴 - */ - const handleDriverAccountDelete = useCallback(async () => { - if (!confirm("정말로 탈퇴하시겠습니까?\n차량 정보가 함께 삭제되며, 이 작업은 되돌릴 수 없습니다.")) { - return; - } - - try { - const response = await deleteDriverAccount(); - if (response.success) { - showAlert("탈퇴 완료", "회원 탈퇴가 완료되었습니다.", "success"); - // 로그아웃 처리 - window.location.href = "/login"; - } else { - showAlert("탈퇴 실패", response.message || "회원 탈퇴에 실패했습니다.", "error"); - } - } catch (error) { - console.error("회원 탈퇴 실패:", error); - showAlert("오류", "회원 탈퇴 중 오류가 발생했습니다.", "error"); - } - }, [showAlert]); - - /** - * 차량 삭제 - */ - const handleDeleteVehicle = useCallback(async () => { - if (!confirm("이 차량을 더 이상 사용하지 않습니까?\n차량 정보가 삭제됩니다.")) { - return; - } - - try { - const response = await deleteDriverVehicle(); - if (response.success) { - showAlert("삭제 완료", "차량이 삭제되었습니다.", "success"); - // 운전자 정보 새로고침 - await loadDriverInfo(); - } else { - showAlert("삭제 실패", response.message || "차량 삭제에 실패했습니다.", "error"); - } - } catch (error) { - console.error("차량 삭제 실패:", error); - showAlert("오류", "차량 삭제 중 오류가 발생했습니다.", "error"); - } - }, [showAlert, loadDriverInfo]); - - /** - * 새 차량 등록 모달 열기 - */ - const openVehicleRegisterModal = useCallback(() => { - setNewVehicleData({ - vehicleNumber: "", - vehicleType: "", - branchName: driverFormData.branchName || "", // 기존 소속 지점 유지 - }); - setIsVehicleRegisterModalOpen(true); - }, [driverFormData.branchName]); - - /** - * 새 차량 등록 모달 닫기 - */ - const closeVehicleRegisterModal = useCallback(() => { - setIsVehicleRegisterModalOpen(false); - }, []); - - /** - * 새 차량 데이터 변경 - */ - const updateNewVehicleData = useCallback((field: keyof VehicleRegisterData, value: string) => { - setNewVehicleData((prev) => ({ - ...prev, - [field]: value, - })); - }, []); - - /** - * 새 차량 등록 처리 - */ - const handleRegisterVehicle = useCallback(async () => { - if (!newVehicleData.vehicleNumber) { - showAlert("입력 오류", "차량번호는 필수입니다.", "error"); - return; - } - - try { - const response = await registerDriverVehicle(newVehicleData); - if (response.success) { - showAlert("등록 완료", "차량이 등록되었습니다.", "success"); - setIsVehicleRegisterModalOpen(false); - // 운전자 정보 새로고침 - await loadDriverInfo(); - } else { - showAlert("등록 실패", response.message || "차량 등록에 실패했습니다.", "error"); - } - } catch (error) { - console.error("차량 등록 실패:", error); - showAlert("오류", "차량 등록 중 오류가 발생했습니다.", "error"); - } - }, [newVehicleData, showAlert, loadDriverInfo]); - /** * 이미지 선택 처리 */ @@ -429,22 +229,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr // API 호출 (JWT 토큰 자동 포함) const response = await apiCall("PUT", "/admin/profile", updateData); - // 운전자 정보도 저장 (운전자인 경우) - if (isDriver) { - const driverResponse = await updateDriverProfile({ - userName: modalState.form_data.user_name, - phoneNumber: driverFormData.phoneNumber, - licenseNumber: driverFormData.licenseNumber, - vehicleNumber: driverFormData.vehicleNumber, - vehicleType: driverFormData.vehicleType, - branchName: driverFormData.branchName, - }); - - if (!driverResponse.success) { - console.warn("운전자 정보 저장 실패:", driverResponse.message); - } - } - if (response.success || (response as any).result) { // locale이 변경된 경우 전역 변수와 localStorage 업데이트 const localeChanged = modalState.form_data.locale && modalState.form_data.locale !== user.locale; @@ -481,7 +265,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr } finally { setModalState((prev) => ({ ...prev, isSaving: false })); } - }, [user, modalState.selected_file, modalState.selected_image, modalState.form_data, refreshUserData, showAlert, isDriver, driverFormData]); + }, [user, modalState.selected_file, modalState.selected_image, modalState.form_data, refreshUserData, showAlert]); return { // 상태 @@ -495,16 +279,6 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr alertModal, closeAlert, - // 운전자 관련 상태 - isDriver, - hasVehicle, - driverInfo, - driverFormData, - - // 새 차량 등록 모달 상태 - isVehicleRegisterModalOpen, - newVehicleData, - // 액션 openProfileModal, closeProfileModal, @@ -512,15 +286,5 @@ export const useProfile = (user: any, refreshUserData: () => Promise, refr selectImage, removeImage, saveProfile, - - // 운전자 관련 액션 - updateDriverFormData, - handleDriverStatusChange, - handleDriverAccountDelete, - handleDeleteVehicle, - openVehicleRegisterModal, - closeVehicleRegisterModal, - updateNewVehicleData, - handleRegisterVehicle, }; };