diff --git a/public/image/graphics/image_guest.png b/public/image/graphics/image_guest.png index 5efd879a..5f3924ff 100644 Binary files a/public/image/graphics/image_guest.png and b/public/image/graphics/image_guest.png differ diff --git a/public/image/graphics/image_hostapply_finish.png b/public/image/graphics/image_hostapply_finish.png index d0c24d38..3c2a0f8d 100644 Binary files a/public/image/graphics/image_hostapply_finish.png and b/public/image/graphics/image_hostapply_finish.png differ diff --git a/public/image/graphics/image_spicker_apply.png b/public/image/graphics/image_spicker_apply.png new file mode 100644 index 00000000..9183063d Binary files /dev/null and b/public/image/graphics/image_spicker_apply.png differ diff --git a/public/image/profile/image_host_background.png b/public/image/profile/image_host_background.png new file mode 100644 index 00000000..1ce7a551 Binary files /dev/null and b/public/image/profile/image_host_background.png differ diff --git a/public/image/profile/image_host_profile.png b/public/image/profile/image_host_profile.png index 5360a78d..02bb936c 100644 Binary files a/public/image/profile/image_host_profile.png and b/public/image/profile/image_host_profile.png differ diff --git a/public/svg/ic_camera.svg b/public/svg/ic_camera.svg new file mode 100644 index 00000000..0b748720 --- /dev/null +++ b/public/svg/ic_camera.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/svg/ic_edit.svg b/public/svg/ic_edit.svg new file mode 100644 index 00000000..c9017897 --- /dev/null +++ b/public/svg/ic_edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/svg/ic_spicker_apply.svg b/public/svg/ic_spicker_apply.svg new file mode 100644 index 00000000..10cfdd2c --- /dev/null +++ b/public/svg/ic_spicker_apply.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/apis/domains/host/useFetchHostInfo.ts b/src/apis/domains/host/useFetchHostInfo.ts new file mode 100644 index 00000000..717f1f0b --- /dev/null +++ b/src/apis/domains/host/useFetchHostInfo.ts @@ -0,0 +1,28 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { get } from '@apis/api'; +import { QUERY_KEY } from '@apis/queryKeys/queryKeys'; + +import { components } from '@schema'; +import { ApiResponseType } from '@types'; + +type HostIntroGetResponse = components['schemas']['HostIntroGetResponse']; + +const getHostInfo = async (hostId: number): Promise => { + try { + const response = await get>(`/v2/host/${hostId}/intro`); + return response.data.data; + } catch (error) { + console.error('An error occurred while fetching the host info:', error); + return null; + } +}; + +export const useFetchHostInfo = (hostId: number) => { + return useSuspenseQuery({ + queryKey: [QUERY_KEY.HOST_INFO, hostId], + queryFn: () => getHostInfo(hostId), + staleTime: 1000 * 10, + gcTime: 1000 * 10, + }); +}; diff --git a/src/apis/domains/host/usePatchHostInfo.ts b/src/apis/domains/host/usePatchHostInfo.ts new file mode 100644 index 00000000..a5c740ee --- /dev/null +++ b/src/apis/domains/host/usePatchHostInfo.ts @@ -0,0 +1,65 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { SetStateAction } from 'jotai'; +import { Dispatch, RefObject } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { patch } from '@apis/api'; +import { QUERY_KEY } from '@apis/queryKeys/queryKeys'; + +import { smoothScroll } from '@utils'; + +import { components } from '@schema'; +import { ApiResponseType, ErrorResponse, ErrorType, MutateResponseType } from '@types'; + +type HostUpdateRequest = components['schemas']['HostUpdateRequest']; +export interface PatchHostInfoRequest { + hostId: number; + hostInfoValue: HostUpdateRequest; +} + +const patchHostInfo = async ({ + hostId, + hostInfoValue, +}: PatchHostInfoRequest): Promise => { + try { + const response = await patch>( + `/v2/host/${hostId}`, + hostInfoValue + ); + return response.data.data; + } catch (error) { + const errorResponse = error as ErrorResponse; + const errorData = errorResponse.response.data; + throw errorData; + } +}; + +export const usePatchHostInfo = ( + hostId: number, + setIsNicknameDuplicate: Dispatch>, + nicknameRef: RefObject +) => { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + return useMutation({ + mutationFn: ({ hostId, hostInfoValue }: PatchHostInfoRequest) => + patchHostInfo({ hostId, hostInfoValue }), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [QUERY_KEY.HOST_INFO, hostId], + }); + navigate(`/host/info/${hostId}`); + }, + + onError: (error: ErrorType) => { + if (error.status === 40008) { + setIsNicknameDuplicate(true); + nicknameRef.current?.focus(); + smoothScroll(0); + } else { + alert(error.message); + } + }, + }); +}; diff --git a/src/apis/domains/moim/useFetchMoimListByHost.ts b/src/apis/domains/moim/useFetchMoimListByHost.ts new file mode 100644 index 00000000..7efa507b --- /dev/null +++ b/src/apis/domains/moim/useFetchMoimListByHost.ts @@ -0,0 +1,31 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { get } from '@apis/api'; +import { QUERY_KEY } from '@apis/queryKeys/queryKeys'; + +import { components } from '@schema'; +import { ApiResponseType } from '@types'; + +type MoimListByHostResponse = components['schemas']['MoimListByHostGetResponse']; + +const getMoimListByHost = async (hostId: number): Promise => { + try { + const response = await get>( + `/v2/host/${hostId}/moim-list` + ); + + return response.data.data; + } catch (error) { + console.error('An error occurred while fetching the category:', error); + return null; + } +}; + +export const useFetchMoimListByHost = (hostId: number) => { + return useSuspenseQuery({ + queryKey: [QUERY_KEY.HOST_INFO_CLASS, hostId], + queryFn: () => getMoimListByHost(hostId), + staleTime: 1000 * 30, // 30초 + gcTime: 1000 * 60 * 5, // 5분 + }); +}; diff --git a/src/apis/domains/review/useFetchReviewByHost.ts b/src/apis/domains/review/useFetchReviewByHost.ts new file mode 100644 index 00000000..27fb4b62 --- /dev/null +++ b/src/apis/domains/review/useFetchReviewByHost.ts @@ -0,0 +1,31 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { get } from '@apis/api'; +import { QUERY_KEY } from '@apis/queryKeys/queryKeys'; + +import { components } from '@schema'; +import { ApiResponseType } from '@types'; + +type ReviewByHostResponse = components['schemas']['ReviewListGetByHostResponse']; + +const getReviewByHost = async (hostId: number): Promise => { + try { + const response = await get>( + `/v2/host/${hostId}/review-list` + ); + + return response.data.data; + } catch (error) { + console.error('An error occurred while fetching the category:', error); + return null; + } +}; + +export const useFetchReviewByHost = (hostId: number) => { + return useSuspenseQuery({ + queryKey: [QUERY_KEY.HOST_INFO_REVIEW, hostId], + queryFn: () => getReviewByHost(hostId), + staleTime: 1000 * 30, // 30초 + gcTime: 1000 * 60 * 5, // 5분 + }); +}; diff --git a/src/apis/queryKeys/queryKeys.ts b/src/apis/queryKeys/queryKeys.ts index f4841b08..e0d6343a 100644 --- a/src/apis/queryKeys/queryKeys.ts +++ b/src/apis/queryKeys/queryKeys.ts @@ -26,6 +26,9 @@ export const QUERY_KEY = { HOST_SUBMIT_REQUEST: 'hostSubmitRequest', MOIM_SUBMITTER_ALL: 'moimSubmitterAll', MOIM_SUBMITTER_ALL_REQUEST: 'miomSubmitterAllRequest', + HOST_INFO: 'hostInfo', + HOST_INFO_CLASS: 'hostInfoClass', + HOST_INFO_REVIEW: 'hostInfoReview', REVIEW_MOIM_INFO: 'reviewMoimInfo', REVIEW_TAG_LIST: 'reviewTagList', MOIM_NOTICE_DETAIL: 'moimNoticeDetail', diff --git a/src/assets/svg/IcCamera.tsx b/src/assets/svg/IcCamera.tsx new file mode 100644 index 00000000..a71f2d1c --- /dev/null +++ b/src/assets/svg/IcCamera.tsx @@ -0,0 +1,11 @@ +import type { SVGProps } from 'react'; +const SvgIcCamera = (props: SVGProps) => ( + + + + +); +export default SvgIcCamera; diff --git a/src/assets/svg/IcEdit.tsx b/src/assets/svg/IcEdit.tsx new file mode 100644 index 00000000..a428d734 --- /dev/null +++ b/src/assets/svg/IcEdit.tsx @@ -0,0 +1,11 @@ +import type { SVGProps } from 'react'; +const SvgIcEdit = (props: SVGProps) => ( + + + + +); +export default SvgIcEdit; diff --git a/src/assets/svg/IcSpickerApply.tsx b/src/assets/svg/IcSpickerApply.tsx new file mode 100644 index 00000000..9a992c1c --- /dev/null +++ b/src/assets/svg/IcSpickerApply.tsx @@ -0,0 +1,193 @@ +import type { SVGProps } from 'react'; +const SvgIcSpickerApply = (props: SVGProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default SvgIcSpickerApply; diff --git a/src/assets/svg/index.ts b/src/assets/svg/index.ts index ac02064c..d6ee9cba 100644 --- a/src/assets/svg/index.ts +++ b/src/assets/svg/index.ts @@ -4,6 +4,7 @@ export { default as IcApplicantArrcodionDown } from './IcApplicantArrcodionDown' export { default as IcApplicantArrcodionUp } from './IcApplicantArrcodionUp'; export { default as IcBtnMinus } from './IcBtnMinus'; export { default as IcBtnPlus } from './IcBtnPlus'; +export { default as IcCamera } from './IcCamera'; export { default as IcCameraAdd } from './IcCameraAdd'; export { default as IcCaution } from './IcCaution'; export { default as IcCheckActive } from './IcCheckActive'; @@ -24,6 +25,7 @@ export { default as IcDropdownPlatformDown } from './IcDropdownPlatformDown'; export { default as IcDropdownPlatformUp } from './IcDropdownPlatformUp'; export { default as IcDropdownRight } from './IcDropdownRight'; export { default as IcDropdownUp } from './IcDropdownUp'; +export { default as IcEdit } from './IcEdit'; export { default as IcEmploymentActive } from './IcEmploymentActive'; export { default as IcEmploymentBlack } from './IcEmploymentBlack'; export { default as IcEmploymentSmall } from './IcEmploymentSmall'; @@ -72,6 +74,7 @@ export { default as IcProductivityBlack } from './IcProductivityBlack'; export { default as IcProductivitySmall } from './IcProductivitySmall'; export { default as IcSend } from './IcSend'; export { default as IcShare } from './IcShare'; +export { default as IcSpickerApply } from './IcSpickerApply'; export { default as IcSpickerMark } from './IcSpickerMark'; export { default as IcStartupActive } from './IcStartupActive'; export { default as IcStartupBlack } from './IcStartupBlack'; diff --git a/src/components/common/DateSelect/DateSelect.tsx b/src/components/common/DateSelect/DateSelect.tsx index 95aff290..6de97f62 100644 --- a/src/components/common/DateSelect/DateSelect.tsx +++ b/src/components/common/DateSelect/DateSelect.tsx @@ -28,7 +28,7 @@ const CustomInput = React.forwardRef( const hasValue = !!value; return (
- + css` - ${flexGenerator('column')}; + ${flexGenerator('column', 'flex-start', 'flex-start')}; gap: ${gapSize}rem; width: 100%; `; + export const referTextStyle = (theme: Theme) => css` ${flexGenerator('row', 'flex-start')}; width: 100%; diff --git a/src/pages/class/components/StepOne/StepOne.tsx b/src/pages/class/components/StepOne/StepOne.tsx index 73e7796f..0f9b4979 100644 --- a/src/pages/class/components/StepOne/StepOne.tsx +++ b/src/pages/class/components/StepOne/StepOne.tsx @@ -149,6 +149,7 @@ const StepOne = ({ onNext }: StepProps) => { onStartTimeChange={handleStartTimeChange} onEndTimeChange={handleEndTimeChange} /> + *픽플은 최소 10분 이상의 네트워킹 시간을 권장합니다.
몇 명의 게스트와 함께하고 싶으신가요? diff --git a/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.style.ts b/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.style.ts index 2862028a..82444435 100644 --- a/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.style.ts +++ b/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.style.ts @@ -39,11 +39,15 @@ export const questionMainStyle = css` export const questionDataStyle = css` ${flexGenerator('column', 'flex-start', 'flex-start')} - /* padding: 1.2rem 1.6rem 1rem 1rem; */ - gap: 1.5rem; + gap: 3rem; width: 100%; `; +export const eachQuestionWrapper = css` + ${flexGenerator('column')} + gap: 1rem; +`; + export const questionCautionStyle = (theme: Theme) => css` ${flexGenerator('row', 'flex-start', 'flex-start')}; gap: 1rem; @@ -65,6 +69,12 @@ export const questionCautionTextStyle = (theme: Theme) => css` ${theme.font['body02-r-14']} `; +export const question4WrapperStyle = css` + ${flexGenerator('column', 'flex-start', 'flex-start')} + width: 100%; + gap: 1.5rem; +`; + export const questionRefundStyle = () => css` ${flexGenerator('row', 'flex-start', 'flex-start')}; gap: 1.5rem; diff --git a/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.tsx b/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.tsx index 3dd07217..9fe52d4c 100644 --- a/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.tsx +++ b/src/pages/class/page/ClassApply/ClassApplyQuestion/ClassApplyQuestion.tsx @@ -11,7 +11,9 @@ import { IcCaution } from '@svg'; import AccountNumberInput from 'src/components/common/inputs/AccountNumberInput/AccountNumberInput'; import { + eachQuestionWrapper, headerStyle, + question4WrapperStyle, questionArticleLayout, questionCautionIconStyle, questionCautionStyle, @@ -125,7 +127,7 @@ const ClassApplyQuestion = ({ handlePageChange }: ClassApplyProps) => { {questionList.map((question, index) => (
{question && ( - <> +
{question}