Working on auth

This commit is contained in:
Benjamin Sherriff
2023-10-17 20:49:27 -04:00
parent 140488c925
commit 3b15f520c8
18 changed files with 454 additions and 49 deletions

View File

@@ -1,18 +1,25 @@
import axios, { AxiosResponse } from 'axios';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
const serviceHost = process.env.SERVICE_HOST || 'http://localhost';
const servicePort = process.env.SERVICE_PORT || 5000;
export async function getRequest(endpoint: string, params: any): Promise<AxiosResponse<any, any> | undefined> {
export async function getRequest(
url: string,
params: AxiosRequestConfig<any>
): Promise<AxiosResponse<any, any> | undefined> {
const response = await axios
.get(`${serviceHost}:${servicePort}/${endpoint}`, { params })
.get(`${serviceHost}:${servicePort}/${url}`, { params })
.catch((error) => console.error(error));
return response || undefined;
}
export async function postRequest(endpoint: string, body: any): Promise<AxiosResponse<any, any> | undefined> {
export async function postRequest(
url: string,
data?: any,
config?: AxiosRequestConfig<any>
): Promise<AxiosResponse<any, any> | undefined> {
const response = await axios
.post(`${serviceHost}:${servicePort}/${endpoint}`, body || {})
.post(`${serviceHost}:${servicePort}/${url}`, data, config)
.catch((error) => console.error(error));
return response || undefined;
}

9
ui/src/api/users.ts Normal file
View File

@@ -0,0 +1,9 @@
import { postRequest } from '.';
export async function login(email: string, password: string) {
return await postRequest('users/login', { email, password }, { withCredentials: true });
}
export async function logout() {
return await postRequest('users/logout', {}, { withCredentials: true });
}

View File

@@ -3,6 +3,25 @@
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import './topbar.css';
import {
Anchor,
Avatar,
Button,
Checkbox,
Container,
Group,
Menu,
Modal,
Paper,
PasswordInput,
Text,
TextInput,
Title
} from '@mantine/core';
import Cookies from 'js-cookie';
import { useEffect, useState } from 'react';
import { useForm } from '@mantine/form';
import { login, logout } from '@/api/users';
const headerItems = [
{
@@ -41,21 +60,118 @@ const headerItems = [
export default function Topbar() {
const pathName = usePathname();
const [showLogin, setShowLogin] = useState(false);
const [authenticated, setAuthenticated] = useState(false);
// Check if the auth cookie is set
// If it is, show the user avatar
// If not, show the login button
useEffect(() => {
console.log('cookies', Cookies.get());
if (Cookies.get('auth')) {
setAuthenticated(true);
}
}, []);
return (
<nav className='navbar'>
<div className='left'>
<Link href={'/'} className='title'>
Siren
</Link>
<div className='header-items'>
{headerItems.map((item) => (
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link} key={item.name}>
{item.name}
</Link>
))}
<>
<nav className='navbar'>
<div className='left'>
<Link href={'/'} className='title'>
Siren
</Link>
<div className='header-items'>
{headerItems.map((item) => (
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link} key={item.name}>
{item.name}
</Link>
))}
</div>
</div>
</div>
</nav>
<div className='user'>
<Menu shadow='md' width={200} trigger='hover' openDelay={100} closeDelay={400}>
<Menu.Target>
<Avatar style={{ cursor: 'pointer' }} />
</Menu.Target>
<Menu.Dropdown>
{!authenticated && <Menu.Item onClick={() => setShowLogin(true)}>Login</Menu.Item>}
{authenticated && (
<Menu.Item
onClick={async () => {
const response = await logout();
if (response?.status == 200) {
Cookies.remove('auth');
setAuthenticated(false);
}
}}
>
Logout
</Menu.Item>
)}
</Menu.Dropdown>
</Menu>
</div>
</nav>
<LoginModal showLogin={showLogin} setShowLogin={setShowLogin} setAuthenticated={setAuthenticated} />
</>
);
}
function LoginModal({
showLogin,
setShowLogin,
setAuthenticated
}: {
showLogin: boolean;
setShowLogin: (show: boolean) => void;
setAuthenticated: (authenticated: boolean) => void;
}) {
const form = useForm({
initialValues: {
email: '',
password: ''
}
});
return (
<Modal opened={showLogin} onClose={() => setShowLogin(false)} withCloseButton={false}>
<Container>
<Title ta='center'>Welcome back!</Title>
<Text c='dimmed' size='sm' ta='center' mt={5}>
Do not have an account yet?{' '}
<Anchor size='sm' component='button'>
Create account
</Anchor>
</Text>
<Paper withBorder shadow='md' p={30} mt={30} radius='md'>
<form
onSubmit={form.onSubmit(async (values) => {
const response = await login(values.email, values.password);
if (response?.status == 200) {
setShowLogin(false);
setAuthenticated(true);
}
})}
>
<TextInput label='Email' placeholder='you@example.com' required {...form.getInputProps('email')} />
<PasswordInput
label='Password'
placeholder='Your password'
required
mt='md'
{...form.getInputProps('password')}
/>
<Group justify='space-between' mt='lg'>
<Checkbox label='Remember me' />
<Anchor component='button' size='sm'>
Forgot password?
</Anchor>
</Group>
<Button type='submit' fullWidth mt='xl'>
Sign in
</Button>
</form>
</Paper>
</Container>
</Modal>
);
}

View File

@@ -9,6 +9,11 @@
display: flex;
}
.navbar .user {
padding-left: 1em;
padding-right: 1em;
}
.navbar .title {
padding-left: 2em;
padding-right: 2em;
@@ -44,4 +49,4 @@
.header-items .active {
border-bottom: 2px solid #5f5f5f;
}
}