Skip to content

Commit 9c15ec1

Browse files
committed
feat: update ui
1 parent 4b64266 commit 9c15ec1

File tree

11 files changed

+425
-246
lines changed

11 files changed

+425
-246
lines changed

website/app/eslint.config.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import js from '@eslint/js'
2-
import globals from 'globals'
3-
import react from 'eslint-plugin-react'
4-
import reactHooks from 'eslint-plugin-react-hooks'
5-
import reactRefresh from 'eslint-plugin-react-refresh'
1+
import js from '@eslint/js';
2+
import globals from 'globals';
3+
import react from 'eslint-plugin-react';
4+
import reactHooks from 'eslint-plugin-react-hooks';
5+
import reactRefresh from 'eslint-plugin-react-refresh';
66

77
export default [
88
{ ignores: ['dist'] },
@@ -28,11 +28,13 @@ export default [
2828
...react.configs.recommended.rules,
2929
...react.configs['jsx-runtime'].rules,
3030
...reactHooks.configs.recommended.rules,
31+
'react/prop-types': 'off',
32+
'no-unused-vars': 'off',
3133
'react/jsx-no-target-blank': 'off',
3234
'react-refresh/only-export-components': [
3335
'warn',
3436
{ allowConstantExport: true },
3537
],
3638
},
3739
},
38-
]
40+
];

website/app/src/App.jsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
1+
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
22

3-
import ChatPage from "./chat/ChatPage";
4-
import LoginPage from "./auth/LoginPage";
5-
import RegistrationPage from "./auth/RegistrationPage";
6-
import Layout from "./app/Layout";
7-
import { AuthProvider } from "./auth/AuthProvider";
8-
import { ProtectedRoute } from "./auth/ProtectedRoute";
3+
import ChatPage from './chat/ChatPage';
4+
import LoginPage from './auth/LoginPage';
5+
import RegistrationPage from './auth/RegistrationPage';
6+
import Layout from './app/Layout';
7+
import { AuthProvider } from './auth/AuthProvider';
8+
import { ProtectedRoute } from './auth/ProtectedRoute';
9+
import AuthLayout from './app/AuthLayout';
910

