fix: add types and cleanup code

This commit is contained in:
Lucàs
2023-04-11 22:02:33 +02:00
parent 7b6733bc09
commit 66d20e156d
4 changed files with 163 additions and 187 deletions
+138 -141
View File
@@ -8,12 +8,12 @@ import {
Input, Input,
Container, Container,
FormErrorMessage, FormErrorMessage,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useRouter } from "next/router"; import {useRouter} from 'next/router';
import { useState } from "react"; import {useState} from 'react';
import { signIn, SignInResponse } from "next-auth/react"; import {signIn, SignInResponse} from 'next-auth/react';
import { RegisterData } from "@/models/form/RegisterData"; import {RegisterData} from '@/models/form/RegisterData';
import { useForm } from "react-hook-form"; import {SubmitHandler, useForm} from 'react-hook-form';
export default function RegisterForm() { export default function RegisterForm() {
const router = useRouter(); const router = useRouter();
@@ -22,25 +22,23 @@ export default function RegisterForm() {
handleSubmit, handleSubmit,
register, register,
watch, watch,
formState: { errors, isSubmitting }, formState: {errors, isSubmitting},
} = useForm(); } = useForm();
const buttonWidth = { base: "100%", md: "unset" };
const validateDate = (value: string) => { const validateDate = (value: string) => {
const selected = new Date(value).getFullYear(); const selected = new Date(value).getFullYear();
const now = new Date().getFullYear(); const now = new Date().getFullYear();
return now - selected >= 18 || "Vous devez avoir 18 ans ou plus"; return now - selected >= 18 || 'Vous devez avoir 18 ans ou plus';
}; };
const registerUser = (values: RegisterData) => { const submitHandler: SubmitHandler<any> = (values: RegisterData) => {
let { email, firstName, lastName, birthdate, password, confirmPassword } = let {email, firstName, lastName, birthdate, password, confirmPassword} =
values; values;
const date = new Date(birthdate); const date = new Date(birthdate);
const options = { const options = {
method: "POST", method: 'POST',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
email, email,
firstName, firstName,
@@ -50,143 +48,142 @@ export default function RegisterForm() {
}), }),
}; };
fetch("/api/users", options) fetch('/api/users', options).then(() => {
.then(() => { signIn('credentials', {email, password, redirect: false}).then(
signIn("credentials", { email, password, redirect: false }).then(
(res: unknown) => { (res: unknown) => {
const { ok: connexionSuccess } = res as SignInResponse; const {ok: connexionSuccess} = res as SignInResponse;
// TODO If success -> goto interactive form else login // TODO If success -> goto interactive form else login
router.push(connexionSuccess ? "/dashboard" : "/"); router.push(connexionSuccess ? '/dashboard' : '/');
} },
); );
}) }).catch((err) => console.error(err));
.catch(() => {});
}; };
return ( return (
<Box flexBasis={"100%"}> <Box flexBasis={'100%'}>
<Container> <Container>
<form id="register_form" onSubmit={handleSubmit(registerUser)}> <form id="register_form" onSubmit={handleSubmit(submitHandler)}>
<Heading textAlign={"center"} size={"2xl"}> <Heading textAlign={'center'} size={'2xl'}>
Inscription Inscription
</Heading> </Heading>
<Flex mt={"100px"} mb={"1rem"} gap={5}> <Flex mt={'100px'} mb={'1rem'} gap={5}>
{/*Prénom*/} {/*Prénom*/}
<FormControl id="firstName" isInvalid={errors.firstName}> <FormControl id="firstName" isInvalid={errors.firstName as boolean|undefined}>
<FormLabel>Prénom</FormLabel> <FormLabel>Prénom</FormLabel>
<Input
type="text"
placeholder="Prénom"
{...register('firstName', {
required: {value: true, message: 'Prénom requis'},
})}
/>
<FormErrorMessage>{errors.firstName?.message as string}</FormErrorMessage>
</FormControl>
{/*Nom*/}
<FormControl id="lastName" isInvalid={errors.lastName as boolean|undefined}>
<FormLabel>Nom</FormLabel>
<Input
type="text"
placeholder="Nom"
{...register('lastName', {
required: {value: true, message: 'Nom requis'},
})}
/>
<FormErrorMessage>{errors.lastName?.message as string}</FormErrorMessage>
</FormControl>
</Flex>
{/*Email*/}
<FormControl mb={'1rem'} id={'email'} isInvalid={errors.email as boolean|undefined}>
<FormLabel>Adresse email</FormLabel>
<Input <Input
type="text" type="text"
placeholder="Prénom" {...register('email', {
{...register("firstName", { required: {value: true, message: 'Adresse email requise'},
required: { value: true, message: "Prénom requis" }, pattern: {
})} value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Adresse email invalide',
},
})}
placeholder="adresse@email.com"
/> />
<FormErrorMessage>{errors.firstName?.message}</FormErrorMessage> <FormErrorMessage>{errors.email?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
{/*Nom*/} {/*Date de naissance*/}
<FormControl id="lastName" isInvalid={errors.lastName}> <FormControl
<FormLabel>Nom</FormLabel> mb={'1rem'}
<Input id={'birthdate'}
type="text" isInvalid={errors.birthdate as boolean|undefined}
placeholder="Nom"
{...register("lastName", {
required: { value: true, message: "Nom requis" },
})}
/>
<FormErrorMessage>{errors.lastName?.message}</FormErrorMessage>
</FormControl>
</Flex>
{/*Email*/}
<FormControl mb={"1rem"} id={"email"} isInvalid={errors.email}>
<FormLabel>Adresse email</FormLabel>
<Input
type="text"
{...register("email", {
required: { value: true, message: "Adresse email requise" },
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "Adresse email invalide",
},
})}
placeholder="adresse@email.com"
/>
<FormErrorMessage>{errors.email?.message}</FormErrorMessage>
</FormControl>
{/*Date de naissance*/}
<FormControl
mb={"1rem"}
id={"birthdate"}
isInvalid={errors.birthdate}
>
<FormLabel>Date de naissance</FormLabel>
<Input
type="date"
{...register("birthdate", {
required: { value: true, message: "Date de naissance requise" },
validate: validateDate,
})}
/>
<FormErrorMessage>{errors.birthdate?.message}</FormErrorMessage>
</FormControl>
{/*Mot de passe*/}
<FormControl mb={"1rem"} id="password" isInvalid={errors.password}>
<FormLabel>Mot de passe</FormLabel>
<Input
type="password"
placeholder="Mot de passe"
{...register("password", {
required: { value: true, message: "Mot de passe requis" },
})}
/>
<FormErrorMessage>{errors.password?.message}</FormErrorMessage>
</FormControl>
{/*Mot de passe (2)*/}
<FormControl
mb={"1rem"}
id="confirmPassword"
isInvalid={errors.confirmPassword}
>
<FormLabel>Confirmation du mot de passe</FormLabel>
<Input
type="password"
placeholder="Mot de passe"
{...register("confirmPassword", {
required: { value: true, message: "Confirmation requise" },
validate: (value: string) => {
return (
watch("password") === value ||
"Les mots de passe ne correspondent pas"
);
},
})}
/>
<FormErrorMessage>
{errors.confirmPassword?.message}
</FormErrorMessage>
</FormControl>
<Flex mt={"50px"} w={"100%"} justify={"space-between"} gap={5}>
<Button onClick={() => router.push("/")} w={buttonWidth}>
Retour
</Button>
<Button
isLoading={isSubmitting}
w={buttonWidth}
colorScheme="purple"
type="submit"
> >
Je m&apos;inscris <FormLabel>Date de naissance</FormLabel>
</Button> <Input
</Flex> type="date"
</form> {...register('birthdate', {
</Container> required: {
</Box> value: true,
message: 'Date de naissance requise',
},
validate: validateDate,
})}
/>
{ (errors.birthdate) ? <FormErrorMessage>{errors.birthdate.message as string}</FormErrorMessage> : "" }
</FormControl>
{/*Mot de passe*/}
<FormControl mb={'1rem'} id="password" isInvalid={errors.password as boolean|undefined}>
<FormLabel>Mot de passe</FormLabel>
<Input
type="password"
placeholder="Mot de passe"
{...register('password', {
required: {value: true, message: 'Mot de passe requis'},
})}
/>
<FormErrorMessage>{errors.password?.message as string}</FormErrorMessage>
</FormControl>
{/*Mot de passe (2)*/}
<FormControl
mb={'1rem'}
id="confirmPassword"
isInvalid={errors.confirmPassword as boolean|undefined}
>
<FormLabel>Confirmation du mot de passe</FormLabel>
<Input
type="password"
placeholder="Mot de passe"
{...register('confirmPassword', {
required: {value: true, message: 'Confirmation requise'},
validate: (value: string) => {
return (
watch('password') === value ||
'Les mots de passe ne correspondent pas'
);
},
})}
/>
<FormErrorMessage>{errors.confirmPassword?.message as string}</FormErrorMessage>
</FormControl>
<Flex mt={'50px'} w={'100%'} justify={'space-between'} gap={5}>
<Button onClick={() => router.push('/')} w={{base: '100%', md: 'unset'}}>
Retour
</Button>
<Button
isLoading={isSubmitting}
w={{base: '100%', md: 'unset'}}
colorScheme="purple"
type="submit"
>
Je m&apos;inscris
</Button>
</Flex>
</form>
</Container>
</Box>
); );
} }
+9 -15
View File
@@ -1,9 +1,11 @@
import NextAuth from 'next-auth'; import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials'; import CredentialsProvider from 'next-auth/providers/credentials';
import {NextApiRequest, NextApiResponse} from 'next'; import {NextApiRequest, NextApiResponse} from 'next';
import {LoginData} from '@/models/form/LoginData'; import {LoginData} from '@/models/form/LoginData';
import {isSamePassword} from '@/lib/PasswordTools'; import {isSamePassword} from '@/lib/PasswordTools';
import {User} from '@prisma/client';
import type {User} from '@prisma/client';
import prismaClient from '@/lib/prismaClient'; import prismaClient from '@/lib/prismaClient';
export default async function auth(req: NextApiRequest, res: NextApiResponse) { export default async function auth(req: NextApiRequest, res: NextApiResponse) {
@@ -11,27 +13,19 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
CredentialsProvider({ CredentialsProvider({
name: 'Credentials', name: 'Credentials',
credentials: { credentials: {
email: { email: {label: 'Email', type: 'text'},
label: 'Email', password: {label: 'Password', type: 'password'},
type: 'text',
placeholder: 'adresse@email.com'
},
password: {
label: 'Password',
type: 'password',
placeholder: 'mot de passe',
},
}, },
async authorize(credentials: unknown) { async authorize(credentials: unknown) {
const {email, password} = credentials as LoginData; const {email, password} = credentials as LoginData;
if (!email || !password) return null; if (!email || !password) return null;
// Appel à la base de donnée // Appel à la base de donnée
const user = await getUserByEmail(email); const user: User | null = await getUserByEmail(email);
if (!user) return null; if (!user) return null;
// Vérification de la connexion // Vérification de la connexion
const passwordIsValid = await isSamePassword(password, user.password); const passwordIsValid: boolean = await isSamePassword(password, user.password);
if (passwordIsValid) return user; if (passwordIsValid) return user;
else return null; else return null;
}, },
@@ -46,7 +40,7 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
signOut: '/auth/signout', signOut: '/auth/signout',
error: '/auth/error', error: '/auth/error',
verifyRequest: '/auth/verify-request', verifyRequest: '/auth/verify-request',
newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest) newUser: '/auth/new-user', // New users will be directed here on first sign in (leave the property out if not of interest)
}, },
secret: process.env.NEXTAUTH_SECRET, secret: process.env.NEXTAUTH_SECRET,
callbacks: { callbacks: {
@@ -62,6 +56,6 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
async function getUserByEmail(email: string): Promise<null | User> { async function getUserByEmail(email: string): Promise<null | User> {
return prismaClient.user.findUnique({ return prismaClient.user.findUnique({
where: {email} where: {email},
}); });
} }
+7 -12
View File
@@ -1,10 +1,10 @@
import {Server} from 'socket.io'; import {Server} from 'socket.io';
import prismaClient from '@/lib/prismaClient'; import prismaClient from '@/lib/prismaClient';
import type {Chat, Message as Message} from '@prisma/client';
export default async function SocketHandler(req: any, res: any) { export default async function SocketHandler(req: any, res: any) {
const {id: chatId} = req.query; const {id: chatId} = req.query;
// It means that socket server was already initialised
if (res.socket.server.io) { if (res.socket.server.io) {
console.log('Already set up'); console.log('Already set up');
res.end(); res.end();
@@ -14,17 +14,13 @@ export default async function SocketHandler(req: any, res: any) {
const io = new Server(res.socket.server); const io = new Server(res.socket.server);
res.socket.server.io = io; res.socket.server.io = io;
// Define actions inside io.on('connection', async (socket): Promise<void> => {
io.on('connection', async (socket) => {
console.log(socket.id);
await prismaClient.chat.findFirst({ await prismaClient.chat.findFirst({
where: {id: chatId}, where: {id: chatId}, include: {Message: true},
include: {Message: true}, }).then((chat: (Chat & { Message: Message[] }) | null) =>
}).then(chat => { {if (chat) socket.emit('allOldMessages', chat.Message)}
// @ts-ignore );
return socket.emit('allOldMessages', chat.Message);
});
socket.on('createdMessage', async (msgInput) => { socket.on('createdMessage', async (msgInput) => {
await prismaClient.message.create({ await prismaClient.message.create({
@@ -33,10 +29,9 @@ export default async function SocketHandler(req: any, res: any) {
User: {connect: {id: msgInput.sender}}, User: {connect: {id: msgInput.sender}},
Chat: {connect: {id: chatId}}, Chat: {connect: {id: chatId}},
}, },
}).then((newMessage) => socket.emit('newIncomingMessage', newMessage)); }).then((newMessage: Message) => socket.emit('newIncomingMessage', newMessage));
}); });
}); });
console.log('Setting up socket');
res.end(); res.end();
} }
+9 -19
View File
@@ -3,12 +3,12 @@ import Head from 'next/head';
import {websiteName} from '@/lib/constants'; import {websiteName} from '@/lib/constants';
import {useSession} from 'next-auth/react'; import {useSession} from 'next-auth/react';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {useCallback, useEffect, useState} from 'react'; import {useEffect, useState} from 'react';
import MessageList from '@/components/chat/MessageList'; import MessageList from '@/components/chat/MessageList';
import {io, Socket} from 'socket.io-client'; import {io, Socket} from 'socket.io-client';
import {Message} from '@prisma/client'; import {Message, User} from '@prisma/client';
export default function ChatId() { export default function ChatId() {
const router = useRouter(); const router = useRouter();
@@ -26,22 +26,13 @@ export default function ChatId() {
const socketInitializer = async () => { const socketInitializer = async () => {
await fetch(`/api/socket/chat/${chatId}`) await fetch(`/api/socket/chat/${chatId}`)
const soc = io() const soc = io();
soc.on('connect', () => { soc.on('connect', () => console.log('connected'))
console.log('connected') soc.on("allOldMessages", (allOldMessages: Message[]) => setMessages(allOldMessages))
}) soc.on("newIncomingMessage", (newIncomingMessage: Message) =>
setMessages(messages => [...messages, newIncomingMessage])
soc.on("allOldMessages", (allOldMessages: Message[]) => { );
console.log("allOldMessages", allOldMessages);
setMessages(allOldMessages);
})
soc.on("newIncomingMessage", (newIncomingMessage: Message) => {
console.log("newIncomingMessage", newIncomingMessage);
console.log("messages", messages);
setMessages(messages => ([...messages, newIncomingMessage]));
});
setSocket(soc); setSocket(soc);
} }
@@ -50,7 +41,6 @@ export default function ChatId() {
const handleSubmit = () => { const handleSubmit = () => {
if (text !== "" && socket) { if (text !== "" && socket) {
// @ts-ignore
socket.emit("createdMessage", {text, sender: session.user.id}) socket.emit("createdMessage", {text, sender: session.user.id})
setText(""); setText("");
} }
@@ -62,7 +52,7 @@ export default function ChatId() {
<Head><title>{websiteName}</title></Head> <Head><title>{websiteName}</title></Head>
<Container> <Container>
<MessageList user={session.user} messages={messages}/> <MessageList user={session.user as User} messages={messages}/>
<Flex gap={5} mt={5}> <Flex gap={5} mt={5}>
<Input type={"text"} colorScheme={'purple'} onChange={(evt) => setText(evt.target.value) } value={text} /> <Input type={"text"} colorScheme={'purple'} onChange={(evt) => setText(evt.target.value) } value={text} />