Skip to content

Commit 727bbd6

Browse files
authored
Merge pull request #22 from dcorroyer/mb-32-revoir-la-gestion-de-lauth-et-des-routes
MB-32 revoir la gestion de lauth et des routes
2 parents caef7f4 + e4e600f commit 727bbd6

38 files changed

+642
-1419
lines changed

app/assets/components/not-found.tsx

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react'
2+
3+
import { Button, Container, Group, Text, Title } from '@mantine/core'
4+
5+
import { Link } from 'react-router-dom'
6+
7+
import { Illustration } from '@/components/illustration'
8+
9+
import classes from './not-found.module.css'
10+
11+
const NotFound: React.FC = () => {
12+
return (
13+
<Container className={classes.root}>
14+
<div className={classes.inner}>
15+
<Illustration className={classes.image} />
16+
<div className={classes.content}>
17+
<Title className={classes.title}>Nothing to see here</Title>
18+
<Text c='dimmed' size='lg' ta='center' className={classes.description}>
19+
Page you are trying to open does not exist. The page is in construction.
20+
</Text>
21+
<Group justify='center'>
22+
<Button size='md' component={Link} to={'/budgets'}>
23+
Take me back to budget page
24+
</Button>
25+
</Group>
26+
</div>
27+
</div>
28+
</Container>
29+
)
30+
}
31+
32+
export default NotFound

app/assets/components/sidebar.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState } from 'react'
22

3-
import { Link, useLocation } from '@tanstack/react-router'
3+
import { Link, useLocation } from 'react-router-dom'
44

55
import cx from 'clsx'
66

