From 9364848ab043ba6ab4c079ae6af13818d2d70fbb Mon Sep 17 00:00:00 2001 From: Gwanho Kim <83526533+khkim6040@users.noreply.github.com> Date: Sun, 31 Mar 2024 19:57:20 +0900 Subject: [PATCH] Set format and lint (#71) Co-authored-by: bluehorn07 --- .eslintrc.js | 23 + .eslintrc.json | 3 - .github/workflows/github-action.yaml | 20 +- .prettierrc | 8 + assets/club.type.options.js | 12 +- assets/owner.options.js | 10 +- assets/region.options.js | 10 +- .../benefit/affiliate/affiliate.cards.jsx | 70 +- .../benefit/affiliate/affiliate.table.jsx | 70 +- .../board/benefit/discount/discount.cards.jsx | 92 +- .../board/benefit/discount/discount.table.jsx | 82 +- components/board/board.layout.jsx | 12 +- components/board/board.menubar.jsx | 24 +- components/board/notice/notice.table.jsx | 92 +- .../whitebook/whitebook.create.modal.jsx | 53 +- .../board/whitebook/whitebook.table.jsx | 67 +- .../whitebook/whitebook.update.modal.jsx | 67 +- components/common/csv-upload.form.jsx | 105 +- components/common/delete.confirm.modal.jsx | 42 +- components/common/image-upload.form.jsx | 91 +- components/common/opening_hours.editor.jsx | 138 +- .../equipment.reservation.confirm.modal.jsx | 93 +- .../equipment/equipment.reservation.table.jsx | 100 +- .../equipment.reservation.wait.table.jsx | 125 +- components/equipment/equipment.table.jsx | 99 +- components/introduce/association.table.jsx | 58 +- components/introduce/club.table.jsx | 50 +- components/introduce/introduce.layout.jsx | 14 +- components/introduce/introduce.menubar.jsx | 22 +- components/layout/layout.auth.with.jsx | 63 +- components/layout/layout.auth.without.jsx | 18 +- components/navbar/menu.item.user.jsx | 54 +- components/navbar/navbar.desktop.jsx | 42 +- components/navbar/navbar.mobile.jsx | 49 +- components/navbar/sidebar.jsx | 35 +- .../place/place.reservation.confirm.modal.jsx | 78 +- components/place/place.reservation.table.jsx | 76 +- .../place/place.reservation.wait.table.jsx | 178 +- components/place/place.table.jsx | 94 +- components/reservation/opening_hours.list.jsx | 57 +- .../reservation.datetime.picker.jsx | 55 +- components/reservation/reservation.layout.jsx | 14 +- .../reservation/reservation.menubar.jsx | 40 +- components/statistics/new-reservation.bar.jsx | 38 +- components/statistics/new-user.bar.jsx | 31 +- components/user/rc-user.table.jsx | 25 +- components/user/user.create.modal.jsx | 75 +- components/user/user.table.jsx | 76 +- components/user/user.update.modal.jsx | 87 +- docker-stack.yaml | 12 +- jsconfig.json | 4 +- next.config.js | 5 +- package-lock.json | 1948 ++++++++++++++--- package.json | 7 +- pages/404.jsx | 24 +- pages/_app.jsx | 17 +- pages/_document.jsx | 23 +- pages/board/benefit/affiliate/create.jsx | 61 +- pages/board/benefit/affiliate/update/[id].jsx | 77 +- pages/board/benefit/discount/create.jsx | 71 +- pages/board/benefit/discount/update/[id].jsx | 89 +- pages/board/benefit/index.jsx | 20 +- pages/board/index.jsx | 12 +- pages/board/notice/create.jsx | 123 +- pages/board/notice/index.jsx | 30 +- pages/board/notice/update/[id].jsx | 137 +- pages/board/rc-students-list.jsx | 89 +- pages/board/setting.jsx | 75 +- pages/board/whitebook.jsx | 42 +- pages/equipment/create.jsx | 224 +- pages/equipment/index.jsx | 40 +- pages/equipment/reservation.jsx | 72 +- pages/equipment/update/[uuid].jsx | 261 +-- pages/index.jsx | 40 +- pages/introduce/association/create.jsx | 183 +- pages/introduce/association/index.jsx | 66 +- pages/introduce/association/update/[uuid].jsx | 288 +-- pages/introduce/club/create.jsx | 209 +- pages/introduce/club/index.jsx | 118 +- pages/introduce/club/update/[uuid].jsx | 339 ++- pages/introduce/index.jsx | 27 +- pages/login.jsx | 68 +- pages/place/create.jsx | 128 +- pages/place/index.jsx | 35 +- pages/place/reservation/create.jsx | 236 +- pages/place/reservation/index.jsx | 70 +- pages/place/update/[uuid].jsx | 147 +- pages/reservation/index.jsx | 160 +- pages/statistics/index.jsx | 51 +- pages/user.jsx | 113 +- styles/globals.css | 8 +- styles/theme.js | 4 +- utils/axios.instance.js | 12 +- utils/file-upload.js | 10 +- utils/opening_hours.js | 25 +- utils/time-date.js | 28 +- 96 files changed, 5036 insertions(+), 3629 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json create mode 100644 .prettierrc diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..9cc8144 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,23 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + }, + settings: { + react: { + version: 'detect', + }, + }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:prettier/recommended', + 'plugin:@next/next/recommended', + 'next/core-web-vitals', + ], + rules: { + 'react/prop-types': 'off', + 'react/react-in-jsx-scope': 'off', + }, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index bffb357..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/.github/workflows/github-action.yaml b/.github/workflows/github-action.yaml index 173b728..a8e298f 100644 --- a/.github/workflows/github-action.yaml +++ b/.github/workflows/github-action.yaml @@ -10,8 +10,26 @@ env: ECR_REPOSITORY: popo-admin-web jobs: + lint: + name: Prettier and ESLint check + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install dependencies + run: npm install + - name: Run Prettier + run: npx prettier --check . + - name: Run ESLint + run: npx next lint + docker_build_and_push: name: Docker build and push + needs: lint runs-on: ubuntu-latest steps: - name: Checkout @@ -60,7 +78,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check the deployed service URL - uses: jtalk/url-health-check-action@v3 + uses: jtalk/url-health-check-action@v4 with: url: https://admin.popo.poapper.club|https://admin.popo-dev.poapper.club follow-redirect: true diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9ff7535 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "singleQuote": true, + "semi": true, + "useTabs": false, + "tabWidth": 2, + "trailingComma": "all", + "printWidth": 80 +} diff --git a/assets/club.type.options.js b/assets/club.type.options.js index 182e1b0..201b85b 100644 --- a/assets/club.type.options.js +++ b/assets/club.type.options.js @@ -1,8 +1,8 @@ export const ClubTypeOptions = [ - { key: "performance1", text: "공연1", value: "performance1" }, - { key: "performance2", text: "공연2", value: "performance2" }, - { key: "societyAndReligion", text: "사회종교", value: "societyAndReligion" }, - { key: "sports", text: "체육", value: "sports" }, - { key: "hobbyAndExhibition", text: "취미전시", value: "hobbyAndExhibition" }, - { key: "study", text: "학술", value: "study" }, + { key: 'performance1', text: '공연1', value: 'performance1' }, + { key: 'performance2', text: '공연2', value: 'performance2' }, + { key: 'societyAndReligion', text: '사회종교', value: 'societyAndReligion' }, + { key: 'sports', text: '체육', value: 'sports' }, + { key: 'hobbyAndExhibition', text: '취미전시', value: 'hobbyAndExhibition' }, + { key: 'study', text: '학술', value: 'study' }, ]; diff --git a/assets/owner.options.js b/assets/owner.options.js index 7e503fc..2d6e66f 100644 --- a/assets/owner.options.js +++ b/assets/owner.options.js @@ -1,7 +1,7 @@ export const OwnerOptions = [ - { key: "dongyeon", text: "동아리연합회", value: "dongyeon" }, - { key: "dormUnion", text: "생활관자치회", value: "dormUnion" }, - { key: "chonghak", text: "총학생회", value: "chonghak" }, - { key: "saengna", text: "생각나눔", value: "saengna" }, - { key: "others", text: "그 외", value: "others" }, + { key: 'dongyeon', text: '동아리연합회', value: 'dongyeon' }, + { key: 'dormUnion', text: '생활관자치회', value: 'dormUnion' }, + { key: 'chonghak', text: '총학생회', value: 'chonghak' }, + { key: 'saengna', text: '생각나눔', value: 'saengna' }, + { key: 'others', text: '그 외', value: 'others' }, ]; diff --git a/assets/region.options.js b/assets/region.options.js index b6c4b89..f7be405 100644 --- a/assets/region.options.js +++ b/assets/region.options.js @@ -1,7 +1,7 @@ export const RegionOptions = [ - { key: "STUDENT_HALL", text: "학생 회관", value: "STUDENT_HALL" }, - { key: "JIGOK_CENTER", text: "지곡 회관", value: "JIGOK_CENTER" }, - { key: "COMMUNITY_CENTER", text: "커뮤니티 센터", value: "COMMUNITY_CENTER" }, - { key: "RESIDENTIAL_COLLEGE", text: "RC", value: "RESIDENTIAL_COLLEGE" }, - { key: "OTHERS", text: "기타", value: "OTHERS" }, + { key: 'STUDENT_HALL', text: '학생 회관', value: 'STUDENT_HALL' }, + { key: 'JIGOK_CENTER', text: '지곡 회관', value: 'JIGOK_CENTER' }, + { key: 'COMMUNITY_CENTER', text: '커뮤니티 센터', value: 'COMMUNITY_CENTER' }, + { key: 'RESIDENTIAL_COLLEGE', text: 'RC', value: 'RESIDENTIAL_COLLEGE' }, + { key: 'OTHERS', text: '기타', value: 'OTHERS' }, ]; diff --git a/components/board/benefit/affiliate/affiliate.cards.jsx b/components/board/benefit/affiliate/affiliate.cards.jsx index f0b4567..8086b22 100644 --- a/components/board/benefit/affiliate/affiliate.cards.jsx +++ b/components/board/benefit/affiliate/affiliate.cards.jsx @@ -1,50 +1,44 @@ -import React, { useState } from 'react' -import { Card, Modal, Grid, Header } from 'semantic-ui-react' +import React, { useState } from 'react'; +import { Card, Modal, Grid, Header } from 'semantic-ui-react'; -const AffiliateCards = ({affiliates}) => { +const AffiliateCards = ({ affiliates }) => { const initialFlags = Array.from({ length: affiliates.length }, () => false); const [flags, setFlags] = useState(initialFlags); const toggleFlag = (index) => { - setFlags(prevFlags => { + setFlags((prevFlags) => { const newFlags = [...prevFlags]; newFlags[index] = !newFlags[index]; return newFlags; }); }; - + return ( - - { - affiliates.map((affiliate, idx) => - - - - {affiliate.title} - - {affiliate.meta_content} - - - - } - onClose={() => toggleFlag(idx)} - onOpen={() => toggleFlag(idx)} - > -
- -

- {affiliate.content} -

-
- - - ) - } + + {affiliates.map((affiliate, idx) => ( + + + + {affiliate.title} + {affiliate.meta_content} + + + } + onClose={() => toggleFlag(idx)} + onOpen={() => toggleFlag(idx)} + > +
+ +

{affiliate.content}

+
+ + + ))} - ) -} + ); +}; -export default AffiliateCards \ No newline at end of file +export default AffiliateCards; diff --git a/components/board/benefit/affiliate/affiliate.table.jsx b/components/board/benefit/affiliate/affiliate.table.jsx index d0c6203..4ce2a93 100644 --- a/components/board/benefit/affiliate/affiliate.table.jsx +++ b/components/board/benefit/affiliate/affiliate.table.jsx @@ -1,54 +1,40 @@ -import React from 'react' -import Link from "next/link"; -import moment from 'moment' -import { Table } from 'semantic-ui-react' +import React from 'react'; +import Link from 'next/link'; +import moment from 'moment'; +import { Table } from 'semantic-ui-react'; const AffiliateTable = ({ affiliateList }) => { - return ( - +
- - id - - - 업체명 - - - 짤은 설명 - - - 설명 - - - 생성일 - + id + 업체명 + 짤은 설명 + 설명 + 생성일 - { - affiliateList.map((affiliate) => ( - - - {affiliate.id} - {affiliate.title} - {affiliate.content_short} - {affiliate.content} - - { - moment(affiliate.created_at).format('YYYY-MM-DD HH:mm') - } - - - - )) - } + {affiliateList.map((affiliate) => ( + + + {affiliate.id} + {affiliate.title} + {affiliate.content_short} + {affiliate.content} + + {moment(affiliate.created_at).format('YYYY-MM-DD HH:mm')} + + + + ))}
- ) -} + ); +}; export default AffiliateTable; diff --git a/components/board/benefit/discount/discount.cards.jsx b/components/board/benefit/discount/discount.cards.jsx index fa843c9..5cae66f 100644 --- a/components/board/benefit/discount/discount.cards.jsx +++ b/components/board/benefit/discount/discount.cards.jsx @@ -1,54 +1,60 @@ -import React, { useState } from 'react' -import { Card, Modal, Grid, Header, Divider, Icon } from 'semantic-ui-react' +import React, { useState } from 'react'; +import { Card, Modal, Grid, Header, Divider, Icon } from 'semantic-ui-react'; -const DiscountOfferCards = ({discountOffers}) => { - const initialFlags = Array.from({ length: discountOffers.length }, () => false); +const DiscountOfferCards = ({ discountOffers }) => { + const initialFlags = Array.from( + { length: discountOffers.length }, + () => false, + ); const [flags, setFlags] = useState(initialFlags); const toggleFlag = (index) => { - setFlags(prevFlags => { + setFlags((prevFlags) => { const newFlags = [...prevFlags]; newFlags[index] = !newFlags[index]; return newFlags; }); }; - + return ( - - { - discountOffers.map((discountOffer, idx) => - - - - {discountOffer.title} - - {discountOffer.content} - - - - } - onClose={() => toggleFlag(idx)} - onOpen={() => toggleFlag(idx)} - > -
- -

영업 시간: {discountOffer.open_hour}

-

가게 번호: {discountOffer.phone}

- -

할인 내용

-

- {discountOffer.content} -

-
- - - ) - } + + {discountOffers.map((discountOffer, idx) => ( + + + + {discountOffer.title} + {discountOffer.content} + + + } + onClose={() => toggleFlag(idx)} + onOpen={() => toggleFlag(idx)} + > +
+ +

+ + 영업 시간: {discountOffer.open_hour} +

+

+ + 가게 번호: {discountOffer.phone} +

+ +

+ + 할인 내용 +

+

{discountOffer.content}

+
+ + + ))} - ) -} + ); +}; -export default DiscountOfferCards \ No newline at end of file +export default DiscountOfferCards; diff --git a/components/board/benefit/discount/discount.table.jsx b/components/board/benefit/discount/discount.table.jsx index 60553e8..9eeed52 100644 --- a/components/board/benefit/discount/discount.table.jsx +++ b/components/board/benefit/discount/discount.table.jsx @@ -1,62 +1,44 @@ -import React from 'react' -import Link from "next/link"; -import moment from 'moment' -import { Table } from 'semantic-ui-react' +import React from 'react'; +import Link from 'next/link'; +import moment from 'moment'; +import { Table } from 'semantic-ui-react'; const DiscountTable = ({ discountList }) => { - return ( - +
- - id - - - 업체명 - - - 지역 - - - 영업 시간 - - - 가게 번호 - - - 할인 내용 - - - 생성일 - + id + 업체명 + 지역 + 영업 시간 + 가게 번호 + 할인 내용 + 생성일 - { - discountList.map((discount) => ( - - - {discount.id} - {discount.title} - {discount.region} - {discount.open_hour} - {discount.phone} - {discount.content} - - { - moment(discount.created_at).format('YYYY-MM-DD HH:mm') - } - - - - )) - } + {discountList.map((discount) => ( + + + {discount.id} + {discount.title} + {discount.region} + {discount.open_hour} + {discount.phone} + {discount.content} + + {moment(discount.created_at).format('YYYY-MM-DD HH:mm')} + + + + ))}
- ) -} + ); +}; export default DiscountTable; diff --git a/components/board/board.layout.jsx b/components/board/board.layout.jsx index 96b39dd..18d5d6c 100644 --- a/components/board/board.layout.jsx +++ b/components/board/board.layout.jsx @@ -1,14 +1,14 @@ -import LayoutWithAuth from '../layout/layout.auth.with' -import BoardMenubar from './board.menubar' +import LayoutWithAuth from '../layout/layout.auth.with'; +import BoardMenubar from './board.menubar'; const BoardLayout = ({ children }) => { return (

게시물 관리

- + {children}
- ) -} + ); +}; -export default BoardLayout \ No newline at end of file +export default BoardLayout; diff --git a/components/board/board.menubar.jsx b/components/board/board.menubar.jsx index 12975cf..2282797 100644 --- a/components/board/board.menubar.jsx +++ b/components/board/board.menubar.jsx @@ -1,33 +1,27 @@ -import React, { Component } from 'react' -import Link from 'next/link' -import { Menu } from 'semantic-ui-react' +import React, { Component } from 'react'; +import Link from 'next/link'; +import { Menu } from 'semantic-ui-react'; export default class BoardMenubar extends Component { - render () { + render() { return ( - - POPO 설정값 - + POPO 설정값 - - 공지사항 - + 공지사항 RC 사생 명단 업로드 - - 생활백서 - + 생활백서 총학 제휴/할인 업체 - ) + ); } -} \ No newline at end of file +} diff --git a/components/board/notice/notice.table.jsx b/components/board/notice/notice.table.jsx index 50c185c..dfc1fdc 100644 --- a/components/board/notice/notice.table.jsx +++ b/components/board/notice/notice.table.jsx @@ -1,14 +1,10 @@ -import Link from 'next/link' -import moment from 'moment' -import { Table } from 'semantic-ui-react' +import Link from 'next/link'; +import moment from 'moment'; +import { Table } from 'semantic-ui-react'; -const NoticeTable - = ({notices}) => { +const NoticeTable = ({ notices }) => { return ( - +
id. @@ -20,44 +16,50 @@ const NoticeTable - { - notices.map((notice, idx) => { - const isActive = moment().isBetween(moment(notice.start_datetime), moment(notice.end_datetime)); - const duration = moment(notice.end_datetime).diff(moment(notice.start_datetime), 'hours'); - return ( - - - {notice.id} - - { - notice.link ? ( - - {notice.title} - - ) : notice.title - } - - - {notice.content} - - {/* + {notices.map((notice) => { + const isActive = moment().isBetween( + moment(notice.start_datetime), + moment(notice.end_datetime), + ); + const duration = moment(notice.end_datetime).diff( + moment(notice.start_datetime), + 'hours', + ); + return ( + + + {notice.id} + + {notice.link ? ( + + {notice.title} + + ) : ( + notice.title + )} + + + {notice.content} + + {/* */} - - {moment(notice.start_datetime).format('YYYY-MM-DD HH:mm')} ~ {moment(notice.end_datetime).format('YYYY-MM-DD HH:mm')}
- ({Number(duration/24).toFixed(0)}일 {duration%24}시간) -
- - {notice.click_count} - -
- - ) - }) - } + + {moment(notice.start_datetime).format('YYYY-MM-DD HH:mm')} ~{' '} + {moment(notice.end_datetime).format('YYYY-MM-DD HH:mm')} +
({Number(duration / 24).toFixed(0)}일 {duration % 24} + 시간) +
+ {notice.click_count} +
+ + ); + })}
- ) -} + ); +}; -export default NoticeTable +export default NoticeTable; diff --git a/components/board/whitebook/whitebook.create.modal.jsx b/components/board/whitebook/whitebook.create.modal.jsx index 56d93ab..2e7032b 100644 --- a/components/board/whitebook/whitebook.create.modal.jsx +++ b/components/board/whitebook/whitebook.create.modal.jsx @@ -1,36 +1,39 @@ -import { Form, Modal } from 'semantic-ui-react' -import { useState } from 'react' +import { Form, Modal } from 'semantic-ui-react'; +import { useState } from 'react'; import { PoPoAxios } from '@/utils/axios.instance'; const WhitebookCreateModal = (props) => { - const [open, setOpen] = useState(false) - const [title, setTitle] = useState('') - const [link, setLink] = useState('') - const [content, setContent] = useState('') - const [showOnlyLogin, setShowOnlyLogin] = useState(false) + const [open, setOpen] = useState(false); + const [title, setTitle] = useState(''); + const [link, setLink] = useState(''); + const [content, setContent] = useState(''); + const [showOnlyLogin, setShowOnlyLogin] = useState(false); const handleSubmit = async () => { try { await PoPoAxios.post( - '/whitebook', { + '/whitebook', + { title: title, link: link, content: content, - show_only_login: showOnlyLogin - }, { withCredentials: true }, - ) - setOpen(false) - window.location.reload() + show_only_login: showOnlyLogin, + }, + { withCredentials: true }, + ); + setOpen(false); + window.location.reload(); } catch (e) { - alert('생활백서 생성에 실패했습니다.') - console.log(e) + alert('생활백서 생성에 실패했습니다.'); + console.log(e); } - } + }; return ( setOpen(false)} onOpen={() => setOpen(true)} > @@ -40,18 +43,18 @@ const WhitebookCreateModal = (props) => { setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setLink(e.target.value)} + onChange={(e) => setLink(e.target.value)} /> setContent(e.target.value)} + onChange={(e) => setContent(e.target.value)} /> { /> - + 생성 - ) -} + ); +}; -export default WhitebookCreateModal \ No newline at end of file +export default WhitebookCreateModal; diff --git a/components/board/whitebook/whitebook.table.jsx b/components/board/whitebook/whitebook.table.jsx index d8e8560..6528345 100644 --- a/components/board/whitebook/whitebook.table.jsx +++ b/components/board/whitebook/whitebook.table.jsx @@ -1,14 +1,10 @@ -import moment from 'moment' -import { Table } from 'semantic-ui-react' -import WhitebookUpdateModal from './whitebook.update.modal' - -const WhitebookTable = ({whitebooks}) => { +import moment from 'moment'; +import { Table } from 'semantic-ui-react'; +import WhitebookUpdateModal from './whitebook.update.modal'; +const WhitebookTable = ({ whitebooks }) => { return ( - +
idx. @@ -19,35 +15,30 @@ const WhitebookTable = ({whitebooks}) => { - { - whitebooks.map((whitebook, idx) => - - {idx + 1} - - - {whitebook.title} - - - {whitebook.content} - - {moment(whitebook.created_at). - format('YYYY-MM-DD HH:mm')} - - - {whitebook.click_count} - - - } - /> - ) - } + {whitebooks.map((whitebook, idx) => ( + + {idx + 1} + + + {whitebook.title} + + + {whitebook.content} + + {moment(whitebook.created_at).format('YYYY-MM-DD HH:mm')} + + {whitebook.click_count} + + } + /> + ))}
- ) -} + ); +}; -export default WhitebookTable \ No newline at end of file +export default WhitebookTable; diff --git a/components/board/whitebook/whitebook.update.modal.jsx b/components/board/whitebook/whitebook.update.modal.jsx index 452a2cd..6643ced 100644 --- a/components/board/whitebook/whitebook.update.modal.jsx +++ b/components/board/whitebook/whitebook.update.modal.jsx @@ -1,39 +1,42 @@ -import { Button, Form, Icon, Modal } from 'semantic-ui-react' -import { useState } from 'react' -import DeleteConfirmModal from '../../common/delete.confirm.modal' +import { Button, Form, Icon, Modal } from 'semantic-ui-react'; +import { useState } from 'react'; +import DeleteConfirmModal from '../../common/delete.confirm.modal'; import { PoPoAxios } from '@/utils/axios.instance'; const WhitebookUpdateModal = ({ trigger, whitebook }) => { - const [open, setOpen] = useState(false) - const [deleteModalOpen, setDeleteModalOpen] = useState(false) + const [open, setOpen] = useState(false); + const [deleteModalOpen, setDeleteModalOpen] = useState(false); - const [title, setTitle] = useState(whitebook.title) - const [link, setLink] = useState(whitebook.link) - const [content, setContent] = useState(whitebook.content) - const [showOnlyLogin, setShowOnlyLogin] = useState(whitebook.show_only_login) + const [title, setTitle] = useState(whitebook.title); + const [link, setLink] = useState(whitebook.link); + const [content, setContent] = useState(whitebook.content); + const [showOnlyLogin, setShowOnlyLogin] = useState(whitebook.show_only_login); const handleSubmit = async () => { try { await PoPoAxios.put( - `/whitebook/${whitebook.uuid}`, { + `/whitebook/${whitebook.uuid}`, + { title: title, link: link, content: content, - show_only_login: showOnlyLogin - }, { withCredentials: true }, - ) - setOpen(false) - window.location.reload() + show_only_login: showOnlyLogin, + }, + { withCredentials: true }, + ); + setOpen(false); + window.location.reload(); } catch (e) { - alert('생활백서 수정에 실패했습니다.') - console.log(e) + alert('생활백서 수정에 실패했습니다.'); + console.log(e); } - } + }; return ( setOpen(false)} onOpen={() => setOpen(true)} > @@ -44,20 +47,20 @@ const WhitebookUpdateModal = ({ trigger, whitebook }) => { required label={'생활백서 제목'} value={title} - onChange={e => setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setLink(e.target.value)} + onChange={(e) => setLink(e.target.value)} /> setContent(e.target.value)} + onChange={(e) => setContent(e.target.value)} /> { - + 수정 setDeleteModalOpen(true)}> - 삭제 - )} + trigger={ + + } /> - ) -} + ); +}; -export default WhitebookUpdateModal \ No newline at end of file +export default WhitebookUpdateModal; diff --git a/components/common/csv-upload.form.jsx b/components/common/csv-upload.form.jsx index 1429e91..b71494a 100644 --- a/components/common/csv-upload.form.jsx +++ b/components/common/csv-upload.form.jsx @@ -1,51 +1,54 @@ -import { useState } from "react"; -import { Button, Form } from "semantic-ui-react" -import { CsvUpload } from "@/utils/file-upload"; -import { PoPoAxios } from "@/utils/axios.instance"; - -const CsvUploadForm = ({ label, uploadUri }) => { - const [uploadedFile, setUploadedFile] = useState(null) - - return ( -
- { - const file = evt.target.files[0]; - if (!file.name.includes('.csv')) { - alert('CSV 파일만 업로드 가능합니다.'); - return; - } - setUploadedFile(file); - }} - /> - - - - ) -} - -export default CsvUploadForm; +import { useState } from 'react'; +import { Button, Form } from 'semantic-ui-react'; +import { CsvUpload } from '@/utils/file-upload'; +import { PoPoAxios } from '@/utils/axios.instance'; + +const CsvUploadForm = ({ label, uploadUri }) => { + const [uploadedFile, setUploadedFile] = useState(null); + + return ( +
+ { + const file = evt.target.files[0]; + if (!file.name.includes('.csv')) { + alert('CSV 파일만 업로드 가능합니다.'); + return; + } + setUploadedFile(file); + }} + /> + + + + ); +}; + +export default CsvUploadForm; diff --git a/components/common/delete.confirm.modal.jsx b/components/common/delete.confirm.modal.jsx index 7571fe6..1d89509 100644 --- a/components/common/delete.confirm.modal.jsx +++ b/components/common/delete.confirm.modal.jsx @@ -1,35 +1,35 @@ -import { useState } from 'react' -import { Button, Modal } from 'semantic-ui-react' -import { useRouter } from "next/router"; +import { useState } from 'react'; +import { Button, Modal } from 'semantic-ui-react'; +import { useRouter } from 'next/router'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; const DeleteConfirmModal = (props) => { const router = useRouter(); - const deleteTarget = props.target - const deleteURI = props.deleteURI + const deleteTarget = props.target; + const deleteURI = props.deleteURI; const afterDeleteURI = props.afterDeleteURI; - const [open, setOpen] = useState(props.open) + const [open, setOpen] = useState(props.open); const handleDelete = async () => { try { - await PoPoAxios.delete(`/${deleteURI}`, - { withCredentials: true }) + await PoPoAxios.delete(`/${deleteURI}`, { withCredentials: true }); if (afterDeleteURI) { router.push(afterDeleteURI); } else { - window.location.reload() + window.location.reload(); } } catch (err) { const errMsg = err.response.data.message; alert(`삭제에 실패했습니다.\n${errMsg}`); } - } + }; return ( setOpen(false)} onOpen={() => setOpen(true)} > @@ -38,19 +38,11 @@ const DeleteConfirmModal = (props) => { {deleteTarget}이 삭제 됩니다. 정말 삭제 하시겠습니까? - - -
- { - type === 'Everyday' ? ( -
+
+ {type === 'Everyday' ? ( +
+ + updateOpeningHour('Everyday', evt.target.value) + } + className={checkValid(openingHour['Everyday']) ? 'green' : 'red'} + placeholder="08:00-14:00, 20:00-24:00" + size={'mini'} + /> +
+ ) : ( +
+ {Weekdays.map((weekday) => ( updateOpeningHour('Everyday', evt.target.value)} - className={checkValid(openingHour['Everyday']) ? 'green' : 'red'} - placeholder='08:00-14:00, 20:00-24:00' size={'mini'} + key={weekday.key} + label={weekday.label} + value={openingHour[weekday.key]} + onChange={(evt) => + updateOpeningHour(weekday.key, evt.target.value) + } + className={ + checkValid(openingHour[weekday.key]) ? 'green' : 'red' + } + placeholder="08:00-14:00, 20:00-24:00" + size={'mini'} /> -
- ) : ( -
- { - Weekdays.map(weekday => - updateOpeningHour(weekday.key, evt.target.value)} - className={checkValid(openingHour[weekday.key]) ? 'green' : 'red'} - placeholder='08:00-14:00, 20:00-24:00' size={'mini'} /> - ) - } -
- ) - } + ))} +
+ )}
- ) -} + ); +}; export default OpeningHoursEditor; - diff --git a/components/equipment/equipment.reservation.confirm.modal.jsx b/components/equipment/equipment.reservation.confirm.modal.jsx index 841da17..bd01aac 100644 --- a/components/equipment/equipment.reservation.confirm.modal.jsx +++ b/components/equipment/equipment.reservation.confirm.modal.jsx @@ -1,33 +1,36 @@ -import { Button, Form, Icon, Label, Modal, Segment } from 'semantic-ui-react' -import React, { useState } from 'react' -import moment from 'moment' -import DeleteConfirmModal from '../common/delete.confirm.modal' +import { Button, Form, Icon, Label, Modal, Segment } from 'semantic-ui-react'; +import React, { useState } from 'react'; +import moment from 'moment'; +import DeleteConfirmModal from '../common/delete.confirm.modal'; import { PoPoAxios } from '@/utils/axios.instance'; const EquipmentReservationConfirmModal = (props) => { - const reservation = props.reservation + const reservation = props.reservation; - const [open, setOpen] = useState(false) - const [send_email, setSendEmail] = useState(true) + const [open, setOpen] = useState(false); + const [send_email, setSendEmail] = useState(true); const handlePatch = async (e, data) => { try { - const patch_type = data.name // {accept, reject} + const patch_type = data.name; // {accept, reject} await PoPoAxios.patch( `/reservation-equip/${reservation.uuid}/status/${patch_type}?sendEmail=${send_email}`, - {}, {withCredentials: true}) - setOpen(false) - window.location.reload() + {}, + { withCredentials: true }, + ); + setOpen(false); + window.location.reload(); } catch (err) { const errMsg = err.response.data.message; alert(`예약 승인/거절에 실패했습니다.\n${errMsg}`); } - } + }; return ( setOpen(false)} onOpen={() => setOpen(true)} > @@ -37,56 +40,40 @@ const EquipmentReservationConfirmModal = (props) => {

장비 목록

- { - reservation.equipments.map(equipment => { - return ( - - ) - }) - } + {reservation.equipments.map((equipment) => { + return ( + + ); + })}

사용자

-
- {reservation.booker.name} -
+
{reservation.booker.name}

전화번호

-
- {reservation.phone} -
+
{reservation.phone}

예약 제목

-
- {reservation.title} -
+
{reservation.title}

설명

-
- {reservation.description} -
+
{reservation.description}

예약 기간

- {moment(reservation.date, 'YYYYMMDD'). - format('YYYY-MM-DD')} + {moment(reservation.date, 'YYYYMMDD').format('YYYY-MM-DD')}   - {moment(reservation.start_time, 'HHmm'). - format('HH:mm')} + {moment(reservation.start_time, 'HHmm').format('HH:mm')}  ~  - {moment(reservation.end_time, 'HHmm'). - format('HH:mm')} + {moment(reservation.end_time, 'HHmm').format('HH:mm')}
@@ -106,15 +93,11 @@ const EquipmentReservationConfirmModal = (props) => { /> - - @@ -123,7 +106,7 @@ const EquipmentReservationConfirmModal = (props) => { deleteURI={`reservation-equip/${reservation.uuid}`} trigger={ } /> @@ -132,7 +115,7 @@ const EquipmentReservationConfirmModal = (props) => {
- ) -} + ); +}; -export default EquipmentReservationConfirmModal \ No newline at end of file +export default EquipmentReservationConfirmModal; diff --git a/components/equipment/equipment.reservation.table.jsx b/components/equipment/equipment.reservation.table.jsx index ec7f254..239779b 100644 --- a/components/equipment/equipment.reservation.table.jsx +++ b/components/equipment/equipment.reservation.table.jsx @@ -1,14 +1,11 @@ -import React from 'react' -import { Label, Table } from 'semantic-ui-react' -import moment from 'moment' -import EquipmentReservationConfirmModal - from './equipment.reservation.confirm.modal' +import React from 'react'; +import { Label, Table } from 'semantic-ui-react'; +import moment from 'moment'; +import EquipmentReservationConfirmModal from './equipment.reservation.confirm.modal'; const EquipmentReservationTable = ({ reservations, startIdx }) => { return ( - +
idx. @@ -20,52 +17,47 @@ const EquipmentReservationTable = ({ reservations, startIdx }) => { - { - reservations.map((reservation, idx) => - - {startIdx + idx + 1} - - { - reservation.equipments.map(equipment => { - return ( - - ) - }) - } - - {reservation.booker.name} - {reservation.title} - - - {moment(reservation.date, 'YYYYMMDD'). - format('YYYY년 MM월 DD일')} -
- {moment(reservation.start_time, 'HHmm'). - format('HH:mm')} -  ~  - {moment(reservation.end_time, 'HHmm'). - format('HH:mm')} -
-
- {reservation.status} - - } - />, - ) - } + {reservations.map((reservation, idx) => ( + + {startIdx + idx + 1} + + {reservation.equipments.map((equipment) => { + return ( + + ); + })} + + {reservation.booker.name} + {reservation.title} + + + {moment(reservation.date, 'YYYYMMDD').format( + 'YYYY년 MM월 DD일', + )} +
+ {moment(reservation.start_time, 'HHmm').format('HH:mm')} +  ~  + {moment(reservation.end_time, 'HHmm').format('HH:mm')} +
+
+ {reservation.status} + + } + /> + ))}
- ) -} + ); +}; -export default EquipmentReservationTable \ No newline at end of file +export default EquipmentReservationTable; diff --git a/components/equipment/equipment.reservation.wait.table.jsx b/components/equipment/equipment.reservation.wait.table.jsx index 90df58b..35e8429 100644 --- a/components/equipment/equipment.reservation.wait.table.jsx +++ b/components/equipment/equipment.reservation.wait.table.jsx @@ -1,14 +1,11 @@ -import React from 'react' -import { Label, Table } from 'semantic-ui-react' -import moment from 'moment' -import EquipmentReservationConfirmModal - from './equipment.reservation.confirm.modal' +import React from 'react'; +import { Label, Table } from 'semantic-ui-react'; +import moment from 'moment'; +import EquipmentReservationConfirmModal from './equipment.reservation.confirm.modal'; const EquipmentReservationWaitTable = ({ reservations, startIdx }) => { return ( - +
idx. @@ -20,63 +17,65 @@ const EquipmentReservationWaitTable = ({ reservations, startIdx }) => { - { - reservations.map((reservation, idx) => { + {reservations.map((reservation, idx) => { + const start_datetime = moment( + `${reservation.date} ${reservation.start_time}`, + 'YYYYMMDD HHmm', + ); + const end_datetime = moment( + `${reservation.date} ${reservation.end_time}`, + 'YYYYMMDD HHmm', + ); - const start_datetime = moment( - `${reservation.date} ${reservation.start_time}`, 'YYYYMMDD HHmm') - const end_datetime = moment( - `${reservation.date} ${reservation.end_time}`, 'YYYYMMDD HHmm') + const isOutdated = moment() > end_datetime; + const isNow = start_datetime <= moment() && moment() <= end_datetime; - const isOutdated = moment() > end_datetime; - const isNow = start_datetime <= moment() && moment() <= end_datetime; - - return ( - - {startIdx + idx + 1} - - { - reservation.equipments.map(equipment => { - return ( - - ) - }) - } - - {reservation.booker.name} - {reservation.title} - - - {moment(reservation.date, 'YYYYMMDD'). - format('YYYY년 MM월 DD일')} -
- {moment(reservation.start_time, 'HHmm'). - format('HH:mm')} -  ~  - {moment(reservation.end_time, 'HHmm'). - format('HH:mm')} -
-
- {reservation.status} - - } - /> - ) - }) - } + return ( + + {startIdx + idx + 1} + + {reservation.equipments.map((equipment) => { + return ( + + ); + })} + + {reservation.booker.name} + {reservation.title} + + + {moment(reservation.date, 'YYYYMMDD').format( + 'YYYY년 MM월 DD일', + )} +
+ {moment(reservation.start_time, 'HHmm').format('HH:mm')} +  ~  + {moment(reservation.end_time, 'HHmm').format('HH:mm')} +
+
+ {reservation.status} + + } + /> + ); + })}
- ) -} + ); +}; -export default EquipmentReservationWaitTable \ No newline at end of file +export default EquipmentReservationWaitTable; diff --git a/components/equipment/equipment.table.jsx b/components/equipment/equipment.table.jsx index a6c981e..9a34f1c 100644 --- a/components/equipment/equipment.table.jsx +++ b/components/equipment/equipment.table.jsx @@ -1,22 +1,22 @@ -import React from 'react' -import Link from "next/link"; -import { Table } from 'semantic-ui-react' -import _ from 'lodash' +import React from 'react'; +import Link from 'next/link'; +import { Table } from 'semantic-ui-react'; +import _ from 'lodash'; const ownerNames = { - 'chonghak': '총학생회', - 'dongyeon': '동아리연합회', - 'dormUnion': '생활관자치회', - 'saengna': '생각나눔', - 'others': '그 외', -} + chonghak: '총학생회', + dongyeon: '동아리연합회', + dormUnion: '생활관자치회', + saengna: '생각나눔', + others: '그 외', +}; const EquipmentTable = ({ equipmentList }) => { const [state, dispatch] = React.useReducer(exampleReducer, { column: null, data: equipmentList, direction: null, - }) - const { column, data, direction } = state + }); + const { column, data, direction } = state; function exampleReducer(state, action) { switch (action.type) { @@ -27,23 +27,21 @@ const EquipmentTable = ({ equipmentList }) => { data: state.data.slice().reverse(), direction: state.direction === 'ascending' ? 'descending' : 'ascending', - } + }; } return { column: action.column, data: _.sortBy(state.data, [action.column]), direction: 'ascending', - } + }; default: - throw new Error() + throw new Error(); } } return ( - +
idx. @@ -55,7 +53,9 @@ const EquipmentTable = ({ equipmentList }) => { dispatch({ type: 'CHANGE_SORT', column: 'equip_owner' })} + onClick={() => + dispatch({ type: 'CHANGE_SORT', column: 'equip_owner' }) + } > 장비 소속 @@ -67,46 +67,53 @@ const EquipmentTable = ({ equipmentList }) => { dispatch({ type: 'CHANGE_SORT', column: 'max_minutes' })} + onClick={() => + dispatch({ type: 'CHANGE_SORT', column: 'max_minutes' }) + } > 일일 한도 (분) dispatch({ type: 'CHANGE_SORT', column: 'total_reservation_count' })} + onClick={() => + dispatch({ + type: 'CHANGE_SORT', + column: 'total_reservation_count', + }) + } > 총 예약 갯수 - { - data.map((equipment, idx) => ( - - - {idx + 1} - {equipment.name} - {ownerNames[equipment.equip_owner]} - {equipment.fee.toLocaleString()} - - { - equipment.max_minutes === 1440 ? - '제한 없음' : - equipment.max_minutes.toLocaleString() - } - - {equipment.total_reservation_count.toLocaleString()} - - - )) - } + {data.map((equipment, idx) => ( + + + {idx + 1} + {equipment.name} + {ownerNames[equipment.equip_owner]} + {equipment.fee.toLocaleString()} + + {equipment.max_minutes === 1440 + ? '제한 없음' + : equipment.max_minutes.toLocaleString()} + + + {equipment.total_reservation_count.toLocaleString()} + + + + ))} - - +
- ) -} + ); +}; -export default EquipmentTable \ No newline at end of file +export default EquipmentTable; diff --git a/components/introduce/association.table.jsx b/components/introduce/association.table.jsx index 07426ee..66a4eaa 100644 --- a/components/introduce/association.table.jsx +++ b/components/introduce/association.table.jsx @@ -1,15 +1,12 @@ -import moment from 'moment' -import Link from "next/link"; -import { Table } from 'semantic-ui-react' +import moment from 'moment'; +import Link from 'next/link'; +import { Table } from 'semantic-ui-react'; const AssociationTable = (props) => { - const associations = props.associations + const associations = props.associations; return ( - +
idx. @@ -22,30 +19,27 @@ const AssociationTable = (props) => { - { - associations.map((association, idx) => - - - {idx + 1} - {association.name} - {association.location} - {association.representative} - {association.contact} - {association.views} - - {moment(association.updateAt). - format('YYYY-MM-DD HH:mm')} - - - - ) - } + {associations.map((association, idx) => ( + + + {idx + 1} + {association.name} + {association.location} + {association.representative} + {association.contact} + {association.views} + + {moment(association.updateAt).format('YYYY-MM-DD HH:mm')} + + + + ))}
- ) -} + ); +}; -export default AssociationTable \ No newline at end of file +export default AssociationTable; diff --git a/components/introduce/club.table.jsx b/components/introduce/club.table.jsx index 410bd0e..19b9833 100644 --- a/components/introduce/club.table.jsx +++ b/components/introduce/club.table.jsx @@ -1,13 +1,10 @@ -import moment from 'moment' -import Link from "next/link"; -import { Table } from 'semantic-ui-react' +import moment from 'moment'; +import Link from 'next/link'; +import { Table } from 'semantic-ui-react'; const ClubTable = ({ clubs }) => { return ( - +
idx. @@ -20,27 +17,24 @@ const ClubTable = ({ clubs }) => { - { - clubs.map((club, idx) => - - - {idx + 1} - {club.name} - {club.location} - {club.representative} - {club.contact} - {club.views} - - {moment(club.updateAt). - format('YYYY-MM-DD HH:mm')} - - - - ) - } + {clubs.map((club, idx) => ( + + + {idx + 1} + {club.name} + {club.location} + {club.representative} + {club.contact} + {club.views} + + {moment(club.updateAt).format('YYYY-MM-DD HH:mm')} + + + + ))}
- ) -} + ); +}; -export default ClubTable \ No newline at end of file +export default ClubTable; diff --git a/components/introduce/introduce.layout.jsx b/components/introduce/introduce.layout.jsx index 558bd92..e70c928 100644 --- a/components/introduce/introduce.layout.jsx +++ b/components/introduce/introduce.layout.jsx @@ -1,14 +1,14 @@ -import LayoutWithAuth from '../layout/layout.auth.with' -import IntroduceMenubar from './introduce.menubar' +import LayoutWithAuth from '../layout/layout.auth.with'; +import IntroduceMenubar from './introduce.menubar'; const IntroduceLayout = ({ children }) => { return (

소개글 관리

- - { children } + + {children}
- ) -} + ); +}; -export default IntroduceLayout \ No newline at end of file +export default IntroduceLayout; diff --git a/components/introduce/introduce.menubar.jsx b/components/introduce/introduce.menubar.jsx index 546b53e..cd5d7ab 100644 --- a/components/introduce/introduce.menubar.jsx +++ b/components/introduce/introduce.menubar.jsx @@ -1,22 +1,18 @@ -import React, {Component} from 'react'; -import Link from 'next/link' -import {Menu} from "semantic-ui-react"; +import React, { Component } from 'react'; +import Link from 'next/link'; +import { Menu } from 'semantic-ui-react'; export default class IntroduceMenubar extends Component { render() { return ( - - - 자치단체 소개글 - + + 자치단체 소개글 - - - 동아리 소개글 - + + 동아리 소개글 - ) + ); } -} \ No newline at end of file +} diff --git a/components/layout/layout.auth.with.jsx b/components/layout/layout.auth.with.jsx index f9cb1a3..9dd5722 100644 --- a/components/layout/layout.auth.with.jsx +++ b/components/layout/layout.auth.with.jsx @@ -1,68 +1,61 @@ -import React, { useEffect, useState } from 'react' -import Head from 'next/head' -import { useRouter } from 'next/router' -import styled, { ThemeProvider } from 'styled-components' -import MediaQuery from 'react-responsive' +import React, { useEffect, useState } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import styled, { ThemeProvider } from 'styled-components'; +import MediaQuery from 'react-responsive'; -import theme from '../../styles/theme' +import theme from '../../styles/theme'; import { PoPoAxios } from '@/utils/axios.instance'; -import NavbarDesktop from '../navbar/navbar.desktop' -import NavbarMobile from '../navbar/navbar.mobile' -import SideBar from '../navbar/sidebar' +import NavbarDesktop from '../navbar/navbar.desktop'; +import NavbarMobile from '../navbar/navbar.mobile'; +import SideBar from '../navbar/sidebar'; const LayoutWithAuth = ({ children }) => { - const router = useRouter() - const [sidebarVisible, setSidebarVisible] = useState(false) + const router = useRouter(); + const [sidebarVisible, setSidebarVisible] = useState(false); useEffect(() => { - if (process.env.NEXT_PUBLIC_ENV === 'local') - return + if (process.env.NEXT_PUBLIC_ENV === 'local') return; PoPoAxios.get('/auth/verifyToken', { withCredentials: true, - }) - .catch(() => { - router.push('/login') - }) - }, [router]) + }).catch(() => { + router.push('/login'); + }); + }, [router]); return ( POPO 관리자페이지 - - + + <>
- setSidebarVisible(true)} - /> + setSidebarVisible(true)} /> setSidebarVisible(!sidebarVisible)} pushContent={ -
- {children} -
+
{children}
- }/> + } + />
- + -
- {children} -
+
{children}
- ) -} + ); +}; const Wrapper = styled.div` height: 100%; @@ -73,6 +66,6 @@ const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; -` +`; -export default LayoutWithAuth \ No newline at end of file +export default LayoutWithAuth; diff --git a/components/layout/layout.auth.without.jsx b/components/layout/layout.auth.without.jsx index 2dcf75b..abde8c8 100644 --- a/components/layout/layout.auth.without.jsx +++ b/components/layout/layout.auth.without.jsx @@ -1,22 +1,22 @@ -import Head from 'next/head' -import React from 'react' -import styled from 'styled-components' +import Head from 'next/head'; +import React from 'react'; +import styled from 'styled-components'; const LayoutWithoutAuth = ({ children }) => { return (
POPO 관리자페이지 - + - +
{children}
- ) -} + ); +}; const Wrapper = styled.div` height: 100%; @@ -27,6 +27,6 @@ const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; -` +`; -export default LayoutWithoutAuth \ No newline at end of file +export default LayoutWithoutAuth; diff --git a/components/navbar/menu.item.user.jsx b/components/navbar/menu.item.user.jsx index eb7379a..2edea9d 100644 --- a/components/navbar/menu.item.user.jsx +++ b/components/navbar/menu.item.user.jsx @@ -1,51 +1,49 @@ -import { useEffect, useState } from 'react' -import { Dropdown, Menu } from 'semantic-ui-react' -import { useRouter } from 'next/router' +import { useEffect, useState } from 'react'; +import { Dropdown, Menu } from 'semantic-ui-react'; +import { useRouter } from 'next/router'; import { PoPoAxios } from '@/utils/axios.instance'; const MenuItemUser = () => { - const router = useRouter() - const [user, setUser] = useState({}) + const router = useRouter(); + const [user, setUser] = useState({}); useEffect(() => { PoPoAxios.get('/auth/verifyToken', { - withCredentials: true, - }) - .then(res => setUser(res.data)) - .catch(() => {}) - }, []) + withCredentials: true, + }) + .then((res) => setUser(res.data)) + .catch(() => {}); + }, []); const handleLogout = async () => { try { await PoPoAxios.get('/auth/logout', { withCredentials: true, - }) - await router.push('/login') + }); + await router.push('/login'); } catch (err) { - alert('로그아웃에 실패했습니다.') - console.log(err) + alert('로그아웃에 실패했습니다.'); + console.log(err); } - } + }; return ( - - - + + + - ) -} + ); +}; -export default MenuItemUser \ No newline at end of file +export default MenuItemUser; diff --git a/components/navbar/navbar.desktop.jsx b/components/navbar/navbar.desktop.jsx index 2116389..52c3c19 100644 --- a/components/navbar/navbar.desktop.jsx +++ b/components/navbar/navbar.desktop.jsx @@ -1,7 +1,7 @@ -import styled from 'styled-components' -import { Image, Menu } from 'semantic-ui-react' -import Link from 'next/link' -import MenuItemUser from './menu.item.user' +import styled from 'styled-components'; +import { Image, Menu } from 'semantic-ui-react'; +import Link from 'next/link'; +import MenuItemUser from './menu.item.user'; const NavbarDesktop = () => { return ( @@ -11,12 +11,14 @@ const NavbarDesktop = () => { - - {'logo'} - + + {'logo'} + 관리자 @@ -36,15 +38,15 @@ const NavbarDesktop = () => { 통계 보기 - + - ) -} + ); +}; -export default NavbarDesktop +export default NavbarDesktop; const NavbarWrapper = styled.nav` border-bottom: 1px solid rgba(0, 0, 0, 0.1); @@ -56,7 +58,7 @@ const NavbarWrapper = styled.nav` position: fixed; top: 0; z-index: 10; -` +`; const NavbarInner = styled.div` display: flex; @@ -64,15 +66,11 @@ const NavbarInner = styled.div` align-items: center; margin: auto; - max-width: ${({ - theme, - }) => theme.contentWidth - }; -` + max-width: ${({ theme }) => theme.contentWidth}; +`; const NavbarMenu = styled(Menu)` box-shadow: none !important; border: none !important; width: 100%; -` - +`; diff --git a/components/navbar/navbar.mobile.jsx b/components/navbar/navbar.mobile.jsx index 2ef1602..120e288 100644 --- a/components/navbar/navbar.mobile.jsx +++ b/components/navbar/navbar.mobile.jsx @@ -1,43 +1,45 @@ -import { Icon, Image, Menu } from 'semantic-ui-react' -import styled from 'styled-components' -import Link from 'next/link' -import MenuItemUser from './menu.item.user' +import { Icon, Image, Menu } from 'semantic-ui-react'; +import styled from 'styled-components'; +import Link from 'next/link'; +import MenuItemUser from './menu.item.user'; const NavbarMobile = ({ openSidebar }) => { return ( -
+
관리자
- - + + - + {'logo'} - + - ) -} + ); +}; -export default NavbarMobile +export default NavbarMobile; const NavbarWrapper = styled.nav` border-bottom: 1px solid rgba(0, 0, 0, 0.1); @@ -49,7 +51,7 @@ const NavbarWrapper = styled.nav` position: fixed; top: 0; z-index: 10; -` +`; const NavbarInner = styled.div` display: flex; @@ -57,14 +59,11 @@ const NavbarInner = styled.div` align-items: center; margin: auto; - max-width: ${({ - theme, - }) => theme.contentWidth - }; -` + max-width: ${({ theme }) => theme.contentWidth}; +`; const NavbarMenu = styled(Menu)` box-shadow: none !important; border: none !important; width: 100%; -` \ No newline at end of file +`; diff --git a/components/navbar/sidebar.jsx b/components/navbar/sidebar.jsx index 7d7eb87..db22997 100644 --- a/components/navbar/sidebar.jsx +++ b/components/navbar/sidebar.jsx @@ -1,8 +1,7 @@ -import Link from 'next/link' -import { Menu, Segment, Sidebar } from 'semantic-ui-react' +import Link from 'next/link'; +import { Menu, Segment, Sidebar } from 'semantic-ui-react'; const SideBar = ({ visible, toggleSidebar, pushContent }) => { - return ( { onHide={toggleSidebar} > - + 유저 관리 - - 예약 관리 - + 예약 관리 - - 소개글 관리 - + 소개글 관리 - - 게시물 관리 - + 게시물 관리 - - 통계 보기 - + 통계 보기 - - {pushContent} - + {pushContent} - ) -} + ); +}; -export default SideBar \ No newline at end of file +export default SideBar; diff --git a/components/place/place.reservation.confirm.modal.jsx b/components/place/place.reservation.confirm.modal.jsx index cc36002..306a224 100644 --- a/components/place/place.reservation.confirm.modal.jsx +++ b/components/place/place.reservation.confirm.modal.jsx @@ -1,31 +1,34 @@ -import { Button, Form, Icon, Modal, Segment } from 'semantic-ui-react' -import React, { useState } from 'react' -import moment from 'moment' -import DeleteConfirmModal from '../common/delete.confirm.modal' +import { Button, Form, Icon, Modal, Segment } from 'semantic-ui-react'; +import React, { useState } from 'react'; +import moment from 'moment'; +import DeleteConfirmModal from '../common/delete.confirm.modal'; import { PoPoAxios } from '@/utils/axios.instance'; -const PlaceReservationConfirmModal = ({trigger, reservation}) => { - const [open, setOpen] = useState(false) - const [send_email, setSendEmail] = useState(true) +const PlaceReservationConfirmModal = ({ trigger, reservation }) => { + const [open, setOpen] = useState(false); + const [send_email, setSendEmail] = useState(true); const handlePatch = async (e, data) => { try { - const patch_type = data.name // {accept, reject} + const patch_type = data.name; // {accept, reject} await PoPoAxios.patch( `/reservation-place/${reservation.uuid}/status/${patch_type}?sendEmail=${send_email}`, - {}, {withCredentials: true}) - setOpen(false) - window.location.reload() + {}, + { withCredentials: true }, + ); + setOpen(false); + window.location.reload(); } catch (err) { const errMsg = err.response.data.message; alert(`예약 승인/거절에 실패했습니다.\n${errMsg}`); } - } + }; return ( setOpen(false)} onOpen={() => setOpen(true)} > @@ -34,46 +37,33 @@ const PlaceReservationConfirmModal = ({trigger, reservation}) => {

장소

-
- {reservation.place.name} -
+
{reservation.place.name}

사용자

-
- {reservation.booker.name} -
+
{reservation.booker.name}

전화번호

-
- {reservation.phone} -
+
{reservation.phone}

예약 제목

-
- {reservation.title} -
+
{reservation.title}

설명

-
- {reservation.description} -
+
{reservation.description}

예약 기간

- {moment(reservation.date, 'YYYYMMDD'). - format('YYYY-MM-DD')} + {moment(reservation.date, 'YYYYMMDD').format('YYYY-MM-DD')}   - {moment(reservation.start_time, 'HHmm'). - format('HH:mm')} + {moment(reservation.start_time, 'HHmm').format('HH:mm')}  ~  - {moment(reservation.end_time, 'HHmm'). - format('HH:mm')} + {moment(reservation.end_time, 'HHmm').format('HH:mm')}
@@ -93,15 +83,11 @@ const PlaceReservationConfirmModal = ({trigger, reservation}) => { /> - - @@ -110,7 +96,7 @@ const PlaceReservationConfirmModal = ({trigger, reservation}) => { deleteURI={`reservation-place/${reservation.uuid}`} trigger={ } /> @@ -119,7 +105,7 @@ const PlaceReservationConfirmModal = ({trigger, reservation}) => {
- ) -} + ); +}; -export default PlaceReservationConfirmModal \ No newline at end of file +export default PlaceReservationConfirmModal; diff --git a/components/place/place.reservation.table.jsx b/components/place/place.reservation.table.jsx index e5c1272..cf6f24e 100644 --- a/components/place/place.reservation.table.jsx +++ b/components/place/place.reservation.table.jsx @@ -1,14 +1,11 @@ -import React from 'react' -import { Table } from 'semantic-ui-react' -import moment from 'moment' -import PlaceReservationConfirmModal - from './place.reservation.confirm.modal' +import React from 'react'; +import { Table } from 'semantic-ui-react'; +import moment from 'moment'; +import PlaceReservationConfirmModal from './place.reservation.confirm.modal'; -const PlaceReservationTable = ({reservations, startIdx}) => { +const PlaceReservationTable = ({ reservations, startIdx }) => { return ( - +
idx. @@ -20,38 +17,35 @@ const PlaceReservationTable = ({reservations, startIdx}) => { - { - reservations.map((reservation, idx) => - - {startIdx + idx + 1} - {reservation.place.name} - {reservation.booker.name} - {reservation.title} - - - {moment(reservation.date, 'YYYYMMDD'). - format('YYYY년 MM월 DD일')} -
- {moment(reservation.start_time, 'HHmm'). - format('HH:mm')} -  ~  - {moment(reservation.end_time, 'HHmm'). - format('HH:mm')} -
-
- {reservation.status} - - } - />, - ) - } + {reservations.map((reservation, idx) => ( + + {startIdx + idx + 1} + {reservation.place.name} + {reservation.booker.name} + {reservation.title} + + + {moment(reservation.date, 'YYYYMMDD').format( + 'YYYY년 MM월 DD일', + )} +
+ {moment(reservation.start_time, 'HHmm').format('HH:mm')} +  ~  + {moment(reservation.end_time, 'HHmm').format('HH:mm')} +
+
+ {reservation.status} + + } + /> + ))}
- ) -} + ); +}; -export default PlaceReservationTable \ No newline at end of file +export default PlaceReservationTable; diff --git a/components/place/place.reservation.wait.table.jsx b/components/place/place.reservation.wait.table.jsx index 2b10561..62f248b 100644 --- a/components/place/place.reservation.wait.table.jsx +++ b/components/place/place.reservation.wait.table.jsx @@ -1,53 +1,64 @@ -import React, { useState } from 'react' -import { Checkbox, Table, Button } from 'semantic-ui-react' -import moment from 'moment' -import PlaceReservationConfirmModal - from './place.reservation.confirm.modal' +import React, { useState } from 'react'; +import { Checkbox, Table, Button } from 'semantic-ui-react'; +import moment from 'moment'; +import PlaceReservationConfirmModal from './place.reservation.confirm.modal'; import { PoPoAxios } from '@/utils/axios.instance'; -const PlaceReservationWaitTable = ({reservations}) => { +const PlaceReservationWaitTable = ({ reservations }) => { const [selectedUuidList, setSelectedUuidList] = useState([]); function acceptAllInProgressPlaceReservations() { - PoPoAxios.patch('/reservation-place/all/status/accept', - {uuid_list: selectedUuidList}, {withCredentials: true}).then(() => { - alert(`${selectedUuidList.length}개 장소 예약을 일괄 승인했습니다.`) - window.location.reload(); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`전체 예약 승인에 실패했습니다.\n${errMsg}`); - }) + PoPoAxios.patch( + '/reservation-place/all/status/accept', + { uuid_list: selectedUuidList }, + { withCredentials: true }, + ) + .then(() => { + alert(`${selectedUuidList.length}개 장소 예약을 일괄 승인했습니다.`); + window.location.reload(); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`전체 예약 승인에 실패했습니다.\n${errMsg}`); + }); } function handleCheck(newUuid) { const currentList = selectedUuidList; const isTargetSelected = currentList.includes(newUuid); - const newList = isTargetSelected ? - currentList.filter(uuid => uuid !== newUuid) + const newList = isTargetSelected + ? currentList.filter((uuid) => uuid !== newUuid) : currentList.concat(newUuid); - setSelectedUuidList(newList) + setSelectedUuidList(newList); } return ( - +
-
-

- 일괄 예약 승인은 예약 생성 순으로 처리 됩니다.
- 일괄 처리 도중 예약 Overlap이 발생하면, 처리가 중단 됩니다.
- 일괄 예약 승인 때는 승인 메일을 보내지 않습니다.
+

+

+ 일괄 예약 승인은 예약 생성 순으로 처리 됩니다. +
+ 일괄 처리 도중 예약 Overlap이 발생하면, 처리가 중단 됩니다. +
+ 일괄 예약 승인 때는 승인 메일을 보내지 않습니다. +

- ) -} + ); +}; -export default PlaceReservationWaitTable \ No newline at end of file +export default PlaceReservationWaitTable; diff --git a/components/place/place.table.jsx b/components/place/place.table.jsx index b7b18c8..d9a03fc 100644 --- a/components/place/place.table.jsx +++ b/components/place/place.table.jsx @@ -1,23 +1,23 @@ -import React from 'react' -import Link from "next/link"; -import { Table } from 'semantic-ui-react' -import _ from 'lodash' +import React from 'react'; +import Link from 'next/link'; +import { Table } from 'semantic-ui-react'; +import _ from 'lodash'; const regionNames = { - 'STUDENT_HALL': '학생 회관', - 'JIGOK_CENTER': '지곡 회관', - 'COMMUNITY_CENTER': '커뮤니티 센터', - 'RESIDENTIAL_COLLEGE': 'RC', - 'OTHERS': 'OTHERS', -} + STUDENT_HALL: '학생 회관', + JIGOK_CENTER: '지곡 회관', + COMMUNITY_CENTER: '커뮤니티 센터', + RESIDENTIAL_COLLEGE: 'RC', + OTHERS: 'OTHERS', +}; const PlaceTable = ({ placeList }) => { const [state, dispatch] = React.useReducer(exampleReducer, { column: null, data: placeList, direction: null, - }) - const { column, data, direction } = state + }); + const { column, data, direction } = state; function exampleReducer(state, action) { switch (action.type) { @@ -28,23 +28,21 @@ const PlaceTable = ({ placeList }) => { data: state.data.slice().reverse(), direction: state.direction === 'ascending' ? 'descending' : 'ascending', - } + }; } return { column: action.column, data: _.sortBy(state.data, [action.column]), direction: 'ascending', - } + }; default: - throw new Error() + throw new Error(); } } return ( - +
idx. @@ -56,7 +54,9 @@ const PlaceTable = ({ placeList }) => { dispatch({ type: 'CHANGE_SORT', column: 'location' })} + onClick={() => + dispatch({ type: 'CHANGE_SORT', column: 'location' }) + } > 위치 @@ -68,46 +68,50 @@ const PlaceTable = ({ placeList }) => { dispatch({ type: 'CHANGE_SORT', column: 'max_minutes' })} + onClick={() => + dispatch({ type: 'CHANGE_SORT', column: 'max_minutes' }) + } > 일일 한도 (분) dispatch({ type: 'CHANGE_SORT', column: 'total_reservation_count' })} + onClick={() => + dispatch({ + type: 'CHANGE_SORT', + column: 'total_reservation_count', + }) + } > 총 예약 갯수 - { - data.map((place, idx) => ( - - - {idx + 1} - {place.name} - {place.location} - {regionNames[place.region]} - - { - place.max_minutes === 1440 ? - '제한 없음' : - place.max_minutes.toLocaleString() - } - - {place.total_reservation_count.toLocaleString()} - - - )) - } + {data.map((place, idx) => ( + + + {idx + 1} + {place.name} + {place.location} + {regionNames[place.region]} + + {place.max_minutes === 1440 + ? '제한 없음' + : place.max_minutes.toLocaleString()} + + + {place.total_reservation_count.toLocaleString()} + + + + ))} - - +
- ) -} + ); +}; export default PlaceTable; diff --git a/components/reservation/opening_hours.list.jsx b/components/reservation/opening_hours.list.jsx index 75afafd..a3f0135 100644 --- a/components/reservation/opening_hours.list.jsx +++ b/components/reservation/opening_hours.list.jsx @@ -1,4 +1,4 @@ -import { KoreanWeekday } from '@/utils/opening_hours' +import { KoreanWeekday } from '@/utils/opening_hours'; const OpeningHoursList = ({ openingHours }) => { let isBriefCase; @@ -6,47 +6,36 @@ const OpeningHoursList = ({ openingHours }) => { isBriefCase = false; } else { let cnt = 0; - for(const day of Object.keys(openingHours)) { - if(openingHours[day] === '00:00-24:00') { + for (const day of Object.keys(openingHours)) { + if (openingHours[day] === '00:00-24:00') { cnt += 1; } } - isBriefCase = (cnt > 5); + isBriefCase = cnt > 5; } return (
- { - Object.keys(openingHours).map(day => { - if(isBriefCase && openingHours[day] === '00:00-24:00') { - return; - } + {Object.keys(openingHours).map((day) => { + if (isBriefCase && openingHours[day] === '00:00-24:00') { + return; + } - return ( -
-
- {KoreanWeekday[day]}: -
-
- {openingHours[day]} -
-
- ) - }, - ) - } - { - isBriefCase ? ( -
-
그외:
-
- 00:00-24:00 -
+ return ( +
+
{KoreanWeekday[day]}:
+
{openingHours[day]}
- ) : null - } + ); + })} + {isBriefCase ? ( +
+
그외:
+
00:00-24:00
+
+ ) : null}
- ) -} + ); +}; -export default OpeningHoursList +export default OpeningHoursList; diff --git a/components/reservation/reservation.datetime.picker.jsx b/components/reservation/reservation.datetime.picker.jsx index 88d01e1..8cf9731 100644 --- a/components/reservation/reservation.datetime.picker.jsx +++ b/components/reservation/reservation.datetime.picker.jsx @@ -1,8 +1,8 @@ -import moment from 'moment' -import React from 'react' -import DatePicker from 'react-datepicker' -import 'react-datepicker/dist/react-datepicker.css' -import { roundUpByDuration } from '@/utils/time-date' +import moment from 'moment'; +import React from 'react'; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; +import { roundUpByDuration } from '@/utils/time-date'; const ReservationDatetimePicker = ({ date, @@ -15,18 +15,18 @@ const ReservationDatetimePicker = ({ const now = roundUpByDuration(moment(), 30); const nowNext30Min = moment(now).add(30, 'minute'); - return ( + return ( <>
e.preventDefault()} + onKeyDown={(e) => e.preventDefault()} dateFormat={'yyyy-MM-dd'} minDate={now.toDate()} // maxDate={now.add(30, 'day').toDate()} selected={date.toDate()} onChange={(date) => { - const targetDate = moment(date).format('YYYY-MM-DD') + const targetDate = moment(date).format('YYYY-MM-DD'); const nowDate = now.format('YYYY-MM-DD'); if (targetDate === nowDate) { setDate(now); @@ -44,39 +44,48 @@ const ReservationDatetimePicker = ({
e.preventDefault()} + showTimeSelect + showTimeSelectOnly + timeIntervals={30} + onKeyDown={(e) => e.preventDefault()} dateFormat={'hh:mm aa'} selected={startTime.toDate()} minTime={date.toDate()} maxTime={moment(date.format('YYYY-MM-DD') + 'T23:59').toDate()} onChange={(startTime) => { const newStartTime = moment(startTime); - const newStartTimeNext30Min = moment(newStartTime).add(30, 'minute'); + const newStartTimeNext30Min = moment(newStartTime).add( + 30, + 'minute', + ); setStartTime(newStartTime); setEndTime(newStartTimeNext30Min); - }}/> + }} + />
e.preventDefault()} + showTimeSelect + showTimeSelectOnly + timeIntervals={30} + onKeyDown={(e) => e.preventDefault()} dateFormat={'hh:mm aa'} selected={endTime.toDate()} - minTime={ - moment(startTime).add(30, 'minute').toDate() - } + minTime={moment(startTime).add(30, 'minute').toDate()} maxTime={ - (endTime.format('HHmm') === '0000') ? - moment(date.format('YYYY-MM-DD') + 'T00:00').toDate() // edge-case + endTime.format('HHmm') === '0000' + ? moment(date.format('YYYY-MM-DD') + 'T00:00').toDate() // edge-case : moment(date.format('YYYY-MM-DD') + 'T23:59').toDate() } - onChange={(endTime) => {setEndTime(moment(endTime))}}/> + onChange={(endTime) => { + setEndTime(moment(endTime)); + }} + />
- ) -} + ); +}; -export default ReservationDatetimePicker; \ No newline at end of file +export default ReservationDatetimePicker; diff --git a/components/reservation/reservation.layout.jsx b/components/reservation/reservation.layout.jsx index f3e4f0a..b69daf2 100644 --- a/components/reservation/reservation.layout.jsx +++ b/components/reservation/reservation.layout.jsx @@ -1,14 +1,14 @@ -import LayoutWithAuth from '../layout/layout.auth.with' -import ReservationMenubar from './reservation.menubar' +import LayoutWithAuth from '../layout/layout.auth.with'; +import ReservationMenubar from './reservation.menubar'; const ReservationLayout = ({ children }) => { return (

예약 관리

- - { children } + + {children}
- ) -} + ); +}; -export default ReservationLayout \ No newline at end of file +export default ReservationLayout; diff --git a/components/reservation/reservation.menubar.jsx b/components/reservation/reservation.menubar.jsx index bdd48b4..cabd5e0 100644 --- a/components/reservation/reservation.menubar.jsx +++ b/components/reservation/reservation.menubar.jsx @@ -1,37 +1,27 @@ -import React, {Component} from 'react'; -import Link from 'next/link' -import {Menu} from "semantic-ui-react"; +import React, { Component } from 'react'; +import Link from 'next/link'; +import { Menu } from 'semantic-ui-react'; export default class ReservationMenubar extends Component { render() { return ( - - - 예약 대기 목록 - + + 예약 대기 목록 - - - 장소 목록 - + + 장소 목록 - - - 장소 예약 - + + 장소 예약 - - - 장비 목록 - + + 장비 목록 - - - 장비 예약 - + + 장비 예약 - ) + ); } -} \ No newline at end of file +} diff --git a/components/statistics/new-reservation.bar.jsx b/components/statistics/new-reservation.bar.jsx index ae7fe69..79e1130 100644 --- a/components/statistics/new-reservation.bar.jsx +++ b/components/statistics/new-reservation.bar.jsx @@ -1,26 +1,26 @@ -import { useEffect, useState } from 'react' -import { ResponsiveBar } from '@nivo/bar' +import { useEffect, useState } from 'react'; +import { ResponsiveBar } from '@nivo/bar'; import { PoPoAxios } from '@/utils/axios.instance'; const NewReservationBar = ({ year }) => { - const [barData, setBarData] = useState([]) + const [barData, setBarData] = useState([]); useEffect(() => { PoPoAxios.get( - `/statistics/reservation?start=${year}01&end=${year+1}01`). - then((res) => { - // process data format - const barData = [] - for (const [key, value] of Object.entries(res.data.data)) { - barData.push({ - 'month': key, - 'new-reservation': value, - }) - } - setBarData(barData) - }) - }, [year]) + `/statistics/reservation?start=${year}01&end=${year + 1}01`, + ).then((res) => { + // process data format + const barData = []; + for (const [key, value] of Object.entries(res.data.data)) { + barData.push({ + month: key, + 'new-reservation': value, + }); + } + setBarData(barData); + }); + }, [year]); return ( <> @@ -34,7 +34,7 @@ const NewReservationBar = ({ year }) => { margin={{ top: 10, right: 50, bottom: 30, left: 50 }} /> - ) -} + ); +}; -export default NewReservationBar \ No newline at end of file +export default NewReservationBar; diff --git a/components/statistics/new-user.bar.jsx b/components/statistics/new-user.bar.jsx index b247a96..533e69f 100644 --- a/components/statistics/new-user.bar.jsx +++ b/components/statistics/new-user.bar.jsx @@ -1,24 +1,25 @@ -import { ResponsiveBar } from '@nivo/bar' -import { useEffect, useState } from 'react' +import { ResponsiveBar } from '@nivo/bar'; +import { useEffect, useState } from 'react'; import { PoPoAxios } from '@/utils/axios.instance'; const NewUserBar = ({ year }) => { - const [barData, setBarData] = useState([]) + const [barData, setBarData] = useState([]); useEffect(() => { - PoPoAxios.get(`/statistics/user?start=${year}01&end=${year+1}01`). - then((res) => { + PoPoAxios.get(`/statistics/user?start=${year}01&end=${year + 1}01`).then( + (res) => { // process data format - const barData = [] + const barData = []; for (const [key, value] of Object.entries(res.data.data)) { barData.push({ - 'month': key, - 'new-user': value - }) + month: key, + 'new-user': value, + }); } - setBarData(barData) - }) - }, [year]) + setBarData(barData); + }, + ); + }, [year]); return ( <> @@ -31,7 +32,7 @@ const NewUserBar = ({ year }) => { margin={{ top: 10, right: 50, bottom: 30, left: 50 }} /> - ) -} + ); +}; -export default NewUserBar \ No newline at end of file +export default NewUserBar; diff --git a/components/user/rc-user.table.jsx b/components/user/rc-user.table.jsx index fc1d122..6a342ca 100644 --- a/components/user/rc-user.table.jsx +++ b/components/user/rc-user.table.jsx @@ -1,10 +1,8 @@ -import { Table } from 'semantic-ui-react' +import { Table } from 'semantic-ui-react'; const RcUserTable = ({ userStatusList }) => { return ( - +
idx. @@ -16,9 +14,12 @@ const RcUserTable = ({ userStatusList }) => { - { - userStatusList.map((userStatus, idx) => { return ( - + {userStatusList.map((userStatus, idx) => { + return ( + {idx + 1} {userStatus.name} {userStatus.email} @@ -26,11 +27,11 @@ const RcUserTable = ({ userStatusList }) => { {userStatus.created_at} {userStatus.user_type} - )}) - } + ); + })}
- ) -} + ); +}; -export default RcUserTable \ No newline at end of file +export default RcUserTable; diff --git a/components/user/user.create.modal.jsx b/components/user/user.create.modal.jsx index f5e8948..7b9bfb0 100644 --- a/components/user/user.create.modal.jsx +++ b/components/user/user.create.modal.jsx @@ -1,5 +1,5 @@ -import { Form, Modal } from 'semantic-ui-react' -import { useState } from 'react' +import { Form, Modal } from 'semantic-ui-react'; +import { useState } from 'react'; import { PoPoAxios } from '@/utils/axios.instance'; export const userTypeOptions = [ @@ -11,34 +11,39 @@ export const userTypeOptions = [ { key: 'ADMIN', text: '관리자', value: 'ADMIN' }, { key: 'STAFF', text: 'Staff', value: 'STAFF' }, { key: 'OTHERS', text: 'OTHERS', value: 'OTHERS' }, -] +]; const UserCreateModal = ({ trigger }) => { - const [open, setOpen] = useState(false) + const [open, setOpen] = useState(false); - const [email, setEmail] = useState() - const [password, setPW] = useState() - const [name, setName] = useState() - const [userType, setUserType] = useState() + const [email, setEmail] = useState(); + const [password, setPW] = useState(); + const [name, setName] = useState(); + const [userType, setUserType] = useState(); const handleSubmit = async () => { try { - await PoPoAxios.post('/user', { - 'email': email, - 'password': password, - 'name': name, - 'userType': userType, - }, {withCredentials: true}) + await PoPoAxios.post( + '/user', + { + email: email, + password: password, + name: name, + userType: userType, + }, + { withCredentials: true }, + ); window.location.reload(); } catch (err) { - alert('유저 생성에 실패했습니다.') - console.log(err) + alert('유저 생성에 실패했습니다.'); + console.log(err); } - } + }; return ( setOpen(false)} @@ -49,31 +54,37 @@ const UserCreateModal = ({ trigger }) => {
setEmail(e.target.value)}/> + label={'email'} + name="email" + onChange={(e) => setEmail(e.target.value)} + /> setPW(e.target.value)}/> + label={'password'} + name="password" + onChange={(e) => setPW(e.target.value)} + /> setName(e.target.value)}/> + label={'이름'} + name="name" + onChange={(e) => setName(e.target.value)} + /> setUserType(value)}/> + onChange={(e, { value }) => setUserType(value)} + /> - - 생성 - + 생성
- ) -} + ); +}; -export default UserCreateModal \ No newline at end of file +export default UserCreateModal; diff --git a/components/user/user.table.jsx b/components/user/user.table.jsx index c7869df..de0ba4f 100644 --- a/components/user/user.table.jsx +++ b/components/user/user.table.jsx @@ -1,23 +1,21 @@ -import { Table } from 'semantic-ui-react' -import moment from 'moment' -import UserUpdateModal from './user.update.modal' +import { Table } from 'semantic-ui-react'; +import moment from 'moment'; +import UserUpdateModal from './user.update.modal'; const userTypes = { - 'STUDENT': '학생', - 'RC_STUDENT': 'RC 학부생', - 'FACULTY': '교직원', - 'CLUB': '동아리', - 'ASSOCIATION': '학생단체', - 'ADMIN': '관리자', - 'STAFF': 'Staff', - 'OTHERS': 'OTHERS', -} + STUDENT: '학생', + RC_STUDENT: 'RC 학부생', + FACULTY: '교직원', + CLUB: '동아리', + ASSOCIATION: '학생단체', + ADMIN: '관리자', + STAFF: 'Staff', + OTHERS: 'OTHERS', +}; const UserTable = ({ users, startIdx }) => { return ( - +
idx. @@ -28,30 +26,30 @@ const UserTable = ({ users, startIdx }) => { - { - users.map((user, idx) => { - return ( - - {startIdx + idx + 1} - {user.name} - {userTypes[user.userType]} - {moment(user.createdAt). - format('YYYY-MM-DD HH:mm')} - {moment(user.lastLoginAt). - format('YYYY-MM-DD HH:mm')} - - } - /> - ) - }) - } + {users.map((user, idx) => { + return ( + + {startIdx + idx + 1} + {user.name} + {userTypes[user.userType]} + + {moment(user.createdAt).format('YYYY-MM-DD HH:mm')} + + + {moment(user.lastLoginAt).format('YYYY-MM-DD HH:mm')} + + + } + /> + ); + })}
- ) -} + ); +}; -export default UserTable \ No newline at end of file +export default UserTable; diff --git a/components/user/user.update.modal.jsx b/components/user/user.update.modal.jsx index c7fbbd3..e04cb8a 100644 --- a/components/user/user.update.modal.jsx +++ b/components/user/user.update.modal.jsx @@ -1,6 +1,6 @@ -import { Button, Form, Modal } from 'semantic-ui-react' -import { useState } from 'react' -import DeleteConfirmModal from '../common/delete.confirm.modal' +import { Button, Form, Modal } from 'semantic-ui-react'; +import { useState } from 'react'; +import DeleteConfirmModal from '../common/delete.confirm.modal'; import { PoPoAxios } from '@/utils/axios.instance'; export const userTypeOptions = [ @@ -12,41 +12,46 @@ export const userTypeOptions = [ { key: 'ADMIN', text: '관리자', value: 'ADMIN' }, { key: 'STAFF', text: 'Staff', value: 'STAFF' }, { key: 'OTHERS', text: 'OTHERS', value: 'OTHERS' }, -] +]; const userStatusOptions = [ - {key: 'ACTIVATED', text: 'ACTIVATED', value: 'ACTIVATED'}, - {key: 'DEACTIVATED', text: 'DEACTIVATED', value: 'DEACTIVATED'}, - {key: 'BANNED', text: 'BANNED', value: 'BANNED'}, -] + { key: 'ACTIVATED', text: 'ACTIVATED', value: 'ACTIVATED' }, + { key: 'DEACTIVATED', text: 'DEACTIVATED', value: 'DEACTIVATED' }, + { key: 'BANNED', text: 'BANNED', value: 'BANNED' }, +]; -const UserUpdateModal = ({user, trigger}) => { - const [open, setOpen] = useState(false) - const [deleteModalOpen, setDeleteModalOpen] = useState(false) +const UserUpdateModal = ({ user, trigger }) => { + const [open, setOpen] = useState(false); + const [deleteModalOpen, setDeleteModalOpen] = useState(false); - const [email, setEmail] = useState(user.email) - const [name, setName] = useState(user.name) - const [userType, setUserType] = useState(user.userType) - const [userStatus, setUserStatus] = useState(user.userStatus) + const [email, setEmail] = useState(user.email); + const [name, setName] = useState(user.name); + const [userType, setUserType] = useState(user.userType); + const [userStatus, setUserStatus] = useState(user.userStatus); const handleSubmit = async () => { try { - await PoPoAxios.put(`/user/${user.uuid}`, { - 'email': email, - 'name': name, - 'userType': userType, - 'userStatus': userStatus - }, {withCredentials: true}) + await PoPoAxios.put( + `/user/${user.uuid}`, + { + email: email, + name: name, + userType: userType, + userStatus: userStatus, + }, + { withCredentials: true }, + ); window.location.reload(); } catch (err) { - alert('유저 정보 수정에 실패했습니다.') - console.log(err) + alert('유저 정보 수정에 실패했습니다.'); + console.log(err); } - } + }; return ( setOpen(false)} @@ -59,53 +64,51 @@ const UserUpdateModal = ({user, trigger}) => { required label={'email'} value={email} - onChange={e => setEmail(e.target.value)}/> + onChange={(e) => setEmail(e.target.value)} + /> setName(e.target.value)}/> + onChange={(e) => setName(e.target.value)} + /> setUserType(value)}/> + onChange={(e, { value }) => setUserType(value)} + /> setUserStatus(value)}/> + onChange={(e, { value }) => setUserStatus(value)} + /> - + 수정 setDeleteModalOpen(true)} - > + trigger={ + - )} + } /> - ) -} + ); +}; -export default UserUpdateModal \ No newline at end of file +export default UserUpdateModal; diff --git a/docker-stack.yaml b/docker-stack.yaml index 0b6560d..38a5a83 100644 --- a/docker-stack.yaml +++ b/docker-stack.yaml @@ -3,7 +3,7 @@ services: dev: image: 151345152001.dkr.ecr.ap-northeast-2.amazonaws.com/popo-admin-web:latest ports: - - 5001:3001 + - 5001:3001 logging: driver: local options: @@ -13,13 +13,13 @@ services: swarmpit.service.deployment.autoredeploy: 'true' placement: constraints: - - node.role != manager - - node.labels.application == popo + - node.role != manager + - node.labels.application == popo prod: # Prod Image Tag should be updated manually image: 151345152001.dkr.ecr.ap-northeast-2.amazonaws.com/popo-admin-web:vX.X.X ports: - - 3001:3001 + - 3001:3001 logging: driver: local options: @@ -29,5 +29,5 @@ services: swarmpit.service.deployment.autoredeploy: 'true' placement: constraints: - - node.role != manager - - node.labels.application == popo + - node.role != manager + - node.labels.application == popo diff --git a/jsconfig.json b/jsconfig.json index 49852dd..20bf8ef 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -4,7 +4,7 @@ "paths": { "@/components/*": ["components/*"], "@/utils/*": ["utils/*"], - "@/assets/*": ["assets/*"] + "@/assets/*": ["assets/*"] } } -} \ No newline at end of file +} diff --git a/next.config.js b/next.config.js index 0d60710..a423267 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,6 @@ module.exports = { + env: { + node: true, + }, reactStrictMode: true, -} +}; diff --git a/package-lock.json b/package-lock.json index 3a57345..508815e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,9 +22,11 @@ "styled-components": "^6.1.8" }, "devDependencies": { - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-next": "^13.5.6", - "prettier": "^3.1.1" + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "prettier": "^3.2.5" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -36,6 +38,481 @@ "node": ">=0.10.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true, + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", + "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", + "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-react-display-name": "^7.24.1", + "@babel/plugin-transform-react-jsx": "^7.23.4", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", @@ -47,6 +524,57 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", @@ -128,9 +656,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -215,13 +743,13 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -242,11 +770,64 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@next/env": { "version": "12.3.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.4.tgz", @@ -456,6 +1037,37 @@ "node": ">= 10" } }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nivo/annotations": { "version": "0.85.1", "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.85.1.tgz", @@ -732,19 +1344,11 @@ "node": ">= 8" } }, - "node_modules/@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - }, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -1071,6 +1675,19 @@ "node": ">=8" } }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1304,6 +1921,39 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -1354,6 +2004,21 @@ } ] }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", @@ -1367,6 +2032,23 @@ "node": ">=6" } }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1384,6 +2066,13 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1605,15 +2294,6 @@ "node": ">= 0.4" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -1663,6 +2343,13 @@ "node": ">=6.0.0" } }, + "node_modules/electron-to-chromium": { + "version": "1.4.715", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", + "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==", + "dev": true, + "peer": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -1817,17 +2504,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -1898,6 +2605,18 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -2100,6 +2819,36 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.33.2", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", @@ -2375,6 +3124,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -2566,6 +3321,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -2638,6 +3403,16 @@ "node": ">=10.13.0" } }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/globalthis": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", @@ -2653,12 +3428,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -2679,12 +3448,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -2730,6 +3493,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", @@ -2982,21 +3755,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3215,18 +3973,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -3274,6 +4020,19 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3557,6 +4316,13 @@ } } }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3699,23 +4465,6 @@ "wrappy": "1" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -3872,9 +4621,9 @@ } }, "node_modules/prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", - "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -3886,6 +4635,18 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4518,6 +5279,19 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -4531,13 +5305,13 @@ } }, "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", "dev": true, "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4546,6 +5320,12 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", @@ -4566,14 +5346,13 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" + "engines": { + "node": ">=4" } }, "node_modules/to-regex-range": { @@ -4744,6 +5523,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4800,97 +5610,444 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true, + "peer": true + }, + "@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "dev": true, + "peer": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true + } + } + }, + "@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", + "dev": true, + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "peer": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + } + }, + "@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true, + "peer": true + }, + "@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" } }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" } }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "requires": { + "@babel/plugin-transform-react-jsx": "^7.22.5" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", + "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0" + } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "@babel/preset-react": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", + "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-react-display-name": "^7.24.1", + "@babel/plugin-transform-react-jsx": "^7.23.4", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.24.1" } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true }, "@babel/runtime": { "version": "7.21.0", @@ -4900,6 +6057,48 @@ "regenerator-runtime": "^0.13.11" } }, + "@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, "@emotion/is-prop-valid": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", @@ -4962,9 +6161,9 @@ } }, "@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true }, "@floating-ui/core": { @@ -5032,13 +6231,13 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" } }, @@ -5049,11 +6248,55 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "peer": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "peer": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@next/env": { "version": "12.3.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.4.tgz", @@ -5146,6 +6389,33 @@ "integrity": "sha512-DQ20JEfTBZAgF8QCjYfJhv2/279M6onxFjdG/+5B0Cyj00/EdBxiWb2eGGFgQhrBbNv/lsvzFbbi0Ptf8Vw/bg==", "optional": true }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "@nivo/annotations": { "version": "0.85.1", "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.85.1.tgz", @@ -5377,19 +6647,11 @@ "fastq": "^1.6.0" } }, - "@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - } + "@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true }, "@popperjs/core": { "version": "2.11.8", @@ -5626,6 +6888,16 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5811,6 +7083,19 @@ "fill-range": "^7.0.1" } }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "peer": true, + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, "call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -5838,6 +7123,18 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz", "integrity": "sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", @@ -5848,6 +7145,23 @@ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5862,6 +7176,13 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6043,12 +7364,6 @@ "has-property-descriptors": "^1.0.0" } }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, "define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -6083,6 +7398,13 @@ "esutils": "^2.0.2" } }, + "electron-to-chromium": { + "version": "1.4.715", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", + "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==", + "dev": true, + "peer": true + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -6216,17 +7538,31 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "peer": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true + }, "eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -6345,6 +7681,13 @@ "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" } }, + "eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "requires": {} + }, "eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -6506,6 +7849,16 @@ } } }, + "eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + } + }, "eslint-plugin-react": { "version": "7.33.2", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", @@ -6633,6 +7986,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -6776,6 +8135,13 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true + }, "get-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -6827,6 +8193,13 @@ "is-glob": "^4.0.3" } }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "peer": true + }, "globalthis": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", @@ -6836,12 +8209,6 @@ "define-properties": "^1.1.3" } }, - "globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6856,12 +8223,6 @@ "slash": "^3.0.0" } }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -6898,6 +8259,13 @@ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true + }, "has-property-descriptors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", @@ -7069,12 +8437,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7218,15 +8580,6 @@ "get-intrinsic": "^1.1.1" } }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -7271,6 +8624,13 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7474,6 +8834,13 @@ "use-sync-external-store": "1.2.0" } }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7577,17 +8944,6 @@ "wrappy": "1" } }, - "open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -7692,11 +9048,20 @@ "dev": true }, "prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", - "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -8132,6 +9497,16 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + }, "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -8139,13 +9514,21 @@ "dev": true }, "synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", "dev": true, "requires": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } } }, "tabbable": { @@ -8165,15 +9548,11 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "requires": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true }, "to-regex-range": { "version": "5.0.1", @@ -8299,6 +9678,17 @@ "which-boxed-primitive": "^1.0.2" } }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "peer": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index 5926a0a..4958990 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start -p 3001", + "format": "prettier --w .", "lint": "next lint" }, "dependencies": { @@ -23,8 +24,10 @@ "styled-components": "^6.1.8" }, "devDependencies": { - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-next": "^13.5.6", - "prettier": "^3.1.1" + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "prettier": "^3.2.5" } } diff --git a/pages/404.jsx b/pages/404.jsx index f76cdca..37df970 100644 --- a/pages/404.jsx +++ b/pages/404.jsx @@ -1,23 +1,17 @@ -import Link from 'next/link' -import { Button, Image } from 'semantic-ui-react' -import LayoutWithoutAuth from '@/components/layout/layout.auth.without' +import Link from 'next/link'; +import { Button, Image } from 'semantic-ui-react'; +import LayoutWithoutAuth from '@/components/layout/layout.auth.without'; const ErrorPage = () => { return ( - {'popo_logo'}/ -

