diff --git a/src/components/common/Dropdown.tsx b/src/components/common/Dropdown.tsx index 25d3815a..671cc2d7 100644 --- a/src/components/common/Dropdown.tsx +++ b/src/components/common/Dropdown.tsx @@ -9,10 +9,11 @@ import Down from '@/assets/icons/dropdown.svg'; interface DropdownProps { options: readonly T[]; - selected: T; - setSelect: Dispatch>; // Dispatch>는 set함수 타입 + selected: T | null; + setSelect: Dispatch>; // Dispatch>는 set함수 타입 placeholder?: string; variant: 'form' | 'filter'; + id?: string; } export default function Dropdown({ @@ -21,6 +22,7 @@ export default function Dropdown({ setSelect, placeholder = '선택', variant, + id, }: DropdownProps) { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); @@ -54,6 +56,7 @@ export default function Dropdown({ return (
; + return ( + <> + 등록하기 + + ); } diff --git a/src/pages/profile/ProfileForm.tsx b/src/pages/profile/ProfileForm.tsx index 8944225d..dff3bd50 100644 --- a/src/pages/profile/ProfileForm.tsx +++ b/src/pages/profile/ProfileForm.tsx @@ -1,3 +1,207 @@ +import { useState, useEffect, useCallback, useContext } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { AuthContext } from '@/context/AuthContext'; +import { getUser, putUser, type SeoulDistrict } from '@/api/userApi'; +import Dropdown from '@/components/common/Dropdown'; +import Input from '@/components/common/Input'; +import Button from '@/components/common/Button'; +import Modal from '@/components/common/Modal'; +import close from '@/assets/icons/close.svg'; +import { ADDRESS_OPTIONS } from '@/constants/dropdownOptions'; + export default function ProfileForm() { - return
내 프로필 등록/편집 (알바님)
; + const navigate = useNavigate(); + const { isLoggedIn } = useContext(AuthContext); + // 사용자 입력값 상태 (이름, 전화번호, 소개글) + const [profileInfo, setProfileInfo] = useState({ + name: '', + phone: '', + bio: '', + }); + + // dropdown 컴포넌트에 set함수를 전달하기 위해 address는 따로 분리 + const [selectedAddress, setSelectedAddress] = useState( + null, + ); + + const [modal, setModal] = useState({ + isOpen: false, + message: '', + }); + + useEffect(() => { + if (isLoggedIn) { + 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 ?? '', + bio: userInfo.item.bio ?? '', + }); + setSelectedAddress((userInfo.item.address as SeoulDistrict) ?? ''); + } catch (error) { + setModal({ + isOpen: true, + message: (error as Error).message, + }); + } + }; + fetchUserInfo(); + } else { + setModal({ + isOpen: true, + message: '로그인이 필요합니다.', + }); + } + }, [isLoggedIn]); + + function handleChange( + e: React.ChangeEvent, + ) { + const { name, value } = e.target; + const sanitized = name === 'phone' ? value.replace(/[^0-9]/g, '') : value; // phone은 숫자만 입력 가능하도록 설정 + + setProfileInfo((prev) => ({ + ...prev, + [name]: sanitized, + })); + } + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + const { name, phone, bio } = profileInfo; + const userId = localStorage.getItem('userId'); + // 로그인이 안된 상태에 대한 처리 + if (!isLoggedIn || !userId) { + setModal({ + isOpen: true, + message: '로그인이 필요합니다.', + }); + return; + } + + // 이름이 입력되지 않은 경우 + if (!name.trim()) { + setModal({ + isOpen: true, + message: '이름을 입력해주세요.', + }); + return; + } + + // 지역이 선택되지 않은 경우 + if (!selectedAddress) { + setModal({ + isOpen: true, + message: '선호 지역을 선택해주세요', + }); + return; + } + + try { + await putUser(userId, { + name, + phone, + address: selectedAddress, + bio, + }); + setModal({ + isOpen: true, + message: '등록이 완료되었습니다.', + }); + } catch (error) { + setModal({ + isOpen: true, + message: (error as Error).message, + }); + } + } + + const handleModalConfirm = useCallback(() => { + if (modal.message === '등록이 완료되었습니다.') { + setModal({ isOpen: false, message: '' }); + navigate('/profile'); + } else if (modal.message.includes('로그인')) { + setModal({ isOpen: false, message: '' }); + navigate('/login'); + } else { + setModal({ isOpen: false, message: '' }); + } + }, [modal.message, navigate]); + + return ( +
+
+
+

내 프로필

+ + 닫기 + +
+
+
+
+ + +
+ + +
+
+
+ + +
+
+ +
+
+ {modal.isOpen && ( + + {modal.message} + + )} +
+ ); }