From b80a6c32a7a309f9b1b9e381c5d5c242eb01af51 Mon Sep 17 00:00:00 2001 From: ji-young Date: Fri, 4 Apr 2025 17:49:06 +0900 Subject: [PATCH 1/3] =?UTF-8?q?phoneNumber=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mypage/account/account-form.tsx | 14 +++++++------- src/lib/api/core/axios.ts | 2 +- src/lib/api/user/index.ts | 4 ++-- src/lib/atoms/auth.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/mypage/account/account-form.tsx b/src/app/mypage/account/account-form.tsx index 0522c0a..518450e 100644 --- a/src/app/mypage/account/account-form.tsx +++ b/src/app/mypage/account/account-form.tsx @@ -20,7 +20,7 @@ export default function AccountForm() { email: '', password: '', confirmPassword: '', - phone: '', + phoneNumber: '', }); useEffect(() => { @@ -30,7 +30,7 @@ export default function AccountForm() { email: user.email || '', password: '', confirmPassword: '', - phone: user.phone || '', + phoneNumber: user.phoneNumber || '', }); } }, [user]); @@ -62,7 +62,7 @@ export default function AccountForm() { const updateData: Partial & { password?: string } = { name: formData.name, email: formData.email, - phone: formData.phone, + phoneNumber: formData.phoneNumber, }; if (formData.password) { updateData.password = formData.password; @@ -79,7 +79,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 +99,7 @@ export default function AccountForm() { }; return ( -
+ => { 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으로 매핑 }; return user; @@ -84,7 +84,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; diff --git a/src/lib/atoms/auth.ts b/src/lib/atoms/auth.ts index d418218..b6037a9 100644 --- a/src/lib/atoms/auth.ts +++ b/src/lib/atoms/auth.ts @@ -10,7 +10,7 @@ export interface User { email: string; role: string; company?: string; - phone?: string; // phone 속성 추가 + phoneNumber?: string; // phone 속성 추가 } export interface AuthState { From 93aaae006bd175cb540908fede393844f688d0d0 Mon Sep 17 00:00:00 2001 From: ji-young Date: Sat, 5 Apr 2025 18:01:46 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=ED=9A=8C=EC=82=AC=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mypage/account/account-form.tsx | 24 ++++- src/app/mypage/company/company-form.tsx | 129 ++++++++++++++++++------ src/lib/api/user/index.ts | 30 +++++- src/lib/atoms/auth.ts | 16 ++- 4 files changed, 157 insertions(+), 42 deletions(-) diff --git a/src/app/mypage/account/account-form.tsx b/src/app/mypage/account/account-form.tsx index 518450e..8c12a3f 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); + // 현재 로그인한 사용자의 정보. user는 사용자 객체, setUser는 사용자 정보 업데이트 함수 const [user, setUser] = useAtom(userAtom); + // 로그인 관련 로직을 실행하는 함수. 호출 시 내부적으로 토큰 및 사용자 정보를 갱신 const [, login] = useAtom(loginAtom); + // 사용자 입력값을 저장하는 상태 변수 const [formData, setFormData] = useState< Partial >({ @@ -23,6 +27,8 @@ export default function AccountForm() { phoneNumber: '', }); + // userAtom 값이 변경될 때마다 formData를 업데이트 + // 로그인한 사용자 정보(user)가 존재하면 formData 상태를 해당 사용자 정보로 초기화 useEffect(() => { if (user) { setFormData({ @@ -33,24 +39,28 @@ export default function AccountForm() { phoneNumber: user.phoneNumber || '', }); } - }, [user]); + }, [user]); // user 값이 변경될 때마다 실행 + // 입력 필드(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 +69,20 @@ export default function AccountForm() { } const token = currentAuth.token; + // 3. 서버에 전송할 사용자 정보 객체 생성 const updateData: Partial & { password?: string } = { name: formData.name, email: formData.email, 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; diff --git a/src/app/mypage/company/company-form.tsx b/src/app/mypage/company/company-form.tsx index fe8e1a9..c0a7f69 100644 --- a/src/app/mypage/company/company-form.tsx +++ b/src/app/mypage/company/company-form.tsx @@ -1,43 +1,109 @@ 'use client'; -import React, { useState } from 'react'; +import { useState, useEffect } from 'react'; import LabeledInputBox from '@/components/labeled-inputbox'; import { Button } from '@/components/ui/button'; +import { useAtom } from 'jotai'; +import { authAtom, userAtom, loginAtom } from '@/lib/atoms/auth'; +import type { AuthState, User } from '@/lib/atoms/auth'; +import api from '@/lib/api'; export default function AccountForm() { - const [formData, setFormData] = useState({ - name: '', - email: '', - password: '', - confirmPassword: '', - phone: '', + const [auth] = useAtom(authAtom); + const [user, setUser] = useAtom(userAtom); + 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.ceoName ||'', + companyPhoneNumber: user.companyPhoneNumber || '', + }); + } + }, [user]); // user 값이 변경될 때마다 실행 + const handleChange = (e: React.ChangeEvent) => { setFormData({ ...formData, [e.target.name]: e.target.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 ( - => { name: response.data.name, email: response.data.email, role: response.data.role || 'user', // role이 없으면 기본값 'user' 사용 - company: response.data.companyName, // companyName -> company로 매핑 - phoneNumber: 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; @@ -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; + } catch (error) { + console.error('[API User] 회사 정보 업데이트 오류:', error); + throw error; + } +} + /** * 사용자 프로필 이미지 업데이트 함수 * diff --git a/src/lib/atoms/auth.ts b/src/lib/atoms/auth.ts index b6037a9..49b47c0 100644 --- a/src/lib/atoms/auth.ts +++ b/src/lib/atoms/auth.ts @@ -11,7 +11,11 @@ export interface User { role: string; company?: string; 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) { From 5a8efd3e5c9977c42e078f5a2eca208276572851 Mon Sep 17 00:00:00 2001 From: ji-young Date: Sun, 6 Apr 2025 02:23:39 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=B0=8F=20?= =?UTF-8?q?=ED=9A=8C=EC=82=AC=20=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?,=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=A1=9C=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mypage/account/account-form.tsx | 16 ++++++++- src/app/mypage/company/company-form.tsx | 43 ++++++++++++++++++------- src/lib/api/auth/index.ts | 4 +-- src/lib/api/user/index.ts | 2 +- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/app/mypage/account/account-form.tsx b/src/app/mypage/account/account-form.tsx index 8c12a3f..571c724 100644 --- a/src/app/mypage/account/account-form.tsx +++ b/src/app/mypage/account/account-form.tsx @@ -12,7 +12,7 @@ export default function AccountForm() { // 현재 로그인한 사용자의 인증 정보 (예: 토큰) const [auth] = useAtom(authAtom); // 현재 로그인한 사용자의 정보. user는 사용자 객체, setUser는 사용자 정보 업데이트 함수 - const [user, setUser] = useAtom(userAtom); + const [user, setUser] = useState(null); // 로그인 관련 로직을 실행하는 함수. 호출 시 내부적으로 토큰 및 사용자 정보를 갱신 const [, login] = useAtom(loginAtom); @@ -41,6 +41,20 @@ export default function AccountForm() { } }, [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; // 입력 요소의 name 속성과 입력된 값 diff --git a/src/app/mypage/company/company-form.tsx b/src/app/mypage/company/company-form.tsx index c0a7f69..2c8adf6 100644 --- a/src/app/mypage/company/company-form.tsx +++ b/src/app/mypage/company/company-form.tsx @@ -10,7 +10,7 @@ import api from '@/lib/api'; export default function AccountForm() { const [auth] = useAtom(authAtom); - const [user, setUser] = useAtom(userAtom); + const [user, setUser] = useState(null); const [, login] = useAtom(loginAtom); const [formData, setFormData] = useState< Partial @@ -26,14 +26,33 @@ export default function AccountForm() { setFormData({ companyName: user.companyName || '', ceoName: user.ceoName || '', - companyCode: 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 = async (e: React.FormEvent) => { @@ -83,15 +102,15 @@ export default function AccountForm() { if (finalUserData) { login({ user: finalUserData, token: token }); - alert('프로필이 성공적으로 업데이트되었습니다.'); + alert('회사정보가 성공적으로 업데이트되었습니다.'); } else { console.warn('Could not determine updated user data after successful API call.'); - alert('프로필 업데이트는 성공했으나, 화면 갱신에 문제가 있을 수 있습니다.'); + alert('회사정보가 업데이트는 성공했으나, 화면 갱신에 문제가 있을 수 있습니다.'); } } catch (error) { - console.error('프로필 업데이트 오류:', error); + console.error('회사정보 업데이트 오류:', error); alert( - `프로필 업데이트 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}` + `회사정보 업데이트 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}` ); } }; @@ -107,7 +126,7 @@ export default function AccountForm() { onChange={handleChange} direction="row" width="w-[400px]" - labelWidth="w-[100px]" + labelWidth="w-[120px]" className="gap-4" />
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/user/index.ts b/src/lib/api/user/index.ts index c1acf35..1b51d7d 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -113,7 +113,7 @@ export const updateCompany = async (userData: companyUpdateRequest ): Promise = await axiosInstance.put('/users/update-company', userData); console.log('[API User] 회사 정보 업데이트 성공:', response.status); - return response.data; + return response.data as User; } catch (error) { console.error('[API User] 회사 정보 업데이트 오류:', error); throw error;