From 61696e59ccfee7e17dc9941eefbd003afdbb932d Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sat, 17 Aug 2024 21:40:08 +0900 Subject: [PATCH 01/15] #86 chore: modify components folders to private folder --- .../{actions => _actions}/uploadAction.ts | 0 .../CreatePolaroidModal/ArrowBack.tsx | 0 .../CreatePolaroidModal/ModalContext.tsx | 0 .../CreatePolaroidModal/UploadBtn.tsx | 0 .../CreatePolaroidModal/index.tsx | 2 +- .../{components => _components}/Empty.tsx | 4 ++-- .../{components => _components}/OpenModalBtn.tsx | 0 .../{components => _components}/ShareBtn.tsx | 0 .../Tutorial/Tooltip.tsx | 0 .../Tutorial/Tooltips.tsx | 0 .../Tutorial/TutorialContext.tsx | 0 .../Tutorial/index.tsx | 0 .../modals/AskBfCloseModal.tsx | 0 .../modals/CannotUploadModal.tsx | 0 .../modals/FinalModal.tsx | 0 src/app/(board)/board/[boardId]/page.tsx | 16 ++++++++-------- .../BoardAvailabilityCheckModal.tsx | 0 .../BoardNameForm.tsx | 0 .../BoardNameRecommendations.tsx | 0 src/app/(board)/board/create/page.tsx | 6 +++--- .../{components => _components}/CopyLinkBtn.tsx | 4 ++-- .../CreateBoardBtn.tsx | 0 .../GoToLoginModal.tsx | 0 .../{components => _components}/TotalCount.tsx | 0 src/app/(home)/page.tsx | 6 +++--- .../{components => _components}/KakaoLogin.tsx | 0 .../login/{components => _components}/Policy.tsx | 0 src/app/(onboarding)/login/page.tsx | 4 ++-- .../{components => _components}/NicknameForm.tsx | 0 .../{components => _components}/Buttons.tsx | 0 src/app/(onboarding)/signup/complete/page.tsx | 2 +- src/app/(onboarding)/signup/page.tsx | 2 +- .../LeaveConfirmModal.tsx | 0 .../{components => _components}/LeaveForm.tsx | 0 .../leave/{components => _components}/Title.tsx | 0 .../{components => _components}/Email.tsx | 0 .../{components => _components}/NicknameForm.tsx | 0 .../{components => _components}/Title.tsx | 0 38 files changed, 23 insertions(+), 23 deletions(-) rename src/app/(board)/board/[boardId]/{actions => _actions}/uploadAction.ts (100%) rename src/app/(board)/board/[boardId]/{components => _components}/CreatePolaroidModal/ArrowBack.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/CreatePolaroidModal/ModalContext.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/CreatePolaroidModal/UploadBtn.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/CreatePolaroidModal/index.tsx (95%) rename src/app/(board)/board/[boardId]/{components => _components}/Empty.tsx (64%) rename src/app/(board)/board/[boardId]/{components => _components}/OpenModalBtn.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/ShareBtn.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/Tutorial/Tooltip.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/Tutorial/Tooltips.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/Tutorial/TutorialContext.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/Tutorial/index.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/modals/AskBfCloseModal.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/modals/CannotUploadModal.tsx (100%) rename src/app/(board)/board/[boardId]/{components => _components}/modals/FinalModal.tsx (100%) rename src/app/(board)/board/create/{components => _components}/BoardAvailabilityCheckModal.tsx (100%) rename src/app/(board)/board/create/{components => _components}/BoardNameForm.tsx (100%) rename src/app/(board)/board/create/{components => _components}/BoardNameRecommendations.tsx (100%) rename src/app/(home)/{components => _components}/CopyLinkBtn.tsx (89%) rename src/app/(home)/{components => _components}/CreateBoardBtn.tsx (100%) rename src/app/(home)/{components => _components}/GoToLoginModal.tsx (100%) rename src/app/(home)/{components => _components}/TotalCount.tsx (100%) rename src/app/(onboarding)/login/{components => _components}/KakaoLogin.tsx (100%) rename src/app/(onboarding)/login/{components => _components}/Policy.tsx (100%) rename src/app/(onboarding)/signup/{components => _components}/NicknameForm.tsx (100%) rename src/app/(onboarding)/signup/complete/{components => _components}/Buttons.tsx (100%) rename src/app/mypage/leave/{components => _components}/LeaveConfirmModal.tsx (100%) rename src/app/mypage/leave/{components => _components}/LeaveForm.tsx (100%) rename src/app/mypage/leave/{components => _components}/Title.tsx (100%) rename src/app/mypage/profileEdit/{components => _components}/Email.tsx (100%) rename src/app/mypage/profileEdit/{components => _components}/NicknameForm.tsx (100%) rename src/app/mypage/profileEdit/{components => _components}/Title.tsx (100%) diff --git a/src/app/(board)/board/[boardId]/actions/uploadAction.ts b/src/app/(board)/board/[boardId]/_actions/uploadAction.ts similarity index 100% rename from src/app/(board)/board/[boardId]/actions/uploadAction.ts rename to src/app/(board)/board/[boardId]/_actions/uploadAction.ts diff --git a/src/app/(board)/board/[boardId]/components/CreatePolaroidModal/ArrowBack.tsx b/src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/CreatePolaroidModal/ArrowBack.tsx rename to src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx diff --git a/src/app/(board)/board/[boardId]/components/CreatePolaroidModal/ModalContext.tsx b/src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/ModalContext.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/CreatePolaroidModal/ModalContext.tsx rename to src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/ModalContext.tsx diff --git a/src/app/(board)/board/[boardId]/components/CreatePolaroidModal/UploadBtn.tsx b/src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/CreatePolaroidModal/UploadBtn.tsx rename to src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx diff --git a/src/app/(board)/board/[boardId]/components/CreatePolaroidModal/index.tsx b/src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/index.tsx similarity index 95% rename from src/app/(board)/board/[boardId]/components/CreatePolaroidModal/index.tsx rename to src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/index.tsx index bd96150..cd59ebe 100644 --- a/src/app/(board)/board/[boardId]/components/CreatePolaroidModal/index.tsx +++ b/src/app/(board)/board/[boardId]/_components/CreatePolaroidModal/index.tsx @@ -2,7 +2,7 @@ import PolaroidMaker from '@/components/Polaroid/PolaroidMaker' import { useRef, useState } from 'react' -import { uploadAction } from '../../actions/uploadAction' +import { uploadAction } from '../../_actions/uploadAction' import ArrowBack from './ArrowBack' import { useModal } from './ModalContext' import UploadBtn from './UploadBtn' diff --git a/src/app/(board)/board/[boardId]/components/Empty.tsx b/src/app/(board)/board/[boardId]/_components/Empty.tsx similarity index 64% rename from src/app/(board)/board/[boardId]/components/Empty.tsx rename to src/app/(board)/board/[boardId]/_components/Empty.tsx index 504c9cd..f936c16 100644 --- a/src/app/(board)/board/[boardId]/components/Empty.tsx +++ b/src/app/(board)/board/[boardId]/_components/Empty.tsx @@ -1,8 +1,8 @@ import Icon from 'public/icons/pinned.svg' const Empty = () => ( -
- +
+ 보드를 꾸며주세요!
) diff --git a/src/app/(board)/board/[boardId]/components/OpenModalBtn.tsx b/src/app/(board)/board/[boardId]/_components/OpenModalBtn.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/OpenModalBtn.tsx rename to src/app/(board)/board/[boardId]/_components/OpenModalBtn.tsx diff --git a/src/app/(board)/board/[boardId]/components/ShareBtn.tsx b/src/app/(board)/board/[boardId]/_components/ShareBtn.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/ShareBtn.tsx rename to src/app/(board)/board/[boardId]/_components/ShareBtn.tsx diff --git a/src/app/(board)/board/[boardId]/components/Tutorial/Tooltip.tsx b/src/app/(board)/board/[boardId]/_components/Tutorial/Tooltip.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/Tutorial/Tooltip.tsx rename to src/app/(board)/board/[boardId]/_components/Tutorial/Tooltip.tsx diff --git a/src/app/(board)/board/[boardId]/components/Tutorial/Tooltips.tsx b/src/app/(board)/board/[boardId]/_components/Tutorial/Tooltips.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/Tutorial/Tooltips.tsx rename to src/app/(board)/board/[boardId]/_components/Tutorial/Tooltips.tsx diff --git a/src/app/(board)/board/[boardId]/components/Tutorial/TutorialContext.tsx b/src/app/(board)/board/[boardId]/_components/Tutorial/TutorialContext.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/Tutorial/TutorialContext.tsx rename to src/app/(board)/board/[boardId]/_components/Tutorial/TutorialContext.tsx diff --git a/src/app/(board)/board/[boardId]/components/Tutorial/index.tsx b/src/app/(board)/board/[boardId]/_components/Tutorial/index.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/Tutorial/index.tsx rename to src/app/(board)/board/[boardId]/_components/Tutorial/index.tsx diff --git a/src/app/(board)/board/[boardId]/components/modals/AskBfCloseModal.tsx b/src/app/(board)/board/[boardId]/_components/modals/AskBfCloseModal.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/modals/AskBfCloseModal.tsx rename to src/app/(board)/board/[boardId]/_components/modals/AskBfCloseModal.tsx diff --git a/src/app/(board)/board/[boardId]/components/modals/CannotUploadModal.tsx b/src/app/(board)/board/[boardId]/_components/modals/CannotUploadModal.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/modals/CannotUploadModal.tsx rename to src/app/(board)/board/[boardId]/_components/modals/CannotUploadModal.tsx diff --git a/src/app/(board)/board/[boardId]/components/modals/FinalModal.tsx b/src/app/(board)/board/[boardId]/_components/modals/FinalModal.tsx similarity index 100% rename from src/app/(board)/board/[boardId]/components/modals/FinalModal.tsx rename to src/app/(board)/board/[boardId]/_components/modals/FinalModal.tsx diff --git a/src/app/(board)/board/[boardId]/page.tsx b/src/app/(board)/board/[boardId]/page.tsx index dac5931..4360153 100644 --- a/src/app/(board)/board/[boardId]/page.tsx +++ b/src/app/(board)/board/[boardId]/page.tsx @@ -5,14 +5,14 @@ import PolaroidCard from '@/components/Polaroid/PolaroidCard' import { getBoard } from '@/lib' import { Metadata } from 'next' import PinIcon from 'public/icons/pinFilled.svg' -import CreatePolaroid from './components/CreatePolaroidModal' -import { ModalProvider } from './components/CreatePolaroidModal/ModalContext' -import Empty from './components/Empty' -import OpenModalBtn from './components/OpenModalBtn' -import ShareBtn from './components/ShareBtn' -import Tutorial from './components/Tutorial' -import { Step1Tooltip } from './components/Tutorial/Tooltips' -import { TutorialProvider } from './components/Tutorial/TutorialContext' +import CreatePolaroid from './_components/CreatePolaroidModal' +import { ModalProvider } from './_components/CreatePolaroidModal/ModalContext' +import Empty from './_components/Empty' +import OpenModalBtn from './_components/OpenModalBtn' +import ShareBtn from './_components/ShareBtn' +import Tutorial from './_components/Tutorial' +import { Step1Tooltip } from './_components/Tutorial/Tooltips' +import { TutorialProvider } from './_components/Tutorial/TutorialContext' export async function generateMetadata({ params, diff --git a/src/app/(board)/board/create/components/BoardAvailabilityCheckModal.tsx b/src/app/(board)/board/create/_components/BoardAvailabilityCheckModal.tsx similarity index 100% rename from src/app/(board)/board/create/components/BoardAvailabilityCheckModal.tsx rename to src/app/(board)/board/create/_components/BoardAvailabilityCheckModal.tsx diff --git a/src/app/(board)/board/create/components/BoardNameForm.tsx b/src/app/(board)/board/create/_components/BoardNameForm.tsx similarity index 100% rename from src/app/(board)/board/create/components/BoardNameForm.tsx rename to src/app/(board)/board/create/_components/BoardNameForm.tsx diff --git a/src/app/(board)/board/create/components/BoardNameRecommendations.tsx b/src/app/(board)/board/create/_components/BoardNameRecommendations.tsx similarity index 100% rename from src/app/(board)/board/create/components/BoardNameRecommendations.tsx rename to src/app/(board)/board/create/_components/BoardNameRecommendations.tsx diff --git a/src/app/(board)/board/create/page.tsx b/src/app/(board)/board/create/page.tsx index e6e6518..4d8e862 100644 --- a/src/app/(board)/board/create/page.tsx +++ b/src/app/(board)/board/create/page.tsx @@ -1,8 +1,8 @@ import Image from 'next/image' import PolaboLogo from 'public/images/polabo_logo.png' -import BoardAvailabilityCheckModal from './components/BoardAvailabilityCheckModal' -import BoardNameForm from './components/BoardNameForm' -import BoardNameRecommendations from './components/BoardNameRecommendations' +import BoardAvailabilityCheckModal from './_components/BoardAvailabilityCheckModal' +import BoardNameForm from './_components/BoardNameForm' +import BoardNameRecommendations from './_components/BoardNameRecommendations' const CreateBoardPage = () => { return ( diff --git a/src/app/(home)/components/CopyLinkBtn.tsx b/src/app/(home)/_components/CopyLinkBtn.tsx similarity index 89% rename from src/app/(home)/components/CopyLinkBtn.tsx rename to src/app/(home)/_components/CopyLinkBtn.tsx index 1d72033..2a72ac4 100644 --- a/src/app/(home)/components/CopyLinkBtn.tsx +++ b/src/app/(home)/_components/CopyLinkBtn.tsx @@ -19,12 +19,12 @@ const CopyLinkBtn = () => { return ( <> -
+
copy link!
+
+ ) +} + +export default SubmitBtn diff --git a/src/app/mypage/profileEdit/page.tsx b/src/app/mypage/profileEdit/page.tsx index 8029897..3581b63 100644 --- a/src/app/mypage/profileEdit/page.tsx +++ b/src/app/mypage/profileEdit/page.tsx @@ -1,15 +1,14 @@ import Header from '@/components/Header' import Link from 'next/link' import Email from './_components/Email' -import NicknameForm from './_components/NicknameForm' +import ProfileForm from './_components/ProfileForm' import Title from './_components/Title' const Page = () => { return (
} /> - - + 연결된 계정 @@ -19,7 +18,7 @@ const Page = () => { > 탈퇴하기 - +
) } diff --git a/src/components/BirthDateInput/index.tsx b/src/components/BirthDateInput/index.tsx new file mode 100644 index 0000000..89495e4 --- /dev/null +++ b/src/components/BirthDateInput/index.tsx @@ -0,0 +1,94 @@ +'use client' + +import { + ChangeEvent, + Dispatch, + SetStateAction, + useEffect, + useState, +} from 'react' + +interface BirthDateInputProps { + birthDt: string // 'YYYY-MM-DD' + setBirthDt: Dispatch> +} + +const BirthDateInput = ({ birthDt, setBirthDt }: BirthDateInputProps) => { + const [year, setYear] = useState('') + const [month, setMonth] = useState('') + const [day, setDay] = useState('') + + useEffect(() => { + if (!birthDt) return + const [y, m, d] = birthDt.split('-') + setYear(y) + setMonth(m) + setDay(d) + }, [birthDt]) + + useEffect(() => { + setBirthDt(`${year}-${month}-${day}`) + }, [year, month, day]) + + const handleYearChange = (e: ChangeEvent) => { + const { value } = e.target + if (/^\d{0,4}$/.test(value)) { + setYear(value) + } + } + + const handleMonthChange = (e: ChangeEvent) => { + const { value } = e.target + if (/^\d{0,2}$/.test(value) && +value <= 12) { + setMonth(value) + } + } + + const handleDayChange = (e: ChangeEvent) => { + const { value } = e.target + if (/^\d{0,2}$/.test(value) && +value <= 31) { + setDay(value) + } + } + return ( +
+
+ +
+ / +
+ +
+ / +
+ +
+
+ ) +} + +export default BirthDateInput diff --git a/src/components/TextInput/NicknameInput.tsx b/src/components/TextInput/NicknameInput.tsx index a48fada..05fa0ec 100644 --- a/src/components/TextInput/NicknameInput.tsx +++ b/src/components/TextInput/NicknameInput.tsx @@ -1,12 +1,19 @@ 'use client' -import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from 'react' +import { + Dispatch, + InputHTMLAttributes, + ReactNode, + SetStateAction, + useEffect, + useState, +} from 'react' import { useSession } from 'next-auth/react' import TextInput from '.' const MAX_NICKNAME_LENGTH = 10 -interface NicknameInputProps { +interface NicknameInputProps extends InputHTMLAttributes { value: string setValue: Dispatch> setHasError: Dispatch> @@ -18,6 +25,7 @@ const NicknameInput = ({ setValue, setHasError, icon = '', + ...rest }: NicknameInputProps) => { const [errorMessage, setErrorMessage] = useState('') @@ -62,6 +70,7 @@ const NicknameInput = ({ hasError={errorMessage.length > 0} setValue={onInput} icon={icon} + {...rest} // eslint-disable-line react/jsx-props-no-spreading /> ) } diff --git a/src/components/TextInput/index.tsx b/src/components/TextInput/index.tsx index b744efe..eac4363 100644 --- a/src/components/TextInput/index.tsx +++ b/src/components/TextInput/index.tsx @@ -2,10 +2,10 @@ import ExitIcon from 'public/icons/exit.svg' import PinIcon from 'public/icons/pinFilled.svg' -import { ChangeEvent } from 'react' +import { ChangeEvent, InputHTMLAttributes } from 'react' import { twMerge } from 'tailwind-merge' -interface TextInputProps { +interface TextInputProps extends InputHTMLAttributes { value: string setValue: (value: string) => void hasError: boolean @@ -21,6 +21,7 @@ const TextInput = ({ description, errorMessage, icon = , + ...rest }: TextInputProps) => { const borderClass = twMerge( 'flex items-center mb-2 border-b', @@ -40,6 +41,7 @@ const TextInput = ({ setValue(e.target.value) } className="flex-1 bg-transparent p-1 outline-none" + {...rest} />
From ba4256f032ce4f3da70dd61e7da7794a85ca7693 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 00:28:34 +0900 Subject: [PATCH 04/15] #86 feat: select gender --- .../profileEdit/_components/GenderInput.tsx | 27 +++++++++++++++++++ .../profileEdit/_components/ProfileForm.tsx | 4 ++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/app/mypage/profileEdit/_components/GenderInput.tsx diff --git a/src/app/mypage/profileEdit/_components/GenderInput.tsx b/src/app/mypage/profileEdit/_components/GenderInput.tsx new file mode 100644 index 0000000..a082b0c --- /dev/null +++ b/src/app/mypage/profileEdit/_components/GenderInput.tsx @@ -0,0 +1,27 @@ +import Button from '@/components/Button' +import { SignInPayload } from '@/types' +import { useState } from 'react' + +const GenderInput = () => { + const [selectedOption, setSelectedOption] = + useState('NONE') + + return ( +
+ + +
+ ) +} + +export default GenderInput diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index e5bbbd2..7491187 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -6,6 +6,7 @@ import NicknameInput from '@/components/TextInput/NicknameInput' import BirthDateInput from '@/components/BirthDateInput' import Title from './Title' import SubmitBtn from './SubmitBtn' +import GenderInput from './GenderInput' const ProfileForm = ({ children }: { children: ReactNode }) => { const { data: session, update } = useSession() @@ -24,7 +25,7 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { ref={formRef} className="mt-9 flex flex-1 flex-col px-10" > -
+
닉네임 {
성별 + {children}
Date: Sun, 18 Aug 2024 01:16:28 +0900 Subject: [PATCH 05/15] #86 feat: updated next auth profile --- .../profileEdit/_components/GenderInput.tsx | 20 ++++++----- .../profileEdit/_components/NicknameForm.tsx | 8 +++-- .../profileEdit/_components/ProfileForm.tsx | 31 ++++++++++++----- src/auth.ts | 33 ++++++++++++------- src/components/BirthDateInput/index.tsx | 16 +++++---- src/components/HamburgerMenu/Menu.tsx | 4 ++- src/components/TextInput/NicknameInput.tsx | 2 +- src/lib/api/auth.ts | 2 +- src/types/auth.ts | 14 -------- src/types/next-auth.d.ts | 4 +++ src/types/user.ts | 17 ++++++++++ 11 files changed, 98 insertions(+), 53 deletions(-) delete mode 100644 src/types/auth.ts diff --git a/src/app/mypage/profileEdit/_components/GenderInput.tsx b/src/app/mypage/profileEdit/_components/GenderInput.tsx index a082b0c..fa384ef 100644 --- a/src/app/mypage/profileEdit/_components/GenderInput.tsx +++ b/src/app/mypage/profileEdit/_components/GenderInput.tsx @@ -1,22 +1,24 @@ import Button from '@/components/Button' -import { SignInPayload } from '@/types' -import { useState } from 'react' +import { UserProfile } from '@/types' +import { Dispatch, SetStateAction } from 'react' -const GenderInput = () => { - const [selectedOption, setSelectedOption] = - useState('NONE') +interface GenderInputProps { + gender: UserProfile['gender'] + setGender: Dispatch> +} +const GenderInput = ({ gender, setGender }: GenderInputProps) => { return (
diff --git a/src/app/mypage/profileEdit/_components/NicknameForm.tsx b/src/app/mypage/profileEdit/_components/NicknameForm.tsx index f1db913..0b0cf7a 100644 --- a/src/app/mypage/profileEdit/_components/NicknameForm.tsx +++ b/src/app/mypage/profileEdit/_components/NicknameForm.tsx @@ -9,7 +9,9 @@ import Title from './Title' const NicknameForm = ({ children }: { children: ReactNode }) => { const { data: session, update } = useSession() - const [newName, setNewName] = useState(session?.user?.name || '') + const [newName, setNewName] = useState( + session?.profile.nickName || '', + ) const [hasError, setHasError] = useState(false) const updateNickname = async () => { @@ -35,7 +37,9 @@ const NicknameForm = ({ children }: { children: ReactNode }) => { onClick={updateNickname} className="mb-10 mt-auto w-full" disabled={ - session?.user?.name === newName || newName.length === 0 || hasError + session?.profile.nickName === newName || + newName.length === 0 || + hasError } > 저장 diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index 7491187..2f80740 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -4,23 +4,36 @@ import { ReactNode, useRef, useState } from 'react' import { useSession } from 'next-auth/react' import NicknameInput from '@/components/TextInput/NicknameInput' import BirthDateInput from '@/components/BirthDateInput' +import { UserProfile } from '@/types' import Title from './Title' import SubmitBtn from './SubmitBtn' import GenderInput from './GenderInput' const ProfileForm = ({ children }: { children: ReactNode }) => { const { data: session, update } = useSession() - const [newName, setNewName] = useState(session?.user?.name || '') - const [newBirthDt, setNewBirthDt] = useState('') + const [newName, setNewName] = useState( + session?.profile.nickName ?? '', + ) + const [newBirthDt, setNewBirthDt] = useState( + session?.profile.birthDt, + ) + const [newGender, setNewGender] = useState( + session?.profile.gender ?? 'NONE', + ) const formRef = useRef(null) const [hasError, setHasError] = useState(false) return (
{ - update({ - name: newName, - }) + const newProfile = { + nickName: newName, + birthDt: newBirthDt, + gender: newGender, + } + if (session?.profile !== newProfile) { + update({ profile: newProfile }) + } }} ref={formRef} className="mt-9 flex flex-1 flex-col px-10" @@ -37,16 +50,18 @@ const ProfileForm = ({ children }: { children: ReactNode }) => {
생년월일 - +
성별 - + {children}
diff --git a/src/auth.ts b/src/auth.ts index ed384f1..663df7c 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -23,18 +23,28 @@ export const { handlers, signIn, signOut, auth, unstable_update } = NextAuth({ if (account && user) { try { // 신규 유저인지 확인, polabo 백에서 토큰 발급 - const { newUser, nickName, accessToken, refreshToken, expiredDate } = - await login({ - email: user.email!, - nickName: user.name!, - birthDt: '2024-08-11', // TODO: 기획 대기 - gender: 'F', // TODO: 기획 대기 - }) - user.name = nickName + const { + newUser, + nickName, + birthDt, + gender, + accessToken, + refreshToken, + expiredDate, + } = await login({ + email: user.email!, + nickName: user.name!, + }) + // user.name = nickName user.newUser = newUser user.accessToken = accessToken user.refreshToken = refreshToken user.expiredDate = expiredDate + user.profile = { + nickName, + birthDt, + gender, + } } catch (e) { console.log('error', e) return false @@ -44,9 +54,8 @@ export const { handlers, signIn, signOut, auth, unstable_update } = NextAuth({ return true }, async jwt({ token, user, account, trigger, session }) { - if (trigger === 'update' && session?.name) { - const { name } = session - token.name = name + if (trigger === 'update' && session?.profile) { + token.profile = session.profile } if (trigger === 'update' && session?.accessToken) { token.accessToken = session.accessToken @@ -62,6 +71,7 @@ export const { handlers, signIn, signOut, auth, unstable_update } = NextAuth({ accessToken: user.accessToken, refreshToken: user.refreshToken, expiredDate: user.expiredDate, + profile: user.profile, user, } } @@ -80,6 +90,7 @@ export const { handlers, signIn, signOut, auth, unstable_update } = NextAuth({ session.refreshToken = token.refreshToken session.expiredDate = token.expiredDate session.newUser = token.newUser + session.profile = token.profile } return session }, diff --git a/src/components/BirthDateInput/index.tsx b/src/components/BirthDateInput/index.tsx index 89495e4..b9b07c0 100644 --- a/src/components/BirthDateInput/index.tsx +++ b/src/components/BirthDateInput/index.tsx @@ -1,5 +1,7 @@ 'use client' +import { UserProfile } from '@/types' +import { useSession } from 'next-auth/react' import { ChangeEvent, Dispatch, @@ -9,22 +11,24 @@ import { } from 'react' interface BirthDateInputProps { - birthDt: string // 'YYYY-MM-DD' - setBirthDt: Dispatch> + setBirthDt: Dispatch> } -const BirthDateInput = ({ birthDt, setBirthDt }: BirthDateInputProps) => { +const BirthDateInput = ({ setBirthDt }: BirthDateInputProps) => { const [year, setYear] = useState('') const [month, setMonth] = useState('') const [day, setDay] = useState('') + const { data: session } = useSession() + useEffect(() => { - if (!birthDt) return - const [y, m, d] = birthDt.split('-') + if (!session || !session.profile.birthDt) return + + const [y, m, d] = session.profile.birthDt.split('-') setYear(y) setMonth(m) setDay(d) - }, [birthDt]) + }, [session]) useEffect(() => { setBirthDt(`${year}-${month}-${day}`) diff --git a/src/components/HamburgerMenu/Menu.tsx b/src/components/HamburgerMenu/Menu.tsx index 218da24..e7f817c 100644 --- a/src/components/HamburgerMenu/Menu.tsx +++ b/src/components/HamburgerMenu/Menu.tsx @@ -20,7 +20,9 @@ const Profile = ({ > - {status === 'authenticated' ? session?.user?.name : '로그인해주세요.'} + {status === 'authenticated' + ? session.profile.nickName + : '로그인해주세요.'}
) diff --git a/src/components/TextInput/NicknameInput.tsx b/src/components/TextInput/NicknameInput.tsx index 05fa0ec..0a002e5 100644 --- a/src/components/TextInput/NicknameInput.tsx +++ b/src/components/TextInput/NicknameInput.tsx @@ -33,7 +33,7 @@ const NicknameInput = ({ useEffect(() => { if (session) { - setValue(session.user!.name!) + setValue(session.profile.nickName) } }, [session]) diff --git a/src/lib/api/auth.ts b/src/lib/api/auth.ts index c3de855..cd6c51e 100644 --- a/src/lib/api/auth.ts +++ b/src/lib/api/auth.ts @@ -31,7 +31,7 @@ export const login = async (body: SignInPayload): Promise => { }) const data = await handleResponse(res) - return data.data + return { ...data.data, birthDt: '2002-01-17', gender: 'F' } } export const refreshAT = async (refreshToken: string) => { diff --git a/src/types/auth.ts b/src/types/auth.ts deleted file mode 100644 index 6e8d8cf..0000000 --- a/src/types/auth.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface SignInPayload { - email: string - nickName: string - birthDt: string // '2024-08-11' - gender: 'F' | 'M' | 'NONE' -} - -export interface User { - newUser: boolean - nickName: string - accessToken: string - expiredDate: string - refreshToken: string -} diff --git a/src/types/next-auth.d.ts b/src/types/next-auth.d.ts index ce93c36..9de6919 100644 --- a/src/types/next-auth.d.ts +++ b/src/types/next-auth.d.ts @@ -1,5 +1,6 @@ import { DefaultSession } from 'next-auth' import 'next-auth/jwt' +import { UserProfile } from '.' declare module 'next-auth/jwt' { interface JWT { @@ -7,6 +8,7 @@ declare module 'next-auth/jwt' { accessToken: string refreshToken: string expiredDate: string + profile: UserProfile } } @@ -16,11 +18,13 @@ declare module 'next-auth' { accessToken: string refreshToken: string expiredDate: string + profile: UserProfile } interface User { newUser: boolean accessToken: string refreshToken: string expiredDate: string + profile: UserProfile } } diff --git a/src/types/user.ts b/src/types/user.ts index 4fec770..44e9965 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -2,3 +2,20 @@ export type WithdrawUserPayload = { type: string reason: string } + +export interface SignInPayload { + email: string + nickName: string +} + +export interface User { + newUser: boolean + nickName: string + birthDt: `${string}-${string}-${string}` | undefined // '2024-08-11' + gender: 'F' | 'M' | 'NONE' + accessToken: string + expiredDate: string + refreshToken: string +} + +export type UserProfile = Pick From ad5b874522c69b2b1483eb0bbea772c88c111f72 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 01:25:37 +0900 Subject: [PATCH 06/15] =?UTF-8?q?#86=20feat:=20update=20profile=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profileEdit/_components/NicknameForm.tsx | 51 ------------------- .../profileEdit/_components/ProfileForm.tsx | 6 ++- src/lib/api/user.ts | 8 +-- 3 files changed, 9 insertions(+), 56 deletions(-) delete mode 100644 src/app/mypage/profileEdit/_components/NicknameForm.tsx diff --git a/src/app/mypage/profileEdit/_components/NicknameForm.tsx b/src/app/mypage/profileEdit/_components/NicknameForm.tsx deleted file mode 100644 index 0b0cf7a..0000000 --- a/src/app/mypage/profileEdit/_components/NicknameForm.tsx +++ /dev/null @@ -1,51 +0,0 @@ -'use client' - -import Button from '@/components/Button' -import { useSession } from 'next-auth/react' -import { ReactNode, useState } from 'react' -import NicknameInput from '@/components/TextInput/NicknameInput' -import { changeNickname } from '@/lib' -import Title from './Title' - -const NicknameForm = ({ children }: { children: ReactNode }) => { - const { data: session, update } = useSession() - const [newName, setNewName] = useState( - session?.profile.nickName || '', - ) - const [hasError, setHasError] = useState(false) - - const updateNickname = async () => { - update({ - name: newName, - }) - await changeNickname(newName) - } - - return ( -
-
- 닉네임 - - {children} -
- -
- ) -} - -export default NicknameForm diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index 2f80740..1660098 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -5,6 +5,7 @@ import { useSession } from 'next-auth/react' import NicknameInput from '@/components/TextInput/NicknameInput' import BirthDateInput from '@/components/BirthDateInput' import { UserProfile } from '@/types' +import { updateProfile } from '@/lib' import Title from './Title' import SubmitBtn from './SubmitBtn' import GenderInput from './GenderInput' @@ -34,6 +35,7 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { if (session?.profile !== newProfile) { update({ profile: newProfile }) } + await updateProfile(newProfile) }} ref={formRef} className="mt-9 flex flex-1 flex-col px-10" @@ -59,7 +61,9 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { { @@ -7,9 +7,9 @@ export const withdraw = async (body: WithdrawUserPayload) => { }) } -export const changeNickname = async (nickName: string) => { - return put(`/api/v1/user/nickname`, { - body: JSON.stringify({ nickName }), +export const updateProfile = async (body: UserProfile) => { + return put('/api/v1/user/profile', { + body: JSON.stringify(body), }) } From 716a5194790139bbacd906ea7f98c10a0b270a44 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 02:23:51 +0900 Subject: [PATCH 07/15] #86 feat: onboarding step 1 --- .../signup/_components/Header.tsx | 19 +++++++++ .../signup/_components/Indicator.tsx | 26 ++++++++++++ .../signup/_components/NicknameForm.tsx | 38 +++++++++--------- .../signup/_components/ProfileForm.tsx | 17 ++++++++ .../signup/_components/StepContext.tsx | 40 +++++++++++++++++++ src/app/(onboarding)/signup/page.tsx | 23 ++++++----- 6 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 src/app/(onboarding)/signup/_components/Header.tsx create mode 100644 src/app/(onboarding)/signup/_components/Indicator.tsx create mode 100644 src/app/(onboarding)/signup/_components/ProfileForm.tsx create mode 100644 src/app/(onboarding)/signup/_components/StepContext.tsx diff --git a/src/app/(onboarding)/signup/_components/Header.tsx b/src/app/(onboarding)/signup/_components/Header.tsx new file mode 100644 index 0000000..3d8bbc8 --- /dev/null +++ b/src/app/(onboarding)/signup/_components/Header.tsx @@ -0,0 +1,19 @@ +'use client' + +import BackIcon from 'public/icons/arrow_back_ios.svg' +import { useStep } from './StepContext' + +const Header = () => { + const { step, prevStep } = useStep() + return ( +
+ {step !== 1 && ( +
+ prevStep()} /> +
+ )} +
+ ) +} + +export default Header diff --git a/src/app/(onboarding)/signup/_components/Indicator.tsx b/src/app/(onboarding)/signup/_components/Indicator.tsx new file mode 100644 index 0000000..8b3017c --- /dev/null +++ b/src/app/(onboarding)/signup/_components/Indicator.tsx @@ -0,0 +1,26 @@ +import { useStep } from './StepContext' + +const Circle = ({ step, active }: { step: number; active: boolean }) => ( +
+ {active ? step : ''} +
+) + +const Indicator = () => { + const { step } = useStep() + return ( +
+ + + +
+ ) +} + +export default Indicator diff --git a/src/app/(onboarding)/signup/_components/NicknameForm.tsx b/src/app/(onboarding)/signup/_components/NicknameForm.tsx index 43ea7e8..bc8d53c 100644 --- a/src/app/(onboarding)/signup/_components/NicknameForm.tsx +++ b/src/app/(onboarding)/signup/_components/NicknameForm.tsx @@ -2,33 +2,35 @@ import Button from '@/components/Button' import NicknameInput from '@/components/TextInput/NicknameInput' -import { changeNickname } from '@/lib' -import { useSession } from 'next-auth/react' -import { useRouter } from 'next/navigation' +// import { useSession } from 'next-auth/react' +// import { useRouter } from 'next/navigation' import SketchIcon from 'public/icons/sketchIcons-1.svg' import { useState } from 'react' +import { useStep } from './StepContext' const NicknameForm = () => { const [nickname, setNickname] = useState('') const [hasError, setHasError] = useState(false) const isEmpty = nickname.length === 0 - const { update } = useSession() - const router = useRouter() + // const { update } = useSession() + // const router = useRouter() + const { nextStep } = useStep() const createNickname = async () => { - update({ - name: nickname, - }) - await changeNickname(nickname) - router.push('/signup/complete') + // update({ + // name: nickname, + // }) + // await changeNickname(nickname) + nextStep() + // router.push('/signup/complete') } return ( - <> -
-
- 닉네임을 정해주세요! -
+
+
+ 닉네임을 정해주세요! +
+
{
- +
) } diff --git a/src/app/(onboarding)/signup/_components/ProfileForm.tsx b/src/app/(onboarding)/signup/_components/ProfileForm.tsx new file mode 100644 index 0000000..000a759 --- /dev/null +++ b/src/app/(onboarding)/signup/_components/ProfileForm.tsx @@ -0,0 +1,17 @@ +'use client' + +import Indicator from './Indicator' +import NicknameForm from './NicknameForm' +import { useStep } from './StepContext' + +const ProfileForm = () => { + const { step } = useStep() + return ( +
+ + {step === 1 && } +
+ ) +} + +export default ProfileForm diff --git a/src/app/(onboarding)/signup/_components/StepContext.tsx b/src/app/(onboarding)/signup/_components/StepContext.tsx new file mode 100644 index 0000000..b4ce3c6 --- /dev/null +++ b/src/app/(onboarding)/signup/_components/StepContext.tsx @@ -0,0 +1,40 @@ +'use client' + +import { ReactNode, createContext, useContext, useMemo, useState } from 'react' + +interface StepContextProps { + step: 1 | 2 | 3 + nextStep: () => void + prevStep: () => void +} + +const StepContext = createContext(undefined) + +export const StepProvider = ({ children }: { children: ReactNode }) => { + const [step, setStep] = useState<1 | 2 | 3>(1) + + const nextStep = () => + setStep((prev) => (prev !== 3 ? ((prev + 1) as 1 | 2 | 3) : prev)) + + const prevStep = () => + setStep((prev) => (prev !== 1 ? ((prev - 1) as 1 | 2 | 3) : prev)) + + const value = useMemo( + () => ({ + step, + nextStep, + prevStep, + }), + [step], + ) + + return {children} +} + +export const useStep = () => { + const context = useContext(StepContext) + if (context === undefined) { + throw new Error('Error at useStep') + } + return context +} diff --git a/src/app/(onboarding)/signup/page.tsx b/src/app/(onboarding)/signup/page.tsx index 8da2818..97fd12a 100644 --- a/src/app/(onboarding)/signup/page.tsx +++ b/src/app/(onboarding)/signup/page.tsx @@ -1,16 +1,21 @@ -import { auth } from '@/auth' -import { redirect } from 'next/navigation' -import NicknameForm from './_components/NicknameForm' +// import { auth } from '@/auth' +// import { redirect } from 'next/navigation' +import ProfileForm from './_components/ProfileForm' +import { StepProvider } from './_components/StepContext' +import Header from './_components/Header' const SignUpPage = async () => { - const session = await auth() + // const session = await auth() - if (session && !session.newUser) { - redirect('/board/create') - } + // if (session && !session.newUser) { + // redirect('/board/create') + // } return ( -
- +
+ +
+ +
) } From 22ce36c437b394c33de04330687578ab13f781dd Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 03:00:18 +0900 Subject: [PATCH 08/15] =?UTF-8?q?#86=20feat:=20onboarding=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EC=A0=95=EB=B3=B4=20submit=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/_components/Header.tsx | 2 +- .../signup/_components/Indicator.tsx | 2 +- .../signup/_components/ProfileForm.tsx | 23 ++++++- .../_components/contexts/ProfileContext.tsx | 60 +++++++++++++++++++ .../{ => contexts}/StepContext.tsx | 0 .../signup/_components/steps/BirthDtForm.tsx | 30 ++++++++++ .../signup/_components/steps/GenderForm.tsx | 39 ++++++++++++ .../_components/{ => steps}/NicknameForm.tsx | 5 +- src/app/(onboarding)/signup/page.tsx | 2 +- 9 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx rename src/app/(onboarding)/signup/_components/{ => contexts}/StepContext.tsx (100%) create mode 100644 src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx create mode 100644 src/app/(onboarding)/signup/_components/steps/GenderForm.tsx rename src/app/(onboarding)/signup/_components/{ => steps}/NicknameForm.tsx (88%) diff --git a/src/app/(onboarding)/signup/_components/Header.tsx b/src/app/(onboarding)/signup/_components/Header.tsx index 3d8bbc8..5a76234 100644 --- a/src/app/(onboarding)/signup/_components/Header.tsx +++ b/src/app/(onboarding)/signup/_components/Header.tsx @@ -1,7 +1,7 @@ 'use client' import BackIcon from 'public/icons/arrow_back_ios.svg' -import { useStep } from './StepContext' +import { useStep } from './contexts/StepContext' const Header = () => { const { step, prevStep } = useStep() diff --git a/src/app/(onboarding)/signup/_components/Indicator.tsx b/src/app/(onboarding)/signup/_components/Indicator.tsx index 8b3017c..f31b7d4 100644 --- a/src/app/(onboarding)/signup/_components/Indicator.tsx +++ b/src/app/(onboarding)/signup/_components/Indicator.tsx @@ -1,4 +1,4 @@ -import { useStep } from './StepContext' +import { useStep } from './contexts/StepContext' const Circle = ({ step, active }: { step: number; active: boolean }) => (
{ const { step } = useStep() + const { update } = useSession() + + const handleSubmit = async (newProfile: UserProfile) => { + update({ profile: newProfile }) + await updateProfile(newProfile) + } + return (
- {step === 1 && } + + {step === 1 && } + {step === 2 && } + {step === 3 && } +
) } diff --git a/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx new file mode 100644 index 0000000..a427d3e --- /dev/null +++ b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx @@ -0,0 +1,60 @@ +'use client' + +import { UserProfile } from '@/types' +import { useSession } from 'next-auth/react' +import { + Dispatch, + SetStateAction, + createContext, + useContext, + useMemo, + useState, +} from 'react' + +interface ProfileContextProps { + newName: UserProfile['nickName'] + newBirthDt: UserProfile['birthDt'] + newGender: UserProfile['gender'] + setNewName: Dispatch> + setBirthDt: Dispatch> + setGender: Dispatch> +} + +const ProfileContext = createContext(undefined) + +export const ProfileProvider = ({ + children, +}: { + children: React.ReactNode +}) => { + const { data: session } = useSession() + const [newName, setNewName] = useState( + session?.profile.nickName ?? '', + ) + const [newBirthDt, setBirthDt] = useState(undefined) + const [newGender, setGender] = useState('NONE') + + const value = useMemo( + () => ({ + newName, + newBirthDt, + newGender, + setNewName, + setBirthDt, + setGender, + }), + [newName, newBirthDt, newGender], + ) + + return ( + {children} + ) +} + +export const useProfile = () => { + const context = useContext(ProfileContext) + if (context === undefined) { + throw new Error('Error at useProfile') + } + return context +} diff --git a/src/app/(onboarding)/signup/_components/StepContext.tsx b/src/app/(onboarding)/signup/_components/contexts/StepContext.tsx similarity index 100% rename from src/app/(onboarding)/signup/_components/StepContext.tsx rename to src/app/(onboarding)/signup/_components/contexts/StepContext.tsx diff --git a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx new file mode 100644 index 0000000..f3d2f82 --- /dev/null +++ b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx @@ -0,0 +1,30 @@ +import Button from '@/components/Button' +import { useProfile } from '../contexts/ProfileContext' +import { useStep } from '../contexts/StepContext' + +const BirthDtForm = () => { + const { newName } = useProfile() + const { nextStep } = useStep() + return ( +
+
+ {newName} + {'님의 \n 생일을 입력해주세요!'} +
+

+ 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :) +

+ + +
+ ) +} + +export default BirthDtForm diff --git a/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx new file mode 100644 index 0000000..b93e173 --- /dev/null +++ b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx @@ -0,0 +1,39 @@ +import Button from '@/components/Button' +import { UserProfile } from '@/types' +import { useProfile } from '../contexts/ProfileContext' + +const GenderForm = ({ + handleSubmit, +}: { + handleSubmit: (profile: UserProfile) => void +}) => { + const { newName, newBirthDt, newGender } = useProfile() + return ( +
+
+ 성별 + {'을 \n 입력해주세요!'} +
+

+ 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :) +

+ + +
+ ) +} + +export default GenderForm diff --git a/src/app/(onboarding)/signup/_components/NicknameForm.tsx b/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx similarity index 88% rename from src/app/(onboarding)/signup/_components/NicknameForm.tsx rename to src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx index bc8d53c..77f4072 100644 --- a/src/app/(onboarding)/signup/_components/NicknameForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx @@ -6,9 +6,11 @@ import NicknameInput from '@/components/TextInput/NicknameInput' // import { useRouter } from 'next/navigation' import SketchIcon from 'public/icons/sketchIcons-1.svg' import { useState } from 'react' -import { useStep } from './StepContext' +import { useProfile } from '../contexts/ProfileContext' +import { useStep } from '../contexts/StepContext' const NicknameForm = () => { + const { setNewName } = useProfile() const [nickname, setNickname] = useState('') const [hasError, setHasError] = useState(false) const isEmpty = nickname.length === 0 @@ -21,6 +23,7 @@ const NicknameForm = () => { // name: nickname, // }) // await changeNickname(nickname) + setNewName(nickname) nextStep() // router.push('/signup/complete') } diff --git a/src/app/(onboarding)/signup/page.tsx b/src/app/(onboarding)/signup/page.tsx index 97fd12a..0bc9b46 100644 --- a/src/app/(onboarding)/signup/page.tsx +++ b/src/app/(onboarding)/signup/page.tsx @@ -1,7 +1,7 @@ // import { auth } from '@/auth' // import { redirect } from 'next/navigation' import ProfileForm from './_components/ProfileForm' -import { StepProvider } from './_components/StepContext' +import { StepProvider } from './_components/contexts/StepContext' import Header from './_components/Header' const SignUpPage = async () => { From bd776a8b342e2228e7fb63dd5d53ff4a44619c97 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 15:38:22 +0900 Subject: [PATCH 09/15] =?UTF-8?q?#86=20feat:=20update=20profile=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/_components/ProfileForm.tsx | 13 +++++-- .../signup/_components/steps/BirthDtForm.tsx | 9 ++++- .../signup/_components/steps/GenderForm.tsx | 9 ++++- .../profileEdit/_components/ProfileForm.tsx | 39 +++++++++++++------ src/components/BirthDateInput/index.tsx | 14 ++++++- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/app/(onboarding)/signup/_components/ProfileForm.tsx b/src/app/(onboarding)/signup/_components/ProfileForm.tsx index b8f2ea5..9f79240 100644 --- a/src/app/(onboarding)/signup/_components/ProfileForm.tsx +++ b/src/app/(onboarding)/signup/_components/ProfileForm.tsx @@ -3,6 +3,7 @@ import { updateProfile } from '@/lib' import { UserProfile } from '@/types' import { useSession } from 'next-auth/react' +import { useRouter } from 'next/navigation' import Indicator from './Indicator' import { ProfileProvider } from './contexts/ProfileContext' import { useStep } from './contexts/StepContext' @@ -12,11 +13,17 @@ import NicknameForm from './steps/NicknameForm' const ProfileForm = () => { const { step } = useStep() - const { update } = useSession() + const { data: session, update } = useSession() + const router = useRouter() const handleSubmit = async (newProfile: UserProfile) => { - update({ profile: newProfile }) - await updateProfile(newProfile) + if (session?.profile !== newProfile) { + const serverRes = await updateProfile(newProfile) + if (serverRes.code === 'SUCCESS') { + update({ profile: newProfile }) + router.push('/signup/complete') + } + } } return ( diff --git a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx index f3d2f82..7ac8de9 100644 --- a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx @@ -1,4 +1,5 @@ import Button from '@/components/Button' +import Link from 'next/link' import { useProfile } from '../contexts/ProfileContext' import { useStep } from '../contexts/StepContext' @@ -17,12 +18,18 @@ const BirthDtForm = () => { + + 다음에 할게요 +
) } diff --git a/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx index b93e173..1da279f 100644 --- a/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx @@ -1,5 +1,6 @@ import Button from '@/components/Button' import { UserProfile } from '@/types' +import Link from 'next/link' import { useProfile } from '../contexts/ProfileContext' const GenderForm = ({ @@ -20,7 +21,7 @@ const GenderForm = ({ + + 다음에 할게요 +
) } diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index 1660098..eeff186 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -1,6 +1,6 @@ 'use client' -import { ReactNode, useRef, useState } from 'react' +import { ReactNode, useEffect, useRef, useState } from 'react' import { useSession } from 'next-auth/react' import NicknameInput from '@/components/TextInput/NicknameInput' import BirthDateInput from '@/components/BirthDateInput' @@ -22,7 +22,22 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { session?.profile.gender ?? 'NONE', ) const formRef = useRef(null) - const [hasError, setHasError] = useState(false) + const [nameError, setNameError] = useState(false) + const [birthError, setBirthError] = useState(false) + const [unChanged, setUnChanged] = useState(true) + + useEffect(() => { + console.log('birthDt:', newBirthDt) + if ( + session?.profile.nickName === newName && + session?.profile.birthDt === newBirthDt && + session?.profile.gender === newGender + ) { + setUnChanged(true) + } else { + setUnChanged(false) + } + }, [newName, newBirthDt, newGender]) return (
{ gender: newGender, } if (session?.profile !== newProfile) { - update({ profile: newProfile }) + const serverRes = await updateProfile(newProfile) + + if (serverRes.code === 'SUCCESS') { + update({ profile: newProfile }) + } } - await updateProfile(newProfile) }} ref={formRef} className="mt-9 flex flex-1 flex-col px-10" @@ -46,13 +64,16 @@ const ProfileForm = ({ children }: { children: ReactNode }) => {
생년월일 - +
성별 @@ -61,11 +82,7 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { diff --git a/src/components/BirthDateInput/index.tsx b/src/components/BirthDateInput/index.tsx index b9b07c0..c882daa 100644 --- a/src/components/BirthDateInput/index.tsx +++ b/src/components/BirthDateInput/index.tsx @@ -12,9 +12,10 @@ import { interface BirthDateInputProps { setBirthDt: Dispatch> + setHasError: Dispatch> } -const BirthDateInput = ({ setBirthDt }: BirthDateInputProps) => { +const BirthDateInput = ({ setBirthDt, setHasError }: BirthDateInputProps) => { const [year, setYear] = useState('') const [month, setMonth] = useState('') const [day, setDay] = useState('') @@ -31,7 +32,16 @@ const BirthDateInput = ({ setBirthDt }: BirthDateInputProps) => { }, [session]) useEffect(() => { - setBirthDt(`${year}-${month}-${day}`) + if (!year && !month && !day) { + setHasError(false) + setBirthDt(undefined) + } else if (year.length === 4 && month.length === 2 && day.length === 2) { + setBirthDt(`${year}-${month}-${day}`) + setHasError(false) + } else { + setBirthDt(undefined) + setHasError(true) + } }, [year, month, day]) const handleYearChange = (e: ChangeEvent) => { From 76f1fd59dc3c43bb64780e8d3e2146dc28a129bc Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 18:23:54 +0900 Subject: [PATCH 10/15] #86 feat: signup step 3 - gender --- public/icons/gender_f.png | Bin 0 -> 10122 bytes public/icons/gender_f.svg | 5 +++ public/icons/gender_m.png | Bin 0 -> 10159 bytes public/icons/gender_m.svg | 5 +++ .../_components/contexts/ProfileContext.tsx | 5 +++ .../signup/_components/steps/BirthDtForm.tsx | 16 ++++++++-- .../signup/_components/steps/GenderBtn.tsx | 30 ++++++++++++++++++ .../signup/_components/steps/GenderForm.tsx | 19 +++++++++-- .../profileEdit/_components/ProfileForm.tsx | 1 + src/components/BirthDateInput/index.tsx | 17 ++++++++-- tailwind.config.ts | 1 + 11 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 public/icons/gender_f.png create mode 100644 public/icons/gender_f.svg create mode 100644 public/icons/gender_m.png create mode 100644 public/icons/gender_m.svg create mode 100644 src/app/(onboarding)/signup/_components/steps/GenderBtn.tsx diff --git a/public/icons/gender_f.png b/public/icons/gender_f.png new file mode 100644 index 0000000000000000000000000000000000000000..e1dfb08cf34c0e11801c62ef1af2430132fd0e12 GIT binary patch literal 10122 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 literal 0 HcmV?d00001 diff --git a/public/icons/gender_f.svg b/public/icons/gender_f.svg new file mode 100644 index 0000000..acf6736 --- /dev/null +++ b/public/icons/gender_f.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/icons/gender_m.png b/public/icons/gender_m.png new file mode 100644 index 0000000000000000000000000000000000000000..9a906e778636c85c3322e3ae00826de9c2b615f0 GIT binary patch literal 10159 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 literal 0 HcmV?d00001 diff --git a/public/icons/gender_m.svg b/public/icons/gender_m.svg new file mode 100644 index 0000000..0155767 --- /dev/null +++ b/public/icons/gender_m.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx index a427d3e..2400c24 100644 --- a/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx +++ b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx @@ -7,6 +7,7 @@ import { SetStateAction, createContext, useContext, + useEffect, useMemo, useState, } from 'react' @@ -34,6 +35,10 @@ export const ProfileProvider = ({ const [newBirthDt, setBirthDt] = useState(undefined) const [newGender, setGender] = useState('NONE') + useEffect(() => { + console.log(newName, newBirthDt, newGender) + }, [newName, newBirthDt, newGender]) + const value = useMemo( () => ({ newName, diff --git a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx index 7ac8de9..8d9e79a 100644 --- a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx @@ -1,11 +1,16 @@ +import BirthDateInput from '@/components/BirthDateInput' import Button from '@/components/Button' import Link from 'next/link' +import { useState } from 'react' import { useProfile } from '../contexts/ProfileContext' import { useStep } from '../contexts/StepContext' const BirthDtForm = () => { - const { newName } = useProfile() + const { newName, newBirthDt, setBirthDt } = useProfile() const { nextStep } = useStep() + + const [hasError, setHasError] = useState(false) + return (
@@ -16,10 +21,17 @@ const BirthDtForm = () => { 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :)

+
+ +
+ ) +} + +export default GenderBtn diff --git a/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx index 1da279f..4fe339e 100644 --- a/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/GenderForm.tsx @@ -1,14 +1,24 @@ import Button from '@/components/Button' import { UserProfile } from '@/types' import Link from 'next/link' +import { useEffect, useState } from 'react' import { useProfile } from '../contexts/ProfileContext' +import GenderBtn from './GenderBtn' const GenderForm = ({ handleSubmit, }: { handleSubmit: (profile: UserProfile) => void }) => { - const { newName, newBirthDt, newGender } = useProfile() + const { newName, newBirthDt, newGender, setGender } = useProfile() + const [hasError, setHasError] = useState(false) + + useEffect(() => { + if (newGender === 'NONE') { + setHasError(true) + } else setHasError(false) + }, [newGender]) + return (
@@ -19,10 +29,15 @@ const GenderForm = ({ 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :)

+
+ setGender('M')} /> + setGender('F')} /> +
+
성별 diff --git a/src/components/BirthDateInput/index.tsx b/src/components/BirthDateInput/index.tsx index c882daa..d3b0709 100644 --- a/src/components/BirthDateInput/index.tsx +++ b/src/components/BirthDateInput/index.tsx @@ -9,13 +9,19 @@ import { useEffect, useState, } from 'react' +import { twMerge } from 'tailwind-merge' interface BirthDateInputProps { setBirthDt: Dispatch> setHasError: Dispatch> + className?: React.ComponentProps<'div'>['className'] } -const BirthDateInput = ({ setBirthDt, setHasError }: BirthDateInputProps) => { +const BirthDateInput = ({ + setBirthDt, + setHasError, + className = '', +}: BirthDateInputProps) => { const [year, setYear] = useState('') const [month, setMonth] = useState('') const [day, setDay] = useState('') @@ -65,14 +71,19 @@ const BirthDateInput = ({ setBirthDt, setHasError }: BirthDateInputProps) => { } } return ( -
+
diff --git a/tailwind.config.ts b/tailwind.config.ts index 5ae6e4d..cbf0f7c 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -114,6 +114,7 @@ const config: Config = { boxShadow: { header: '0px 1px 2px 0px rgba(0, 0, 0, 0.10)', button: '0px 4px 8px 0px rgba(0, 0, 0, 0.15)', + signupGenderBtn: '2px 4px 0px 0px rgba(0, 0, 0, 0.30)', }, }, }, From 7983f63f469c7edebfbcdf77c89b7b640abdbff3 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 18:29:41 +0900 Subject: [PATCH 11/15] #86 style: removed arrow on input type number --- public/icons/gender_f.png | Bin 10122 -> 0 bytes public/icons/gender_m.png | Bin 10159 -> 0 bytes src/styles/globals.css | 5 +++++ 3 files changed, 5 insertions(+) delete mode 100644 public/icons/gender_f.png delete mode 100644 public/icons/gender_m.png diff --git a/public/icons/gender_f.png b/public/icons/gender_f.png deleted file mode 100644 index e1dfb08cf34c0e11801c62ef1af2430132fd0e12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10122 zcmb_?Ra9Hu6K{)4fuOydzvp$K)VERu@wGcxS?*QU1myvugYrREL-y6H+Bocg7O1aYvCyb0$m)E4 zeUc>;Pc(QlNbwYasb{X!R8G059;SlJ$W)bRu8KnTgQ!dtHBtVpt|p_dn~tg)6PWD} zYksoK^g9J_((sxm+LHM^mlp55PHNq|doa8oy6~9Hmcolk{4S+rA0wxd zzqt{g9%1c#dgNb30a%>9yugeLJ#UJcA!n}%W6hsw5sl4Aj~8tt0P9kJ8#ECh%u;F( zdmqFlOIPN0;W{(cCn($-#M*2^*&KuQkxj>(m^GisQe2<17!*i9R|gscxh@D6R)k@3 zLixd!86}LckIj)=UUW^yN*8%ZgseDN3ZC61C5#nt!8**6E)v%K-%J7(8SJP@n{Yva zT8(IaMO54D1-+wwx3#;$Eb5?+pQeTAq{T{9lu9R`pUVIb$AOC9Lk;W)Z(wtm5 zIy%lOXV+IZj}=Xq2-_5*>S1APHD;qp``x+vO8Q>gu~T>M)?(vQi3<{w$H688R*{l6 zTOb(DvlXlyY&A`xiUqBnNAo(M<>lqce60z<24L~Cq_A=vbyk3Lz9lkfEE3z?PO6!3;J+=J@wJXG#b#G4)d4r< z2i>=l4|fZ{o`wAX-Tr!!k_z~Dp?q~UDf5oz{yCf`AT3~BaLzsyKGy2KS9D{n!QAiW z1pE6;i>e2UA_L}RGI4poiF913(!hyg4hglxrIxgNJ`a}xp^kt0TI}X!SS%Q{`%meWe`i#;Axkf|WNl|E#D1BoPxU=g3;$o~?_- z(Z~qD%a-Kxl(iF@RW33&IsPJe)X|jzGaALfrt5fqINGgjUKM zv)2v6N0nV(ACSLM6rqulC~!i$*#VWBInt|-*VSx*y4Cj2nqRlL!FH?;iWK5;Q z-k~5wcUCqNEnC#hvZhg&0$vgZx2*juZL7kF7q#U<10Gnzr~m+y+&O^lUh!#!q`_F_ zWQSPJj*c9{85(0CYr|XYgU~K4H$FRvj}n?zR0f-uA%^{*#rhAr1~_14yOlSp6b!9t z^`mKxU253b$*xZ9a&v92bec(NBp6YzEefg1uqrJDN1M1u^~?*?Yi-!)jTOqh*ZoDx z<{wti0zRyLIg|24C4^2@nf;Qc>Wj^l6YMqdYX%tUVV~6z8JM{7eE_)ii-ruw(TJS= zyoxOfrjliB_qno7?wH(sw?=_KUMC<^M`&(*o$ZQYHPBeIv>y24uYoQQ)PR2x z@)nX4_XU52;)rr$$W;wjnzQzJxYh)K5xBMcO8?ZS`5x*EyjeWK%YN zoIQ|bo~dBI=X|OpMWl8*npH^!NL_@L+{80A66Qe>6j z$z3D9X-REi_b2W3mcWMz&|p*YbI|PPy$PzbF90Au&(x=nmf}Q)#Yp80RipyQ48i+N z4g#y;XqsCKW`R^ro?SPt&;NYZjhTxW5SwmC?!Q*##G)eKF!UkT52hXh5;+~$1WuENYe!N4%e&z|hkJ9uudM!G*0(!Zh z42(RpkZb_Nx%3Mztes)!A2+GKt;5jsd?4JU|8zgl0$4!kc!}*mWOtq>v-{&%98Be# zHPlrtNXwln(#Ivb#T5%bHG`~NHToW(u5LcHjS=4<cdaY>Mt z|FFi&nS05}#9TLHwvUt?eh!+aqHh`(^2fN(KyLY}68?F--|vg_vR7s>(UKQFH9HQ> z$mZFf47qXf&VkhmEXx!5nPdi(JW1o=(X+I>*;H zzzK*XVQch5C@7@}%~L;_iY6m>+S`qedYSEZ+2xnB2B;RW;e>A4hJS0~N|#Wpis}xO znk_TplQP0LXq}^Ri?Ljz$uNfNySdFcbJR0GbTnhiZMmP;!{z9s(rEoE4*Uz32@D!a z@ei}6MVjM>LP}tItx;+{k(F_Tg{sZ?>DC(zRp@xsD$84%kz1}w!Ba8V6>49E#@XFk82Jp867(C@lzzINbxOVEVc=|EWruFo?sCVg2g3nNC(F%_XQA_{ zFr_lqtn#-~^D1RfneZnFzcEDzEIa*9VO@Y1Ju%~V-xBSopukuUe9Po5s}6_ijp zcGBu&UgDpB@No>QdpstajJ&tNHXLgY5YYik*|1_v^gw$4bvZdUDs5ILzACA(beE+Cl#XTF$rD&HWAAp z*Uckgfl1Jcz&aJm4O-|3rY%FixeHzi&0rQpJ|0czLiEhFO6ge8gH)%sxPfkTtl+S; z5+Q2~F0ihhSkox>Z>wyb+P{$gB_xi%#*elppF2Xpz26VH2jcJIPdL4362^JZmB);v zuthZZlfHwM)@eOxbt`N>|Fm{^UlgWgYN%f%&+e6;xC-!A zHYA^@_0YyBKMG1d)UbJj)Q@#sS5>u$-IYnJNK*}snb?bAwF645Ddt{&3!$#Za1w8a zQ#d=P$clnh#nbnZ*Jfq=WM8w1?DHfiwtr}%7>f%rD(um6+eU}<6>4!r$JplPVnPfb zD0aW{=x(>!q=W}+{bto;gA%{o!Nd{qQR5Aa$F|%T;0F^h@Pmrd=n{o%#{(he%h>9^d1IY$ z3@`3$w2&Q&tHV#2Sf?p2HH2;#_2n%YgY)&B$(gdxRfEHR8Yw8Vwv>eZP$Z6*1h;*E z>AjNC+PJCV`c3c>L!OP%IWt_?T0c?dEeaujy*Be(5Q;Io?;@_EN!N;;*+Vxb-pRL8 zL1cPt4IYLVJm-c5X6d-Mq(BM%CRU;gtcvfAwI7l0^7Qqe-iT>QU%(&U&h~hOIPf1` zdfBW$=8?Ycn;s2``mp*LL$QW+?|r1{zZw%ViZPyKN_k>^Z+OgT;bgYEQX8B&QU7a8 z2&>o3XADdy%FnA59c^_x^7np2i{Pcux$oU}n1{P%9q%%F{+@ZuDs96oP3z@}45Ec{ ztgh*WuG7iOTf#V$(|+wQw?{3tmivPEcL1s8i&3`WJW$ke9JA5ts=US8QfezzRsB+W zjWh^Ahw^dZBxy#04T}2YKPk!OM)o!{Uh^)}N=WFkFN2z(Akw5IGFjBgb{|Tei2FSw z0fhvFXMeB*HKa&cDyXHlDprgbJl2rP`NiUHur%EaqXLB2p*`#z ztOhh0TcY((a}gWejbo?6+$cEFz#Lah&NON@0minP-4onI?i#3&&@o;^PZC6Nf{((b zKq=C)=X`FupT!hl0P=+e)2CA?$5Qf@CS1Co!aChZnBMszPnpbF&IoZ8L~Ql9MnvH| zIU(JR;rzYTz?@dE+abG}+5at*wnNtlJ))0XG?6yxYl(U zcM9?qE_NHFHDJspFh6I=YrmYIRK=KYf^wN1v zvTokL5DalKqG)sQb&nM2fL6_`A~}mN)ti|Zas}Sqg;_pAk-q#rPQSWO zMnm^$(iuBk>HRGmX};p8JyDhVtx6O{7^?_2Luzn%AI|OP)5u+;5ZG}=a zbtzr-gKT|MpZu&W-VT*>h}BK(k=wS>4AOG z*cr%&u47)VJh2B+!~YV6<#e;ZEH-IsZsJ5!cAb=LZ^_Bdt7xBajQZ`*-8 zKuK4!0r;$nynEI(lTs{tn$7-TQ49~8bMHWfz2-N=p8M&H+6fU~IO@m$y5T$8#Jf_O z0E5bM!NM+f&S^a~%?Woa6Dtplu~ot!3TpV;6Q#AjT8X! zD=bBHZMwFnY>bR7cob_QF5>0!P|Scd#EXaVqtc#W6n8PRg<{Np15b6=5V0F z)W~(XKSDi#CH#Bhprv*Y8TCx-wpko zn&|}cUmF%h@i}**aluGzXPticby{JH+y}WXIp?8&1k!T?THx18oYs^+yYAq53)*z5 zl@q~89CZ5BZ9tB+|5AZM+W^&Lh|6SPJ!_58mPIM*-+5z~h~SACs&@x8o$l$r|BjxY z9w+vw*7~q*H}bkxep?ThY8Qi2UVd_=iNy>-N*4Jj3-q6V$UQYmy^Lccakvjg z;Jf~_(k8`LU;S+Mi4cDwg+o7j#s!dS{gG1aQ(r;Il6qSwkRIOKzhhQ4kZ(y9M#UBr zzS{0RSr9@bt44^3D`Cf2N-6VK@QQq@+XG&oN7Y)Vb~zMAlpgWMW0~|7###o_At&VN zJGdhk5Devpn%V6EkvQa5nl9is;0#z7*hPpa(sD`jN1*G3s5dvv6nwHu0*Z^Q_{Ci4 zW%~9|gJ(%(`+K5EAOd_Rk*`yota`5tsr{n88e;RkpXm*Ka9qBTRyAJ}bo2LLz4rs! z=kY}HaTg_heGGP4DUaGm1y8xcuO@zM6T$iIEe}hz0g;vtpRa?h24f?tJ6@h2nT1-y zXO3gs_a?>zk3e|c&Hh@If)@yPP^gp+N+lDpa!>B9C?t6~m`YC23YG|`Rjh_z1N@N6 zQ82q1GpDY z=HHaZ>xJrMYVI_O8fVGRsCprt#hrm)UqJj4A6Hr|+P-@9crR>)I7rP)DO5%Qc_OR5 zQ^=u29WV&?TCZ)%jUOvCh!hEbAru?w3%f?-M&K>f^(UE)4!+V+96r zJM#UR*w17wqjyY=Z{Zc1$d+j<;`cF^SYJOjH*|<;e91uASN1oC zts3gPf(5Ogg6+u4wH(W92y`N$mp@xp)*Hi??661AU8QJd+vs!+9YNy2|1h5S+5SiT z;;>jjq@H!|ZVIS;#*pTMcYv7OcuWy;J}$Bj6WGOHsGG+Ao0f5Wdis$V&uYQZuj}#l z3@EezPWqnlptDUHR+ei@?>D7iZAz^1U3U<7DSYXh`-FQ*>np3RU_5Ep&Vl=Y^FQ5w z%md$hjnw%Lm3RS;d;v9+GB1#SQDy=6g~O=F8&h{tm255Y3^He=S(8f-C4CH6hr7W6m}*0H#~$Y7#6~H@b9Kt>-)zfHyA}P zue+@>+tfO+_bjMcXZOJ_bAJ%()PsQ9|HQJ025W6lnn00u&W}c6=&p%vUc`I3=S4~| zd%S@=Tu)}?(sFaCfyITyAPif}4S8G@0#L&N#>Ck4p{gtLMopf-GK-y{Y^W+8Zt1$C zjY$#iFtskhAOBdSRk$uAEeH=MpfyoY{u4^p(^!%u>i?7wR?TbgTAN;D0Arp=q}8SwA4*D=^J znP^F^Vas>9*rgZt+zy*j76|deQuu*zhit@gNg22uxSny@EMhk|m#}bHMY70^$Ro_Z zy)PS5WVz}6WBGhN`>wv$4Oknzt!q59h+2BhGwewj+z@Y#LlzGIGR^B~RO$ z&R14#n%y~k8nAgK;O7>mALDKXC9(OeHfJ%(Lg4AMkZ6E>32Q=C-eWs=xwn==Tg6DwCOv@Sn<6QbpZ zlp5S}0|DgI(Gn#MHyWpZP-gsg`yvPzGc*ZA!`?8f7b!)yIcCqJpym2E$@2G5|KqW zLlSMWsM4QMK2EK!0{PlP5?!EoSmk2`Bn<)K4Vd})kA&0L`50(@{R4CITlEUr5|I3S z{zpegp@b4WBOTAJSCcss(NEFx1J%w6yiqPfV#F zMnR+dfS<;Bl-XNMuT852sZcaFFcRS75)b1}#CnrKU|2Gk%MU5h$B%sn8GC~44~z0e z^rH@=qUG*z0SL%$(2j;4__yTk(ZVF8T{Y8$qTbx_$u28c7o>nudPxxC2vm zFvq!2WFdn~lt-7-L%ucQ$-j6tV-1`xW$)(`Ueoxd8Z)w;$TwK(`Kdr49AXjJ;!)<` z(o{%30cFSIETHMK9sPhXyl`W9Ys(M!Alc{(d=CD@I&Kj+?TlbDo;QGSat1N91Qy$- z>jG^zSrVjR(uC>T@7$Vv{&x-BMuk8`zQMhMfKe~oeJ=qGsQkU!P>2cr0<@*5 z$gqrzyw;k9SKSWE%PT9|gvmU*B9yVC>NJNmc>JbC55sZQTBQjoSk9WFKX{>d@LSAk zvaDnMzb@b6c`QY)_FR}%@E~LT=22o}*AGa8&u_u^sjnLsb6);^K%~cB=X;>zZkWA1 zEc|%Fy=IYxVY6*CIDeVdaL8c(g5dxDHJ@H*D4U*wfCj~^oH$ILv^}dPofy=P5ly6e~j$ zHeg1}wt6lapvnEhE>1pf23Ha5;&^thJR#2tWhx8&(lm9}V}XaKeS9DjONmn0VD&2cjF?hLJ$=-?yAXs!#sN zV86wBZHf{$RhB^)6)(OdeTEUM+16T=q`>)TOwI@wGK&7-6Vm_n0_ac1TQ#bN zIPinhssh${TP#LZsZj5VgBoc zv7-3VIfttn(qw6RHke@;4YsAY&*ioUr8-Qnrmm;%U$vo@8pr3Pd_j4boz?of1rj@u zNLkzRaWe4P3S0}?u1jE-)2T6`6m0m}SccfYqHC9p8>%5dxHL32FddumRwolkp!A? zpIs%5;CY}f;##RzRh-ZOM_9*tx--nW`*PKga-=dnwO(G1@?`!8jCH1BME7<}#B$2p zuKm4Jv@UA4zDy#ZYnJoE{NSh^;UD81TYiJVz1bGw>u|EcT2p-o(VOa0a60Vkx- z)GR+3nC1~+&^;Q4tA@xCJX*K2rZz|xpCM6fJ3WxHwS@)Z@Cmho^^Z)%F;l(UYzMbm~cxt;xR7_~3{=3_Xo7fZ6$G-M;;U$H3 z2}f-uraQy`VryoJ?+}rCtQJ2ZYB^@9@Bd4!v$X`iJYT7r09=G*c2|!NbMrKZ7E!halPht zI1|CHN$mq-g2j={XR>=$hI{IGt3en z{1kX`xIBWh5XE3ZH_N>+=Je{9y~=71Za-bL#W_-DF=g_aFxPvfkz8IfUu)G+?iQW@ zKl1W_m%f_asS~FZvmZ!~vB#)?5j8i1osGA~&AUBnjn0l_URFQZJBF0La3e~0ex)O$ zS;gcWKSEO&YY^G%c< z?+iUt??~WQ$$G3jaIV=kFIA0N6UySztPjay(?Pr6{y@26d;3#UH9BiH?)ZpPXB;E# zgt30xL@ct$t}qF diff --git a/public/icons/gender_m.png b/public/icons/gender_m.png deleted file mode 100644 index 9a906e778636c85c3322e3ae00826de9c2b615f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10159 zcmb`N_di?T|G=9z|m|h?N?l6ftX+DoU-yir8vasa;f6tQxJ_N^9>` zqpDS-Mp2{s&HM8=e1Eu)`?&YM&bjBD*Xx|uInUQC-qiT^6?!gu3JQuV`bZr#1qCJO zzY9b|ep7Pn@sE6?^F>`gqM{;G=!aTINExN9 zBZAS#)yXTvJlFZFo-pJ|4X-KA)Z+$g+}2!ojah4#;5DdhQI2?cA)shdZ`XKH&O_l5 z^J0ovE^<+ch*lzKD;A&_F3z^zOe`%eZ9Y~jC{PXX7);qD+*ID>{`da<`_0wWRryFm zJ+q&}d6*z#{r2?hyKwsWq%n7SR{EH{f7mv9j6!tLXjb|1M8H=xqwO)@Pv^O2$4uC+p&ytN4eDgM{GU zKhjjf&KfpZ0^1OZFF4_Fuz|O2>!X3~ot@VgjH{s80a2BLTM<6PFK#`ECAM-5s-lQe zlJ@OhXL?ZG*W{jL1mrCI&0H#eW7p<-)^qdMJEz!0`e<}+QqmP5c9;Fh-?IS!-9?oN z+Am=zOLH8uaPVO3qGUVFwB^Hxblms$*v)*O6T9(=GKKQ}j*`+k=N z&J;m%gt!=$Pi*=e``Vr54me}yqyPP@AJI6ZxqdFfv>bl^`gFga*D5?K|K@&>1uUa+ zK$ugw>#0{F3J+s~O4{xb&Fv-P0)Sd}j4s}F4nl9gF}U*W-3UGCS7wAc3eALAPQaZtfhn zk%FND0g!jKhmHvNDvy$qQpyV}AW8XS-%_g+hs(ziI#Ti+)XdMf1TY4sHgxQNtbA+`?IwR=^i7;=RtP9xRvMC|}` zn86w=%_6N%(G^3S2H}SB^Bnc;5WY*Y!PM{noO(6qgsK$>Ghm@Otc=WU_TGZZNMd(L z1p-Je)w6QEvrykJ3`n%Sc=O@1RfTMp+iTxdQW!Oy%&F7<{5@Gt;f*-od23CdITM;) zt^+J8oZ>EK?&!&Y(Era=_F#0{ccuZ*f7c$olVPR8hpE*FP;B85v(FgjM+Nu;h_I}l z-CZAd`@wiRFtI(p`(!!dLHM85xVgnbW}oWQLcnUr4Mq&ZTc4$>Z(6~JLrQM^h`irT zy)cLl6{%1{JtcsfRt$pM?e9^JE>2nNsC{?x<;mEYT@|7lcD@GcuDOro08_x(+XO)x z)eaXIha>g37c;70Ow)fs5F&%()>x2VWKP5@dL2ru);cD~4tX{IjnAKLI>P=Na#qjl zBoR@_lZ}dgp>GrK*=S911XTEpCPxk1vb_}tF{=x#(;36YP@Mp$97&fUa)$j+1bHkZ zmD^Q(ouN%F?DF(`W;CT3j#b&&%y)mnxE4}`gLz|DaOLyg2D2uuK_-RPy0=caeY=l^A7X=4V7-KW5OKn%j z5A9kRMG!SB_*1c0HNX=;6ez9@Cb!caWL1q*rCFp~?t$YoJM_D-ravjuRsf;`5DatB z?qaSwlO}he7+|b2%Rjg~?MeA)Bi*aj!AvnZ97s2&Naf>!^dKmvkxN8m>t{QgOHYyE zBR$wbYplvLj)Q6q?4eL0#(Y%=PazdlGs2n2(CjydV3uoLH zvGK5o%4KJZ3q;z$4#cS?d;KEh+hVw`=V`(0^sU9Fk_~RcAiSY_ov6|emuFk!I22pl zF*4BYwb~b7TOWoV&My)F{=)n^&w0J5D zdH*NsYv^dNc6!VesMNj0CJsGOTIj{g7vZWmP1;{8;mB1^?OJSn z^T}DXmMg~;&bS%1fD6d(vWbz6CU%p3-X@hkosKXQP#|UNnpT2qWE*pMjU^(G;abnd z!6&H{C)O}9EzhUP^-=@b|NT7e=COhwjV&=Xs(LA^^-8g^*V^gfcR4ZX-XkfO-Xf_6 zN${)joJpnVo@+T6-ta#~k`+Jc$o^7MRMy-t(vliWk^zlgCS6i$5Wo??$8P^bizLZ9 z`$bLz`Jr(wDBTKW_pzreQAG(<4Y?bF8`5=BNT*l=RTm;GiWoI62xq$8fYn^5956gq zSnH^>=XDl+gv%V4CwmTNJJ^BwMsk?ZP30HL4icdU12=4#E9H}k-D+mk{8D(;8h_Y^ z@6No!eh^42{9?Z!&SdbFywI{5!PvzF^$+UHu=m<`CAEdm{Z*Ts|HHsWo2y6752d9qa^1R@+tJ?076y(h zhMC{LVy|>@MRyD#Qeor#CWR0BOhJ&T;?c=W@OOD{%~TS{9JKw|SMlyxuYN*aN4czp z>dpQ>`o5s$FeQIO_p3_sBzGjYyZOUzZUvQ})Jb$YJQ>el1?)-8?LJdp(HPZB($y2i z&|7p=Il;&CqPa`f!97B1nSK(E8esF@Oeqi&#l&UFkDl?L+E3#!6qg0#2GF`W_ zR`mRRily$;wOSHsziURX-E&eB9K5(%9+qU-8P3LHcVF{CPH5rpm5u31fkXs^1aSX48%S-)W;N|Foa&o_PfWS5|Q z{;ZkGngLq*QjSgyi?td+I`DaUdk?{N?|ja8GBe#U9&ILK9^H4Vn_Ww_qjmDnn16A7 zq26tz=7Ki1`RI#ZwlNc6a zB(dTUIky9|EY0c;ndAqzc*@khVW!<2?kP2pal(mpM#H}vOOtBuy;o(8liZDp%#oRO zyhhr~Z{wfdK~6pUb2xIVcSOY=&Lr!plsI6QV0X?ngI~qlKJm~H$9E)~G((EkI&^#2 zRn^pwa&T&!^a&Aaf|>U_rRD>hfq+zt}BkJWM4 z?^JLz_(`A-taeJ7=yV?5=wkfdwfRa~92~k$!{OOIIIRlzFK53*_aTT>+Xl*D?AJqo2We~pa_wP0oLqAFD5XiLT;p_OC4$G?1 zd^2Ld7phMHD#16Ohg1{%+ChG%8SI3`kXh0j(YmziI7l5kSt~vL9(xMo7RfM0O|QQ1 z4}CB0Fw<2w+=4j-PdrKuSbPU(@3B2s7WIwOpK0=BhBGy@5VVP9W1>!9<$D`>Ume>YlpTr1c3K1d~YWoY?GB%xXW}R+o*%|`*rtfmvY2q=qr9ciM6#~-2p7SwMw$M zS-T_6+&uS%$I-rewFzkv`=qd)S2ogti}8v&C(InCZ}k-t2eyn9%dAR{A;Ggzmva zJy&bg=d^3GRB{@0+HXP4zTUXn}k#*58xXM&tR$Qi$V|B1z15u?c{$JvQSB!yPQ8?;}qab>r2~A-d~hz z%#xXrN5Q9nIF7e%R_s8}uStvTd=IQKvxGm8Itv-X9 z1lL_(?s-HN+R@T}#TbV{c^klqXH914A-xv#E9C{0r9Lg*d7LF=u@|!iA+F3fKO2NG zi5oy>1H(r7(pDHG8>gO%6a4mLGPv#wNN@T})N;u?r3tsws4a&cCf%pHZx?+dPiFW* zg;*~2xuPN_8#Yt;mJ07HbbcOa`C2Lsh^@(go-ywwP}`HQ2QQnJG~L8MHaub`L|hA# zXc=ok7nGi;bH-i&%6GEEOuswLIw46r=P+Sg$3~_cHZ4+m<*^xIN!y;4#nnkGr4InB zmhLwy8ak(H?^4zPwoF?c@;Ye5?ED#&sNPOd?zh@~sPH?n ziRW{?$+!GM1xx2?(Rrk=SJ6Y-G5P5kS$nTR$t~*nF@I=d?!Kz9VI6a^mF&w3*<5$Ojhf@ z?Qjn2C2sHjB&FeZE$TV#Tr#O;tl**&pNZEaKqQ_FAIBNGX7_Gl>PF*@JU`<>*GFj< z0KaN{GkeY1sp29-BhQ(>hh_A-tFQXw#YDsM+n?!l?#Ze)y%E~t3-n;!(u5PyTSaYu zstJlAdd=0K9!;A^t|1$);x^!~YYd{7;Dz_F)@@mZsgNHU>1>@te1QRF4Hhrly!%uf zz4g9>sk_QDa_mVGpn>bQ<{JZpCpi3oXeyN-SBPs#rPS-_`Wm;^|j#Y`6Ll6R%T!s*u}?0CyxO7=DX z!8vR8B;JBCNuJ=_k}Qpm8C0`cd=R81#sU1Ev#jyAEpb&7Gg$Hvzi6hw^#p<6RP0ohJOM5#08t<36`!mKad_Ru_C_ zNv4^uD>SgOn@(%bP6}W`iKu?-hcf8+Tg^R`lOY^5Xm0+E*bnHA$*;Q&Z->H+-eqND zMy$b-So-MSLCB4l7+JmO9^!?8FHzQha5~PJJ-JTX!b%x)H6+$h$m~ zNv|;UY5-;>_ZbRM&ti7!?xM`y)HVZ;GDyz26q*FPJbwEjml)Ci@ewx=YaS|)$q{W> zVa^>J+?xiR(1YItO_ zmxF!$G+7i(1_aVY1t(@j!{8NCd6H2Y{@jw8`cO-#abAs1MiY~9^+Lq<-4CnZV#ER zjUzp;W6Qt98Pp<5Q_=YLmzf#CSfxsf4Qmzx1kQFeTv)0HSNb?hE-7=zfQ5A8Wb{32BZHOaY0h+%{0SAXctT@8otiIf6~m81RFj~%an{nBF&U~kZJ%3_2o&)_ z=|RlQYyx8Qznw`2kiP@}qhTNc@!6snX|L>BVtQW+z!vWabE!uA$pGfBqEK<7Y^8~u z19nbUE@d~kxw(~ZC2(?Q%wJ{f#OFYkQz0^$Lk11(SPrBT-aIgv;YZzv9khIN(w z5_)L#-RH zB1Svw8L%QZHPWw%w!8?acfBY&?3BH$uOiwm8n$mAe%jl!_WJFYhvDVyIv@Pu2}l6oPVJOMvX z!pomfrc>opo0oM@xychsV+Eu%g8E&_l{l3PM`?gD6)8JWPIHQN7 znxG;A%-~GS3&hkq&hZ{}E6(JHQyX;L$XA5YK!m=hb1g2NlWl?c_U8NTA+;DMvX>~tm_@=yIzh2zQcda4n>+Rtm^ zljJ|du|!1nmN)tfc};3H|KzKMVWqwtWZrwlHfDtMHn8i$(%xXEwZcKxz~G3-4k2B| z2yxNnGQ;dd2GJ{%K%iLJK(VFH34){aFm{SVPMHp^UHmCqDvu(>Q&T*%R^KOf{iQ;T zvkz9&{WRe1N~r#{HgqY$LaelH@Ht}L-U}USB3n7{D;H|n)95+V&{`(|V{B_{8y;Dx zZgYwQA&C)>u8Tm&f@11C{D=Ii8I{4q*^%t97~c(Aua2*9?fSu z?fMlBwBLmqI|L_F-~TWQnOI{Xyzf;apCLVL!POZyQA*T4v5;DGD*<&(*p|Np*2)Nw zRcn5oJN12GRKPE;jA{tM!iPpOwn4GviWmTdF{tTtdl6QC_ecovU9(PS;i1F|IoJ^t zuIDS;@&1R)N%2hdNESVPjs1t+i`6Dzmr^A`8^*$w;tuUu?TTSo8}a2?0HLtzNZknB zuC5e=uOJSC))B?TvyDw>J=U;_GQw#5yYMe*pw)C5Nca5INP*v$gyzo2QJfS9%`qh0 zfgMP_Gna+u5_E72UEe)cPCQ2Iu7lk~*(b|ADbt_u^?srMEvbAzcAOesP!``2^mh2``H!^V2s9evw?&aZwtt-(z$jgm;_0Xz{M>1Fug+3SigwPyD`c zmLV2?rk>A*I?GnrRobm>{^hVX`?G;jFQy*v8l)5qVZJh zuh%^ca3|C>aw>QyaB44~G#f$pb1ox_Wz)E8z4`Gz_7zUl&>aOZ_)`)^Y1Q?%rb`R{ z)JqpSeA831KrI*x;LzFbMECX9TK1%eV09N;{QFOzJb$hzCY}JZ{C76ERC&ou|SIK8BltzOZ%{4W>;Uf9Ct^i#qGaLewWTfHD^ePRJ2&A0aAL9xxu(4AFn$ zZ!+eW@7AL5|45?4UIDrMF#ZWaG}-|zqFZiI3s*8ST|qGk9Xp7A!(wEuoSv(1OSL}` zn3wz@FJ#rN6&n3437k!pgTxq88b;nU;S2&Oe;@Dkj`0hawl=t+8$+Jn3r{6@dh9icMc|pphCLXoN z(g{)--k;*85G4f=bWXyGYWUFtpP5gy%>8M*{+Y1l z71+7CR1NKV`S>((&FX-7ZiTBosph(=$>DW1&O9dnad*k>ly}r-IJT#(avdGcX^qqX z*)$lt%)QWMD+D#FDFcmtRiP~s>5$`%_jsKkEY6s$R6~XD5O7+m`GR5a4#=0J;uNjy zR_#CE+ZzQwEc^ABCv;K>T(XUmZ4k1G8qgm_KP#-Hk$_ejiV!hlA{s1tq^`~_Y)1Z9 z47Zeh`*S+Lh|2VFu-zkFjt*#sIA;(?gQsJqE)2#>$L_pndz351LpiziGK=4TEZVeG z2WlIyTgyduFBMsgUII!oR6!ErjdZ|f+balIsezg>KYtq5wL501x!FTnPJuvY2E|W} zvN=)=cS7w$`7TlM%~XtE8fzydz_VS=TqPDSSW`L}1JlL_Kh#O{8vy1g6d4WhwEf>*TmX0yL?@iPf!Z(VJI4eAO2 zDA8&FC91U4A5W2xPKcfe7}<71aAeDUFQF}x1KjU8n~2O_qvMMvP%U5oR1~dTJB^(Y z@s}3`3;3^lBwB_I-^;CrWc+xAtOnp5)(+kKUs=7eq$fu+;#qIFj;JUye%ZG}A+#h#P+%=po@qIwDqE{GI7Jf&U-ii}sAu?t`U*W>mIsnxjVG<5l`Q4S$@rS=m z>!OSYyDBM~rrrUA7>g&pgZeG!d&_0R)_e~)hU(UQHG4aaO4y@y>20(=ZYbo8$P4hD z)i5&1YVj?N8BVKqoSzz@{J{THC(GEdY}4rV8uV=9?fBd7DarI}d%<5c%$WZ~2(!!$ zoG)*$PIz7Xvv{$PnJg}yUK=K%eG?(N6ulxoCwYH0GbSgh;i!xLBjzH-?43?MtRs6a z($tXuo2$@Z$n119U&62fjiBa4t`GqZ2J^G3)Cr%@!m?q73e8X%=3$V>mj#~$~Dvp#Yd5B5M+ z+ZMZiZrwwfCc>IW!A3l)STn#(6BIgdDs|lQNps)<24FOel!Qe!9YO@;JicRH&l5h) zOd|^^m71A-V;+^p{39BH(fZ25zKinWv9%PT@WhXOYuYn%RAQhvvSRN<7yhVRKiKBy zdO$$F1Og70dg2WewZhx0792a%Yq2uUuK;EUa219jQhLQ0#>lorr!0ND?VeF0OUy7G za9y(BM^Q5Fa=2BC616SoHq6*ZT~r(YSFKvv++|3a%0Xdq6yh4HDhkd*i3EO5`y@mE zH(xaxkh9&)Yqy+VMOdn*G9&LWPHplod_zT2^tj>XTI`ObDYl*Kb4>Z{pbD%J!cL3Q z-0h*}sOb#-ZK#OPS`=)OgflU!0g`Kaa%B#W1Qh@m<47xt zJYNj=(bX9&g#0>I`;K+n<7QrIVZ$M{Or0&)o#n;Gg3V#{sFdPOr#toMGBBpZR_6Cw z)LojLRkN~ib`~-hH4JQI4G*YEpX-#xTligPR`XMs$V(6j}5JtKN*+C(PsYCd*N z7LTD~15%sAxP+lemA$z>^H4iosm(yEeW;ZPFJ2cji^Xn+|b&Yjuv>fpN2S9a+EdT%j diff --git a/src/styles/globals.css b/src/styles/globals.css index a410675..546e919 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -16,6 +16,11 @@ .text-balance { text-wrap: balance; } + input[type='number']::-webkit-inner-spin-button, + input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } } .bg-gradient-polaroid { From 34711504b985659ef57499db3fe89e24c55734a1 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 18:41:09 +0900 Subject: [PATCH 12/15] =?UTF-8?q?#86=20chore:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/_components/contexts/ProfileContext.tsx | 5 ----- src/app/(onboarding)/signup/page.tsx | 12 ++++++------ .../mypage/profileEdit/_components/ProfileForm.tsx | 3 +-- src/lib/api/auth.ts | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx index 2400c24..a427d3e 100644 --- a/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx +++ b/src/app/(onboarding)/signup/_components/contexts/ProfileContext.tsx @@ -7,7 +7,6 @@ import { SetStateAction, createContext, useContext, - useEffect, useMemo, useState, } from 'react' @@ -35,10 +34,6 @@ export const ProfileProvider = ({ const [newBirthDt, setBirthDt] = useState(undefined) const [newGender, setGender] = useState('NONE') - useEffect(() => { - console.log(newName, newBirthDt, newGender) - }, [newName, newBirthDt, newGender]) - const value = useMemo( () => ({ newName, diff --git a/src/app/(onboarding)/signup/page.tsx b/src/app/(onboarding)/signup/page.tsx index 0bc9b46..335412c 100644 --- a/src/app/(onboarding)/signup/page.tsx +++ b/src/app/(onboarding)/signup/page.tsx @@ -1,15 +1,15 @@ -// import { auth } from '@/auth' -// import { redirect } from 'next/navigation' +import { auth } from '@/auth' +import { redirect } from 'next/navigation' import ProfileForm from './_components/ProfileForm' import { StepProvider } from './_components/contexts/StepContext' import Header from './_components/Header' const SignUpPage = async () => { - // const session = await auth() + const session = await auth() - // if (session && !session.newUser) { - // redirect('/board/create') - // } + if (session && !session.newUser) { + redirect('/board/create') + } return (
diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index e714243..c14d5e6 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -27,7 +27,6 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { const [unChanged, setUnChanged] = useState(true) useEffect(() => { - console.log('birthDt:', newBirthDt) if ( session?.profile.nickName === newName && session?.profile.birthDt === newBirthDt && @@ -37,7 +36,7 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { } else { setUnChanged(false) } - }, [newName, newBirthDt, newGender]) + }, [newName, newBirthDt, newGender, session]) return (
=> { }) const data = await handleResponse(res) - return { ...data.data, birthDt: '2002-01-17', gender: 'F' } + return data.data } export const refreshAT = async (refreshToken: string) => { From 0fc8e8263ee5a8c1c8dfa568b493def6ddc481bb Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Sun, 18 Aug 2024 18:52:19 +0900 Subject: [PATCH 13/15] =?UTF-8?q?#86=20chore:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/_components/steps/NicknameForm.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx b/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx index 77f4072..d3d8c06 100644 --- a/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/NicknameForm.tsx @@ -2,8 +2,6 @@ import Button from '@/components/Button' import NicknameInput from '@/components/TextInput/NicknameInput' -// import { useSession } from 'next-auth/react' -// import { useRouter } from 'next/navigation' import SketchIcon from 'public/icons/sketchIcons-1.svg' import { useState } from 'react' import { useProfile } from '../contexts/ProfileContext' @@ -14,18 +12,12 @@ const NicknameForm = () => { const [nickname, setNickname] = useState('') const [hasError, setHasError] = useState(false) const isEmpty = nickname.length === 0 - // const { update } = useSession() - // const router = useRouter() + const { nextStep } = useStep() const createNickname = async () => { - // update({ - // name: nickname, - // }) - // await changeNickname(nickname) setNewName(nickname) nextStep() - // router.push('/signup/complete') } return ( From 83f8835e13a9def747f9350d19dade30f6195df3 Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Mon, 19 Aug 2024 02:15:47 +0900 Subject: [PATCH 14/15] #86 feat: birth date validation --- package-lock.json | 135 ++---------------- package.json | 1 + src/__tests__/validateBirthDt.test.ts | 37 +++++ .../signup/_components/steps/BirthDtForm.tsx | 76 ++++++---- .../profileEdit/_components/ProfileForm.tsx | 102 +++++++------ src/components/Modal/BirthInvalidModal.tsx | 22 +++ src/lib/utils/validation.ts | 30 ++++ 7 files changed, 207 insertions(+), 196 deletions(-) create mode 100644 src/__tests__/validateBirthDt.test.ts create mode 100644 src/components/Modal/BirthInvalidModal.tsx create mode 100644 src/lib/utils/validation.ts diff --git a/package-lock.json b/package-lock.json index 8f80253..7403e19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "polabo-fe", "version": "0.1.0", "dependencies": { + "@jest/globals": "^29.7.0", "@storybook/preview-api": "^8.1.11", "@svgr/webpack": "^8.1.0", "browser-image-compression": "^2.0.2", @@ -602,7 +603,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -3099,7 +3099,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -3115,7 +3114,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -3124,7 +3122,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "engines": { "node": ">=6" } @@ -3133,7 +3130,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -3146,7 +3142,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3159,7 +3154,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -3171,7 +3165,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -3186,7 +3179,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -3198,7 +3190,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "engines": { "node": ">=8" } @@ -3207,7 +3198,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, "engines": { "node": ">=8" } @@ -3428,7 +3418,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -3443,7 +3432,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -3456,7 +3444,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, "dependencies": { "jest-get-type": "^29.6.3" }, @@ -3468,7 +3455,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -3485,7 +3471,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -3650,7 +3635,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -3706,7 +3690,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -3732,7 +3715,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3747,7 +3729,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3763,7 +3744,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3772,7 +3752,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -3784,7 +3763,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3801,7 +3779,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3816,7 +3793,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3832,7 +3808,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3841,7 +3816,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -4207,8 +4181,7 @@ "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", @@ -4225,7 +4198,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, "dependencies": { "type-detect": "4.0.8" } @@ -4234,7 +4206,6 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -6153,7 +6124,6 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, "dependencies": { "@types/node": "*" } @@ -6181,14 +6151,12 @@ "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -6197,7 +6165,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -6365,8 +6332,7 @@ "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, "node_modules/@types/tough-cookie": { "version": "4.0.5", @@ -6390,7 +6356,6 @@ "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, "dependencies": { "@types/yargs-parser": "*" } @@ -6398,8 +6363,7 @@ "node_modules/@types/yargs-parser": { "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.16.1", @@ -7156,7 +7120,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -7670,7 +7633,6 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -7686,7 +7648,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -7753,7 +7714,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -8131,7 +8091,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, "dependencies": { "node-int64": "^0.4.0" } @@ -8412,7 +8371,6 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, "funding": [ { "type": "github", @@ -9517,7 +9475,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -11267,7 +11224,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -11409,7 +11365,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, "dependencies": { "bser": "2.1.1" } @@ -11903,7 +11858,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -12006,7 +11960,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "engines": { "node": ">=8.0.0" } @@ -13178,7 +13131,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, "engines": { "node": ">=8" } @@ -13862,7 +13814,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -13877,7 +13828,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -13892,7 +13842,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13908,7 +13857,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -13917,7 +13865,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -13931,7 +13878,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -13942,14 +13888,12 @@ "node_modules/jest-diff/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14117,7 +14061,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -14126,7 +14069,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -14196,7 +14138,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -14211,7 +14152,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14226,7 +14166,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14242,7 +14181,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -14251,7 +14189,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -14265,7 +14202,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -14276,14 +14212,12 @@ "node_modules/jest-matcher-utils/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/jest-matcher-utils/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14295,7 +14229,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -14315,7 +14248,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14330,7 +14262,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14346,7 +14277,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -14355,7 +14285,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -14369,7 +14298,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -14380,14 +14308,12 @@ "node_modules/jest-message-util/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/jest-message-util/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14399,7 +14325,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -14430,7 +14355,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -14736,7 +14660,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -14767,7 +14690,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14782,7 +14704,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14798,7 +14719,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -14807,7 +14727,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -14821,7 +14740,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -14832,14 +14750,12 @@ "node_modules/jest-snapshot/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/jest-snapshot/node_modules/semver": { "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -14851,7 +14767,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14863,7 +14778,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -14880,7 +14794,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14895,7 +14808,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14911,7 +14823,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -14920,7 +14831,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -15104,7 +15014,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -15119,7 +15028,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -15128,7 +15036,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16087,7 +15994,6 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, "dependencies": { "tmpl": "1.0.5" } @@ -16593,8 +16499,7 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-polyfill-webpack-plugin": { "version": "2.0.1", @@ -16644,7 +16549,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19253,7 +19157,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "engines": { "node": ">=8" } @@ -19386,14 +19289,12 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -19405,7 +19306,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, "engines": { "node": ">=8" } @@ -20493,7 +20393,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -20507,7 +20406,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -20518,7 +20416,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -20538,7 +20435,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -20601,8 +20497,7 @@ "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -20991,7 +20886,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -21453,7 +21347,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, "dependencies": { "makeerror": "1.0.12" } @@ -21925,7 +21818,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -21937,8 +21829,7 @@ "node_modules/write-file-atomic/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/ws": { "version": "8.18.0", diff --git a/package.json b/package.json index 20d913c..0071ff7 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ ] }, "dependencies": { + "@jest/globals": "^29.7.0", "@storybook/preview-api": "^8.1.11", "@svgr/webpack": "^8.1.0", "browser-image-compression": "^2.0.2", diff --git a/src/__tests__/validateBirthDt.test.ts b/src/__tests__/validateBirthDt.test.ts new file mode 100644 index 0000000..6517edb --- /dev/null +++ b/src/__tests__/validateBirthDt.test.ts @@ -0,0 +1,37 @@ +import { validateBirthDt } from '@/lib/utils/validation' +import { describe, expect, it } from '@jest/globals' + +describe('validateBirthDt', () => { + it('before 1900 -> false', () => { + expect(validateBirthDt('1899-12-31')).toBe(false) + }) + + it('year after the current year -> false', () => { + const nextYear = (new Date().getFullYear() + 1).toString() + expect(validateBirthDt(`${nextYear}-01-01`)).toBe(false) + }) + + it('invalid month -> false', () => { + expect(validateBirthDt('2020-13-01')).toBe(false) + expect(validateBirthDt('2020-00-01')).toBe(false) + }) + + it('invalid day -> false', () => { + expect(validateBirthDt('2024-01-32')).toBe(false) + expect(validateBirthDt('2024-02-30')).toBe(false) + }) + + it('valid date -> true', () => { + expect(validateBirthDt('2024-01-31')).toBe(true) + expect(validateBirthDt('2020-02-29')).toBe(true) // Leap year + }) + + it('non-leap year February 29 -> false', () => { + expect(validateBirthDt('2019-02-29')).toBe(false) // non-leap year + }) + + it('at the edge of the year range -> true', () => { + expect(validateBirthDt('1900-01-01')).toBe(true) + expect(validateBirthDt(`${new Date().getFullYear()}-12-31`)).toBe(true) + }) +}) diff --git a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx index 8d9e79a..45973d9 100644 --- a/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx +++ b/src/app/(onboarding)/signup/_components/steps/BirthDtForm.tsx @@ -2,47 +2,63 @@ import BirthDateInput from '@/components/BirthDateInput' import Button from '@/components/Button' import Link from 'next/link' import { useState } from 'react' +import { validateBirthDt } from '@/lib/utils/validation' +import BirthInvalidModal from '@/components/Modal/BirthInvalidModal' import { useProfile } from '../contexts/ProfileContext' import { useStep } from '../contexts/StepContext' const BirthDtForm = () => { const { newName, newBirthDt, setBirthDt } = useProfile() const { nextStep } = useStep() - const [hasError, setHasError] = useState(false) + const [modalOpen, setModalOpen] = useState(false) + + const handleSubmit = async () => { + if (validateBirthDt(newBirthDt!) === false) { + setModalOpen(true) + return + } + nextStep() + } return ( -
-
- {newName} - {'님의 \n 생일을 입력해주세요!'} -
-

- 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :) -

+ <> +
+
+ {newName} + {'님의 \n 생일을 입력해주세요!'} +
+

+ 추가 정보를 입력하시면 나에게 딱 맞는 보드 주제를 추천해드려요 :) +

-
- +
+ +
+ + + 다음에 할게요 +
- - - 다음에 할게요 - -
+ setModalOpen(false)} + /> + ) } diff --git a/src/app/mypage/profileEdit/_components/ProfileForm.tsx b/src/app/mypage/profileEdit/_components/ProfileForm.tsx index c14d5e6..117430a 100644 --- a/src/app/mypage/profileEdit/_components/ProfileForm.tsx +++ b/src/app/mypage/profileEdit/_components/ProfileForm.tsx @@ -6,6 +6,8 @@ import NicknameInput from '@/components/TextInput/NicknameInput' import BirthDateInput from '@/components/BirthDateInput' import { UserProfile } from '@/types' import { updateProfile } from '@/lib' +import { validateBirthDt } from '@/lib/utils/validation' +import BirthInvalidModal from '@/components/Modal/BirthInvalidModal' import Title from './Title' import SubmitBtn from './SubmitBtn' import GenderInput from './GenderInput' @@ -25,6 +27,7 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { const [nameError, setNameError] = useState(false) const [birthError, setBirthError] = useState(false) const [unChanged, setUnChanged] = useState(true) + const [modalOpen, setModalOpen] = useState(false) useEffect(() => { if ( @@ -39,53 +42,64 @@ const ProfileForm = ({ children }: { children: ReactNode }) => { }, [newName, newBirthDt, newGender, session]) return ( - { - const newProfile = { - nickName: newName, - birthDt: newBirthDt, - gender: newGender, - } - if (session?.profile !== newProfile) { - const serverRes = await updateProfile(newProfile) + <> + setModalOpen(false)} + /> + { + if (validateBirthDt(newBirthDt!) === false) { + setModalOpen(true) + return + } - if (serverRes.code === 'SUCCESS') { - update({ profile: newProfile }) + const newProfile = { + nickName: newName, + birthDt: newBirthDt, + gender: newGender, } - } - }} - ref={formRef} - className="mt-9 flex flex-1 flex-col px-10" - > -
-
- 닉네임 - -
-
- 생년월일 - + if (session?.profile !== newProfile) { + const serverRes = await updateProfile(newProfile) + + if (serverRes.code === 'SUCCESS') { + update({ profile: newProfile }) + } + } + }} + ref={formRef} + className="mt-9 flex flex-1 flex-col px-10" + > +
+
+ 닉네임 + +
+
+ 생년월일 + +
+ 성별 + + {children}
- 성별 - - {children} -
- - + + + ) } diff --git a/src/components/Modal/BirthInvalidModal.tsx b/src/components/Modal/BirthInvalidModal.tsx new file mode 100644 index 0000000..ceb6be5 --- /dev/null +++ b/src/components/Modal/BirthInvalidModal.tsx @@ -0,0 +1,22 @@ +import Modal from '@/components/Modal' +import PinIcon from 'public/icons/pinStroked.svg' + +interface ModalProps { + isOpen: boolean + onClose: () => void +} + +const BirthInvalidModal = ({ isOpen, onClose }: ModalProps) => { + return ( + + }> + + {'생년월일이 제대로 입력되었는지 \n 한 번 더 확인해주세요!'} + + + + + ) +} + +export default BirthInvalidModal diff --git a/src/lib/utils/validation.ts b/src/lib/utils/validation.ts new file mode 100644 index 0000000..ef8dc0b --- /dev/null +++ b/src/lib/utils/validation.ts @@ -0,0 +1,30 @@ +import { UserProfile } from '@/types' + +export const validateBirthDt = ( + birthDt: NonNullable, +) => { + const [year, month, day] = birthDt.split('-') + // year: 1900~2024 + const currentYear = new Date().getFullYear().toString() + if (year < '1900' || year > currentYear) { + return false + } + + // month: 01~12 + if (month < '01' || month > '12') { + return false + } + + const daysInMonth = new Date( + parseInt(year, 10), + parseInt(month, 10), + 0, + ).getDate() + + // day: 01~해당 월의 마지막 날짜 + if (day < '01' || parseInt(day, 10) > daysInMonth) { + return false + } + + return true +} From e8ee38ebc67a4d1a05059bde47728524febf2cad Mon Sep 17 00:00:00 2001 From: hwanheejung Date: Mon, 19 Aug 2024 20:19:47 +0900 Subject: [PATCH 15/15] #86 feat: added future date validation --- src/__tests__/validateBirthDt.test.ts | 10 +++++++++- src/lib/utils/validation.ts | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/__tests__/validateBirthDt.test.ts b/src/__tests__/validateBirthDt.test.ts index 6517edb..8c9c081 100644 --- a/src/__tests__/validateBirthDt.test.ts +++ b/src/__tests__/validateBirthDt.test.ts @@ -32,6 +32,14 @@ describe('validateBirthDt', () => { it('at the edge of the year range -> true', () => { expect(validateBirthDt('1900-01-01')).toBe(true) - expect(validateBirthDt(`${new Date().getFullYear()}-12-31`)).toBe(true) + }) + + it('future date -> false', () => { + const tomorrow = new Date() + tomorrow.setDate(tomorrow.getDate() + 1) + const futureDate = tomorrow + .toISOString() + .split('T')[0] as `${string}-${string}-${string}` + expect(validateBirthDt(futureDate)).toBe(false) }) }) diff --git a/src/lib/utils/validation.ts b/src/lib/utils/validation.ts index ef8dc0b..f8a7a11 100644 --- a/src/lib/utils/validation.ts +++ b/src/lib/utils/validation.ts @@ -4,13 +4,12 @@ export const validateBirthDt = ( birthDt: NonNullable, ) => { const [year, month, day] = birthDt.split('-') - // year: 1900~2024 + const currentYear = new Date().getFullYear().toString() if (year < '1900' || year > currentYear) { return false } - // month: 01~12 if (month < '01' || month > '12') { return false } @@ -21,10 +20,20 @@ export const validateBirthDt = ( 0, ).getDate() - // day: 01~해당 월의 마지막 날짜 if (day < '01' || parseInt(day, 10) > daysInMonth) { return false } + // 미래 날짜인 경우 + const inputDate = new Date( + `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`, + ) + const today = new Date() + today.setHours(0, 0, 0, 0) + + if (inputDate > today) { + return false + } + return true }