diff --git a/apps/admin/app/actions/authActions.ts b/apps/admin/app/actions/authActions.ts new file mode 100644 index 00000000..153a8d71 --- /dev/null +++ b/apps/admin/app/actions/authActions.ts @@ -0,0 +1,42 @@ +'use server'; + +import { instance } from '@withbee/apis'; +import { signIn, signOut } from '../../auth'; +import { AuthError } from 'next-auth'; +import { auth, logout } from '@withbee/auth-config'; +import { LogoutRequest } from '@withbee/types'; + +export const handleCredentialsSignin = async ({ + email, + password, +}: { + email: string; + password: string; +}) => { + try { + await signIn('credentials', { + email, + password, + redirect: false, + }); + } catch (error) { + console.error('Error occurred during credentials signin:', error); + if (error instanceof AuthError) { + switch (error.type) { + case 'CredentialsSignin': + return { error: 'Invalid credentials' }; + default: + return { error: 'Something went wrong' }; + } + } + return { error: 'Unexpected error occurred' }; + } +}; + +export const handleSignOut = async ( + accessToken: string, + refreshToken: string, +) => { + await signOut(); + await logout({ accessToken, refreshToken }); +}; diff --git a/apps/admin/app/api/auth/[...nextauth]/route.ts b/apps/admin/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 00000000..ca225652 --- /dev/null +++ b/apps/admin/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,3 @@ +import { handlers } from '../../../../auth'; + +export const { GET, POST } = handlers; diff --git a/apps/admin/app/layout.tsx b/apps/admin/app/layout.tsx index f0c7ae52..d1f38168 100644 --- a/apps/admin/app/layout.tsx +++ b/apps/admin/app/layout.tsx @@ -12,8 +12,8 @@ const geistMono = localFont({ }); export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', + title: 'WithbeeTravel Admin', + description: 'Generated by Withbee from 우리FISA', }; export default function RootLayout({ diff --git a/apps/admin/app/login-logs/page.tsx b/apps/admin/app/login-logs/page.tsx index 8bf088c3..8992ef77 100644 --- a/apps/admin/app/login-logs/page.tsx +++ b/apps/admin/app/login-logs/page.tsx @@ -13,16 +13,17 @@ const AdminPage = () => { const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); const [loginLogType, setLoginLogType] = useState('ALL'); - const [userId, setUserId] = useState(); + const [userId, setUserId] = useState(''); const fetchLoginLogs = async ( page: number, logType: string, - userId: number, + userId: string, ) => { setLoading(true); try { - const response = await getLoginLogs(page, 5, logType, userId); + const response = await getLoginLogs(page, 5, logType, Number(userId)); + console.log('response', response); if ('data' in response && response.data) { setLoginLogs(response.data.content); setPageable(response.data.pageable); @@ -96,9 +97,7 @@ const AdminPage = () => { - {loading ? ( -

로딩 중...

- ) : ( + {loginLogs.length !== 0 && (
diff --git a/apps/admin/app/login/page.module.css b/apps/admin/app/login/page.module.css new file mode 100644 index 00000000..ef7d07b2 --- /dev/null +++ b/apps/admin/app/login/page.module.css @@ -0,0 +1,106 @@ +.loginWrapper { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background-color: #f5f5f5; +} + +.loginCard { + background: white; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 400px; +} + +.loginHeader { + padding: 1.5rem; + text-align: center; +} + +.loginHeader h1 { + font-size: 1.5rem; + font-weight: bold; + margin: 0; +} + +.loginContent { + padding: 1.5rem; +} + +.formGroup { + margin-bottom: 1rem; +} + +.formGroup label { + display: block; + margin-bottom: 0.5rem; + font-size: 0.875rem; + font-weight: 500; +} + +.inputContainer { + position: relative; +} + +.inputIcon { + position: absolute; + left: 12px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + color: #9ca3af; +} + +.inputContainer input { + width: 100%; + padding: 0.75rem; + padding-left: 2.5rem; + border: 1px solid #e5e7eb; + border-radius: 4px; + font-size: 0.875rem; +} + +.inputContainer input:focus { + outline: none; + border-color: #2563eb; + box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.2); +} + +.loginButton { + width: 100%; + padding: 0.75rem; + background-color: #2563eb; + color: white; + border: none; + border-radius: 4px; + font-size: 0.875rem; + cursor: pointer; + transition: background-color 0.2s; +} + +.loginButton:hover { + background-color: #1d4ed8; +} + +.loginFooter { + padding: 1.5rem; + text-align: center; + border-top: 1px solid #e5e7eb; +} + +.loginFooter p { + font-size: 0.875rem; + color: #6b7280; +} + +.loginFooter a { + color: #2563eb; + text-decoration: none; +} + +.loginFooter a:hover { + text-decoration: underline; +} diff --git a/apps/admin/app/login/page.tsx b/apps/admin/app/login/page.tsx new file mode 100644 index 00000000..7dc87290 --- /dev/null +++ b/apps/admin/app/login/page.tsx @@ -0,0 +1,79 @@ +'use client'; + +import React, { useState } from 'react'; +import { Lock, User } from 'lucide-react'; +import styles from './page.module.css'; +import { handleCredentialsSignin } from '../actions/authActions'; + +const AdminLogin = () => { + const [formData, setFormData] = useState({ + email: '', + password: '', + }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + // 로그인 로직 구현 + console.log('Login attempt:', formData); + await handleCredentialsSignin({ + email: formData.email, + password: formData.password, + }); + + // 로그인 성공 시 리다이렉트 + window.location.href = '/'; + }; + + return ( +
+
+
+

관리자 로그인

+
+
+
+
+ +
+ + + setFormData({ ...formData, email: e.target.value }) + } + /> +
+
+
+ +
+ + + setFormData({ ...formData, password: e.target.value }) + } + /> +
+
+ + +
+
+

+ 비밀번호를 잊으셨나요? 비밀번호 찾기 +

+
+
+
+ ); +}; + +export default AdminLogin; diff --git a/apps/admin/app/page.module.css b/apps/admin/app/page.module.css index 21d6b6e8..a0d30436 100644 --- a/apps/admin/app/page.module.css +++ b/apps/admin/app/page.module.css @@ -107,7 +107,7 @@ } .mainContent { flex: 1; - padding: 2rem; + padding: 20px; background-color: #ffffff; } @@ -217,4 +217,4 @@ .button:hover { background-color: #f3f4f6; /* hover:bg-gray-50 */ -} \ No newline at end of file +} diff --git a/apps/admin/auth.ts b/apps/admin/auth.ts new file mode 100644 index 00000000..f3680d31 --- /dev/null +++ b/apps/admin/auth.ts @@ -0,0 +1 @@ +export { handlers, signIn, signOut, auth } from '@withbee/auth-config'; diff --git a/apps/admin/components/Sidebar.tsx b/apps/admin/components/Sidebar.tsx index be977bdb..3dc38a0a 100644 --- a/apps/admin/components/Sidebar.tsx +++ b/apps/admin/components/Sidebar.tsx @@ -5,7 +5,7 @@ import styles from '../app/page.module.css'; const Sidebar = () => { return (