-
Notifications
You must be signed in to change notification settings - Fork 1
✨ feat: 내 프로필 상세 페이지 구현 #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
837cab1
✨ feat: 데이터 불러오는 로직 구현
Yun-Jinwoo 1107138
🐛 fix: 초기 랜더링시 로그인 정보 인식 불가 문제 수정
Yun-Jinwoo b4845b0
🐛 fix: 초기 랜더링시 로그인 정보 인식 불가 문제 수정
Yun-Jinwoo 42a66c5
✨ feat: 전화번호 포멧팅 함수 추가
Yun-Jinwoo f8353a1
✨ feat: 프로필 상세 페이지의 내 프로필 부분 구현
Yun-Jinwoo e8cbae0
✨ feat: 프로필 상세 페이지의 신청 내역 부분 구현
Yun-Jinwoo 1028973
Merge branch 'develop' of https://github.com/codeit-6team/The-julge i…
Yun-Jinwoo f01c239
✨ feat: 내 프로필 상세 페이지 구현
Yun-Jinwoo 18c13c2
🎨 style: 정보 없을 때 신청 내역도 가리기 + 공간 추가
Yun-Jinwoo bbbc32b
🎨 style: 밑공간 남는 부분에 대한 수정
Yun-Jinwoo 3aad51f
🎨 style: 밑공간 남는 부분에 대한 스타일 추가
Yun-Jinwoo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,174 @@ | ||
| 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 ( | ||
| <> | ||
| <Link to="/profile/edit">등록하기</Link> | ||
| {isLoading ? ( | ||
| <div className="flex min-h-[calc(100vh-102px)] items-center justify-center md:min-h-[calc(100vh-70px)]"> | ||
| <div className="size-100 animate-spin rounded-full border-8 border-gray-200 border-t-primary" /> | ||
| </div> | ||
| ) : ( | ||
| <div className="min-h-[calc(100vh-102px)] md:min-h-[calc(100vh-70px)]"> | ||
| {!hasInfo ? ( | ||
| <div className="mx-12 flex flex-col gap-16 py-40 md:mx-32 md:gap-24 md:py-60 lg:mx-auto lg:w-964"> | ||
| <h1 className="text-h3 font-bold md:text-h1">내 프로필</h1> | ||
| <RegisterLayout type="profile" /> | ||
| </div> | ||
| ) : ( | ||
| <div className="mx-12 flex flex-col gap-16 py-40 md:mx-32 md:gap-24 md:py-60 lg:mx-auto lg:w-964 lg:flex-row lg:justify-between lg:gap-180"> | ||
| <h1 className="text-h3 font-bold md:text-h1">내 프로필</h1> | ||
| <div className="flex justify-between rounded-[12px] bg-red-10 p-20 md:p-32 lg:flex-1"> | ||
| <div className="flex flex-col gap-8 md:gap-12"> | ||
| <div className="flex flex-col gap-8"> | ||
| <div className="text-body2/17 font-bold text-primary md:text-body1/20"> | ||
| 이름 | ||
| </div> | ||
| <h2 className="text-h2/29 font-bold md:text-h1/34"> | ||
| {profileInfo.name} | ||
| </h2> | ||
| </div> | ||
| <div className="flex items-center gap-6 text-body2/22 text-gray-50 md:text-body1/26"> | ||
| <img src={phone} className="size-16 md:size-20" /> | ||
| {formatPhone(profileInfo.phone)} | ||
| </div> | ||
| <div className="flex items-center gap-6 text-body2/22 text-gray-50 md:text-body1/26"> | ||
| <img src={location} className="size-16 md:size-20" /> | ||
| 선호 지역: {profileInfo.address} | ||
| </div> | ||
| {profileInfo.bio && ( | ||
| <p className="mt-12 text-body2/22 md:mt-16 md:text-body1/26"> | ||
| {profileInfo.bio} | ||
| </p> | ||
| )} | ||
| </div> | ||
| <Button | ||
| size={buttonSize} | ||
| solid={false} | ||
| onClick={() => navigate('/profile/edit')} | ||
| className="w-108 shrink-0 md:w-169" | ||
| > | ||
| 편집하기 | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| )} | ||
|
|
||
| {hasInfo ? ( | ||
| <div className="bg-gray-5"> | ||
| <div className="mx-12 flex flex-col gap-16 pt-40 pb-80 md:mx-32 md:gap-24 md:pt-60 md:pb-120 lg:mx-auto lg:w-964"> | ||
| <h1 className="text-h3 font-bold md:text-h1">신청 내역</h1> | ||
| {!hasApplications ? ( | ||
| <RegisterLayout type="application" /> | ||
| ) : ( | ||
| <Table | ||
| mode="user" | ||
| userId={localStorage.getItem('userId') ?? ''} | ||
| /> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ) : ( | ||
| <div className="h-355 md:h-463" /> | ||
| )} | ||
| <Footer /> | ||
| {modal.isOpen && ( | ||
| <Modal | ||
| onClose={handleModalConfirm} | ||
| onButtonClick={handleModalConfirm} | ||
| > | ||
| {modal.message} | ||
| </Modal> | ||
| )} | ||
| </div> | ||
| )} | ||
| </> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; // 그대로 보여줌 | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 아마 2-4-4, 2-3-4, 4-4, 3-4 등의 배열도 가능할 거 같긴 합니다~ 다만 급한 기능은 아니니 참고만 해주세요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제공된 api내에서 전화번호 유효성을 체크하는데 명확한 기준은 모르겠으나 아마 개인번호로 설정이 되어있는것 같아요~ 그래서 맨앞에 010, 011 등 정해진 숫자가 아니면 안되더라구요