- 잘못된 주소이거나 현재 개발중인 페이지 입니다 🙏 -

+ {'popo_logo'} +

잘못된 주소이거나 현재 개발중인 페이지 입니다 🙏

- +
- ) -} + ); +}; -export default ErrorPage \ No newline at end of file +export default ErrorPage; diff --git a/pages/_app.jsx b/pages/_app.jsx index e2d6772..f2ff30d 100644 --- a/pages/_app.jsx +++ b/pages/_app.jsx @@ -1,20 +1,15 @@ -import '../styles/globals.css' -import 'semantic-ui-css/semantic.min.css' -import Error from "next/error"; +import '../styles/globals.css'; +import 'semantic-ui-css/semantic.min.css'; +import Error from 'next/error'; function MyApp({ Component, pageProps }) { const error = pageProps.error; if (pageProps.error) { - return ( - - ) + return ; } - return + return ; } -export default MyApp +export default MyApp; diff --git a/pages/_document.jsx b/pages/_document.jsx index 4b98c46..89e4aa3 100644 --- a/pages/_document.jsx +++ b/pages/_document.jsx @@ -1,18 +1,19 @@ -import Document from 'next/document' -import { ServerStyleSheet } from 'styled-components' +import Document from 'next/document'; +import { ServerStyleSheet } from 'styled-components'; class MyDocument extends Document { - static async getInitialProps (ctx) { - const sheet = new ServerStyleSheet() - const originalRenderPage = ctx.renderPage + static async getInitialProps(ctx) { + const sheet = new ServerStyleSheet(); + const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ - enhanceApp: App => props => sheet.collectStyles(), - }) + enhanceApp: (App) => (props) => + sheet.collectStyles(), + }); - const initialProps = await Document.getInitialProps(ctx) + const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( @@ -21,11 +22,11 @@ class MyDocument extends Document { {sheet.getStyleElement()} ), - } + }; } finally { - sheet.seal() + sheet.seal(); } } } -export default MyDocument \ No newline at end of file +export default MyDocument; diff --git a/pages/board/benefit/affiliate/create.jsx b/pages/board/benefit/affiliate/create.jsx index 74eac50..e1589de 100644 --- a/pages/board/benefit/affiliate/create.jsx +++ b/pages/board/benefit/affiliate/create.jsx @@ -1,35 +1,34 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Form } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form } from 'semantic-ui-react'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; const AffiliateCreatePage = () => { const router = useRouter(); - const [title, setTitle] = useState('') - const [content_short, setContentShort] = useState('') - const [content, setContent] = useState('') + const [title, setTitle] = useState(''); + const [content_short, setContentShort] = useState(''); + const [content, setContent] = useState(''); const handleSubmit = async () => { const body = { - 'title': title, - 'content_short': content_short, - 'content': content, - } - - PoPoAxios.post('/benefit/affiliate', - body, - { withCredentials: true }, - ).then(() => { - alert('제휴 업체가 등록 되었습니다!') - router.push('/board/benefit'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`제휴 업체 등록에 실패했습니다.\n${errMsg}`); - }) - } + title: title, + content_short: content_short, + content: content, + }; + + PoPoAxios.post('/benefit/affiliate', body, { withCredentials: true }) + .then(() => { + alert('제휴 업체가 등록 되었습니다!'); + router.push('/board/benefit'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`제휴 업체 등록에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -39,28 +38,26 @@ const AffiliateCreatePage = () => { setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setContentShort(e.target.value)} + onChange={(e) => setContentShort(e.target.value)} /> setContent(e.target.value)} + style={{ height: 300 }} + onChange={(e) => setContent(e.target.value)} /> - - 생성 - + 생성 - ) -} + ); +}; export default AffiliateCreatePage; diff --git a/pages/board/benefit/affiliate/update/[id].jsx b/pages/board/benefit/affiliate/update/[id].jsx index 077666f..fe2dd37 100644 --- a/pages/board/benefit/affiliate/update/[id].jsx +++ b/pages/board/benefit/affiliate/update/[id].jsx @@ -1,39 +1,40 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Button, Form, Icon } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; const AffiliateUpdatePage = ({ affiliateInfo }) => { const router = useRouter(); - const [deleteModalOpen, setDeleteModalOpen] = useState(false) + const [deleteModalOpen, setDeleteModalOpen] = useState(false); const id = affiliateInfo.id; - const [title, setTitle] = useState(affiliateInfo.title) - const [content_short, setContentShort] = useState(affiliateInfo.content_short) - const [content, setContent] = useState(affiliateInfo.content) + const [title, setTitle] = useState(affiliateInfo.title); + const [content_short, setContentShort] = useState( + affiliateInfo.content_short, + ); + const [content, setContent] = useState(affiliateInfo.content); const handleSubmit = async () => { const body = { - 'title': title, - 'content_short': content_short, - 'content': content, - } + title: title, + content_short: content_short, + content: content, + }; - PoPoAxios.put(`/benefit/affiliate/${id}`, - body, - { withCredentials: true }, - ).then(() => { - alert('제휴 업체 정보가 수정 되었습니다!') - router.push('/board/benefit'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`제휴 업체 정보 수정에 실패했습니다.\n${errMsg}`); - }) - } + PoPoAxios.put(`/benefit/affiliate/${id}`, body, { withCredentials: true }) + .then(() => { + alert('제휴 업체 정보가 수정 되었습니다!'); + router.push('/board/benefit'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`제휴 업체 정보 수정에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -44,28 +45,26 @@ const AffiliateUpdatePage = ({ affiliateInfo }) => { required label={'업체 이름'} value={title} - onChange={e => setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setContentShort(e.target.value)} + onChange={(e) => setContentShort(e.target.value)} /> setContent(e.target.value)} + style={{ height: 300 }} + onChange={(e) => setContent(e.target.value)} /> - + 수정 { target={title} deleteURI={`benefit/affiliate/${id}`} afterDeleteURI={'/board/benefit'} - trigger={( - )} + trigger={ + + } /> - ) -} + ); +}; export default AffiliateUpdatePage; @@ -92,5 +91,5 @@ export async function getServerSideProps(ctx) { const res = await PoPoAxios.get(`benefit/affiliate/${id}`); const affiliateInfo = res.data; - return { props: { affiliateInfo } } + return { props: { affiliateInfo } }; } diff --git a/pages/board/benefit/discount/create.jsx b/pages/board/benefit/discount/create.jsx index fc8ce05..8f643ce 100644 --- a/pages/board/benefit/discount/create.jsx +++ b/pages/board/benefit/discount/create.jsx @@ -1,39 +1,38 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Form } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form } from 'semantic-ui-react'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; const DiscountCreatePage = () => { const router = useRouter(); - const [title, setTitle] = useState('') - const [region, setRegion] = useState('') - const [open_hour, setOpenHour] = useState('') - const [phone, setPhone] = useState('') - const [content, setContent] = useState('') + const [title, setTitle] = useState(''); + const [region, setRegion] = useState(''); + const [open_hour, setOpenHour] = useState(''); + const [phone, setPhone] = useState(''); + const [content, setContent] = useState(''); const handleSubmit = async () => { const body = { - 'title': title, - 'region': region, - 'open_hour': open_hour, - 'phone': phone, - 'content': content, - } + title: title, + region: region, + open_hour: open_hour, + phone: phone, + content: content, + }; - PoPoAxios.post('/benefit/discount', - body, - { withCredentials: true }, - ).then(() => { - alert('할인 업체가 등록 되었습니다!') - router.push('/board/benefit'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`할인 업체 등록에 실패했습니다.\n${errMsg}`); - }) - } + PoPoAxios.post('/benefit/discount', body, { withCredentials: true }) + .then(() => { + alert('할인 업체가 등록 되었습니다!'); + router.push('/board/benefit'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`할인 업체 등록에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -43,40 +42,38 @@ const DiscountCreatePage = () => { setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setRegion(e.target.value)} + onChange={(e) => setRegion(e.target.value)} /> setOpenHour(e.target.value)} + onChange={(e) => setOpenHour(e.target.value)} /> setPhone(e.target.value)} + onChange={(e) => setPhone(e.target.value)} /> setContent(e.target.value)} + style={{ height: 300 }} + onChange={(e) => setContent(e.target.value)} /> - - 생성 - + 생성 - ) -} + ); +}; export default DiscountCreatePage; diff --git a/pages/board/benefit/discount/update/[id].jsx b/pages/board/benefit/discount/update/[id].jsx index c572d65..af23ff6 100644 --- a/pages/board/benefit/discount/update/[id].jsx +++ b/pages/board/benefit/discount/update/[id].jsx @@ -1,43 +1,42 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Button, Form, Icon } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; const DiscountUpdatePage = ({ discountInfo }) => { const router = useRouter(); - const [deleteModalOpen, setDeleteModalOpen] = useState(false) + const [deleteModalOpen, setDeleteModalOpen] = useState(false); const id = discountInfo.id; - const [title, setTitle] = useState(discountInfo.title) - const [region, setRegion] = useState(discountInfo.region) - const [open_hour, setOpenHour] = useState(discountInfo.open_hour) - const [phone, setPhone] = useState(discountInfo.phone) - const [content, setContent] = useState(discountInfo.content) + const [title, setTitle] = useState(discountInfo.title); + const [region, setRegion] = useState(discountInfo.region); + const [open_hour, setOpenHour] = useState(discountInfo.open_hour); + const [phone, setPhone] = useState(discountInfo.phone); + const [content, setContent] = useState(discountInfo.content); const handleSubmit = async () => { const body = { - 'title': title, - 'region': region, - 'open_hour': open_hour, - 'phone': phone, - 'content': content, - } - - PoPoAxios.put(`/benefit/discount/${id}`, - body, - { withCredentials: true }, - ).then(() => { - alert('할인 업체 정보가 수정 되었습니다!') - router.push('/board/benefit'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`할인 업체 정보 수정에 실패했습니다.\n${errMsg}`); - }) - } + title: title, + region: region, + open_hour: open_hour, + phone: phone, + content: content, + }; + + PoPoAxios.put(`/benefit/discount/${id}`, body, { withCredentials: true }) + .then(() => { + alert('할인 업체 정보가 수정 되었습니다!'); + router.push('/board/benefit'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`할인 업체 정보 수정에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -48,42 +47,40 @@ const DiscountUpdatePage = ({ discountInfo }) => { required label={'업체 이름'} value={title} - onChange={e => setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> setRegion(e.target.value)} + onChange={(e) => setRegion(e.target.value)} /> setOpenHour(e.target.value)} + onChange={(e) => setOpenHour(e.target.value)} /> setPhone(e.target.value)} + onChange={(e) => setPhone(e.target.value)} /> setContent(e.target.value)} + style={{ height: 300 }} + onChange={(e) => setContent(e.target.value)} /> - + 수정 { target={title} deleteURI={`benefit/discount/${id}`} afterDeleteURI={'/board/benefit'} - trigger={( - )} + trigger={ + + } /> - ) -} + ); +}; export default DiscountUpdatePage; @@ -110,5 +107,5 @@ export async function getServerSideProps(ctx) { const res = await PoPoAxios.get(`benefit/discount/${id}`); const discountInfo = res.data; - return { props: { discountInfo } } + return { props: { discountInfo } }; } diff --git a/pages/board/benefit/index.jsx b/pages/board/benefit/index.jsx index 5b6cb11..e13f20e 100644 --- a/pages/board/benefit/index.jsx +++ b/pages/board/benefit/index.jsx @@ -1,9 +1,9 @@ -import React from 'react' -import Link from 'next/link' -import { Button, Message } from 'semantic-ui-react' +import React from 'react'; +import Link from 'next/link'; +import { Button, Message } from 'semantic-ui-react'; -import { PoPoAxios } from "@/utils/axios.instance"; -import BoardLayout from '@/components/board/board.layout' +import { PoPoAxios } from '@/utils/axios.instance'; +import BoardLayout from '@/components/board/board.layout'; import AffiliateTable from '@/components/board/benefit/affiliate/affiliate.table'; import DiscountTable from '@/components/board/benefit/discount/discount.table'; @@ -23,10 +23,9 @@ const BenefitPage = ({ affiliateList, discountList }) => {
- +
-

총학 할인 업체

@@ -34,11 +33,11 @@ const BenefitPage = ({ affiliateList, discountList }) => {
- +
- ) -} + ); +}; export default BenefitPage; @@ -46,7 +45,6 @@ export async function getServerSideProps() { const res1 = await PoPoAxios.get('benefit/affiliate'); const affiliateList = res1.data; - const res2 = await PoPoAxios.get('benefit/discount'); const discountList = res2.data; diff --git a/pages/board/index.jsx b/pages/board/index.jsx index cf0b124..827a4c9 100644 --- a/pages/board/index.jsx +++ b/pages/board/index.jsx @@ -1,13 +1,11 @@ -import BoardLayout from '@/components/board/board.layout' +import BoardLayout from '@/components/board/board.layout'; const BoardIndexPage = () => { return ( -

- 총학생회/동아리 게시판 기능을 개발하고 있습니다 👨‍💻 -

+

총학생회/동아리 게시판 기능을 개발하고 있습니다 👨‍💻

- ) -} + ); +}; -export default BoardIndexPage \ No newline at end of file +export default BoardIndexPage; diff --git a/pages/board/notice/create.jsx b/pages/board/notice/create.jsx index 20ddb6c..5d6d59b 100644 --- a/pages/board/notice/create.jsx +++ b/pages/board/notice/create.jsx @@ -1,54 +1,53 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import moment from 'moment' -import { Form, Message } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import moment from 'moment'; +import { Form, Message } from 'semantic-ui-react'; import ReactDatePicker from 'react-datepicker'; -import 'react-datepicker/dist/react-datepicker.css' +import 'react-datepicker/dist/react-datepicker.css'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; const NoticeCreatePage = () => { const router = useRouter(); - const [title, setTitle] = useState('') - const [content, setContent] = useState() - const [link, setLink] = useState() - const [start_datetime, setStartDatetime] = useState() - const [end_datetime, setEndDatetime] = useState() + const [title, setTitle] = useState(''); + const [content, setContent] = useState(); + const [link, setLink] = useState(); + const [start_datetime, setStartDatetime] = useState(); + const [end_datetime, setEndDatetime] = useState(); const duration = moment(end_datetime).diff(moment(start_datetime), 'hours'); - + const handleSubmit = async () => { const body = { - 'title': title, - 'content': content, - 'link': link, - 'start_datetime': start_datetime, - 'end_datetime': end_datetime, - } - + title: title, + content: content, + link: link, + start_datetime: start_datetime, + end_datetime: end_datetime, + }; + if (!start_datetime || !end_datetime) { - alert('시작 일자와 종료 일자를 입력해주세요.') + alert('시작 일자와 종료 일자를 입력해주세요.'); return; } - + if (start_datetime > end_datetime) { - alert('시작 일자가 종료 일자보다 늦을 수 없습니다.') + alert('시작 일자가 종료 일자보다 늦을 수 없습니다.'); return; } - PoPoAxios.post('/notice', - body, - { withCredentials: true }, - ).then(() => { - alert('공지사항이 등록 되었습니다!') - router.push('/board/notice'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`공지사항 등록에 실패했습니다.\n${errMsg}`); - }) - } + PoPoAxios.post('/notice', body, { withCredentials: true }) + .then(() => { + alert('공지사항이 등록 되었습니다!'); + router.push('/board/notice'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`공지사항 등록에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -58,9 +57,9 @@ const NoticeCreatePage = () => { setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> - + 공지사항 이미지 업로드는 공지사항 생성 후, 등록 할 수 있습니다. @@ -68,24 +67,24 @@ const NoticeCreatePage = () => { setContent(e.target.value)} + onChange={(e) => setContent(e.target.value)} /> - + setLink(e.target.value)} + onChange={(e) => setLink(e.target.value)} /> -

- 링크가 존재하는 공지사항일 경우 링크를 입력해주세요. -

- -
+

링크가 존재하는 공지사항일 경우 링크를 입력해주세요.

+ +
setStartDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss'))} - onKeyDown={e => e.preventDefault()} + onChange={(date) => + setStartDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss')) + } + onKeyDown={(e) => e.preventDefault()} dateFormat="yyyy-MM-dd HH:mm" timeIntervals={60} minDate={new Date()} @@ -94,10 +93,12 @@ const NoticeCreatePage = () => {
- setEndDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss'))} - onKeyDown={e => e.preventDefault()} + + setEndDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss')) + } + onKeyDown={(e) => e.preventDefault()} dateFormat="yyyy-MM-dd HH:mm" timeIntervals={60} minDate={moment(start_datetime).toDate()} @@ -106,25 +107,17 @@ const NoticeCreatePage = () => {
- { - (!start_datetime || !end_datetime) ? ( - "게시 시작 날짜와 종료 날짜를 입력해주세요." - ) : ( - start_datetime > end_datetime ? ( - "시작 날짜가 종료 날짜보다 늦을 수 없습니다." - ) : ( - `게시 기간: ${start_datetime} ~ ${end_datetime} (${Number(duration/24).toFixed(0)}일 ${duration%24}시간)` - ) - ) - } + {!start_datetime || !end_datetime + ? '게시 시작 날짜와 종료 날짜를 입력해주세요.' + : start_datetime > end_datetime + ? '시작 날짜가 종료 날짜보다 늦을 수 없습니다.' + : `게시 기간: ${start_datetime} ~ ${end_datetime} (${Number(duration / 24).toFixed(0)}일 ${duration % 24}시간)`} - - 생성 - + 생성 - ) -} + ); +}; export default NoticeCreatePage; diff --git a/pages/board/notice/index.jsx b/pages/board/notice/index.jsx index a5acf56..5523c25 100644 --- a/pages/board/notice/index.jsx +++ b/pages/board/notice/index.jsx @@ -1,9 +1,9 @@ -import Link from 'next/link' -import { Button, Message } from 'semantic-ui-react' +import Link from 'next/link'; +import { Button, Message } from 'semantic-ui-react'; -import BoardLayout from '@/components/board/board.layout' +import BoardLayout from '@/components/board/board.layout'; import { PoPoAxios } from '@/utils/axios.instance'; -import NoticeTable from '@/components/board/notice/notice.table' +import NoticeTable from '@/components/board/notice/notice.table'; const AnnouncementPage = ({ noticeList }) => { return ( @@ -14,23 +14,17 @@ const AnnouncementPage = ({ noticeList }) => {
- - - 공지사항은 빠른 게시 시작 일자로 정렬되어 표시됩니다! - - - - 기능 개발이 계속 이뤄지고 있습니다. - - + + 공지사항은 빠른 게시 시작 일자로 정렬되어 표시됩니다! + + 기능 개발이 계속 이뤄지고 있습니다. +
- +
- ) -} + ); +}; export default AnnouncementPage; diff --git a/pages/board/notice/update/[id].jsx b/pages/board/notice/update/[id].jsx index a274397..42cb509 100644 --- a/pages/board/notice/update/[id].jsx +++ b/pages/board/notice/update/[id].jsx @@ -1,54 +1,55 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import moment from 'moment' -import { Button, Form, Icon, Message } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import moment from 'moment'; +import { Button, Form, Icon, Message } from 'semantic-ui-react'; import ReactDatePicker from 'react-datepicker'; -import 'react-datepicker/dist/react-datepicker.css' +import 'react-datepicker/dist/react-datepicker.css'; -import { PoPoAxios } from "@/utils/axios.instance"; +import { PoPoAxios } from '@/utils/axios.instance'; import BoardLayout from '@/components/board/board.layout'; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; // import ImageUploadForm from '@/components/common/image-upload.form'; const NoticeUpdatePage = ({ noticeInfo }) => { const router = useRouter(); - const [deleteModalOpen, setDeleteModalOpen] = useState(false) - + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + const id = noticeInfo.id; - const [title, setTitle] = useState(noticeInfo.title) - const [content, setContent] = useState(noticeInfo.content) - const [link, setLink] = useState(noticeInfo.link) - const [start_datetime, setStartDatetime] = useState(noticeInfo.start_datetime) - const [end_datetime, setEndDatetime] = useState(noticeInfo.end_datetime) + const [title, setTitle] = useState(noticeInfo.title); + const [content, setContent] = useState(noticeInfo.content); + const [link, setLink] = useState(noticeInfo.link); + const [start_datetime, setStartDatetime] = useState( + noticeInfo.start_datetime, + ); + const [end_datetime, setEndDatetime] = useState(noticeInfo.end_datetime); const duration = moment(end_datetime).diff(moment(start_datetime), 'hours'); - + const handleSubmit = async () => { const body = { - 'title': title, - 'content': content, - 'link': link, - 'start_datetime': start_datetime, - 'end_datetime': end_datetime, - } - + title: title, + content: content, + link: link, + start_datetime: start_datetime, + end_datetime: end_datetime, + }; + if (start_datetime > end_datetime) { - alert('시작 일자가 종료 일자보다 늦을 수 없습니다.') + alert('시작 일자가 종료 일자보다 늦을 수 없습니다.'); return; } - PoPoAxios.put(`/notice/${id}`, - body, - { withCredentials: true }, - ).then(() => { - alert('공지사항이 업데이트 되었습니다!') - router.push('/board/notice'); - }).catch(err => { - const errMsg = err.response.data.message; - alert(`공지사항 업데이트에 실패했습니다.\n${errMsg}`); - }) - } + PoPoAxios.put(`/notice/${id}`, body, { withCredentials: true }) + .then(() => { + alert('공지사항이 업데이트 되었습니다!'); + router.push('/board/notice'); + }) + .catch((err) => { + const errMsg = err.response.data.message; + alert(`공지사항 업데이트에 실패했습니다.\n${errMsg}`); + }); + }; return ( @@ -59,9 +60,9 @@ const NoticeUpdatePage = ({ noticeInfo }) => { required label={'제목'} value={title} - onChange={e => setTitle(e.target.value)} + onChange={(e) => setTitle(e.target.value)} /> - + 공지사항 이미지 업로드는 공지사항 생성 후, 수정 페이지에서 가능합니다. @@ -70,17 +71,15 @@ const NoticeUpdatePage = ({ noticeInfo }) => { required label={'내용'} value={content} - onChange={e => setContent(e.target.value)} + onChange={(e) => setContent(e.target.value)} /> - + setLink(e.target.value)} + onChange={(e) => setLink(e.target.value)} /> -

- 링크가 존재하는 공지사항일 경우 링크를 입력해주세요. -

+

링크가 존재하는 공지사항일 경우 링크를 입력해주세요.

{/* { 권장 이미지 사이즈(가로 x 세로): 540 x 200 */} - -
+ +
setStartDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss'))} - onKeyDown={e => e.preventDefault()} + onChange={(date) => + setStartDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss')) + } + onKeyDown={(e) => e.preventDefault()} dateFormat="yyyy-MM-dd HH:mm" timeIntervals={60} minDate={new Date()} @@ -106,10 +107,12 @@ const NoticeUpdatePage = ({ noticeInfo }) => {
- setEndDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss'))} - onKeyDown={e => e.preventDefault()} + + setEndDatetime(moment(date).format('YYYY-MM-DD HH:mm:ss')) + } + onKeyDown={(e) => e.preventDefault()} dateFormat="yyyy-MM-dd HH:mm" timeIntervals={60} minDate={moment(start_datetime).toDate()} @@ -118,20 +121,13 @@ const NoticeUpdatePage = ({ noticeInfo }) => {
- { - (!start_datetime || !end_datetime) ? ( - "게시 시작 날짜와 종료 날짜를 입력해주세요." - ) : ( - start_datetime > end_datetime ? ( - "시작 날짜가 종료 날짜보다 늦을 수 없습니다." - ) : ( - `게시 기간: ${start_datetime} ~ ${end_datetime} (${Number(duration/24).toFixed(0)}일 ${duration%24}시간)` - ) - ) - } + {!start_datetime || !end_datetime + ? '게시 시작 날짜와 종료 날짜를 입력해주세요.' + : start_datetime > end_datetime + ? '시작 날짜가 종료 날짜보다 늦을 수 없습니다.' + : `게시 기간: ${start_datetime} ~ ${end_datetime} (${Number(duration / 24).toFixed(0)}일 ${duration % 24}시간)`} - 수정 @@ -141,18 +137,17 @@ const NoticeUpdatePage = ({ noticeInfo }) => { target={title} deleteURI={`notice/${id}`} afterDeleteURI={'/board/notice'} - trigger={( - )} + trigger={ + + } /> - - ) -} + ); +}; export default NoticeUpdatePage; @@ -161,5 +156,5 @@ export async function getServerSideProps(ctx) { const res = await PoPoAxios.get(`notice/${id}`); const noticeInfo = res.data; - return { props: { noticeInfo } } + return { props: { noticeInfo } }; } diff --git a/pages/board/rc-students-list.jsx b/pages/board/rc-students-list.jsx index b8d41c6..1bc94b9 100644 --- a/pages/board/rc-students-list.jsx +++ b/pages/board/rc-students-list.jsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { Button } from 'semantic-ui-react'; import { PoPoAxios } from '@/utils/axios.instance'; -import BoardLayout from '@/components/board/board.layout' +import BoardLayout from '@/components/board/board.layout'; import CsvUploadForm from '@/components/common/csv-upload.form'; import RcUserTable from '@/components/user/rc-user.table'; @@ -17,80 +17,85 @@ const RcStudentsListPage = ({ popoRcStdntCnt, totalRcStdntCnt }) => { setIsLoaded(true); }) .catch((err) => { - alert(`RC 사생 명단을 불러오는데 실패했습니다.\n${err.response.data.message}`) - }) - }, [popoRcStdntCnt, totalRcStdntCnt]) + alert( + `RC 사생 명단을 불러오는데 실패했습니다.\n${err.response.data.message}`, + ); + }); + }, [popoRcStdntCnt, totalRcStdntCnt]); return (

RC 사생 명단 업로드

-

- RC 사생에게만 RC 장소 예약을 받기 위해 RC 사생 명단 정보가 필요합니다.
- 아래 주소에서 CSV 파일을 다운 받아 요 형식에 맞춰 입력 후, 다시 CSV 파일을 업로드 해주세요. - (name, email 컬럼은 필수 입니다.)
- CSV 파일이 업로드 되면, RC 사생 명단 초기화(reset) 후 업로드 된 명단에 있는 Povis ID를 가진 모든 유저를 RC 사생으로 분류합니다.
- 만약 RC 사생 명단을 업로드 한 후에, RC 사생이 가입한다면 그때는 자동으로 RC 사생으로 분류됩니다. +

+ RC 사생에게만 RC 장소 예약을 받기 위해 RC 사생 명단 정보가 필요합니다. +
+ 아래 주소에서 CSV 파일을 다운 받아 요 형식에 맞춰 입력 후, 다시 CSV + 파일을 업로드 해주세요. + (name, email 컬럼은 필수 입니다.) +
+ CSV 파일이 업로드 되면, RC 사생 명단 초기화(reset) 후 업로드 된 명단에 + 있는 Povis ID를 가진 모든 유저를 RC 사생으로 분류합니다. +
+ 만약 RC 사생 명단을 업로드 한 후에, RC 사생이 가입한다면 그때는{' '} + 자동으로 RC 사생으로 분류됩니다.

  • - POPO 가입 RC 사생 수: {popoRcStdntCnt}명 ({Number((popoRcStdntCnt / totalRcStdntCnt * 100).toFixed(1))}%) -
  • -
  • - 전체 RC 사생 수: {totalRcStdntCnt}명 + POPO 가입 RC 사생 수: {popoRcStdntCnt}명 ( + {Number(((popoRcStdntCnt / totalRcStdntCnt) * 100).toFixed(1))}%)
  • +
  • 전체 RC 사생 수: {totalRcStdntCnt}명
-
+
-
+
-
- { - isLoaded ? ( - <> -

RC 사생 명단

- - - ) : ( -

RC 사생 명단 불러오는 중...

- ) - } +
+ {isLoaded ? ( + <> +

RC 사생 명단

+ + + ) : ( +

RC 사생 명단 불러오는 중...

+ )}
- ) -} + ); +}; export default RcStudentsListPage; @@ -101,5 +106,5 @@ export async function getServerSideProps() { const res2 = await PoPoAxios.get('/setting/count-rc-students-list'); const totalRcStdntCnt = res2.data; - return { props: { popoRcStdntCnt, totalRcStdntCnt } } + return { props: { popoRcStdntCnt, totalRcStdntCnt } }; } diff --git a/pages/board/setting.jsx b/pages/board/setting.jsx index b50f5a1..849dc2b 100644 --- a/pages/board/setting.jsx +++ b/pages/board/setting.jsx @@ -1,82 +1,91 @@ -import { useState } from 'react' -import { Form } from 'semantic-ui-react' +import { useState } from 'react'; +import { Form } from 'semantic-ui-react'; -import BoardLayout from '@/components/board/board.layout' +import BoardLayout from '@/components/board/board.layout'; import { PoPoAxios } from '@/utils/axios.instance'; const SettingPage = ({ settingKeyValue }) => { - const [popoCRMEmail, setPOPOCRMEmail] = useState(settingKeyValue.popo_crm_email); + const [popoCRMEmail, setPOPOCRMEmail] = useState( + settingKeyValue.popo_crm_email, + ); const [STUEmail, setSTUEmail] = useState(settingKeyValue.stu_email); - const [dongyeonBank, setDongyeonBank] = useState(settingKeyValue.dongyeon_bank); - const [dongyeonServiceTime, setDongyeonServiceTime] = useState(settingKeyValue.dongyeon_service_time); - const [dongyeonContact, setDongyeonContact] = useState(settingKeyValue.dongyeon_contact); + const [dongyeonBank, setDongyeonBank] = useState( + settingKeyValue.dongyeon_bank, + ); + const [dongyeonServiceTime, setDongyeonServiceTime] = useState( + settingKeyValue.dongyeon_service_time, + ); + const [dongyeonContact, setDongyeonContact] = useState( + settingKeyValue.dongyeon_contact, + ); - function handleSubmit () { - PoPoAxios.post('/setting', { - popo_crm_email: popoCRMEmail, - stu_email: STUEmail, - dongyeon_bank: dongyeonBank, - dongyeon_service_time: dongyeonServiceTime, - dongyeon_contact: dongyeonContact, - }, {withCredentials: true}) + function handleSubmit() { + PoPoAxios.post( + '/setting', + { + popo_crm_email: popoCRMEmail, + stu_email: STUEmail, + dongyeon_bank: dongyeonBank, + dongyeon_service_time: dongyeonServiceTime, + dongyeon_contact: dongyeonContact, + }, + { withCredentials: true }, + ) .then(() => alert('설정값을 저장했습니다!')) .catch((err) => { const errMsg = err.response.data.message; alert(`설정값을 저장하는데 실패했습니다.\n${errMsg}`); - }) + }); } return (

POPO 설정값

- 이곳에서 동적으로 변경할 수 있는 POPO 설정값을 채울 수 있습니다. 추가를 원하는게 설정값이 있으면 POPO 개발팀으로 문의 부탁드립니다. + 이곳에서 동적으로 변경할 수 있는 POPO 설정값을 채울 수 있습니다. 추가를 + 원하는게 설정값이 있으면 POPO 개발팀으로 문의 부탁드립니다.

setPOPOCRMEmail(e.target.value)} + onChange={(e) => setPOPOCRMEmail(e.target.value)} /> setSTUEmail(e.target.value)} + onChange={(e) => setSTUEmail(e.target.value)} /> setDongyeonBank(e.target.value)} + onChange={(e) => setDongyeonBank(e.target.value)} /> setDongyeonServiceTime(e.target.value)} + onChange={(e) => setDongyeonServiceTime(e.target.value)} /> setDongyeonContact(e.target.value)} + onChange={(e) => setDongyeonContact(e.target.value)} /> - + 저장 -
- ) -} + ); +}; -export default SettingPage +export default SettingPage; export async function getServerSideProps() { - const res = await PoPoAxios.get('/setting'); - const settingKeyValue = res.data; + const res = await PoPoAxios.get('/setting'); + const settingKeyValue = res.data; - return { props: { settingKeyValue } } + return { props: { settingKeyValue } }; } diff --git a/pages/board/whitebook.jsx b/pages/board/whitebook.jsx index 122ded4..454732a 100644 --- a/pages/board/whitebook.jsx +++ b/pages/board/whitebook.jsx @@ -1,42 +1,38 @@ -import { useState, useEffect } from 'react' -import { Button } from 'semantic-ui-react' +import { useState, useEffect } from 'react'; +import { Button } from 'semantic-ui-react'; -import BoardLayout from '@/components/board/board.layout' -import WhitebookCreateModal from '@/components/board/whitebook/whitebook.create.modal' -import WhitebookTable from '@/components/board/whitebook/whitebook.table' +import BoardLayout from '@/components/board/board.layout'; +import WhitebookCreateModal from '@/components/board/whitebook/whitebook.create.modal'; +import WhitebookTable from '@/components/board/whitebook/whitebook.table'; import { PoPoAxios } from '@/utils/axios.instance'; const WhitebookPage = () => { - const [whitebooks, setWhitebooks] = useState([]) + const [whitebooks, setWhitebooks] = useState([]); useEffect(() => { - PoPoAxios.get( - '/whitebook/with-login?orderBy=click_count', - { withCredentials: true }). - then((res) => setWhitebooks(res.data)). - catch((err) => { - alert('생활백서 목록을 불러오는데 실패했습니다.') - console.log(err) - }) - }, []) + PoPoAxios.get('/whitebook/with-login?orderBy=click_count', { + withCredentials: true, + }) + .then((res) => setWhitebooks(res.data)) + .catch((err) => { + alert('생활백서 목록을 불러오는데 실패했습니다.'); + console.log(err); + }); + }, []); return (

생활백서

- 생활백서 생성} - /> + 생활백서 생성} />

생활백서는 조회순으로 정렬되어 표시됩니다!

- +
- ) -} + ); +}; export default WhitebookPage; diff --git a/pages/equipment/create.jsx b/pages/equipment/create.jsx index ae9dd1b..74cb73c 100644 --- a/pages/equipment/create.jsx +++ b/pages/equipment/create.jsx @@ -1,113 +1,111 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Form, Message } from "semantic-ui-react"; - -import ReservationLayout from '@/components/reservation/reservation.layout' -import { PoPoAxios } from "@/utils/axios.instance"; -import { OwnerOptions } from "@/assets/owner.options"; - -const EquipmentCreatePage = () => { - const router = useRouter(); - - const [name, setName] = useState('') - const [equip_owner, setEquipOwner] = useState('') - const [fee, setFee] = useState('') - const [description, setDescription] = useState('') - const [staff_email, setStaffEmail] = useState('') - const [max_minutes, setMaxMinutes] = useState() - - const handleSubmit = async () => { - const body = { - 'name': name, - 'equip_owner': equip_owner, - 'fee': fee, - 'description': description, - 'staff_email': staff_email, - }; - - if (max_minutes) { - body['max_minutes'] = max_minutes; - } - - PoPoAxios.post('/equip', - body, - { withCredentials: true }, - ).then(() => { - alert('장비가 생성 되었습니다!') - router.push('/equipment'); - }).catch((err) => { - alert('장비 생성에 실패했습니다.'); - console.log(err); - }); - } - - return ( - -

장비 생성

-
- - setName(e.target.value)} - /> - setEquipOwner(value)} - /> - - - setFee(e.target.value)} - /> - - setMaxMinutes(e.target.value)} - /> -

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다.

- - setDescription(e.target.value)} - /> - - setStaffEmail(e.target.value)} - /> -

장비 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

- - - 장비 이미지 -

- 장비 이미지는 장비 생성 후에 설정 할 수 있습니다. - 장비의 이미지가 없으면 기본 이미지가 표시됩니다. -

-
- - - - 생성 - - - -
- ) -} - -export default EquipmentCreatePage; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form, Message } from 'semantic-ui-react'; + +import ReservationLayout from '@/components/reservation/reservation.layout'; +import { PoPoAxios } from '@/utils/axios.instance'; +import { OwnerOptions } from '@/assets/owner.options'; + +const EquipmentCreatePage = () => { + const router = useRouter(); + const [name, setName] = useState(''); + const [equip_owner, setEquipOwner] = useState(''); + const [fee, setFee] = useState(''); + const [description, setDescription] = useState(''); + const [staff_email, setStaffEmail] = useState(''); + const [max_minutes, setMaxMinutes] = useState(); + + const handleSubmit = async () => { + const body = { + name: name, + equip_owner: equip_owner, + fee: fee, + description: description, + staff_email: staff_email, + }; + + if (max_minutes) { + body['max_minutes'] = max_minutes; + } + + PoPoAxios.post('/equip', body, { withCredentials: true }) + .then(() => { + alert('장비가 생성 되었습니다!'); + router.push('/equipment'); + }) + .catch((err) => { + alert('장비 생성에 실패했습니다.'); + console.log(err); + }); + }; + + return ( + +

장비 생성

+
+ + setName(e.target.value)} + /> + setEquipOwner(value)} + /> + + + setFee(e.target.value)} + /> + + setMaxMinutes(e.target.value)} + /> +

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다.

+ + setDescription(e.target.value)} + /> + + setStaffEmail(e.target.value)} + /> +

장비 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

+ + + 장비 이미지 +

+ 장비 이미지는 장비 생성 후에 설정 할 수 있습니다. 장비의 이미지가 + 없으면 기본 이미지가 표시됩니다. +

+
+ + + + 생성 + + + +
+ ); +}; + +export default EquipmentCreatePage; diff --git a/pages/equipment/index.jsx b/pages/equipment/index.jsx index 69c4884..5441219 100644 --- a/pages/equipment/index.jsx +++ b/pages/equipment/index.jsx @@ -1,29 +1,37 @@ -import { useMemo, useState } from "react"; -import Link from "next/link"; -import { Button, Select } from 'semantic-ui-react' +import { useMemo, useState } from 'react'; +import Link from 'next/link'; +import { Button, Select } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import EquipmentTable from '@/components/equipment/equipment.table' -import { PoPoAxios } from "@/utils/axios.instance"; -import { OwnerOptions } from "@/assets/owner.options"; +import ReservationLayout from '@/components/reservation/reservation.layout'; +import EquipmentTable from '@/components/equipment/equipment.table'; +import { PoPoAxios } from '@/utils/axios.instance'; +import { OwnerOptions } from '@/assets/owner.options'; const EquipmentOwnerOptions = [ { key: 'ALL', value: 'ALL', text: '전체' }, ...OwnerOptions, -] +]; const EquipmentPage = ({ equipmentList }) => { const [selectedOwner, setSelectedOwner] = useState('ALL'); const filteredEquipmentList = useMemo(() => { if (selectedOwner === 'ALL') return equipmentList; - return equipmentList.filter(equipment => equipment.equip_owner === selectedOwner); + return equipmentList.filter( + (equipment) => equipment.equip_owner === selectedOwner, + ); }, [selectedOwner, equipmentList]); return (

장비 목록

-
+
@@ -38,15 +46,17 @@ const EquipmentPage = ({ equipmentList }) => {

- 예약은 생성일 순서로 정렬되어 표시됩니다!
- 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 가능합니다. + 예약은 생성일 순서로 정렬되어 표시됩니다! +
+ 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 + 가능합니다.

- +
- ) -} + ); +}; export default EquipmentPage; diff --git a/pages/equipment/reservation.jsx b/pages/equipment/reservation.jsx index cf5e0a0..7cf3cd9 100644 --- a/pages/equipment/reservation.jsx +++ b/pages/equipment/reservation.jsx @@ -1,51 +1,52 @@ -import React, { useEffect, useState } from 'react' -import { Pagination } from 'semantic-ui-react' +import React, { useEffect, useState } from 'react'; +import { Pagination } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import EquipmentReservationTable - from '@/components/equipment/equipment.reservation.table' +import ReservationLayout from '@/components/reservation/reservation.layout'; +import EquipmentReservationTable from '@/components/equipment/equipment.reservation.table'; import { PoPoAxios } from '@/utils/axios.instance'; const EquipmentReservationPage = () => { - const [reservations, setReservations] = useState([]) - const [page, setPage] = useState(1) - const [total_count, setTotalCount] = useState(0) - const page_size = 10 + const [reservations, setReservations] = useState([]); + const [page, setPage] = useState(1); + const [total_count, setTotalCount] = useState(0); + const page_size = 10; useEffect(() => { try { - PoPoAxios.get( - `/reservation-equip?take=${page_size}`, { - withCredentials: true, - }).then((res) => { - setReservations(res.data) - }) - PoPoAxios.get( - '/reservation-equip/count', - ).then((res) => { - setTotalCount(res.data) - }) + PoPoAxios.get(`/reservation-equip?take=${page_size}`, { + withCredentials: true, + }).then((res) => { + setReservations(res.data); + }); + PoPoAxios.get('/reservation-equip/count').then((res) => { + setTotalCount(res.data); + }); } catch (err) { - alert('장비 예약 목록을 불러오는데 실패했습니다.') - console.log(err) + alert('장비 예약 목록을 불러오는데 실패했습니다.'); + console.log(err); } - }, []) + }, []); const handlePageChange = async (e, target) => { - const activePage = target.activePage + const activePage = target.activePage; const ret = await PoPoAxios.get( - `/reservation-equip?take=${page_size}&skip=${page_size * - (activePage - 1)}`, { withCredentials: true }) - setReservations(ret.data) - setPage(activePage) - } + `/reservation-equip?take=${page_size}&skip=${ + page_size * (activePage - 1) + }`, + { withCredentials: true }, + ); + setReservations(ret.data); + setPage(activePage); + }; return (

장비 예약 목록

- 예약은 생성일 순서로 정렬되어 표시됩니다!
- 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 가능합니다. + 예약은 생성일 순서로 정렬되어 표시됩니다! +
+ 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 + 가능합니다.

{ style={{ margin: '0 auto' }} activePage={page} totalPages={Math.ceil(total_count / page_size)} - prevItem={null} nextItem={null} + prevItem={null} + nextItem={null} onPageChange={handlePageChange} />
- ) -} + ); +}; -export default EquipmentReservationPage \ No newline at end of file +export default EquipmentReservationPage; diff --git a/pages/equipment/update/[uuid].jsx b/pages/equipment/update/[uuid].jsx index a8d116b..95ae1b1 100644 --- a/pages/equipment/update/[uuid].jsx +++ b/pages/equipment/update/[uuid].jsx @@ -1,130 +1,131 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Button, Form, Icon } from 'semantic-ui-react' - -import { PoPoAxios } from "@/utils/axios.instance"; -import { OwnerOptions } from "@/assets/owner.options"; -import ReservationLayout from "@/components/reservation/reservation.layout"; -import ImageUploadForm from "@/components/common/image-upload.form"; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; - -const EquipmentUpdatePage = ({ equipmentInfo }) => { - const router = useRouter(); - - const [deleteModalOpen, setDeleteModalOpen] = useState(false) - - const [name, setName] = useState(equipmentInfo.name) - const [equip_owner, setEquipOwner] = useState(equipmentInfo.equip_owner) - const [fee, setFee] = useState(equipmentInfo.fee) - const [description, setDescription] = useState(equipmentInfo.description) - const [staff_email, setStaffEmail] = useState(equipmentInfo.staff_email) - const [max_minutes, setMaxMinutes] = useState(equipmentInfo.max_minutes) - - const handleSubmit = async () => { - const body = { - 'name': name, - 'equip_owner': equip_owner, - 'fee': fee, - 'description': description, - 'staff_email': staff_email, - }; - - if (max_minutes) { - body['max_minutes'] = max_minutes; - } - - PoPoAxios.put(`/equip/${equipmentInfo.uuid}`, - body, - { withCredentials: true }, - ).then(() => { - alert('장비 정보가 수정 되었습니다!') - router.push('/equipment'); - }).catch((err) => { - alert('장비 정보 수정에 실패했습니다.'); - console.log(err); - }); - } - - return ( - -

장비 수정

-
- - setName(e.target.value)} - /> - setEquipOwner(value)} - /> - - setFee(e.target.value)} - /> - setMaxMinutes(e.target.value)} - /> -

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다.

- setDescription(e.target.value)} - /> - setStaffEmail(e.target.value)} - /> -

장비 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

- - - - - - 수정 - - setDeleteModalOpen(true)}> - 삭제 - )} - /> - - -
- ) -} - -export default EquipmentUpdatePage; - -export async function getServerSideProps(ctx) { - const { uuid } = ctx['params']; - const res = await PoPoAxios.get(`equip/${uuid}`); - const equipmentInfo = res.data; - - return { props: { equipmentInfo } } -} +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; + +import { PoPoAxios } from '@/utils/axios.instance'; +import { OwnerOptions } from '@/assets/owner.options'; +import ReservationLayout from '@/components/reservation/reservation.layout'; +import ImageUploadForm from '@/components/common/image-upload.form'; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; + +const EquipmentUpdatePage = ({ equipmentInfo }) => { + const router = useRouter(); + + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + + const [name, setName] = useState(equipmentInfo.name); + const [equip_owner, setEquipOwner] = useState(equipmentInfo.equip_owner); + const [fee, setFee] = useState(equipmentInfo.fee); + const [description, setDescription] = useState(equipmentInfo.description); + const [staff_email, setStaffEmail] = useState(equipmentInfo.staff_email); + const [max_minutes, setMaxMinutes] = useState(equipmentInfo.max_minutes); + + const handleSubmit = async () => { + const body = { + name: name, + equip_owner: equip_owner, + fee: fee, + description: description, + staff_email: staff_email, + }; + + if (max_minutes) { + body['max_minutes'] = max_minutes; + } + + PoPoAxios.put(`/equip/${equipmentInfo.uuid}`, body, { + withCredentials: true, + }) + .then(() => { + alert('장비 정보가 수정 되었습니다!'); + router.push('/equipment'); + }) + .catch((err) => { + alert('장비 정보 수정에 실패했습니다.'); + console.log(err); + }); + }; + + return ( + +

장비 수정

+
+ + setName(e.target.value)} + /> + setEquipOwner(value)} + /> + + setFee(e.target.value)} + /> + setMaxMinutes(e.target.value)} + /> +

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다.

+ setDescription(e.target.value)} + /> + setStaffEmail(e.target.value)} + /> +

장비 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

+ + + + + + 수정 + + setDeleteModalOpen(true)}> + 삭제 + + } + /> + + +
+ ); +}; + +export default EquipmentUpdatePage; + +export async function getServerSideProps(ctx) { + const { uuid } = ctx['params']; + const res = await PoPoAxios.get(`equip/${uuid}`); + const equipmentInfo = res.data; + + return { props: { equipmentInfo } }; +} diff --git a/pages/index.jsx b/pages/index.jsx index 1ca8283..f6a0c2e 100644 --- a/pages/index.jsx +++ b/pages/index.jsx @@ -1,5 +1,5 @@ -import { Divider, Grid, Image, List } from 'semantic-ui-react' -import LayoutWithAuth from '@/components/layout/layout.auth.with' +import { Divider, Grid, Image, List } from 'semantic-ui-react'; +import LayoutWithAuth from '@/components/layout/layout.auth.with'; const HomePage = () => { return ( @@ -8,41 +8,47 @@ const HomePage = () => {

POPO 관리자 페이지🎩

- 안녕하세요, POPO의 관리자 페이지입니다. - 이곳에서 POPO 사이트의 기능과 데이터베이스를 관리할 수 있습니다. - POPO 서비스가 지속되기 위해선 관리자 여러분의 노력이 필요합니다. 🙏 + 안녕하세요, POPO의 관리자 페이지입니다. 이곳에서 POPO 사이트의 + 기능과 데이터베이스를 관리할 수 있습니다. POPO 서비스가 지속되기 + 위해선 관리자 여러분의 노력이 필요합니다. 🙏

- 현재 POPO의 유지/보수는 동아리 PoApper가 진행하고 있습니다. 서비스 장애시 PoApper에 문의 부탁드립니다 👨‍💻 + 현재 POPO의 유지/보수는 동아리 PoApper가 진행하고 있습니다. 서비스 + 장애시 PoApper에 문의 부탁드립니다 👨‍💻

리뉴얼 이전   - + (구) POPO 홈페이지 -   - (2014 ~ 2019) + {' '} +   (2014 ~ 2019)

- +

최근 추가된 신규 기능 🚀

공지사항 기능 대기중인 예약 목록 가시성 향상 - 관리자 페이지에서 날짜 조건 없이 예약 생성 가능 + + 관리자 페이지에서 날짜 조건 없이 예약 생성 가능 +
{'home_background'} - - ) -} + ); +}; -export default HomePage \ No newline at end of file +export default HomePage; diff --git a/pages/introduce/association/create.jsx b/pages/introduce/association/create.jsx index 6271a17..df15e75 100644 --- a/pages/introduce/association/create.jsx +++ b/pages/introduce/association/create.jsx @@ -1,94 +1,89 @@ -import React, { useState } from 'react' -import { useRouter } from "next/router"; -import { Form, Message } from "semantic-ui-react"; - -import { PoPoAxios } from "@/utils/axios.instance"; -import IntroduceLayout from "@/components/introduce/introduce.layout"; - -const AssociationIntroduceCreatePage = () => { - const router = useRouter(); - - const [name, setName] = useState('') - const [content, setContent] = useState('') - const [location, setLocation] = useState('') - const [representative, setRepresentative] = useState('') - const [contact, setContact] = useState('') - - async function handleSubmit() { - const body = { - 'name': name, - 'content': content, - 'location': location, - 'representative': representative, - 'contact': contact, - }; - - PoPoAxios.post( - 'introduce/association', - body, - { withCredentials: true, }, - ).then(() => { - alert('소개글을 생성 했습니다.'); - router.push('/introduce/association'); - }).catch((err) => { - alert('소개글 생성에 실패했습니다.'); - console.log(err); - }); - } - - return ( - -

자치단체 소개글 생성

- -
- setName(e.target.value)} - /> - setContent(e.target.value)} - /> - setLocation(e.target.value)} - /> - setRepresentative(e.target.value)} - /> - setContact(e.target.value)} - /> - - - 자치단체 로고 -

- 자치단체 로고는 동아리 생성 후에 설정 할 수 있습니다. - 자치단체 로고가 없으면 기본 이미지가 표시됩니다. -

-
- - - - 생성 - - - -
- ) -} - -export default AssociationIntroduceCreatePage; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form, Message } from 'semantic-ui-react'; + +import { PoPoAxios } from '@/utils/axios.instance'; +import IntroduceLayout from '@/components/introduce/introduce.layout'; + +const AssociationIntroduceCreatePage = () => { + const router = useRouter(); + + const [name, setName] = useState(''); + const [content, setContent] = useState(''); + const [location, setLocation] = useState(''); + const [representative, setRepresentative] = useState(''); + const [contact, setContact] = useState(''); + + async function handleSubmit() { + const body = { + name: name, + content: content, + location: location, + representative: representative, + contact: contact, + }; + + PoPoAxios.post('introduce/association', body, { withCredentials: true }) + .then(() => { + alert('소개글을 생성 했습니다.'); + router.push('/introduce/association'); + }) + .catch((err) => { + alert('소개글 생성에 실패했습니다.'); + console.log(err); + }); + } + + return ( + +

자치단체 소개글 생성

+ +
+ setName(e.target.value)} + /> + setContent(e.target.value)} + /> + setLocation(e.target.value)} + /> + setRepresentative(e.target.value)} + /> + setContact(e.target.value)} + /> + + + 자치단체 로고 +

+ 자치단체 로고는 동아리 생성 후에 설정 할 수 있습니다. 자치단체 + 로고가 없으면 기본 이미지가 표시됩니다. +

+
+ + + + 생성 + + + +
+ ); +}; + +export default AssociationIntroduceCreatePage; diff --git a/pages/introduce/association/index.jsx b/pages/introduce/association/index.jsx index 53c65c7..e0659d5 100644 --- a/pages/introduce/association/index.jsx +++ b/pages/introduce/association/index.jsx @@ -1,34 +1,32 @@ -import React from 'react' -import Link from "next/link"; -import { Button } from 'semantic-ui-react' - -import IntroduceLayout from '@/components/introduce/introduce.layout' -import AssociationTable from '@/components/introduce/association.table' -import { PoPoAxios } from "@/utils/axios.instance"; - -const AssociationIntroducePage = ({ associationList }) => { - return ( - -

자치단체 소개글

-
- - - -
-
- -
-
- ) -} - -export default AssociationIntroducePage; - -export async function getServerSideProps() { - const res = await PoPoAxios.get('introduce/association'); - const associationList = res.data; - - return { props: { associationList } }; -} +import React from 'react'; +import Link from 'next/link'; +import { Button } from 'semantic-ui-react'; + +import IntroduceLayout from '@/components/introduce/introduce.layout'; +import AssociationTable from '@/components/introduce/association.table'; +import { PoPoAxios } from '@/utils/axios.instance'; + +const AssociationIntroducePage = ({ associationList }) => { + return ( + +

자치단체 소개글

+
+ + + +
+
+ +
+
+ ); +}; + +export default AssociationIntroducePage; + +export async function getServerSideProps() { + const res = await PoPoAxios.get('introduce/association'); + const associationList = res.data; + + return { props: { associationList } }; +} diff --git a/pages/introduce/association/update/[uuid].jsx b/pages/introduce/association/update/[uuid].jsx index a4f7363..aa2d246 100644 --- a/pages/introduce/association/update/[uuid].jsx +++ b/pages/introduce/association/update/[uuid].jsx @@ -1,144 +1,144 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Button, Form, Icon } from 'semantic-ui-react' - -import { PoPoAxios } from "@/utils/axios.instance"; -import IntroduceLayout from "@/components/introduce/introduce.layout"; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; -import ImageUploadForm from "@/components/common/image-upload.form"; - -const AssociationUpdatePage = ({ associationInfo }) => { - const router = useRouter(); - const [deleteModalOpen, setDeleteModalOpen] = useState(false) - - const [name, setName] = useState(associationInfo.name) - const [content, setContent] = useState(associationInfo.content) - const [location, setLocation] = useState(associationInfo.location) - const [representative, setRepresentative] = useState(associationInfo.representative) - const [contact, setContact] = useState(associationInfo.contact) - const [homepageUrl, setHomepageUrl] = useState(associationInfo.homepage_url) - const [facebookUrl, setFacebookUrl] = useState(associationInfo.facebook_url) - const [instagramUrl, setInstagramUrl] = useState(associationInfo.instagram_url) - - async function handleSubmit() { - const body = { - 'name': name, - 'content': content, - 'location': location, - 'representative': representative, - 'contact': contact, - 'homepage_url': homepageUrl, - 'facebook_url': facebookUrl, - 'instagram_url': instagramUrl, - }; - - PoPoAxios.put( - `/introduce/association/${associationInfo.uuid}`, - body, - { - withCredentials: true, - }, - ).then(() => { - alert('자치단체 정보를 수정 했습니다.'); - router.push('/introduce/association'); - }).catch((err) => { - alert('자치단체 정보 수정에 실패했습니다.'); - console.log(err); - }); - } - - return ( - -

자치단체 소개글 수정

-
- - setName(e.target.value)} - /> - - setContent(e.target.value)} - /> - setLocation(e.target.value)} - /> - setRepresentative(e.target.value)} - /> - setContact(e.target.value)} - /> - setHomepageUrl(e.target.value)} - /> - setFacebookUrl(e.target.value)} - /> - setInstagramUrl(e.target.value)} - /> - - - - - - 수정 - - setDeleteModalOpen(true)}> - 삭제 - )} - /> - - -
- ) -} - -export default AssociationUpdatePage; - -export async function getServerSideProps(ctx) { - const { uuid } = ctx['params']; - const res = await PoPoAxios.get(`introduce/association/${uuid}`); - const associationInfo = res.data; - - return { props: { associationInfo } } -} +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; + +import { PoPoAxios } from '@/utils/axios.instance'; +import IntroduceLayout from '@/components/introduce/introduce.layout'; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; +import ImageUploadForm from '@/components/common/image-upload.form'; + +const AssociationUpdatePage = ({ associationInfo }) => { + const router = useRouter(); + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + + const [name, setName] = useState(associationInfo.name); + const [content, setContent] = useState(associationInfo.content); + const [location, setLocation] = useState(associationInfo.location); + const [representative, setRepresentative] = useState( + associationInfo.representative, + ); + const [contact, setContact] = useState(associationInfo.contact); + const [homepageUrl, setHomepageUrl] = useState(associationInfo.homepage_url); + const [facebookUrl, setFacebookUrl] = useState(associationInfo.facebook_url); + const [instagramUrl, setInstagramUrl] = useState( + associationInfo.instagram_url, + ); + + async function handleSubmit() { + const body = { + name: name, + content: content, + location: location, + representative: representative, + contact: contact, + homepage_url: homepageUrl, + facebook_url: facebookUrl, + instagram_url: instagramUrl, + }; + + PoPoAxios.put(`/introduce/association/${associationInfo.uuid}`, body, { + withCredentials: true, + }) + .then(() => { + alert('자치단체 정보를 수정 했습니다.'); + router.push('/introduce/association'); + }) + .catch((err) => { + alert('자치단체 정보 수정에 실패했습니다.'); + console.log(err); + }); + } + + return ( + +

자치단체 소개글 수정

+
+ + setName(e.target.value)} + /> + + setContent(e.target.value)} + /> + setLocation(e.target.value)} + /> + setRepresentative(e.target.value)} + /> + setContact(e.target.value)} + /> + setHomepageUrl(e.target.value)} + /> + setFacebookUrl(e.target.value)} + /> + setInstagramUrl(e.target.value)} + /> + + + + + + 수정 + + setDeleteModalOpen(true)}> + 삭제 + + } + /> + + +
+ ); +}; + +export default AssociationUpdatePage; + +export async function getServerSideProps(ctx) { + const { uuid } = ctx['params']; + const res = await PoPoAxios.get(`introduce/association/${uuid}`); + const associationInfo = res.data; + + return { props: { associationInfo } }; +} diff --git a/pages/introduce/club/create.jsx b/pages/introduce/club/create.jsx index 645296a..1f5b79b 100644 --- a/pages/introduce/club/create.jsx +++ b/pages/introduce/club/create.jsx @@ -1,107 +1,102 @@ -import React, { useState } from 'react' -import { useRouter } from "next/router"; -import { Form, Message } from "semantic-ui-react"; - -import IntroduceLayout from '@/components/introduce/introduce.layout' -import { PoPoAxios } from "@/utils/axios.instance"; -import { ClubTypeOptions } from "@/assets/club.type.options"; - -const ClubIntroduceCreatePage = () => { - const router = useRouter(); - - const [name, setName] = useState('') - const [short_desc, setShortDesc] = useState('') - const [clubType, setClubType] = useState('') - const [content, setContent] = useState('') - const [location, setLocation] = useState('') - const [representative, setRepresentative] = useState('') - const [contact, setContact] = useState('') - - const handleSubmit = async () => { - const body = { - 'name': name, - 'short_desc': short_desc, - 'clubType': clubType, - 'content': content, - 'location': location, - 'representative': representative, - 'contact': contact, - } - - PoPoAxios.post( - '/introduce/club', - body, - { withCredentials: true, }, - ).then(() => { - alert('소개글을 생성 했습니다.') - router.push('/introduce/club'); - }).catch((err) => { - alert('소개글 생성에 실패했습니다.'); - console.log(err); - }) - } - - return ( - -

동아리 소개글 생성

- -
- setName(e.target.value)} - /> - setShortDesc(e.target.value)} - /> - setClubType(value)} - /> - setContent(e.target.value)} - /> - setLocation(e.target.value)} - /> - setRepresentative(e.target.value)} - /> - setContact(e.target.value)} - /> - - - 동아리 로고 -

- 동아리 로고는 동아리 생성 후에 설정 할 수 있습니다. - 동아리 로고가 없으면 기본 이미지가 표시됩니다. -

-
- - - 생성 - - -
- ) -} - -export default ClubIntroduceCreatePage; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form, Message } from 'semantic-ui-react'; + +import IntroduceLayout from '@/components/introduce/introduce.layout'; +import { PoPoAxios } from '@/utils/axios.instance'; +import { ClubTypeOptions } from '@/assets/club.type.options'; + +const ClubIntroduceCreatePage = () => { + const router = useRouter(); + + const [name, setName] = useState(''); + const [short_desc, setShortDesc] = useState(''); + const [clubType, setClubType] = useState(''); + const [content, setContent] = useState(''); + const [location, setLocation] = useState(''); + const [representative, setRepresentative] = useState(''); + const [contact, setContact] = useState(''); + + const handleSubmit = async () => { + const body = { + name: name, + short_desc: short_desc, + clubType: clubType, + content: content, + location: location, + representative: representative, + contact: contact, + }; + + PoPoAxios.post('/introduce/club', body, { withCredentials: true }) + .then(() => { + alert('소개글을 생성 했습니다.'); + router.push('/introduce/club'); + }) + .catch((err) => { + alert('소개글 생성에 실패했습니다.'); + console.log(err); + }); + }; + + return ( + +

동아리 소개글 생성

+ +
+ setName(e.target.value)} + /> + setShortDesc(e.target.value)} + /> + setClubType(value)} + /> + setContent(e.target.value)} + /> + setLocation(e.target.value)} + /> + setRepresentative(e.target.value)} + /> + setContact(e.target.value)} + /> + + + 동아리 로고 +

+ 동아리 로고는 동아리 생성 후에 설정 할 수 있습니다. 동아리 로고가 + 없으면 기본 이미지가 표시됩니다. +

+
+ + + 생성 + + +
+ ); +}; + +export default ClubIntroduceCreatePage; diff --git a/pages/introduce/club/index.jsx b/pages/introduce/club/index.jsx index 78f9a3f..b45e2e7 100644 --- a/pages/introduce/club/index.jsx +++ b/pages/introduce/club/index.jsx @@ -1,58 +1,60 @@ -import React, { useMemo, useState } from 'react' -import Link from "next/link"; -import { Button, Select } from 'semantic-ui-react' - -import IntroduceLayout from '@/components/introduce/introduce.layout' -import ClubTable from '@/components/introduce/club.table' -import { PoPoAxios } from '@/utils/axios.instance'; -import { ClubTypeOptions } from '@/assets/club.type.options'; - -const SelectClubTypeOptions = [ - { key: 'ALL', value: 'ALL', text: '전체' }, - ...ClubTypeOptions, -] - -const ClubIntroducePage = ({ clubList }) => { - const [selectedClubType, setSelectedClubType] = useState('ALL'); - - const filteredClubList = useMemo(() => { - if (selectedClubType === 'ALL') return clubList; - return clubList.filter(club => club.clubType === selectedClubType); - - }, [selectedClubType, clubList]) - - - return ( - -

동아리 소개글

-
-
- - - -
-
- setSelectedClubType(value)} + /> +
+
+
+ +
+
+ ); +}; + +export default ClubIntroducePage; + +export async function getServerSideProps() { + const res = await PoPoAxios.get('introduce/club'); + const clubList = res.data; + + return { props: { clubList } }; +} diff --git a/pages/introduce/club/update/[uuid].jsx b/pages/introduce/club/update/[uuid].jsx index 81de36f..9fda328 100644 --- a/pages/introduce/club/update/[uuid].jsx +++ b/pages/introduce/club/update/[uuid].jsx @@ -1,172 +1,167 @@ -import React, { useState } from 'react' -import { useRouter } from "next/router"; -import { Button, Form, Icon } from "semantic-ui-react"; - -import { PoPoAxios } from "@/utils/axios.instance"; -import { ClubTypeOptions } from "@/assets/club.type.options"; -import IntroduceLayout from "@/components/introduce/introduce.layout"; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; -import ImageUploadForm from "@/components/common/image-upload.form"; - -const ClubUpdatePage = ({ clubInfo }) => { - const router = useRouter(); - - const [deleteModalOpen, setDeleteModalOpen] = useState(false) - const [name, setName] = useState(clubInfo.name) - const [short_desc, setShortDesc] = useState(clubInfo.short_desc) - const [clubType, setClubType] = useState(clubInfo.clubType) - const [content, setContent] = useState(clubInfo.content) - const [location, setLocation] = useState(clubInfo.location) - const [representative, setRepresentative] = useState(clubInfo.representative) - const [contact, setContact] = useState(clubInfo.contact) - const [homepageUrl, setHomepageUrl] = useState(clubInfo.homepage_url) - const [facebookUrl, setFacebookUrl] = useState(clubInfo.facebook_url) - const [instagramUrl, setInstagramUrl] = useState(clubInfo.instagram_url) - const [youtubeUrl, setYoutubeUrl] = useState(clubInfo.youtube_url) - - const handleSubmit = async () => { - const body = { - 'name': name, - 'short_desc': short_desc, - 'clubType': clubType, - 'content': content, - 'location': location, - 'representative': representative, - 'contact': contact, - 'homepage_url': homepageUrl, - 'facebook_url': facebookUrl, - 'instagram_url': instagramUrl, - 'youtube_url': youtubeUrl, - }; - - PoPoAxios.put(`/introduce/club/${clubInfo.uuid}`, - body, - { - withCredentials: true, - }, - ).then(() => { - alert('동아리 정보를 수정 했습니다.'); - router.push('/introduce/club'); - }).catch((err) => { - alert('동아리 정보 수정에 실패했습니다.'); - console.log(err); - }); - } - - return ( - -

동아리 정보 수정

- -
- setName(e.target.value)} - /> - setShortDesc(e.target.value)} - /> - setClubType(e.target.value)} - /> - setContent(e.target.value)} - /> - setLocation(e.target.value)} - /> - setRepresentative(e.target.value)} - /> - setContact(e.target.value)} - /> - - setHomepageUrl(e.target.value)} - /> - setFacebookUrl(e.target.value)} - /> - setInstagramUrl(e.target.value)} - /> - setYoutubeUrl(e.target.value)} - /> - - - - - - 수정 - - setDeleteModalOpen(true)} - > - 삭제 - )} - /> - - -
- ) -} - -export default ClubUpdatePage; - -export async function getServerSideProps(ctx) { - const { uuid } = ctx['params']; - const res = await PoPoAxios.get(`introduce/club/${uuid}`); - const clubInfo = res.data; - - return { props: { clubInfo } } -} +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; + +import { PoPoAxios } from '@/utils/axios.instance'; +import { ClubTypeOptions } from '@/assets/club.type.options'; +import IntroduceLayout from '@/components/introduce/introduce.layout'; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; +import ImageUploadForm from '@/components/common/image-upload.form'; + +const ClubUpdatePage = ({ clubInfo }) => { + const router = useRouter(); + + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + const [name, setName] = useState(clubInfo.name); + const [short_desc, setShortDesc] = useState(clubInfo.short_desc); + const [clubType, setClubType] = useState(clubInfo.clubType); + const [content, setContent] = useState(clubInfo.content); + const [location, setLocation] = useState(clubInfo.location); + const [representative, setRepresentative] = useState(clubInfo.representative); + const [contact, setContact] = useState(clubInfo.contact); + const [homepageUrl, setHomepageUrl] = useState(clubInfo.homepage_url); + const [facebookUrl, setFacebookUrl] = useState(clubInfo.facebook_url); + const [instagramUrl, setInstagramUrl] = useState(clubInfo.instagram_url); + const [youtubeUrl, setYoutubeUrl] = useState(clubInfo.youtube_url); + + const handleSubmit = async () => { + const body = { + name: name, + short_desc: short_desc, + clubType: clubType, + content: content, + location: location, + representative: representative, + contact: contact, + homepage_url: homepageUrl, + facebook_url: facebookUrl, + instagram_url: instagramUrl, + youtube_url: youtubeUrl, + }; + + PoPoAxios.put(`/introduce/club/${clubInfo.uuid}`, body, { + withCredentials: true, + }) + .then(() => { + alert('동아리 정보를 수정 했습니다.'); + router.push('/introduce/club'); + }) + .catch((err) => { + alert('동아리 정보 수정에 실패했습니다.'); + console.log(err); + }); + }; + + return ( + +

동아리 정보 수정

+ +
+ setName(e.target.value)} + /> + setShortDesc(e.target.value)} + /> + setClubType(e.target.value)} + /> + setContent(e.target.value)} + /> + setLocation(e.target.value)} + /> + setRepresentative(e.target.value)} + /> + setContact(e.target.value)} + /> + + setHomepageUrl(e.target.value)} + /> + setFacebookUrl(e.target.value)} + /> + setInstagramUrl(e.target.value)} + /> + setYoutubeUrl(e.target.value)} + /> + + + + + + 수정 + + setDeleteModalOpen(true)}> + 삭제 + + } + /> + + +
+ ); +}; + +export default ClubUpdatePage; + +export async function getServerSideProps(ctx) { + const { uuid } = ctx['params']; + const res = await PoPoAxios.get(`introduce/club/${uuid}`); + const clubInfo = res.data; + + return { props: { clubInfo } }; +} diff --git a/pages/introduce/index.jsx b/pages/introduce/index.jsx index 680d18a..ff99dd1 100644 --- a/pages/introduce/index.jsx +++ b/pages/introduce/index.jsx @@ -1,37 +1,32 @@ -import { PoPoAxios } from "@/utils/axios.instance"; -import IntroduceLayout from '@/components/introduce/introduce.layout' -import AssociationTable from '@/components/introduce/association.table' -import ClubTable from '@/components/introduce/club.table' +import { PoPoAxios } from '@/utils/axios.instance'; +import IntroduceLayout from '@/components/introduce/introduce.layout'; +import AssociationTable from '@/components/introduce/association.table'; +import ClubTable from '@/components/introduce/club.table'; const IntroducePage = ({ associationList, clubList }) => { return (

현재 영문 소개글을 지원하기 위해 개발하고 있습니다 👨‍💻

- +

오늘 조회된 자치단체 소개글

- +
- +

오늘 조회된 동아리 소개글

- +
- ) -} + ); +}; export default IntroducePage; - export async function getServerSideProps() { const res1 = await PoPoAxios.get('introduce/association/today'); const associationList = res1.data; - + const res2 = await PoPoAxios.get('introduce/club/today'); const clubList = res2.data; diff --git a/pages/login.jsx b/pages/login.jsx index af6b6bb..b3ca8b5 100644 --- a/pages/login.jsx +++ b/pages/login.jsx @@ -1,45 +1,48 @@ -import { useEffect, useState } from 'react' -import { useRouter } from 'next/router' -import { Form, Image } from 'semantic-ui-react' -import styled from 'styled-components' +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form, Image } from 'semantic-ui-react'; +import styled from 'styled-components'; -import LayoutWithoutAuth from '@/components/layout/layout.auth.without' +import LayoutWithoutAuth from '@/components/layout/layout.auth.without'; import { PoPoAxios } from '@/utils/axios.instance'; const LoginPage = () => { - const router = useRouter() + const router = useRouter(); - const [email, setEmail] = useState('') - const [password, setPW] = useState('') + const [email, setEmail] = useState(''); + const [password, setPW] = useState(''); useEffect(() => { PoPoAxios.get('/auth/verifyToken', { withCredentials: true, - }).then(() => { - alert('이미 로그인 상태 입니다.') - router.push('/') - }).catch(() => {}) - }, [router]) + }) + .then(() => { + alert('이미 로그인 상태 입니다.'); + router.push('/'); + }) + .catch(() => {}); + }, [router]); const handleLogin = async () => { try { - await PoPoAxios.post('/auth/login/admin', { - email: email, - password: password, - }, { withCredentials: true }) - await router.push('/') + await PoPoAxios.post( + '/auth/login/admin', + { + email: email, + password: password, + }, + { withCredentials: true }, + ); + await router.push('/'); } catch (e) { - alert('로그인에 실패했습니다.') - console.log(e) + alert('로그인에 실패했습니다.'); + console.log(e); } - } + }; return ( - {'popo-logo'} + {'popo-logo'} 관리자 페이지 @@ -55,23 +58,20 @@ const LoginPage = () => { label={'비밀번호'} onChange={(e) => setPW(e.target.value)} /> - - 로그인 - + 로그인 - - ) -} + ); +}; -export default LoginPage +export default LoginPage; const SubTitle = styled.h2` margin-top: 0; font-size: 26px !important; font-weight: 500; -` +`; const LoginFormDiv = styled.div` width: 500px; @@ -79,4 +79,4 @@ const LoginFormDiv = styled.div` @media only screen and (max-width: 768px) { width: 100%; } -` \ No newline at end of file +`; diff --git a/pages/place/create.jsx b/pages/place/create.jsx index cc9cc27..c5dbcf2 100644 --- a/pages/place/create.jsx +++ b/pages/place/create.jsx @@ -1,56 +1,59 @@ -import { useState } from 'react' -import { useRouter } from "next/router"; -import { Form, Message } from "semantic-ui-react"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Form, Message } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import { RegionOptions } from '@/assets/region.options' -import { PoPoAxios } from "@/utils/axios.instance"; -import OpeningHoursEditor, {checkValid} from '@/components/common/opening_hours.editor'; +import ReservationLayout from '@/components/reservation/reservation.layout'; +import { RegionOptions } from '@/assets/region.options'; +import { PoPoAxios } from '@/utils/axios.instance'; +import OpeningHoursEditor, { + checkValid, +} from '@/components/common/opening_hours.editor'; const PlaceCreatePage = () => { const router = useRouter(); - const [name, setName] = useState('') - const [region, setRegion] = useState('') - const [location, setLocation] = useState('') - const [description, setDescription] = useState('') - const [staff_email, setStaffEmail] = useState('') - const [max_minutes, setMaxMinutes] = useState(24 * 60) - const [max_concurrent_reservation, setMaxConcurrentReservation] = useState(1) - const [opening_hours, setOpeningHours] = useState({ 'Everyday': '00:00-24:00' }) - const [enable_auto_accept, setEnableAutoAccept] = useState('Inactive') + const [name, setName] = useState(''); + const [region, setRegion] = useState(''); + const [location, setLocation] = useState(''); + const [description, setDescription] = useState(''); + const [staff_email, setStaffEmail] = useState(''); + const [max_minutes, setMaxMinutes] = useState(24 * 60); + const [max_concurrent_reservation, setMaxConcurrentReservation] = useState(1); + const [opening_hours, setOpeningHours] = useState({ + Everyday: '00:00-24:00', + }); + const [enable_auto_accept, setEnableAutoAccept] = useState('Inactive'); const handleSubmit = async () => { - for(const day of Object.keys(opening_hours)) { + for (const day of Object.keys(opening_hours)) { if (!checkValid(opening_hours[day])) { - alert(`사용 가능 시간이 올바르지 않습니다: ${day}`) + alert(`사용 가능 시간이 올바르지 않습니다: ${day}`); return; } } const body = { - 'name': name, - 'region': region, - 'location': location, - 'description': description, - 'staff_email': staff_email, - 'max_minutes': max_minutes, - 'max_concurrent_reservation': max_concurrent_reservation, - 'opening_hours': JSON.stringify(opening_hours), - 'enable_auto_accept': enable_auto_accept, - } - - PoPoAxios.post('/place', - body, - { withCredentials: true }, - ).then(() => { - alert('장소가 생성 되었습니다!') - router.push('/place'); - }).catch(err => { - console.log(err); - alert('장소 생성에 실패했습니다.'); - }) - } + name: name, + region: region, + location: location, + description: description, + staff_email: staff_email, + max_minutes: max_minutes, + max_concurrent_reservation: max_concurrent_reservation, + opening_hours: JSON.stringify(opening_hours), + enable_auto_accept: enable_auto_accept, + }; + + PoPoAxios.post('/place', body, { withCredentials: true }) + .then(() => { + alert('장소가 생성 되었습니다!'); + router.push('/place'); + }) + .catch((err) => { + console.log(err); + alert('장소 생성에 실패했습니다.'); + }); + }; return ( @@ -68,27 +71,34 @@ const PlaceCreatePage = () => { setName(e.target.value)} + onChange={(e) => setName(e.target.value)} /> setLocation(e.target.value)} + onChange={(e) => setLocation(e.target.value)} /> setMaxMinutes(e.target.value)} + label={'최대 예약가능 시간'} + placeholder={ + '해당 장소를 예약가능한 최대 시간을 분단위로 입력해주세요 (ex. 60)' + } + onChange={(e) => setMaxMinutes(e.target.value)} /> -

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다. (단위: minutes)

+

+ 최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다. (단위: + minutes) +

setMaxConcurrentReservation(e.target.value)} + label={'최대 동시 예약 갯수'} + placeholder={ + '해당 장소를 동시 예약 가능한 최대 갯수를 입력해주세요 (ex. 1)' + } + onChange={(e) => setMaxConcurrentReservation(e.target.value)} /> { label={'자동 승인 기능 활성화'} value={enable_auto_accept} options={[ - {key: 'active', text: '활성', value: 'Active'}, - {key: 'inactive', text: '비활성', value: 'Inactive'}, + { key: 'active', text: '활성', value: 'Active' }, + { key: 'inactive', text: '비활성', value: 'Inactive' }, ]} onChange={(e, { value }) => setEnableAutoAccept(value)} /> @@ -112,30 +122,28 @@ const PlaceCreatePage = () => { setDescription(e.target.value)} + onChange={(e) => setDescription(e.target.value)} /> setStaffEmail(e.target.value)} + onChange={(e) => setStaffEmail(e.target.value)} />

