diff --git a/src/pages/form/ideal_partner/IdealPartnerPage.module.css b/src/pages/form/ideal_partner/IdealPartnerPage.module.css new file mode 100644 index 0000000..aedfc21 --- /dev/null +++ b/src/pages/form/ideal_partner/IdealPartnerPage.module.css @@ -0,0 +1,44 @@ +.Container { + display: flex; + flex-direction: column; + height: 100%; +} + +.Header { + margin-bottom: 30px; +} + +.HeaderBar { + margin-bottom: 15px; + height: 44px; + display: flex; + justify-content: space-between; + align-items: center; + + font-weight: 500; + font-size: 16px; + color: var(--color-neutral-40); +} + +.Description { + display: block; + margin-top: 10px; + font-weight: 500; + font-size: 14px; + line-height: 24px; + color: var(--color-neutral-50); + + & strong { + font-size: 14px; + } +} + +.Main { + flex-grow: 1; + overflow-y: auto; +} + +.Footer { + margin-top: auto; + padding: 15px 0; +} \ No newline at end of file diff --git a/src/pages/form/ideal_partner/IdealPartnerPage.stories.tsx b/src/pages/form/ideal_partner/IdealPartnerPage.stories.tsx new file mode 100644 index 0000000..d29c9a6 --- /dev/null +++ b/src/pages/form/ideal_partner/IdealPartnerPage.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { IdealPartnerPage } from 'src/pages/form/ideal_partner/IdealPartnerPage'; + +const meta: Meta = { + component: IdealPartnerPage, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, + decorators: (fn) =>
{fn()}
, +}; diff --git a/src/pages/form/ideal_partner/IdealPartnerPage.tsx b/src/pages/form/ideal_partner/IdealPartnerPage.tsx new file mode 100644 index 0000000..ab43ffb --- /dev/null +++ b/src/pages/form/ideal_partner/IdealPartnerPage.tsx @@ -0,0 +1,43 @@ +import { useState } from 'react'; +import { useProfileFirstName } from 'src/entities/profile/lib/useProfileFirstName'; +import styles from './IdealPartnerPage.module.css'; +import { ArrowLeft } from 'src/shared/ui/icons'; +import { Button } from 'src/shared/ui/Button/Button'; +import { IdealPartnerStepMeta } from 'src/pages/form/ideal_partner/IdealPartnerStepMeta'; +import { useIdlePartnerStore } from 'src/entities/ideal_partner/model/idealPartnerStore'; + +const Steps = Object.values(IdealPartnerStepMeta); +export const IdealPartnerPage = () => { + const [currentStepIdx, setCurrentStep] = useState(0); + const name = useProfileFirstName(); + + const currentStep = Steps[currentStepIdx]; + const canGoNext = useIdlePartnerStore(currentStep.canGoNext); + + return ( +
+
+
+ setCurrentStep((prev) => Math.max(0, prev - 1))} /> + + {currentStepIdx + 1}/{Steps.length} + +
+

{currentStep.title({ name })}

+ {currentStep.description && {currentStep.description()}} +
+
{currentStep.form}
+
+ +
+
+ ); +}; diff --git a/src/pages/form/ideal_partner/IdealPartnerStepMeta.tsx b/src/pages/form/ideal_partner/IdealPartnerStepMeta.tsx new file mode 100644 index 0000000..1866efb --- /dev/null +++ b/src/pages/form/ideal_partner/IdealPartnerStepMeta.tsx @@ -0,0 +1,94 @@ +import { StepMeta } from 'src/shared/types/FormStepMeta'; +import { AgeForm } from 'src/processes/ideal_partner/AgeForm/AgeForm'; +import { IdealPartner } from 'src/entities/ideal_partner/model/idealPartnerStore'; +import { HeightStyleForm } from 'src/processes/ideal_partner/HeightStyleForm/HeightStyleForm'; +import { LocationForm } from 'src/processes/ideal_partner/LocationForm/LocationForm'; +import { HobbyForm } from 'src/processes/ideal_partner/HobbyForm/HobbyForm'; +import { ReligionForm } from 'src/processes/ideal_partner/ReligionForm/ReligionForm'; +import { DrinkingForm } from 'src/processes/ideal_partner/DrinkingForm/DrinkingForm'; +import { SmokingForm } from 'src/processes/ideal_partner/SmokingForm/SmokingForm'; + +export const IdealPartnerStepMeta: Record> = { + AGE: { + title: () => <>선호하는 연령대는 어떻게 되나요?, + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.ageRange.max && state.ageRange.min), + }, + HEIGHT_STYLE: { + title: () => <>선호하는 키와 스타일을 알려주세요, + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.heightRange.min && state.heightRange.max && state.style), + }, + LOCATION: { + title: ({ name }) => ( + <> + 상대방이 어느 지역에 있어야 +
+ {name}님과 만나기 좋을까요? + + ), + description: () => <>, + form: , + canGoNext: () => true, + }, + HOBBY: { + title: () => ( + <> + 상대방이 어떤 취미생활을 할 때
좀 더 관심이 갈 것 같나요? + + ), + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.hobbies.length > 0), + }, + RELIGION: { + title: () => <>상대방이 어떤 종교이길 희망하시나요?, + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.religion.religionCategory), + }, + DRINKING: { + title: () => ( + <> + 상대방의 음주 빈도는 +
+ 어디까지 이해할 수 있나요? + + ), + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.drinking.drinkingCategory), + }, + SMOKING: { + title: () => <>상대방의 흡연은 괜찮으신가요?, + description: () => <>, + form: , + canGoNext: (state) => Boolean(state.smoking.smokingCategory), + }, + REQUIRED_OPTIONS: { + title: () => ( + <> + 지금까지 입력한 것 중에서, +
+ 포기할 수 없는 조건이 있나요? (최대 3개) + + ), + description: () => <>, + form: <>, + canGoNext: (state) => Boolean(state.requiredOptions.length > 0), + }, + TO_MATCHR: { + title: () => ( + <> + 주선자에게 추가로 말하고 싶은 +
+ 내용이 있다면 입력해주세요. + + ), + description: () => <>, + form: <>, + canGoNext: (state) => Boolean(state.toMatchMaker), + }, +}; diff --git a/src/pages/form/my_profile/MyProfileStepMeta.tsx b/src/pages/form/my_profile/MyProfileStepMeta.tsx index 37cd0c8..b3cd568 100644 --- a/src/pages/form/my_profile/MyProfileStepMeta.tsx +++ b/src/pages/form/my_profile/MyProfileStepMeta.tsx @@ -9,8 +9,9 @@ import { ReligionForm } from 'src/processes/my_profile/ReligionForm/ReligionForm import { HobbyForm } from 'src/processes/my_profile/HobbyForm/HobbyForm'; import { SmokeAlcoholForm } from 'src/processes/my_profile/SmokeAlcoholForm/SmokeAlcoholForm'; import { IntroduceForm } from 'src/processes/my_profile/IntroduceForm/IntroduceForm'; +import { MyProfile } from 'src/entities/profile/model/myProfileStore'; -export const MyProfileStepMeta: Record = { +export const MyProfileStepMeta: Record> = { PERSONAL_INFO: { title: () => ( <> diff --git a/src/processes/ideal_partner/HeightStyleForm/HeightStyleForm.module.css b/src/processes/ideal_partner/HeightStyleForm/HeightStyleForm.module.css index 975af4d..879a550 100644 --- a/src/processes/ideal_partner/HeightStyleForm/HeightStyleForm.module.css +++ b/src/processes/ideal_partner/HeightStyleForm/HeightStyleForm.module.css @@ -1,5 +1,6 @@ .Container { height: 100%; - display: grid; + display: flex; + flex-direction: column; gap: 40px; } \ No newline at end of file diff --git a/src/shared/types/FormStepMeta.ts b/src/shared/types/FormStepMeta.ts index 38659e4..e08956c 100644 --- a/src/shared/types/FormStepMeta.ts +++ b/src/shared/types/FormStepMeta.ts @@ -1,9 +1,8 @@ import { ReactElement, ReactNode } from 'react'; -import { MyProfile } from 'src/entities/profile/model/myProfileStore'; -export type StepMeta = { +export type StepMeta = { title: ({ name }: { name: string }) => ReactNode; description?: () => ReactNode; form: ReactElement; - canGoNext: (state: MyProfile) => boolean; + canGoNext: (state: State) => boolean; };