diff --git a/apps/shelter/src/apis/shelter.ts b/apps/shelter/src/apis/shelter.ts index 87faad9f..d512eeb7 100644 --- a/apps/shelter/src/apis/shelter.ts +++ b/apps/shelter/src/apis/shelter.ts @@ -1,6 +1,6 @@ import axiosInstance from 'shared/apis/axiosInstance'; -import { ShelterInfo } from '@/types/apis/shetler'; +import { ShelterInfo, UpdateShelterInfo } from '@/types/apis/shetler'; type PasswordUpdateParams = { newPassword: string; @@ -15,8 +15,8 @@ type PageParams = { export const getShelterInfoAPI = () => axiosInstance.get('/shelters/me'); -export const updateShelterInfo = (shelterInfo: ShelterInfo) => - axiosInstance.patch('/shelters/me', shelterInfo); +export const updateShelterInfo = (shelterInfo: UpdateShelterInfo) => + axiosInstance.patch('/shelters/me', shelterInfo); export const updatePassword = (passwordUpdateParams: PasswordUpdateParams) => axiosInstance.patch( diff --git a/apps/shelter/src/mocks/handlers/shelter.ts b/apps/shelter/src/mocks/handlers/shelter.ts index d7ee40cf..8418542f 100644 --- a/apps/shelter/src/mocks/handlers/shelter.ts +++ b/apps/shelter/src/mocks/handlers/shelter.ts @@ -22,7 +22,7 @@ export const handlers = [ shelterId: 1, shelterEmail: 'Shelter1234@gmail.com', shelterName: '양천구 보호소', - imageUrl: null, + shelterImageUrl: 'https://source.unsplash.com/random/?animal', shelterAddress: '서울특별시 양천구', shelterAddressDetail: '서울특별시 양천구 신월동 동자빌딩', shelterPhoneNumber: '010-1234-5678', @@ -49,4 +49,8 @@ export const handlers = [ { status: 200 }, ); }), + http.patch('/shelters/me', async () => { + await delay(200); + return new HttpResponse(null, { status: 204 }); + }), ]; diff --git a/apps/shelter/src/pages/settings/account/_hooks/useFetchShelterAccount.ts b/apps/shelter/src/pages/settings/account/_hooks/useFetchShelterAccount.ts new file mode 100644 index 00000000..2ea3579f --- /dev/null +++ b/apps/shelter/src/pages/settings/account/_hooks/useFetchShelterAccount.ts @@ -0,0 +1,35 @@ +import { useQuery } from '@tanstack/react-query'; + +import { getShelterInfoAPI } from '@/apis/shelter'; + +const useFethShelterAccount = () => { + return useQuery({ + queryKey: ['shelter', 'account'], + queryFn: async () => (await getShelterInfoAPI()).data, + select: (data) => { + return { + imageUrl: data.shelterImageUrl, + email: data.shelterEmail, + name: data.shelterName, + address: data.shelterAddress, + addressDetail: data.shelterAddressDetail, + phoneNumber: data.shelterPhoneNumber, + sparePhoneNumber: data.shelterSparePhoneNumber, + isOpenedAddress: data.shelterIsOpenedAddress, + }; + }, + initialData: { + shelterId: 1, + shelterImageUrl: '', + shelterEmail: '', + shelterName: '', + shelterAddress: '', + shelterAddressDetail: '', + shelterPhoneNumber: '', + shelterSparePhoneNumber: '', + shelterIsOpenedAddress: false, + }, + }); +}; + +export default useFethShelterAccount; diff --git a/apps/shelter/src/pages/settings/account/index.tsx b/apps/shelter/src/pages/settings/account/index.tsx index 378b2756..e9730a0e 100644 --- a/apps/shelter/src/pages/settings/account/index.tsx +++ b/apps/shelter/src/pages/settings/account/index.tsx @@ -8,11 +8,43 @@ import { HStack, Input, Switch, + useToast, } from '@chakra-ui/react'; -import { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; + +import { updateShelterInfo } from '@/apis/shelter'; +import { UpdateShelterInfo } from '@/types/apis/shetler'; + +import useFetchShelterAccount from './_hooks/useFetchShelterAccount'; export default function SettingsAccountPage() { + const toast = useToast(); const [imgFile, setImgFile] = useState(''); + const { data } = useFetchShelterAccount(); + const { mutate: updateShelter } = useMutation({ + mutationFn: (data: UpdateShelterInfo) => updateShelterInfo(data), + onSuccess: () => { + toast({ + position: 'top', + description: '계정 정보가 수정되었습니다.', + status: 'success', + duration: 1500, + }); + }, + }); + + const { register, handleSubmit, reset, watch } = useForm(); + + useEffect(() => { + reset(data); + setImgFile(data.imageUrl); + }, [data]); + + const onSubmit = handleSubmit((newData) => { + updateShelter(newData); + }); const uploadImgFile = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -24,7 +56,7 @@ export default function SettingsAccountPage() { return ( -
+
@@ -50,17 +82,21 @@ export default function SettingsAccountPage() { bgColor="gray.100" color="gray.500" _hover={{ border: 'none' }} + value={data.email} /> 보호소 이름 - + 보호소 주소 - + @@ -78,20 +114,35 @@ export default function SettingsAccountPage() { > 상세주소 공개 - + - + 보호소 전화번호 - + 보호소 임시 전화번호 - +
diff --git a/apps/shelter/src/types/apis/shetler.ts b/apps/shelter/src/types/apis/shetler.ts index bf14ca0a..98cab73b 100644 --- a/apps/shelter/src/types/apis/shetler.ts +++ b/apps/shelter/src/types/apis/shetler.ts @@ -9,3 +9,13 @@ export type ShelterInfo = { shelterSparePhoneNumber: string; shelterIsOpenedAddress: boolean; }; + +export type UpdateShelterInfo = { + imageUrl?: string; + name: string; + address: string; + addressDetail: string; + phoneNumber: string; + sparePhoneNumber: string; + isOpenedAddress: boolean; +}; diff --git a/apps/volunteer/src/apis/volunteer.ts b/apps/volunteer/src/apis/volunteer.ts index 51f38d75..95aa9522 100644 --- a/apps/volunteer/src/apis/volunteer.ts +++ b/apps/volunteer/src/apis/volunteer.ts @@ -1,7 +1,7 @@ import axiosInstance from 'shared/apis/axiosInstance'; -type MyInfoResponse = { - volunteerId: string; +export type MyInfoResponse = { + volunteerId: number; volunteerEmail: string; volunteerName: string; volunteerBirthDate: string; @@ -9,7 +9,7 @@ type MyInfoResponse = { volunteerTemperture: number; volunteerCount: number; volunteerImageUrl: string; - volunteerGender: 'FEMAIL' | 'MALE'; + volunteerGender: 'FEMALE' | 'MALE'; }; export const getMyVolunteerInfo = () => @@ -29,10 +29,10 @@ export const updateVolunteerPassword = ( ); }; -type UpdateUserInfoParams = { +export type UpdateUserInfoParams = { name: string; - gender: string; - birthData: string; + gender: 'FEMALE' | 'MALE'; + birthDate: string; phoneNumber: string; imageUrl: string; }; diff --git a/apps/volunteer/src/mocks/browser.ts b/apps/volunteer/src/mocks/browser.ts index 36cf206f..063a98c3 100644 --- a/apps/volunteer/src/mocks/browser.ts +++ b/apps/volunteer/src/mocks/browser.ts @@ -2,5 +2,6 @@ import { setupWorker } from 'msw/browser'; import { handlers as authHandlers } from './handlers/auth'; import { handlers as recruitmentHandler } from './handlers/recruitment'; +import { handlers as volunteerHandlers } from './handlers/volunteer'; -export const worker = setupWorker(...authHandlers, ...recruitmentHandler); +export const worker = setupWorker(...authHandlers, ...recruitmentHandler, ...volunteerHandlers ); diff --git a/apps/volunteer/src/mocks/handlers/volunteer.ts b/apps/volunteer/src/mocks/handlers/volunteer.ts new file mode 100644 index 00000000..34af7b55 --- /dev/null +++ b/apps/volunteer/src/mocks/handlers/volunteer.ts @@ -0,0 +1,23 @@ +import { delay, http, HttpResponse } from 'msw'; + +export const handlers = [ + http.get('/volunteers/me', async () => { + await delay(200); + return HttpResponse.json({ + volunteerId: 1, + volunteerEmail: 'programmers@gmail.com', + volunteerName: '김프롱', + volunteerBirthDate: '2023-03-16', + volunteerPhoneNumber: '010-1234-5678', + volunteerTemperature: 32, + completedVolunteerCount: 3, + volunteerImageUrl: 'https://source.unsplash.com/random', + volunteerGender: 'FEMALE', + }); + }), + http.patch('/volunteers/me', async ({ request }) => { + const updateVolunteer = await request.json(); + console.log(updateVolunteer); + return new HttpResponse(null, { status: 204 }); + }), +]; diff --git a/apps/volunteer/src/pages/settings/account/_hooks/useFetchAccount.ts b/apps/volunteer/src/pages/settings/account/_hooks/useFetchAccount.ts new file mode 100644 index 00000000..5e463e7f --- /dev/null +++ b/apps/volunteer/src/pages/settings/account/_hooks/useFetchAccount.ts @@ -0,0 +1,32 @@ +import { useQuery } from '@tanstack/react-query'; + +import { getMyVolunteerInfo, MyInfoResponse } from '@/apis/volunteer'; + +const useFetchAccount = () => + useQuery({ + queryKey: ['volunteer', 'account'], + queryFn: async () => (await getMyVolunteerInfo()).data, + select: (data: MyInfoResponse) => { + return { + imageUrl: data.volunteerImageUrl, + email: data.volunteerEmail, + name: data.volunteerName, + birthDate: data.volunteerBirthDate, + phoneNumber: data.volunteerPhoneNumber, + gender: data.volunteerGender, + }; + }, + initialData: { + volunteerId: 1, + volunteerEmail: '', + volunteerName: '', + volunteerBirthDate: '', + volunteerPhoneNumber: '', + volunteerTemperture: 36, + volunteerCount: 0, + volunteerImageUrl: '', + volunteerGender: 'MALE', + }, + }); + +export default useFetchAccount; diff --git a/apps/volunteer/src/pages/settings/account/index.tsx b/apps/volunteer/src/pages/settings/account/index.tsx index 02d2abc6..bb60b4c9 100644 --- a/apps/volunteer/src/pages/settings/account/index.tsx +++ b/apps/volunteer/src/pages/settings/account/index.tsx @@ -9,11 +9,47 @@ import { Input, Radio, RadioGroup, + useToast, } from '@chakra-ui/react'; -import { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; + +import { + UpdateUserInfoParams, + updateVolunteerUserInfo, +} from '@/apis/volunteer'; + +import useFetchAccount from './_hooks/useFetchAccount'; export default function SettingsAccountPage() { + const toast = useToast(); const [imgFile, setImgFile] = useState(''); + const { data } = useFetchAccount(); + const { mutate: updateAccount } = useMutation({ + mutationFn: (data: UpdateUserInfoParams) => updateVolunteerUserInfo(data), + onSuccess: () => { + toast({ + position: 'top', + description: '계정 정보가 수정되었습니다.', + status: 'success', + duration: 1500, + }); + }, + }); + const { register, handleSubmit, reset, watch } = + useForm(); + + useEffect(() => { + reset({ + name: data.name, + imageUrl: data.imageUrl, + birthDate: data.birthDate, + phoneNumber: data.phoneNumber, + gender: data.gender, + }); + setImgFile(data.imageUrl); + }, [data, reset]); const uploadImgFile = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -22,9 +58,14 @@ export default function SettingsAccountPage() { setImgFile(newImgFile); } }; + + const onSubmit = handleSubmit((newData) => { + updateAccount(newData); + // console.log(newData); + }); return ( - +
@@ -49,31 +90,40 @@ export default function SettingsAccountPage() { bgColor="gray.100" color="gray.500" _hover={{ border: `none` }} + value={data.email} /> 이름 - + 생년월일 - + 전화번호 - + 성별 - + - + 남성 - + 여성 @@ -89,6 +139,8 @@ export default function SettingsAccountPage() { color="white" pos="absolute" bottom={21} + _active={{ bg: undefined }} + _hover={{ bg: undefined }} > 수정 완료