Skip to content

Commit

Permalink
Merge pull request #30 from BCSDLab/feature/#27
Browse files Browse the repository at this point in the history
[가게 등록] 가게 등록 페이지 PC 버전 로직 구현 및 API 구현
  • Loading branch information
dooohun authored Nov 29, 2023
2 parents ae8e320 + ad2fc39 commit d05cbb5
Show file tree
Hide file tree
Showing 63 changed files with 1,206 additions and 524 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"react/jsx-props-no-spreading": "off",
"react/require-default-props": "off",
"@typescript-eslint/no-redeclare" : "off",
"import/prefer-default-export": "off",
"no-restricted-imports": [
"error",
{
Expand Down
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import CompleteChangePassword from 'page/Auth/FindPassword/CompleteChangePasswor
import AuthLayout from 'layout/AuthLayout';

import MyStorePage from 'page/MyShopPage';
import StoreRegistration from 'page/StoreRegistration';
import ShopRegistration from 'page/ShopRegistration';
import AddMenu from 'page/AddMenu';

function App() {
return (
<Routes>
<Route path="/" element={<DefaultLayout />}>
<Route path="/" element={<MyStorePage />} />
<Route path="/store-registration" element={<StoreRegistration />} />
<Route path="/store-registration" element={<ShopRegistration />} />
<Route path="/add-menu" element={<AddMenu />} />
</Route>
<Route element={<AuthLayout />}>
Expand Down
4 changes: 2 additions & 2 deletions src/api/category/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { accessClient } from 'api';
import { StoreCategory } from 'model/category/storeCategory';

const getStoreCategory = async () => {
const getShopCategory = async () => {
const { data } = await accessClient.get<StoreCategory>('/shops/categories');
return StoreCategory.parse(data);
};

export default getStoreCategory;
export default getShopCategory;
17 changes: 13 additions & 4 deletions src/api/shop/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { MyShopList, MyShopInfoRes, MyShopParam } from 'model/shopInfo/myShopInfo';
import { MyShopListRes, MyShopInfoRes, MyShopParam } from 'model/shopInfo/myShopInfo';
import { MenuInfoRes } from 'model/shopInfo/menuCategory';
import { accessClient } from 'api';
import { ShopListRes } from 'model/shopInfo/allShopInfo';
import { accessClient, client } from 'api';
import { OwnerShop } from 'model/shopInfo/ownerShop';

export const getMyShopList = async () => {
const { data } = await accessClient.get<MyShopList>('/owner/shops');
return MyShopList.parse(data);
const { data } = await accessClient.get<MyShopListRes>('/owner/shops');
return MyShopListRes.parse(data);
};

export const getShopInfo = async (param: MyShopParam) => {
Expand All @@ -16,3 +18,10 @@ export const getMenuInfoList = async (param: MyShopParam) => {
const { data } = await accessClient.get<MenuInfoRes>(`/owner/shops/${param.id}/menus`);
return MenuInfoRes.parse(data);
};

export const getShopList = async () => {
const { data } = await client.get<ShopListRes>('/shops');
return ShopListRes.parse(data);
};

export const postShop = (data: OwnerShop) => accessClient.post('/owner/shops', data);
File renamed without changes
61 changes: 56 additions & 5 deletions src/component/common/CustomModal/CustomModal.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,71 @@
}

.container {
display: flex;
flex-direction: column;
align-items: center;
width: 430px;
background-color: #ffffff;
&__small {
display: flex;
flex-direction: column;
align-items: center;
width: 430px;
height: 434px;
background-color: #ffffff;
overflow: auto;

&--visible {
overflow: visible;
}

&::-webkit-scrollbar {
display: none;
}
}

&__medium {
display: flex;
flex-direction: column;
align-items: center;
width: 430px;
height: 536px;
background-color: #ffffff;
overflow: auto;

&--visible {
overflow: visible;
}

&::-webkit-scrollbar {
display: none;
}
}

&__large {
display: flex;
flex-direction: column;
align-items: center;
width: 430px;
height: 75vh;
background-color: #ffffff;
overflow: auto;

&--visible {
overflow: visible;
}

&::-webkit-scrollbar {
display: none;
}
}

&__header {
position: sticky;
top: 0;
display: flex;
align-items: center;
justify-content: space-between;
width: 398px;
height: 30px;
background-color: #175c8e;
padding: 24px 16px;
z-index: 3;
}

&__title {
Expand Down
32 changes: 28 additions & 4 deletions src/component/common/CustomModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
import { ReactComponent as XClose } from 'assets/svg/StoreRegistration/close-x.svg';
import { ReactComponent as XClose } from 'assets/svg/shopRegistration/close-x.svg';
import CustomButton from 'page/Auth/Signup/component/CustomButton';
import { createPortal } from 'react-dom';
import cn from 'utils/ts/className';
import { useEffect } from 'react';
import styles from './CustomModal.module.scss';

interface CustomModalProps {
buttonText?: string;
title: string;
height: string;
modalSize: string;
hasFooter: boolean;
isOpen: boolean;
isOverflowVisible: boolean;
onCancel: () => void;
children: React.ReactNode
}

export default function CustomModal({
buttonText = '', title, height, hasFooter, isOpen, onCancel, children,
buttonText = '', title, modalSize, hasFooter, isOpen, isOverflowVisible, onCancel, children,
}: CustomModalProps) {
useEffect(() => {
if (isOpen) {
document.body.style.cssText = `
position: fixed;
top: -${window.scrollY}px;
overflow-y: scroll;
width: 100%;`;
return () => {
const scrollY = document.body.style.top;
document.body.style.cssText = '';
window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
};
}
return undefined;
}, [isOpen]);

if (!isOpen) return null;
return createPortal(
<div className={styles.modal}>
<div className={styles.container} style={{ height }}>
<div
className={cn({
[styles[`container__${modalSize}`]]: true,
[styles[`container__${modalSize}--visible`]]: isOverflowVisible,
})}
>
<div className={styles.container__header}>
<span className={styles.container__title}>{title}</span>
<XClose
Expand Down
28 changes: 28 additions & 0 deletions src/model/shopInfo/allShopInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import z from 'zod';

const Open = z.object({
day_of_week: z.string(),
closed: z.boolean(),
open_time: z.string().nullable(),
close_time: z.string().nullable(),
});

export const Shop = z.object({
id: z.number(),
name: z.string(),
phone: z.string(),
delivery: z.boolean(),
pay_bank: z.boolean(),
pay_card: z.boolean(),
open: z.array(Open),
category_ids: z.array(z.number()),
});

export type Shop = z.infer<typeof Shop>;

export const ShopListRes = z.object({
count: z.number(),
shops: z.array(Shop),
});

export type ShopListRes = z.infer<typeof ShopListRes>;
4 changes: 2 additions & 2 deletions src/model/shopInfo/myShopInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ export const MyShop = z.object({

export type MyShop = z.infer<typeof MyShop>;

export const MyShopList = z.object({
export const MyShopListRes = z.object({
count: z.number(),
shops: z.array(MyShop),
});

export type MyShopList = z.infer<typeof MyShopList>;
export type MyShopListRes = z.infer<typeof MyShopListRes>;

export const OpenInfo = z.object({
day_of_week: z.string(),
Expand Down
11 changes: 11 additions & 0 deletions src/model/shopInfo/ownerShop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import z from 'zod';
import { Shop } from './allShopInfo';

export const OwnerShop = Shop.omit({ id: true }).extend({
address: z.string(),
description: z.string(),
delivery_price: z.string(),
image_urls: z.array(z.string()),
});

export type OwnerShop = z.infer<typeof OwnerShop>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { createPortal } from 'react-dom';
import useStepStore from 'store/useStepStore';
import styles from './ConfirmPopup.module.scss';

interface ConfirmPopupProps {
Expand All @@ -8,11 +6,9 @@ interface ConfirmPopupProps {
}

export default function ConfirmPopup({ isOpen, onCancel }: ConfirmPopupProps) {
const { setStep } = useStepStore();

if (!isOpen) return null;

return createPortal(
return (
<div className={styles.popup}>
<div className={styles.content}>
<span className={styles['content__top-text']}>가게 정보를 저장하시겠습니까?</span>
Expand All @@ -27,15 +23,13 @@ export default function ConfirmPopup({ isOpen, onCancel }: ConfirmPopupProps) {
취소
</button>
<button
type="button"
onClick={() => setStep(5)}
type="submit"
className={styles['content__next-button']}
>
확인
</button>
</div>
</div>
</div>,
document.body,
</div>
);
}
44 changes: 44 additions & 0 deletions src/page/ShopRegistration/component/InputBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { UseFormRegister } from 'react-hook-form';
import { OwnerShop } from 'model/shopInfo/ownerShop';
import { HTMLInputTypeAttribute, useState } from 'react';
import styles from './InputBox.module.scss';

interface InputBoxProps {
content: string;
id: keyof OwnerShop
register: UseFormRegister<OwnerShop>;
inputType: HTMLInputTypeAttribute;
}

function formatPhoneNumber(inputNumber: string) {
const phoneNumber = inputNumber.replace(/\D/g, '');

const formattedPhoneNumber = phoneNumber.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');

return formattedPhoneNumber;
}

export default function InputBox({
content, id, register, inputType,
}: InputBoxProps) {
const [formattedPhoneNumber, setFormattedPhoneNumber] = useState('');

const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputNumber = e.target.value;
const formattedNumber = formatPhoneNumber(inputNumber);
setFormattedPhoneNumber(formattedNumber);
};
return (
<label htmlFor={id} className={styles.form}>
<span className={styles.form__label}>{content}</span>
<input
type={inputType}
id={id}
className={styles.form__input}
{...register(id)}
onChange={inputType === 'tel' ? handlePhoneChange : undefined}
value={inputType === 'tel' ? formattedPhoneNumber : undefined}
/>
</label>
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import useStoreCategory from 'query/storeCategory';
import useShopCategory from 'query/shopCategory';
import { useState } from 'react';
import cn from 'utils/ts/className';
import useModalStore from 'store/modalStore';
import { Category as CategoryProps } from 'model/category/storeCategory';
import styles from './Category.module.scss';

export default function Category() {
const [selectedCategory, setSelectedCategory] = useState('');
const { categoryList } = useStoreCategory();
const { categoryList } = useShopCategory();
const { setCategoryState } = useModalStore();

const handleCategoryClick = (category: CategoryProps) => {
setSelectedCategory(category.name);
setCategoryState([category.name, category.id]);
};

return (
<div className={styles.category}>
{categoryList?.shop_categories.filter((_, index) => index > 0).map((category) => (
Expand All @@ -15,7 +24,7 @@ export default function Category() {
[styles['category__menu--selected']]: category.name === selectedCategory,
})}
type="button"
onClick={() => setSelectedCategory(category.name)}
onClick={() => { handleCategoryClick(category); }}
key={category.id}
>
<img className={styles.category__image} src={category.image_url} alt="" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
.container {
position: absolute;
position: sticky;
bottom: 0;
left: 0;
display: flex;
justify-content: space-around;
justify-content: space-between;
align-items: center;
height: 25%;
height: 23%;
width: 100%;
border-radius: 20px 20px 0 0;
box-shadow: 0 -5px 10px #00000026;
background-color: #ffffff;

&__info {
margin-left: 32px;
}

&__title {
font-size: 20px;
Expand All @@ -34,6 +38,7 @@
width: 144px;
height: 48px;
background-color: #175c8e;
margin-right: 31px;
font-size: 20px;
font-weight: 600;
color: #ffffff;
Expand Down
Loading

0 comments on commit d05cbb5

Please sign in to comment.