From ecee2f31dc5f616d371519b3bdca30f4bc665e85 Mon Sep 17 00:00:00 2001 From: qkrxogmla Date: Tue, 6 May 2025 01:14:34 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/Admin.jsx | 9 ++ frontend/src/App.jsx | 2 + frontend/src/Login.jsx | 96 +++++++++++++++++-- frontend/src/Login.module.css | 44 +++++++++ frontend/src/assets/root.css | 2 +- frontend/src/components/InputBlock.jsx | 7 +- .../components/componentsCss/InfoBlock.css | 7 ++ frontend/vite.config.js | 16 +++- 8 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 frontend/src/Admin.jsx create mode 100644 frontend/src/Login.module.css diff --git a/frontend/src/Admin.jsx b/frontend/src/Admin.jsx new file mode 100644 index 0000000..1eb01d0 --- /dev/null +++ b/frontend/src/Admin.jsx @@ -0,0 +1,9 @@ +const Admin = () => { + return ( +
+

Admin Page

+

This is the admin page.

+
+ ); +}; +export default Admin; diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index b168902..a8edf28 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -5,6 +5,7 @@ import Home from "./Home"; import Assignment from "./Assignment"; import Deposit from "./Deposit"; import Intro from "./Intro"; +import Admin from "./Admin"; function App() { return ( @@ -15,6 +16,7 @@ function App() { } /> } /> } /> + } /> ); diff --git a/frontend/src/Login.jsx b/frontend/src/Login.jsx index 06d3ddb..166e8a9 100644 --- a/frontend/src/Login.jsx +++ b/frontend/src/Login.jsx @@ -1,14 +1,96 @@ import React from "react"; +import { useState } from "react"; +import InputBlock from "./components/InputBlock"; +import { useNavigate } from "react-router-dom"; +import styles from "./Login.module.css"; + +const Login = () => { + const [name, setName] = useState(""); + const [password, setPassword] = useState(""); + const [responseMessage, setResponseMessage] = useState(""); + + const navigate = useNavigate(); + + const handleChange = (index, value) => { + if (index === 0) setName(value); + else if (index === 1) setPassword(value); + }; + + const handleLogin = async () => { + try { + const res = await fetch("/api/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + credentials: "include", + body: JSON.stringify({ name, password }), + }); + + if (!res.ok) { + const data = await res.json(); + + if (res.status === 401) { + setResponseMessage( + data?.message || "이름 또는 비밀번호를 다시 확인해주세요." + ); + } else { + setResponseMessage( + data?.message || + "알 수 없는 오류가 발생했습니다. 다시 시도해주세요." + ); + } + + return; + } + + const data = await res.json(); // { id, name, role } + + localStorage.setItem("user", JSON.stringify(data)); + + if (data.role === "ADMIN") { + navigate("/admin"); + } else if (data.role === "MEMBER") { + navigate("/home"); + } else { + setResponseMessage("알 수 없는 사용자 유형입니다."); + } + } catch (error) { + console.error(error); + setResponseMessage("서버 연결에 실패했습니다. 다시 시도해주세요."); + } + }; -const Login = ({ onLogin }) => { return ( -
-

로그인 페이지

- - - +
+
+

PIROCHECK

+ + +
+ {responseMessage} +
+ +
); }; - export default Login; diff --git a/frontend/src/Login.module.css b/frontend/src/Login.module.css new file mode 100644 index 0000000..ece282e --- /dev/null +++ b/frontend/src/Login.module.css @@ -0,0 +1,44 @@ +.login { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.pirocheck { + font-size: 1.25rem; + transform: scaleX(1.5); + margin-bottom: 65px; +} +.login_container { + background-color: var(--background-black); + color: var(--main-green); + font-family: "Cafe24Moyamoya-Regular-v1.0", sans-serif; + padding: 1rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} +.button { + background-color: var(--main-green); + color: white; + width: 309px; + height: 47px; + border-radius: 14px; + margin-top: 15px; + font-size: 16px; +} +button:disabled { + opacity: 0.6; + cursor: default; +} +.errorWrapper { + width: 309px; + display: flex; + justify-content: flex-start; + margin-left: 8px; +} +.errormessage { + font-family: "Noto Sans", sans-serif; + color: #ff5858; + font-size: 10px; + margin-top: 10px; +} diff --git a/frontend/src/assets/root.css b/frontend/src/assets/root.css index 03f70a6..0b747e1 100644 --- a/frontend/src/assets/root.css +++ b/frontend/src/assets/root.css @@ -17,7 +17,7 @@ --fill-gray: #d9d9d9; --warn-red: #ff5858; --text-white: #ffffff; - --border-gray: #c7c7c7; + --border-gray: rgba(204, 204, 204, 0.4); } .noto-sans-kr-context { font-family: "Noto Sans KR", sans-serif; diff --git a/frontend/src/components/InputBlock.jsx b/frontend/src/components/InputBlock.jsx index 18acb60..a6ff2d4 100644 --- a/frontend/src/components/InputBlock.jsx +++ b/frontend/src/components/InputBlock.jsx @@ -1,15 +1,16 @@ import React from "react"; import "./componentsCss/InfoBlock.css"; -const InputBlock = ({ inputs }) => { +const InputBlock = ({ inputs, onChange }) => { return ( -
+
{inputs.map((input, index) => ( onChange && onChange(index, e.target.value)} /> ))}
diff --git a/frontend/src/components/componentsCss/InfoBlock.css b/frontend/src/components/componentsCss/InfoBlock.css index 73b7438..82aa409 100644 --- a/frontend/src/components/componentsCss/InfoBlock.css +++ b/frontend/src/components/componentsCss/InfoBlock.css @@ -9,7 +9,14 @@ font-family: "Noto Sans KR", sans-serif; border: 1px var(--background-black) solid; padding: 10px; + margin-top: 11px; } .inputTag:focus { border: 1px var(--main-green) solid; } +.inputBlock { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 8b0f57b..6b46dee 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,7 +1,15 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; -// https://vite.dev/config/ +// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) + server: { + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + }, + }, + }, +});