diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index 8725cae0..3c14e807 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -5,8 +5,6 @@ import { useCallback, useState } from 'react'; import { useForm } from 'react-hook-form'; -import { useRouter } from 'next/navigation'; - import { AGE_MAP, AgeType, GENDER_MAP, GenderType, } from '@constants/dropdownMap'; @@ -28,7 +26,6 @@ type SignUpFormType = { } & ISignUp; function SignupPage() { - const router = useRouter(); const [duplicationValidation, setDuplicationValidation] = useState({ id: false, email: false, @@ -56,7 +53,6 @@ function SignupPage() { mutate({ id, password, email, gender, age, }); - router.push('/login'); }; const [step, setStep] = useState(1); diff --git a/src/app/(car-details)/car-details/hydrated-page.tsx b/src/app/(car-details)/car-details/hydrated-page.tsx index f51d94dc..37343330 100644 --- a/src/app/(car-details)/car-details/hydrated-page.tsx +++ b/src/app/(car-details)/car-details/hydrated-page.tsx @@ -93,8 +93,8 @@ function CarDetailsPage() { {step === 3 && ( { return import('@shared/fixedBottomButton/FixedBottomButton'); }, { ssr: false, }); -function MyCarDetailsPage() { - // TODO: api or store를 통해 defaultValue 설정하기 +function MyCarDetailsPage({ myCarInfo }: { myCarInfo: CarInfoType }) { + const { carOptions, mappingCarOptions } = mappingCarDetails(myCarInfo); + const { mutate } = useRegisterCarDetails(); const { - register, watch, formState: { + register, watch, reset, formState: { isDirty, isValid, - }, getValues, + }, handleSubmit, } = useForm({ - defaultValues: { - segment: '세단', - cartype: '중형', - color: '빨간색', - driving: '복합적', - parking: '노상', - }, + defaultValues: useMemo(() => { + return { + segment: myCarInfo.value.car_info.segment, + cartype: myCarInfo.value.car_info.cartype, + color: myCarInfo.value.car_info.color, + driving: myCarInfo.value.car_info.driving, + parking: myCarInfo.value.car_info.parking, + }; + }, [myCarInfo]), mode: 'onBlur', }); - const onSubmit = () => { - // eslint-disable-next-line no-console - console.log(getValues()); + const onSubmit = (carInfo: ICarDetails) => { + mutate(carInfo); }; + useEffect(() => { + reset({ + segment: myCarInfo.value.car_info.segment, + cartype: myCarInfo.value.car_info.cartype, + color: myCarInfo.value.car_info.color, + driving: myCarInfo.value.car_info.driving, + parking: myCarInfo.value.car_info.parking, + }); + }, [myCarInfo, reset]); + return ( <>
@@ -44,47 +61,47 @@ function MyCarDetailsPage() {
- 변경 사항 저장하기 + 변경 사항 저장하기
); } -export default MyCarDetailsPage; +export default withRegisterCarDetails(MyCarDetailsPage); diff --git a/src/app/(my-page)/my-page/car-wash-details/page.tsx b/src/app/(my-page)/my-page/car-wash-details/page.tsx index baf3b3bc..2f93b0fa 100644 --- a/src/app/(my-page)/my-page/car-wash-details/page.tsx +++ b/src/app/(my-page)/my-page/car-wash-details/page.tsx @@ -1,40 +1,55 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ + 'use client'; +import { useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import dynamic from 'next/dynamic'; -import { - COST_OPTIONS, FREQUENCY_OPTIONS, INTEREST_OPTIONS, -} from '@constants/myPage'; +import withRegisterCarWashDetails from '@hooks/withRegisterCarWashDetails'; +import { ICarWashDetails } from '@remote/api/types/additional-info'; +import { CarWashInfoType } from '@remote/api/types/my-page'; +import useRegisterCarWashDetails from '@remote/queries/additional-info/car-wash-details/useRegisterCarWashDetails'; import DropdownField from '@shared/dropdown-field/DropdownField'; import Header from '@shared/header/Header'; import Spacing from '@shared/spacing/Spacing'; +import mappingCarWashDetails from '@utils/mappingCarWashDetails'; const FixedBottomButton = dynamic(() => { return import('@shared/fixedBottomButton/FixedBottomButton'); }, { ssr: false, }); -function MyCarWashDetailsPage() { - // TODO: api or store를 통해 defaultValue 설정하기 +function MyCarWashDetailsPage({ myCarWashInfo }: { myCarWashInfo: CarWashInfoType }) { + const { carWashOptions, mappingCarWashOptions } = mappingCarWashDetails(myCarWashInfo); + const { mutate } = useRegisterCarWashDetails(); const { - register, watch, formState: { + register, watch, reset, formState: { isDirty, isValid, - }, getValues, + }, handleSubmit, } = useForm({ - defaultValues: { - frequency: '월 4회 이상', - cost: '월 10만원 이상', - interest: '도장', - }, + defaultValues: useMemo(() => { + return { + frequency: myCarWashInfo.value.wash_info.frequency, + cost: myCarWashInfo.value.wash_info.cost, + interest: myCarWashInfo.value.wash_info.interest, + }; + }, [myCarWashInfo]), mode: 'onBlur', }); - const onSubmit = () => { - // eslint-disable-next-line no-console - console.log(getValues()); + const onSubmit = (carWashInfo: ICarWashDetails) => { + mutate(carWashInfo); }; + useEffect(() => { + reset({ + frequency: myCarWashInfo.value.wash_info.frequency, + cost: myCarWashInfo.value.wash_info.cost, + interest: myCarWashInfo.value.wash_info.interest, + }); + }, [myCarWashInfo, reset]); + return ( <>
@@ -42,31 +57,31 @@ function MyCarWashDetailsPage() {
- 변경 사항 저장하기 + 변경 사항 저장하기
); } -export default MyCarWashDetailsPage; +export default withRegisterCarWashDetails(MyCarWashDetailsPage); diff --git a/src/app/(my-page)/my-page/page.tsx b/src/app/(my-page)/my-page/page.tsx index 9a8d03fe..ec81c75b 100644 --- a/src/app/(my-page)/my-page/page.tsx +++ b/src/app/(my-page)/my-page/page.tsx @@ -1,7 +1,5 @@ 'use client'; -import { useEffect, useState } from 'react'; - import classNames from 'classnames/bind'; import Link from 'next/link'; @@ -30,19 +28,13 @@ function MyProfilePage() { (prev, curr) => { return prev === curr; }, ); - const [isLoggedIn, setIsLoggedIn] = useState(false); - - useEffect(() => { - setIsLoggedIn(userId !== null); - }, [userId]); - // 로그아웃 const handleLoggedOut = () => { // TODO: 먼저 로그아웃 모달이 뜨도록 할지 논의필요 logout(); }; - if (isLoggedIn === false) { + if (userId == null) { return ( <>
  • - + 나의 차량 정보
  • - + 나의 세차 정보 diff --git a/src/app/(my-page)/my-page/profile/page.tsx b/src/app/(my-page)/my-page/profile/page.tsx index 1e401570..28324493 100644 --- a/src/app/(my-page)/my-page/profile/page.tsx +++ b/src/app/(my-page)/my-page/profile/page.tsx @@ -24,7 +24,6 @@ const FixedBottomButton = dynamic(() => { return import('@shared/fixedBottomButt function ProfilePage() { const { data: profile } = useProfile(); const { mutate } = useUpdateProfile(); - const { register, watch, reset, formState: { errors, isDirty, isValid, @@ -37,7 +36,7 @@ function ProfilePage() { gender: profile?.value.gender, age: profile?.value.age, }; - }, [profile?.value.age, profile?.value.email, profile?.value.gender, profile?.value.id]), + }, [profile]), mode: 'onBlur', }); @@ -56,7 +55,7 @@ function ProfilePage() { gender: profile?.value.gender, age: profile?.value.age, }); - }, [profile?.value.age, profile?.value.email, profile?.value.gender, profile?.value.id, reset]); + }, [profile, reset]); return ( <> diff --git a/src/constants/myPage.ts b/src/constants/myPage.ts index e20ec1d0..7ae36007 100644 --- a/src/constants/myPage.ts +++ b/src/constants/myPage.ts @@ -30,163 +30,3 @@ export const AGE_OPTIONS = [ value: 'AGE_60', }, ]; - -export const SEGMENT_OPTIONS = [ - { - label: '경차', - value: 'micro', - }, - { - label: '소형', - value: 'subcompact', - }, - { - label: '중형', - value: 'compact', - }, - { - label: '대형', - value: 'fullsize', - }, -]; - -export const CARTYPE_OPTIONS = [ - { - label: '세단', - value: 'sedan', - }, - { - label: '해치백', - value: 'hatchback', - }, - { - label: 'SUV', - value: 'suv', - }, - { - label: '기타', - value: 'etc', - }, -]; - -export const COLOR_OPTIONS = [ - { - label: '흰색', - value: 'FFFFFF', - }, - { - label: '쥐색', - value: '808080', - }, - { - label: '검정색', - value: '37383C', - }, - { - label: '빨간색', - value: 'FF4500', - }, - { - label: '노란색', - value: 'FFD400', - }, - { - label: '초록색', - value: '2F4F4F', - }, - { - label: '파란색', - value: '145B7D', - }, - { - label: '기타', - value: '6E0000', - }, -]; - -export const DRIVING_OPTIONS = [ - { - label: '도심', - value: 'comport', - }, - { - label: '고속', - value: 'highway', - }, - { - label: '복합', - value: 'complex', - }, -]; - -export const PARKING_OPTIONS = [ - { - label: '실내/지하', - value: 'house', - }, - { - label: '노상', - value: 'road', - }, { - - label: '필로티', - value: 'piloti', - }, -]; - -export const FREQUENCY_OPTIONS = [ - { - label: '월 평균 1회', - value: 'month1', - }, - { - label: '월 평균 2회', - value: 'month2', - }, - { - label: '월 평균 3회', - value: 'month3', - }, - { - label: '월 평균 4회', - value: 'month4', - }, -]; - -export const COST_OPTIONS = [ - { - label: '월 평균 1~3만원', - value: '1to3', - }, - { - label: '월 평균 4~6만원', - value: '4to6', - }, - { - label: '월 평균 7~9만원', - value: '7to9', - }, - { - label: '월 평균 10만원 이상', - value: '10over', - }, -]; - -export const INTEREST_OPTIONS = [ - { - label: '도장', - value: 'outercare', - }, - { - label: '타이어', - value: 'tire', - }, - { - label: '휠', - value: 'wheel', - }, - { - label: '실내', - value: 'innercare', - }, -]; diff --git a/src/hooks/withRegisterCarDetails.tsx b/src/hooks/withRegisterCarDetails.tsx new file mode 100644 index 00000000..c84207aa --- /dev/null +++ b/src/hooks/withRegisterCarDetails.tsx @@ -0,0 +1,51 @@ +import { + ComponentType, useCallback, useEffect, useState, +} from 'react'; + +import { isAxiosError } from 'axios'; +import { useRouter } from 'next/navigation'; + +import { getRequest } from '@remote/api/requests/requests.api'; +import { CarInfoType } from '@remote/api/types/my-page'; + +interface WithCarInfoProps { + myCarInfo: CarInfoType; +} + +function withRegisterCarDetails( + WrappedComponent: ComponentType, +) { + return function RegisteredComponent(props: Omit) { + const router = useRouter(); + const [myCarInfo, setMyCarInfo] = useState(null); + + // eslint-disable-next-line consistent-return + const handleRegister = useCallback(async () => { + try { + const response = await getRequest('/mypage/car'); + setMyCarInfo(response); + return response; + } catch (error) { + if (isAxiosError(error) && error.response) { + const { status } = error.response; + if (status === 400) { + router.push('/car-details'); + } + } + } + }, [router]); + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + handleRegister(); + }, [handleRegister]); + + if (myCarInfo == null) { + return null; + } + + return ; + }; +} + +export default withRegisterCarDetails; diff --git a/src/hooks/withRegisterCarWashDetails.tsx b/src/hooks/withRegisterCarWashDetails.tsx new file mode 100644 index 00000000..8e0624c3 --- /dev/null +++ b/src/hooks/withRegisterCarWashDetails.tsx @@ -0,0 +1,51 @@ +import { + ComponentType, useCallback, useEffect, useState, +} from 'react'; + +import { isAxiosError } from 'axios'; +import { useRouter } from 'next/navigation'; + +import { getRequest } from '@remote/api/requests/requests.api'; +import { CarWashInfoType } from '@remote/api/types/my-page'; + +interface WithCarWashInfoProps { + myCarWashInfo: CarWashInfoType; +} + +function withRegisterCarWashDetails( + WrappedComponent: ComponentType, +) { + return function RegisteredComponent(props: Omit) { + const router = useRouter(); + const [myCarWashInfo, setMyCarWashInfo] = useState(null); + + // eslint-disable-next-line consistent-return + const handleRegister = useCallback(async () => { + try { + const response = await getRequest('/mypage/wash'); + setMyCarWashInfo(response); + return response; + } catch (error) { + if (isAxiosError(error) && error.response) { + const { status } = error.response; + if (status === 400) { + router.push('/car-wash-details'); + } + } + } + }, [router]); + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + handleRegister(); + }, [handleRegister]); + + if (myCarWashInfo == null) { + return null; + } + + return ; + }; +} + +export default withRegisterCarWashDetails; diff --git a/src/remote/api/requests/additional-info/additional-info.post.api.ts b/src/remote/api/requests/additional-info/additional-info.post.api.ts index 8a329d76..d5c481bc 100644 --- a/src/remote/api/requests/additional-info/additional-info.post.api.ts +++ b/src/remote/api/requests/additional-info/additional-info.post.api.ts @@ -4,10 +4,10 @@ import { postRequest } from '../requests.api'; /* ----- 차량 정보 입력 api ----- */ export const postCarDetails = async ({ - segment, carType, color, driving, parking, + segment, cartype, color, driving, parking, }: ICarDetails) => { const response = await postRequest, ICarDetails>('/member/car', { - segment, carType, color, driving, parking, + segment, cartype, color, driving, parking, }); return response; diff --git a/src/remote/api/types/additional-info.ts b/src/remote/api/types/additional-info.ts index e9ab5175..db4a3ba2 100644 --- a/src/remote/api/types/additional-info.ts +++ b/src/remote/api/types/additional-info.ts @@ -18,7 +18,7 @@ export interface IAdditionalInfo { export interface ICarDetails { segment: number - carType: number + cartype: number color: number driving: number parking: number diff --git a/src/remote/api/types/my-page.ts b/src/remote/api/types/my-page.ts new file mode 100644 index 00000000..ec442142 --- /dev/null +++ b/src/remote/api/types/my-page.ts @@ -0,0 +1,30 @@ +import { IAdditionalInfo, ICarDetails, ICarWashDetails } from './additional-info'; +import { ICommon } from './common'; + +/* ----- 차량 정보 타입 ----- */ +export interface ICarInfo { + segment_options: IAdditionalInfo[] + carType_options: IAdditionalInfo[] + color_options: IAdditionalInfo[] + driving_options: IAdditionalInfo[] + parking_options: IAdditionalInfo[] + car_info: ICarDetails +} + +/* ----- 세차용품 정보 타입 ----- */ +export interface ICarWashInfo { + frequency_options: IAdditionalInfo[] + cost_options: IAdditionalInfo[] + interest_options: IAdditionalInfo[] + wash_info: ICarWashDetails +} + +/* ----- 마이페이지 dropdown 정보 ----- */ +export interface IinfoOptions { + [key: string]: { + [key: number]: string + }; +} + +export type CarInfoType = ICommon; +export type CarWashInfoType = ICommon; diff --git a/src/utils/mappingCarDetails.ts b/src/utils/mappingCarDetails.ts new file mode 100644 index 00000000..b69a0b2b --- /dev/null +++ b/src/utils/mappingCarDetails.ts @@ -0,0 +1,75 @@ +import { CarInfoType, IinfoOptions } from '@remote/api/types/my-page'; + +const mappingCarDetails = (info: CarInfoType) => { + const carOptions = { + segment_options: info.value.segment_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + carType_options: info.value.carType_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + color_options: info.value.color_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + driving_options: info.value.driving_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + parking_options: info.value.parking_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + }; + + const mappingCarOptions: IinfoOptions = { + segment_options: { + 16: '경차', + 17: '소형', + 18: '중형', + 19: '대형', + }, + carType_options: { + 11: '세단', + 12: '해치백', + 13: 'SUV', + 14: '기타', + }, + parking_options: { + 40: '실내/지하', + 41: '노상', + 42: '필로티', + }, + driving_options: { + 36: '도심', + 37: '고속', + 38: '복합', + }, + color_options: { + 21: '흰색', + 22: '쥐색', + 23: '검정색', + 24: '빨간색', + 25: '노란색', + 26: '초록색', + 27: '파란색', + 28: '기타', + }, + }; + + return { carOptions, mappingCarOptions }; +}; + +export default mappingCarDetails; diff --git a/src/utils/mappingCarWashDetails.ts b/src/utils/mappingCarWashDetails.ts new file mode 100644 index 00000000..bd3d54e8 --- /dev/null +++ b/src/utils/mappingCarWashDetails.ts @@ -0,0 +1,49 @@ +import { CarWashInfoType, IinfoOptions } from '@/remote/api/types/my-page'; + +const mappingCarWashDetails = (info: CarWashInfoType) => { + const carWashOptions = { + interest_options: info.value.interest_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + cost_options: info.value.cost_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + frequency_options: info.value.frequency_options.map((option) => { + return { + label: option.description, + value: option.codeNo, + }; + }), + }; + + const mappingCarWashOptions: IinfoOptions = { + interest_options: { + 44: '도장', + 45: '타이어', + 46: '휠', + 47: '실내', + }, + cost_options: { + 63: '월 평균 1~3만원', + 64: '월 평균 4~6만원', + 65: '월 평균 7~9만원', + 66: '월 평균 10만원 이상', + }, + frequency_options: { + 58: '월 평균 1회', + 59: '월 평균 2회', + 60: '월 평균 3회', + 61: '월 평균 4회', + }, + }; + + return { carWashOptions, mappingCarWashOptions }; +}; + +export default mappingCarWashDetails;