Edit Crud, add loaders during authentication

Took 2 hours 49 minutes
This commit is contained in:
Lucàs
2023-03-26 17:02:24 +02:00
parent 668e092dd3
commit 5cc56e46ec
16 changed files with 3319 additions and 154 deletions
+2006 -1
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -12,6 +12,7 @@
"@chakra-ui/react": "^2.5.1",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@premieroctet/next-crud": "^2.2.0",
"@prisma/client": "^4.11.0",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
+9 -9
View File
@@ -43,15 +43,6 @@ model User {
OtherUserLikes User[] @relation("Likes", fields: [OtherUserLikesID], references: [id])
}
model Chat {
id String @id @default(auto()) @map("_id") @db.ObjectId
messages Message[]
// Les utilisateurs qui ont un chat en commun
User User[] @relation(fields: [UserId], references: [id])
UserId String[] @db.ObjectId
}
model Passion {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
@@ -61,6 +52,15 @@ model Passion {
User User[] @relation(fields: [UserId], references: [id])
}
model Chat {
id String @id @default(auto()) @map("_id") @db.ObjectId
messages Message[]
// Les utilisateurs qui ont un chat en commun
User User[] @relation(fields: [UserId], references: [id])
UserId String[] @db.ObjectId
}
model Message {
id String @id @default(auto()) @map("_id") @db.ObjectId
message String
+9 -4
View File
@@ -16,6 +16,7 @@ import {LoginData} from '@/models/form/LoginData';
export default function LoginForm() {
const router = useRouter();
const [loginData, setLoginData] = useState(new LoginData());
const [isLoading, setIsLoading] = useState(false);
const [invalidInput, setInvalidInput] = useState(false);
const buttonWidth = {base: '100%', md: 'unset'};
@@ -26,11 +27,15 @@ export default function LoginForm() {
};
const handleSubmit = async () => {
await signIn('credentials',
{...loginData, redirect: false}).then((res) => {
setIsLoading(true)
signIn('credentials', {...loginData, redirect: false})
.then((res: unknown) => {
const {ok: connexionSuccess} = res as SignInResponse;
if (!connexionSuccess) setInvalidInput(true);
if (!connexionSuccess) {
setIsLoading(false);
setInvalidInput(true);
}
else router.push('/dashboard');
});
};
@@ -76,7 +81,7 @@ export default function LoginForm() {
justifyContent={'space-between'}>
<Button onClick={() => router.push('/')}
w={buttonWidth}>Retour</Button>
<Button onClick={handleSubmit}
<Button isLoading={isLoading} onClick={handleSubmit}
w={buttonWidth} colorScheme="purple">Connexion</Button>
</Flex>
</Container>
+20 -15
View File
@@ -9,12 +9,13 @@ import {
} from '@chakra-ui/react';
import {useRouter} from 'next/router';
import {useState} from 'react';
import {RegisterData} from '@/models/form/RegisterData';
import {signIn, SignInResponse} from 'next-auth/react';
import {RegisterData} from '@/models/form/RegisterData';
export default function RegisterForm() {
const router = useRouter();
const [registerData, setRegisterData] = useState(new RegisterData());
const [isLoading, setIsLoading] = useState(false);
const [invalidInput, setInvalidInput] = useState(false);
const buttonWidth = {base: '100%', md: 'unset'};
@@ -28,31 +29,34 @@ export default function RegisterForm() {
let {email, firstName, lastName, password, confirmPassword} = registerData;
if (password !== confirmPassword) setInvalidInput(true);
fetch('/api/user', {
method: 'PUT',
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email, firstName, lastName, password}),
}).then(() => {
};
setIsLoading(true);
fetch('/api/users', options).then(() => {
signIn('credentials', {email, password, redirect: false})
.then((res) => {
const {ok: connexionSuccess} = res as SignInResponse;
// TODO If success -> goto interactive form else login
router.push( connexionSuccess ? "/" : "/login");
});
.then((res: unknown) => {
const {ok: connexionSuccess} = res as SignInResponse;
// TODO If success -> goto interactive form else login
router.push(connexionSuccess ? '/' : '/login');
});
}).catch(() => {
setIsLoading(false);
setInvalidInput(true);
setRegisterData({...registerData, password: '', confirmPassword: ''});
});
};
return (
<Box flexBasis={"100%"}>
<Box flexBasis={'100%'}>
<Container>
<Heading textAlign={"center"} size={"2xl"}>Inscription</Heading>
<Heading textAlign={'center'} size={'2xl'}>Inscription</Heading>
<Flex mt={"100px"} mb={'1rem'} gap={5}>
<Flex mt={'100px'} mb={'1rem'} gap={5}>
{/*Prénom*/}
<FormControl>
<FormLabel>Prénom</FormLabel>
@@ -119,8 +123,9 @@ export default function RegisterForm() {
<Flex mt={'50px'} w={'100%'} justify={'space-between'} gap={5}>
<Button onClick={() => router.push('/')} w={buttonWidth}>Retour</Button>
<Button onClick={handleSubmit} w={buttonWidth} colorScheme="purple">Je
<Button onClick={() => router.push('/')}
w={buttonWidth}>Retour</Button>
<Button isLoading={isLoading} onClick={handleSubmit} w={buttonWidth} colorScheme="purple">Je
m&apos;inscris</Button>
</Flex>
</Container>
+1 -1
View File
@@ -6,7 +6,7 @@ export async function hashPassword(unHashedPassword: string): Promise<string> {
export async function isSamePassword(
unHashedPassword: string,
hashedPassword: string
hashedPassword: string,
): Promise<boolean> {
return await bcrypt.compare(unHashedPassword, hashedPassword).
then((result: boolean) => result);
-8
View File
@@ -1,8 +0,0 @@
const CRUD = {
CREATE: "PUT",
READ: "GET",
UPDATE: "POST",
DELETE: "DELETE",
};
export default CRUD;
-16
View File
@@ -1,16 +0,0 @@
type CreateUserQuery = {
email: string
password: string
firstName: string
lastName: string
}
type ReadUserQuery = {
id?: string
}
type DeleteUserQuery = {
id: string
}
export type {CreateUserQuery, ReadUserQuery, DeleteUserQuery};
@@ -1,4 +1,4 @@
import {User} from '@/models/data_models/User';
import type {User} from "@prisma/client";
export type Session = {
user: User
-8
View File
@@ -1,8 +0,0 @@
export type User = {
id: string
email: string
password: string
firstName: string
lastName: string
role: "USER" | "ADMIN"
}
+34
View File
@@ -0,0 +1,34 @@
import NextCrud, {PrismaAdapter} from '@premieroctet/next-crud';
import prismaClient from '@/lib/prismaClient';
import {NextApiRequest, NextApiResponse} from 'next';
import {hashPassword} from '@/lib/PasswordTools';
type CreateUserQuery = {
email: string
password: string
firstName: string
lastName: string
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const nextCrudHandler = await NextCrud({
adapter: new PrismaAdapter({prismaClient: prismaClient}),
});
// Hash le mot de passe quand on crée un utilisateur
if (req.url === "/api/users" && req.method === "POST") {
const {email, password, firstName, lastName} = req.body as CreateUserQuery;
if (!email || !password || !firstName || !lastName)
return res.status(400).send({message: req.body});
const hashedPassword: string = await hashPassword(password);
req.body = {...req.body, password: hashedPassword}
}
return nextCrudHandler(req, res);
}
+18 -11
View File
@@ -3,30 +3,37 @@ import CredentialsProvider from 'next-auth/providers/credentials';
import {NextApiRequest, NextApiResponse} from 'next';
import {LoginData} from '@/models/form/LoginData';
import {isSamePassword} from '@/lib/PasswordTools';
import {User} from '@prisma/client';
import prismaClient from '@/lib/prismaClient';
import {dmmf} from '.prisma/client/edge';
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
const providers = [
CredentialsProvider({
name: 'Credentials',
credentials: {
email: {label: 'Email', type: 'text', placeholder: 'adress@email.com'},
password: {label: 'Password', type: 'password'},
email: {
label: 'Email',
type: 'text',
placeholder: 'adresse@email.com'
},
password: {
label: 'Password',
type: 'password',
placeholder: 'mot de passe',
},
},
async authorize(credentials) {
async authorize(credentials: unknown) {
const {email, password} = credentials as LoginData;
if (!email || !password) return null;
// Appel à la base de donnée
const user = await getUserByEmail(email);
if (!user) return null;
// Vérification de la connexion
if (user && await isSamePassword(password, user.password)) {
return user;
}
return null;
const passwordIsValid = await isSamePassword(password, user.password);
if (passwordIsValid) return user;
else return null;
},
}),
];
@@ -46,8 +53,8 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
});
}
async function getUserByEmail(email: string) {
async function getUserByEmail(email: string): Promise<null | User> {
return prismaClient.user.findUnique({
where: {email},
where: {email}
});
}
-51
View File
@@ -1,51 +0,0 @@
import type {NextApiRequest, NextApiResponse} from 'next';
import CRUD from '@/models/api/CRUD';
import {CreateUserQuery} from '@/models/api/UserQuery';
import {hashPassword} from '@/lib/PasswordTools';
import prismaClient from '@/lib/prismaClient';
export default function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
switch (req.method) {
case CRUD.CREATE:
return createUser(req, res);
case CRUD.READ:
return readUser(req, res);
default:
return help(res);
}
}
function help(res: NextApiResponse) {
res.status(400).send({message: 'error'}); // TODO add help message
}
const prisma = prismaClient;
async function createUser(req: NextApiRequest, res: NextApiResponse) {
const {email, password, firstName, lastName} = req.body as CreateUserQuery;
if (!email || !password || !firstName || !lastName)
return res.status(400).send({message: req.body});
const hashedPassword = await hashPassword(password);
const newUser = await prisma.user.create({
data: {...req.body, password: hashedPassword},
});
return res.status(201).send({message: 'createUser', newUser});
}
async function readUser(req: NextApiRequest, res: NextApiResponse) {
const {id, email} = req.query as { id: string, email: string };
const user = (id)
? await prisma.user.findUnique({where: {id}})
: await prisma.user.findMany()
;
return res.status(200).send({message: 'readUser', user});
}
+1 -1
View File
@@ -2,7 +2,7 @@ import {Grid, GridItem, Text, Box} from '@chakra-ui/react';
import {useSession} from 'next-auth/react';
import {useRouter} from 'next/router';
import type {Session} from '@/models/data_models/Session';
import type {Session} from '@/models/auth/Session';
import CardUser from '../components/layout/dashboard/card_user/CardUser';
import LeftPanel from '../components/layout/dashboard/left_panel/LeftPanel';
import Head from 'next/head';
+1 -1
View File
@@ -10,7 +10,7 @@ export default function Home() {
<>
<Head><title>{websiteName}</title></Head>
<Navbar/>
<Navbar variant={"fixed"}/>
<HeroBanner/>
<HomePresentation/>
</>
+1218 -27
View File
File diff suppressed because it is too large Load Diff