diff --git a/src/assets/icons/phone.svg b/src/assets/icons/phone.svg new file mode 100644 index 00000000..4e79d051 --- /dev/null +++ b/src/assets/icons/phone.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/pages/profile/Profile.tsx b/src/pages/profile/Profile.tsx index 134f0c1c..72624ea9 100644 --- a/src/pages/profile/Profile.tsx +++ b/src/pages/profile/Profile.tsx @@ -1,8 +1,172 @@ -import { Link } from 'react-router-dom'; +import { useState, useEffect, useContext, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { AuthContext } from '@/context/AuthContext'; +import RegisterLayout from '@/components/layout/RegisterLayout'; +import Footer from '@/components/layout/Footer'; +import Table from '@/components/common/table/Table'; +import Button from '@/components/common/Button'; +import Modal from '@/components/common/Modal'; +import { getUser } from '@/api/userApi'; +import { getUserApplications } from '@/api/applicationApi'; +import formatPhone from '@/utils/formatPhone'; +import phone from '@/assets/icons/phone.svg'; +import location from '@/assets/icons/location-red.svg'; + export default function Profile() { + const navigate = useNavigate(); + const { isLoggedIn } = useContext(AuthContext); + const [profileInfo, setProfileInfo] = useState({ + name: '', + phone: '', + address: '', + bio: '', + }); + const [hasInfo, setHasInfo] = useState(false); + const [hasApplications, setHasApplications] = useState(false); + const [modal, setModal] = useState({ + isOpen: false, + message: '', + }); + const [buttonSize, setButtonSize] = useState<'large' | 'medium'>('medium'); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const handleResize = () => { + if (window.innerWidth >= 768) { + setButtonSize('large'); + } else { + setButtonSize('medium'); + } + }; + + handleResize(); + window.addEventListener('resize', handleResize); + + return () => window.removeEventListener('resize', handleResize); + }, []); + + useEffect(() => { + const userId = localStorage.getItem('userId'); + + if (!userId) { + setModal({ + isOpen: true, + message: '로그인이 필요합니다.', + }); + return; + } + + const fetchUserInfo = async () => { + try { + const userInfo = await getUser(userId); + setProfileInfo({ + name: userInfo.item.name ?? '', + phone: userInfo.item.phone ?? '', + address: userInfo.item.address ?? '', + bio: userInfo.item.bio ?? '', + }); + setHasInfo(!!userInfo.item.name); + const applications = await getUserApplications(userId); + setHasApplications(applications.count > 0); + } catch (error) { + setModal({ + isOpen: true, + message: (error as Error).message, + }); + } finally { + setIsLoading(false); + } + }; + fetchUserInfo(); + }, [isLoggedIn]); + + const handleModalConfirm = useCallback(() => { + if (modal.message.includes('로그인')) { + setModal({ isOpen: false, message: '' }); + navigate('/login'); + } else { + setModal({ isOpen: false, message: '' }); + } + }, [modal.message, navigate]); + return ( <> - 등록하기 + {isLoading ? ( +
+
+
+ ) : ( +
+ {!hasInfo ? ( +
+

내 프로필

+ +
+ ) : ( +
+

내 프로필

+
+
+
+
+ 이름 +
+

+ {profileInfo.name} +

+
+
+ + {formatPhone(profileInfo.phone)} +
+
+ + 선호 지역: {profileInfo.address} +
+ {profileInfo.bio && ( +

+ {profileInfo.bio} +

+ )} +
+ +
+
+ )} + + {hasInfo && ( +
+
+

신청 내역

+ {!hasApplications ? ( + + ) : ( + + )} + + + )} +
+ {modal.isOpen && ( + + {modal.message} + + )} + + )} ); } diff --git a/src/pages/profile/ProfileForm.tsx b/src/pages/profile/ProfileForm.tsx index dff3bd50..f66624de 100644 --- a/src/pages/profile/ProfileForm.tsx +++ b/src/pages/profile/ProfileForm.tsx @@ -30,40 +30,33 @@ export default function ProfileForm() { }); useEffect(() => { - if (isLoggedIn) { - const userId = localStorage.getItem('userId'); - - if (!userId) { - setModal({ - isOpen: true, - message: '사용자 정보를 가져올 수 없습니다. 다시 로그인해주세요.', - }); - return; - } + const userId = localStorage.getItem('userId'); - const fetchUserInfo = async () => { - try { - const userInfo = await getUser(userId); - setProfileInfo({ - name: userInfo.item.name ?? '', - phone: userInfo.item.phone ?? '', - bio: userInfo.item.bio ?? '', - }); - setSelectedAddress((userInfo.item.address as SeoulDistrict) ?? ''); - } catch (error) { - setModal({ - isOpen: true, - message: (error as Error).message, - }); - } - }; - fetchUserInfo(); - } else { + if (!userId) { setModal({ isOpen: true, message: '로그인이 필요합니다.', }); + return; } + + const fetchUserInfo = async () => { + try { + const userInfo = await getUser(userId); + setProfileInfo({ + name: userInfo.item.name ?? '', + phone: userInfo.item.phone ?? '', + bio: userInfo.item.bio ?? '', + }); + setSelectedAddress((userInfo.item.address as SeoulDistrict) ?? ''); + } catch (error) { + setModal({ + isOpen: true, + message: (error as Error).message, + }); + } + }; + fetchUserInfo(); }, [isLoggedIn]); function handleChange( diff --git a/src/utils/formatPhone.ts b/src/utils/formatPhone.ts new file mode 100644 index 00000000..aa69e1dc --- /dev/null +++ b/src/utils/formatPhone.ts @@ -0,0 +1,9 @@ +export default function formatPhone(phone: string) { + if (phone.length === 11) { + return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3'); + } else if (phone.length === 10) { + return phone.replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3'); + } else { + return phone; // 그대로 보여줌 + } +}