@@ -63,13 +63,14 @@ export function Sidebar() {
6363
<Link
6464
onClick={() => setColorScheme(computedColorScheme === 'light' ? 'dark' : 'light')}
6565
className={classes.link}
66+
to={''}
6667
>
6768
<IconSun className={cx(classes.light, classes.linkIcon)} stroke={1.5} />
6869
<IconMoon className={cx(classes.dark, classes.linkIcon)} stroke={1.5} />
6970
<span>Change Theme</span>
7071
</Link>
7172

72-
<Link onClick={() => logout()} className={classes.link}>
73+
<Link onClick={() => logout()} className={classes.link} to={''}>
7374
<IconLogout className={classes.linkIcon} stroke={1.5} />
7475
<span>Logout</span>
7576
</Link>

app/assets/contexts/AuthContext.ts

-9
This file was deleted.

app/assets/features/auth/api/auth.ts

+8-21
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import { readLocalStorageValue } from '@mantine/hooks'
2-
31
import { LoginParams, RegisterParams, User } from '@/features/auth/types'
42
import { ApiErrorResponse } from '@/utils/ApiErrorResponse'
53
import { ApiResponse } from '@/utils/ApiResponse'
4+
import { client } from '@/utils/client'
65

76
export async function postLogin(values: LoginParams): Promise<Response | ApiErrorResponse> {
8-
const response = await fetch('/api/login', {
7+
const response = await client('/api/login', {
98
method: 'POST',
10-
headers: {
11-
'Content-Type': 'application/json',
12-
},
139
body: JSON.stringify({
1410
username: values.email,
1511
password: values.password,
@@ -18,15 +14,12 @@ export async function postLogin(values: LoginParams): Promise<Response | ApiErro
1814

1915
if (!response.ok) return Promise.reject('Failed to login')
2016

21-
return await response.json()
17+
return response.json()
2218
}
2319

2420
export async function postRegister(values: RegisterParams): Promise<Response | ApiErrorResponse> {
25-
const response = await fetch('/api/register', {
21+
const response = await client('/api/register', {
2622
method: 'POST',
27-
headers: {
28-
'Content-Type': 'application/json',
29-
},
3023
body: JSON.stringify({
3124
firstName: values.firstName,
3225
lastName: values.lastName,
@@ -37,21 +30,15 @@ export async function postRegister(values: RegisterParams): Promise<Response | A
3730

3831
if (!response.ok) return Promise.reject('Failed to register')
3932

40-
return await response.json()
33+
return response.json()
4134
}
4235

43-
export async function getMe(): Promise<ApiResponse<User>> {
44-
const token = readLocalStorageValue({ key: 'token' }) as string | null
45-
46-
const response = await fetch('/api/users/me', {
36+
export const getMe = async (): Promise<ApiResponse<User>> => {
37+
const response = await client('/api/users/me', {
4738
method: 'GET',
48-
headers: {
49-
'Content-Type': 'application/json',
50-
Authorization: `Bearer ${token}`,
51-
},
5239
})
5340

5441
if (!response.ok) return Promise.reject('Failed to get current user')
5542

56-
return await response.json()
43+
return response.json()
5744
}

app/assets/features/auth/api/index.ts

-1
This file was deleted.

app/assets/features/auth/hooks/useAuth.ts

+9-19
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@ import { useCallback } from 'react'
22

33
import { useMutation } from '@tanstack/react-query'
44

5-
import { useLocalStorage } from '@mantine/hooks'
65
import { notifications } from '@mantine/notifications'
76

87
import { postLogin, postRegister } from '@/features/auth/api/auth'
9-
import { useRouter } from '@tanstack/react-router'
8+
import { useNavigate } from 'react-router-dom'
9+
import { removeUser, saveUser } from './useUserLocalStorage'
1010

1111
export const useAuth = () => {
12-
const [token, setToken] = useLocalStorage({ key: 'token', defaultValue: null })
13-
const [isAuthenticated, setIsAuthenticated] = useLocalStorage({
14-
key: 'isAuthenticated',
15-
defaultValue: false,
16-
})
17-
const router = useRouter()
18-
12+
const navigate = useNavigate()
1913
const login = useCallback((email: string, password: string) => {
2014
authLogin.mutate({ email, password })
2115
}, [])
@@ -35,10 +29,7 @@ export const useAuth = () => {
3529
return
3630
}
3731

38-
setToken(data.token)
39-
setIsAuthenticated(true)
40-
41-
router.invalidate()
32+
saveUser(data)
4233

4334
notifications.show({
4435
withBorder: true,
@@ -47,6 +38,8 @@ export const useAuth = () => {
4738
title: 'Successful Login',
4839
message: 'You are now logged in',
4940
})
41+
42+
navigate('/')
5043
},
5144
onError: (error: Error) => {
5245
console.log('error:', error)
@@ -86,10 +79,7 @@ export const useAuth = () => {
8679
})
8780

8881
const logout = () => {
89-
setToken(null)
90-
setIsAuthenticated(false)
91-
92-
router.invalidate()
82+
removeUser()
9383

9484
notifications.show({
9585
withBorder: true,
@@ -98,13 +88,13 @@ export const useAuth = () => {
9888
title: 'Logout',
9989
message: 'You are now logged out',
10090
})
91+
92+
navigate('/auth/login')
10193
}
10294

10395
return {
10496
login,
10597
logout,
10698
register,
107-
isAuthenticated,
108-
token,
10999
}
110100
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useQuery } from '@tanstack/react-query'
2+
import { getMe } from '../api/auth'
3+
4+
export function useUser() {
5+
const { data: user, isFetching } = useQuery({
6+
queryKey: ['me'],
7+
queryFn: getMe,
8+
})
9+
10+
return { user, isFetching }
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export function saveUser(data: { token: string }): void {
2+
localStorage.setItem('token', data.token)
3+
}
4+
5+
export function removeUser(): void {
6+
localStorage.removeItem('token')
7+
}
8+
9+
export function getUser(): string | null {
10+
return localStorage.getItem('token')
11+
}

app/assets/features/auth/pages/login.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { useForm } from 'react-hook-form'
3+
import { Link } from 'react-router-dom'
34

45
import { zodResolver } from '@hookform/resolvers/zod'
56

@@ -17,10 +18,9 @@ import {
1718
import { useAuth } from '@/features/auth/hooks/useAuth'
1819
import { loginFormSchema, loginFormType } from '@/features/auth/schemas/login'
1920

20-
import { Link } from '@tanstack/react-router'
2121
import classes from './login.module.css'
2222

23-
export const Login = () => {
23+
const Login: React.FC = () => {
2424
const { login } = useAuth()
2525

2626
const loginForm = useForm<loginFormType>({
@@ -42,7 +42,7 @@ export const Login = () => {
4242
</Title>
4343
<Text c='dimmed' size='sm' ta='center' mt={5}>
4444
Do not have an account yet?{' '}
45-
<Anchor size='sm' component={Link} to='/register'>
45+
<Anchor size='sm' component={Link} to='/auth/register'>
4646
Create account
4747
</Anchor>
4848
</Text>
@@ -70,3 +70,5 @@ export const Login = () => {
7070
</Container>
7171
)
7272
}
73+
74+
export default Login

app/assets/features/auth/pages/register.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { useForm } from 'react-hook-form'
3+
import { Link } from 'react-router-dom'
34

45
import { zodResolver } from '@hookform/resolvers/zod'
56

@@ -17,10 +18,9 @@ import {
1718
import { useAuth } from '@/features/auth/hooks/useAuth'
1819
import { registerFormSchema, registerFormType } from '@/features/auth/schemas/register'
1920

20-
import { Link } from '@tanstack/react-router'
2121
import classes from './register.module.css'
2222

23-
export const Register = () => {
23+
const Register: React.FC = () => {
2424
const { register } = useAuth()
2525

2626
const registerForm = useForm<registerFormType>({
@@ -45,7 +45,7 @@ export const Register = () => {
4545
</Title>
4646
<Text c='dimmed' size='sm' ta='center' mt={5}>
4747
Already have an account?{' '}
48-
<Anchor size='sm' component={Link} to='/login'>
48+
<Anchor size='sm' component={Link} to='/auth/login'>
4949
Sign in
5050
</Anchor>
5151
</Text>
@@ -94,3 +94,5 @@ export const Register = () => {
9494
</Container>
9595
)
9696
}
97+
98+
export default Register

app/assets/features/auth/schemas/index.ts

-2
This file was deleted.

app/assets/features/budgets/api/budgets.ts

+6-37
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
import { readLocalStorageValue } from '@mantine/hooks'
2-
31
import { Budget, BudgetDetails, BudgetParams } from '@/features/budgets/types'
42

53
import { ApiErrorResponse } from '@/utils/ApiErrorResponse'
64
import { ApiResponse, ApiResponseList } from '@/utils/ApiResponse'
5+
import { client } from '@/utils/client'
76

87
export async function getBudgetList(): Promise<ApiResponseList<Budget[]>> {
9-
const token = readLocalStorageValue({ key: 'token' }) as string | null
10-
11-
const response = await fetch('/api/budgets', {
8+
const response = await client('/api/budgets', {
129
method: 'GET',
13-
headers: {
14-
'Content-Type': 'application/json',
15-
Authorization: `Bearer ${token}`,
16-
},
1710
})
1811

1912
if (!response.ok) return Promise.reject('Failed to get user budgets')
@@ -22,14 +15,8 @@ export async function getBudgetList(): Promise<ApiResponseList<Budget[]>> {
2215
}
2316

2417
export async function getBudgetDetail(id: string): Promise<ApiResponse<BudgetDetails>> {
25-
const token = readLocalStorageValue({ key: 'token' }) as string | null
26-
27-
const response = await fetch(`/api/budgets/${id}`, {
18+
const response = await client(`/api/budgets/${id}`, {
2819
method: 'GET',
29-
headers: {
30-
'Content-Type': 'application/json',
31-
Authorization: `Bearer ${token}`,
32-
},
3320
})
3421

3522
if (!response.ok) return Promise.reject('Failed to get user budgets')
@@ -38,14 +25,8 @@ export async function getBudgetDetail(id: string): Promise<ApiResponse<BudgetDet
3825
}
3926

4027
export async function postBudget(values: BudgetParams): Promise<Response | ApiErrorResponse> {
41-
const token = readLocalStorageValue({ key: 'token' }) as string | null
42-
43-
const response = await fetch('/api/budgets', {
28+
const response = await client('/api/budgets', {
4429
method: 'POST',
45-
headers: {
46-
'Content-Type': 'application/json',
47-
Authorization: `Bearer ${token}`,
48-
},
4930
body: JSON.stringify({
5031
date: values.date,
5132
incomes: values.incomes,
@@ -59,14 +40,8 @@ export async function postBudget(values: BudgetParams): Promise<Response | ApiEr
5940
}
6041

6142
export async function deleteBudgetId(id: string): Promise<Response | ApiErrorResponse> {
62-
const token = readLocalStorageValue({ key: 'token' }) as string | null
63-
64-
const response = await fetch(`/api/budgets/${id}`, {
43+
const response = await client(`/api/budgets/${id}`, {
6544
method: 'DELETE',
66-
headers: {
67-
'Content-Type': 'application/json',
68-
Authorization: `Bearer ${token}`,
69-
},
7045
})
7146

7247
if (!response.ok) return Promise.reject('Failed to delete budget')
@@ -78,14 +53,8 @@ export async function updateBudgetId(
7853
id: string,
7954
values: BudgetParams,
8055
): Promise<Response | ApiErrorResponse> {
81-
const token = readLocalStorageValue({ key: 'token' }) as string | null
82-
83-
const response = await fetch(`/api/budgets/${id}`, {
56+
const response = await client(`/api/budgets/${id}`, {
8457
method: 'PUT',
85-
headers: {
86-
'Content-Type': 'application/json',
87-
Authorization: `Bearer ${token}`,
88-
},
8958
body: JSON.stringify({
9059
date: values.date,
9160
incomes: values.incomes,

app/assets/features/budgets/api/index.ts

-1
This file was deleted.

0 commit comments

Comments
 (0)