차량관리(기초데이터) 구현

This commit is contained in:
dohyeons
2025-12-01 18:41:02 +09:00
parent cea2421899
commit 9c3f1d26ad
10 changed files with 914 additions and 3 deletions

View File

@@ -4,6 +4,14 @@ import { useState, useCallback, useEffect } 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,
DriverProfile,
} from "@/lib/api/driver";
import { DriverInfo, DriverFormData } from "@/components/layout/ProfileModal";
// 알림 모달 상태 타입
interface AlertModalState {
@@ -48,6 +56,16 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
}>
>([]);
// 운전자 정보 상태
const [isDriver, setIsDriver] = useState(false);
const [driverInfo, setDriverInfo] = useState<DriverInfo | null>(null);
const [driverFormData, setDriverFormData] = useState<DriverFormData>({
vehicleNumber: "",
vehicleType: "",
licenseNumber: "",
phoneNumber: "",
});
// 알림 모달 표시 함수
const showAlert = useCallback((title: string, message: string, type: "success" | "error" | "info" = "info") => {
setAlertModal({
@@ -75,6 +93,35 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
}
}, []);
// 운전자 정보 로드 함수
const loadDriverInfo = useCallback(async () => {
try {
const response = await getDriverProfile();
if (response.success && response.data) {
setIsDriver(true);
setDriverInfo({
vehicleNumber: response.data.vehicleNumber,
vehicleType: response.data.vehicleType,
licenseNumber: response.data.licenseNumber,
phoneNumber: response.data.phoneNumber,
vehicleStatus: response.data.vehicleStatus,
});
setDriverFormData({
vehicleNumber: response.data.vehicleNumber || "",
vehicleType: response.data.vehicleType || "",
licenseNumber: response.data.licenseNumber || "",
phoneNumber: response.data.phoneNumber || "",
});
} else {
setIsDriver(false);
setDriverInfo(null);
}
} catch (error) {
console.error("운전자 정보 로드 실패:", error);
setIsDriver(false);
}
}, []);
/**
* 프로필 모달 열기
*/
@@ -82,6 +129,8 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
if (user) {
// 부서 목록 로드
loadDepartments();
// 운전자 정보 로드
loadDriverInfo();
setModalState((prev) => ({
...prev,
@@ -98,7 +147,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
isSaving: false,
}));
}
}, [user, loadDepartments]);
}, [user, loadDepartments, loadDriverInfo]);
/**
* 프로필 모달 닫기
@@ -125,6 +174,61 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, 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]);
/**
* 이미지 선택 처리
*/
@@ -229,6 +333,21 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
// API 호출 (JWT 토큰 자동 포함)
const response = await apiCall("PUT", "/admin/profile", updateData);
// 운전자 정보도 저장 (운전자인 경우)
if (isDriver) {
const driverResponse = await updateDriverProfile({
userName: modalState.formData.userName,
phoneNumber: driverFormData.phoneNumber,
licenseNumber: driverFormData.licenseNumber,
vehicleNumber: driverFormData.vehicleNumber,
vehicleType: driverFormData.vehicleType,
});
if (!driverResponse.success) {
console.warn("운전자 정보 저장 실패:", driverResponse.message);
}
}
if (response.success || (response as any).result) {
// locale이 변경된 경우 전역 변수와 localStorage 업데이트
const localeChanged = modalState.formData.locale && modalState.formData.locale !== user.locale;
@@ -265,7 +384,7 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
} finally {
setModalState((prev) => ({ ...prev, isSaving: false }));
}
}, [user, modalState.selectedFile, modalState.selectedImage, modalState.formData, refreshUserData, showAlert]);
}, [user, modalState.selectedFile, modalState.selectedImage, modalState.formData, refreshUserData, showAlert, isDriver, driverFormData]);
return {
// 상태
@@ -279,6 +398,11 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
alertModal,
closeAlert,
// 운전자 관련 상태
isDriver,
driverInfo,
driverFormData,
// 액션
openProfileModal,
closeProfileModal,
@@ -286,5 +410,10 @@ export const useProfile = (user: any, refreshUserData: () => Promise<void>, refr
selectImage,
removeImage,
saveProfile,
// 운전자 관련 액션
updateDriverFormData,
handleDriverStatusChange,
handleDriverAccountDelete,
};
};