1011
const AppRoutes = () => {
1112
return (
1213
<Routes>
13-
<Route path="" element={<Layout />}>
14-
<Route path="/login" element={<LoginPage />} />
15-
<Route path="/register" element={<RegistrationPage />} />
16-
<Route element={<ProtectedRoute loginPath="/login" />}>
17-
<Route path="" element={<Navigate to="/chat" />} />
18-
<Route path="/chat" element={<ChatPage />} />
14+
<Route element={<AuthLayout />}>
15+
<Route path='/login' element={<LoginPage />} />
16+
<Route path='/register' element={<RegistrationPage />} />
17+
</Route>
18+
<Route path='' element={<Layout />}>
19+
<Route element={<ProtectedRoute loginPath='/login' />}>
20+
<Route path='' element={<Navigate to='/chat' />} />
21+
<Route path='/chat' element={<ChatPage />} />
1922
</Route>
2023
</Route>
2124
</Routes>

website/app/src/app/AuthLayout.jsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Outlet, Link, useLocation } from 'react-router-dom';
2+
import { Logo } from '../components/Logo';
3+
4+
const AuthLayout = () => {
5+
const location = useLocation();
6+
const isLoginPage = location.pathname === '/login';
7+
8+
return (
9+
<div className='min-h-screen flex flex-col justify-center items-center space-y-6'>
10+
<Logo />
11+
<div className='w-full max-w-md px-8 py-10 bg-white rounded-lg border flex flex-col space-y-6 items-center animate-fadeIn'>
12+
<div className='w-full max-w-sm mx-auto'>
13+
<Outlet />
14+
</div>
15+
<div className='text-center'>
16+
{isLoginPage ? (
17+
<div>
18+
<span className='text-gray-500'>Don&apos;t have an account?</span>{' '}
19+
<Link to='/register' className=' font-bold'>
20+
Register here.
21+
</Link>
22+
</div>
23+
) : (
24+
<div>
25+
<span className='text-gray-500'>Already have an account?</span>{' '}
26+
<Link to='/login' className=' font-bold'>
27+
Login here.
28+
</Link>
29+
</div>
30+
)}
31+
</div>
32+
</div>
33+
<div className='animate-fadeIn flex flex-col items-center gap-2 text-center '>
34+
<span className='text-xs text-gray-800'>Powered By</span>
35+
<img
36+
src='https://s3.us-east-2.amazonaws.com/assets.public.serverless/general/framework-text-lighting-icon-center-black.svg'
37+
alt='Serverless Framework'
38+
className='h-8 p-0 m-0'
39+
/>
40+
</div>
41+
</div>
42+
);
43+
};
44+
45+
export default AuthLayout;

website/app/src/app/Layout.jsx

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,57 @@
1-
import { Outlet, useNavigate } from "react-router-dom";
2-
import { useAuth } from "../auth/AuthProvider";
1+
import { Outlet, useNavigate } from 'react-router-dom';
2+
import { useAuth } from '../auth/AuthProvider';
33

44
const Layout = () => {
55
const navigate = useNavigate();
66
const { logout, isLoggedIn } = useAuth();
77

88
const handleLogout = () => {
99
logout();
10-
navigate("/login");
10+
navigate('/login');
1111
};
1212

1313
return (
14-
<div className="bg-gray-100 min-h-screen pt-20">
15-
<div className="flex flex-row justify-between fixed top-0 left-0 w-full p-2 bg-white shadow-md">
16-
<img
17-
src="https://assets.serverless-extras.com/general/logo-aws-ai-stack-black.png"
18-
alt="AWS AI Stack"
19-
className="h-10 p-0 m-0"
20-
/>
21-
<div className="m-2">
22-
{isLoggedIn() && (
23-
<div className="cursor-pointer" onClick={handleLogout}>
24-
Logout
25-
</div>
26-
)}
14+
<div className='min-h-screen flex flex-col'>
15+
{isLoggedIn() && (
16+
<div className='flex bg-white items-center sticky top-0 left-0 w-full p-4 z-10 shadow-md gap-2'>
17+
<img
18+
src='https://assets.serverless-extras.com/general/logo-aws-ai-stack-black.png'
19+
alt='AWS AI Stack'
20+
className='h-10'
21+
/>
22+
<div className='flex items-center gap-2 text-center ml-auto mr-0 justify-center'>
23+
<span className='text-xs text-gray-800 mt-1.5'>By</span>
24+
<img
25+
src='https://s3.us-east-2.amazonaws.com/assets.public.serverless/general/framework-text-lighting-icon-center-black.svg'
26+
alt='Serverless Framework'
27+
className='h-8'
28+
/>
29+
</div>
30+
<button
31+
onClick={handleLogout}
32+
className='text-gray-400 bg-transparent px-2 py-2 rounded-md hover:bg-primary hover:text-white focus:outline-none focus:ring-2 focus:ring-primary transition-colors'
33+
>
34+
<svg
35+
xmlns='http://www.w3.org/2000/svg'
36+
width='18'
37+
height='18'
38+
viewBox='0 0 24 24'
39+
fill='none'
40+
stroke='currentColor'
41+
strokeWidth='2'
42+
strokeLinecap='round'
43+
strokeLinejoin='round'
44+
className='lucide lucide-log-out'
45+
>
46+
<path d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4' />
47+
<polyline points='16 17 21 12 16 7' />
48+
<line x1='21' x2='9' y1='12' y2='12' />
49+
</svg>
50+
</button>
2751
</div>
28-
</div>
29-
<div>
30-
<Outlet />
31-
</div>
52+
)}
53+
54+
<Outlet />
3255
</div>
3356
);
3457
};

website/app/src/auth/AuthProvider.jsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
1-
import { createContext, useContext } from "react";
1+
import { createContext, useContext } from 'react';
22

33
const authApiUrl = import.meta.env.VITE_AUTH_API_URL;
44
const AuthContext = createContext();
55

66
export const AuthProvider = ({ children }) => {
7-
const getToken = () => localStorage.getItem("token");
7+
const getToken = () => localStorage.getItem('token');
88

99
const login = async ({ email, password }) => {
1010
const response = await fetch(`${authApiUrl}/login`, {
11-
method: "POST",
11+
method: 'POST',
1212
headers: {
13-
"Content-Type": "application/json",
13+
'Content-Type': 'application/json',
1414
},
1515
body: JSON.stringify({ email, password }),
1616
});
1717
const data = await response.json();
1818
if (data.token) {
19-
localStorage.setItem("token", data.token);
19+
localStorage.setItem('token', data.token);
2020
} else if (data.error) {
2121
throw new Error(data.error);
2222
} else {
23-
throw new Error("Unknown error");
23+
throw new Error('Unknown error');
2424
}
2525
};
2626

2727
const register = async ({ email, password }) => {
2828
const response = await fetch(`${authApiUrl}/register`, {
29-
method: "POST",
29+
method: 'POST',
3030
headers: {
31-
"Content-Type": "application/json",
31+
'Content-Type': 'application/json',
3232
},
3333
body: JSON.stringify({ email, password }),
3434
});
3535
const data = await response.json();
3636
if (data.token) {
37-
localStorage.setItem("token", data.token);
37+
localStorage.setItem('token', data.token);
3838
} else if (data.error) {
3939
throw new Error(data.error);
4040
} else {
41-
throw new Error("Unknown error");
41+
throw new Error('Unknown error');
4242
}
4343
};
4444

4545
const logout = () => {
46-
localStorage.removeItem("token");
46+
localStorage.removeItem('token');
4747
};
4848

4949
const isLoggedIn = () => {

0 commit comments

Comments
 (0)