From 84c51c5868e44c4b317d7242873c5ccf7ede4c2f Mon Sep 17 00:00:00 2001 From: se030 Date: Thu, 5 Jan 2023 00:29:22 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=ED=9A=8C=EC=9D=98=EB=A1=9D=20id=20url=20params=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/MomList.tsx | 4 ++++ client/src/pages/Workspace/index.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index df718bef..46977299 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -2,6 +2,7 @@ import { RiFileAddLine } from '@react-icons/all-files/ri/RiFileAddLine'; import * as MomMessage from '@wabinar/api-types/mom'; import { MOM_EVENT } from '@wabinar/constants/socket-message'; import { memo, useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import useSocketContext from 'src/hooks/context/useSocketContext'; import { TMom } from 'src/types/mom'; @@ -18,6 +19,8 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { const { momSocket: socket } = useSocketContext(); const [momList, setMomList] = useState(moms); + const navigate = useNavigate(); + const onCreateMom = () => { socket.emit(MOM_EVENT.CREATE); }; @@ -44,6 +47,7 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { ); socket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { + navigate(mom._id); setSelectedMom(mom); }); diff --git a/client/src/pages/Workspace/index.tsx b/client/src/pages/Workspace/index.tsx index 15e3b1b4..1856d81b 100644 --- a/client/src/pages/Workspace/index.tsx +++ b/client/src/pages/Workspace/index.tsx @@ -58,7 +58,7 @@ function WorkspacePage() { }> } /> - } /> + } /> ) : ( From c92fb51e854407e5597ae34cd63ed83775011839 Mon Sep 17 00:00:00 2001 From: se030 Date: Sun, 28 May 2023 22:00:30 +0900 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20URL=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=ED=9A=8C=EC=9D=98=EB=A1=9D=20=EC=84=A0=ED=83=9D=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/App.tsx | 4 ++-- client/src/components/Sidebar/MomList.tsx | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 706528cc..0ae8a3d8 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -16,7 +16,7 @@ function App() { const [user, setUser] = useState(null); const [isLoaded, setIsLoaded] = useState(false); - const location = useLocation(); + const { pathname } = useLocation(); const navigate = useNavigate(); const autoLogin = async () => { @@ -25,7 +25,7 @@ function App() { setIsLoaded(true); setUser(user); - if (user && !/^\/workspace(\/\d+)?$/.test(location.pathname)) { + if (user && !/^\/workspace(\/\d+(\/.+)?)?$/.test(pathname)) { navigate('/workspace'); } }; diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index 46977299..381da868 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -2,7 +2,7 @@ import { RiFileAddLine } from '@react-icons/all-files/ri/RiFileAddLine'; import * as MomMessage from '@wabinar/api-types/mom'; import { MOM_EVENT } from '@wabinar/constants/socket-message'; import { memo, useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import useSocketContext from 'src/hooks/context/useSocketContext'; import { TMom } from 'src/types/mom'; @@ -20,6 +20,7 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { const [momList, setMomList] = useState(moms); const navigate = useNavigate(); + const { pathname } = useLocation(); const onCreateMom = () => { socket.emit(MOM_EVENT.CREATE); @@ -32,7 +33,10 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { useEffect(() => { if (moms.length) { - const message: MomMessage.Select = { id: moms[0]._id }; + const momId = + pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId ?? + moms[0]._id; + const message: MomMessage.Select = { id: momId }; socket.emit(MOM_EVENT.SELECT, message); } From e093b3a6e98f258d62b15db3a5f42ae91aee65c1 Mon Sep 17 00:00:00 2001 From: se030 Date: Tue, 30 May 2023 19:26:01 +0900 Subject: [PATCH 03/18] =?UTF-8?q?refactor:=20navigation,=20=ED=9A=8C?= =?UTF-8?q?=EC=9D=98=EB=A1=9D=20=EC=83=81=ED=83=9C=20=EB=B0=8F=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/MomList.tsx | 44 +++++------------- client/src/components/Sidebar/index.tsx | 9 +--- client/src/components/Workspace/index.tsx | 56 +++++++++++++++++++++-- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index 381da868..a8e2f1a4 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -2,65 +2,43 @@ import { RiFileAddLine } from '@react-icons/all-files/ri/RiFileAddLine'; import * as MomMessage from '@wabinar/api-types/mom'; import { MOM_EVENT } from '@wabinar/constants/socket-message'; import { memo, useEffect, useState } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; +import ee from 'src/components/Mom/EventEmitter'; +import useSelectedMomContext from 'src/hooks/context/useSelectedMomContext'; import useSocketContext from 'src/hooks/context/useSocketContext'; import { TMom } from 'src/types/mom'; -import ee from '../Mom/EventEmitter'; import style from './style.module.scss'; interface MomListProps { moms: TMom[]; - selectedMom: TMom | null; - setSelectedMom: React.Dispatch>; } -function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { +function MomList({ moms }: MomListProps) { + const { selectedMom } = useSelectedMomContext(); + const { momSocket: socket } = useSocketContext(); const [momList, setMomList] = useState(moms); const navigate = useNavigate(); - const { pathname } = useLocation(); const onCreateMom = () => { socket.emit(MOM_EVENT.CREATE); }; - const onSelect = (id: string) => { - const message: MomMessage.Select = { id }; - socket.emit(MOM_EVENT.SELECT, message); - }; - useEffect(() => { - if (moms.length) { - const momId = - pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId ?? - moms[0]._id; - const message: MomMessage.Select = { id: momId }; - socket.emit(MOM_EVENT.SELECT, message); - } - setMomList(moms); + }, [moms]); - ee.on(MOM_EVENT.REQUEST_LOADED, () => { - ee.emit(MOM_EVENT.LOADED, moms ? moms.length : 0); - }); - + useEffect(() => { socket.on(MOM_EVENT.CREATE, ({ mom }: MomMessage.Created) => setMomList((prev) => [...prev, mom]), ); - socket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { - navigate(mom._id); - setSelectedMom(mom); - }); - return () => { socket.off(MOM_EVENT.CREATE); - socket.off(MOM_EVENT.SELECT); - ee.off(MOM_EVENT.REQUEST_LOADED); }; - }, [moms]); + }, [socket]); useEffect(() => { ee.on(MOM_EVENT.UPDATE_TITLE, (title) => { @@ -79,7 +57,7 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) { return () => { ee.off(MOM_EVENT.UPDATE_TITLE); }; - }, []); + }, [selectedMom]); return (
@@ -97,7 +75,7 @@ function MomList({ moms, selectedMom, setSelectedMom }: MomListProps) {
    {momList.map(({ _id: id, title }) => ( -
  • onSelect(id)} role="button"> +
  • navigate(id)} role="button"> {title}
  • ))} diff --git a/client/src/components/Sidebar/index.tsx b/client/src/components/Sidebar/index.tsx index 4ea139c6..b6535d7a 100644 --- a/client/src/components/Sidebar/index.tsx +++ b/client/src/components/Sidebar/index.tsx @@ -1,4 +1,3 @@ -import useSelectedMomContext from 'src/hooks/context/useSelectedMomContext'; import { WorkspaceInfo } from 'src/types/workspace'; import Header from './Header'; @@ -12,18 +11,12 @@ interface SidebarProps { } function Sidebar({ workspace }: SidebarProps) { - const { selectedMom, setSelectedMom } = useSelectedMomContext(); - return (
    - +
    diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 8c4df93b..058cf990 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -1,10 +1,12 @@ -import { WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; +import * as MomMessage from '@wabinar/api-types/mom'; +import { MOM_EVENT, WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; import Mom from 'components/Mom'; import Sidebar from 'components/Sidebar'; import { useEffect, useMemo, useState } from 'react'; -import { useParams } from 'react-router-dom'; +import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { getWorkspaceInfo } from 'src/apis/workspace'; import MeetingMediaBar from 'src/components/MeetingMediaBar'; +import ee from 'src/components/Mom/EventEmitter'; import MeetingContext from 'src/contexts/meeting'; import { SelectedMomContext } from 'src/contexts/selected-mom'; import { SocketContext } from 'src/contexts/socket'; @@ -14,10 +16,12 @@ import { WorkspaceInfo } from 'src/types/workspace'; function Workspace() { const { id } = useParams(); - const [isOnGoing, setIsOnGoing] = useState(false); + const navigate = useNavigate(); + const { pathname } = useLocation(); const [workspace, setWorkspace] = useState(null); const [selectedMom, setSelectedMom] = useState(null); + const [isOnGoing, setIsOnGoing] = useState(false); const momSocket = useSocket(`/workspace-mom/${id}`); const workspaceSocket = useSocket(`/workspace/${id}`); @@ -28,7 +32,9 @@ function Workspace() { setWorkspace(workspaceInfo); - if (!workspaceInfo.moms[0]) setSelectedMom(null); + if (!workspaceInfo.moms.length) { + setSelectedMom(null); + } } }; @@ -37,6 +43,44 @@ function Workspace() { setIsOnGoing(false); }, [id]); + useEffect(() => { + if (!momSocket) return; + + momSocket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { + setSelectedMom(mom); + }); + + return () => { + momSocket.off(MOM_EVENT.SELECT); + }; + }, [momSocket]); + + useEffect(() => { + if (!workspace || !momSocket) return; + + const { moms } = workspace; + + if (moms.length && !getCurrentMom(pathname)) { + navigate(moms[0]._id); + } + + ee.on(MOM_EVENT.REQUEST_LOADED, () => { + ee.emit(MOM_EVENT.LOADED, moms ? moms.length : 0); + }); + + return () => { + ee.off(MOM_EVENT.REQUEST_LOADED); + }; + }, [workspace?.moms, momSocket]); + + useEffect(() => { + const momId = getCurrentMom(pathname); + if (!momSocket || !momId) return; + + const message: MomMessage.Select = { id: momId }; + momSocket.emit(MOM_EVENT.SELECT, message); + }, [pathname, momSocket]); + useEffect(() => { if (!workspaceSocket) { return; @@ -83,3 +127,7 @@ function Workspace() { } export default Workspace; + +const getCurrentMom = (pathname: string) => { + return pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId; +}; From 6dc17bf6d46ef6ec9d7c93b6bf542f7c444945f1 Mon Sep 17 00:00:00 2001 From: se030 Date: Wed, 31 May 2023 12:34:56 +0900 Subject: [PATCH 04/18] =?UTF-8?q?chore:=20recoil=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + client/src/main.tsx | 13 +-- package-lock.json | 214 ++++++++++++++++++++++++++++++++------------ 3 files changed, 164 insertions(+), 64 deletions(-) diff --git a/client/package.json b/client/package.json index 442a67e8..82fcc73c 100644 --- a/client/package.json +++ b/client/package.json @@ -20,6 +20,7 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", + "recoil": "^0.7.7", "socket.io-client": "^4.5.4", "uuid": "^9.0.0" }, diff --git a/client/src/main.tsx b/client/src/main.tsx index fda074a0..a4564c60 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -1,13 +1,16 @@ import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; - +import { RecoilRoot } from 'recoil'; import 'react-toastify/dist/ReactToastify.css'; + import App from './App'; import Toaster from './components/common/Toaster'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - - , + + + + + + , ); diff --git a/package-lock.json b/package-lock.json index 2ae803a9..846282c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,6 +71,7 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", + "recoil": "^0.7.7", "socket.io-client": "^4.5.4", "uuid": "^9.0.0" }, @@ -1882,6 +1883,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "android" @@ -1897,6 +1899,7 @@ "cpu": [ "loong64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3882,7 +3885,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "devOptional": true, + "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4236,7 +4239,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } @@ -4308,7 +4311,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -4558,7 +4561,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "devOptional": true, + "dev": true, "funding": [ { "type": "individual", @@ -4585,7 +4588,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -5631,6 +5634,7 @@ "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", + "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -5670,6 +5674,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "android" @@ -5685,6 +5690,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "android" @@ -5700,6 +5706,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5715,6 +5722,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -5730,6 +5738,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -5745,6 +5754,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -5760,6 +5770,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5775,6 +5786,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5790,6 +5802,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5805,6 +5818,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5820,6 +5834,7 @@ "cpu": [ "mips64el" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5835,6 +5850,7 @@ "cpu": [ "ppc64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5850,6 +5866,7 @@ "cpu": [ "riscv64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5865,6 +5882,7 @@ "cpu": [ "s390x" ], + "dev": true, "optional": true, "os": [ "linux" @@ -5880,6 +5898,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "netbsd" @@ -5895,6 +5914,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "openbsd" @@ -5910,6 +5930,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "sunos" @@ -5925,6 +5946,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5940,6 +5962,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -5955,6 +5978,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -6867,7 +6891,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7028,6 +7052,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -7298,6 +7323,11 @@ "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", "dev": true }, + "node_modules/hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -7549,7 +7579,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "devOptional": true + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -7814,7 +7844,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -7854,6 +7884,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -7895,7 +7926,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -7925,7 +7956,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -7967,7 +7998,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.12.0" } @@ -10456,6 +10487,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -10591,7 +10623,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -11121,7 +11153,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -11140,7 +11173,8 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -11242,6 +11276,7 @@ "version": "8.4.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -11780,7 +11815,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -11788,6 +11823,25 @@ "node": ">=8.10.0" } }, + "node_modules/recoil": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz", + "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==", + "dependencies": { + "hamt_plus": "1.0.2" + }, + "peerDependencies": { + "react": ">=16.13.1" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/recrawl-sync": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recrawl-sync/-/recrawl-sync-2.2.3.tgz", @@ -12009,6 +12063,7 @@ "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -12114,7 +12169,7 @@ "version": "1.56.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", - "devOptional": true, + "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -12383,6 +12438,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -13035,6 +13091,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -13308,7 +13365,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -13696,6 +13753,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.3.tgz", "integrity": "sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==", + "dev": true, "dependencies": { "esbuild": "^0.15.9", "postcss": "^8.4.18", @@ -13807,6 +13865,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -15701,8 +15760,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", - "dev": true, - "requires": {} + "dev": true }, "@cush/relative": { "version": "1.0.0", @@ -15737,12 +15795,14 @@ "version": "0.15.13", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", + "dev": true, "optional": true }, "@esbuild/linux-loong64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", + "dev": true, "optional": true }, "@eslint/eslintrc": { @@ -16635,8 +16695,7 @@ "@react-icons/all-files": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@react-icons/all-files/-/all-files-4.1.0.tgz", - "integrity": "sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==", - "requires": {} + "integrity": "sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==" }, "@remix-run/router": { "version": "1.0.3", @@ -17222,8 +17281,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "8.2.0", @@ -17290,7 +17348,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "devOptional": true, + "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -17553,7 +17611,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true + "dev": true }, "bl": { "version": "4.1.0", @@ -17620,7 +17678,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -17784,7 +17842,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "devOptional": true, + "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -17800,7 +17858,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -17936,6 +17994,7 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", + "recoil": "^0.7.7", "sass": "^1.56.1", "socket.io-client": "^4.5.4", "stylelint": "^14.15.0", @@ -18637,6 +18696,7 @@ "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", + "dev": true, "requires": { "@esbuild/android-arm": "0.15.13", "@esbuild/linux-loong64": "0.15.13", @@ -18666,120 +18726,140 @@ "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", + "dev": true, "optional": true }, "esbuild-android-arm64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", + "dev": true, "optional": true }, "esbuild-darwin-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", + "dev": true, "optional": true }, "esbuild-darwin-arm64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", + "dev": true, "optional": true }, "esbuild-freebsd-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", + "dev": true, "optional": true }, "esbuild-freebsd-arm64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", + "dev": true, "optional": true }, "esbuild-linux-32": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", + "dev": true, "optional": true }, "esbuild-linux-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", + "dev": true, "optional": true }, "esbuild-linux-arm": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", + "dev": true, "optional": true }, "esbuild-linux-arm64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", + "dev": true, "optional": true }, "esbuild-linux-mips64le": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", + "dev": true, "optional": true }, "esbuild-linux-ppc64le": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", + "dev": true, "optional": true }, "esbuild-linux-riscv64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", + "dev": true, "optional": true }, "esbuild-linux-s390x": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", + "dev": true, "optional": true }, "esbuild-netbsd-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", + "dev": true, "optional": true }, "esbuild-openbsd-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", + "dev": true, "optional": true }, "esbuild-sunos-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", + "dev": true, "optional": true }, "esbuild-windows-32": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", + "dev": true, "optional": true }, "esbuild-windows-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", + "dev": true, "optional": true }, "esbuild-windows-arm64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", + "dev": true, "optional": true }, "escalade": { @@ -18911,8 +18991,7 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.6", @@ -19481,7 +19560,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -19603,6 +19682,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "optional": true }, "function-bind": { @@ -19802,6 +19882,11 @@ "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", "dev": true }, + "hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -19971,7 +20056,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "devOptional": true + "dev": true }, "import-fresh": { "version": "3.3.0", @@ -20172,7 +20257,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "dev": true, "requires": { "binary-extensions": "^2.0.0" } @@ -20197,6 +20282,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, "requires": { "has": "^1.0.3" } @@ -20220,7 +20306,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true + "dev": true }, "is-fullwidth-code-point": { "version": "4.0.0", @@ -20238,7 +20324,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -20265,7 +20351,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true + "dev": true }, "is-number-object": { "version": "1.0.7", @@ -20941,8 +21027,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "29.2.0", @@ -22099,7 +22184,8 @@ "nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true }, "natural-compare": { "version": "1.4.0", @@ -22209,7 +22295,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true + "dev": true }, "npm-run-path": { "version": "5.1.0", @@ -22577,7 +22663,8 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "path-to-regexp": { "version": "0.1.7", @@ -22593,7 +22680,8 @@ "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "picomatch": { "version": "2.3.1", @@ -22664,6 +22752,7 @@ "version": "8.4.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "dev": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -22686,15 +22775,13 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-scss": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.5.tgz", "integrity": "sha512-F7xpB6TrXyqUh3GKdyB4Gkp3QL3DDW1+uI+gxx/oJnUt/qXI4trj5OGlp9rOKdoABGULuqtqeG+3HEVQk4DjmA==", - "dev": true, - "requires": {} + "dev": true }, "postcss-selector-parser": { "version": "6.0.10", @@ -23038,11 +23125,19 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "requires": { "picomatch": "^2.2.1" } }, + "recoil": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz", + "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==", + "requires": { + "hamt_plus": "1.0.2" + } + }, "recrawl-sync": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recrawl-sync/-/recrawl-sync-2.2.3.tgz", @@ -23209,6 +23304,7 @@ "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, "requires": { "fsevents": "~2.3.2" } @@ -23271,7 +23367,7 @@ "version": "1.56.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", - "devOptional": true, + "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -23511,7 +23607,8 @@ "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true }, "source-map-support": { "version": "0.5.13", @@ -23876,8 +23973,7 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.4.tgz", "integrity": "sha512-38nIGTGpFOiK5LjJ8Ma1yUgpKENxoKSOhbDNSemY7Ep0VsJoXIW9Iq/2hSt699oB9tReynfWicTAoIHiq8Rvbg==", - "dev": true, - "requires": {} + "dev": true }, "stylelint-config-prettier-scss": { "version": "0.0.1", @@ -23902,8 +23998,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", - "dev": true, - "requires": {} + "dev": true }, "stylelint-config-recommended-scss": { "version": "8.0.0", @@ -23930,8 +24025,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-7.0.1.tgz", "integrity": "sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -24005,7 +24099,8 @@ "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", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true }, "svg-tags": { "version": "1.0.0", @@ -24220,7 +24315,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -24475,6 +24570,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.3.tgz", "integrity": "sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==", + "dev": true, "requires": { "esbuild": "^0.15.9", "fsevents": "~2.3.2", @@ -24487,6 +24583,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, "requires": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -24750,8 +24847,7 @@ "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "requires": {} + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" }, "xmlhttprequest-ssl": { "version": "2.0.0", From 7e4ffc7f5a411b19cca44fce0ceebad23335a47f Mon Sep 17 00:00:00 2001 From: se030 Date: Wed, 31 May 2023 12:42:10 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20Mom=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=B0=8F=20DefaultMom=20=EB=A0=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81=20=EB=A1=9C=EC=A7=81=EC=9D=98=20workspace.mo?= =?UTF-8?q?ms=EC=97=90=20recoil=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Mom/index.tsx | 24 ++++++----------------- client/src/components/Workspace/index.tsx | 21 ++++++-------------- client/src/store/atom/workspace.ts | 7 +++++++ 3 files changed, 19 insertions(+), 33 deletions(-) create mode 100644 client/src/store/atom/workspace.ts diff --git a/client/src/components/Mom/index.tsx b/client/src/components/Mom/index.tsx index e3618303..92d20b37 100644 --- a/client/src/components/Mom/index.tsx +++ b/client/src/components/Mom/index.tsx @@ -3,10 +3,12 @@ import * as MomMessage from '@wabinar/api-types/mom'; import { BLOCK_EVENT, MOM_EVENT } from '@wabinar/constants/socket-message'; import Block from 'components/Block'; import { useEffect, useRef, useState } from 'react'; +import { useRecoilState } from 'recoil'; import useSelectedMomContext from 'src/hooks/context/useSelectedMomContext'; import useSocketContext from 'src/hooks/context/useSocketContext'; import { useCRDT } from 'src/hooks/useCRDT'; import useDebounce from 'src/hooks/useDebounce'; +import { workspaceState } from 'src/store/atom/workspace'; import { v4 as uuid } from 'uuid'; import DefaultMom from './DefaultMom'; @@ -14,6 +16,7 @@ import ee from './EventEmitter'; import style from './style.module.scss'; function Mom() { + const [workspace] = useRecoilState(workspaceState); const { selectedMom } = useSelectedMomContext(); const { momSocket: socket } = useSocketContext(); @@ -37,8 +40,6 @@ function Mom() { const focusIndex = useRef(); const [blocks, setBlocks] = useState([]); - const [isLoaded, setIsLoaded] = useState(false); - const [isMomsEmpty, setIsMomsEmpty] = useState(false); const onTitleUpdate: React.FormEventHandler = useDebounce( () => { @@ -230,20 +231,7 @@ function Mom() { BLOCK_EVENT.UPDATE_TYPE, ].forEach((event) => socket.off(event)); }; - }, [selectedMom]); - - useEffect(() => { - ee.on(MOM_EVENT.LOADED, (momsLength: number) => { - setIsLoaded(true); - setIsMomsEmpty(momsLength === 0); - }); - - ee.emit(MOM_EVENT.REQUEST_LOADED); - - return () => { - ee.off(MOM_EVENT.LOADED); - }; - }, [socket]); + }, [selectedMom, socket]); const registerRef = (index: number) => (ref: React.RefObject) => { @@ -251,11 +239,11 @@ function Mom() { setBlockFocus(index); }; - if (!isLoaded) { + if (!workspace) { return
    ; } - if (isMomsEmpty && !selectedMom) { + if (!workspace.moms.length) { return ; } diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 058cf990..79344160 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -4,22 +4,22 @@ import Mom from 'components/Mom'; import Sidebar from 'components/Sidebar'; import { useEffect, useMemo, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { useRecoilState } from 'recoil'; import { getWorkspaceInfo } from 'src/apis/workspace'; import MeetingMediaBar from 'src/components/MeetingMediaBar'; -import ee from 'src/components/Mom/EventEmitter'; import MeetingContext from 'src/contexts/meeting'; import { SelectedMomContext } from 'src/contexts/selected-mom'; import { SocketContext } from 'src/contexts/socket'; import useSocket from 'src/hooks/useSocket'; +import { workspaceState } from 'src/store/atom/workspace'; import { TMom } from 'src/types/mom'; -import { WorkspaceInfo } from 'src/types/workspace'; function Workspace() { const { id } = useParams(); const navigate = useNavigate(); const { pathname } = useLocation(); - const [workspace, setWorkspace] = useState(null); + const [workspace, setWorkspace] = useRecoilState(workspaceState); const [selectedMom, setSelectedMom] = useState(null); const [isOnGoing, setIsOnGoing] = useState(false); @@ -56,22 +56,13 @@ function Workspace() { }, [momSocket]); useEffect(() => { - if (!workspace || !momSocket) return; - + if (!workspace) return; const { moms } = workspace; - if (moms.length && !getCurrentMom(pathname)) { + if (!getCurrentMom(pathname) && moms.length) { navigate(moms[0]._id); } - - ee.on(MOM_EVENT.REQUEST_LOADED, () => { - ee.emit(MOM_EVENT.LOADED, moms ? moms.length : 0); - }); - - return () => { - ee.off(MOM_EVENT.REQUEST_LOADED); - }; - }, [workspace?.moms, momSocket]); + }, [workspace]); useEffect(() => { const momId = getCurrentMom(pathname); diff --git a/client/src/store/atom/workspace.ts b/client/src/store/atom/workspace.ts new file mode 100644 index 00000000..77d762f7 --- /dev/null +++ b/client/src/store/atom/workspace.ts @@ -0,0 +1,7 @@ +import { atom } from 'recoil'; +import { WorkspaceInfo } from 'src/types/workspace'; + +export const workspaceState = atom({ + key: 'workspace', + default: null, +}); From 3fdc7da39cad50fde3c0f514dc5d0308bcd5b514 Mon Sep 17 00:00:00 2001 From: se030 Date: Wed, 31 May 2023 12:59:17 +0900 Subject: [PATCH 06/18] =?UTF-8?q?docs:=20=ED=9A=8C=EC=9D=98=EB=A1=9D=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=EC=97=90=20=EB=94=B0=EB=A5=B8=20URL=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20SELECT=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=9D=90=EB=A6=84=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Workspace/index.tsx | 26 ++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 79344160..889d58b8 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -43,18 +43,6 @@ function Workspace() { setIsOnGoing(false); }, [id]); - useEffect(() => { - if (!momSocket) return; - - momSocket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { - setSelectedMom(mom); - }); - - return () => { - momSocket.off(MOM_EVENT.SELECT); - }; - }, [momSocket]); - useEffect(() => { if (!workspace) return; const { moms } = workspace; @@ -64,6 +52,7 @@ function Workspace() { } }, [workspace]); + // 선택된 회의록이 변경되면 서버에 emit SELECT useEffect(() => { const momId = getCurrentMom(pathname); if (!momSocket || !momId) return; @@ -72,6 +61,19 @@ function Workspace() { momSocket.emit(MOM_EVENT.SELECT, message); }, [pathname, momSocket]); + // on SELECT 통해 전달된 회의록 정보 selectedMom 상태에 반영 + useEffect(() => { + if (!momSocket) return; + + momSocket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { + setSelectedMom(mom); + }); + + return () => { + momSocket.off(MOM_EVENT.SELECT); + }; + }, [momSocket]); + useEffect(() => { if (!workspaceSocket) { return; From 0a269f090f9f793b595a31c069e54627c169f478 Mon Sep 17 00:00:00 2001 From: se030 Date: Sun, 4 Jun 2023 14:52:07 +0900 Subject: [PATCH 07/18] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9D=98=EB=A1=9D?= =?UTF-8?q?=20=EC=84=A0=ED=83=9D=20=EB=A1=9C=EC=A7=81=20MomList=EB=A1=9C?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/MomList.tsx | 17 +++++++++-- client/src/components/Workspace/index.tsx | 35 ++++++----------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index a8e2f1a4..10e3a0b4 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -15,7 +15,7 @@ interface MomListProps { } function MomList({ moms }: MomListProps) { - const { selectedMom } = useSelectedMomContext(); + const { selectedMom, setSelectedMom } = useSelectedMomContext(); const { momSocket: socket } = useSocketContext(); const [momList, setMomList] = useState(moms); @@ -26,16 +26,29 @@ function MomList({ moms }: MomListProps) { socket.emit(MOM_EVENT.CREATE); }; + const onSelect = (id: string) => { + const message: MomMessage.Select = { id }; + socket.emit(MOM_EVENT.SELECT, message); + + navigate(id); + setSelectedMom(null); + }; + useEffect(() => { setMomList(moms); }, [moms]); useEffect(() => { + socket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { + setSelectedMom(mom); + }); + socket.on(MOM_EVENT.CREATE, ({ mom }: MomMessage.Created) => setMomList((prev) => [...prev, mom]), ); return () => { + socket.off(MOM_EVENT.SELECT); socket.off(MOM_EVENT.CREATE); }; }, [socket]); @@ -75,7 +88,7 @@ function MomList({ moms }: MomListProps) {
      {momList.map(({ _id: id, title }) => ( -
    • navigate(id)} role="button"> +
    • onSelect(id)} role="button"> {title}
    • ))} diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 889d58b8..4c0f821d 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -17,7 +17,9 @@ import { TMom } from 'src/types/mom'; function Workspace() { const { id } = useParams(); const navigate = useNavigate(); + const { pathname } = useLocation(); + const momId = pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId; const [workspace, setWorkspace] = useRecoilState(workspaceState); const [selectedMom, setSelectedMom] = useState(null); @@ -47,32 +49,17 @@ function Workspace() { if (!workspace) return; const { moms } = workspace; - if (!getCurrentMom(pathname) && moms.length) { + if (!momId && moms.length) { navigate(moms[0]._id); } - }, [workspace]); - - // 선택된 회의록이 변경되면 서버에 emit SELECT - useEffect(() => { - const momId = getCurrentMom(pathname); - if (!momSocket || !momId) return; + }, [workspace, momId]); - const message: MomMessage.Select = { id: momId }; - momSocket.emit(MOM_EVENT.SELECT, message); - }, [pathname, momSocket]); - - // on SELECT 통해 전달된 회의록 정보 selectedMom 상태에 반영 useEffect(() => { - if (!momSocket) return; - - momSocket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { - setSelectedMom(mom); - }); - - return () => { - momSocket.off(MOM_EVENT.SELECT); - }; - }, [momSocket]); + if (momId && !selectedMom && momSocket) { + const message: MomMessage.Select = { id: momId }; + momSocket.emit(MOM_EVENT.SELECT, message); + } + }, [momId, selectedMom, momSocket]); useEffect(() => { if (!workspaceSocket) { @@ -120,7 +107,3 @@ function Workspace() { } export default Workspace; - -const getCurrentMom = (pathname: string) => { - return pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId; -}; From 94c03b61857df3149fda0a1a0be0d963313d8948 Mon Sep 17 00:00:00 2001 From: se030 Date: Sun, 4 Jun 2023 15:21:46 +0900 Subject: [PATCH 08/18] =?UTF-8?q?del:=20=EC=A4=91=EB=B3=B5=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Workspace/index.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 4c0f821d..a1b2cd87 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -54,13 +54,6 @@ function Workspace() { } }, [workspace, momId]); - useEffect(() => { - if (momId && !selectedMom && momSocket) { - const message: MomMessage.Select = { id: momId }; - momSocket.emit(MOM_EVENT.SELECT, message); - } - }, [momId, selectedMom, momSocket]); - useEffect(() => { if (!workspaceSocket) { return; From 07c6c331265a8af578ad521d46f19af3b10abdf0 Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:06:56 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9D=98=EB=A1=9D?= =?UTF-8?q?=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=EC=9D=98=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=20Mom=EC=97=90=EC=84=9C=20Workspace=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Mom/index.tsx | 12 ------------ client/src/components/Workspace/index.tsx | 6 +++--- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/client/src/components/Mom/index.tsx b/client/src/components/Mom/index.tsx index 92d20b37..d2d56be1 100644 --- a/client/src/components/Mom/index.tsx +++ b/client/src/components/Mom/index.tsx @@ -3,20 +3,16 @@ import * as MomMessage from '@wabinar/api-types/mom'; import { BLOCK_EVENT, MOM_EVENT } from '@wabinar/constants/socket-message'; import Block from 'components/Block'; import { useEffect, useRef, useState } from 'react'; -import { useRecoilState } from 'recoil'; import useSelectedMomContext from 'src/hooks/context/useSelectedMomContext'; import useSocketContext from 'src/hooks/context/useSocketContext'; import { useCRDT } from 'src/hooks/useCRDT'; import useDebounce from 'src/hooks/useDebounce'; -import { workspaceState } from 'src/store/atom/workspace'; import { v4 as uuid } from 'uuid'; -import DefaultMom from './DefaultMom'; import ee from './EventEmitter'; import style from './style.module.scss'; function Mom() { - const [workspace] = useRecoilState(workspaceState); const { selectedMom } = useSelectedMomContext(); const { momSocket: socket } = useSocketContext(); @@ -239,14 +235,6 @@ function Mom() { setBlockFocus(index); }; - if (!workspace) { - return
      ; - } - - if (!workspace.moms.length) { - return ; - } - return (
      {selectedMom && ( diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index a1b2cd87..3d1c70b0 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -1,6 +1,6 @@ -import * as MomMessage from '@wabinar/api-types/mom'; -import { MOM_EVENT, WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; +import { WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; import Mom from 'components/Mom'; +import DefaultMom from 'components/Mom/DefaultMom'; import Sidebar from 'components/Sidebar'; import { useEffect, useMemo, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; @@ -90,7 +90,7 @@ function Workspace() { {workspace && ( - + {workspace.moms.length ? : } )} {isOnGoing && } From 10fb0b45fcac59c373ec44ce332a9a8e1d3af2ca Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:17:18 +0900 Subject: [PATCH 10/18] =?UTF-8?q?refactor:=20Sidebar=EC=9D=98=20workspace?= =?UTF-8?q?=20recoil=20atom=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/index.tsx | 21 +++++++++++++-------- client/src/components/Workspace/index.tsx | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/client/src/components/Sidebar/index.tsx b/client/src/components/Sidebar/index.tsx index b6535d7a..899510ae 100644 --- a/client/src/components/Sidebar/index.tsx +++ b/client/src/components/Sidebar/index.tsx @@ -1,4 +1,5 @@ -import { WorkspaceInfo } from 'src/types/workspace'; +import { useRecoilValue } from 'recoil'; +import { workspaceState } from 'src/store/atom/workspace'; import Header from './Header'; import MeetingButton from './MeetingButton'; @@ -6,17 +7,21 @@ import MemberList from './MemberList'; import MomList from './MomList'; import style from './style.module.scss'; -interface SidebarProps { - workspace: WorkspaceInfo; -} +function Sidebar() { + const workspace = useRecoilValue(workspaceState); + + if (!workspace) { + return
      ; + } + + const { name, members, moms } = workspace; -function Sidebar({ workspace }: SidebarProps) { return (
      -
      +
      - - + +
      diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 3d1c70b0..dfe3ba93 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -89,7 +89,7 @@ function Workspace() { {workspace && ( - + {workspace.moms.length ? : } )} From ea184e717e2f29ab011c35535867e1669588532d Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:30:52 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=20=ED=9A=8C?= =?UTF-8?q?=EC=9D=98=EB=A1=9D=20=EC=A0=95=EB=B3=B4=20MomList=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/MomList.tsx | 17 ++++++++++------- client/src/components/Sidebar/style.module.scss | 5 +++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index 10e3a0b4..e51a5d73 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -1,7 +1,7 @@ import { RiFileAddLine } from '@react-icons/all-files/ri/RiFileAddLine'; import * as MomMessage from '@wabinar/api-types/mom'; import { MOM_EVENT } from '@wabinar/constants/socket-message'; -import { memo, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import ee from 'src/components/Mom/EventEmitter'; import useSelectedMomContext from 'src/hooks/context/useSelectedMomContext'; @@ -88,7 +88,14 @@ function MomList({ moms }: MomListProps) {
        {momList.map(({ _id: id, title }) => ( -
      • onSelect(id)} role="button"> +
      • onSelect(id)} + role="button" + > {title}
      • ))} @@ -97,8 +104,4 @@ function MomList({ moms }: MomListProps) { ); } -const isMemoized = (prevProps: MomListProps, nextProps: MomListProps) => { - return prevProps.moms === nextProps.moms; -}; - -export default memo(MomList, isMemoized); +export default MomList; diff --git a/client/src/components/Sidebar/style.module.scss b/client/src/components/Sidebar/style.module.scss index 1bdc0356..8780fe01 100644 --- a/client/src/components/Sidebar/style.module.scss +++ b/client/src/components/Sidebar/style.module.scss @@ -135,6 +135,11 @@ } } +.mom-list-item__selected { + color: $black; + font-weight: 500; +} + .meeting-button { position: absolute; bottom: 15px; From 56e826a9d50ec1aea501185222e0bb9348fbad89 Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:38:39 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat:=20MOM=5FEVENT.SELECT=20emit=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20Workspace=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 초기 접속한 URL에 momId가 지정되어 있을 경우도 커버하기 위해 URL 변경에 소켓 이벤트가 발생하도록 변경 - MomList는 navigate 역할만 수행 --- client/src/components/Sidebar/MomList.tsx | 5 +---- client/src/components/Workspace/index.tsx | 10 +++++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index e51a5d73..abeb0ef1 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -27,11 +27,8 @@ function MomList({ moms }: MomListProps) { }; const onSelect = (id: string) => { - const message: MomMessage.Select = { id }; - socket.emit(MOM_EVENT.SELECT, message); - - navigate(id); setSelectedMom(null); + navigate(id); }; useEffect(() => { diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index dfe3ba93..7a1f377b 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -1,4 +1,5 @@ -import { WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; +import * as MomMessage from '@wabinar/api-types/mom'; +import { MOM_EVENT, WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; import Mom from 'components/Mom'; import DefaultMom from 'components/Mom/DefaultMom'; import Sidebar from 'components/Sidebar'; @@ -54,6 +55,13 @@ function Workspace() { } }, [workspace, momId]); + useEffect(() => { + if (momId && momSocket) { + const message: MomMessage.Select = { id: momId }; + momSocket.emit(MOM_EVENT.SELECT, message); + } + }, [momId, momSocket]); + useEffect(() => { if (!workspaceSocket) { return; From b910d5bd67391138a3932a128c7e5b3e625e4ba6 Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:40:33 +0900 Subject: [PATCH 13/18] =?UTF-8?q?feat:=20=EC=9B=8C=ED=81=AC=EC=8A=A4?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이동할 워크스페이스 정보가 로드되기 전 렌더링 로직을 위해 workspace atom null로 리셋 - 이전과 값이 동일한 경우에는 변동이 없도록 수정 --- client/src/components/WorkspaceThumbnailList/index.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/src/components/WorkspaceThumbnailList/index.tsx b/client/src/components/WorkspaceThumbnailList/index.tsx index 9f1d7182..30be3c0f 100644 --- a/client/src/components/WorkspaceThumbnailList/index.tsx +++ b/client/src/components/WorkspaceThumbnailList/index.tsx @@ -1,4 +1,6 @@ -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useRecoilState } from 'recoil'; +import { workspaceState } from 'src/store/atom/workspace'; import { Workspace } from 'src/types/workspace'; import style from './style.module.scss'; @@ -9,9 +11,14 @@ interface WorkspaceThumbnailListProps { } function WorkspaceThumbnailList({ workspaces }: WorkspaceThumbnailListProps) { + const { id: currentId } = useParams(); const navigate = useNavigate(); + const [, setWorkspace] = useRecoilState(workspaceState); const onClick = (targetId: number) => { + if (Number(currentId) === targetId) return; + + setWorkspace(null); navigate(`/workspace/${targetId}`); }; From 2775b022b31b9df904f92da5afce181da536e257 Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 21:57:04 +0900 Subject: [PATCH 14/18] =?UTF-8?q?refactor:=20MOM=5FEVENT.SELECT=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20Workspace=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Sidebar/MomList.tsx | 5 ----- client/src/components/Workspace/index.tsx | 12 ++++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/client/src/components/Sidebar/MomList.tsx b/client/src/components/Sidebar/MomList.tsx index abeb0ef1..e4bd01d2 100644 --- a/client/src/components/Sidebar/MomList.tsx +++ b/client/src/components/Sidebar/MomList.tsx @@ -36,16 +36,11 @@ function MomList({ moms }: MomListProps) { }, [moms]); useEffect(() => { - socket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { - setSelectedMom(mom); - }); - socket.on(MOM_EVENT.CREATE, ({ mom }: MomMessage.Created) => setMomList((prev) => [...prev, mom]), ); return () => { - socket.off(MOM_EVENT.SELECT); socket.off(MOM_EVENT.CREATE); }; }, [socket]); diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 7a1f377b..eb3a2ae6 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -62,6 +62,18 @@ function Workspace() { } }, [momId, momSocket]); + useEffect(() => { + if (!momSocket) return; + + momSocket.on(MOM_EVENT.SELECT, ({ mom }: MomMessage.Selected) => { + setSelectedMom(mom); + }); + + return () => { + momSocket.off(MOM_EVENT.SELECT); + }; + }, [momSocket]); + useEffect(() => { if (!workspaceSocket) { return; From 33b1bf3710558226ca5cd8b2319f887483a55fbc Mon Sep 17 00:00:00 2001 From: se030 Date: Mon, 5 Jun 2023 22:02:47 +0900 Subject: [PATCH 15/18] =?UTF-8?q?docs:=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/App.tsx | 3 ++- client/src/components/Workspace/index.tsx | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 0ae8a3d8..7625e115 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -25,7 +25,8 @@ function App() { setIsLoaded(true); setUser(user); - if (user && !/^\/workspace(\/\d+(\/.+)?)?$/.test(pathname)) { + const validPathPattern = /^\/workspace(\/\d+(\/.+)?)?$/; // /workspace(/숫자(/아무거나)) 와 처음부터 끝까지 일치하는 패턴 + if (user && !validPathPattern.test(pathname)) { navigate('/workspace'); } }; diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index eb3a2ae6..3885c4d2 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -20,7 +20,11 @@ function Workspace() { const navigate = useNavigate(); const { pathname } = useLocation(); - const momId = pathname.match(/\/workspace\/\d+\/(?.+)/)?.groups?.momId; + const momId = pathname.match( + // /workspace/숫자/회의록id 패턴에서 회의록id를 추출하기 위한 정규식 + // /workspace/숫자/ 까지는 상위 컴포넌트에서 보장되는 패턴 + /\/workspace\/\d+\/(?.+)/, + )?.groups?.momId; const [workspace, setWorkspace] = useRecoilState(workspaceState); const [selectedMom, setSelectedMom] = useState(null); From c249d90b4cfd19cd3e578831bc968d64758ff4c2 Mon Sep 17 00:00:00 2001 From: se030 Date: Tue, 6 Jun 2023 00:02:41 +0900 Subject: [PATCH 16/18] =?UTF-8?q?refactor:=20momId=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=EC=97=90=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20=EB=8C=80=EC=8B=A0=20?= =?UTF-8?q?react-router=20useParams=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Workspace/index.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index 3885c4d2..e4601996 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -4,7 +4,7 @@ import Mom from 'components/Mom'; import DefaultMom from 'components/Mom/DefaultMom'; import Sidebar from 'components/Sidebar'; import { useEffect, useMemo, useState } from 'react'; -import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import { getWorkspaceInfo } from 'src/apis/workspace'; import MeetingMediaBar from 'src/components/MeetingMediaBar'; @@ -19,12 +19,8 @@ function Workspace() { const { id } = useParams(); const navigate = useNavigate(); - const { pathname } = useLocation(); - const momId = pathname.match( - // /workspace/숫자/회의록id 패턴에서 회의록id를 추출하기 위한 정규식 - // /workspace/숫자/ 까지는 상위 컴포넌트에서 보장되는 패턴 - /\/workspace\/\d+\/(?.+)/, - )?.groups?.momId; + const params = useParams(); + const momId = params['*']; const [workspace, setWorkspace] = useRecoilState(workspaceState); const [selectedMom, setSelectedMom] = useState(null); From abdaea1bdd032479edfa86fdb036ad81dc31ca46 Mon Sep 17 00:00:00 2001 From: se030 Date: Tue, 13 Jun 2023 03:23:00 +0900 Subject: [PATCH 17/18] =?UTF-8?q?chore:=20react-query=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor: 상태 관리에 react-query 적용 #412 --- client/package.json | 2 +- package-lock.json | 103 +++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 40 deletions(-) diff --git a/client/package.json b/client/package.json index 82fcc73c..982e2ce8 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@react-icons/all-files": "^4.1.0", + "@tanstack/react-query": "^4.29.12", "@types/react-helmet": "^6.1.6", "axios": "^1.1.3", "classnames": "^2.3.2", @@ -20,7 +21,6 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", - "recoil": "^0.7.7", "socket.io-client": "^4.5.4", "uuid": "^9.0.0" }, diff --git a/package-lock.json b/package-lock.json index 846282c5..9a93b287 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "version": "0.0.0", "dependencies": { "@react-icons/all-files": "^4.1.0", + "@tanstack/react-query": "^4.29.12", "@types/react-helmet": "^6.1.6", "axios": "^1.1.3", "classnames": "^2.3.2", @@ -71,7 +72,6 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", - "recoil": "^0.7.7", "socket.io-client": "^4.5.4", "uuid": "^9.0.0" }, @@ -3137,6 +3137,41 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, + "node_modules/@tanstack/query-core": { + "version": "4.29.11", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.11.tgz", + "integrity": "sha512-8C+hF6SFAb/TlFZyS9FItgNwrw4PMa7YeX+KQYe2ZAiEz6uzg6yIr+QBzPkUwZ/L0bXvGd1sufTm3wotoz+GwQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.29.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.12.tgz", + "integrity": "sha512-zhcN6+zF6cxprxhTHQajHGlvxgK8npnp9uLe9yaWhGc6sYcPWXzyO4raL4HomUzQOPzu3jLvkriJQ7BOrDM8vA==", + "dependencies": { + "@tanstack/query-core": "4.29.11", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.16.5", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", @@ -7323,11 +7358,6 @@ "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", "dev": true }, - "node_modules/hamt_plus": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", - "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -11823,25 +11853,6 @@ "node": ">=8.10.0" } }, - "node_modules/recoil": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz", - "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==", - "dependencies": { - "hamt_plus": "1.0.2" - }, - "peerDependencies": { - "react": ">=16.13.1" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/recrawl-sync": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recrawl-sync/-/recrawl-sync-2.2.3.tgz", @@ -13683,6 +13694,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16740,6 +16759,20 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, + "@tanstack/query-core": { + "version": "4.29.11", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.11.tgz", + "integrity": "sha512-8C+hF6SFAb/TlFZyS9FItgNwrw4PMa7YeX+KQYe2ZAiEz6uzg6yIr+QBzPkUwZ/L0bXvGd1sufTm3wotoz+GwQ==" + }, + "@tanstack/react-query": { + "version": "4.29.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.12.tgz", + "integrity": "sha512-zhcN6+zF6cxprxhTHQajHGlvxgK8npnp9uLe9yaWhGc6sYcPWXzyO4raL4HomUzQOPzu3jLvkriJQ7BOrDM8vA==", + "requires": { + "@tanstack/query-core": "4.29.11", + "use-sync-external-store": "^1.2.0" + } + }, "@testing-library/jest-dom": { "version": "5.16.5", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", @@ -17978,6 +18011,7 @@ "version": "file:client", "requires": { "@react-icons/all-files": "^4.1.0", + "@tanstack/react-query": "^4.29.12", "@testing-library/jest-dom": "^5.16.5", "@types/react": "^18.0.24", "@types/react-dom": "^18.0.8", @@ -17994,7 +18028,6 @@ "react-loader-spinner": "^5.3.4", "react-router-dom": "^6.4.3", "react-toastify": "^9.1.1", - "recoil": "^0.7.7", "sass": "^1.56.1", "socket.io-client": "^4.5.4", "stylelint": "^14.15.0", @@ -19882,11 +19915,6 @@ "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", "dev": true }, - "hamt_plus": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", - "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -23130,14 +23158,6 @@ "picomatch": "^2.2.1" } }, - "recoil": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz", - "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==", - "requires": { - "hamt_plus": "1.0.2" - } - }, "recrawl-sync": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recrawl-sync/-/recrawl-sync-2.2.3.tgz", @@ -24512,6 +24532,11 @@ "punycode": "^2.1.0" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", From 075356bcb80bebd57a0b68b6f07e9e7cade8cc38 Mon Sep 17 00:00:00 2001 From: se030 Date: Tue, 13 Jun 2023 03:26:23 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20workspace=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EC=97=90=20useQuery=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit recoil 관련 코드 제거 및 react-query로 대체 --- client/src/apis/workspace.ts | 4 ++- client/src/components/Sidebar/index.tsx | 11 +++++--- client/src/components/Workspace/index.tsx | 26 +++++++------------ .../WorkspaceThumbnailList/index.tsx | 8 +++--- client/src/main.tsx | 8 +++--- client/src/store/atom/workspace.ts | 7 ----- 6 files changed, 30 insertions(+), 34 deletions(-) delete mode 100644 client/src/store/atom/workspace.ts diff --git a/client/src/apis/workspace.ts b/client/src/apis/workspace.ts index ee359c08..b8b688b1 100644 --- a/client/src/apis/workspace.ts +++ b/client/src/apis/workspace.ts @@ -28,7 +28,9 @@ export const postWorkspaceJoin = async ({ export const getWorkspaceInfo = async ({ id, -}: GetInfoParams): Promise => { +}: Partial): Promise => { + if (!id) return null; + const res = await http.get(`/workspace/${id}`); if (res.status !== OK) throw new Error(); diff --git a/client/src/components/Sidebar/index.tsx b/client/src/components/Sidebar/index.tsx index 899510ae..fd0be935 100644 --- a/client/src/components/Sidebar/index.tsx +++ b/client/src/components/Sidebar/index.tsx @@ -1,5 +1,6 @@ -import { useRecoilValue } from 'recoil'; -import { workspaceState } from 'src/store/atom/workspace'; +import { useQuery } from '@tanstack/react-query'; +import { useParams } from 'react-router-dom'; +import { getWorkspaceInfo } from 'src/apis/workspace'; import Header from './Header'; import MeetingButton from './MeetingButton'; @@ -8,7 +9,11 @@ import MomList from './MomList'; import style from './style.module.scss'; function Sidebar() { - const workspace = useRecoilValue(workspaceState); + const { id } = useParams(); + const { data: workspace } = useQuery({ + queryKey: ['workspace', id], + queryFn: () => getWorkspaceInfo({ id }), + }); if (!workspace) { return
        ; diff --git a/client/src/components/Workspace/index.tsx b/client/src/components/Workspace/index.tsx index e4601996..54a8961e 100644 --- a/client/src/components/Workspace/index.tsx +++ b/client/src/components/Workspace/index.tsx @@ -1,3 +1,4 @@ +import { useQuery } from '@tanstack/react-query'; import * as MomMessage from '@wabinar/api-types/mom'; import { MOM_EVENT, WORKSPACE_EVENT } from '@wabinar/constants/socket-message'; import Mom from 'components/Mom'; @@ -5,14 +6,12 @@ import DefaultMom from 'components/Mom/DefaultMom'; import Sidebar from 'components/Sidebar'; import { useEffect, useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; import { getWorkspaceInfo } from 'src/apis/workspace'; import MeetingMediaBar from 'src/components/MeetingMediaBar'; import MeetingContext from 'src/contexts/meeting'; import { SelectedMomContext } from 'src/contexts/selected-mom'; import { SocketContext } from 'src/contexts/socket'; import useSocket from 'src/hooks/useSocket'; -import { workspaceState } from 'src/store/atom/workspace'; import { TMom } from 'src/types/mom'; function Workspace() { @@ -22,27 +21,18 @@ function Workspace() { const params = useParams(); const momId = params['*']; - const [workspace, setWorkspace] = useRecoilState(workspaceState); + const { data: workspace } = useQuery({ + queryKey: ['workspace', id], + queryFn: () => getWorkspaceInfo({ id }), + }); + const [selectedMom, setSelectedMom] = useState(null); const [isOnGoing, setIsOnGoing] = useState(false); const momSocket = useSocket(`/workspace-mom/${id}`); const workspaceSocket = useSocket(`/workspace/${id}`); - const loadWorkspaceInfo = async () => { - if (id) { - const workspaceInfo = await getWorkspaceInfo({ id }); - - setWorkspace(workspaceInfo); - - if (!workspaceInfo.moms.length) { - setSelectedMom(null); - } - } - }; - useEffect(() => { - loadWorkspaceInfo(); setIsOnGoing(false); }, [id]); @@ -53,6 +43,10 @@ function Workspace() { if (!momId && moms.length) { navigate(moms[0]._id); } + + if (!moms.length) { + setSelectedMom(null); + } }, [workspace, momId]); useEffect(() => { diff --git a/client/src/components/WorkspaceThumbnailList/index.tsx b/client/src/components/WorkspaceThumbnailList/index.tsx index 30be3c0f..a16391ec 100644 --- a/client/src/components/WorkspaceThumbnailList/index.tsx +++ b/client/src/components/WorkspaceThumbnailList/index.tsx @@ -1,6 +1,5 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useNavigate, useParams } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; -import { workspaceState } from 'src/store/atom/workspace'; import { Workspace } from 'src/types/workspace'; import style from './style.module.scss'; @@ -11,14 +10,15 @@ interface WorkspaceThumbnailListProps { } function WorkspaceThumbnailList({ workspaces }: WorkspaceThumbnailListProps) { + const queryClient = useQueryClient(); + const { id: currentId } = useParams(); const navigate = useNavigate(); - const [, setWorkspace] = useRecoilState(workspaceState); const onClick = (targetId: number) => { if (Number(currentId) === targetId) return; - setWorkspace(null); + queryClient.invalidateQueries({ queryKey: ['workspace', currentId] }); navigate(`/workspace/${targetId}`); }; diff --git a/client/src/main.tsx b/client/src/main.tsx index a4564c60..76a65715 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -1,16 +1,18 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; -import { RecoilRoot } from 'recoil'; import 'react-toastify/dist/ReactToastify.css'; import App from './App'; import Toaster from './components/common/Toaster'; +const queryClient = new QueryClient(); + ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - + - , + , ); diff --git a/client/src/store/atom/workspace.ts b/client/src/store/atom/workspace.ts deleted file mode 100644 index 77d762f7..00000000 --- a/client/src/store/atom/workspace.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { atom } from 'recoil'; -import { WorkspaceInfo } from 'src/types/workspace'; - -export const workspaceState = atom({ - key: 'workspace', - default: null, -});