From 26a5423bdad51c403161b62f82aedb7224cf6cc5 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 16 Oct 2023 20:35:10 +0900 Subject: [PATCH 01/15] =?UTF-8?q?[fix]:=20staticServerUri=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 --- src/App.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 74618d82..55a928aa 100644 --- a/src/App.js +++ b/src/App.js @@ -13,9 +13,11 @@ import routes from './constant/routes'; import './global.css'; +const staticServerUri = process.env.REACT_APP_PATH || ''; + function App() { return ( - + } /> } /> From 76545296601681dce81d75bc5d8667bf78f8607e Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 16 Oct 2023 20:40:45 +0900 Subject: [PATCH 02/15] =?UTF-8?q?[conf]:=20=EB=B0=B0=ED=8F=AC=20=EC=A4=80?= =?UTF-8?q?=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 21 +++++++++++++++++++++ k8s/deployment.yaml | 19 +++++++++++++++++++ k8s/ingress.yaml | 19 +++++++++++++++++++ k8s/kustomization.yaml | 5 +++++ k8s/service.yaml | 15 +++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 Dockerfile create mode 100644 k8s/deployment.yaml create mode 100644 k8s/ingress.yaml create mode 100644 k8s/kustomization.yaml create mode 100644 k8s/service.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a254c95d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# node 16 이미지를 기반으로 함 +FROM krmp-d2hub-idock.9rum.cc/goorm/node:16 + +# 작업 디렉토리 설정 +WORKDIR /usr/src/app + +# 필요한 React App 소스 코드를 이미지에 복사 +COPY krampoline/ ./ + +# 필요한 npm 패키지 설치 +RUN npm ci +RUN npm install -g serve + +# 프로젝트 npm build +RUN npm run build + +# 서버 실행 시 사용하는 포트 지정 +EXPOSE 3000 + +# 컨테이너를 시작할 때 빌드된 React App을 서빙 +CMD ["serve", "-s", "build"] \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 00000000..0f63af32 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + labels: + app: frontend +spec: + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + # 여러분의 image 주소를 입력해주세요. + image: krmp-d2hub-idock.9rum.cc/dev-test/repo_a512d3e0fae0 diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml new file mode 100644 index 00000000..bf24649e --- /dev/null +++ b/k8s/ingress.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/rewrite-target: /$2 + nginx.ingress.kubernetes.io/ssl-redirect: "false" + labels: + app.kubernetes.io/managed-by: kargocd + name: krampoline + namespace: default +spec: + rules: + - http: + paths: + - backend: + serviceName: frontend + servicePort: 3000 + # 여러분의 app path 를 넣어주세요. + path: /k097d170c1331a(/|$)(.*) diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml new file mode 100644 index 00000000..64f2f680 --- /dev/null +++ b/k8s/kustomization.yaml @@ -0,0 +1,5 @@ +namespace: krampoline +resources: + - deployment.yaml + - service.yaml + - ingress.yaml diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 00000000..8c901d29 --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: frontend + name: frontend +spec: + ports: + - name: 3000-3000 + port: 3000 + protocol: TCP + targetPort: 3000 + selector: + app: frontend + type: LoadBalancer From e59016426354631a386725ac90e751e3fc63e6ab Mon Sep 17 00:00:00 2001 From: baegyeong Date: Fri, 27 Oct 2023 15:10:48 +0900 Subject: [PATCH 03/15] =?UTF-8?q?[fix]:=20switch=EB=AC=B8=EC=9D=84=20IIFE?= =?UTF-8?q?=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 --- src/pages/PostWritePage.jsx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/pages/PostWritePage.jsx b/src/pages/PostWritePage.jsx index 3566e985..fb9a4a5a 100644 --- a/src/pages/PostWritePage.jsx +++ b/src/pages/PostWritePage.jsx @@ -12,7 +12,6 @@ import CircleNavigate from '../components/organisms/CircleNavigate'; const PostWritePage = () => { const navigate = useNavigate(); const [focus, setFocus] = useState(1); - let currentPage; const { register, @@ -72,19 +71,17 @@ const PostWritePage = () => { console.log(data); // api 연결 후 수정 예정 }; - switch (focus) { - case 1: - currentPage = ; - break; - case 2: - currentPage = ; - break; - case 3: - currentPage = ; - break; - default: - currentPage = null; - } + const currentPage = (function (page) { + if (page === 1) { + return ; + } + if (page === 2) { + return ; + } + if (page === 3) { + return ; + } + })(focus); return (
From 095408fcafdc9f5fb1c5571befb33a6922045c02 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Fri, 27 Oct 2023 15:19:21 +0900 Subject: [PATCH 04/15] =?UTF-8?q?[fix]:=20alert=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20utils=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 --- src/pages/PostWritePage.jsx | 14 ++------------ src/utils/alert.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/pages/PostWritePage.jsx b/src/pages/PostWritePage.jsx index fb9a4a5a..ce7b5af7 100644 --- a/src/pages/PostWritePage.jsx +++ b/src/pages/PostWritePage.jsx @@ -8,6 +8,7 @@ import OrderInfo from '../components/templates/OrderInfo'; import OrderRequest from '../components/templates/OrderRequest'; import OrderDeadLine from '../components/templates/OrderDeadLine'; import CircleNavigate from '../components/organisms/CircleNavigate'; +import { registerMessage } from '../utils/alert'; const PostWritePage = () => { const navigate = useNavigate(); @@ -43,18 +44,7 @@ const PostWritePage = () => { }; const handleAlert = () => { - Swal.fire({ - title: '공고를 등록하시겠습니까?', - html: `정보를 알맞게 입력하셨나요?
- 피커는 입력한 정보를 바탕으로 움직이게 됩니다.`, - icon: 'question', - showCancelButton: true, - reverseButtons: true, - confirmButtonColor: '#0075FF', - cancelButtonColor: '#D9D9D9', - cancelButtonText: '취소', - confirmButtonText: '확인', - }); + Swal.fire(registerMessage); }; const handleNext = () => { diff --git a/src/utils/alert.js b/src/utils/alert.js index d864e974..8cee30fa 100644 --- a/src/utils/alert.js +++ b/src/utils/alert.js @@ -18,3 +18,16 @@ export const authInvalidMessage = { icon: 'error', confirmButtonText: '확인', }; + +export const registerMessage = { + title: '공고를 등록하시겠습니까?', + html: `정보를 알맞게 입력하셨나요?
+ 피커는 입력한 정보를 바탕으로 움직이게 됩니다.`, + icon: 'question', + showCancelButton: true, + reverseButtons: true, + confirmButtonColor: '#0075FF', + cancelButtonColor: '#D9D9D9', + cancelButtonText: '취소', + confirmButtonText: '확인', +}; From fb79718e6c9822a7554c6fee8cc95d65ecf8ecdc Mon Sep 17 00:00:00 2001 From: baegyeong Date: Fri, 27 Oct 2023 19:53:15 +0900 Subject: [PATCH 05/15] =?UTF-8?q?[style]:=20margin-left=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/atoms/MinusBtn.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/atoms/MinusBtn.jsx b/src/components/atoms/MinusBtn.jsx index 88fc9c09..746599f0 100644 --- a/src/components/atoms/MinusBtn.jsx +++ b/src/components/atoms/MinusBtn.jsx @@ -1,7 +1,7 @@ import { PiMinus } from 'react-icons/pi'; const MinusBtn = ({ onClick }) => { - return ; + return ; }; export default MinusBtn; From c12c3c16f836eaa0540803c73b711dfdc3f76883 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sat, 28 Oct 2023 22:26:02 +0900 Subject: [PATCH 06/15] =?UTF-8?q?[feat]:=20admin=20=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=ED=84=B0=20=EB=B0=8F=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 2 ++ src/constant/routes.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/App.js b/src/App.js index 573ad3a3..770d5a30 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,7 @@ import PostWriteIntroPage from './pages/PostWriteIntroPage'; import PostWritePage from './pages/PostWritePage'; import ErrorPage from './pages/ErrorPage'; import PostDetailWriterPage from './pages/PostDetailWriterPage'; +import AdminPage from './pages/AdminPage'; import ProtectedRoute from './components/templates/ProtectedRoute'; import routes from './constant/routes'; @@ -37,6 +38,7 @@ function App() { } /> } /> } /> + } /> ); diff --git a/src/constant/routes.js b/src/constant/routes.js index 355a8f90..039f2c52 100644 --- a/src/constant/routes.js +++ b/src/constant/routes.js @@ -9,6 +9,7 @@ const routes = { postWriter: '/post/writer', postWrite: '/post-write', error: '/*', + admin: '/admin', }; export default routes; From 0abcc4ec00a2152324c2cf7801c2d22b82a11db3 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sat, 28 Oct 2023 22:28:12 +0900 Subject: [PATCH 07/15] =?UTF-8?q?[conf]:=20eslint=20=EC=A1=B0=EA=B1=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 395274d7..488713a6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -30,7 +30,13 @@ "labelAttributes": ["htmlFor"] } ], - "max-len": ["error", { "code": 300, "ignoreRegExpLiterals": true }] + "max-len": ["error", { "code": 300, "ignoreRegExpLiterals": true }], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": true + } + ] }, "settings": { "import/resolver": { From c342c9c352e50cc3887fafc424d597287111c8fb Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sat, 28 Oct 2023 22:29:41 +0900 Subject: [PATCH 08/15] =?UTF-8?q?[feat]:=20msw=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4=EC=B9=98=20=EB=B0=8F=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/index.js | 5 +++++ src/mocks/handlers.js | 10 ++++++++++ src/mocks/mockData.js | 26 ++++++++++++++++++++++++++ src/mocks/worker.js | 5 +++++ 5 files changed, 47 insertions(+) create mode 100644 src/mocks/handlers.js create mode 100644 src/mocks/mockData.js create mode 100644 src/mocks/worker.js diff --git a/package.json b/package.json index f323d4d5..5f768108 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "msw": "^2.0.1", "prettier": "3.0.3", "tailwindcss": "^3.3.3" } diff --git a/src/index.js b/src/index.js index 42e9c04e..4f4cc6af 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,11 @@ import ReactDOM from 'react-dom/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import App from './App'; import reportWebVitals from './reportWebVitals'; +/* eslint import/newline-after-import: "off" */ +import worker from './mocks/worker'; +if (process.env.NODE_ENV === 'development') { + worker.start(); +} const queryClient = new QueryClient(); const root = ReactDOM.createRoot(document.getElementById('root')); diff --git a/src/mocks/handlers.js b/src/mocks/handlers.js new file mode 100644 index 00000000..5065abd3 --- /dev/null +++ b/src/mocks/handlers.js @@ -0,0 +1,10 @@ +import { http, HttpResponse } from 'msw'; +import REQUEST_LIST from './mockData'; + +const handlers = [ + http.get('/admin', () => { + return HttpResponse.json(REQUEST_LIST); + }), +]; + +export default handlers; diff --git a/src/mocks/mockData.js b/src/mocks/mockData.js new file mode 100644 index 00000000..86223f9e --- /dev/null +++ b/src/mocks/mockData.js @@ -0,0 +1,26 @@ +const REQUEST_LIST = { + success: true, + response: { + user: [ + { + user_id: 1, + nickname: '홍길동', + }, + { + user_id: 2, + nickname: '홍길동', + }, + { + user_id: 3, + nickname: '홍길동', + }, + { + user_id: 4, + nickname: '홍길동', + }, + ], + }, + error: null, +}; + +export default REQUEST_LIST; diff --git a/src/mocks/worker.js b/src/mocks/worker.js new file mode 100644 index 00000000..18cde22b --- /dev/null +++ b/src/mocks/worker.js @@ -0,0 +1,5 @@ +import { setupWorker } from 'msw/browser'; +import handlers from './handlers'; + +const worker = setupWorker(...handlers); +export default worker; From 60195f2ffa533dd4e4df88305a9caee397a0437c Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:16:30 +0900 Subject: [PATCH 09/15] =?UTF-8?q?[conf]:=20=EC=84=9C=EB=B2=84=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=8F=99=EC=A0=81=20?= =?UTF-8?q?import=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - development가 아닐 때만 msw import --- src/index.js | 27 ++++++++++++++++++--------- src/mocks/browser.js | 5 +++++ 2 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 src/mocks/browser.js diff --git a/src/index.js b/src/index.js index 4f4cc6af..bb32d5d3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,21 +1,30 @@ +/* eslint-disable */ import React from 'react'; import ReactDOM from 'react-dom/client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import App from './App'; import reportWebVitals from './reportWebVitals'; -/* eslint import/newline-after-import: "off" */ -import worker from './mocks/worker'; -if (process.env.NODE_ENV === 'development') { - worker.start(); + +async function deferRender() { + if (process.env.NODE_ENV !== 'development') { + return; + } + + const { worker } = await import('./mocks/browser'); + + return worker.start(); } const queryClient = new QueryClient(); const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - , -); + +deferRender().then(() => { + root.render( + + + , + ); +}); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) diff --git a/src/mocks/browser.js b/src/mocks/browser.js new file mode 100644 index 00000000..8bb6e702 --- /dev/null +++ b/src/mocks/browser.js @@ -0,0 +1,5 @@ +/* eslint-disable */ +import { setupWorker } from 'msw/browser'; +import handlers from './handlers/index'; + +export const worker = setupWorker(...handlers); From 5bc5573f7e62819d492fa9cbd3456df88a60e9b2 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:17:49 +0900 Subject: [PATCH 10/15] =?UTF-8?q?[conf]:=20mock=20data=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/data/adminData.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/mocks/data/adminData.js diff --git a/src/mocks/data/adminData.js b/src/mocks/data/adminData.js new file mode 100644 index 00000000..d4e6d391 --- /dev/null +++ b/src/mocks/data/adminData.js @@ -0,0 +1,34 @@ +export const REQUEST_LIST = { + success: true, + response: { + user: [ + { + userId: 1, + nickname: '홍길동', + }, + { + userId: 2, + nickname: '카테캠', + }, + { + userId: 3, + nickname: '12조', + }, + { + userId: 4, + nickname: 'msw', + }, + ], + }, + error: null, +}; + +export const REQUEST_DETAIL = { + success: true, + response: { + userId: 1, + nickname: '홍길동', + imageUrl: 'https://aws.amazon.com', + }, + error: null, +}; From b420b0ddc199d504372954e68f0dd1b12d332471 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:18:26 +0900 Subject: [PATCH 11/15] =?UTF-8?q?[feat]:=20handlers=20=EC=97=AD=ED=95=A0?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 추후 admin외에 더 추가할 때 handlers 폴더 아래에 생성 - public/mockServiceWorker는 기본 설정파일 --- public/mockServiceWorker.js | 292 ++++++++++++++++++++++++++++++++++++ src/mocks/handlers.js | 10 -- src/mocks/handlers/admin.js | 14 ++ src/mocks/handlers/index.js | 5 + src/mocks/mockData.js | 26 ---- src/mocks/worker.js | 5 - 6 files changed, 311 insertions(+), 41 deletions(-) create mode 100644 public/mockServiceWorker.js delete mode 100644 src/mocks/handlers.js create mode 100644 src/mocks/handlers/admin.js create mode 100644 src/mocks/handlers/index.js delete mode 100644 src/mocks/mockData.js delete mode 100644 src/mocks/worker.js diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js new file mode 100644 index 00000000..33a657b7 --- /dev/null +++ b/public/mockServiceWorker.js @@ -0,0 +1,292 @@ +/* eslint-disable */ +/* tslint:disable */ + +/** + * Mock Service Worker (2.0.1). + * @see https://github.com/mswjs/msw + * - Please do NOT modify this file. + * - Please do NOT serve this file on production. + */ + +const INTEGRITY_CHECKSUM = '0877fcdc026242810f5bfde0d7178db4' +const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') +const activeClientIds = new Set() + +self.addEventListener('install', function () { + self.skipWaiting() +}) + +self.addEventListener('activate', function (event) { + event.waitUntil(self.clients.claim()) +}) + +self.addEventListener('message', async function (event) { + const clientId = event.source.id + + if (!clientId || !self.clients) { + return + } + + const client = await self.clients.get(clientId) + + if (!client) { + return + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + switch (event.data) { + case 'KEEPALIVE_REQUEST': { + sendToClient(client, { + type: 'KEEPALIVE_RESPONSE', + }) + break + } + + case 'INTEGRITY_CHECK_REQUEST': { + sendToClient(client, { + type: 'INTEGRITY_CHECK_RESPONSE', + payload: INTEGRITY_CHECKSUM, + }) + break + } + + case 'MOCK_ACTIVATE': { + activeClientIds.add(clientId) + + sendToClient(client, { + type: 'MOCKING_ENABLED', + payload: true, + }) + break + } + + case 'MOCK_DEACTIVATE': { + activeClientIds.delete(clientId) + break + } + + case 'CLIENT_CLOSED': { + activeClientIds.delete(clientId) + + const remainingClients = allClients.filter((client) => { + return client.id !== clientId + }) + + // Unregister itself when there are no more clients + if (remainingClients.length === 0) { + self.registration.unregister() + } + + break + } + } +}) + +self.addEventListener('fetch', function (event) { + const { request } = event + + // Bypass navigation requests. + if (request.mode === 'navigate') { + return + } + + // Opening the DevTools triggers the "only-if-cached" request + // that cannot be handled by the worker. Bypass such requests. + if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + return + } + + // Bypass all requests when there are no active clients. + // Prevents the self-unregistered worked from handling requests + // after it's been deleted (still remains active until the next reload). + if (activeClientIds.size === 0) { + return + } + + // Generate unique request ID. + const requestId = crypto.randomUUID() + event.respondWith(handleRequest(event, requestId)) +}) + +async function handleRequest(event, requestId) { + const client = await resolveMainClient(event) + const response = await getResponse(event, client, requestId) + + // Send back the response clone for the "response:*" life-cycle events. + // Ensure MSW is active and ready to handle the message, otherwise + // this message will pend indefinitely. + if (client && activeClientIds.has(client.id)) { + ;(async function () { + const responseClone = response.clone() + // When performing original requests, response body will + // always be a ReadableStream, even for 204 responses. + // But when creating a new Response instance on the client, + // the body for a 204 response must be null. + const responseBody = response.status === 204 ? null : responseClone.body + + sendToClient( + client, + { + type: 'RESPONSE', + payload: { + requestId, + isMockedResponse: IS_MOCKED_RESPONSE in response, + type: responseClone.type, + status: responseClone.status, + statusText: responseClone.statusText, + body: responseBody, + headers: Object.fromEntries(responseClone.headers.entries()), + }, + }, + [responseBody], + ) + })() + } + + return response +} + +// Resolve the main client for the given event. +// Client that issues a request doesn't necessarily equal the client +// that registered the worker. It's with the latter the worker should +// communicate with during the response resolving phase. +async function resolveMainClient(event) { + const client = await self.clients.get(event.clientId) + + if (client?.frameType === 'top-level') { + return client + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + return allClients + .filter((client) => { + // Get only those clients that are currently visible. + return client.visibilityState === 'visible' + }) + .find((client) => { + // Find the client ID that's recorded in the + // set of clients that have registered the worker. + return activeClientIds.has(client.id) + }) +} + +async function getResponse(event, client, requestId) { + const { request } = event + + // Clone the request because it might've been already used + // (i.e. its body has been read and sent to the client). + const requestClone = request.clone() + + function passthrough() { + const headers = Object.fromEntries(requestClone.headers.entries()) + + // Remove internal MSW request header so the passthrough request + // complies with any potential CORS preflight checks on the server. + // Some servers forbid unknown request headers. + delete headers['x-msw-intention'] + + return fetch(requestClone, { headers }) + } + + // Bypass mocking when the client is not active. + if (!client) { + return passthrough() + } + + // Bypass initial page load requests (i.e. static assets). + // The absence of the immediate/parent client in the map of the active clients + // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet + // and is not ready to handle requests. + if (!activeClientIds.has(client.id)) { + return passthrough() + } + + // Bypass requests with the explicit bypass header. + // Such requests can be issued by "ctx.fetch()". + const mswIntention = request.headers.get('x-msw-intention') + if (['bypass', 'passthrough'].includes(mswIntention)) { + return passthrough() + } + + // Notify the client that a request has been intercepted. + const requestBuffer = await request.arrayBuffer() + const clientMessage = await sendToClient( + client, + { + type: 'REQUEST', + payload: { + id: requestId, + url: request.url, + mode: request.mode, + method: request.method, + headers: Object.fromEntries(request.headers.entries()), + cache: request.cache, + credentials: request.credentials, + destination: request.destination, + integrity: request.integrity, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + body: requestBuffer, + keepalive: request.keepalive, + }, + }, + [requestBuffer], + ) + + switch (clientMessage.type) { + case 'MOCK_RESPONSE': { + return respondWithMock(clientMessage.data) + } + + case 'MOCK_NOT_FOUND': { + return passthrough() + } + } + + return passthrough() +} + +function sendToClient(client, message, transferrables = []) { + return new Promise((resolve, reject) => { + const channel = new MessageChannel() + + channel.port1.onmessage = (event) => { + if (event.data && event.data.error) { + return reject(event.data.error) + } + + resolve(event.data) + } + + client.postMessage( + message, + [channel.port2].concat(transferrables.filter(Boolean)), + ) + }) +} + +async function respondWithMock(response) { + // Setting response status code to 0 is a no-op. + // However, when responding with a "Response.error()", the produced Response + // instance will have status code set to 0. Since it's not possible to create + // a Response instance with status code 0, handle that use-case separately. + if (response.status === 0) { + return Response.error() + } + + const mockedResponse = new Response(response.body, response) + + Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { + value: true, + enumerable: true, + }) + + return mockedResponse +} diff --git a/src/mocks/handlers.js b/src/mocks/handlers.js deleted file mode 100644 index 5065abd3..00000000 --- a/src/mocks/handlers.js +++ /dev/null @@ -1,10 +0,0 @@ -import { http, HttpResponse } from 'msw'; -import REQUEST_LIST from './mockData'; - -const handlers = [ - http.get('/admin', () => { - return HttpResponse.json(REQUEST_LIST); - }), -]; - -export default handlers; diff --git a/src/mocks/handlers/admin.js b/src/mocks/handlers/admin.js new file mode 100644 index 00000000..6b435b35 --- /dev/null +++ b/src/mocks/handlers/admin.js @@ -0,0 +1,14 @@ +import { http, HttpResponse } from 'msw'; +import { REQUEST_LIST, REQUEST_DETAIL } from '../data/adminData'; + +const adminHandlers = [ + http.get('/admin', () => { + return HttpResponse.json(REQUEST_LIST); + }), + + http.get('/admin/auth/1', () => { + return HttpResponse.json(REQUEST_DETAIL); + }), +]; + +export default adminHandlers; diff --git a/src/mocks/handlers/index.js b/src/mocks/handlers/index.js new file mode 100644 index 00000000..2cfd5763 --- /dev/null +++ b/src/mocks/handlers/index.js @@ -0,0 +1,5 @@ +import adminHandlers from './admin'; + +const handlers = [...adminHandlers]; + +export default handlers; diff --git a/src/mocks/mockData.js b/src/mocks/mockData.js deleted file mode 100644 index 86223f9e..00000000 --- a/src/mocks/mockData.js +++ /dev/null @@ -1,26 +0,0 @@ -const REQUEST_LIST = { - success: true, - response: { - user: [ - { - user_id: 1, - nickname: '홍길동', - }, - { - user_id: 2, - nickname: '홍길동', - }, - { - user_id: 3, - nickname: '홍길동', - }, - { - user_id: 4, - nickname: '홍길동', - }, - ], - }, - error: null, -}; - -export default REQUEST_LIST; diff --git a/src/mocks/worker.js b/src/mocks/worker.js deleted file mode 100644 index 18cde22b..00000000 --- a/src/mocks/worker.js +++ /dev/null @@ -1,5 +0,0 @@ -import { setupWorker } from 'msw/browser'; -import handlers from './handlers'; - -const worker = setupWorker(...handlers); -export default worker; From c59c074e02d9efd80d5204d091465f335ef560de Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:19:37 +0900 Subject: [PATCH 12/15] =?UTF-8?q?[feat]:=20=ED=95=99=EC=83=9D=EC=A6=9D=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 2 ++ src/constant/routes.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/App.js b/src/App.js index 770d5a30..0ae18f38 100644 --- a/src/App.js +++ b/src/App.js @@ -10,6 +10,7 @@ import PostWritePage from './pages/PostWritePage'; import ErrorPage from './pages/ErrorPage'; import PostDetailWriterPage from './pages/PostDetailWriterPage'; import AdminPage from './pages/AdminPage'; +import AdminAuthPage from './pages/AdminAuthPage'; import ProtectedRoute from './components/templates/ProtectedRoute'; import routes from './constant/routes'; @@ -39,6 +40,7 @@ function App() { } /> } /> } /> + } /> ); diff --git a/src/constant/routes.js b/src/constant/routes.js index 039f2c52..cf1b4771 100644 --- a/src/constant/routes.js +++ b/src/constant/routes.js @@ -10,6 +10,7 @@ const routes = { postWrite: '/post-write', error: '/*', admin: '/admin', + adminAuth: '/admin/auth/:id', }; export default routes; From 174ba5984c06656d6920017006428f52fd76e85f Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:20:31 +0900 Subject: [PATCH 13/15] =?UTF-8?q?[feat]:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - msw 라이브러리 사용 - 각 학생 컴포넌트에 user 정보 넘김 - 하위 컴포넌트인 AuthRequest.jsx에서 nickname 출력 - id에 따라 Link로 상세페이지 이동 가능 --- src/components/organisms/AuthRequest.jsx | 17 ++++++++++++++ src/pages/AdminPage.jsx | 30 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/components/organisms/AuthRequest.jsx create mode 100644 src/pages/AdminPage.jsx diff --git a/src/components/organisms/AuthRequest.jsx b/src/components/organisms/AuthRequest.jsx new file mode 100644 index 00000000..f842b94f --- /dev/null +++ b/src/components/organisms/AuthRequest.jsx @@ -0,0 +1,17 @@ +import { Link } from 'react-router-dom'; +import { PiCaretRightLight } from 'react-icons/pi'; + +const AuthRequest = ({ user }) => { + return ( +
+ +
+ {user.nickname} + +
+ +
+ ); +}; + +export default AuthRequest; diff --git a/src/pages/AdminPage.jsx b/src/pages/AdminPage.jsx new file mode 100644 index 00000000..0e4981d6 --- /dev/null +++ b/src/pages/AdminPage.jsx @@ -0,0 +1,30 @@ +import { useEffect, useState } from 'react'; +import AuthRequest from '../components/organisms/AuthRequest'; +import OtherNav from '../components/atoms/OtherNav'; + +const AdminPage = () => { + const [userInfo, setUserInfo] = useState([]); + + useEffect(() => { + fetch('/admin') + .then((response) => response.json()) + .then((data) => { + const userArray = data.response.user; + setUserInfo(userArray); + }); + }, []); + + return ( + + +
+
학생 인증 요청
+ {userInfo.map((item) => { + return ; + })} +
+
+ ); +}; + +export default AdminPage; From db8412b3fa5865cab254a1629756d982b12a53bb Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:22:11 +0900 Subject: [PATCH 14/15] =?UTF-8?q?[feat]:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=95=99=EC=83=9D=EC=A6=9D=20=EC=9D=B8=EC=A6=9D=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 추후 params에 따라 데이터 fetch --- src/components/organisms/AuthDetail.jsx | 10 +++++++++ src/pages/AdminAuthPage.jsx | 28 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/components/organisms/AuthDetail.jsx create mode 100644 src/pages/AdminAuthPage.jsx diff --git a/src/components/organisms/AuthDetail.jsx b/src/components/organisms/AuthDetail.jsx new file mode 100644 index 00000000..bec643a3 --- /dev/null +++ b/src/components/organisms/AuthDetail.jsx @@ -0,0 +1,10 @@ +const AuthDetail = ({ user }) => { + return ( + <> +
{user.nickname}
+ student + + ); +}; + +export default AuthDetail; diff --git a/src/pages/AdminAuthPage.jsx b/src/pages/AdminAuthPage.jsx new file mode 100644 index 00000000..e06fc3a4 --- /dev/null +++ b/src/pages/AdminAuthPage.jsx @@ -0,0 +1,28 @@ +import { useEffect, useState } from 'react'; +import OtherNav from '../components/atoms/OtherNav'; +import AuthDetail from '../components/organisms/AuthDetail'; + +const AdminAuthPage = () => { + // const { id } = useParams(); + const [userInfo, setUserInfo] = useState([]); + + useEffect(() => { + fetch('/admin/auth/1') + .then((response) => response.json()) + .then((data) => { + const userArray = data.response; + setUserInfo(userArray); + }); + }, []); + + return ( +
+ +
+ +
+
+ ); +}; + +export default AdminAuthPage; From 7da8dbe8ed19f2edce14ddf3d3f860d83ebdcebb Mon Sep 17 00:00:00 2001 From: baegyeong Date: Sun, 29 Oct 2023 00:28:08 +0900 Subject: [PATCH 15/15] =?UTF-8?q?[conf]:=20=EB=B0=B0=ED=8F=AC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 21 --------------------- k8s/deployment.yaml | 19 ------------------- k8s/ingress.yaml | 19 ------------------- k8s/kustomization.yaml | 5 ----- k8s/service.yaml | 15 --------------- 5 files changed, 79 deletions(-) delete mode 100644 Dockerfile delete mode 100644 k8s/deployment.yaml delete mode 100644 k8s/ingress.yaml delete mode 100644 k8s/kustomization.yaml delete mode 100644 k8s/service.yaml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index a254c95d..00000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# node 16 이미지를 기반으로 함 -FROM krmp-d2hub-idock.9rum.cc/goorm/node:16 - -# 작업 디렉토리 설정 -WORKDIR /usr/src/app - -# 필요한 React App 소스 코드를 이미지에 복사 -COPY krampoline/ ./ - -# 필요한 npm 패키지 설치 -RUN npm ci -RUN npm install -g serve - -# 프로젝트 npm build -RUN npm run build - -# 서버 실행 시 사용하는 포트 지정 -EXPOSE 3000 - -# 컨테이너를 시작할 때 빌드된 React App을 서빙 -CMD ["serve", "-s", "build"] \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml deleted file mode 100644 index 0f63af32..00000000 --- a/k8s/deployment.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: frontend - labels: - app: frontend -spec: - selector: - matchLabels: - app: frontend - template: - metadata: - labels: - app: frontend - spec: - containers: - - name: frontend - # 여러분의 image 주소를 입력해주세요. - image: krmp-d2hub-idock.9rum.cc/dev-test/repo_a512d3e0fae0 diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml deleted file mode 100644 index bf24649e..00000000 --- a/k8s/ingress.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$2 - nginx.ingress.kubernetes.io/ssl-redirect: "false" - labels: - app.kubernetes.io/managed-by: kargocd - name: krampoline - namespace: default -spec: - rules: - - http: - paths: - - backend: - serviceName: frontend - servicePort: 3000 - # 여러분의 app path 를 넣어주세요. - path: /k097d170c1331a(/|$)(.*) diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml deleted file mode 100644 index 64f2f680..00000000 --- a/k8s/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -namespace: krampoline -resources: - - deployment.yaml - - service.yaml - - ingress.yaml diff --git a/k8s/service.yaml b/k8s/service.yaml deleted file mode 100644 index 8c901d29..00000000 --- a/k8s/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: frontend - name: frontend -spec: - ports: - - name: 3000-3000 - port: 3000 - protocol: TCP - targetPort: 3000 - selector: - app: frontend - type: LoadBalancer