From e6cc7e871199a033093a40a2ecc4c729926a24fd Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 10:57:38 +0900 Subject: [PATCH 01/23] refactor: routes refactor and feat questionCheck admin routes --- src/routes/admin-routes.tsx | 4 +++- src/routes/app-routes.tsx | 2 -- src/routes/private-route.tsx | 2 +- src/ui/pages/page-test.tsx | 12 ------------ 4 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 src/ui/pages/page-test.tsx diff --git a/src/routes/admin-routes.tsx b/src/routes/admin-routes.tsx index 1b1739f..e4ce230 100644 --- a/src/routes/admin-routes.tsx +++ b/src/routes/admin-routes.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { Route, Routes } from 'react-router-dom'; import PrivateRoute from './private-route'; import FileList from '../ui/pages/admin/file-list'; -import AdminLayout from '../ui/components/admin/Layout/admin-layout'; import Login from '../ui/pages/admin/login'; +import QuestionCheck from '../ui/pages/admin/question-check'; +import AdminLayout from '../ui/components/admin/Layout/admin-layout'; const AdminRoutes: React.FC = () => { const token = sessionStorage.getItem('Authorization'); @@ -12,6 +13,7 @@ const AdminRoutes: React.FC = () => { } /> } authenticated={token} />}> } /> + } /> ); diff --git a/src/routes/app-routes.tsx b/src/routes/app-routes.tsx index 8b6ce2b..8c1de84 100644 --- a/src/routes/app-routes.tsx +++ b/src/routes/app-routes.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { Route, Routes } from 'react-router-dom'; import AdminRoutes from './admin-routes'; -import PageTest from '../ui/pages/page-test'; import MaruEgg from '../ui/pages/maru-egg'; const AppRoutes: React.FC = () => { @@ -9,7 +8,6 @@ const AppRoutes: React.FC = () => { } /> } /> - } /> ); }; diff --git a/src/routes/private-route.tsx b/src/routes/private-route.tsx index f2d49d8..445a8c1 100644 --- a/src/routes/private-route.tsx +++ b/src/routes/private-route.tsx @@ -7,7 +7,7 @@ export interface PrivateRouteProps { } const PrivateRoute = ({ authenticated, component }: PrivateRouteProps) => { - return authenticated ? component : ; + return authenticated ? component : ; }; export default PrivateRoute; diff --git a/src/ui/pages/page-test.tsx b/src/ui/pages/page-test.tsx deleted file mode 100644 index 58a9c97..0000000 --- a/src/ui/pages/page-test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import AdminLayout from '../components/molecule/admin/Layout/admin-layout'; - -const PageTest: React.FC = () => { - return ( -
- -
- ); -}; - -export default PageTest; From ca5b1d78686036be08f4605f00025524ced00172 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 10:57:57 +0900 Subject: [PATCH 02/23] Refactor: tailwind CSS refactor --- src/ui/pages/admin/login.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/pages/admin/login.tsx b/src/ui/pages/admin/login.tsx index 83c868a..f3059d4 100644 --- a/src/ui/pages/admin/login.tsx +++ b/src/ui/pages/admin/login.tsx @@ -44,7 +44,7 @@ export default function Login() { required value={email} onChange={(e) => setEmail(e.target.value)} - className="block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" + className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" /> @@ -64,7 +64,7 @@ export default function Login() { required value={password} onChange={(e) => setPassword(e.target.value)} - className="block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" + className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" /> From 3919640d0573ed06ce82785e74db6939dbb9f44e Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 10:59:27 +0900 Subject: [PATCH 03/23] feat: api admin-retrieve-file logic --- src/api/admin-retrieve-file.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/api/admin-retrieve-file.ts diff --git a/src/api/admin-retrieve-file.ts b/src/api/admin-retrieve-file.ts new file mode 100644 index 0000000..a1b377c --- /dev/null +++ b/src/api/admin-retrieve-file.ts @@ -0,0 +1,20 @@ +import { llm_axiosInstance } from '../utils/axios'; + +interface AdminRetrieveFileProps { + type?: string; + category?: string; +} + +export async function adminRetrieveFile({ type, category }: AdminRetrieveFileProps) { + try { + const response = await llm_axiosInstance.get('/retrieve_documents_by_type_and_category', { + params: { + type, + category, + }, + }); + return response.data; + } catch (error: any) { + throw new Error(`Upload failed: ${error.message}`); + } +} From ff432d18813fa68fafe7d999acc0758a5a5ac39b Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 10:59:46 +0900 Subject: [PATCH 04/23] refactor: add list current file list --- src/ui/pages/admin/file-list.tsx | 52 ++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/ui/pages/admin/file-list.tsx b/src/ui/pages/admin/file-list.tsx index 570b2b0..6bef3b6 100644 --- a/src/ui/pages/admin/file-list.tsx +++ b/src/ui/pages/admin/file-list.tsx @@ -1,14 +1,22 @@ -import { Button, Divider, Select } from 'antd'; -import React, { useState } from 'react'; +import { Button, Divider, List, Select } from 'antd'; +import React, { useEffect, useState } from 'react'; import { UploadFile } from 'antd/es/upload/interface'; import Uploader from '../../components/admin/Uploader'; import { useHtmlFileSubmit } from '../../../hooks/use-html-file-submit.hooks'; +import { adminRetrieveFile } from '../../../api/admin-retrieve-file'; + +interface DataListType { + title: string; + createdAt: string; +} const FileList: React.FC = () => { const [category, setCategory] = useState('모집요강'); const [type, setType] = useState('수시'); const [uploading, setUploading] = useState(false); const [fileList, setFileList] = useState[]>([]); + const [loading, setLoading] = useState(false); + const [dataList, setDataList] = useState([]); const handleTypeChange = (value: string) => { setType(value); @@ -33,6 +41,33 @@ const FileList: React.FC = () => { setUploading(false); }; + useEffect(() => { + const fetchData = async () => { + setLoading(true); + try { + const response = await adminRetrieveFile({ type, category }); + const formattedData = response.documents.reduce((acc: DataListType[], item: any) => { + const exists = acc.find((data) => data.title === item.title); + if (!exists) { + acc.push({ + title: item.title, + createdAt: item.created_at, + }); + } + return acc; + }, []); + console.log(dataList); + setDataList(formattedData); // Overwrite the existing dataList instead of appending + } catch (error) { + console.error('다운로드 에러', error); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, [type, category]); + return (
챗봇 관리 파일 리스트 @@ -78,6 +113,19 @@ const FileList: React.FC = () => { {uploading ? 'Uploading' : 'Start Upload'}
+ + 업로드된 파일 확인하기 +
+ ( + + + + )} + /> +
); }; From e6aca88b739f70fc927f5079e8fb0e67275e5180 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 11:00:06 +0900 Subject: [PATCH 05/23] feat: adminQuestionCheck api logic --- src/api/admin-question-check.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/api/admin-question-check.ts diff --git a/src/api/admin-question-check.ts b/src/api/admin-question-check.ts new file mode 100644 index 0000000..a25185b --- /dev/null +++ b/src/api/admin-question-check.ts @@ -0,0 +1,20 @@ +import { server_axiosInstance } from '../utils/axios'; + +interface AdminQuestionCheckProps { + type: string; + category?: string; +} + +export async function adminQuestionCheck({ type, category }: AdminQuestionCheckProps) { + try { + const response = await server_axiosInstance.get('/api/questions', { + params: { + type, + category, + }, + }); + return response.data; + } catch (error: any) { + throw new Error(`Upload failed: ${error.message}`); + } +} From 061f79fed9a93d44c793080af32d69409cba0756 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Mon, 5 Aug 2024 11:00:39 +0900 Subject: [PATCH 06/23] Feat: table question check page --- src/ui/pages/admin/question-check.tsx | 103 ++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/ui/pages/admin/question-check.tsx diff --git a/src/ui/pages/admin/question-check.tsx b/src/ui/pages/admin/question-check.tsx new file mode 100644 index 0000000..96bd9d0 --- /dev/null +++ b/src/ui/pages/admin/question-check.tsx @@ -0,0 +1,103 @@ +import { Divider, Select, Table, TableProps } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { adminQuestionCheck } from '../../../api/admin-question-check'; + +interface DataType { + questionContent: string; + viewCount: string; + isChecked: boolean; +} + +const columns: TableProps['columns'] = [ + { + title: '질문내용', + dataIndex: 'questionContent', + key: 'question_content', + }, + { + title: '질문횟수', + dataIndex: 'viewCount', + key: 'viewCount', + }, + { + title: '질문확인여부', + dataIndex: 'isChecked', + key: 'isChecked', + render: (isChecked) => (isChecked ? '확인됨' : '미확인'), + }, +]; + +const QuestionCheck = () => { + const [type, setType] = useState('SUSI'); + const [category, setCategory] = useState(''); + const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + + const handleTypeChange = (value: string) => { + setType(value); + }; + + const handleCategoryChange = (value: string) => { + setCategory(value); + }; + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + try { + const response = await adminQuestionCheck({ type, category }); + const formattedData = response.map((item: any) => ({ + questionContent: item.content, + viewCount: item.viewCount.toString(), + isChecked: item.isChecked, + })); + setData(formattedData); + } catch (error) { + console.error('Error fetching data:', error); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, [type, category]); + + return ( +
+ 챗봇 질문 내용-답변 확인 +
+ 전형선택 + +
+
+ + + + ); +}; + +export default QuestionCheck; From b8c1354f204b3c08050cd3b62b1c660963f30542 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 11:37:28 +0900 Subject: [PATCH 07/23] Chore: Feat react-cookie --- package-lock.json | 50 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 51 insertions(+) diff --git a/package-lock.json b/package-lock.json index 33c1f06..7076b63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "prettier": "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.5", "react": "^18.3.1", + "react-cookie": "^7.2.0", "react-dom": "^18.3.1", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", @@ -11333,6 +11334,11 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" + }, "node_modules/@types/cross-spawn": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", @@ -11455,6 +11461,15 @@ "@types/unist": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -18766,6 +18781,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -27010,6 +27038,19 @@ "react": "^16.3.0 || ^17.0.1 || ^18.0.0" } }, + "node_modules/react-cookie": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-7.2.0.tgz", + "integrity": "sha512-mqhPERUyfOljq5yJ4woDFI33bjEtigsl8JDJdPPeNhr0eSVZmBc/2Vdf8mFxOUktQxhxTR1T+uF0/FRTZyBEgw==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.5", + "hoist-non-react-statics": "^3.3.2", + "universal-cookie": "^7.0.0" + }, + "peerDependencies": { + "react": ">= 16.3.0" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -30356,6 +30397,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universal-cookie": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-7.2.0.tgz", + "integrity": "sha512-PvcyflJAYACJKr28HABxkGemML5vafHmiL4ICe3e+BEKXRMt0GaFLZhAwgv637kFFnnfiSJ8e6jknrKkMrU+PQ==", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/package.json b/package.json index 6176ae1..cc8c13b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "prettier": "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.5", "react": "^18.3.1", + "react-cookie": "^7.2.0", "react-dom": "^18.3.1", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", From eb76e931e4056cd571c7f62cdc2503e45ac3c559 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 11:37:41 +0900 Subject: [PATCH 08/23] Refactor: set cookie provider --- src/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index 1a58c8e..234a8af 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,9 +3,14 @@ import App from './App'; import ReactDOM from 'react-dom/client'; import reportWebVitals from './reportWebVitals'; import './index.css'; +import { CookiesProvider } from 'react-cookie'; const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); -root.render(); +root.render( + + + , +); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) From fa58b68fac5bbb529431e7949595ff6206d395b5 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 11:38:07 +0900 Subject: [PATCH 09/23] Feat: cookies util setting --- src/utils/cookies.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/utils/cookies.ts diff --git a/src/utils/cookies.ts b/src/utils/cookies.ts new file mode 100644 index 0000000..9603afa --- /dev/null +++ b/src/utils/cookies.ts @@ -0,0 +1,15 @@ +import { Cookies } from 'react-cookie'; + +const cookies = new Cookies(); + +export const setCookie = (name: string, value: string, options: any) => { + return cookies.set(name, value, { ...options }); +}; + +export const getCookie = (name: string) => { + return cookies.get(name); +}; + +export const removeCookie = (name: string) => { + return cookies.remove(name); +}; From 83a5f5eaecc28844c4bde72cf530173513c5976e Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 11:38:25 +0900 Subject: [PATCH 10/23] Refactor: axios util withCredentails true --- src/utils/axios.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/axios.ts b/src/utils/axios.ts index 5d78409..813a9e6 100644 --- a/src/utils/axios.ts +++ b/src/utils/axios.ts @@ -9,5 +9,5 @@ export const llm_axiosInstance = axios.create({ export const server_axiosInstance = axios.create({ baseURL: process.env.REACT_APP_SPRING_SERVER_API_ADDRESS, timeout: 20000, - withCredentials: false, + withCredentials: true, }); From ff8b0e4dc8377ad9f0a20d01bd6936cd9b3ad77f Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 13:14:48 +0900 Subject: [PATCH 11/23] Refactor: admin-login api not use swr and set Cookie --- src/api/admin-login.ts | 45 +++++++++++++------------------- src/ui/pages/admin/file-list.tsx | 2 +- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/api/admin-login.ts b/src/api/admin-login.ts index 64b34f1..3c1a087 100644 --- a/src/api/admin-login.ts +++ b/src/api/admin-login.ts @@ -1,34 +1,25 @@ -import axios from 'axios'; -import useSWR, { mutate } from 'swr'; +import { server_axiosInstance } from '../utils/axios'; +import { getCookie, removeCookie, setCookie } from '../utils/cookies'; -interface LoginResponse { - token: string; - user: { - email: string; +export async function AdminLogin(email: string, password: string) { + const data = { + email, + password, }; -} -const fetcher = (url: string) => axios.get(url).then((res) => res.data); + try { + if (getCookie('accessToken')) { + removeCookie('accessToken'); + removeCookie('refreshToken'); + } -export async function login(email: string, password: string): Promise { - const response = await axios.post('경로변경넣어야됌', { email, password }, { withCredentials: true }); - return response.data; -} + const response = await server_axiosInstance.post('/api/auth/sign-in', data); + const accessToken: string = response.headers['jwt-token']; + const refreshToken: string = response.headers['jwt-token-refresh']; -export function useUser() { - const { data, error } = useSWR('경로넣어야행', fetcher); - return { - user: data, - isLoading: !error && !data, - isError: error, - }; -} - -export async function handleLogin(email: string, password: string): Promise { - try { - const userData = await login(email, password); - mutate('경로헤헿콩', userData, false); - } catch (err: any) { - throw new Error(err.message); + setCookie('accessToken', accessToken.split(' ')[1], { path: '/admin', secure: true, sameSite: 'lax' }); + setCookie('refreshToken', refreshToken.split(' ')[1], { path: '/admin', secure: true, sameSite: 'lax' }); + } catch (error: any) { + throw new Error('Login Failed - Server network failed'); } } diff --git a/src/ui/pages/admin/file-list.tsx b/src/ui/pages/admin/file-list.tsx index 6bef3b6..d7891aa 100644 --- a/src/ui/pages/admin/file-list.tsx +++ b/src/ui/pages/admin/file-list.tsx @@ -57,7 +57,7 @@ const FileList: React.FC = () => { return acc; }, []); console.log(dataList); - setDataList(formattedData); // Overwrite the existing dataList instead of appending + setDataList(formattedData); } catch (error) { console.error('다운로드 에러', error); } finally { From d26b38ff5111a08acbb1790630a07fa3b5602594 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 13:15:27 +0900 Subject: [PATCH 12/23] Refactor: token postion set refactor sessionStorage to cookie --- src/routes/admin-routes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/admin-routes.tsx b/src/routes/admin-routes.tsx index e4ce230..537dccf 100644 --- a/src/routes/admin-routes.tsx +++ b/src/routes/admin-routes.tsx @@ -5,9 +5,9 @@ import FileList from '../ui/pages/admin/file-list'; import Login from '../ui/pages/admin/login'; import QuestionCheck from '../ui/pages/admin/question-check'; import AdminLayout from '../ui/components/admin/Layout/admin-layout'; - +import { getCookie } from '../utils/cookies'; const AdminRoutes: React.FC = () => { - const token = sessionStorage.getItem('Authorization'); + const token = getCookie('accessToken'); return ( } /> From 52df81d90440db27d7f90696fff68e13cd6f9f90 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 13:16:00 +0900 Subject: [PATCH 13/23] Refactor: admin login tsx refactor --- src/ui/pages/admin/login.tsx | 126 ++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/src/ui/pages/admin/login.tsx b/src/ui/pages/admin/login.tsx index f3059d4..a8583d4 100644 --- a/src/ui/pages/admin/login.tsx +++ b/src/ui/pages/admin/login.tsx @@ -1,89 +1,93 @@ import React, { useState } from 'react'; -import { useUser, handleLogin } from '../../../api/admin-login'; +import { AdminLogin } from '../../../api/admin-login'; import { Spin } from 'antd'; import { LoadingOutlined } from '@ant-design/icons'; +import { useNavigate } from 'react-router-dom'; export default function Login() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); - const { user, isLoading, isError } = useUser(); + const [isLoading, setIsLoading] = useState(false); + const navigate = useNavigate(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); + setIsLoading(true); try { - await handleLogin(email, password); + await AdminLogin(email, password); } catch (err: any) { setError(err.message); + } finally { + setIsLoading(false); + navigate('/admin/question/list'); } }; return ( - <> -
-
-

- Sign in to your account -

-
+
+
+

+ Sign in to your account +

+
-
-
-
- -
- setEmail(e.target.value)} - className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" - /> -
+
+ +
+ +
+ setEmail(e.target.value)} + className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" + />
+
-
-
- -
-
- setPassword(e.target.value)} - className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" - /> -
+
+
+
- {isError ? '' :
다시 로그인해주세요
} -
- +
+ setPassword(e.target.value)} + className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-lg sm:leading-6" + />
- -
+
+ {error &&
{error}
} +
+ +
+
- +
); } From e7ae47d0d57e8d3f18b3deb78ae9dec880f23bf3 Mon Sep 17 00:00:00 2001 From: Choi JunHo Date: Tue, 6 Aug 2024 13:16:30 +0900 Subject: [PATCH 14/23] Feat: edit modal ant.design --- src/ui/components/admin/modal/edit-modal.tsx | 108 +++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/ui/components/admin/modal/edit-modal.tsx diff --git a/src/ui/components/admin/modal/edit-modal.tsx b/src/ui/components/admin/modal/edit-modal.tsx new file mode 100644 index 0000000..37c83c9 --- /dev/null +++ b/src/ui/components/admin/modal/edit-modal.tsx @@ -0,0 +1,108 @@ +import { Button, Modal } from 'antd'; +import TextArea from 'antd/es/input/TextArea'; +import React, { useState } from 'react'; +import { AdminEditAnswer } from '../../../../api/admin-edit-answer'; +import { AdminCheckQuestionAnswer } from '../../../../api/admin-check-question-answer'; + +interface CustomModalProps { + open: boolean; + setOpen: React.Dispatch>; + modalTitle: string; + modalContent: string; + modalContentId: number; + questionId: number; + isChecked: boolean; +} + +const EditModal = ({ + open, + setOpen, + modalTitle, + modalContent, + modalContentId, + questionId, + isChecked, +}: CustomModalProps) => { + const [editStatus, setEditStatus] = useState(false); + const [loading, setLoading] = useState(false); + const [content, setContent] = useState(modalContent); + + const executeWithLoading = async (action: () => Promise) => { + setLoading(true); + try { + await action(); + } catch (error) { + console.error(error); + } finally { + setLoading(false); + } + }; + + const handleEditSubmit = async () => { + try { + await executeWithLoading(async () => { + await AdminEditAnswer(modalContentId, modalContent); + await AdminCheckQuestionAnswer({ questionId, check: true }); + console.log('편집 및 확인 완료'); + }); + } catch (err) { + setEditStatus(false); + console.error(err); + } + }; + + const handleCheckToggle = async () => { + await executeWithLoading(async () => { + await AdminCheckQuestionAnswer({ questionId, check: !isChecked }); + console.log('검토 상태 변경 완료'); + }); + }; + + const handleClose = () => { + setOpen(false); + }; + + const enableEditMode = () => { + setEditStatus(true); + }; + + const handleChange = (e: React.ChangeEvent) => { + setContent(e.target.value); + }; + + return ( + + 닫기 + , + !isChecked ? ( + + ) : ( + + ), + + editStatus ? ( + + ) : ( + + ), + ]} + > + {editStatus ?