Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 41 additions & 13 deletions src/app/mypage/account/account-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,72 @@ 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<User | null>(null);
// 로그인 관련 로직을 실행하는 함수. 호출 시 내부적으로 토큰 및 사용자 정보를 갱신
const [, login] = useAtom(loginAtom);

// 사용자 입력값을 저장하는 상태 변수
const [formData, setFormData] = useState<
Partial<User & { password?: string; confirmPassword?: string }>
>({
name: '',
email: '',
password: '',
confirmPassword: '',
phone: '',
phoneNumber: '',
});

// userAtom 값이 변경될 때마다 formData를 업데이트
// 로그인한 사용자 정보(user)가 존재하면 formData 상태를 해당 사용자 정보로 초기화
useEffect(() => {
if (user) {
setFormData({
name: user.name || '',
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<HTMLInputElement>) => {
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('인증 정보가 유효하지 않습니다. 다시 로그인해주세요.');
Expand All @@ -59,16 +83,20 @@ export default function AccountForm() {
}
const token = currentAuth.token;

// 3. 서버에 전송할 사용자 정보 객체 생성
const updateData: Partial<User> & { 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;
Expand All @@ -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,
};
}

Expand All @@ -99,7 +127,7 @@ export default function AccountForm() {
};

return (
<form className="space-y-6 w-full max-w-4xl" onSubmit={handleSubmit}>
<form className="w-full max-w-4xl space-y-6" onSubmit={handleSubmit}>
<LabeledInputBox
label="담당자 이름"
name="name"
Expand Down Expand Up @@ -154,9 +182,9 @@ export default function AccountForm() {
</LabeledInputBox>
<LabeledInputBox
label="휴대전화"
name="phone"
name="phoneNumber"
type="tel"
value={formData.phone}
value={formData.phoneNumber}
onChange={handleChange}
direction="row"
width="w-[400px]"
Expand Down
160 changes: 124 additions & 36 deletions src/app/mypage/company/company-form.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,172 @@
'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] = useState<User | null>(null);
const [, login] = useAtom(loginAtom);
const [formData, setFormData] = useState<
Partial<User & { password?: string; confirmPassword?: string }>
>({
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<HTMLInputElement>) => {
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<User> & { 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 (
<form className="w-full max-w-4xl space-y-6" onSubmit={handleSubmit}>
<LabeledInputBox
label="담당자 이름"
label="회사명"
name="companyName"
type="text"
value={formData.name}
value={formData.companyName}
onChange={handleChange}
direction="row"
width="w-[400px]"
labelWidth="w-[100px]"
labelWidth="w-[120px]"
className="gap-4"
/>
<LabeledInputBox
label="이메일"
type="email"
value={formData.email}
onChange={handleChange}
direction="row"
width="w-[400px]"
labelWidth="w-[100px]"
className="gap-4"
/>
<LabeledInputBox
label="비밀번호"
type="password"
value={formData.password}
label="대표자명"
name='ceoName'
type="text"
value={formData.ceoName}
onChange={handleChange}
direction="row"
width="w-[400px]"
labelWidth="w-[100px]"
labelWidth="w-[120px]"
className="gap-4"
/>
<LabeledInputBox
label="비밀번호 확인"
type="password"
value={formData.confirmPassword}
label="사업자 등록 번호"
name='companyCode'
type="text"
value={formData.companyCode}
onChange={handleChange}
direction="row"
width="w-[400px]"
labelWidth="w-[100px]"
labelWidth="w-[120px]"
className="gap-4"
/>
<LabeledInputBox
label="휴대전화"
label="대표번호"
name='companyPhoneNumber'
type="tel"
value={formData.phone}
value={formData.companyPhoneNumber}
onChange={handleChange}
direction="row"
width="w-[400px]"
labelWidth="w-[100px]"
labelWidth="w-[120px]"
className="gap-4"
/>

<div className="flex justify-end">
<Button
type="submit"
className="mt-4 text-white bg-black border border-black w-1/8 hover:bg-white hover:text-black"
className="w-[100px] mt-4 text-white bg-black border border-black hover:bg-white hover:text-black"
>
저장
</Button>
Expand Down
4 changes: 2 additions & 2 deletions src/lib/api/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ interface SignupResponse {
name: string; // 사용자 이름
email: string; // 이메일 주소
role: string; // 권한 (일반적으로 'user')
company?: string; // 회사명 (선택적)
companyName?: string; // 회사명 (선택적)
};
token: string; // 자동 로그인을 위한 인증 토큰
}
Expand Down Expand Up @@ -145,7 +145,7 @@ export const signup = async (userData: SignUpRequest): Promise<SignupResponse> =
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' // 토큰이 없으면 임시 토큰 사용
};
Expand Down
2 changes: 1 addition & 1 deletion src/lib/api/core/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

// 로컬 스토리지에 인증 정보를 저장할 때 사용하는 키
Expand Down
Loading