From da7b63ebd7be9560f5bf567b2af752d89e06db0f Mon Sep 17 00:00:00 2001 From: harry kim <73218463+hanyugeon@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:27:52 +0900 Subject: [PATCH] =?UTF-8?q?[#679]=20[=EB=AA=A8=EC=9E=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1]=20=EB=AA=A8=EC=9E=84=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=8D=BC=EB=84=90=20=EC=A2=85=EB=A3=8C=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#683)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 모임생성 퍼널 종료 버튼 추가 * feat: FunnelBottomActionButton 합성 컴포넌트 작성 * feat: FunnelBottomActionButton 적용 * feat: 모임 생성 종료 Modal 작성 * fix: 모임 생성 모달 종료 옵션을 router.push에서 router.back으로 수정 * feat: StickyFooter 작성 * refactor: 기존의 BottomActionButtond을 StickyFooter로 교체 * fix: LoginBottomActionButton 내부의 link 태그 위치 수정 --- src/app/book/[bookId]/page.tsx | 11 +-- src/app/group/[groupId]/join/page.tsx | 10 ++- .../create/CreateBookGroupFunnel.tsx | 67 ++++++++++++++----- .../steps/EnterTitleStep/EnterTitleStep.tsx | 30 ++++++--- .../SelectJoinTypeStep/SelectJoinTypeStep.tsx | 30 ++++++--- .../steps/SetUpDetailStep/SetUpDetailStep.tsx | 29 +++++--- .../bookGroup/detail/JoinBookGroupButton.tsx | 19 ++++-- src/components/common/BottomActionButton.tsx | 23 ------- .../common/LoginBottomActionButton.tsx | 11 +-- src/components/common/StickyFooter.tsx | 44 ++++++++++++ .../common/BottomActionButton.stories.tsx | 28 -------- src/stories/common/StickyFooter.stories.tsx | 55 +++++++++++++++ 12 files changed, 248 insertions(+), 109 deletions(-) delete mode 100644 src/components/common/BottomActionButton.tsx create mode 100644 src/components/common/StickyFooter.tsx delete mode 100644 src/stories/common/BottomActionButton.stories.tsx create mode 100644 src/stories/common/StickyFooter.stories.tsx diff --git a/src/app/book/[bookId]/page.tsx b/src/app/book/[bookId]/page.tsx index 57f4d2ed..166320fb 100644 --- a/src/app/book/[bookId]/page.tsx +++ b/src/app/book/[bookId]/page.tsx @@ -16,12 +16,13 @@ import { SERVICE_ERROR_MESSAGE } from '@/constants'; import Skeleton from '@/components/common/Skeleton'; import SSRSafeSuspense from '@/components/common/SSRSafeSuspense'; import TopNavigation from '@/components/common/TopNavigation'; -import BottomActionButton from '@/components/common/BottomActionButton'; +import StickyFooter from '@/components/common/StickyFooter'; import LoginBottomActionButton from '@/components/common/LoginBottomActionButton'; import CommentDrawer from '@/components/comment/CommentDrawer'; import BackButton from '@/components/common/BackButton'; import BookInfo, { BookInfoSkeleton } from '@/components/book/detail/BookInfo'; import BookCommentList from '@/components/comment/BookCommentList'; +import Button from '@/components/common/Button'; const BookDetailPage = ({ params: { bookId }, @@ -125,9 +126,11 @@ const AddBookCommentButton = ({ bookId }: { bookId: APIBook['bookId'] }) => { return ( <> - - 코멘트 작성하기 - + + + { - 제출하기 + + + + ); }; diff --git a/src/components/bookGroup/create/CreateBookGroupFunnel.tsx b/src/components/bookGroup/create/CreateBookGroupFunnel.tsx index fa14f2e5..a760f2fe 100644 --- a/src/components/bookGroup/create/CreateBookGroupFunnel.tsx +++ b/src/components/bookGroup/create/CreateBookGroupFunnel.tsx @@ -7,14 +7,17 @@ import type { CreateBookGroupFormValues } from '@/components/bookGroup/create/ty import useCreateBookGroupMutation from '@/queries/group/useCreateBookGroupMutation'; import { useFunnel } from '@/hooks/useFunnel'; +import useDisclosure from '@/hooks/useDisclosure'; import useToast from '@/components/common/Toast/useToast'; import { getTodayDate } from '@/utils/date'; import { isAxiosErrorWithCustomCode } from '@/utils/helpers'; import { SERVICE_ERROR_MESSAGE } from '@/constants'; -import { IconArrowLeft } from '@public/icons'; +import { IconClose } from '@public/icons'; import TopNavigation from '@/components/common/TopNavigation'; import Stepper from '@/components/common/Stepper'; +import Modal from '@/components/common/Modal'; +import Button from '@/components/common/Button'; import { EnterTitleStep, SelectBookStep, @@ -34,7 +37,7 @@ const steps = [ { label: '모임이름' }, { label: '모임정보' }, { label: '가입유형' }, -]; +] as const; const CreateBookGroupFunnel = () => { const router = useRouter(); @@ -44,6 +47,7 @@ const CreateBookGroupFunnel = () => { const stepIndex = FUNNEL_STEPS.indexOf(currentStep); const activeStep = stepIndex !== -1 ? stepIndex : 0; + const { isOpen, onOpen, onClose } = useDisclosure(); const { show: showToast } = useToast(); const { mutate } = useCreateBookGroupMutation(); @@ -58,16 +62,9 @@ const CreateBookGroupFunnel = () => { }, }); - const handleBackButtonClick = () => { - const currentStepIndex = FUNNEL_STEPS.indexOf(currentStep); - - if (currentStepIndex === 0 || currentStepIndex === -1) { - router.back(); - } else { - setStep(FUNNEL_STEPS[currentStepIndex - 1]); - } - - return; + const handleCloseButtonClick = () => { + onClose(); + router.back(); }; const handleCreateGroupSubmit: SubmitHandler< @@ -118,10 +115,16 @@ const CreateBookGroupFunnel = () => { - + + +
@@ -138,16 +141,21 @@ const CreateBookGroupFunnel = () => { setStep('EnterTitle')} /> - setStep('SetUpDetail')} /> + setStep('SelectBook')} + onNextStep={() => setStep('SetUpDetail')} + /> setStep('SelectBook')} + onPrevStep={() => setStep('EnterTitle')} onNextStep={() => setStep('SelectJoinType')} + goToSelectBookStep={() => setStep('SelectBook')} /> setStep('SetUpDetail')} onSubmit={methods.handleSubmit(handleCreateGroupSubmit)} /> @@ -158,3 +166,32 @@ const CreateBookGroupFunnel = () => { }; export default CreateBookGroupFunnel; + +const FunnelCloseModal = ({ + isOpen, + onClose, + handleSubmit, +}: { + isOpen: boolean; + onClose?: () => void; + handleSubmit?: () => void; +}) => { + return ( + onClose?.()}> +
+ 독서모임 만들기를 그만할까요? +

+ 작성한 내용은 저장되지 않아요. +

+
+
+ + +
+
+ ); +}; diff --git a/src/components/bookGroup/create/steps/EnterTitleStep/EnterTitleStep.tsx b/src/components/bookGroup/create/steps/EnterTitleStep/EnterTitleStep.tsx index 532808b5..52cd9aa9 100644 --- a/src/components/bookGroup/create/steps/EnterTitleStep/EnterTitleStep.tsx +++ b/src/components/bookGroup/create/steps/EnterTitleStep/EnterTitleStep.tsx @@ -6,9 +6,10 @@ import type { EnterTitleStepFormValues } from '@/components/bookGroup/create/typ import useRemoveVerticalScroll from '@/hooks/useRemoveVerticalScroll'; import { TitleField } from '@/components/bookGroup/create/steps/EnterTitleStep/fields'; -import BottomActionButton from '@/components/common/BottomActionButton'; +import StickyFooter from '@/components/common/StickyFooter'; +import Button from '@/components/common/Button'; -const EnterTitleStep = ({ onNextStep }: MoveFunnelStepProps) => { +const EnterTitleStep = ({ onPrevStep, onNextStep }: MoveFunnelStepProps) => { const { handleSubmit, formState: { isValid }, @@ -25,13 +26,24 @@ const EnterTitleStep = ({ onNextStep }: MoveFunnelStepProps) => { - onNextStep?.())} - > - 다음 - + + + + ); }; diff --git a/src/components/bookGroup/create/steps/SelectJoinTypeStep/SelectJoinTypeStep.tsx b/src/components/bookGroup/create/steps/SelectJoinTypeStep/SelectJoinTypeStep.tsx index 4ef50567..5fd12ea6 100644 --- a/src/components/bookGroup/create/steps/SelectJoinTypeStep/SelectJoinTypeStep.tsx +++ b/src/components/bookGroup/create/steps/SelectJoinTypeStep/SelectJoinTypeStep.tsx @@ -7,12 +7,13 @@ import { JoinPasswordFieldset, JoinTypeFieldset, } from '@/components/bookGroup/create/steps/SelectJoinTypeStep/fields'; -import BottomActionButton from '@/components/common/BottomActionButton'; +import StickyFooter from '@/components/common/StickyFooter'; +import Button from '@/components/common/Button'; export type JoinTypeStepFieldName = keyof SelectJoinTypeStepFormValues; export type JoinTypeStepFieldProp = { name: JoinTypeStepFieldName }; -const SelectJoinTypeStep = ({ onSubmit }: MoveFunnelStepProps) => { +const SelectJoinTypeStep = ({ onPrevStep, onSubmit }: MoveFunnelStepProps) => { const { handleSubmit, formState: { isValid }, @@ -35,13 +36,24 @@ const SelectJoinTypeStep = ({ onSubmit }: MoveFunnelStepProps) => { - - 독서모임 만들기 - + + + + ); }; diff --git a/src/components/bookGroup/create/steps/SetUpDetailStep/SetUpDetailStep.tsx b/src/components/bookGroup/create/steps/SetUpDetailStep/SetUpDetailStep.tsx index d0f08a6e..db8c6d54 100644 --- a/src/components/bookGroup/create/steps/SetUpDetailStep/SetUpDetailStep.tsx +++ b/src/components/bookGroup/create/steps/SetUpDetailStep/SetUpDetailStep.tsx @@ -7,7 +7,6 @@ import { MAX_MEMBER_COUNT_OPTIONS } from '@/constants'; import { getTodayDate } from '@/utils/date'; import withScrollLockOnFocus from '@/hocs/withScrollLockOnFocus'; -import BottomActionButton from '@/components/common/BottomActionButton'; import DatePicker from '@/components/common/DatePicker'; import ErrorMessage from '@/components/common/ErrorMessage'; import Input from '@/components/common/Input'; @@ -16,6 +15,8 @@ import RadioButton from '@/components/common/RadioButton'; import Switch from '@/components/common/Switch'; import TextArea from '@/components/common/TextArea'; import BookInfoCard from '@/components/bookGroup/BookInfoCard'; +import StickyFooter from '@/components/common/StickyFooter'; +import Button from '@/components/common/Button'; interface SetUpDetailStepProps extends MoveFunnelStepProps { goToSelectBookStep?: () => void; @@ -28,6 +29,7 @@ interface SetUpDetailStepProps extends MoveFunnelStepProps { const SetUpDetailStep = ({ goToSelectBookStep, + onPrevStep, onNextStep, }: SetUpDetailStepProps) => { const { @@ -56,13 +58,24 @@ const SetUpDetailStep = ({ - onNextStep?.())} - > - 다음 - + + + + ); }; diff --git a/src/components/bookGroup/detail/JoinBookGroupButton.tsx b/src/components/bookGroup/detail/JoinBookGroupButton.tsx index 95457fe6..43191ff5 100644 --- a/src/components/bookGroup/detail/JoinBookGroupButton.tsx +++ b/src/components/bookGroup/detail/JoinBookGroupButton.tsx @@ -1,7 +1,8 @@ import { usePathname, useRouter } from 'next/navigation'; import useJoinBookGroup from '@/hooks/group/useJoinBookGroup'; -import BottomActionButton from '@/components/common/BottomActionButton'; +import StickyFooter from '@/components/common/StickyFooter'; +import Button from '@/components/common/Button'; const JoinBookGroupButton = ({ groupId }: { groupId: number }) => { const router = useRouter(); @@ -24,16 +25,20 @@ const JoinBookGroupButton = ({ groupId }: { groupId: number }) => { if (isExpired) { return ( - - 모임이 종료되었어요. - + + + ); } return ( - - 참여하기 - + + + ); }; diff --git a/src/components/common/BottomActionButton.tsx b/src/components/common/BottomActionButton.tsx deleted file mode 100644 index 1e5b3e5e..00000000 --- a/src/components/common/BottomActionButton.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentPropsWithoutRef } from 'react'; - -import Button from '@/components/common/Button'; - -type BottomActionButtonProps = Omit< - ComponentPropsWithoutRef, - 'className' ->; - -const BottomActionButton = ({ - children, - ...props -}: BottomActionButtonProps) => { - return ( -
- -
- ); -}; - -export default BottomActionButton; diff --git a/src/components/common/LoginBottomActionButton.tsx b/src/components/common/LoginBottomActionButton.tsx index d1241956..84ce687f 100644 --- a/src/components/common/LoginBottomActionButton.tsx +++ b/src/components/common/LoginBottomActionButton.tsx @@ -1,10 +1,13 @@ -import BottomActionButton from '@/components/common/BottomActionButton'; +import StickyFooter from '@/components/common/StickyFooter'; import LoginLink from '@/components/common/LoginLink'; +import Button from '@/components/common/Button'; const LoginBottomActionButton = () => ( - - 로그인 및 회원가입 - + + + + + ); export default LoginBottomActionButton; diff --git a/src/components/common/StickyFooter.tsx b/src/components/common/StickyFooter.tsx new file mode 100644 index 00000000..bdc6f9a1 --- /dev/null +++ b/src/components/common/StickyFooter.tsx @@ -0,0 +1,44 @@ +import { useMemo } from 'react'; + +type Direction = 'row' | 'column'; + +type StickyFooterProps = { + children?: React.ReactNode; + direction?: Direction; + className?: string; +}; + +const getDirectionClass = (direction: Direction) => { + switch (direction) { + case 'row': { + return 'flex-row'; + } + case 'column': { + return 'flex-col'; + } + } +}; + +const BASE_STICKY_FOOTER_CLASSES = + 'fixed bottom-0 left-0 right-0 z-10 mx-auto flex w-full max-w-[43rem] gap-[0.8rem] bg-white px-[2.0rem] pb-[calc(env(safe-area-inset-bottom)+1.5rem)] pt-[1.5rem]'; + +const StickyFooter = ({ + children, + direction = 'row', + className, +}: StickyFooterProps) => { + const directionClass = useMemo( + () => getDirectionClass(direction), + [direction] + ); + + return ( +
+ {children} +
+ ); +}; + +export default StickyFooter; diff --git a/src/stories/common/BottomActionButton.stories.tsx b/src/stories/common/BottomActionButton.stories.tsx deleted file mode 100644 index cee9d753..00000000 --- a/src/stories/common/BottomActionButton.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import BottomActionButton from '@/components/common/BottomActionButton'; -import { Meta, StoryObj } from '@storybook/react'; - -const meta: Meta = { - title: 'Common/BottomActionButton', - component: BottomActionButton, - tags: ['autodocs'], - parameters: { - docs: { - story: { - inline: false, - }, - }, - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - args: {}, - render: () => ( - alert('click!')}> - 다음 - - ), -}; diff --git a/src/stories/common/StickyFooter.stories.tsx b/src/stories/common/StickyFooter.stories.tsx new file mode 100644 index 00000000..3ed9153c --- /dev/null +++ b/src/stories/common/StickyFooter.stories.tsx @@ -0,0 +1,55 @@ +import Button from '@/components/common/Button'; +import StickyFooter from '@/components/common/StickyFooter'; +import { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + title: 'Common/StickyFooter', + component: StickyFooter, + tags: ['autodocs'], + parameters: { + docs: { + story: { + inline: false, + }, + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, + render: () => ( + + + + ), +}; + +export const Row: Story = { + args: { direction: 'row' }, + render: args => ( + + + + + ), +}; + +export const Column: Story = { + args: { direction: 'column' }, + render: args => ( + + + + + ), +};