장소 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

장소 이미지

- 장소 이미지는 장소 생성 후에 설정 할 수 있습니다. - 장소의 이미지가 없으면 기본 이미지가 표시됩니다. + 장소 이미지는 장소 생성 후에 설정 할 수 있습니다. 장소의 이미지가 + 없으면 기본 이미지가 표시됩니다.

- - 생성 - + 생성
- ) -} + ); +}; export default PlaceCreatePage; diff --git a/pages/place/index.jsx b/pages/place/index.jsx index 566501b..69c90b7 100644 --- a/pages/place/index.jsx +++ b/pages/place/index.jsx @@ -1,29 +1,35 @@ -import React from 'react' -import Link from 'next/link' -import { Button, Select } from 'semantic-ui-react' +import React from 'react'; +import Link from 'next/link'; +import { Button, Select } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import PlaceTable from '@/components/place/place.table' -import { PoPoAxios } from "@/utils/axios.instance"; -import { RegionOptions } from '@/assets/region.options' +import ReservationLayout from '@/components/reservation/reservation.layout'; +import PlaceTable from '@/components/place/place.table'; +import { PoPoAxios } from '@/utils/axios.instance'; +import { RegionOptions } from '@/assets/region.options'; const PlaceRegionOptions = [ { key: 'ALL', value: 'ALL', text: '전체' }, ...RegionOptions, -] +]; const PlacePage = ({ placeList }) => { const [selectedRegion, setSelectedRegion] = React.useState('ALL'); const filteredPlaceList = React.useMemo(() => { if (selectedRegion === 'ALL') return placeList; - return placeList.filter(place => place.region === selectedRegion); + return placeList.filter((place) => place.region === selectedRegion); }, [selectedRegion, placeList]); return (

장소 목록

-
+
@@ -38,15 +44,16 @@ const PlacePage = ({ placeList }) => {

- 퍼블릭 페이지에는 마지막 수정일 순서로 정렬되어 표시됩니다.
+ 퍼블릭 페이지에는 마지막 수정일 순서로 정렬되어 표시됩니다. +
테이블 헤더를 클릭하여 정렬된 결과를 확인할 수 있습니다.

- +
- ) -} + ); +}; export default PlacePage; diff --git a/pages/place/reservation/create.jsx b/pages/place/reservation/create.jsx index 73057fb..3747be9 100644 --- a/pages/place/reservation/create.jsx +++ b/pages/place/reservation/create.jsx @@ -1,9 +1,9 @@ -import React, { useEffect, useMemo, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/router'; -import moment from 'moment' +import moment from 'moment'; import { Divider, Form, Message } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' +import ReservationLayout from '@/components/reservation/reservation.layout'; import { PoPoAxios } from '@/utils/axios.instance'; import { RegionOptions } from '@/assets/region.options'; import { hourDiff, roundUpByDuration } from '@/utils/time-date'; @@ -15,61 +15,65 @@ const RegionKorNameMapping = { STUDENT_HALL: '학생 회관', JIGOK_CENTER: '지곡 회관', OTHERS: '기타', - COMMUNITY_CENTER : '커뮤니티 센터', + COMMUNITY_CENTER: '커뮤니티 센터', RESIDENTIAL_COLLEGE: 'RC', -} +}; const PlaceReservationCreatePage = ({ placeList }) => { - const router = useRouter() + const router = useRouter(); - const [region, setRegion] = useState() + const [region, setRegion] = useState(); const filteredPlaceList = useMemo(() => { - return placeList.filter(place => place.region === region); + return placeList.filter((place) => place.region === region); }, [region, placeList]); - const placeOptions = filteredPlaceList.map(place => { return { - key: place.id, - value: place, - text: place.name, - }}) + const placeOptions = filteredPlaceList.map((place) => { + return { + key: place.id, + value: place, + text: place.name, + }; + }); - const [placeInfo, setPlaceInfo] = useState(null) - const [userInfo, setUserInfo] = useState(null) - console.log(placeInfo) + const [placeInfo, setPlaceInfo] = useState(null); + const [userInfo, setUserInfo] = useState(null); + console.log(placeInfo); - const [phone, setPhone] = useState('') - const [title, setTitle] = useState('') - const [description, setDescription] = useState('') + const [phone, setPhone] = useState(''); + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); const now = roundUpByDuration(moment(), 30); const nowNext30Min = moment(now).add(30, 'minute'); - const [date, setDate] = useState(now) // YYYY-MM-DD - const [startTime, setStartTime] = useState(now) // HHmm - const [endTime, setEndTime] = useState(nowNext30Min) // HHmm + const [date, setDate] = useState(now); // YYYY-MM-DD + const [startTime, setStartTime] = useState(now); // HHmm + const [endTime, setEndTime] = useState(nowNext30Min); // HHmm - const isPossible = placeInfo ? isOnOpeningHours( - placeInfo.opening_hours, - date.format('dddd'), // Monday - startTime.format('HH:mm'), - endTime.format('HH:mm') - ) : false; + const isPossible = placeInfo + ? isOnOpeningHours( + placeInfo.opening_hours, + date.format('dddd'), // Monday + startTime.format('HH:mm'), + endTime.format('HH:mm'), + ) + : false; useEffect(() => { - PoPoAxios.get( - '/auth/verifyToken', - { withCredentials: true }). - then(res => setUserInfo(res.data)). - catch(() => { + PoPoAxios.get('/auth/verifyToken', { withCredentials: true }) + .then((res) => setUserInfo(res.data)) + .catch(() => { // alert('로그인 후 예약 할 수 있습니다.'); // router.push('/auth/login'); - }) - }, [router]) + }); + }, [router]); - function handleSubmit () { + function handleSubmit() { if (!isPossible) { - alert(`예약이 불가능한 시간대입니다. ${placeInfo.name}의 사용 가능 시간을 확인해주세요.`); + alert( + `예약이 불가능한 시간대입니다. ${placeInfo.name}의 사용 가능 시간을 확인해주세요.`, + ); return; } @@ -78,20 +82,26 @@ const PlaceReservationCreatePage = ({ placeList }) => { return; } - PoPoAxios.post('/reservation-place', { - place_id: placeInfo.uuid, - phone: phone, - title: title, - description: description, - date: date.format('YYYYMMDD'), // YYYYMMDD - start_time: startTime.format('HHmm'), // HHmm - end_time: endTime.format('HHmm'), // HHmm - }, { withCredentials: true }).then(() => { - alert('예약을 생성했습니다!'); - router.push('/place/reservation'); - }).catch((error) => { - alert(`예약 생성에 실패했습니다: ${error.response.data.message}`); - }) + PoPoAxios.post( + '/reservation-place', + { + place_id: placeInfo.uuid, + phone: phone, + title: title, + description: description, + date: date.format('YYYYMMDD'), // YYYYMMDD + start_time: startTime.format('HHmm'), // HHmm + end_time: endTime.format('HHmm'), // HHmm + }, + { withCredentials: true }, + ) + .then(() => { + alert('예약을 생성했습니다!'); + router.push('/place/reservation'); + }) + .catch((error) => { + alert(`예약 생성에 실패했습니다: ${error.response.data.message}`); + }); } return ( @@ -99,19 +109,24 @@ const PlaceReservationCreatePage = ({ placeList }) => {

