diff --git a/.pnp.cjs b/.pnp.cjs index d2755122..0f6eb779 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -54,6 +54,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["react", "npm:18.2.0"],\ ["react-dom", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:18.2.0"],\ ["react-hook-form", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:7.50.1"],\ + ["react-quill", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:2.0.0"],\ ["react-router-dom", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:6.22.0"],\ ["react-scripts", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:5.0.1"],\ ["react-toastify", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:10.0.4"],\ @@ -5027,6 +5028,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["@types/quill", [\ + ["npm:1.3.10", {\ + "packageLocation": "./.yarn/cache/@types-quill-npm-1.3.10-4ddf84ba7e-e629157d11.zip/node_modules/@types/quill/",\ + "packageDependencies": [\ + ["@types/quill", "npm:1.3.10"],\ + ["parchment", "npm:1.1.4"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["@types/range-parser", [\ ["npm:1.2.7", {\ "packageLocation": "./.yarn/cache/@types-range-parser-npm-1.2.7-a83c0b6429-95640233b6.zip/node_modules/@types/range-parser/",\ @@ -7081,6 +7092,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["clone", [\ + ["npm:2.1.2", {\ + "packageLocation": "./.yarn/cache/clone-npm-2.1.2-1d491c6629-aaf106e9bc.zip/node_modules/clone/",\ + "packageDependencies": [\ + ["clone", "npm:2.1.2"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["clsx", [\ ["npm:2.1.0", {\ "packageLocation": "./.yarn/cache/clsx-npm-2.1.0-29d286e1de-43fefc29b6.zip/node_modules/clsx/",\ @@ -7971,6 +7991,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["deep-equal", [\ + ["npm:1.1.2", {\ + "packageLocation": "./.yarn/cache/deep-equal-npm-1.1.2-3af5068c14-2d50f27fff.zip/node_modules/deep-equal/",\ + "packageDependencies": [\ + ["deep-equal", "npm:1.1.2"],\ + ["is-arguments", "npm:1.1.1"],\ + ["is-date-object", "npm:1.0.5"],\ + ["is-regex", "npm:1.1.4"],\ + ["object-is", "npm:1.1.5"],\ + ["object-keys", "npm:1.1.1"],\ + ["regexp.prototype.flags", "npm:1.5.1"]\ + ],\ + "linkType": "HARD"\ + }],\ ["npm:2.2.3", {\ "packageLocation": "./.yarn/cache/deep-equal-npm-2.2.3-86cbe803a7-ee8852f23e.zip/node_modules/deep-equal/",\ "packageDependencies": [\ @@ -9400,6 +9433,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["eventemitter3", [\ + ["npm:2.0.3", {\ + "packageLocation": "./.yarn/cache/eventemitter3-npm-2.0.3-71d4ac3a65-dfbf4a0714.zip/node_modules/eventemitter3/",\ + "packageDependencies": [\ + ["eventemitter3", "npm:2.0.3"]\ + ],\ + "linkType": "HARD"\ + }],\ ["npm:4.0.7", {\ "packageLocation": "./.yarn/cache/eventemitter3-npm-4.0.7-7afcdd74ae-1875311c42.zip/node_modules/eventemitter3/",\ "packageDependencies": [\ @@ -9518,6 +9558,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["extend", [\ + ["npm:3.0.2", {\ + "packageLocation": "./.yarn/cache/extend-npm-3.0.2-e1ca07ac54-a50a8309ca.zip/node_modules/extend/",\ + "packageDependencies": [\ + ["extend", "npm:3.0.2"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["fast-deep-equal", [\ ["npm:3.1.3", {\ "packageLocation": "./.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip/node_modules/fast-deep-equal/",\ @@ -9527,6 +9576,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["fast-diff", [\ + ["npm:1.1.2", {\ + "packageLocation": "./.yarn/cache/fast-diff-npm-1.1.2-907d4b29ef-2ef726603e.zip/node_modules/fast-diff/",\ + "packageDependencies": [\ + ["fast-diff", "npm:1.1.2"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["fast-glob", [\ ["npm:3.3.2", {\ "packageLocation": "./.yarn/cache/fast-glob-npm-3.3.2-0a8cb4f2ca-900e4979f4.zip/node_modules/fast-glob/",\ @@ -12360,6 +12418,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["react", "npm:18.2.0"],\ ["react-dom", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:18.2.0"],\ ["react-hook-form", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:7.50.1"],\ + ["react-quill", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:2.0.0"],\ ["react-router-dom", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:6.22.0"],\ ["react-scripts", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:5.0.1"],\ ["react-toastify", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:10.0.4"],\ @@ -13602,6 +13661,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["parchment", [\ + ["npm:1.1.4", {\ + "packageLocation": "./.yarn/cache/parchment-npm-1.1.4-a3bac35728-4799756742.zip/node_modules/parchment/",\ + "packageDependencies": [\ + ["parchment", "npm:1.1.4"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["parent-module", [\ ["npm:1.0.1", {\ "packageLocation": "./.yarn/cache/parent-module-npm-1.0.1-1fae11b095-6ba8b25514.zip/node_modules/parent-module/",\ @@ -15758,6 +15826,33 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["quill", [\ + ["npm:1.3.7", {\ + "packageLocation": "./.yarn/cache/quill-npm-1.3.7-c79f7446fc-db3e265a84.zip/node_modules/quill/",\ + "packageDependencies": [\ + ["quill", "npm:1.3.7"],\ + ["clone", "npm:2.1.2"],\ + ["deep-equal", "npm:1.1.2"],\ + ["eventemitter3", "npm:2.0.3"],\ + ["extend", "npm:3.0.2"],\ + ["parchment", "npm:1.1.4"],\ + ["quill-delta", "npm:3.6.3"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["quill-delta", [\ + ["npm:3.6.3", {\ + "packageLocation": "./.yarn/cache/quill-delta-npm-3.6.3-3ae240a64d-e62ed33983.zip/node_modules/quill-delta/",\ + "packageDependencies": [\ + ["quill-delta", "npm:3.6.3"],\ + ["deep-equal", "npm:1.1.2"],\ + ["extend", "npm:3.0.2"],\ + ["fast-diff", "npm:1.1.2"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["raf", [\ ["npm:3.4.1", {\ "packageLocation": "./.yarn/cache/raf-npm-3.4.1-c25d48d76e-50ba284e48.zip/node_modules/raf/",\ @@ -15953,6 +16048,35 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["react-quill", [\ + ["npm:2.0.0", {\ + "packageLocation": "./.yarn/cache/react-quill-npm-2.0.0-f2d141fe1d-568e28656a.zip/node_modules/react-quill/",\ + "packageDependencies": [\ + ["react-quill", "npm:2.0.0"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:2.0.0", {\ + "packageLocation": "./.yarn/__virtual__/react-quill-virtual-4ac55c53db/0/cache/react-quill-npm-2.0.0-f2d141fe1d-568e28656a.zip/node_modules/react-quill/",\ + "packageDependencies": [\ + ["react-quill", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:2.0.0"],\ + ["@types/quill", "npm:1.3.10"],\ + ["@types/react", "npm:18.2.55"],\ + ["@types/react-dom", "npm:18.2.18"],\ + ["lodash", "npm:4.17.21"],\ + ["quill", "npm:1.3.7"],\ + ["react", "npm:18.2.0"],\ + ["react-dom", "virtual:2a928e07684dc9ad50d6744a82230310880d82a84463b276e7d19ce4f4762d0780e66ccb13980e8f3eb76ec0bcd5207e76cb8696dbcb80089851be6e3a1536fb#npm:18.2.0"]\ + ],\ + "packagePeers": [\ + "@types/react-dom",\ + "@types/react",\ + "react-dom",\ + "react"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["react-refresh", [\ ["npm:0.11.0", {\ "packageLocation": "./.yarn/cache/react-refresh-npm-0.11.0-c0a4e59e76-112178a05b.zip/node_modules/react-refresh/",\ diff --git a/.yarn/cache/@types-quill-npm-1.3.10-4ddf84ba7e-e629157d11.zip b/.yarn/cache/@types-quill-npm-1.3.10-4ddf84ba7e-e629157d11.zip new file mode 100644 index 00000000..d7622f11 Binary files /dev/null and b/.yarn/cache/@types-quill-npm-1.3.10-4ddf84ba7e-e629157d11.zip differ diff --git a/.yarn/cache/clone-npm-2.1.2-1d491c6629-aaf106e9bc.zip b/.yarn/cache/clone-npm-2.1.2-1d491c6629-aaf106e9bc.zip new file mode 100644 index 00000000..6ae29b32 Binary files /dev/null and b/.yarn/cache/clone-npm-2.1.2-1d491c6629-aaf106e9bc.zip differ diff --git a/.yarn/cache/deep-equal-npm-1.1.2-3af5068c14-2d50f27fff.zip b/.yarn/cache/deep-equal-npm-1.1.2-3af5068c14-2d50f27fff.zip new file mode 100644 index 00000000..d33272c1 Binary files /dev/null and b/.yarn/cache/deep-equal-npm-1.1.2-3af5068c14-2d50f27fff.zip differ diff --git a/.yarn/cache/eventemitter3-npm-2.0.3-71d4ac3a65-dfbf4a0714.zip b/.yarn/cache/eventemitter3-npm-2.0.3-71d4ac3a65-dfbf4a0714.zip new file mode 100644 index 00000000..2cceee35 Binary files /dev/null and b/.yarn/cache/eventemitter3-npm-2.0.3-71d4ac3a65-dfbf4a0714.zip differ diff --git a/.yarn/cache/extend-npm-3.0.2-e1ca07ac54-a50a8309ca.zip b/.yarn/cache/extend-npm-3.0.2-e1ca07ac54-a50a8309ca.zip new file mode 100644 index 00000000..a33fb285 Binary files /dev/null and b/.yarn/cache/extend-npm-3.0.2-e1ca07ac54-a50a8309ca.zip differ diff --git a/.yarn/cache/fast-diff-npm-1.1.2-907d4b29ef-2ef726603e.zip b/.yarn/cache/fast-diff-npm-1.1.2-907d4b29ef-2ef726603e.zip new file mode 100644 index 00000000..6fafb684 Binary files /dev/null and b/.yarn/cache/fast-diff-npm-1.1.2-907d4b29ef-2ef726603e.zip differ diff --git a/.yarn/cache/fsevents-patch-21ad2b1333-8.zip b/.yarn/cache/fsevents-patch-21ad2b1333-8.zip deleted file mode 100644 index c6a96dfc..00000000 Binary files a/.yarn/cache/fsevents-patch-21ad2b1333-8.zip and /dev/null differ diff --git a/.yarn/cache/parchment-npm-1.1.4-a3bac35728-4799756742.zip b/.yarn/cache/parchment-npm-1.1.4-a3bac35728-4799756742.zip new file mode 100644 index 00000000..dea30b0b Binary files /dev/null and b/.yarn/cache/parchment-npm-1.1.4-a3bac35728-4799756742.zip differ diff --git a/.yarn/cache/quill-delta-npm-3.6.3-3ae240a64d-e62ed33983.zip b/.yarn/cache/quill-delta-npm-3.6.3-3ae240a64d-e62ed33983.zip new file mode 100644 index 00000000..13ae0bfa Binary files /dev/null and b/.yarn/cache/quill-delta-npm-3.6.3-3ae240a64d-e62ed33983.zip differ diff --git a/.yarn/cache/quill-npm-1.3.7-c79f7446fc-db3e265a84.zip b/.yarn/cache/quill-npm-1.3.7-c79f7446fc-db3e265a84.zip new file mode 100644 index 00000000..9c20b754 Binary files /dev/null and b/.yarn/cache/quill-npm-1.3.7-c79f7446fc-db3e265a84.zip differ diff --git a/.yarn/cache/react-quill-npm-2.0.0-f2d141fe1d-568e28656a.zip b/.yarn/cache/react-quill-npm-2.0.0-f2d141fe1d-568e28656a.zip new file mode 100644 index 00000000..0437e9a0 Binary files /dev/null and b/.yarn/cache/react-quill-npm-2.0.0-f2d141fe1d-568e28656a.zip differ diff --git a/package.json b/package.json index 58cc6ceb..c4c73014 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.43.9", + "react-quill": "^2.0.0", "react-router-dom": "^6.9.0", "react-scripts": "5.0.1", "react-toastify": "^10.0.4", diff --git a/src/App.tsx b/src/App.tsx index 298782c8..cc55a3d1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,7 @@ import Toast from 'component/common/Toast'; import { UserType } from 'model/auth'; import Coop from 'page/Coop'; import useUserTypeStore from 'store/userType'; +import AddingEvent from 'page/AddingEvent'; interface ProtectedRouteProps { userTypeRequired: UserType; @@ -59,6 +60,7 @@ function App() { } /> } /> } /> + } /> }> diff --git a/src/api/shop/index.ts b/src/api/shop/index.ts index 8c01cb54..f3016317 100644 --- a/src/api/shop/index.ts +++ b/src/api/shop/index.ts @@ -4,6 +4,7 @@ import { ShopListRes } from 'model/shopInfo/allShopInfo'; import { accessClient, client } from 'api'; import { OwnerShop } from 'model/shopInfo/ownerShop'; import { NewMenu } from 'model/shopInfo/newMenu'; +import { EventInfo } from 'model/shopInfo/event'; export const getMyShopList = async () => { const { data } = await accessClient.get('/owner/shops'); @@ -39,3 +40,5 @@ export const modifyMenu = (menuId:number, param:NewMenu) => accessClient.put(`/o export const putShop = (id: number, data: OwnerShop) => accessClient.put(`/owner/shops/${id}`, data); export const deleteMenu = (menuId:number) => accessClient.delete(`/owner/shops/menus/${menuId}`); + +export const addEvent = (id: string, eventInfo: EventInfo) => accessClient.post(`owner/shops/${id}/event`, eventInfo); diff --git a/src/assets/svg/mystore/delete.svg b/src/assets/svg/mystore/delete.svg new file mode 100644 index 00000000..040fa928 --- /dev/null +++ b/src/assets/svg/mystore/delete.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/component/common/Header/index.tsx b/src/component/common/Header/index.tsx index b94bc371..61af039e 100644 --- a/src/component/common/Header/index.tsx +++ b/src/component/common/Header/index.tsx @@ -49,8 +49,7 @@ function Header() { }, }); }; - - if ((pathname === '/owner/add-menu' || pathname.startsWith('/owner/modify-menu/')) && isMobile) { + if ((pathname === '/owner/add-menu' || pathname.startsWith('/owner/modify-menu/') || pathname.startsWith('/owner/event-add/')) && isMobile) { return (
-
{pathname === '/owner/add-menu' ? '메뉴추가' : '메뉴수정'}
+
+ {pathname === '/owner/add-menu' && '메뉴추가'} + {pathname.startsWith('/owner/event-add/') && '이벤트/공지 작성하기'} + {pathname.startsWith('/owner/modify-menu/') && '메뉴수정'} +
); } diff --git a/src/layout/OwnerLayout/index.tsx b/src/layout/OwnerLayout/index.tsx index 9bdd4796..22b2fb8f 100644 --- a/src/layout/OwnerLayout/index.tsx +++ b/src/layout/OwnerLayout/index.tsx @@ -27,12 +27,12 @@ export default function OwnerLayout() { return (
{user && ( - <> - {location.pathname !== '/owner/shop-registration' &&
} - - - - + <> + {location.pathname !== '/owner/shop-registration' &&
} + + + + )}
); diff --git a/src/model/shopInfo/event.ts b/src/model/shopInfo/event.ts new file mode 100644 index 00000000..dbe73288 --- /dev/null +++ b/src/model/shopInfo/event.ts @@ -0,0 +1,11 @@ +import z from 'zod'; + +export const EventInfo = z.object({ + title: z.string(), + content: z.string(), + thumbnail_images: z.array(z.string()), + start_date: z.string(), + end_date: z.string(), +}); + +export type EventInfo = z.infer; diff --git a/src/page/AddingEvent/AddingEvent.module.scss b/src/page/AddingEvent/AddingEvent.module.scss new file mode 100644 index 00000000..a0fa6f87 --- /dev/null +++ b/src/page/AddingEvent/AddingEvent.module.scss @@ -0,0 +1,131 @@ +.container { + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; +} + +.event { + margin-top: 8%; + width: 90%; + display: flex; + flex-direction: column; + gap: 30px; + + &__count { + color: #8e8e8e; + } + + &__images { + display: flex; + align-items: center; + box-sizing: border-box; + padding: 0 10px; + width: 100%; + background-color: #f5f5f5; + border-radius: 5px; + height: 100px; + margin-bottom: 10px; + } + + &__each-image { + width: 30%; + height: 80px; + margin: 0 5px; + position: relative; + + &--delete { + position: absolute; + top: -5px; + right: -5px; + background-color: transparent; + cursor: pointer; + } + } + + &__image { + width: 100%; + height: 100%; + } + + &__upload { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + background-color: #f5f5f5; + border-radius: 5px; + height: 50px; + } + + &__divide { + width: 100%; + display: flex; + justify-content: space-between; + } + + &__paragraph { + font-weight: bold; + margin-bottom: 10px; + } + + &__input { + border: 1px solid #e1e1e1; + border-radius: 5px; + box-sizing: border-box; + width: 100%; + height: 40px; + padding: 5px 10px; + } +} + +.event-day { + width: 100%; + display: flex; + align-items: center; + gap: 3vw; + margin-top: 10px; + + &__paragraph { + border-radius: 20px; + background-color: #f5f5f5; + width: 20%; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + &__input { + width: 20%; + height: 50px; + border: 1px solid #e1e1e1; + border-radius: 4px; + text-align: center; + } +} + +.buttons { + margin-top: 100px; + width: 100%; + display: flex; + justify-content: center; + gap: 20px; +} + +.cancel { + border: none; + background-color: #f5f5f5; + border-radius: 5px; + width: 35%; + height: 50px; +} + +.add { + border: none; + background-color: #175c8e; + color: white; + border-radius: 5px; + width: 55%; + height: 50px; +} diff --git a/src/page/AddingEvent/index.tsx b/src/page/AddingEvent/index.tsx new file mode 100644 index 00000000..fdcdb4e4 --- /dev/null +++ b/src/page/AddingEvent/index.tsx @@ -0,0 +1,306 @@ +import React, { useState } from 'react'; +import ReactQuill from 'react-quill'; +import 'react-quill/dist/quill.snow.css'; +import { useAddEvent } from 'query/event'; +import { useParams } from 'react-router-dom'; +import { FileResponse, getCoopUrl } from 'api/uploadFile'; +import axios from 'axios'; +import showToast from 'utils/ts/showToast'; +import { ReactComponent as Delete } from 'assets/svg/mystore/delete.svg'; +import styles from './AddingEvent.module.scss'; + +/* eslint-disable no-await-in-loop */ +/* eslint-disable jsx-a11y/label-has-associated-control */ + +const modules = { + toolbar: [ + ['bold'], + [{ list: 'ordered' }, { list: 'bullet' }], + ], +}; + +const initialState = { + title: '', + content: '', + thumbnail_image: [], + start_date: { + year: '', + month: '', + date: '', + }, + end_date: { + year: '', + month: '', + date: '', + }, +}; + +interface EventInfo { + title: string, + content: string, + thumbnail_image: string[], + start_date: { + year: string, + month: string, + date: string, + }, + end_date: { + year: string, + month: string, + date: string, + }, +} + +interface FileInfo { + file: File; + presignedUrl: string; +} + +const uploadImage = async ({ presignedUrl, file }: FileInfo) => { + await axios.put(presignedUrl, file, { + headers: { + 'Content-Type': 'image/jpeg, image/png, image/svg+xml, image/webp', + }, + }); +}; + +interface ImageList { + presigned: FileResponse[]; + file: FileList | null; +} + +export default function AddingEvent() { + const [eventInfo, setEventInfo] = useState(initialState); + const [editor, setEditor] = useState(''); + const param = useParams(); + const [preImages, setPreImages] = useState<(string | ArrayBuffer | null)[]>([]); + const [imageList, setImageList] = useState({ + presigned: [], + file: null, + }); + const { mutate: addEvent, isPending } = useAddEvent(param.id!); + + const changeTitle = (e: React.ChangeEvent) => { + if (e.target.value.length <= 25) setEventInfo({ ...eventInfo, title: e.target.value }); + }; + const changeStartYear = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 4) { + setEventInfo({ ...eventInfo, start_date: { ...eventInfo.start_date, year: value } }); + } + }; + const changeStartMonth = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 2) { + setEventInfo({ ...eventInfo, start_date: { ...eventInfo.start_date, month: value } }); + } + }; + const changeStartDate = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 2) { + setEventInfo({ ...eventInfo, start_date: { ...eventInfo.start_date, date: value } }); + } + }; + const changeEndYear = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 4) { + setEventInfo({ ...eventInfo, end_date: { ...eventInfo.end_date, year: value } }); + } + }; + const changeEndMonth = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 2) { + setEventInfo({ ...eventInfo, end_date: { ...eventInfo.end_date, month: value } }); + } + }; + const changeEndDate = (e: React.ChangeEvent) => { + const value = e.target.value.replaceAll(/[\D]/gi, ''); + if (value.length <= 2) { + setEventInfo({ ...eventInfo, end_date: { ...eventInfo.end_date, date: value } }); + } + }; + + const handleImages = async (e: React.ChangeEvent) => { + const file = e.target.files; + + if (file && file.length > 0) { + if (file.length + imageList.presigned.length > 3) { + showToast('error', '이미지는 3개까지 등록할 수 있습니다'); + return; + } + for (let i = 0; i < file.length; i += 1) { + const presignedUrl = await getCoopUrl({ + content_length: file[i].size, + content_type: file[i].type, + file_name: file[i].name, + }).then((res) => res.data); + setImageList({ file, presigned: [...imageList.presigned, presignedUrl] }); + const reader = new FileReader(); + reader.readAsDataURL(file[i]); + reader.onload = () => { + setPreImages((prev) => [...prev, reader.result]); // 이미지 미리보기 구현 + }; + } + } + }; + + const postEvent = () => { + const startDate = `${eventInfo.start_date.year}-${eventInfo.start_date.month}-${eventInfo.start_date.date}`; + const endDate = `${eventInfo.end_date.year}-${eventInfo.end_date.month}-${eventInfo.end_date.date}`; + + if (imageList.file) { + for (let i = 0; i < imageList.file.length; i += 1) { + const url = imageList.presigned[i].pre_signed_url; + uploadImage({ presignedUrl: url, file: imageList.file[i] }); + } + } + + const requestData = { + title: eventInfo.title, + content: editor, + start_date: startDate, + end_date: endDate, + thumbnail_images: imageList.presigned.map((img) => img.file_url), + }; + + addEvent(requestData); + }; + + return ( +
+
+
+

사진

+
+ 이벤트/공지와 관련된 사진을 올려보세요. + + {`${preImages.length} / 3`} + +
+ {preImages.length > 0 && ( +
+ { + preImages.map((src, id) => { + if (typeof src === 'string') { + return ( +
+ 미리보기 + +
+ ); + } + return ''; + }) + } +
+ )} + + +
+
+
+

제목

+ + {`${eventInfo.title.length} / 25`} + +
+ +
+
+
+

이벤트/공지 내용

+ 0 +
+
+ +
+
+
+

이벤트/공지 등록 기간

+
+
시작일
+ + / + + / + +
+
+
종료일
+ + / + + / + +
+
+
+ + +
+
+
+ ); +} diff --git a/src/query/event.ts b/src/query/event.ts new file mode 100644 index 00000000..0a4cf317 --- /dev/null +++ b/src/query/event.ts @@ -0,0 +1,17 @@ +import { useMutation } from '@tanstack/react-query'; +import { addEvent } from 'api/shop'; +import { EventInfo } from 'model/shopInfo/event'; +import { isKoinError } from '@bcsdlab/koin'; +import showToast from 'utils/ts/showToast'; + +export const useAddEvent = (id: string) => { + const { mutate, isPending } = useMutation({ + mutationFn: (data: EventInfo) => addEvent(id, data), + onSuccess: () => showToast('success', '이벤트 추가에 성공했습니다.'), + onError: (e) => { + if (isKoinError(e)) showToast('error', e.message); + }, + }); + + return { mutate, isPending }; +}; diff --git a/yarn.lock b/yarn.lock index f5eca45f..50aae07a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3047,6 +3047,15 @@ __metadata: languageName: node linkType: hard +"@types/quill@npm:^1.3.10": + version: 1.3.10 + resolution: "@types/quill@npm:1.3.10" + dependencies: + parchment: ^1.1.2 + checksum: e629157d11a8398c945e9d9e6b3ebb678f996b195976ddfcabd9771ac7e55a4ebbab3b0c320dc8eb0033715ea5fd197758ac14b4f50bf1d12fd3648fe24d1cb5 + languageName: node + linkType: hard + "@types/range-parser@npm:*": version: 1.2.7 resolution: "@types/range-parser@npm:1.2.7" @@ -4648,6 +4657,13 @@ __metadata: languageName: node linkType: hard +"clone@npm:^2.1.1": + version: 2.1.2 + resolution: "clone@npm:2.1.2" + checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d + languageName: node + linkType: hard + "clsx@npm:^2.1.0": version: 2.1.0 resolution: "clsx@npm:2.1.0" @@ -5317,6 +5333,20 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:^1.0.1": + version: 1.1.2 + resolution: "deep-equal@npm:1.1.2" + dependencies: + is-arguments: ^1.1.1 + is-date-object: ^1.0.5 + is-regex: ^1.1.4 + object-is: ^1.1.5 + object-keys: ^1.1.1 + regexp.prototype.flags: ^1.5.1 + checksum: 2d50f27fff785fb272cdef038ee5365ee5a30ab1aab053976e6a6add44cc60abd99b38179a46a01ac52c5e54ebb220e8f1a3a1954da20678b79c46ef4d97c9db + languageName: node + linkType: hard + "deep-equal@npm:^2.0.5": version: 2.2.3 resolution: "deep-equal@npm:2.2.3" @@ -6408,6 +6438,13 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:^2.0.3": + version: 2.0.3 + resolution: "eventemitter3@npm:2.0.3" + checksum: dfbf4a07144afea0712d8e6a7f30ae91beb7c12c36c3d480818488aafa437d9a331327461f82c12dfd60a4fbad502efc97f684089cda02809988b84a23630752 + languageName: node + linkType: hard + "eventemitter3@npm:^4.0.0": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -6517,6 +6554,13 @@ __metadata: languageName: node linkType: hard +"extend@npm:^3.0.2": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -6524,6 +6568,13 @@ __metadata: languageName: node linkType: hard +"fast-diff@npm:1.1.2": + version: 1.1.2 + resolution: "fast-diff@npm:1.1.2" + checksum: 2ef726603e22a89ef27225bfaef24c17e3aec188df24da4629d5f012b23a884e09a0c7299ff37a0aec7aa788755bd554f5801f698de4deeffce83308bd11405d + languageName: node + linkType: hard + "fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.1": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" @@ -9017,6 +9068,7 @@ __metadata: react: ^18.2.0 react-dom: ^18.2.0 react-hook-form: ^7.43.9 + react-quill: ^2.0.0 react-router-dom: ^6.9.0 react-scripts: 5.0.1 react-toastify: ^10.0.4 @@ -9203,7 +9255,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0": +"lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.7.0": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -10137,6 +10189,13 @@ __metadata: languageName: node linkType: hard +"parchment@npm:^1.1.2, parchment@npm:^1.1.4": + version: 1.1.4 + resolution: "parchment@npm:1.1.4" + checksum: 47997567424d1ad8648046091a06b3a5423ed83f9dfa421d7fd93e0032e79aedd8db5499ff55327e08eebd89d8e927704a646f87d45d4bcfe63016aa5a88947d + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -11361,6 +11420,31 @@ __metadata: languageName: node linkType: hard +"quill-delta@npm:^3.6.2": + version: 3.6.3 + resolution: "quill-delta@npm:3.6.3" + dependencies: + deep-equal: ^1.0.1 + extend: ^3.0.2 + fast-diff: 1.1.2 + checksum: e62ed339838077841db401da3181bdf559c6667d014a671767788380c5be13a6205603bcdd27445260e6f6b2b5519161e1000023e521e3b2ff087270fa67fef6 + languageName: node + linkType: hard + +"quill@npm:^1.3.7": + version: 1.3.7 + resolution: "quill@npm:1.3.7" + dependencies: + clone: ^2.1.1 + deep-equal: ^1.0.1 + eventemitter3: ^2.0.3 + extend: ^3.0.2 + parchment: ^1.1.4 + quill-delta: ^3.6.2 + checksum: db3e265a8410a4554e50a18cae4ebc0b43a996a776bcf03e26abcadbf617f4db329d49a0fa3ada6a70538a369bbbdc8fa7a66086f194b481914bf1adbab16f8f + languageName: node + linkType: hard + "raf@npm:^3.4.1": version: 3.4.1 resolution: "raf@npm:3.4.1" @@ -11493,6 +11577,20 @@ __metadata: languageName: node linkType: hard +"react-quill@npm:^2.0.0": + version: 2.0.0 + resolution: "react-quill@npm:2.0.0" + dependencies: + "@types/quill": ^1.3.10 + lodash: ^4.17.4 + quill: ^1.3.7 + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + checksum: 568e28656ae3a40944d5c4cc9d35accc21834cf15b61a74af4566d8772eb152ce65c0d5ea6da65918cb5c9453c1a2041c60c4a19819bf319bee2e067b613d32b + languageName: node + linkType: hard + "react-refresh@npm:^0.11.0": version: 0.11.0 resolution: "react-refresh@npm:0.11.0"