diff --git a/src/app/mypage/account/account-form.tsx b/src/app/mypage/account/account-form.tsx index 0522c0a..571c724 100644 --- a/src/app/mypage/account/account-form.tsx +++ b/src/app/mypage/account/account-form.tsx @@ -9,10 +9,14 @@ import type { AuthState, User } from '@/lib/atoms/auth'; import api from '@/lib/api'; export default function AccountForm() { + // 현재 로그인한 사용자의 인증 정보 (예: 토큰) const [auth] = useAtom(authAtom); - const [user, setUser] = useAtom(userAtom); + // 현재 로그인한 사용자의 정보. user는 사용자 객체, setUser는 사용자 정보 업데이트 함수 + const [user, setUser] = useState(null); + // 로그인 관련 로직을 실행하는 함수. 호출 시 내부적으로 토큰 및 사용자 정보를 갱신 const [, login] = useAtom(loginAtom); + // 사용자 입력값을 저장하는 상태 변수 const [formData, setFormData] = useState< Partial >({ @@ -20,9 +24,11 @@ export default function AccountForm() { email: '', password: '', confirmPassword: '', - phone: '', + phoneNumber: '', }); + // userAtom 값이 변경될 때마다 formData를 업데이트 + // 로그인한 사용자 정보(user)가 존재하면 formData 상태를 해당 사용자 정보로 초기화 useEffect(() => { if (user) { setFormData({ @@ -30,27 +36,45 @@ export default function AccountForm() { email: user.email || '', password: '', confirmPassword: '', - phone: user.phone || '', + phoneNumber: user.phoneNumber || '', }); } - }, [user]); + }, [user]); // user 값이 변경될 때마다 실행 + useEffect(() => { + const fetchUserInfo = async () => { + try { + const userData = await api.user.getCurrentUser(); + console.log('사용자 정보:', userData); + setUser(userData); // 사용자 정보를 상태에 저장 + } catch (err) { + console.error('사용자 정보 조회 실패:', err); + } + }; + + fetchUserInfo(); + }, []) + + // 입력 필드(input)의 값이 변경될 때마다 호출되는 함수 const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; + const { name, value } = e.target; // 입력 요소의 name 속성과 입력된 값 setFormData((prevData: typeof formData) => ({ - ...prevData, - [name]: value, + ...prevData, // 이전 상태를 복사 + [name]: value, // 변경된 name 필드만 새로운 값으로 덮어씀 })); }; + // 폼 제출 시 호출되는 함수 const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); + e.preventDefault(); // 기본 제출 동작 방지 + // 1. 비밀번호 확인 유효성 검사 if (formData.password && formData.password !== formData.confirmPassword) { alert('비밀번호가 일치하지 않습니다.'); return; } + // 2. 인증 상태 검사 (로그인 여부 및 토큰 존재 확인) const currentAuth = auth as AuthState | null; if (!currentAuth || typeof currentAuth !== 'object' || !currentAuth.token) { alert('인증 정보가 유효하지 않습니다. 다시 로그인해주세요.'); @@ -59,16 +83,20 @@ export default function AccountForm() { } const token = currentAuth.token; + // 3. 서버에 전송할 사용자 정보 객체 생성 const updateData: Partial & { password?: string } = { name: formData.name, email: formData.email, - phone: formData.phone, + phoneNumber: formData.phoneNumber, }; + + // 비밀번호가 입력되었다면 포함 (선택적) if (formData.password) { updateData.password = formData.password; } try { + // 4. 사용자 정보 업데이트 요청(PUT) const updatedUserData = await api.user.updateUser(updateData); let finalUserData: User | null = null; @@ -79,7 +107,7 @@ export default function AccountForm() { ...user, name: formData.name ?? user.name, email: formData.email ?? user.email, - phone: formData.phone ?? user.phone, + phoneNumber: formData.phoneNumber ?? user.phoneNumber, }; } @@ -99,7 +127,7 @@ export default function AccountForm() { }; return ( -
+ (null); + const [, login] = useAtom(loginAtom); + const [formData, setFormData] = useState< + Partial + >({ + companyName: '', + ceoName: '', + companyCode: '', + companyPhoneNumber: '', }); + useEffect(() => { + if (user) { + setFormData({ + companyName: user.companyName || '', + ceoName: user.ceoName || '', + companyCode: user.companyCode ||'', + companyPhoneNumber: user.companyPhoneNumber || '', + }); + } + }, [user]); // user 값이 변경될 때마다 실행 + + useEffect(() => { + const fetchUserInfo = async () => { + try { + const userData = await api.user.getCurrentUser(); + console.log('사용자 정보:', userData); + setUser(userData); // 사용자 정보를 상태에 저장 + } catch (err) { + console.error('사용자 정보 조회 실패:', err); + } + }; + + fetchUserInfo(); + }, []) + + const handleChange = (e: React.ChangeEvent) => { - setFormData({ ...formData, [e.target.name]: e.target.value }); + const { name, value } = e.target; + setFormData((prevData: typeof formData) => ({ + ...prevData, + [name]: value, + })); }; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - console.log('Form Data:', formData); - }; + // 1. 비밀번호 확인 유효성 검사 + if (formData.password && formData.password !== formData.confirmPassword) { + alert('비밀번호가 일치하지 않습니다.'); + return; + } + + // 2. 인증 상태 검사 (로그인 여부 및 토큰 존재 확인) + const currentAuth = auth as AuthState | null; + if (!currentAuth || typeof currentAuth !== 'object' || !currentAuth.token) { + alert('인증 정보가 유효하지 않습니다. 다시 로그인해주세요.'); + console.error('handleSubmit Error: Invalid auth state', currentAuth); + return; + } + const token = currentAuth.token; + + // 3. 서버에 전송할 사용자 정보 객체 생성 + const updateData: Partial & { password?: string } = { + companyName: formData.companyName, + ceoName: formData.ceoName, + companyCode: formData.companyCode, + companyPhoneNumber: formData.companyPhoneNumber, + }; + + if (formData.password) { + updateData.password = formData.password; + } + + try { + // 4. 사용자 정보 업데이트 요청(PUT) + const updatedUserData = await api.user.updateCompany(updateData); + + let finalUserData: User | null = null; + if (updatedUserData && typeof updatedUserData === 'object' && updatedUserData.id) { + finalUserData = updatedUserData; + } else if (user) { + finalUserData = { + ...user, + name: formData.name ?? user.name, + email: formData.email ?? user.email, + phoneNumber: formData.phoneNumber ?? user.phoneNumber, + }; + } + + if (finalUserData) { + login({ user: finalUserData, token: token }); + alert('회사정보가 성공적으로 업데이트되었습니다.'); + } else { + console.warn('Could not determine updated user data after successful API call.'); + alert('회사정보가 업데이트는 성공했으나, 화면 갱신에 문제가 있을 수 있습니다.'); + } + } catch (error) { + console.error('회사정보 업데이트 오류:', error); + alert( + `회사정보 업데이트 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}` + ); + } + }; + return ( -
diff --git a/src/lib/api/auth/index.ts b/src/lib/api/auth/index.ts index 0fe0ca1..f9c9634 100644 --- a/src/lib/api/auth/index.ts +++ b/src/lib/api/auth/index.ts @@ -61,7 +61,7 @@ interface SignupResponse { name: string; // 사용자 이름 email: string; // 이메일 주소 role: string; // 권한 (일반적으로 'user') - company?: string; // 회사명 (선택적) + companyName?: string; // 회사명 (선택적) }; token: string; // 자동 로그인을 위한 인증 토큰 } @@ -145,7 +145,7 @@ export const signup = async (userData: SignUpRequest): Promise = name: response.data.name, email: response.data.email, role: 'user', // 기본 권한: 'user' - company: response.data.companyName + companyName: response.data.companyName }, token: response.data.token || 'temporary-token' // 토큰이 없으면 임시 토큰 사용 }; diff --git a/src/lib/api/core/axios.ts b/src/lib/api/core/axios.ts index 06d8e20..ff51f45 100644 --- a/src/lib/api/core/axios.ts +++ b/src/lib/api/core/axios.ts @@ -8,7 +8,7 @@ import { authAtom } from '@/lib/atoms/auth'; * 환경 변수에서 API URL을 가져오거나, 기본값을 사용합니다. * 개발 환경과 배포 환경에서 다른 URL을 사용할 수 있습니다. */ -const baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://192.168.0.224:8080/api'; +const baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api'; console.log('[AXIOS] API 기본 URL:', baseURL); // 로컬 스토리지에 인증 정보를 저장할 때 사용하는 키 diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 5fedc7a..1b51d7d 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -13,6 +13,14 @@ interface UserUpdateRequest { password?: string; // 새 비밀번호 (선택적) } + +interface companyUpdateRequest { + companyName?: string; // 회사 이름 (선택적) + ceoName?: string; // CEO 이름 (선택적) + companyCode?: string; // 회사 코드 (선택적) + companyPhoneNumber?: string; // 회사 전화번호 (선택적) +} + /** * 현재 로그인한 사용자 정보를 가져오는 함수 * @@ -47,8 +55,11 @@ export const getCurrentUser = async (): Promise => { name: response.data.name, email: response.data.email, role: response.data.role || 'user', // role이 없으면 기본값 'user' 사용 - company: response.data.companyName, // companyName -> company로 매핑 - phone: response.data.phoneNumber // phoneNumber -> phone으로 매핑 + phoneNumber: response.data.phoneNumber, // phoneNumber -> phone으로 매핑 + companyName: response.data.companyName, // companyName -> company로 매핑 + ceoName: response.data.ceoName, // ceoName -> ceo로 매핑 + companyCode: response.data.companyCode, // companyCode -> companyCode로 매핑 + companyPhoneNumber: response.data.companyPhoneNumber, // companyPhoneNumber -> companyPhoneNumber로 매핑 }; return user; @@ -84,7 +95,7 @@ export const updateUser = async (userData: UserUpdateRequest): Promise => try { console.log('[API User] 사용자 정보 업데이트 시도'); - const response: AxiosResponse = await axiosInstance.put('/user/update', userData); + const response: AxiosResponse = await axiosInstance.put('/users/update', userData); console.log('[API User] 사용자 정보 업데이트 성공:', response.status); return response.data; @@ -94,6 +105,21 @@ export const updateUser = async (userData: UserUpdateRequest): Promise => } }; +// 회사 정보 업데이트 함수 +export const updateCompany = async (userData: companyUpdateRequest ): Promise => { + try { + console.log('[API User] 회사 정보 업데이트 시도'); + + const response: AxiosResponse = await axiosInstance.put('/users/update-company', userData); + + console.log('[API User] 회사 정보 업데이트 성공:', response.status); + return response.data as User; + } catch (error) { + console.error('[API User] 회사 정보 업데이트 오류:', error); + throw error; + } +} + /** * 사용자 프로필 이미지 업데이트 함수 * diff --git a/src/lib/atoms/auth.ts b/src/lib/atoms/auth.ts index d418218..49b47c0 100644 --- a/src/lib/atoms/auth.ts +++ b/src/lib/atoms/auth.ts @@ -10,8 +10,12 @@ export interface User { email: string; role: string; company?: string; - phone?: string; // phone 속성 추가 -} + phoneNumber?: string; // phone 속성 추가 + companyName?: string; // companyName 속성 추가 + ceoName?: string; // ceoName 속성 추가 + companyCode?: string; // companyCode 속성 추가 + companyPhoneNumber?: string; // companyPhoneNumber 속성 추가 +} export interface AuthState { isLoggedIn: boolean; @@ -44,7 +48,9 @@ export const authInitializedAtom = atom(false); // --- 액션 Atom (Write-only) --- export const loginAtom = atom(null, (get, set, { user, token }: { user: User; token: string }) => { console.log('[Auth Atom Action] Login executed'); + // 인증 상태 갱신 set(authAtom, { isLoggedIn: true, user, token, isLoading: false }); + // 초기화 플래그 설정 if (!get(authInitializedAtom)) { set(authInitializedAtom, true); } @@ -60,10 +66,10 @@ export const logoutAtom = atom(null, (get, set) => { // --- 초기화 훅 --- export const useInitializeAuth = () => { - const [isLoading] = useAtom(isLoadingAtom); - const [isInitialized, setInitialized] = useAtom(authInitializedAtom); - const [auth] = useAtom(authAtom); - const [, logout] = useAtom(logoutAtom); + const [isLoading] = useAtom(isLoadingAtom); // 상태 복원 중 여부 + const [isInitialized, setInitialized] = useAtom (authInitializedAtom); // 초기화 여부 + const [auth] = useAtom(authAtom); // 전체 인증 상태 + const [, logout] = useAtom(logoutAtom); // 로그아웃 액션 useEffect(() => { if (!isLoading && !isInitialized) {