장소 예약 생성 (관리자)

- 일반 유저는 한달 이내 예약만 생성 가능하지만, 관리자 페이지에서는 한달 이후 예약도 생성 가능합니다. + 일반 유저는 한달 이내 예약만 생성 가능하지만, 관리자 페이지에서는 한달 + 이후 예약도 생성 가능합니다.
setRegion(value)} /> setPlaceInfo(value)} @@ -119,68 +134,81 @@ const PlaceReservationCreatePage = ({ placeList }) => { + required + readOnly + label={'사용자'} + value={userInfo ? userInfo.name : ''} + /> setPhone(e.target.value)}/> + onChange={(e) => setPhone(e.target.value)} + /> setTitle(e.target.value)}/> + onChange={(e) => setTitle(e.target.value)} + /> setDescription(e.target.value)}/> - - + onChange={(e) => setDescription(e.target.value)} + /> + + + + {placeInfo ? ( + <> + + + + + {isPossible ? null : ( + + 예약이 불가능한 시간대입니다. {placeInfo.name}의 사용 가능 + 시간을 확인해주세요. + + )} - { - placeInfo ? ( - <> - - + +
+ - - - { - isPossible ? null : ( - - 예약이 불가능한 시간대입니다. {placeInfo.name}의 사용 가능 시간을 확인해주세요. - - ) - } - -
- -
- -
- - - 예약 장소와 예약 시간을 꼭 확인해주세요! -

- { - RegionKorNameMapping[placeInfo.region] - } {placeInfo.name}, {hourDiff(startTime, endTime)}시간 예약입니다. -

-
- - - 생성 - - - ) : null - } +
+ + + + 예약 장소와 예약 시간을 꼭 확인해주세요! + +

+ {RegionKorNameMapping[placeInfo.region]} {placeInfo.name},{' '} + {hourDiff(startTime, endTime)}시간 예약입니다. +

+
+ + + 생성 + + + ) : null} - ) -} + ); +}; export default PlaceReservationCreatePage; diff --git a/pages/place/reservation/index.jsx b/pages/place/reservation/index.jsx index 1c70955..1f841f9 100644 --- a/pages/place/reservation/index.jsx +++ b/pages/place/reservation/index.jsx @@ -1,54 +1,53 @@ -import React, { useEffect, useState } from 'react' -import { Button, Pagination } from 'semantic-ui-react' +import React, { useEffect, useState } from 'react'; +import { Button, Pagination } from 'semantic-ui-react'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import PlaceReservationTable - from '@/components/place/place.reservation.table' +import ReservationLayout from '@/components/reservation/reservation.layout'; +import PlaceReservationTable from '@/components/place/place.reservation.table'; import { PoPoAxios } from '@/utils/axios.instance'; const PlaceReservationPage = () => { - const [reservations, setReservations] = useState([]) - const [page, setPage] = useState(1) - const [total_count, setTotalCount] = useState(0) - const page_size = 10 + const [reservations, setReservations] = useState([]); + const [page, setPage] = useState(1); + const [total_count, setTotalCount] = useState(0); + const page_size = 10; useEffect(() => { try { - PoPoAxios.get( - `/reservation-place?take=${page_size}`, { - withCredentials: true, - }).then((res) => { - setReservations(res.data) - }) - PoPoAxios.get( - '/reservation-place/count', - ).then((res) => { - setTotalCount(res.data) - }) + PoPoAxios.get(`/reservation-place?take=${page_size}`, { + withCredentials: true, + }).then((res) => { + setReservations(res.data); + }); + PoPoAxios.get('/reservation-place/count').then((res) => { + setTotalCount(res.data); + }); } catch (err) { - alert('장소 예약 목록을 불러오는데 실패했습니다.') - console.log(err) + alert('장소 예약 목록을 불러오는데 실패했습니다.'); + console.log(err); } - }, []) + }, []); const handlePageChange = async (e, target) => { - const activePage = target.activePage + const activePage = target.activePage; const ret = await PoPoAxios.get( `/reservation-place?take=10&skip=${page_size * (activePage - 1)}`, - { withCredentials: true }) - setReservations(ret.data) - setPage(activePage) - } + { withCredentials: true }, + ); + setReservations(ret.data); + setPage(activePage); + }; return (

장소 예약 목록

- 예약은 생성일 순서로 정렬되어 표시됩니다!
- 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 가능합니다. + 예약은 생성일 순서로 정렬되어 표시됩니다! +
+ 예약 내용을 수정하는 건 불가능합니다. 예약 승인/거절/삭제만 + 가능합니다.

-

@@ -62,13 +61,14 @@ const PlaceReservationPage = () => { style={{ margin: '0 auto' }} activePage={page} totalPages={Math.ceil(total_count / page_size)} - prevItem={null} nextItem={null} + prevItem={null} + nextItem={null} onPageChange={handlePageChange} />
- ) -} + ); +}; -export default PlaceReservationPage \ No newline at end of file +export default PlaceReservationPage; diff --git a/pages/place/update/[uuid].jsx b/pages/place/update/[uuid].jsx index 5e303db..80934b9 100644 --- a/pages/place/update/[uuid].jsx +++ b/pages/place/update/[uuid].jsx @@ -1,61 +1,67 @@ -import { useState } from 'react' -import { useRouter } from 'next/router' -import { Button, Form, Icon } from "semantic-ui-react"; - -import ReservationLayout from "@/components/reservation/reservation.layout"; -import OpeningHoursEditor, { checkValid } from "@/components/common/opening_hours.editor"; -import { PoPoAxios } from "@/utils/axios.instance"; -import { RegionOptions } from "@/assets/region.options"; -import ImageUploadForm from "@/components/common/image-upload.form"; -import DeleteConfirmModal from "@/components/common/delete.confirm.modal"; +import { useState } from 'react'; +import { useRouter } from 'next/router'; +import { Button, Form, Icon } from 'semantic-ui-react'; + +import ReservationLayout from '@/components/reservation/reservation.layout'; +import OpeningHoursEditor, { + checkValid, +} from '@/components/common/opening_hours.editor'; +import { PoPoAxios } from '@/utils/axios.instance'; +import { RegionOptions } from '@/assets/region.options'; +import ImageUploadForm from '@/components/common/image-upload.form'; +import DeleteConfirmModal from '@/components/common/delete.confirm.modal'; const PlaceUpdatePage = ({ placeInfo }) => { const router = useRouter(); - const [deleteModalOpen, setDeleteModalOpen] = useState(false) - - const [name, setName] = useState(placeInfo.name) - const [region, setRegion] = useState(placeInfo.region) - const [location, setLocation] = useState(placeInfo.location) - const [description, setDescription] = useState(placeInfo.description) - const [staff_email, setStaffEmail] = useState(placeInfo.staff_email) - const [max_minutes, setMaxMinutes] = useState(placeInfo.max_minutes) - const [max_concurrent_reservation, setMaxConcurrentReservation] = useState(placeInfo.max_concurrent_reservation) - const [opening_hours, setOpeningHours] = useState(JSON.parse(placeInfo.opening_hours)) - const [enable_auto_accept, setEnableAutoAccept] = useState(placeInfo.enable_auto_accept) - + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + + const [name, setName] = useState(placeInfo.name); + const [region, setRegion] = useState(placeInfo.region); + const [location, setLocation] = useState(placeInfo.location); + const [description, setDescription] = useState(placeInfo.description); + const [staff_email, setStaffEmail] = useState(placeInfo.staff_email); + const [max_minutes, setMaxMinutes] = useState(placeInfo.max_minutes); + const [max_concurrent_reservation, setMaxConcurrentReservation] = useState( + placeInfo.max_concurrent_reservation, + ); + const [opening_hours, setOpeningHours] = useState( + JSON.parse(placeInfo.opening_hours), + ); + const [enable_auto_accept, setEnableAutoAccept] = useState( + placeInfo.enable_auto_accept, + ); const handleSubmit = async () => { - for(const day of Object.keys(opening_hours)) { + for (const day of Object.keys(opening_hours)) { if (!checkValid(opening_hours[day])) { - alert(`사용 가능 시간이 올바르지 않습니다: ${day}`) + alert(`사용 가능 시간이 올바르지 않습니다: ${day}`); return; } } const body = { - 'name': name, - 'region': region, - 'location': location, - 'description': description, - 'staff_email': staff_email, - 'max_minutes': max_minutes, - 'max_concurrent_reservation': max_concurrent_reservation, - 'opening_hours': JSON.stringify(opening_hours), - 'enable_auto_accept': enable_auto_accept, - } - - PoPoAxios.put(`/place/${placeInfo.uuid}`, - body, - { withCredentials: true }, - ).then(() => { - alert('장소 정보가 수정 되었습니다!') - router.push('/place'); - }).catch(err => { - alert('장소 정보 수정에 실패했습니다.'); - console.log(err); - }) - } + name: name, + region: region, + location: location, + description: description, + staff_email: staff_email, + max_minutes: max_minutes, + max_concurrent_reservation: max_concurrent_reservation, + opening_hours: JSON.stringify(opening_hours), + enable_auto_accept: enable_auto_accept, + }; + + PoPoAxios.put(`/place/${placeInfo.uuid}`, body, { withCredentials: true }) + .then(() => { + alert('장소 정보가 수정 되었습니다!'); + router.push('/place'); + }) + .catch((err) => { + alert('장소 정보 수정에 실패했습니다.'); + console.log(err); + }); + }; return ( @@ -75,7 +81,7 @@ const PlaceUpdatePage = ({ placeInfo }) => { required label={'장소 이름'} value={name} - onChange={e => setName(e.target.value)} + onChange={(e) => setName(e.target.value)} /> { label={'위치'} placeholder={'예: 학생회관 304호'} value={location} - onChange={e => setLocation(e.target.value)} + onChange={(e) => setLocation(e.target.value)} /> setMaxMinutes(e.target.value)} + onChange={(e) => setMaxMinutes(e.target.value)} /> -

최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다. (단위: minutes)

+

+ 최대 예약가능 시간이 넘는 예약이 생성되지 않도록 합니다. (단위: + minutes) +

setMaxConcurrentReservation(e.target.value)} + onChange={(e) => setMaxConcurrentReservation(e.target.value)} /> { label={'자동 승인 기능 활성화'} value={enable_auto_accept} options={[ - {key: 'active', text: '활성', value: 'Active'}, - {key: 'inactive', text: '비활성', value: 'Inactive'}, + { key: 'active', text: '활성', value: 'Active' }, + { key: 'inactive', text: '비활성', value: 'Inactive' }, ]} onChange={(e, { value }) => setEnableAutoAccept(value)} /> @@ -123,14 +136,14 @@ const PlaceUpdatePage = ({ placeInfo }) => { required label={'설명'} value={description} - onChange={e => setDescription(e.target.value)} + onChange={(e) => setDescription(e.target.value)} /> setStaffEmail(e.target.value)} + onChange={(e) => setStaffEmail(e.target.value)} />

장소 예약이 생성되면, 담당자 메일로 예약 생성 메일이 갑니다.

@@ -141,26 +154,24 @@ const PlaceUpdatePage = ({ placeInfo }) => { /> - + 수정 setDeleteModalOpen(true)}> - 삭제 - )} + trigger={ + + } />
- ) -} + ); +}; export default PlaceUpdatePage; @@ -169,5 +180,5 @@ export async function getServerSideProps(ctx) { const res = await PoPoAxios.get(`place/${uuid}`); const placeInfo = res.data; - return { props: { placeInfo } } + return { props: { placeInfo } }; } diff --git a/pages/reservation/index.jsx b/pages/reservation/index.jsx index 2733138..1962772 100644 --- a/pages/reservation/index.jsx +++ b/pages/reservation/index.jsx @@ -3,11 +3,9 @@ import { Tab } from 'semantic-ui-react'; import moment from 'moment'; import { PoPoAxios } from '@/utils/axios.instance'; -import ReservationLayout from '@/components/reservation/reservation.layout' -import PlaceReservationWaitTable - from '@/components/place/place.reservation.wait.table' -import EquipmentReservationWaitTable - from '@/components/equipment/equipment.reservation.wait.table'; +import ReservationLayout from '@/components/reservation/reservation.layout'; +import PlaceReservationWaitTable from '@/components/place/place.reservation.wait.table'; +import EquipmentReservationWaitTable from '@/components/equipment/equipment.reservation.wait.table'; const ReservationPage = ({ totalReservationCnt, @@ -27,12 +25,20 @@ const ReservationPage = ({ useEffect(() => { async function getCurrentPlaceReservations() { const res = await PoPoAxios.get('reservation-place?status=심사중'); - const sortedPlace = res.data.sort((a, b) => new moment(`${b.date}T${b.start_time}`) - new moment(`${a.date}T${a.start_time}`)); + const sortedPlace = res.data.sort( + (a, b) => + new moment(`${b.date}T${b.start_time}`) - + new moment(`${a.date}T${a.start_time}`), + ); setPlaceReservations(sortedPlace); } async function getCurrentEquipReservations() { const res = await PoPoAxios.get('reservation-equip?status=심사중'); - const sortedEquip = res.data.sort((a, b) => new moment(`${b.date}T${b.start_time}`) - new moment(`${a.date}T${a.start_time}`)); + const sortedEquip = res.data.sort( + (a, b) => + new moment(`${b.date}T${b.start_time}`) - + new moment(`${a.date}T${a.start_time}`), + ); setEquipReservations(sortedEquip); } @@ -40,91 +46,97 @@ const ReservationPage = ({ getCurrentPlaceReservations(), getCurrentEquipReservations(), ]).then(() => setIsLoading(false)); - }, []) - + }, []); return (

예약 대기 목록

-
    +
    • 총 예약 수: {Number(totalReservationCnt).toLocaleString()}건
    • 오늘 예약 수: {Number(todayReservationCnt).toLocaleString()}건
    • -
    • 이번 주 예약 수: {Number(thisWeekReservationCnt).toLocaleString()}건
    • +
    • + 이번 주 예약 수: {Number(thisWeekReservationCnt).toLocaleString()}건 +

    - 심사중인 모든 예약이 이곳에 표시됩니다. 예약 제목을 누르면 상세 예약 정보를 확인할 수 있습니다. + 심사중인 모든 예약이 이곳에 표시됩니다. 예약 제목을 누르면 상세 + 예약 정보를 확인할 수 있습니다.

    - 예약 종료 시간이 현재 시간을 지났다면 빨간색으로 표시됩니다. + 예약 종료 시간이 현재 시간을 지났다면{' '} + 빨간색으로 표시됩니다.

    - ( -
    -

    - { - isLoading ? '로딩중' : ( - placeReservations.length === 0 ? '대기중인 예약이 없습니다' : - `${placeReservations.length}건 대기중: ${new moment(firstPlaceReservation.date).format('YYYY-MM-DD')} ~ ${new moment(lastPlaceReservation.date).format('YYYY-MM-DD')}` - ) - } -

    - { - isLoading ?

    로딩 중...

    : ( - placeReservations.length ? - :

    대기 중인 장소 예약이 없습니다 🎈

    - ) - } -
    - ) - }, - { - menuItem: '장비 예약', render: () => ( -
    -

    - { - isLoading ? '로딩중' : ( - equipReservations.length === 0 ? '대기중인 예약이 없습니다' : - `${equipReservations.length}건 대기중: ${new moment(firstEquipReservation.date).format('YYYY-MM-DD')} ~ ${new moment(lastEquipReservation.date).format('YYYY-MM-DD')}` - ) - } -

    - { - isLoading ?

    로딩 중...

    : ( - equipReservations.length ? - :

    대기 중인 장비 예약이 없습니다 🎈

    - ) - } -
    - ) - } - ]}/> + ( +
    +

    + {isLoading + ? '로딩중' + : placeReservations.length === 0 + ? '대기중인 예약이 없습니다' + : `${placeReservations.length}건 대기중: ${new moment(firstPlaceReservation.date).format('YYYY-MM-DD')} ~ ${new moment(lastPlaceReservation.date).format('YYYY-MM-DD')}`} +

    + {isLoading ? ( +

    로딩 중...

    + ) : placeReservations.length ? ( + + ) : ( +

    대기 중인 장소 예약이 없습니다 🎈

    + )} +
    + ), + }, + { + menuItem: '장비 예약', + render: () => ( +
    +

    + {isLoading + ? '로딩중' + : equipReservations.length === 0 + ? '대기중인 예약이 없습니다' + : `${equipReservations.length}건 대기중: ${new moment(firstEquipReservation.date).format('YYYY-MM-DD')} ~ ${new moment(lastEquipReservation.date).format('YYYY-MM-DD')}`} +

    + {isLoading ? ( +

    로딩 중...

    + ) : equipReservations.length ? ( + + ) : ( +

    대기 중인 장비 예약이 없습니다 🎈

    + )} +
    + ), + }, + ]} + /> - ) -} + ); +}; -export default ReservationPage +export default ReservationPage; export async function getServerSideProps() { const res1 = await PoPoAxios.get('statistics/reservation/count'); const placeReservationCntStats = res1.data; - const { - totalReservationCnt, - todayReservationCnt, - thisWeekReservationCnt, - } = placeReservationCntStats; + const { totalReservationCnt, todayReservationCnt, thisWeekReservationCnt } = + placeReservationCntStats; - return { props: { - totalReservationCnt, - todayReservationCnt, - thisWeekReservationCnt, - } }; + return { + props: { + totalReservationCnt, + todayReservationCnt, + thisWeekReservationCnt, + }, + }; } diff --git a/pages/statistics/index.jsx b/pages/statistics/index.jsx index 9020334..0d10167 100644 --- a/pages/statistics/index.jsx +++ b/pages/statistics/index.jsx @@ -1,13 +1,19 @@ -import { useState } from "react"; +import { useState } from 'react'; import dynamic from 'next/dynamic'; -import { Dropdown, List } from "semantic-ui-react"; -import moment from 'moment' +import { Dropdown, List } from 'semantic-ui-react'; +import moment from 'moment'; -import LayoutWithAuth from '@/components/layout/layout.auth.with' +import LayoutWithAuth from '@/components/layout/layout.auth.with'; // https://github.com/plouc/nivo/issues/1941 -const NewUserBar = dynamic(() => import('../../components/statistics/new-user.bar'), { ssr: false }) -const NewReservationBar = dynamic(() => import('../../components/statistics/new-reservation.bar'), { ssr: false }) +const NewUserBar = dynamic( + () => import('../../components/statistics/new-user.bar'), + { ssr: false }, +); +const NewReservationBar = dynamic( + () => import('../../components/statistics/new-reservation.bar'), + { ssr: false }, +); const StatisticsPage = () => { const thisYear = moment().year(); @@ -16,19 +22,22 @@ const StatisticsPage = () => { const [year, setYear] = useState(thisYear); const YearOptions = Array.from( - {length: thisYear - popoStartYear + 1}, - (v, k) => { return { - key: k + popoStartYear, - text: `${k + popoStartYear}년`, - value: k + popoStartYear - } } + { length: thisYear - popoStartYear + 1 }, + (v, k) => { + return { + key: k + popoStartYear, + text: `${k + popoStartYear}년`, + value: k + popoStartYear, + }; + }, ); return (

    POPO 통계

    - We don't have better algorithms, we just have more data.
    + We don't have better algorithms, we just have more data. +
    데이터를 통해 POPO를 유연하게 관리하고 활용해봅시다!

    @@ -37,26 +46,26 @@ const StatisticsPage = () => { options={YearOptions} value={year} onChange={(_, { value }) => { - setYear(value) + setYear(value); }} />

    신규 유저

    - +
    -
    +

    신규 장소 예약

    - +
    -
    +

    ToDo List 🚀

    일일 활성 유저 (Daily Active User)
    - ) -} + ); +}; -export default StatisticsPage \ No newline at end of file +export default StatisticsPage; diff --git a/pages/user.jsx b/pages/user.jsx index e03ea5e..6c4ac92 100644 --- a/pages/user.jsx +++ b/pages/user.jsx @@ -1,87 +1,92 @@ -import { useEffect, useState } from 'react' -import { Button, Icon, Input, Pagination } from 'semantic-ui-react' +import { useEffect, useState } from 'react'; +import { Button, Icon, Input, Pagination } from 'semantic-ui-react'; -import LayoutWithAuth from '@/components/layout/layout.auth.with' -import UserTable from '@/components/user/user.table' -import UserCreateModal from '@/components/user/user.create.modal' +import LayoutWithAuth from '@/components/layout/layout.auth.with'; +import UserTable from '@/components/user/user.table'; +import UserCreateModal from '@/components/user/user.create.modal'; import { PoPoAxios } from '@/utils/axios.instance'; const UserPage = ({ totalUserCnt, - todayRegisterUserCnt, todayLoginUserCnt, - thisWeekRegisterUserCnt, thisWeekLoginUserCnt + todayRegisterUserCnt, + todayLoginUserCnt, + thisWeekRegisterUserCnt, + thisWeekLoginUserCnt, }) => { - const PAGE_SIZE = 10 + const PAGE_SIZE = 10; - const [keyword, setKeyword] = useState('') - const [page, setPage] = useState(1) + const [keyword, setKeyword] = useState(''); + const [page, setPage] = useState(1); - const [total_count, setTotalCount] = useState(0) - const [users, setUsers] = useState([]) + const [total_count, setTotalCount] = useState(0); + const [users, setUsers] = useState([]); useEffect(() => { const skip = PAGE_SIZE * (page - 1); - PoPoAxios.get( - `/search/user?q=${keyword}&take=${PAGE_SIZE}&skip=${skip}`, - { withCredentials: true }) - .then((res) => { - const ret = res.data; - setUsers(ret['users']) - setTotalCount(ret['count']) - }) - }, [keyword, page]) + PoPoAxios.get(`/search/user?q=${keyword}&take=${PAGE_SIZE}&skip=${skip}`, { + withCredentials: true, + }).then((res) => { + const ret = res.data; + setUsers(ret['users']); + setTotalCount(ret['count']); + }); + }, [keyword, page]); return (

    유저 관리

    - 유저 생성} - /> + 유저 생성} />
    } - style={{width: 300}} + icon={} + style={{ width: 300 }} placeholder={'찾으려는 유저를 검색하세요...'} - onChange={(_, {value}) => setKeyword(value)} + onChange={(_, { value }) => setKeyword(value)} />
    -
      +
      • 총 유저 수: {Number(totalUserCnt).toLocaleString()}명
      • -
      • 오늘 가입한 유저 수: {Number(todayRegisterUserCnt).toLocaleString()}명
      • -
      • 오늘 로그인한 유저 수: {Number(todayLoginUserCnt).toLocaleString()}명
      • -
      • 이번 주 가입한 유저 수: {Number(thisWeekRegisterUserCnt).toLocaleString()}명
      • -
      • 이번 주 로그인한 유저 수: {Number(thisWeekLoginUserCnt).toLocaleString()}명
      • +
      • + 오늘 가입한 유저 수: {Number(todayRegisterUserCnt).toLocaleString()}명 +
      • +
      • + 오늘 로그인한 유저 수: {Number(todayLoginUserCnt).toLocaleString()}명 +
      • +
      • + 이번 주 가입한 유저 수:{' '} + {Number(thisWeekRegisterUserCnt).toLocaleString()}명 +
      • +
      • + 이번 주 로그인한 유저 수:{' '} + {Number(thisWeekLoginUserCnt).toLocaleString()}명 +
      -

      - 유저는 마지막 로그인 순으로 정렬되어 표시됩니다. -

      +

      유저는 마지막 로그인 순으로 정렬되어 표시됩니다.

      - +
      setPage(activePage)} + prevItem={null} + nextItem={null} + onPageChange={(_, { activePage }) => setPage(activePage)} />
      - ) -} + ); +}; -export default UserPage +export default UserPage; export async function getServerSideProps() { const res = await PoPoAxios.get('statistics/user/count'); @@ -89,13 +94,19 @@ export async function getServerSideProps() { const { totalUserCnt, - todayRegisterUserCnt, todayLoginUserCnt, - thisWeekRegisterUserCnt, thisWeekLoginUserCnt + todayRegisterUserCnt, + todayLoginUserCnt, + thisWeekRegisterUserCnt, + thisWeekLoginUserCnt, } = userCntStats; - return { props: { - totalUserCnt, - todayRegisterUserCnt, todayLoginUserCnt, - thisWeekRegisterUserCnt, thisWeekLoginUserCnt - } }; + return { + props: { + totalUserCnt, + todayRegisterUserCnt, + todayLoginUserCnt, + thisWeekRegisterUserCnt, + thisWeekLoginUserCnt, + }, + }; } diff --git a/styles/globals.css b/styles/globals.css index d7d439c..f2e2aaa 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -1,12 +1,16 @@ @import url(//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSansNeo.css); -* { font-family: 'Spoqa Han Sans Neo', 'sans-serif'; } +* { + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; +} html, body { padding: 0; margin: 0; - font-family: Spoqa Han Sans Neo, sans-serif + font-family: + Spoqa Han Sans Neo, + sans-serif; } a { diff --git a/styles/theme.js b/styles/theme.js index 4f38965..909e4c9 100644 --- a/styles/theme.js +++ b/styles/theme.js @@ -3,7 +3,7 @@ * Used in src/components/layout.jsx */ - const theme = { +const theme = { background: { default: '#ffffffff', sub: '#f5f5f5ff', @@ -24,4 +24,4 @@ contentWidth: '80rem', }; -export default theme; +export default theme; diff --git a/utils/axios.instance.js b/utils/axios.instance.js index 5593cd5..d9ebc5c 100644 --- a/utils/axios.instance.js +++ b/utils/axios.instance.js @@ -1,18 +1,18 @@ -import axios from "axios"; +import axios from 'axios'; const next_env = process.env.NEXT_PUBLIC_ENV; export let popoApiUrl = - next_env === "prod" - ? "https://api.popo.poapper.club" - : "https://api.popo-dev.poapper.club"; - // : "http://localhost:4000"; + next_env === 'prod' + ? 'https://api.popo.poapper.club' + : 'https://api.popo-dev.poapper.club'; +// : "http://localhost:4000"; export const PoPoAxios = axios.create({ baseURL: popoApiUrl, }); -export const PopoCdnUrl = "https://cdn.popo.poapper.club"; +export const PopoCdnUrl = 'https://cdn.popo.poapper.club'; export const PopoCdnAxios = axios.create({ baseURL: PopoCdnUrl, diff --git a/utils/file-upload.js b/utils/file-upload.js index d399260..2b8dfdb 100644 --- a/utils/file-upload.js +++ b/utils/file-upload.js @@ -1,21 +1,21 @@ -import { PoPoAxios } from "./axios.instance"; +import { PoPoAxios } from './axios.instance'; export function ImageUpload(uri, image_file) { let formData = new FormData(); - formData.append("image", image_file); + formData.append('image', image_file); return PoPoAxios.post(uri, formData, { withCredentials: true, - headers: { "Content-Type": "multipart/form-data" }, + headers: { 'Content-Type': 'multipart/form-data' }, }); } export function CsvUpload(uri, csv_file) { let formData = new FormData(); - formData.append("csv_file", csv_file); + formData.append('csv_file', csv_file); return PoPoAxios.post(uri, formData, { withCredentials: true, - headers: { "Content-Type": "multipart/form-data" }, + headers: { 'Content-Type': 'multipart/form-data' }, }); } diff --git a/utils/opening_hours.js b/utils/opening_hours.js index 81da363..5abc023 100644 --- a/utils/opening_hours.js +++ b/utils/opening_hours.js @@ -1,15 +1,15 @@ export const KoreanWeekday = { - 'Monday': '월', - 'Tuesday': '화', - 'Wednesday': '수', - 'Thursday': '목', - 'Friday': '금', - 'Saturday': '토', - 'Sunday': '일', - 'Everyday': '매일', -} + Monday: '월', + Tuesday: '화', + Wednesday: '수', + Thursday: '목', + Friday: '금', + Saturday: '토', + Sunday: '일', + Everyday: '매일', +}; -export function isOnOpeningHours ( +export function isOnOpeningHours( opening_hours, weekday, // Monday start_time, // hh:mm @@ -27,12 +27,11 @@ export function isOnOpeningHours ( const open_end = hour.split('-')[1]; // 하나라도 range 내부에 포함된다면 예약 가능 - const isInside = - (open_start <= start_time && end_time <= open_end); + const isInside = open_start <= start_time && end_time <= open_end; if (isInside) { return true; } } return false; -} \ No newline at end of file +} diff --git a/utils/time-date.js b/utils/time-date.js index 9574272..26c82ea 100644 --- a/utils/time-date.js +++ b/utils/time-date.js @@ -1,41 +1,35 @@ -import moment from "moment"; +import moment from 'moment'; // dt: YYYMMDD export function convertDate(dt) { - return moment(dt, "YYYYMMDD").format("YYYY년 MM월 DD일") + return moment(dt, 'YYYYMMDD').format('YYYY년 MM월 DD일'); } // time: HHmm export function convertTime(time) { - return moment(time, "HHmm").format('HH:mm'); + return moment(time, 'HHmm').format('HH:mm'); } -export function hourDiff( - startTime, - endTime -) { - const startMoment = moment(startTime, "HHmm"); - const endMoment = moment(endTime, "HHmm"); +export function hourDiff(startTime, endTime) { + const startMoment = moment(startTime, 'HHmm'); + const endMoment = moment(endTime, 'HHmm'); const duration = moment.duration(endMoment.diff(startMoment)); return duration.asHours(); } -export function roundUpByDuration( - date, - durationMinutes = 30 -) { +export function roundUpByDuration(date, durationMinutes = 30) { const remainder = durationMinutes - (date.minute() % durationMinutes); - return moment(date).add(remainder, "minutes").second(0) + return moment(date).add(remainder, 'minutes').second(0); } export function convertStatus(status) { switch (status) { case '통과': - return 'green' + return 'green'; case '거절': - return 'red' + return 'red'; default: - return 'black' + return 'black'; } }