From 422aeb2a684703bd635dbcb0ef76726752516819 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Sun, 8 Dec 2024 21:26:48 +0900 Subject: [PATCH 01/14] =?UTF-8?q?=E2=9C=A8Feature=20:=20=EA=B2=AC=EC=A3=BC?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchOwnerProfile.ts | 39 +++++++ src/components/DogProfile/index.tsx | 4 +- src/components/DogProfile/styles.ts | 11 ++ src/modals/OwnerUpdateModal/index.tsx | 132 ++++++++++++++++++++++ src/modals/RegisterAvatarModal/styles.ts | 1 + src/pages/FamilyDDangPage/index.tsx | 7 +- src/pages/RegisterPage/Register/styles.ts | 20 +++- 7 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 src/apis/family/fetchOwnerProfile.ts create mode 100644 src/modals/OwnerUpdateModal/index.tsx diff --git a/src/apis/family/fetchOwnerProfile.ts b/src/apis/family/fetchOwnerProfile.ts new file mode 100644 index 00000000..40ccbe51 --- /dev/null +++ b/src/apis/family/fetchOwnerProfile.ts @@ -0,0 +1,39 @@ +import { AxiosError } from 'axios' +import { APIResponse, CommonAPIResponse, ErrorResponse } from '~types/api' +import { axiosInstance } from '~apis/axiosInstance' + +export type FetchOwnerProfileResponse = Pick< + CommonAPIResponse, + 'memberId' | 'name' | 'gender' | 'familyRole' | 'profileImg' +> + +export const fetchOwnerProfile = async (): Promise> => { + try { + const { data } = await axiosInstance.get>(`/member/update`) + console.log(data) + return data + } catch (error) { + if (error instanceof AxiosError) { + const { response } = error as AxiosError + + if (response) { + const { code, message } = response.data + switch (code) { + case 400: + throw new Error(message || '잘못된 요청입니다.') + case 401: + throw new Error(message || '인증에 실패했습니다.') + case 500: + throw new Error(message || '서버 오류가 발생했습니다.') + default: + throw new Error(message || '알 수 없는 오류가 발생했습니다.') + } + } + // 요청 자체가 실패한 경우 + throw new Error('네트워크 연결을 확인해주세요') + } + + console.error('예상치 못한 에러:', error) + throw new Error('다시 시도해주세요') + } +} diff --git a/src/components/DogProfile/index.tsx b/src/components/DogProfile/index.tsx index 76bf448b..8b9283e4 100644 --- a/src/components/DogProfile/index.tsx +++ b/src/components/DogProfile/index.tsx @@ -4,6 +4,7 @@ import { Separator } from '~components/Separator' import Profile from '~components/Profile' import { DogProfileType } from '~types/dogProfile' import { stringToDate } from '~utils/dateFormat' +import { MdOutlineModeEdit } from 'react-icons/md' //날짜 계산 로직 const calculateAge = (birthDate?: Date): number => { @@ -49,9 +50,8 @@ export default function DogProfile({ {weight} KG - + - 우리 댕댕이를 소개해요! diff --git a/src/components/DogProfile/styles.ts b/src/components/DogProfile/styles.ts index c747dc9c..d4554c6b 100644 --- a/src/components/DogProfile/styles.ts +++ b/src/components/DogProfile/styles.ts @@ -43,3 +43,14 @@ export const OneLineIntro = styled(Box)` display: none; } ` +export const EditIconWrapper = styled.div` + width: 2rem; + height: 2rem; + background-color: ${({ theme }) => theme.colors.brand.lighten_2}; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + margin-left: auto; + cursor: pointer; +` diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx new file mode 100644 index 00000000..930e4349 --- /dev/null +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -0,0 +1,132 @@ +import { useEffect } from 'react' +import * as S from '~pages/RegisterPage/Register/styles' +import { Helmet } from 'react-helmet-async' +import AddOwnerAvatar from '~assets/add-dog-picture.svg' +import GenderSelectButton from '~components/GenderSelectButton' +import { Input } from '~components/Input' +import RegisterAvatarModal from '~modals/RegisterAvatarModal' +import { useModalStore } from '~stores/modalStore' +import { ActionButton } from '~components/Button/ActionButton' +import FamilyRoleChoiceModal from '~modals/PositionChoiceModal' +import { useGeolocation } from '~hooks/useGeolocation' +import { useOwnerProfileStore } from '~stores/ownerProfileStore' +import { validateOwnerProfile } from '~utils/validateOwnerProfile' +import Toast from '~components/Toast' +import { useQuery } from '@tanstack/react-query' +import { fetchOwnerProfile } from '~apis/family/fetchOwnerProfile' +import { Typo14 } from '~components/Typo' + +export default function OwnerUpdateModal() { + const { location, getCurrentLocation } = useGeolocation() + // const popModal = useModalStore(state => state.popModal) + const pushModal = useModalStore(state => state.pushModal) + const setOwnerProfile = useOwnerProfileStore(state => state.setOwnerProfile) // 상태 업데이트 함수 + const ownerProfile = useOwnerProfileStore(state => state.ownerProfile) // 상태 값 가져오기 + + // Fetch owner profile data + const { data } = useQuery({ + queryKey: ['ownerUpdatePage'], + queryFn: fetchOwnerProfile, + }) + console.log('희희, ', data) + + // Update address when location changes + useEffect(() => { + if (location.address) { + setOwnerProfile({ address: location.address }) + } + }, [location.address, setOwnerProfile]) + + const handleLocationClick = () => { + getCurrentLocation() + } + + const handleRoleClick = () => { + pushModal( + setOwnerProfile({ familyRole: role })} + initialRole={ownerProfile.familyRole} + /> + ) + } + + const handleAvatarClick = () => { + pushModal( + setOwnerProfile({ profileImg: avatarSrc })} + initialSelectedAvatar={ownerProfile.profileImg} + /> + ) + } + + const handleGenderSelect = (gender: 'MALE' | 'FEMALE') => { + setOwnerProfile({ gender }) + } + + return ( + + + DDang | 내 정보 수정 + + + + 내 정보 수정 + + + {ownerProfile.profileImg ? ( + + 선택된 아바타 + + ) : ( + + 프로필 선택 +
아바타 선택
+
+ )} + + + 아바타 선택 + + +
+ + + + setOwnerProfile({ name: e.target.value })} + /> + + + {ownerProfile.familyRole || '가족 포지션 선택'} + + + {ownerProfile.address || '내 동네 불러오기'} + + + handleGenderSelect('MALE')} + /> + handleGenderSelect('FEMALE')} + /> + + + + console.log('수정 완료')} + > + 수정 완료 + + + +
+ ) +} diff --git a/src/modals/RegisterAvatarModal/styles.ts b/src/modals/RegisterAvatarModal/styles.ts index ca3084f8..d35fc4a7 100644 --- a/src/modals/RegisterAvatarModal/styles.ts +++ b/src/modals/RegisterAvatarModal/styles.ts @@ -8,6 +8,7 @@ export const RegisterAvatarModal = styled.div` position: relative; background-color: ${({ theme }) => theme.colors.grayscale.gc_4}; overflow: hidden; + z-index: 100; @media (max-height: 700px) { padding: 3.3rem 1.25rem 1rem; diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index 16cdb126..b3a61c69 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -11,6 +11,7 @@ import { fetchMypage, FetchMypageResponse } from '~apis/myPage/fetchMypage' import { APIResponse } from '~types/api' import { useModalStore } from '~stores/modalStore' import ShareCodeModal from '~modals/FamilyDDangModal/ShareCodeModal' +import OwnerUpdateModal from '~modals/OwnerUpdateModal' export default function FamilyDDang() { const { data } = useQuery>({ @@ -25,6 +26,10 @@ export default function FamilyDDang() { pushModal() } + const onClickMemberUpdate = () => { + pushModal() + } + return ( @@ -71,7 +76,7 @@ export default function FamilyDDang() { - + diff --git a/src/pages/RegisterPage/Register/styles.ts b/src/pages/RegisterPage/Register/styles.ts index dd2667a3..d2a7ead8 100644 --- a/src/pages/RegisterPage/Register/styles.ts +++ b/src/pages/RegisterPage/Register/styles.ts @@ -5,7 +5,7 @@ export const RegisterPage = styled.div` display: flex; flex-direction: column; justify-content: space-between; - padding: 5.5rem 1.25rem 1.8rem 1.25rem; + padding: 3.5rem 1.25rem 1.8rem 1.25rem; background-color: ${({ theme }) => theme.colors.grayscale.gc_4}; @media (max-height: 700px) { @@ -23,11 +23,14 @@ export const TextSection = styled.text<{ weight: FontWeight }>` text-align: center; margin: 1rem 0; ` - export const AddOwnerAvatarBtnWrapper = styled.div` display: flex; + flex-direction: column; justify-content: center; + align-items: center; + position: relative; flex-shrink: 0; + gap: 1rem; ` export const AddOwnerAvatarBtn = styled.div` @@ -149,3 +152,16 @@ export const GenderSelectBtnWrapper = styled.div` export const ToastWrapper = styled.div` position: relative; ` + +export const ChoiceAvatarBtn = styled.div` + width: 87px; + height: 32px; + /* display: inline-flex; */ + padding: 5.5px 12px; + justify-content: center; + align-items: center; + gap: 4px; + border-radius: 22px; + color: ${({ theme }) => theme.colors.grayscale.gc_4}; + background-color: ${({ theme }) => theme.colors.grayscale.font_1}; +` From a0ae7c7c16c6212ae9758b10bfa9395b16edafca Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 10:00:25 +0900 Subject: [PATCH 02/14] =?UTF-8?q?=E2=9C=A8=20=EA=B2=AC=EC=A3=BC=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=88=98=EC=A0=95=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchOwnerProfile.ts | 2 +- src/pages/MyPage/styles.ts | 1 + src/pages/RegisterPage/Register/styles.ts | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/apis/family/fetchOwnerProfile.ts b/src/apis/family/fetchOwnerProfile.ts index 40ccbe51..808c3959 100644 --- a/src/apis/family/fetchOwnerProfile.ts +++ b/src/apis/family/fetchOwnerProfile.ts @@ -10,7 +10,7 @@ export type FetchOwnerProfileResponse = Pick< export const fetchOwnerProfile = async (): Promise> => { try { const { data } = await axiosInstance.get>(`/member/update`) - console.log(data) + console.log('잘 오나?', data) return data } catch (error) { if (error instanceof AxiosError) { diff --git a/src/pages/MyPage/styles.ts b/src/pages/MyPage/styles.ts index b21c9864..c3f884a8 100644 --- a/src/pages/MyPage/styles.ts +++ b/src/pages/MyPage/styles.ts @@ -111,3 +111,4 @@ export const CountWrapperSmall = styled.div` color: ${({ theme }) => theme.colors.grayscale.font_1}; font-weight: 500; ` + diff --git a/src/pages/RegisterPage/Register/styles.ts b/src/pages/RegisterPage/Register/styles.ts index d2a7ead8..6c17e1e8 100644 --- a/src/pages/RegisterPage/Register/styles.ts +++ b/src/pages/RegisterPage/Register/styles.ts @@ -165,3 +165,12 @@ export const ChoiceAvatarBtn = styled.div` color: ${({ theme }) => theme.colors.grayscale.gc_4}; background-color: ${({ theme }) => theme.colors.grayscale.font_1}; ` +export const ProfileArea = styled.div` + width: 11rem; + height: 10rem; + flex-shrink: 0; + margin: 1.5rem auto; + display: flex; + justify-content: center; + align-items: center; +` From 951ebc5a1bea2e6e3ed677d7b12514638ba21ce6 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 10:00:40 +0900 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9C=A8=20=EA=B2=AC=EC=A3=BC=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=88=98=EC=A0=95=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/updateOwnerProfile.ts | 42 ++++++ src/constants/familyRole.ts | 5 + src/constants/queryKey.ts | 4 + src/modals/OwnerUpdateModal/index.tsx | 153 +++++++++++++++------- src/modals/RegisterAvatarModal/styles.ts | 8 +- src/pages/RegisterPage/Register/styles.ts | 7 +- src/types/api.ts | 7 + src/utils/validateOwnerProfile.ts | 7 +- 8 files changed, 182 insertions(+), 51 deletions(-) create mode 100644 src/apis/family/updateOwnerProfile.ts diff --git a/src/apis/family/updateOwnerProfile.ts b/src/apis/family/updateOwnerProfile.ts new file mode 100644 index 00000000..51a51401 --- /dev/null +++ b/src/apis/family/updateOwnerProfile.ts @@ -0,0 +1,42 @@ +import { AxiosError } from 'axios' +import { APIResponse, CommonAPIRequest, ErrorResponse, CommonAPIResponse } from '~types/api' +import { axiosInstance } from '~apis/axiosInstance' + +export type UpdateOwnerProfileRequest = Pick + +export type UpdateOwnerProfileResponse = Pick< + CommonAPIResponse, + 'memberId' | 'name' | 'gender' | 'familyRole' | 'profileImg' +> + +export const updateOwnerProfile = async ( + req: UpdateOwnerProfileRequest +): Promise> => { + try { + const { data } = await axiosInstance.patch>(`/member/update`, req) + return data + } catch (error) { + if (error instanceof AxiosError) { + const { response } = error as AxiosError + + if (response) { + const { code, message } = response.data + switch (code) { + case 400: + throw new Error(message || '잘못된 요청입니다.') + case 401: + throw new Error(message || '인증에 실패했습니다.') + case 500: + throw new Error(message || '서버 오류가 발생했습니다.') + default: + throw new Error(message || '알 수 없는 오류가 발생했습니다.') + } + } + // 요청 자체가 실패한 경우 + throw new Error('네트워크 연결을 확인해주세요') + } + + console.error('예상치 못한 에러:', error) + throw new Error('다시 시도해주세요') + } +} diff --git a/src/constants/familyRole.ts b/src/constants/familyRole.ts index ace24a22..535df9e2 100644 --- a/src/constants/familyRole.ts +++ b/src/constants/familyRole.ts @@ -9,3 +9,8 @@ export const FAMILY_ROLE = { GRANDMOTHER: '할머니', '': '', } +export type FamilyRoleKey = keyof typeof FAMILY_ROLE +export type FamilyRoleValue = (typeof FAMILY_ROLE)[FamilyRoleKey] +export const REVERSE_FAMILY_ROLE = Object.fromEntries( + Object.entries(FAMILY_ROLE).map(([key, value]) => [value, key]) +) as { [key in FamilyRoleValue]: FamilyRoleKey } \ No newline at end of file diff --git a/src/constants/queryKey.ts b/src/constants/queryKey.ts index 602a686c..6642f6ae 100644 --- a/src/constants/queryKey.ts +++ b/src/constants/queryKey.ts @@ -15,4 +15,8 @@ export const queryKey = { totalWalks: () => ['totalWalks'], currentMonthWalks: () => ['currentMonthWalks'], }, + family: { + prevOwnerInto: () => ['prevOwnerInfo'], + UpdateOwner: () => ['updateOwnerInfo'], + }, } as const diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx index 930e4349..dfc1ffbf 100644 --- a/src/modals/OwnerUpdateModal/index.tsx +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -1,50 +1,99 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import * as S from '~pages/RegisterPage/Register/styles' import { Helmet } from 'react-helmet-async' -import AddOwnerAvatar from '~assets/add-dog-picture.svg' import GenderSelectButton from '~components/GenderSelectButton' import { Input } from '~components/Input' import RegisterAvatarModal from '~modals/RegisterAvatarModal' import { useModalStore } from '~stores/modalStore' import { ActionButton } from '~components/Button/ActionButton' import FamilyRoleChoiceModal from '~modals/PositionChoiceModal' -import { useGeolocation } from '~hooks/useGeolocation' -import { useOwnerProfileStore } from '~stores/ownerProfileStore' +// import { useOwnerProfileStore } from '~stores/ownerProfileStore' import { validateOwnerProfile } from '~utils/validateOwnerProfile' import Toast from '~components/Toast' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' // 추가 import { fetchOwnerProfile } from '~apis/family/fetchOwnerProfile' +import { UpdateOwnerProfileRequest, updateOwnerProfile } from '~apis/family/updateOwnerProfile' // 추가 import { Typo14 } from '~components/Typo' +import { FAMILY_ROLE } from '~constants/familyRole' +import { queryKey } from '~constants/queryKey' +import { REVERSE_FAMILY_ROLE } from '~constants/familyRole' +import { OwnerProfileType } from '~types/ownerProfile' +// import { UpdateOwnerProfileResponse } from '~apis/family/updateOwnerProfile' + +import { FamilyRole, Gender } from '~types/common' + +interface updateProfileType { + familyRole: FamilyRole + gender: Gender + name: string + profileImg: string +} export default function OwnerUpdateModal() { - const { location, getCurrentLocation } = useGeolocation() - // const popModal = useModalStore(state => state.popModal) const pushModal = useModalStore(state => state.pushModal) - const setOwnerProfile = useOwnerProfileStore(state => state.setOwnerProfile) // 상태 업데이트 함수 - const ownerProfile = useOwnerProfileStore(state => state.ownerProfile) // 상태 값 가져오기 + const popModal = useModalStore(state => state.popModal) + + const [ownerProfile, setOwnerProfile] = useState({ + familyRole: '', + gender: 'MALE', // 기본값 + name: '', + profileImg: '', + }) + const [ProfileImage, setProfileImage] = useState(null) - // Fetch owner profile data - const { data } = useQuery({ - queryKey: ['ownerUpdatePage'], + const queryClient = useQueryClient() + + const { data, isLoading, isError } = useQuery({ + queryKey: queryKey.family.prevOwnerInto(), queryFn: fetchOwnerProfile, }) - console.log('희희, ', data) - // Update address when location changes useEffect(() => { - if (location.address) { - setOwnerProfile({ address: location.address }) + if (data?.data) { + setOwnerProfile(data?.data) + console.log('ownerProfile :', ownerProfile) } - }, [location.address, setOwnerProfile]) + }, [data]) - const handleLocationClick = () => { - getCurrentLocation() + if (!ownerProfile) { + return null } + const prevOwnerProfile = data?.data // fetchOwnerProfile의 데이터를 바로 사용 + + const updateOwnerMutation = useMutation({ + mutationFn: (data: UpdateOwnerProfileRequest) => updateOwnerProfile(data), + onSuccess: () => { + alert('견주정보 수정 완료') + queryClient.invalidateQueries({ queryKey: queryKey.family.UpdateOwner() }) + popModal() + }, + onError: error => { + console.error('정보 수정 실패:', error) + alert('정보 수정에 실패했습니다. 다시 시도해주세요.') + }, + }) + + useEffect(() => { + if (prevOwnerProfile?.profileImg) { + const avatarNumber = prevOwnerProfile.profileImg.match(/Avatar(\d+)/)?.[1] + if (avatarNumber) { + import(`../../../src/assets/avatars/Avatar${avatarNumber}.svg?react`) + .then(module => setProfileImage(() => module.default)) + .catch(err => console.error('Error loading SVG:', err)) + } + } + }, [prevOwnerProfile?.profileImg]) + const handleRoleClick = () => { pushModal( setOwnerProfile({ familyRole: role })} + onSelectRole={role => + setOwnerProfile(prev => ({ + ...prev!, + familyRole: role, + })) + } initialRole={ownerProfile.familyRole} /> ) @@ -53,16 +102,42 @@ export default function OwnerUpdateModal() { const handleAvatarClick = () => { pushModal( setOwnerProfile({ profileImg: avatarSrc })} + onSelectAvatar={avatarSrc => + setOwnerProfile(prev => ({ + ...prev!, + profileImg: avatarSrc, + })) + } initialSelectedAvatar={ownerProfile.profileImg} /> ) } const handleGenderSelect = (gender: 'MALE' | 'FEMALE') => { - setOwnerProfile({ gender }) + setOwnerProfile(prev => ({ + ...prev!, + gender, + })) } + const handleUpdateClick = () => { + if (!ownerProfile.name || !ownerProfile.familyRole || !ownerProfile.gender || !ownerProfile.profileImg) { + alert('모든 필드를 입력해주세요.') + return + } + + // familyRole을 영어 Enum 값으로 변환 + const updatedProfile = { + ...ownerProfile, + familyRole: REVERSE_FAMILY_ROLE[ownerProfile.familyRole || ''], // value를 key로 변환 + } + + console.log('프로필 업데이트 요청 데이터:', updatedProfile) + updateOwnerMutation.mutate(updatedProfile) // 변환된 데이터를 서버로 전송 + } + if (isLoading) return
Loading...
+ if (isError) return
Error loading data
+ return ( @@ -72,38 +147,31 @@ export default function OwnerUpdateModal() { 내 정보 수정 - - {ownerProfile.profileImg ? ( - - 선택된 아바타 - - ) : ( - - 프로필 선택 -
아바타 선택
-
- )} + + {ProfileImage && } 아바타 선택 -
+ setOwnerProfile({ name: e.target.value })} + onChange={e => + setOwnerProfile(prev => ({ + ...prev!, + name: e.target.value, + })) + } /> - {ownerProfile.familyRole || '가족 포지션 선택'} + {FAMILY_ROLE[ownerProfile.familyRole] || ownerProfile.familyRole} - - {ownerProfile.address || '내 동네 불러오기'} - + - console.log('수정 완료')} - > + 수정 완료 diff --git a/src/modals/RegisterAvatarModal/styles.ts b/src/modals/RegisterAvatarModal/styles.ts index d35fc4a7..bfbff724 100644 --- a/src/modals/RegisterAvatarModal/styles.ts +++ b/src/modals/RegisterAvatarModal/styles.ts @@ -8,8 +8,12 @@ export const RegisterAvatarModal = styled.div` position: relative; background-color: ${({ theme }) => theme.colors.grayscale.gc_4}; overflow: hidden; - z-index: 100; - + z-index: 200; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; @media (max-height: 700px) { padding: 3.3rem 1.25rem 1rem; gap: 0.5rem; diff --git a/src/pages/RegisterPage/Register/styles.ts b/src/pages/RegisterPage/Register/styles.ts index 6c17e1e8..0dcfc100 100644 --- a/src/pages/RegisterPage/Register/styles.ts +++ b/src/pages/RegisterPage/Register/styles.ts @@ -7,13 +7,13 @@ export const RegisterPage = styled.div` justify-content: space-between; padding: 3.5rem 1.25rem 1.8rem 1.25rem; background-color: ${({ theme }) => theme.colors.grayscale.gc_4}; - + z-index: 100; + /* position: absolute; */ @media (max-height: 700px) { padding: 4.75rem 1.25rem 1rem; gap: 0.5rem; } ` - export const TextSection = styled.text<{ weight: FontWeight }>` flex-shrink: 0; color: ${({ theme }) => theme.colors.grayscale.font_1}; @@ -104,7 +104,7 @@ export const PositionChoiceBtn = styled.div<{ $hasSelected?: boolean }>` padding: 1rem 2rem; border-radius: 0.75rem; font-size: ${({ theme }) => theme.typography._20}; - color: ${({ theme, $hasSelected }) => ($hasSelected ? theme.colors.grayscale.font_1 : theme.colors.grayscale.font_3)}; + color: ${({ theme }) => theme.colors.grayscale.font_1}; cursor: pointer; @media (max-height: 700px) { @@ -166,6 +166,7 @@ export const ChoiceAvatarBtn = styled.div` background-color: ${({ theme }) => theme.colors.grayscale.font_1}; ` export const ProfileArea = styled.div` + flex-direction: column; width: 11rem; height: 10rem; flex-shrink: 0; diff --git a/src/types/api.ts b/src/types/api.ts index 080bb651..ce803a13 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -246,3 +246,10 @@ export type GetSettingsResponse = { isMatched: BooleanString settings: NotificationSettings } + +export type UpdateOwnerProfileResponse = { + familyRole: FamilyRole + gender: Gender + name: string + profileImg: string +} diff --git a/src/utils/validateOwnerProfile.ts b/src/utils/validateOwnerProfile.ts index 8762ca56..2d09657f 100644 --- a/src/utils/validateOwnerProfile.ts +++ b/src/utils/validateOwnerProfile.ts @@ -2,12 +2,15 @@ import { OwnerProfileType } from '~types/ownerProfile' const regex = /^[가-힣]{1,10}$/ -export const validateOwnerProfile = (ownerProfile: OwnerProfileType): string | null => { +export const validateOwnerProfile = ( + ownerProfile: OwnerProfileType, + options?: { skipAddress?: boolean } // 옵션 추가 +): string | null => { if (!ownerProfile.familyRole) return '아바타를 선택해 주세요' if (!ownerProfile.name) return '견주님의 닉네임을 입력해주세요' if (!regex.test(ownerProfile.name)) return '닉네임은 한글로 10자 이내로 작성해 주세요' if (!ownerProfile.familyRole) return '견주님의 역할을 선택해주세요' - if (!ownerProfile.address) return '견주님의 위치 인증을 해주세요' + if (!options?.skipAddress && !ownerProfile.address) return '견주님의 위치 인증을 해주세요' // address 검사 조건 추가 if (!ownerProfile.gender) return '견주님의 성별을 선택해주세요' return null } From e507b83d28d1141768cdcb9f7695c08c8a5147ef Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 10:34:54 +0900 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20=EC=95=84?= =?UTF-8?q?=EB=B0=94=ED=83=80=20=EC=88=98=EC=A0=95=20=EC=8B=A4=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EB=B0=98=EC=98=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modals/OwnerUpdateModal/index.tsx | 16 ++++++++-------- src/pages/RegisterPage/Register/styles.ts | 7 ++++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx index dfc1ffbf..3649cbb8 100644 --- a/src/modals/OwnerUpdateModal/index.tsx +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -75,15 +75,15 @@ export default function OwnerUpdateModal() { }) useEffect(() => { - if (prevOwnerProfile?.profileImg) { - const avatarNumber = prevOwnerProfile.profileImg.match(/Avatar(\d+)/)?.[1] + if (ownerProfile.profileImg) { + const avatarNumber = ownerProfile.profileImg.match(/Avatar(\d+)/)?.[1] // 프로필 이미지에서 번호 추출 if (avatarNumber) { import(`../../../src/assets/avatars/Avatar${avatarNumber}.svg?react`) - .then(module => setProfileImage(() => module.default)) + .then(module => setProfileImage(() => module.default)) // 동적으로 가져온 컴포넌트를 상태에 저장 .catch(err => console.error('Error loading SVG:', err)) } } - }, [prevOwnerProfile?.profileImg]) + }, [ownerProfile.profileImg]) // profileImg가 변경될 때마다 실행 const handleRoleClick = () => { pushModal( @@ -102,12 +102,12 @@ export default function OwnerUpdateModal() { const handleAvatarClick = () => { pushModal( + onSelectAvatar={avatarSrc => { setOwnerProfile(prev => ({ - ...prev!, - profileImg: avatarSrc, + ...prev, + profileImg: avatarSrc, // 선택된 아바타 경로 업데이트 })) - } + }} initialSelectedAvatar={ownerProfile.profileImg} /> ) diff --git a/src/pages/RegisterPage/Register/styles.ts b/src/pages/RegisterPage/Register/styles.ts index 0dcfc100..abfdcef9 100644 --- a/src/pages/RegisterPage/Register/styles.ts +++ b/src/pages/RegisterPage/Register/styles.ts @@ -157,18 +157,19 @@ export const ChoiceAvatarBtn = styled.div` width: 87px; height: 32px; /* display: inline-flex; */ - padding: 5.5px 12px; + padding: 6.5px 12px; justify-content: center; align-items: center; gap: 4px; border-radius: 22px; color: ${({ theme }) => theme.colors.grayscale.gc_4}; background-color: ${({ theme }) => theme.colors.grayscale.font_1}; + margin-top: 1rem; ` export const ProfileArea = styled.div` flex-direction: column; - width: 11rem; - height: 10rem; + width: 13rem; + height: 13rem; flex-shrink: 0; margin: 1.5rem auto; display: flex; From 10a9b367b8982193061b39f3b83f6e8e10eacd28 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 11:40:39 +0900 Subject: [PATCH 05/14] =?UTF-8?q?=E2=9C=A8=20Feature=20:=20=ED=8C=A8?= =?UTF-8?q?=EB=B0=80=EB=A6=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94?= =?UTF-8?q?=EC=9D=B8=EB=94=A9(=20=EA=B0=95=EC=95=84=EC=A7=80=EB=8A=94=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=94=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=88=EB=9F=AC=EC=98=AC=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchFamilyDDang.ts | 49 +++++++++ src/constants/queryKey.ts | 1 + src/modals/OwnerUpdateModal/index.tsx | 6 -- src/pages/FamilyDDangPage/index.tsx | 149 +++++++++++--------------- 4 files changed, 110 insertions(+), 95 deletions(-) create mode 100644 src/apis/family/fetchFamilyDDang.ts diff --git a/src/apis/family/fetchFamilyDDang.ts b/src/apis/family/fetchFamilyDDang.ts new file mode 100644 index 00000000..da57b28f --- /dev/null +++ b/src/apis/family/fetchFamilyDDang.ts @@ -0,0 +1,49 @@ +import { AxiosError } from 'axios' +import { APIResponse, CommonAPIResponse, ErrorResponse, Member } from '~types/api' +import { axiosInstance } from '~apis/axiosInstance' +import { DayOfWeek } from '~types/common' + +export type FetchFamilyDDangResponse = Pick< + CommonAPIResponse, + 'familyId' | 'members' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' +> & { + members: (Pick & { + walkScheduleInfoList: { + walkScheduleId: number + dayOfWeek: DayOfWeek + walkTime: string + }[] + totalWalkCount: number + })[] +} + +export const fetchFamilyDDang = async (): Promise> => { + try { + const { data } = await axiosInstance.get>(`/family`) + console.log('패밀리댕 정보 바인딩 : ', data) + return data + } catch (error) { + if (error instanceof AxiosError) { + const { response } = error as AxiosError + + if (response) { + const { code, message } = response.data + switch (code) { + case 400: + throw new Error(message || '잘못된 요청입니다.') + case 401: + throw new Error(message || '인증에 실패했습니다.') + case 500: + throw new Error(message || '서버 오류가 발생했습니다.') + default: + throw new Error(message || '알 수 없는 오류가 발생했습니다.') + } + } + // 요청 자체가 실패한 경우 + throw new Error('네트워크 연결을 확인해주세요') + } + + console.error('예상치 못한 에러:', error) + throw new Error('다시 시도해주세요') + } +} diff --git a/src/constants/queryKey.ts b/src/constants/queryKey.ts index 6642f6ae..72c812d9 100644 --- a/src/constants/queryKey.ts +++ b/src/constants/queryKey.ts @@ -16,6 +16,7 @@ export const queryKey = { currentMonthWalks: () => ['currentMonthWalks'], }, family: { + familyList: ()=> ['familyList'], prevOwnerInto: () => ['prevOwnerInfo'], UpdateOwner: () => ['updateOwnerInfo'], }, diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx index 3649cbb8..f7f2f818 100644 --- a/src/modals/OwnerUpdateModal/index.tsx +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -7,8 +7,6 @@ import RegisterAvatarModal from '~modals/RegisterAvatarModal' import { useModalStore } from '~stores/modalStore' import { ActionButton } from '~components/Button/ActionButton' import FamilyRoleChoiceModal from '~modals/PositionChoiceModal' -// import { useOwnerProfileStore } from '~stores/ownerProfileStore' -import { validateOwnerProfile } from '~utils/validateOwnerProfile' import Toast from '~components/Toast' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' // 추가 import { fetchOwnerProfile } from '~apis/family/fetchOwnerProfile' @@ -17,8 +15,6 @@ import { Typo14 } from '~components/Typo' import { FAMILY_ROLE } from '~constants/familyRole' import { queryKey } from '~constants/queryKey' import { REVERSE_FAMILY_ROLE } from '~constants/familyRole' -import { OwnerProfileType } from '~types/ownerProfile' -// import { UpdateOwnerProfileResponse } from '~apis/family/updateOwnerProfile' import { FamilyRole, Gender } from '~types/common' @@ -59,8 +55,6 @@ export default function OwnerUpdateModal() { return null } - const prevOwnerProfile = data?.data // fetchOwnerProfile의 데이터를 바로 사용 - const updateOwnerMutation = useMutation({ mutationFn: (data: UpdateOwnerProfileRequest) => updateOwnerProfile(data), onSuccess: () => { diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index b3a61c69..cfbbc75d 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -3,22 +3,33 @@ import { MdOutlineEditLocation } from 'react-icons/md' import { Typo14, Typo15, Typo17 } from '~components/Typo' import { MdOutlineModeEdit } from 'react-icons/md' import CountSection from '~components/WalkCountArea' -import { Avatar10, Avatar3 } from '~assets/avatars' import Profile from '~components/Profile' -import DogProfile from '~components/DogProfile' +// import DogProfile from '~components/DogProfile' import { useQuery } from '@tanstack/react-query' -import { fetchMypage, FetchMypageResponse } from '~apis/myPage/fetchMypage' import { APIResponse } from '~types/api' import { useModalStore } from '~stores/modalStore' import ShareCodeModal from '~modals/FamilyDDangModal/ShareCodeModal' import OwnerUpdateModal from '~modals/OwnerUpdateModal' +import { fetchFamilyDDang, FetchFamilyDDangResponse } from '~apis/family/fetchFamilyDDang' export default function FamilyDDang() { - const { data } = useQuery>({ - queryKey: ['myPage'], - queryFn: fetchMypage, + // const { data } = useQuery>({ + // queryKey: ['myPage'], + // queryFn: fetchMypage, + // }) + // const dogInfo = data?.data?.dog + + const { data } = useQuery>({ + queryKey: ['familyList'], + queryFn: fetchFamilyDDang, }) - const dogInfo = data?.data?.dog + console.log(data) + + const familyInfo = data?.data + const firstMember = familyInfo?.members[0] // members 배열의 첫 번째 멤버 + // const firstDog = familyInfo?.dogs[0] + + console.log('familyIdfo : ', familyInfo) const { pushModal } = useModalStore() @@ -29,7 +40,6 @@ export default function FamilyDDang() { const onClickMemberUpdate = () => { pushModal() } - return ( @@ -38,74 +48,51 @@ export default function FamilyDDang() { - {dogInfo && ( + {/* {firstDog && ( - )} + )} */} - - - - - {family1Info.nickName} - - {family1Info.gender} | {family1Info.position} - - - - 산책 시간 - - {family1Info.week} - - - {family1Info.time} - - - - 산책 횟수 - - {family1Info.count} - - - - - - - - - - - - {family2Info.nickName} - - {family2Info.gender} | {family2Info.position} - - - - 산책 시간 - - {family2Info.week} - - - {family2Info.time} - - - - 산책 횟수 - - {family2Info.count} - - - - + {firstMember && ( // 첫 번째 멤버가 존재할 때만 렌더링 + + + + + {firstMember.name} + + {firstMember.gender === 'MALE' ? '남자' : '여자'} |{' '} + {firstMember.familyRole === 'MOTHER' ? '엄마' : firstMember.familyRole} + + + + 산책 시간 + + {firstMember.walkScheduleInfoList.map(schedule => schedule.dayOfWeek).join(', ') || '없음'} + + + {firstMember.walkScheduleInfoList.map(schedule => schedule.walkTime).join(', ') || ''} + + + + 산책 횟수 + + {firstMember.totalWalkCount} + + + + + + + + )} 밤톨이와 함께할 동반자를 초대하세요! @@ -118,19 +105,3 @@ export default function FamilyDDang() { ) } -const family1Info = { - nickName: '원돌이', - gender: '여자', - position: '엄마', - week: '월, 수, 금', - time: '10:00', - count: '8', -} -const family2Info = { - nickName: '투돌이', - gender: '남자', - position: '형', - week: '화, 토', - time: '17:00', - count: '23', -} From dfeed151b8b9b4b0fae8eff2d9e86b0957e7b2e1 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 11:42:56 +0900 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=95=88=ED=95=98=EB=8A=94=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DogProfile/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/DogProfile/index.tsx b/src/components/DogProfile/index.tsx index 8b9283e4..820b28c1 100644 --- a/src/components/DogProfile/index.tsx +++ b/src/components/DogProfile/index.tsx @@ -4,7 +4,6 @@ import { Separator } from '~components/Separator' import Profile from '~components/Profile' import { DogProfileType } from '~types/dogProfile' import { stringToDate } from '~utils/dateFormat' -import { MdOutlineModeEdit } from 'react-icons/md' //날짜 계산 로직 const calculateAge = (birthDate?: Date): number => { From 5b506b9ac8c4bcf6ac50c0463005e7d4a2b137d9 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 11:49:17 +0900 Subject: [PATCH 07/14] =?UTF-8?q?=E2=9C=A8=20Feature=20:=20=EB=88=84?= =?UTF-8?q?=EC=A0=81=EC=82=B0=EC=B1=85=20=ED=9A=9F=EC=88=98,=20=EA=B1=B0?= =?UTF-8?q?=EB=A6=AC,=20=EC=B9=BC=EB=A1=9C=EB=A6=AC=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/WalkCountArea/index.tsx | 25 +++++++++++++++---------- src/pages/FamilyDDangPage/index.tsx | 8 +------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/components/WalkCountArea/index.tsx b/src/components/WalkCountArea/index.tsx index 1625530a..30c2268f 100644 --- a/src/components/WalkCountArea/index.tsx +++ b/src/components/WalkCountArea/index.tsx @@ -1,27 +1,32 @@ import * as S from './styles' +import { useQuery } from '@tanstack/react-query' +import { fetchFamilyDDang, FetchFamilyDDangResponse } from '~apis/family/fetchFamilyDDang' +import { APIResponse } from '~types/api' -interface CountSectionProps { - walkCount: number - totalDistance: number - gangCount: number -} +export default function WalkCountArea() { + const { data } = useQuery>({ + queryKey: ['familyList'], + queryFn: fetchFamilyDDang, + }) + const totalCalorie = data?.data?.totalCalorie + const totalDistanceInKilometers = data?.data?.totalDistanceInKilometers + const totalWalkCount = data?.data?.totalWalkCount -export default function WalkCountArea({ walkCount, totalDistance, gangCount }: CountSectionProps) { return ( - {walkCount}회 + {totalCalorie}회 누적 산책 횟수 - {totalDistance}km + {totalDistanceInKilometers}km 총 산책거리 - {gangCount}회 - 강번따 횟수 + {totalWalkCount}kcal + 소요 칼로리 ) diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index cfbbc75d..b171ae07 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -13,12 +13,6 @@ import OwnerUpdateModal from '~modals/OwnerUpdateModal' import { fetchFamilyDDang, FetchFamilyDDangResponse } from '~apis/family/fetchFamilyDDang' export default function FamilyDDang() { - // const { data } = useQuery>({ - // queryKey: ['myPage'], - // queryFn: fetchMypage, - // }) - // const dogInfo = data?.data?.dog - const { data } = useQuery>({ queryKey: ['familyList'], queryFn: fetchFamilyDDang, @@ -101,7 +95,7 @@ export default function FamilyDDang() { - +
) } From d470e9006d307547fa7741451df344e5d73dca8f Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 11:51:46 +0900 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20Mypage=20?= =?UTF-8?q?=EC=B4=9D=20=EC=82=B0=EC=B1=85=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MyPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/MyPage/index.tsx b/src/pages/MyPage/index.tsx index 785216e7..aab9af8d 100644 --- a/src/pages/MyPage/index.tsx +++ b/src/pages/MyPage/index.tsx @@ -78,7 +78,7 @@ export default function MyPage() { - + {myPageData?.dog && } From bf87cba7d6e607b69bb6aa457a8a22b7aeb3e5da Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 11:58:23 +0900 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=94=A5=20Delete=20:=20UPdateMemberM?= =?UTF-8?q?odal=20=ED=8F=B4=EB=8D=94=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UpdateMemberModal/index.tsx | 29 ---- .../UpdateMemberModal/styles.ts | 153 ------------------ 2 files changed, 182 deletions(-) delete mode 100644 src/modals/FamilyDDangModal/UpdateMemberModal/index.tsx delete mode 100644 src/modals/FamilyDDangModal/UpdateMemberModal/styles.ts diff --git a/src/modals/FamilyDDangModal/UpdateMemberModal/index.tsx b/src/modals/FamilyDDangModal/UpdateMemberModal/index.tsx deleted file mode 100644 index b2387539..00000000 --- a/src/modals/FamilyDDangModal/UpdateMemberModal/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as S from './styles' -// import GenderSelectButton from '~components/GenderSelectButton' -// import { useEffect } from 'react' -// import { Input } from '~components/Input' -// import { useModalStore } from '~stores/modalStore' -// import { useToastStore } from '~stores/toastStore' -// import Toast from '~components/Toast' -// import { useGeolocation } from '~hooks/useGeolocation' -// import AddOwnerAvatar from '~assets/add-dog-picture.svg' -// import RegisterAvatarModal from '~modals/RegisterAvatarModal' -// import { ActionButton } from '~components/Button/ActionButton' -// import PositionChoiceModal from '~modals/PositionChoiceModal' -// import { useOwnerProfileStore } from '~stores/ownerProfileStore' -// import { validateOwnerProfile } from '~utils/validateOwnerProfile' -import Header from '~components/Header' -// type UpdateMemberModalProps = { -// : -// } - -export default function UpdateMemberModal() { - // const popModal = useModalStore() - return ( - -
-
- UpdateMemberModal - - ) -} diff --git a/src/modals/FamilyDDangModal/UpdateMemberModal/styles.ts b/src/modals/FamilyDDangModal/UpdateMemberModal/styles.ts deleted file mode 100644 index 7a119756..00000000 --- a/src/modals/FamilyDDangModal/UpdateMemberModal/styles.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { FontWeight, styled } from 'styled-components' - -export const UpdateMemberModal = styled.div`` - -export const RegisterPage = styled.div` - height: 100dvh; - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 5.5rem 1.25rem 1.8rem 1.25rem; - background-color: ${({ theme }) => theme.colors.grayscale.gc_4}; - - @media (max-height: 700px) { - padding: 4.75rem 1.25rem 1rem; - gap: 0.5rem; - } -` - -export const TextSection = styled.text<{ weight: FontWeight }>` - flex-shrink: 0; - color: ${({ theme }) => theme.colors.grayscale.font_1}; - font-size: ${({ theme }) => theme.typography._24}; - font-weight: ${({ weight }) => weight}; - white-space: pre-line; - text-align: center; - margin: 1rem 0; -` - -export const AddOwnerAvatarBtnWrapper = styled.div` - display: flex; - justify-content: center; - flex-shrink: 0; -` - -export const AddOwnerAvatarBtn = styled.div` - width: 180px; - height: 180px; - background-color: ${({ theme }) => theme.colors.brand.lighten_2}; - border-radius: 50%; - margin-top: 0.7rem; - - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - gap: 0.5rem; - - font-weight: 700; - color: ${({ theme }) => theme.colors.brand.darken}; - cursor: pointer; - - @media (max-height: 700px) { - width: 150px; - height: 150px; - } -` -export const Avatar = styled.div` - width: 190px; - height: 190px; - border-radius: 50%; - margin-top: 0.7rem; - - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - gap: 0.5rem; - cursor: pointer; - font-weight: 700; - color: ${({ theme }) => theme.colors.brand.darken}; - - img { - width: 100%; - height: 100%; - object-fit: cover; - } - - @media (max-height: 700px) { - width: 150px; - height: 150px; - } -` - -export const OwnerProfileSection = styled.div` - display: flex; - flex-direction: column; - flex: 1; - justify-content: center; - padding-bottom: 2rem; - @media (max-height: 700px) { - gap: 0.5rem; - } -` - -export const NickNameWrapper = styled.div` - width: 100%; -` - -export const PositionChoiceBtn = styled.div<{ $hasSelected?: boolean }>` - width: 100%; - border: none; - text-align: center; - padding: 1rem 2rem; - border-radius: 0.75rem; - font-size: ${({ theme }) => theme.typography._20}; - color: ${({ theme, $hasSelected }) => ($hasSelected ? theme.colors.grayscale.font_1 : theme.colors.grayscale.font_3)}; - cursor: pointer; - - @media (max-height: 700px) { - padding: 0.75rem 1.5rem; - } -` - -export const LocationBtn = styled.div<{ $hasSelected?: boolean }>` - width: 100%; - border: none; - text-align: center; - padding: 1.063rem 2rem; - border-radius: 0.75rem; - font-size: ${({ theme }) => theme.typography._20}; - color: ${({ theme, $hasSelected }) => ($hasSelected ? theme.colors.grayscale.font_1 : theme.colors.grayscale.font_3)}; - cursor: pointer; - - @media (max-height: 700px) { - padding: 0.75rem 1.5rem; - } -` - -export const GenderSelectBtnWrapper = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; - height: 4rem; - width: 90%; - margin: 1rem auto; - & > * { - height: 100%; - } - - button { - flex-direction: row; - gap: 0.8rem; - height: 100%; - } - - @media (max-height: 700px) { - height: 3.25rem; - } -` - -export const ToastWrapper = styled.div` - position: relative; -` From 9d7c1dd9b38f6b3e4739d196d07adb8066d84af4 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 12:37:33 +0900 Subject: [PATCH 10/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20=ED=8C=A8?= =?UTF-8?q?=EB=B0=80=EB=A6=AC=EB=8C=95=20=EC=88=98=EC=A0=95=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchFamilyDDang.ts | 4 +--- src/modals/OwnerUpdateModal/index.tsx | 2 +- src/pages/FamilyDDangPage/index.tsx | 33 ++++++++++++++++++--------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/apis/family/fetchFamilyDDang.ts b/src/apis/family/fetchFamilyDDang.ts index da57b28f..462a777c 100644 --- a/src/apis/family/fetchFamilyDDang.ts +++ b/src/apis/family/fetchFamilyDDang.ts @@ -2,7 +2,6 @@ import { AxiosError } from 'axios' import { APIResponse, CommonAPIResponse, ErrorResponse, Member } from '~types/api' import { axiosInstance } from '~apis/axiosInstance' import { DayOfWeek } from '~types/common' - export type FetchFamilyDDangResponse = Pick< CommonAPIResponse, 'familyId' | 'members' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' @@ -13,10 +12,9 @@ export type FetchFamilyDDangResponse = Pick< dayOfWeek: DayOfWeek walkTime: string }[] - totalWalkCount: number + totalWalkCount: number // 추가된 속성 })[] } - export const fetchFamilyDDang = async (): Promise> => { try { const { data } = await axiosInstance.get>(`/family`) diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx index f7f2f818..76389e82 100644 --- a/src/modals/OwnerUpdateModal/index.tsx +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -12,8 +12,8 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' // import { fetchOwnerProfile } from '~apis/family/fetchOwnerProfile' import { UpdateOwnerProfileRequest, updateOwnerProfile } from '~apis/family/updateOwnerProfile' // 추가 import { Typo14 } from '~components/Typo' -import { FAMILY_ROLE } from '~constants/familyRole' import { queryKey } from '~constants/queryKey' +import { FAMILY_ROLE } from '~constants/familyRole' import { REVERSE_FAMILY_ROLE } from '~constants/familyRole' import { FamilyRole, Gender } from '~types/common' diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index b171ae07..de5c3294 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -11,16 +11,28 @@ import { useModalStore } from '~stores/modalStore' import ShareCodeModal from '~modals/FamilyDDangModal/ShareCodeModal' import OwnerUpdateModal from '~modals/OwnerUpdateModal' import { fetchFamilyDDang, FetchFamilyDDangResponse } from '~apis/family/fetchFamilyDDang' +import { REVERSE_FAMILY_ROLE } from '~constants/familyRole' +import { FAMILY_ROLE } from '~constants/familyRole' export default function FamilyDDang() { - const { data } = useQuery>({ + const { data, isLoading, isError } = useQuery({ queryKey: ['familyList'], queryFn: fetchFamilyDDang, }) + + if (isLoading) { + return
Loading...
+ } + + if (isError) { + return
Error loading data. Please try again later.
+ } console.log(data) const familyInfo = data?.data const firstMember = familyInfo?.members[0] // members 배열의 첫 번째 멤버 + const members = familyInfo?.members + // const firstDog = familyInfo?.dogs[0] console.log('familyIdfo : ', familyInfo) @@ -55,30 +67,29 @@ export default function FamilyDDang() { /> )} */} - {firstMember && ( // 첫 번째 멤버가 존재할 때만 렌더링 - - + {members?.map(member => ( + + - {firstMember.name} + {member.name} - {firstMember.gender === 'MALE' ? '남자' : '여자'} |{' '} - {firstMember.familyRole === 'MOTHER' ? '엄마' : firstMember.familyRole} + {member.gender === 'MALE' ? '남자' : '여자'} | {FAMILY_ROLE[member.familyRole] || member.familyRole} 산책 시간 - {firstMember.walkScheduleInfoList.map(schedule => schedule.dayOfWeek).join(', ') || '없음'} + {/* {member.walkScheduleInfoList.map(schedule => schedule.dayOfWeek).join(', ') || '없음'} */} - {firstMember.walkScheduleInfoList.map(schedule => schedule.walkTime).join(', ') || ''} + {member.walkScheduleInfoList.map(schedule => schedule.walkTime).join(', ') || ''} 산책 횟수 - {firstMember.totalWalkCount} + {member.totalWalkCount} @@ -86,7 +97,7 @@ export default function FamilyDDang() { - )} + ))} 밤톨이와 함께할 동반자를 초대하세요! From 1696e3bf047095d7bd1c74ea2a08b3c49c54c448 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 14:16:10 +0900 Subject: [PATCH 11/14] =?UTF-8?q?=E2=9C=A8=20Feature=20:=20=ED=8C=A8?= =?UTF-8?q?=EB=B0=80=EB=A6=AC=EB=8C=95=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchFamilyDDang.ts | 18 ++++++++++++++++-- src/pages/FamilyDDangPage/index.tsx | 9 +++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/apis/family/fetchFamilyDDang.ts b/src/apis/family/fetchFamilyDDang.ts index 462a777c..8f563a13 100644 --- a/src/apis/family/fetchFamilyDDang.ts +++ b/src/apis/family/fetchFamilyDDang.ts @@ -2,11 +2,24 @@ import { AxiosError } from 'axios' import { APIResponse, CommonAPIResponse, ErrorResponse, Member } from '~types/api' import { axiosInstance } from '~apis/axiosInstance' import { DayOfWeek } from '~types/common' +// export type FetchFamilyDDangResponse = Pick< +// CommonAPIResponse, +// 'familyId' | 'members' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' +// > & { +// members: (Pick & { +// walkScheduleInfoList: { +// walkScheduleId: number +// dayOfWeek: DayOfWeek +// walkTime: string +// }[] +// totalWalkCount: number // 추가된 속성 +// })[] +// } export type FetchFamilyDDangResponse = Pick< CommonAPIResponse, - 'familyId' | 'members' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' + 'familyId' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' > & { - members: (Pick & { + members: (CommonAPIResponse['members'][number] & { walkScheduleInfoList: { walkScheduleId: number dayOfWeek: DayOfWeek @@ -15,6 +28,7 @@ export type FetchFamilyDDangResponse = Pick< totalWalkCount: number // 추가된 속성 })[] } + export const fetchFamilyDDang = async (): Promise> => { try { const { data } = await axiosInstance.get>(`/family`) diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index de5c3294..634f8266 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -6,15 +6,15 @@ import CountSection from '~components/WalkCountArea' import Profile from '~components/Profile' // import DogProfile from '~components/DogProfile' import { useQuery } from '@tanstack/react-query' -import { APIResponse } from '~types/api' import { useModalStore } from '~stores/modalStore' import ShareCodeModal from '~modals/FamilyDDangModal/ShareCodeModal' import OwnerUpdateModal from '~modals/OwnerUpdateModal' -import { fetchFamilyDDang, FetchFamilyDDangResponse } from '~apis/family/fetchFamilyDDang' -import { REVERSE_FAMILY_ROLE } from '~constants/familyRole' +import { fetchFamilyDDang } from '~apis/family/fetchFamilyDDang' import { FAMILY_ROLE } from '~constants/familyRole' export default function FamilyDDang() { + const { pushModal } = useModalStore() + const { data, isLoading, isError } = useQuery({ queryKey: ['familyList'], queryFn: fetchFamilyDDang, @@ -30,15 +30,12 @@ export default function FamilyDDang() { console.log(data) const familyInfo = data?.data - const firstMember = familyInfo?.members[0] // members 배열의 첫 번째 멤버 const members = familyInfo?.members // const firstDog = familyInfo?.dogs[0] console.log('familyIdfo : ', familyInfo) - const { pushModal } = useModalStore() - const onClickCodeShare = () => { pushModal() } From e0c7c6899196a19a57dfc93f463b49eb16dc421a Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 14:19:24 +0900 Subject: [PATCH 12/14] =?UTF-8?q?=F0=9F=90=9B=20Remove=20:=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchFamilyDDang.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/apis/family/fetchFamilyDDang.ts b/src/apis/family/fetchFamilyDDang.ts index 8f563a13..944a8444 100644 --- a/src/apis/family/fetchFamilyDDang.ts +++ b/src/apis/family/fetchFamilyDDang.ts @@ -2,19 +2,7 @@ import { AxiosError } from 'axios' import { APIResponse, CommonAPIResponse, ErrorResponse, Member } from '~types/api' import { axiosInstance } from '~apis/axiosInstance' import { DayOfWeek } from '~types/common' -// export type FetchFamilyDDangResponse = Pick< -// CommonAPIResponse, -// 'familyId' | 'members' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' -// > & { -// members: (Pick & { -// walkScheduleInfoList: { -// walkScheduleId: number -// dayOfWeek: DayOfWeek -// walkTime: string -// }[] -// totalWalkCount: number // 추가된 속성 -// })[] -// } + export type FetchFamilyDDangResponse = Pick< CommonAPIResponse, 'familyId' | 'dogs' | 'totalWalkCount' | 'totalDistanceInKilometers' | 'totalCalorie' From 52c9f3b143dd4045f74fc7a43f35d7a0382d5319 Mon Sep 17 00:00:00 2001 From: kimjuyoung99 Date: Mon, 9 Dec 2024 14:43:46 +0900 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20hook=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=9E=A5=EC=95=A0=EB=AC=BC=20early=20return=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/family/fetchFamilyDDang.ts | 2 +- src/modals/OwnerUpdateModal/index.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/apis/family/fetchFamilyDDang.ts b/src/apis/family/fetchFamilyDDang.ts index 944a8444..8087d8ec 100644 --- a/src/apis/family/fetchFamilyDDang.ts +++ b/src/apis/family/fetchFamilyDDang.ts @@ -1,5 +1,5 @@ import { AxiosError } from 'axios' -import { APIResponse, CommonAPIResponse, ErrorResponse, Member } from '~types/api' +import { APIResponse, CommonAPIResponse, ErrorResponse } from '~types/api' import { axiosInstance } from '~apis/axiosInstance' import { DayOfWeek } from '~types/common' diff --git a/src/modals/OwnerUpdateModal/index.tsx b/src/modals/OwnerUpdateModal/index.tsx index 76389e82..34fa7348 100644 --- a/src/modals/OwnerUpdateModal/index.tsx +++ b/src/modals/OwnerUpdateModal/index.tsx @@ -51,10 +51,6 @@ export default function OwnerUpdateModal() { } }, [data]) - if (!ownerProfile) { - return null - } - const updateOwnerMutation = useMutation({ mutationFn: (data: UpdateOwnerProfileRequest) => updateOwnerProfile(data), onSuccess: () => { @@ -79,6 +75,10 @@ export default function OwnerUpdateModal() { } }, [ownerProfile.profileImg]) // profileImg가 변경될 때마다 실행 + if (!ownerProfile) { + return null + } + const handleRoleClick = () => { pushModal( Date: Mon, 9 Dec 2024 15:40:24 +0900 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20:=20=EB=A8=B8?= =?UTF-8?q?=EC=A7=80=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DogProfile/styles.ts | 20 ++++++++++---------- src/pages/FamilyDDangPage/index.tsx | 19 ++++++------------- src/pages/MyPage/index.tsx | 2 +- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/components/DogProfile/styles.ts b/src/components/DogProfile/styles.ts index d9be6d50..6a545b7f 100644 --- a/src/components/DogProfile/styles.ts +++ b/src/components/DogProfile/styles.ts @@ -60,16 +60,16 @@ export const OneLineIntro = styled(Box)` } ` -export const EditIconWrapper = styled.div` - width: 2rem; - height: 2rem; - background-color: ${({ theme }) => theme.colors.brand.lighten_2}; - border-radius: 50%; - display: flex; - justify-content: center; - align-items: center; - margin-left: auto; -` +// export const EditIconWrapper = styled.div` +// width: 2rem; +// height: 2rem; +// background-color: ${({ theme }) => theme.colors.brand.lighten_2}; +// border-radius: 50%; +// display: flex; +// justify-content: center; +// align-items: center; +// margin-left: auto; +// ` export const InviteBtn = styled.button` width: 57px; diff --git a/src/pages/FamilyDDangPage/index.tsx b/src/pages/FamilyDDangPage/index.tsx index 8baffa89..bb1188d9 100644 --- a/src/pages/FamilyDDangPage/index.tsx +++ b/src/pages/FamilyDDangPage/index.tsx @@ -12,24 +12,20 @@ import { fetchFamilyDDang } from '~apis/family/fetchFamilyDDang' import { FAMILY_ROLE } from '~constants/familyRole' import DogProfile from '~components/DogProfile' import { useMyPage } from '~apis/myPage/useMyPage' -import { useEffect } from 'react' - +import { useEffect } from 'react' + export default function FamilyDDang() { - const { pushModal } = useModalStore() - const { data, refetch } = useMyPage() - const dogInfo = data?.dog + const { pushModal, modalList } = useModalStore() + const { refetch } = useMyPage() - const { data, isLoading, isError } = useQuery({ + const { data, isLoading, isError } = useQuery({ queryKey: ['familyList'], queryFn: fetchFamilyDDang, }) - - const { pushModal, modalList } = useModalStore() useEffect(() => { refetch() }, [modalList]) - if (isLoading) { return
Loading...
@@ -43,8 +39,6 @@ export default function FamilyDDang() { const familyInfo = data?.data const members = familyInfo?.members - // const firstDog = familyInfo?.dogs[0] - console.log('familyIdfo : ', familyInfo) const onClickCodeShare = () => { @@ -62,7 +56,6 @@ export default function FamilyDDang() { - {/* {firstDog && ( )} */} - {dogInfo && } + {familyInfo?.dogs[0] && } {members?.map(member => ( diff --git a/src/pages/MyPage/index.tsx b/src/pages/MyPage/index.tsx index 2edf1bc7..073a264b 100644 --- a/src/pages/MyPage/index.tsx +++ b/src/pages/MyPage/index.tsx @@ -79,7 +79,7 @@ export default function MyPage() { - {myPageData?.dog && } + {myPageData?.dog && }