From 619afe8657a3d3cd69da1b6f69305bd880489f30 Mon Sep 17 00:00:00 2001
From: MinseoLee <mmmm@ajou.ac.kr>
Date: Thu, 7 Dec 2023 20:14:11 +0900
Subject: [PATCH] refactor: make instances as `Ref` & apply type `GFC`

---
 .eslintrc.js                                  |  3 ++
 src/_app/App.tsx                              | 16 ++++++----
 src/common/constants/index.js                 |  3 +-
 src/common/instances/Connector.ts             | 18 ++++++++++--
 src/common/instances/Socket.ts                |  4 +--
 src/common/types/fc.ts                        | 13 +++++++++
 src/contexts/bottom-sheet/index.tsx           |  2 +-
 src/contexts/cart/index.tsx                   |  2 +-
 src/contexts/toast/index.tsx                  |  2 +-
 src/pages/admin-page/AdminPage.tsx            | 29 +++++++++++++++++--
 src/pages/cart-page/CartPage.tsx              | 13 ++++-----
 src/pages/history-page/HistoryPage.tsx        | 14 ++++-----
 src/pages/login-page/LoginPage.tsx            | 24 ++++++++-------
 src/pages/main-page/MainPage.tsx              | 15 +++++-----
 src/pages/menu-page/MenuPage.tsx              | 11 +++----
 .../order-page/success-page/SuccessPage.tsx   | 12 ++++----
 src/pages/signup-page/SignupPage.tsx          | 13 ++++-----
 17 files changed, 125 insertions(+), 69 deletions(-)
 create mode 100644 src/common/types/fc.ts

