@@ -152,8 +161,8 @@ export default function Sub() {
type="text"
id="extra-info"
className={styles.form__input}
- onChange={(e) => setDescription(e.target.value)}
value={description}
+ {...register('description')}
/>
@@ -161,9 +170,9 @@ export default function Sub() {
setDelivery(e.target.checked)}
className={styles['form__checkbox-input']}
checked={delivery}
+ {...register('delivery')}
/>
배달 가능
@@ -171,9 +180,9 @@ export default function Sub() {
setPayCard(e.target.checked)}
className={styles['form__checkbox-input']}
checked={payCard}
+ {...register('pay_card')}
/>
카드 가능
@@ -181,9 +190,9 @@ export default function Sub() {
setPayBank(e.target.checked)}
className={styles['form__checkbox-input']}
checked={payBank}
+ {...register('pay_bank')}
/>
계좌이체 가능
diff --git a/src/page/ShopRegistration/view/Mobile/index.tsx b/src/page/ShopRegistration/view/Mobile/index.tsx
index aed91226..00be4503 100644
--- a/src/page/ShopRegistration/view/Mobile/index.tsx
+++ b/src/page/ShopRegistration/view/Mobile/index.tsx
@@ -1,58 +1,149 @@
-/* eslint-disable jsx-a11y/label-has-associated-control */
-import PreviousStep from 'component/common/Auth/PreviousStep';
-import ProgressBar from 'component/common/Auth/ProgressBar';
-import Complete from 'component/common/Auth/Complete';
-import SubTitle from 'component/common/Auth/SubTitle';
-import useStepStore from 'store/useStepStore';
+import PreviousStep from 'component/Auth/PreviousStep';
+import ProgressBar from 'component/Auth/ProgressBar';
+import Complete from 'component/Auth/Complete';
+import SubTitle from 'component/Auth/SubTitle';
import PROGRESS_TITLE from 'utils/constant/progress';
import ShopEntry from 'page/ShopRegistration/view/Mobile/ShopEntry';
import ShopCategory from 'page/ShopRegistration/view/Mobile/ShopCategory';
import Main from 'page/ShopRegistration/view/Mobile/Main';
import Sub from 'page/ShopRegistration/view/Mobile/Sub';
import ShopConfirmation from 'page/ShopRegistration/view/Mobile/ShopConfirmation';
+import { useFunnel } from 'utils/hooks/useFunnel';
+import { FormProvider, useForm } from 'react-hook-form';
import styles from './ShopRegistrationMobile.module.scss';
+const OPEN_DEFAULT_VALUES = [
+ {
+ day_of_week: 'MONDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'TUESDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'WEDNESDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'THURSDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'FRIDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'SATURDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'SUNDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+];
+
export default function ShopRegistrationMobile() {
- const { TOTAL_STEP, step, decreaseStep } = useStepStore();
- // 임시로 step 0 일때 뒤로가기 버튼 삭제
+ const {
+ Funnel, Step, setStep, currentStep,
+ } = useFunnel('가게 등록');
+
+ const currentIndex = PROGRESS_TITLE.findIndex((step) => step.title === currentStep);
+
+ const decreaseStep = () => {
+ if (currentIndex > 0) {
+ setStep(PROGRESS_TITLE[currentIndex - 1].title);
+ }
+ };
+
+ const methods = useForm({
+ defaultValues: {
+ category_ids: [],
+ delivery_price: 0,
+ description: '',
+ image_urls: [],
+ name: '',
+ phone: '',
+ address: '',
+ delivery: false,
+ pay_bank: false,
+ pay_card: false,
+ open: OPEN_DEFAULT_VALUES,
+ },
+ });
+
return (
-
- {step !== 0 &&
}
+
+ {currentStep !== '가게 등록' && }
- {step === 0 &&
}
- {step === 1 && (
- <>
-
-
-
- >
- )}
- {step === 2 && (
- <>
-
-
-
- >
- )}
- {step === 3 && (
- <>
-
-
-
- >
- )}
- {step === 4 && (
- <>
-
-
-
-
- >
- )}
- {step === 5 && (
-
- )}
+
+
+ setStep('가게 카테고리 설정')} />
+
+
+ <>
+
+
+ setStep('메인 정보 입력')} />
+ >
+
+
+ <>
+
+
+ setStep('세부 정보 입력')} />
+ >
+
+
+ <>
+
+
+ setStep('가게 정보 확인')} />
+ >
+
+
+ <>
+
+
+
+ setStep('가게 등록 완료')} />
+ >
+
+
+
+
+
-
+
);
}
diff --git a/src/page/ShopRegistration/view/PC/ShopConfirmation/ShopConfirmation.module.scss b/src/page/ShopRegistration/view/PC/ShopConfirmation/ShopConfirmation.module.scss
new file mode 100644
index 00000000..9a4972c4
--- /dev/null
+++ b/src/page/ShopRegistration/view/PC/ShopConfirmation/ShopConfirmation.module.scss
@@ -0,0 +1,177 @@
+.wrapper {
+ position: relative;
+}
+
+.container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 80px 0 94px;
+
+ &__koin-logo {
+ width: 368px;
+ position: relative;
+ margin-bottom: 56px;
+ background-color: #ffffff;
+ }
+}
+
+.form {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 16px;
+
+ &__title {
+ display: block;
+ font-size: 18px;
+ margin-bottom: 8px;
+ }
+
+ &__image-upload {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 210px;
+ height: 93px;
+ border: 1px solid #d2dae2;
+ padding: 53px 80px 54px;
+ cursor: pointer;
+
+ &--active {
+ display: flex;
+ flex-direction: column;
+ padding: 10px 20px;
+ width: 340px;
+ height: 180px;
+ }
+ }
+
+ &__upload-file {
+ display: none;
+ }
+
+ &__main-menu {
+ max-width: 370px;
+ max-height: 200px;
+ }
+
+ &__main-item {
+ max-width: 370px;
+ display: flex;
+ }
+
+ &__main-text {
+ width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ word-break: break-all;
+ color: #858585;
+ }
+
+ &__cutlery-cross {
+ width: 64px;
+ height: 64px;
+ margin: 0 auto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ }
+
+ &__text {
+ text-align: center;
+ font-size: 14px;
+ display: block;
+ color: #858585;
+ margin-top: 8px;
+ }
+
+ &__section {
+ display: flex;
+ justify-content: space-between;
+ gap: 16px;
+ margin-top: 8px;
+ }
+
+ &__input {
+ width: 240px;
+ border: 1px solid #d2dae2;
+ height: 22px;
+ padding: 13px 16px;
+
+ &:focus {
+ border-bottom: 1px solid black;
+ }
+ }
+
+ &__input-large {
+ width: 336px;
+ border: 1px solid #d2dae2;
+ height: 22px;
+ padding: 13px 16px;
+
+ &:focus {
+ border-bottom: 1px solid black;
+ }
+ }
+
+ &__operate-time {
+ display: flex;
+ align-items: center;
+ width: 272px;
+ height: auto;
+ font-size: 16px;
+ color: #858585;
+ }
+
+ &__checkbox {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ gap: 24px;
+ width: 368px;
+ }
+
+ &__checkbox-label {
+ display: flex;
+ align-items: center;
+ font-weight: 500;
+ font-size: 14px;
+ color: #858585;
+ box-sizing: content-box;
+ cursor: pointer;
+
+ input[type="checkbox"]:checked + span {
+ color: #f7941e;
+ }
+ }
+
+ &__checkbox-input {
+ appearance: none;
+ width: 14px;
+ height: 14px;
+ border-radius: 100%;
+ box-sizing: border-box;
+ border: 1px solid #858585;
+ margin-right: 8px;
+ background-size: cover;
+ cursor: pointer;
+
+ &:checked {
+ border: 2px solid #f7941e;
+ padding: 1px;
+ background-clip: content-box;
+ background-color: #f7941e;
+ }
+ }
+
+ &__next-button {
+ width: 368px;
+ margin-top: 56px;
+ }
+}
diff --git a/src/page/ShopRegistration/view/PC/ShopConfirmation/index.tsx b/src/page/ShopRegistration/view/PC/ShopConfirmation/index.tsx
new file mode 100644
index 00000000..2efe31d6
--- /dev/null
+++ b/src/page/ShopRegistration/view/PC/ShopConfirmation/index.tsx
@@ -0,0 +1,370 @@
+import { ReactComponent as Logo } from 'assets/svg/auth/koin-logo.svg';
+import { ReactComponent as Cutlery } from 'assets/svg/shopRegistration/cutlery.svg';
+import Copyright from 'component/common/Copyright';
+import CustomButton from 'page/Auth/Signup/component/CustomButton';
+import Category from 'page/ShopRegistration/component/Modal/Category';
+import SearchShop from 'page/ShopRegistration/component/Modal/SearchShop';
+import OperateTimePC from 'page/ShopRegistration/component/Modal/OperateTimePC';
+import ConfirmPopup from 'page/ShopRegistration/component/ConfirmPopup';
+import CustomModal from 'component/common/CustomModal';
+import cn from 'utils/ts/className';
+import useModalStore from 'store/modalStore';
+import { WEEK } from 'utils/constant/week';
+import { SubmitHandler, useFormContext, useWatch } from 'react-hook-form';
+import { OwnerShop } from 'model/shopInfo/ownerShop';
+import useImagesUpload from 'utils/hooks/useImagesUpload';
+import CheckSameTime from 'page/ShopRegistration/hooks/CheckSameTime';
+import useOperateTimeState from 'page/ShopRegistration/hooks/useOperateTimeState';
+import ErrorMessage from 'component/common/ErrorMessage';
+import { ERRORMESSAGE } from 'page/ShopRegistration/constant/errorMessage';
+import { usePostData } from 'page/ShopRegistration/view/Mobile/ShopConfirmation/index';
+import { ReactComponent as FileImage } from 'assets/svg/auth/default-file.svg';
+import useMyShop from 'query/shop';
+import { useEffect, useState } from 'react';
+import useBooleanState from 'utils/hooks/useBooleanState';
+import useStoreTimeSetUp from 'page/ShopRegistration/hooks/useStoreTimeSetUp';
+import styles from './ShopConfirmation.module.scss';
+
+export default function ShopConfirmation({ onNext }:{ onNext: () => void }) {
+ const {
+ value: showCategory,
+ setTrue: openCategory,
+ setFalse: closeCategory,
+ } = useBooleanState(false);
+ const {
+ value: showOperateTime,
+ setTrue: openOperateTime,
+ setFalse: closeOperateTime,
+ } = useBooleanState(false);
+ const {
+ value: showSearchShop,
+ setTrue: openSearchShop,
+ setFalse: closeSearchShop,
+ } = useBooleanState(false);
+ const {
+ value: showConfirmPopup,
+ setTrue: openConfirmPopup,
+ setFalse: closeConfirmPopup,
+ } = useBooleanState(false);
+
+ const { shopClosedState } = useModalStore();
+
+ const {
+ isAllSameTime,
+ hasClosedDay,
+ isSpecificDayClosedAndAllSameTime,
+ isAllClosed,
+ } = CheckSameTime();
+
+ const { categoryList } = useMyShop();
+
+ const {
+ register, control, setValue, handleSubmit, formState: { errors },
+ } = useFormContext
();
+
+ const {
+ imageFile, imgRef, saveImgFile, uploadError, setImageFile,
+ } = useImagesUpload();
+
+ const [isError, setIsError] = useState(false);
+
+ const operateTimeState = useOperateTimeState();
+
+ const imageUrls = useWatch({ control, name: 'image_urls' });
+ const name = useWatch({ control, name: 'name' });
+ const categoryId = useWatch({ control, name: 'category_ids' });
+ const phone = useWatch({ control, name: 'phone' });
+ const address = useWatch({ control, name: 'address' });
+ const deliveryPrice = useWatch({ control, name: 'delivery_price' });
+ const description = useWatch({ control, name: 'description' });
+ const delivery = useWatch({ control, name: 'delivery' });
+ const payCard = useWatch({ control, name: 'pay_card' });
+ const payBank = useWatch({ control, name: 'pay_bank' });
+ const selectedId = categoryList?.shop_categories[categoryId[0] - 1]?.name;
+
+ useStoreTimeSetUp({ setValue });
+
+ const formatPhoneNumber = (inputNumber: string) => {
+ const phoneNumber = inputNumber.replace(/\D/g, '');
+ const formattedPhoneNumber = phoneNumber.replace(/^(\d{3})(\d{4})(\d{4})$/, '$1-$2-$3');
+ return formattedPhoneNumber;
+ };
+
+ const handlePhoneChange = (e: React.ChangeEvent) => {
+ const formattedValue = formatPhoneNumber(e.target.value);
+ setValue('phone', formattedValue);
+ };
+
+ const handleNextClick = () => {
+ if (imageUrls.length === 0 || name === '' || categoryId.length === 0
+ || address === '' || phone === '') {
+ setIsError(true);
+ } else {
+ setIsError(false);
+ openConfirmPopup();
+ }
+ };
+
+ const handleDeleteImage = (e: React.MouseEvent, imageUrl: string) => {
+ e.preventDefault();
+ setImageFile(imageFile.filter((img) => img !== imageUrl));
+ };
+
+ useEffect(() => {
+ if (imageFile.length > 0) {
+ setValue('image_urls', imageFile);
+ }
+ }, [imageFile, setValue]);
+
+ const mutation = usePostData({ onNext });
+
+ const onSubmit: SubmitHandler = (data) => {
+ mutation.mutate(data);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/page/ShopRegistration/view/PC/ShopEntry/ShopEntry.module.scss b/src/page/ShopRegistration/view/PC/ShopEntry/ShopEntry.module.scss
new file mode 100644
index 00000000..a2f11362
--- /dev/null
+++ b/src/page/ShopRegistration/view/PC/ShopEntry/ShopEntry.module.scss
@@ -0,0 +1,56 @@
+.wrapper {
+ position: relative;
+}
+
+.block {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ &__writing-icon {
+ margin-bottom: 72px;
+ }
+
+ &__title {
+ display: block;
+ text-align: center;
+ font-size: 36px;
+ font-weight: 700;
+ color: #175c8e;
+ margin-bottom: 24px;
+ height: 53px;
+ }
+
+ &__text {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+ text-align: center;
+ font-size: 16px;
+ font-weight: 400;
+ margin-bottom: 80px;
+ color: #858585;
+
+ span {
+ line-height: 180%;
+ }
+ }
+
+ &__next-button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 368px;
+ height: 48px;
+ font-weight: 500;
+ color: #ffffff;
+ background-color: #175c8e;
+ text-decoration: none;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+}
diff --git a/src/page/ShopRegistration/view/PC/ShopEntry/index.tsx b/src/page/ShopRegistration/view/PC/ShopEntry/index.tsx
new file mode 100644
index 00000000..fe3a9dd3
--- /dev/null
+++ b/src/page/ShopRegistration/view/PC/ShopEntry/index.tsx
@@ -0,0 +1,29 @@
+import { ReactComponent as Memo } from 'assets/svg/shopRegistration/memo.svg';
+import Copyright from 'component/common/Copyright';
+import styles from './ShopEntry.module.scss';
+
+export default function ShopEntry({ onNext }:{ onNext: () => void }) {
+ return (
+
+
+
+
가게 정보 기입
+
+
+ 가게의 다양한 정보를 입력 및 수정하여
+
+ 학생들에게 최신 가게 정보를 알려주세요
+
+
+
+
+
+
+ );
+}
diff --git a/src/page/ShopRegistration/view/PC/ShopRegistrationPC.module.scss b/src/page/ShopRegistration/view/PC/ShopRegistrationPC.module.scss
index a5f3393c..d5b080d2 100644
--- a/src/page/ShopRegistration/view/PC/ShopRegistrationPC.module.scss
+++ b/src/page/ShopRegistration/view/PC/ShopRegistrationPC.module.scss
@@ -1,238 +1,3 @@
-input::-webkit-outer-spin-button,
-input::-webkit-inner-spin-button {
- appearance: none;
- margin: 0;
-}
-
.wrapper {
position: relative;
}
-
-.block {
- height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-
- &__writing-icon {
- margin-bottom: 72px;
- }
-
- &__title {
- display: block;
- text-align: center;
- font-size: 36px;
- font-weight: 700;
- color: #175c8e;
- margin-bottom: 24px;
- height: 53px;
- }
-
- &__text {
- display: flex;
- flex-direction: column;
- gap: 5px;
- text-align: center;
- font-size: 16px;
- font-weight: 400;
- margin-bottom: 80px;
- color: #858585;
-
- span {
- line-height: 180%;
- }
- }
-
- &__next-button {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 368px;
- height: 48px;
- font-weight: 500;
- color: #ffffff;
- background-color: #175c8e;
- text-decoration: none;
-
- &:hover {
- cursor: pointer;
- }
- }
-}
-
-.container {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 80px 0 94px;
-
- &__koin-logo {
- width: 368px;
- position: relative;
- margin-bottom: 56px;
- background-color: #ffffff;
- }
-}
-
-.form {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 16px;
-
- &__title {
- display: block;
- font-size: 18px;
- margin-bottom: 8px;
- }
-
- &__image-upload {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- width: 210px;
- height: 93px;
- border: 1px solid #d2dae2;
- padding: 53px 80px 54px;
- cursor: pointer;
-
- &--active {
- display: flex;
- flex-direction: column;
- padding: 10px 20px;
- width: 340px;
- height: 180px;
- justify-content: flex-start;
- }
- }
-
- &__upload-file {
- display: none;
- }
-
- &__main-menu {
- max-width: 370px;
- max-height: 200px;
- }
-
- &__main-item {
- max-width: 370px;
- display: flex;
- z-index: 99;
- }
-
- &__main-text {
- width: 90%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- word-break: break-all;
- color: #858585;
- }
-
- &__cutlery-cross {
- width: 64px;
- height: 64px;
- margin: 0 auto;
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- }
-
- &__text {
- text-align: center;
- font-size: 14px;
- display: block;
- color: #858585;
- margin-top: 8px;
- }
-
- &__section {
- display: flex;
- justify-content: space-between;
- gap: 16px;
- margin-top: 8px;
- }
-
- &__input {
- width: 240px;
- border: 1px solid #d2dae2;
- height: 22px;
- padding: 13px 16px;
-
- &:focus {
- border-bottom: 1px solid black;
- }
- }
-
- &__input-large {
- width: 336px;
- border: 1px solid #d2dae2;
- height: 22px;
- padding: 13px 16px;
-
- &:focus {
- border-bottom: 1px solid black;
- }
- }
-
- &__operate-time {
- display: flex;
- align-items: center;
- width: 272px;
- height: auto;
- font-size: 16px;
- color: #858585;
- }
-
- &__checkbox {
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- gap: 24px;
- width: 368px;
- }
-
- &__checkbox-label {
- display: flex;
- align-items: center;
- font-weight: 500;
- font-size: 14px;
- color: #858585;
- box-sizing: content-box;
- cursor: pointer;
-
- input[type="checkbox"]:checked + span {
- color: #f7941e;
- }
- }
-
- &__checkbox-input {
- appearance: none;
- width: 14px;
- height: 14px;
- border-radius: 100%;
- box-sizing: border-box;
- border: 1px solid #858585;
- margin-right: 8px;
- background-size: cover;
- cursor: pointer;
-
- &:checked {
- border: 2px solid #f7941e;
- padding: 1px;
- background-clip: content-box;
- background-color: #f7941e;
- }
- }
-
- &__next-button {
- width: 368px;
- margin-top: 56px;
- }
-}
diff --git a/src/page/ShopRegistration/view/PC/index.tsx b/src/page/ShopRegistration/view/PC/index.tsx
index 55c57315..243c92c7 100644
--- a/src/page/ShopRegistration/view/PC/index.tsx
+++ b/src/page/ShopRegistration/view/PC/index.tsx
@@ -1,458 +1,71 @@
-/* eslint-disable react-hooks/exhaustive-deps */
-import { ReactComponent as Memo } from 'assets/svg/shopRegistration/memo.svg';
-import { ReactComponent as Logo } from 'assets/svg/auth/koin-logo.svg';
-import { ReactComponent as Cutlery } from 'assets/svg/shopRegistration/cutlery.svg';
-import { useEffect, useState } from 'react';
-import useStepStore from 'store/useStepStore';
import Copyright from 'component/common/Copyright';
-import CustomButton from 'page/Auth/Signup/CustomButton';
-import Complete from 'component/common/Auth/Complete';
-import Category from 'page/ShopRegistration/component/Modal/Category';
-import SearchShop from 'page/ShopRegistration/component/Modal/SearchShop';
-import OperateTimePC from 'page/ShopRegistration/component/Modal/OperateTimePC';
-import ConfirmPopup from 'page/ShopRegistration/component/ConfirmPopup';
-import useMediaQuery from 'utils/hooks/useMediaQuery';
-import useBooleanState from 'utils/hooks/useBooleanState';
-import CustomModal from 'component/common/CustomModal';
-import cn from 'utils/ts/className';
-import useModalStore from 'store/modalStore';
-import { WEEK, DAY_OF_WEEK } from 'utils/constant/week';
-import { SubmitHandler, useForm } from 'react-hook-form';
-import { zodResolver } from '@hookform/resolvers/zod';
+import Complete from 'component/Auth/Complete';
+import { FormProvider, useForm } from 'react-hook-form';
import { OwnerShop } from 'model/shopInfo/ownerShop';
-import useImagesUpload from 'utils/hooks/useImagesUpload';
-import CheckSameTime from 'page/ShopRegistration/hooks/CheckSameTime';
-import useOperateTimeState from 'page/ShopRegistration/hooks/useOperateTimeState';
-import useShopRegistrationStore from 'store/shopRegistration';
-import ErrorMessage from 'page/Auth/Signup/ErrorMessage';
-import { ERRORMESSAGE } from 'page/ShopRegistration/constant/errorMessage';
-import { usePostData } from 'page/ShopRegistration/view/Mobile/ShopConfirmation/index';
-import { ReactComponent as FileImage } from 'assets/svg/auth/default-file.svg';
+import { useFunnel } from 'utils/hooks/useFunnel';
import styles from './ShopRegistrationPC.module.scss';
+import ShopEntry from './ShopEntry';
+import ShopConfirmation from './ShopConfirmation';
-export default function ShopRegistrationPC() {
- const { isMobile } = useMediaQuery();
- const { step, setStep } = useStepStore();
- const {
- value: showCategory,
- setTrue: openCategory,
- setFalse: closeCategory,
- changeValue: toggleCategory,
- } = useBooleanState(false);
- const {
- value: showOperateTime,
- setTrue: openOperateTime,
- setFalse: closeOperateTime,
- } = useBooleanState(false);
- const {
- value: showSearchShop,
- setTrue: openSearchShop,
- setFalse: closeSearchShop,
- } = useBooleanState(false);
- const {
- value: showConfirmPopup,
- setTrue: openConfirmPopup,
- setFalse: closeConfirmPopup,
- } = useBooleanState(false);
- const {
- imageFile, imgRef, saveImgFile, uploadError, setImageFile,
- } = useImagesUpload();
- const [isError, setIsError] = useState(false);
-
- const {
- openTimeState,
- closeTimeState,
- shopClosedState,
- } = useModalStore();
-
- const {
- setImageUrls,
- setName,
- setDelivery,
- setPayCard,
- setPayBank,
- setAddress,
- setPhone,
- setDeliveryPrice,
- setDescription,
- removeImageUrl,
- } = useShopRegistrationStore();
-
- const {
- imageUrls,
- categoryId,
- category,
- name,
- delivery,
- payCard,
- payBank,
- address,
- phone,
- deliveryPrice,
- description,
- } = useShopRegistrationStore();
- const operateTimeState = useOperateTimeState();
-
- const {
- isAllSameTime,
- hasClosedDay,
- isSpecificDayClosedAndAllSameTime,
- isAllClosed,
- } = CheckSameTime();
+const OPEN_DEFAULT_VALUES = [
+ {
+ day_of_week: 'MONDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'TUESDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'WEDNESDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'THURSDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'FRIDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'SATURDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+ {
+ day_of_week: 'SUNDAY', closed: false, open_time: '00:00', close_time: '00:00',
+ },
+];
- const mutation = usePostData(setStep);
-
- const {
- register, handleSubmit, setValue, formState: { errors },
- } = useForm({
- resolver: zodResolver(OwnerShop),
+export default function ShopRegistrationPC() {
+ const methods = useForm({
+ defaultValues: {
+ category_ids: [],
+ delivery_price: 0,
+ description: '',
+ image_urls: [],
+ name: '',
+ phone: '',
+ address: '',
+ delivery: false,
+ pay_bank: false,
+ pay_card: false,
+ open: OPEN_DEFAULT_VALUES,
+ },
});
- const formatPhoneNumber = (inputNumber: string) => {
- const phoneNumber = inputNumber.replace(/\D/g, '');
- const formattedPhoneNumber = phoneNumber.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
- if (formattedPhoneNumber.length > 13) return formattedPhoneNumber.slice(0, 13);
- return formattedPhoneNumber;
- };
- const phoneNumberPattern = /^\d{3}-\d{4}-\d{4}$/;
- const isValidPhoneNumber = phoneNumberPattern.test(phone);
- const handleNextClick = () => {
- if (imageUrls.length === 0 || name === '' || category.length === 0
- || address === '' || phone === '' || !isValidPhoneNumber) {
- setIsError(true);
- } else {
- setIsError(false);
- openConfirmPopup();
- }
- };
- const openTimeArray = Object.values(openTimeState);
- const closeTimeArray = Object.values(closeTimeState);
- const shopClosedArray = Object.values(shopClosedState);
-
- const onClickRemoveImageUrl = (e: React.MouseEvent, imageUrl: string) => {
- e.preventDefault();
- setImageFile(imageFile.filter((img) => img !== imageUrl));
- removeImageUrl(imageUrl);
- };
+ const { Funnel, Step, setStep } = useFunnel('가게 등록');
- useEffect(() => {
- if (imageFile.length > 0 || uploadError !== '') setImageUrls(imageFile);
- const openValue = DAY_OF_WEEK.map((day, index) => ({
- close_time: closeTimeArray[index],
- closed: shopClosedArray[index],
- day_of_week: day,
- open_time: openTimeArray[index],
- }));
- setValue('open', openValue);
- setValue('category_ids', [categoryId]);
- setValue('delivery_price', Number(deliveryPrice));
- setValue('name', name);
- setValue('image_urls', imageUrls);
- }, [openTimeState, closeTimeState, shopClosedState, imageUrls,
- imageFile, categoryId, deliveryPrice, uploadError, name]);
- const onSubmit: SubmitHandler = (data) => {
- mutation.mutate(data);
- };
-
- // step 1일 때 그리고 모바일에서 PC로 변경 될 때 카테고리 모달을 자동으로 켜줌
- useEffect(() => {
- if (!isMobile && step === 1) {
- toggleCategory();
- }
- }, [isMobile]);
return (
- <>
- {step === 0 && (
-
-
-
-
가게 정보 기입
-
-
- 가게의 다양한 정보를 입력 및 수정하여
-
- 학생들에게 최신 가게 정보를 알려주세요
-
-
-
-
-
-
- )}
- {step >= 1 && step <= 4 && (
-
-
-
-
+
+
+
+ setStep('가게 정보 입력')} />
+
+
+ setStep('가게 등록 완료')} />
+
+
+
+
+
-
-
- )}
- {step === 5 && (
-
-
-
-
- )}
- >
+
+
+
);
}
diff --git a/src/query/shop.ts b/src/query/shop.ts
index 9ffa59e9..1a3c3c56 100644
--- a/src/query/shop.ts
+++ b/src/query/shop.ts
@@ -4,14 +4,18 @@ import {
import {
getMyShopList, getShopInfo, getMenuInfoList, addMenu, getShopEventList,
} from 'api/shop';
+import { isKoinError } from '@bcsdlab/koin';
+import showToast from 'utils/ts/showToast';
import useAddMenuStore from 'store/addMenu';
import { NewMenu } from 'model/shopInfo/newMenu';
+import { useNavigate } from 'react-router-dom';
import getShopCategory from 'api/category';
import useSuspenseUser from 'utils/hooks/useSuspenseUser';
import { shopKeys } from './KeyFactory/shopKeys';
const useMyShop = () => {
let myShopQueryKey = '';
+ const navigate = useNavigate();
const { data: user } = useSuspenseUser();
if (user && 'company_number' in user) {
myShopQueryKey = user.company_number;
@@ -57,6 +61,12 @@ const useMyShop = () => {
onSuccess: () => {
resetAddMenuStore();
queryClient.invalidateQueries({ queryKey: shopKeys.myMenuInfo(shopId) });
+ navigate('/owner');
+ },
+ onError: (e) => {
+ if (isKoinError(e)) {
+ showToast('error', e.message);
+ }
},
});
diff --git a/src/store/addMenu.ts b/src/store/addMenu.ts
index f166b53e..ac8d3fc4 100644
--- a/src/store/addMenu.ts
+++ b/src/store/addMenu.ts
@@ -1,11 +1,11 @@
import { create } from 'zustand';
import { MonoMenu } from 'model/shopInfo/menuCategory';
-interface OptionPrices {
+export type OptionPrices = {
id: number;
option: string;
price: number;
-}
+};
interface AddMenuStore {
menuId: number;
diff --git a/src/store/modalStore.ts b/src/store/modalStore.ts
index b2bcc5f5..54520f83 100644
--- a/src/store/modalStore.ts
+++ b/src/store/modalStore.ts
@@ -12,8 +12,9 @@ interface ModalStore {
setOpenTimeState: (state: OperatingTime) => void;
setCloseTimeState: (state: OperatingTime) => void;
setShopClosedState: (state: { [key: string]: boolean }) => void;
- setSearchShopState: (state: string) => void; // 수정 요망
- setSelectedShopId:(state:string) => void; // 수정 요망
+ setSearchShopState: (state: string) => void;
+ setSelectedShopId:(state:string) => void;
+ resetOperatingTime: ()=> void;
}
const initialOperatingTime: OperatingTime = {
@@ -40,13 +41,20 @@ const useModalStore = create
((set) => ({
openTimeState: initialOperatingTime,
closeTimeState: initialOperatingTime,
shopClosedState: initialShopClosed,
- searchShopState: '', // 수정 요망
- selectedShopId: '', // 수정 요망
+ searchShopState: '',
+ selectedShopId: '',
setOpenTimeState: (state) => set(() => ({ openTimeState: state })),
setCloseTimeState: (state) => set(() => ({ closeTimeState: state })),
setShopClosedState: (state) => set({ shopClosedState: state }),
- setSearchShopState: (state) => set({ searchShopState: state }), // 수정 요망
- setSelectedShopId: (state) => set({ selectedShopId: state }), // 수정 요망
+ setSearchShopState: (state) => set({ searchShopState: state }),
+ setSelectedShopId: (state) => set({ selectedShopId: state }),
+ resetOperatingTime: () => {
+ set(() => ({
+ openTimeState: initialOperatingTime,
+ closeTimeState: initialOperatingTime,
+ shopClosedState: initialShopClosed,
+ }));
+ },
}));
export default useModalStore;
diff --git a/src/store/shopRegistration.ts b/src/store/shopRegistration.ts
index 0b478eaf..ebb9dda4 100644
--- a/src/store/shopRegistration.ts
+++ b/src/store/shopRegistration.ts
@@ -39,7 +39,7 @@ const useShopRegistrationStore = create((set) => ({
deliveryPrice: 0,
description: '',
imageUrl: '',
- imageUrls: ['aa'],
+ imageUrls: [],
owner: '',
name: '',
phone: '',
diff --git a/src/utils/constant/progress.ts b/src/utils/constant/progress.ts
index 78a43bc4..29bc9dd9 100644
--- a/src/utils/constant/progress.ts
+++ b/src/utils/constant/progress.ts
@@ -1,4 +1,8 @@
const PROGRESS_TITLE = [
+ {
+ step: 0,
+ title: '가게 등록',
+ },
{
step: 1,
title: '가게 카테고리 설정',
diff --git a/src/utils/hooks/useFunnel.ts b/src/utils/hooks/useFunnel.ts
new file mode 100644
index 00000000..cf3675c8
--- /dev/null
+++ b/src/utils/hooks/useFunnel.ts
@@ -0,0 +1,31 @@
+import { ReactElement, useState } from 'react';
+
+export interface StepProps {
+ name: string;
+ children: ReactElement;
+}
+
+export interface FunnelProps {
+ children: ReactElement[];
+}
+
+/**
+* 단계별 입력 폼을 진행할 시 사용 권장
+* @param { string } defaultStep 시작할 초기 단계
+* @returns { Funnel, Step, setStep, currentStep } 단계별 입력 폼을 관리하는데 사용하는 유틸리티
+*/
+export const useFunnel = (defaultStep: string) => {
+ const [step, setStep] = useState(defaultStep);
+
+ const Step = (props: StepProps) => props.children;
+
+ function Funnel({ children }: FunnelProps): ReactElement | null {
+ const targetStep = children.find((childStep) => childStep.props.name === step);
+
+ return targetStep ?? null;
+ }
+
+ return {
+ Funnel, Step, setStep, currentStep: step,
+ } as const;
+};
diff --git a/src/utils/hooks/useImagesUpload.ts b/src/utils/hooks/useImagesUpload.ts
index 9eed66ac..bcd076c2 100644
--- a/src/utils/hooks/useImagesUpload.ts
+++ b/src/utils/hooks/useImagesUpload.ts
@@ -15,7 +15,6 @@ export default function useImagesUpload() {
const saveImgFile = async () => {
const files = imgRef.current?.files;
- console.log(files?.length)
// imageFile.length + files.length을 통해 저장된 이미지 + 새로 추가할 이미지의 개수를 파악함
if (files && (files.length > 3 || imageFile.length >= 3 || imageFile.length + files.length > 3)) {
showToast('error', '파일은 3개까지 등록할 수 있습니다.')