diff --git a/.eslintrc.js b/.eslintrc.js
index 34d4379..403e496 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -41,6 +41,7 @@ module.exports = {
 
         // react.js
         "react/react-in-jsx-scope": "off",
+        "react/prop-types": "off",
 
         // typescript
         "@typescript-eslint/consistent-type-imports": ["error", {
@@ -58,6 +59,8 @@ module.exports = {
                 "minimumDescriptionLength": 3
             }
         ],
+        "@typescript-eslint/ban-types": "off",
+        "@typescript-eslint/no-non-null-assertion": "off",
 
         // plugins
         "import/order": ["error", {
diff --git a/src/_app/App.tsx b/src/_app/App.tsx
index 2bea1fb..b54e65b 100644
--- a/src/_app/App.tsx
+++ b/src/_app/App.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useEffect, useRef, useState } from 'react';
+import { useContext, useEffect, useRef, useState } from 'react';
 import '../common/css/common.css';
 import '../common/css/reset.css';
 import { Routes, Route, useNavigate } from "react-router-dom";
@@ -30,17 +30,24 @@ import type { CartItemPostModel } from "../pages/cart-page/config/type";
 import type { MutableRefObject } from 'react';
 
 
+
 function App() {
     const { setToastItem } = useContext(ToastContext);
     
     const [headerName, setHeaderName] = useState('');
     const [login, setLogin] = useState(true);
-    const connector = new Connector(setLogin);
-    let socket: MutableRefObject<Socket|null> = useRef(null);
+    
+    const connector: MutableRefObject<Connector|null> = useRef(null);
+    const socket: MutableRefObject<Socket|null> = useRef(null);
     
     const navigator = useNavigate();
     
     
+    useEffect(() => {
+        connector.current = new Connector(setLogin);
+        console.log('app', connector.current);
+    }, []);
+    
     useEffect(() => {
         if (!login) {
             navigator(APP_ROUTE.LOGIN);
@@ -48,7 +55,6 @@ function App() {
         }
         
         socket.current = new Socket();
-        console.log(socket.current);
         
         socket.current?.onOrder((d: CartItemPostModel) => {
             console.log(d);
@@ -86,7 +92,7 @@ function App() {
                                     <Route path={APP_ROUTE.ORDER.SUCCESS} element={<SuccessPage connector={connector} />} />
                                     <Route path={APP_ROUTE.ORDER.FAIL} element={<FailPage />} />
                                     <Route path={APP_ROUTE.ORDER.CANCEL} element={<CancelPage />} />
-                                    <Route path={APP_ROUTE.ADMIN} element={<AdminPage />} />
+                                    <Route path={APP_ROUTE.ADMIN} element={<AdminPage connector={connector} />} />
                                 </Routes>
                             </article>
                         </Wrapper>
diff --git a/src/common/constants/index.js b/src/common/constants/index.js
index 3c5aa63..a97d352 100644
--- a/src/common/constants/index.js
+++ b/src/common/constants/index.js
@@ -6,7 +6,8 @@ const CONFIRM = Object.freeze({
 });
 
 const ALERT = Object.freeze({
-    REQ_FAIL: '요청에 실패하였습니다'
+    REQ_FAIL: '요청에 실패하였습니다',
+    REQ_WRONG: '잘못된 접근입니다'
 });
 
 
diff --git a/src/common/instances/Connector.ts b/src/common/instances/Connector.ts
index bf5af4a..f5b69cd 100644
--- a/src/common/instances/Connector.ts
+++ b/src/common/instances/Connector.ts
@@ -6,18 +6,30 @@ type LoginInstance = Dispatch<SetStateAction<boolean>>;
 
 class Connector {
     private setLoginInstance: LoginInstance;
+    private isAdmin = false;
+    private randomUuid = Math.random();
     
     constructor(setLogin: LoginInstance) {
+        console.log('constructed');
         this.setLoginInstance = setLogin;
     }
     
-    async login<T>(payload?: any): Promise<boolean> {
+    setIsAdmin(b: boolean) {
+        this.isAdmin = b;
+        console.log('setIsAdmin', b);
+    }
+    
+    getIsAdmin() {
+        console.log('getIsAdmin', this.isAdmin);
+        return this.isAdmin;
+    }
+    
+    async login<T>(payload?: any): Promise<T> {
         const postRequest = await fetchData<T>('/user/login', FETCH_METHOD.POST, payload);
         if (postRequest.status === RESPONSE_STATUS.OK) {
             this.setLoginInstance(true);
-            return true;
         }
-        return false;
+        return postRequest.response;
     }
 	
     async get<T>(url: string, payload?: any): Promise<T> {
diff --git a/src/common/instances/Socket.ts b/src/common/instances/Socket.ts
index d457e31..4d450a1 100644
--- a/src/common/instances/Socket.ts
+++ b/src/common/instances/Socket.ts
@@ -8,11 +8,11 @@ class Socket {
 	
     constructor() {
         this.ioInstance.on('connect', () => {
-            console.log('Connected to Socket.IO server');
+            // console.log('Connected to Socket.IO server');
         });
 		
         this.ioInstance.on('auth', (e) => {
-            console.log('auth', e);
+            // console.log('auth', e);
         });
     }
 	
diff --git a/src/common/types/fc.ts b/src/common/types/fc.ts
new file mode 100644
index 0000000..3e9625f
--- /dev/null
+++ b/src/common/types/fc.ts
@@ -0,0 +1,13 @@
+import type Connector from "../instances/Connector";
+import type { FC } from "react";
+
+interface PageDefaultProp {
+	connector: {
+		current: Connector | null;
+	}
+}
+
+type GFC = FC<PageDefaultProp>;
+type GFCWithProp<T> = FC<PageDefaultProp & T>;
+
+export type { GFC, GFCWithProp };
diff --git a/src/contexts/bottom-sheet/index.tsx b/src/contexts/bottom-sheet/index.tsx
index e4f0359..193429f 100644
--- a/src/contexts/bottom-sheet/index.tsx
+++ b/src/contexts/bottom-sheet/index.tsx
@@ -19,7 +19,7 @@ const BSProvider: FC<pProps> = ({ children }) => {
     const [item, setItem] = useState<BSContextType['bSElement']>(null);
 	
     useEffect(() => {
-        console.log('GLOBAL BSProvider: ', item);
+        // console.log('GLOBAL BSProvider: ', item);
     } ,[item]);
     
     const setBSElement = (el: ReactNode | null) => {
diff --git a/src/contexts/cart/index.tsx b/src/contexts/cart/index.tsx
index de51499..0a8bbd0 100644
--- a/src/contexts/cart/index.tsx
+++ b/src/contexts/cart/index.tsx
@@ -29,7 +29,7 @@ const CartProvider: FC<pProps> = ({ children }) => {
             flushCartItem();
         }
         
-        console.log('GLOBAL CartProvider: ', item);
+        // console.log('GLOBAL CartProvider: ', item);
     }, [item]);
     
     
diff --git a/src/contexts/toast/index.tsx b/src/contexts/toast/index.tsx
index 55dc79b..7f63ed4 100644
--- a/src/contexts/toast/index.tsx
+++ b/src/contexts/toast/index.tsx
@@ -19,7 +19,7 @@ const ToastProvider: FC<pProps> = ({ children }) => {
 	
 	
     useEffect(() => {
-        console.log('GLOBAL ToastProvider: ', item);
+        // console.log('GLOBAL ToastProvider: ', item);
     }, [item]);
 	
 	
diff --git a/src/pages/admin-page/AdminPage.tsx b/src/pages/admin-page/AdminPage.tsx
index 85ab9aa..49ff62e 100644
--- a/src/pages/admin-page/AdminPage.tsx
+++ b/src/pages/admin-page/AdminPage.tsx
@@ -1,5 +1,30 @@
-const AdminPage = () => {
-    return (<div>admin</div>);
+import { useEffect } from "react";
+import { useNavigate } from "react-router-dom";
+
+import APP_ROUTE from "../../_app/config/route";
+import { ALERT } from "../../common/constants";
+
+import type Connector from "../../common/instances/Connector";
+import type { GFC } from "../../common/types/fc";
+
+
+const AdminPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
+    const navigator = useNavigate();
+    
+    useEffect(() => {
+        console.log('adminpage', connector);
+        // if (!connector.getIsAdmin()) {
+        //     alert(ALERT.REQ_WRONG);
+        //     navigator(APP_ROUTE.LOGIN);
+        //     return;
+        // }
+    }, [connector]);
+    
+    return (
+        <div>admin</div>
+    );
 };
 
 export default AdminPage;
diff --git a/src/pages/cart-page/CartPage.tsx b/src/pages/cart-page/CartPage.tsx
index 6ffc400..7e99ca0 100644
--- a/src/pages/cart-page/CartPage.tsx
+++ b/src/pages/cart-page/CartPage.tsx
@@ -7,18 +7,15 @@ import { sum } from "../../common/utils/jjLodash";
 import QuantityController from "../../components/quantity-controller/QuantityController";
 import { CartContext } from "../../contexts/cart";
 
-
 import S from './CartPage.module.css';
 
 import type { CartItemData, OrderPostModel } from "./config/type";
-import type Connector from "../../common/instances/Connector";
-import type { FC } from "react";
+import type { GFC } from "../../common/types/fc";
 
 
-interface Props {
-    connector: Connector;
-}
-const CartPage: FC<Props> = ({ connector }) => {
+const CartPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const { cartItem, setCartItem } = useContext(CartContext);
     const [quantities, setQuantities] = useState<number[]>([]);
     const [totalPrice, setTotalPrice] = useState(0);
@@ -54,7 +51,7 @@ const CartPage: FC<Props> = ({ connector }) => {
             try {
                 const _device = detectDeviceType();
     
-                const orderRequest = await connector.post<OrderPostModel>('/order', {
+                const orderRequest = await connector.current!.post<OrderPostModel>('/order', {
                     shopId: cartItem.shop._id,
                     items: cartItem.menus.map((d) => ({ menuId: d._id, quantity: d.quantity })),
                     takeout: cartItem.takeout
diff --git a/src/pages/history-page/HistoryPage.tsx b/src/pages/history-page/HistoryPage.tsx
index f74ce27..d62155f 100644
--- a/src/pages/history-page/HistoryPage.tsx
+++ b/src/pages/history-page/HistoryPage.tsx
@@ -5,21 +5,19 @@ import { ALERT } from "../../common/constants";
 import OrderBox from "./modules/order-box/OrderBox";
 
 import type { HistoryPageModel } from "./config/type";
-import type Connector from "../../common/instances/Connector";
-import type { FC } from "react";
+import type { GFC } from "../../common/types/fc";
 
 
-interface Props {
-    connector: Connector;
-}
 
-const HistoryPage: FC<Props> = ({ connector }) => {
+const HistoryPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const [model, setModel] = useState<HistoryPageModel|null>(null);
     
     useEffect(() => {
         void (async () => {
             try {
-                const response = await connector.get<HistoryPageModel>('/order');
+                const response = await connector.current!.get<HistoryPageModel>('/order');
                 setModel(response);
             } catch {
                 alert(ALERT.REQ_FAIL);
@@ -30,7 +28,7 @@ const HistoryPage: FC<Props> = ({ connector }) => {
         <div>
             {
                 model && model.map((d, i) => (
-                    <OrderBox waitingCount={d.waitingCount} name={'menu_name'} 
+                    <OrderBox waitingCount={d.waitingCount} name={'menu_name'}
                         price={d.totalPrice} status={d.status} shop={'shop_name'}
                         takeout={d.takeout} key={`orderbox-${i}`}
                     />
diff --git a/src/pages/login-page/LoginPage.tsx b/src/pages/login-page/LoginPage.tsx
index e70595e..3c62822 100644
--- a/src/pages/login-page/LoginPage.tsx
+++ b/src/pages/login-page/LoginPage.tsx
@@ -3,24 +3,21 @@ import { useNavigate } from "react-router-dom";
 
 import APP_ROUTE from "../../_app/config/route";
 
+
 import S from './LoginPage.module.css';
 
 import type { LoginPagePostModel } from "./config/type";
-import type Connector from "../../common/instances/Connector";
-import type { FC } from "react";
-
+import type { GFC } from "../../common/types/fc";
 
-interface Props {
-    connector: Connector;
-}
 
-const LoginPage: FC<Props> = ({ connector }) => {
+const LoginPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const [account, setAccount] = useState({
         loginId: '', password: ''
     });
     const navigate = useNavigate();
     
-    
     const handleChangeId = (e: any) => {
         setAccount((prev) => ({
             ...prev,
@@ -41,8 +38,15 @@ const LoginPage: FC<Props> = ({ connector }) => {
     const handleLogin = () => {
         void (async () => {
             try {
-                await connector.login<LoginPagePostModel>(account);
-                navigate(APP_ROUTE.MAIN);
+                const response = await connector.current!.login<LoginPagePostModel>(account);
+                if (response.role?.isAdmin) {
+                    connector.current!.setIsAdmin(true);
+                    console.log('loginpage', connector);
+                    navigate(APP_ROUTE.ADMIN);
+                } else {
+                    connector.current!.setIsAdmin(false);
+                    navigate(APP_ROUTE.MAIN);
+                }
             } catch (e) {
                 console.error(e);
             }
diff --git a/src/pages/main-page/MainPage.tsx b/src/pages/main-page/MainPage.tsx
index 77f70eb..d7c625a 100644
--- a/src/pages/main-page/MainPage.tsx
+++ b/src/pages/main-page/MainPage.tsx
@@ -3,26 +3,25 @@ import { Link } from "react-router-dom";
 
 import { ALERT } from "../../common/constants";
 
+
 import S from "./MainPage.module.css";
 import ShopBox from "./modules/shop-box/ShopBox";
 
 
 import type { MainPageModel } from "./config/type";
-import type Connector from "../../common/instances/Connector";
-import type { FC } from "react";
+import type { GFC } from "../../common/types/fc";
 
 
-interface Props {
-    connector: Connector;
-}
-const MainPage: FC<Props> = ({ connector }) => {
+const MainPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const [model, setModel] = useState<MainPageModel|null>(null);
     
     useEffect(() => {
         void (async () => {
             try {
-                const response = await connector.get<MainPageModel>('/shop');
-                setModel(response);
+                const response = await connector.current!.get<MainPageModel>('/shop');
+                setModel(response as MainPageModel);
             } catch {
                 alert(ALERT.REQ_FAIL);
             }
diff --git a/src/pages/menu-page/MenuPage.tsx b/src/pages/menu-page/MenuPage.tsx
index 024d64c..88ff2ea 100644
--- a/src/pages/menu-page/MenuPage.tsx
+++ b/src/pages/menu-page/MenuPage.tsx
@@ -6,23 +6,24 @@ import { ALERT } from "../../common/constants";
 import MenuBox from "./modules/menu-box/MenuBox";
 
 import type { MenuPageModel } from "./config/type";
-import type Connector from "../../common/instances/Connector";
-import type { Dispatch, FC, SetStateAction } from "react";
+import type { GFCWithProp } from "../../common/types/fc";
+import type { Dispatch, SetStateAction } from "react";
 
 
 
 interface Props {
-    connector: Connector;
     setHeaderName: Dispatch<SetStateAction<string>>;
 }
-const MenuPage: FC<Props> = ({ connector, setHeaderName }) => {
+const MenuPage: GFCWithProp<Props> = ({ connector, setHeaderName }) => {
+    if (!connector) return <></>;
+    
     const [model, setModel] = useState<MenuPageModel|null>(null);
     const { pathname } = useLocation();
     
     useEffect(() => {
         void (async () => {
             try {
-                const response = await connector.get<MenuPageModel>(
+                const response = await connector.current!.get<MenuPageModel>(
                     `/shop/${pathname.split('/').at(2)}/menu`,
                 );
                 setModel(response);
diff --git a/src/pages/order-page/success-page/SuccessPage.tsx b/src/pages/order-page/success-page/SuccessPage.tsx
index 1e99e65..269db00 100644
--- a/src/pages/order-page/success-page/SuccessPage.tsx
+++ b/src/pages/order-page/success-page/SuccessPage.tsx
@@ -4,14 +4,12 @@ import { useLocation } from "react-router-dom";
 import { getQueryStrings } from "../../../common/utils/query";
 
 import type { OrderApprovePostModel } from "./config/type";
-import type Connector from "../../../common/instances/Connector";
-import type { FC } from "react";
+import type { GFC } from "../../../common/types/fc";
 
-interface Props {
-    connector: Connector;
-}
 
-const SuccessPage: FC<Props> = ({ connector }) => {
+const SuccessPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const location = useLocation();
     
     useEffect(() => {
@@ -19,7 +17,7 @@ const SuccessPage: FC<Props> = ({ connector }) => {
         
         void (async () => {
             try {
-                await connector.post<OrderApprovePostModel>('/order/approve', {
+                await connector.current!.post<OrderApprovePostModel>('/order/approve', {
                     pg_token: getQueryStrings(location.search, 'pg_token'),
                     payment_id: localStorage.getItem('payment_id'),
                 });
diff --git a/src/pages/signup-page/SignupPage.tsx b/src/pages/signup-page/SignupPage.tsx
index 773f0b6..e0694b1 100644
--- a/src/pages/signup-page/SignupPage.tsx
+++ b/src/pages/signup-page/SignupPage.tsx
@@ -3,16 +3,15 @@ import { useNavigate } from "react-router-dom";
 
 import APP_ROUTE from "../../_app/config/route";
 
-import S from './SignupPage.module.css';
 
-import type Connector from "../../common/instances/Connector";
+import S from './SignupPage.module.css';
 
+import type { GFC } from "../../common/types/fc";
 
-interface Props {
-    connector: Connector;
-}
 
-const SignupPage: React.FC<Props> = ({ connector }) => {
+const SignupPage: GFC = ({ connector }) => {
+    if (!connector) return <></>;
+    
     const navigate = useNavigate();
     const [accountData, setAccountData] = useState({
         loginId: '',
@@ -83,7 +82,7 @@ const SignupPage: React.FC<Props> = ({ connector }) => {
         ){
             try {
                 void(async () => {
-                    await connector.post('/user/register', accountData);
+                    await connector.current!.post('/user/register', accountData);
                     navigate(APP_ROUTE.LOGIN);
                 })();
             } catch (e) {
-- 
GitLab