Create User Login/Logout

Took 3 hours 40 minutes
This commit is contained in:
Lucàs
2023-03-22 15:36:20 +01:00
parent f1e39e12e9
commit 843b5fcda8
18 changed files with 3351 additions and 2620 deletions
+46 -49
View File
@@ -1,58 +1,55 @@
import { Box, Flex, Text, ButtonGroup, Button } from "@chakra-ui/react";
import { useRouter } from "next/router";
import {Box, Flex, Text, ButtonGroup, Button} from '@chakra-ui/react';
import {useRouter} from 'next/router';
import {signOut, useSession} from 'next-auth/react';
export default function Navbar() {
const router = useRouter();
const {data: session, status} = useSession();
const redirect_connexion = () => {
router.push("/login");
const RightSection = () => {
if (status === "authenticated" && session.user) return (
<Flex justify={'right'} flexBasis={'100%'}>
<Text>{session.user.email}</Text>
<ButtonGroup>
<Button colorScheme={'purple'} onClick={() => signOut()}>
Déconnexion
</Button>
</ButtonGroup>
</Flex>
);
else return (
<Flex justify={'right'} flexBasis={'100%'}>
<ButtonGroup>
<Button
onClick={() => router.push('/register')}>Inscription</Button>
<Button colorScheme={'purple'}
onClick={() => router.push('/login')}>
Connexion
</Button>
</ButtonGroup>
</Flex>
);
};
const redirect_inscription = () => {
router.push("/register");
};
const LeftContent = () => (
<Box flexBasis={"100%"}>
<Text>Logo</Text>
</Box>
);
const CenterContent = () => (
<Flex gap={5} justify={"center"} flexBasis={"100%"}>
<Text>A propos</Text>
<Text>Contact</Text>
<Text>Aide</Text>
</Flex>
);
const RightContent = () => (
<Flex justify={"right"} flexBasis={"100%"}>
<ButtonGroup>
<Button onClick={redirect_inscription}>Inscription</Button>
<Button colorScheme={"purple"} onClick={redirect_connexion}>
Connexion
</Button>
</ButtonGroup>
</Flex>
);
return (
<Box
position={"fixed"}
zIndex={9999}
top={0}
width={"100vw"}
backdropFilter={"auto"}
backdropBlur={"20px"}
px={10}
py={2}
>
<Flex align={"center"}>
<LeftContent />
<CenterContent />
<RightContent />
</Flex>
</Box>
<Box position={'fixed'} zIndex={9999} top={0} width={'100vw'}
backdropFilter={'auto'} backdropBlur={'20px'} px={10} py={2}>
<Flex align={'center'}>
<Box flexBasis={'100%'}>
<Text>Logo</Text>
</Box>
<Flex gap={5} justify={'center'} flexBasis={'100%'}>
<Text>A propos</Text>
<Text>Contact</Text>
<Text>Aide</Text>
</Flex>
<RightSection/>
</Flex>
</Box>
);
}
-24
View File
@@ -1,24 +0,0 @@
import { createContext, useContext, useState } from "react";
// faudra récuperer les users de la base de données
const UsersContext = createContext(null);
export const UsersProvider = ({ children }) => {
const [users, setUsers] = useState(users);
return (
<UserContext.Provider value={{ users, setUsers }}>
{children}
</UserContext.Provider>
);
};
export const useUser = () => {
const usersState = useContext(UsersContext);
if (!usersState) {
throw new Error("useUsers must be used within a UsersProvider");
}
return usersState;
};
+87
View File
@@ -0,0 +1,87 @@
import {
Box, Button,
Flex,
FormControl,
FormLabel,
Heading,
Input,
Container,
} from '@chakra-ui/react';
import {useState} from 'react';
import {useRouter} from 'next/router';
import {signIn, SignInResponse,} from 'next-auth/react';
import {LoginData} from '@/models/form/LoginData';
export default function LoginForm() {
const router = useRouter();
const [loginData, setLoginData] = useState(new LoginData());
const [invalidInput, setInvalidInput] = useState(false);
const buttonWidth = {base: '100%', md: 'unset'};
const handleInput = ({email = loginData.email, password = loginData.password}) => {
setInvalidInput(false);
setLoginData(new LoginData(email, password));
};
const handleSubmit = async () => {
const {email, password} = loginData;
await signIn('credentials',
{email, password, redirect: false})
.then((res) => {
const {ok} = res as SignInResponse
if (!ok) setInvalidInput(true)
else router.push("/")
});
};
return (
<Box flexBasis={'100%'}>
<Container>
<Heading textAlign={'center'} size={'2xl'}>Connexion</Heading>
{/* Email */}
<FormControl mt={'100px'} isInvalid={invalidInput}>
<Box mb={'1rem'}>
<FormLabel>Adresse email</FormLabel>
<Input
isInvalid={invalidInput}
id={'email'}
type={'email'}
value={loginData.email}
onChange={(evt) => handleInput({email: evt.target.value})}
placeholder={'adresse@email.com'}
required={true}
/>
</Box>
{/* Mot de passe */}
<Box mb={'1rem'}>
<FormLabel>Mot de passe</FormLabel>
<Input
isInvalid={invalidInput}
id={'password'}
type={'password'}
value={loginData.password}
onChange={(evt) => handleInput({password: evt.target.value})}
placeholder={'Mot de passe'}
required={true}
/>
</Box>
{/*Boutons*/}
<Flex justify={'center'} mt={'50px'} gap={5}
justifyContent={'space-between'}>
<Button onClick={() => router.push('/')}
w={buttonWidth}>Retour</Button>
<Button onClick={handleSubmit}
w={buttonWidth} colorScheme="purple">Connexion</Button>
</Flex>
</FormControl>
</Container>
</Box>
);
}
@@ -21,13 +21,7 @@ export default function HomeHero() {
);
const LeftSide = () => (
<Box flexBasis={"100%"}>
<Image
boxShadow={"lg"}
minH={"100vh"}
src={"/couple_funny.png"}
alt="funny couple"
/>
<Box flexBasis={"100%"} minH={"100vh"} bgImage={"/couple_funny.png"} bgSize={'cover'} bgPos={"center"}>
</Box>
);
+7
View File
@@ -0,0 +1,7 @@
export class LoginData {
constructor(
public email: string = "",
public password: string = ""
) {}
}
+5 -2
View File
@@ -1,11 +1,14 @@
import '@/styles/globals.css';
import type {AppProps} from 'next/app';
import {ChakraProvider} from '@chakra-ui/react';
import { SessionProvider } from "next-auth/react"
export default function App({Component, pageProps}: AppProps) {
export default function App({Component, pageProps: { session, ...pageProps }}: AppProps) {
return (
<ChakraProvider>
<Component {...pageProps} />
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
</ChakraProvider>
);
}
+49
View File
@@ -0,0 +1,49 @@
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials";
import {PrismaClient} from '@prisma/client';
import {NextApiRequest, NextApiResponse} from 'next';
import {LoginData} from '@/models/form/LoginData';
const prisma = new PrismaClient();
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" }
},
async authorize(credentials) {
const {email, password} = credentials as LoginData;
if (!email || !password) return null;
// Appel à la base de donnée
const user = await prisma.user.findUnique({
where: {email}
});
// Vérification de la connexion
if (user && user.password === password) return user;
return null;
},
})
];
return await NextAuth(req, res, {
providers,
session: {strategy: "jwt",},
secret: process.env.NEXTAUTH_SECRET,
callbacks: {
async session({ session, token }: { session: any; token: any }) {
const user = await prisma.user.findFirst({
where: { email: session.user.email }
});
session.token = token.sub
session.user = user
return session
},
},
})
}
-18
View File
@@ -1,18 +0,0 @@
import {NextApiRequest, NextApiResponse} from 'next';
import { PrismaClient } from '@prisma/client'
import type {CreateUserQuery} from '@/models/api/user';
const prisma = new PrismaClient();
export default 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 newUser = await prisma.user.create({
data: {email, password, firstName, lastName},
});
return res.status(201).send({message: "createUser", newUser});
}
-15
View File
@@ -1,15 +0,0 @@
import {NextApiRequest, NextApiResponse} from 'next';
import { PrismaClient } from '@prisma/client'
import type {DeleteUserQuery} from '@/models/api/user';
const prisma = new PrismaClient();
export default async function deleteUser(req: NextApiRequest, res: NextApiResponse) {
const {id} = req.query as DeleteUserQuery
if (!id) return res.status(400).send({message: "error"});
const deletedUser = await prisma.user.delete({
where: { id }
});
return res.status(200).send({message: "deleteUser", deletedUser});
}
+7 -10
View File
@@ -1,5 +1,4 @@
import type {NextApiRequest, NextApiResponse} from 'next';
import updateUser from '@/pages/api/user/updateUser';
import CRUD from '@/utils/CRUD';
import {CreateUserQuery, DeleteUserQuery} from '@/models/api/user';
import {PrismaClient} from '@prisma/client';
@@ -8,13 +7,13 @@ export default function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const {method} = req;
if (method === CRUD.CREATE) return createUser(req, res);
if (method === CRUD.READ) return readUser(req, res);
if (method === CRUD.UPDATE) return updateUser(req, res);
if (method === CRUD.DELETE) return deleteUser(req, res);
return help(res);
switch (req.method) {
case CRUD.CREATE: return createUser(req, res);
case CRUD.READ: return readUser(req, res);
// case CRUD.UPDATE: return updateUser(req, res);
case CRUD.DELETE: return deleteUser(req, res);
default: return help(res);
}
}
function help(res: NextApiResponse) {
@@ -35,7 +34,6 @@ async function createUser(req: NextApiRequest, res: NextApiResponse) {
return res.status(201).send({message: 'createUser', newUser});
}
async function deleteUser(req: NextApiRequest, res: NextApiResponse) {
const {id} = req.query as DeleteUserQuery;
if (!id) return res.status(400).send({message: 'error'});
@@ -45,7 +43,6 @@ async function deleteUser(req: NextApiRequest, res: NextApiResponse) {
});
return res.status(200).send({message: 'deleteUser', deletedUser});
}
async function readUser(req: NextApiRequest, res: NextApiResponse) {
const users = await prisma.user.findMany();
-24
View File
@@ -1,24 +0,0 @@
import { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export default async function readUser(
req: NextApiRequest,
res: NextApiResponse
) {
const { email, password } = req.query;
if (!email && !password) {
const users = await prisma.user.findMany();
return res.status(200).send({ message: "readUser", users });
}
const user = await prisma.user.findUnique({ where: { email: email } });
if (user?.password == password) {
res.status(200).send({ message: "User found", user });
}
res.status(400).send({ message: "Mot de passe incorrect" });
}
-5
View File
@@ -1,5 +0,0 @@
import {NextApiRequest, NextApiResponse} from 'next';
export default function updateUser(req: NextApiRequest, res: NextApiResponse) {
return res.status(200).send({message: "updateUser"}); // TODO
}
-114
View File
@@ -1,114 +0,0 @@
import {
Box,
Button,
Flex,
FormControl,
FormLabel,
Heading,
Image,
Input,
Spacer,
} from "@chakra-ui/react";
import { useRouter } from "next/router";
import { useForm } from "react-hook-form";
export default function Login() {
const {
handleSubmit,
register,
formState: { errors, isSubmitting },
} = useForm();
const router = useRouter();
const onLogin = async (values) => {
try {
const response = await fetch(`/api/user/?email=${values.email}&password=${values.password}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const data = await response.json();
if (data.error) {
alert(data.message);
} else {
console.log(data);
alert("connexion réussie");
// router.push("/");
}
} catch (error) {
console.log(error);
}
};
const redirect_home = () => {
router.push("/");
};
const RightSide = () => (
<Flex
justify={"center"}
direction={"column"}
flexBasis={"100%"}
align={"center"}
>
<Heading mb={"2.5rem"}>Connexion</Heading>
<Box w={"25vw"}>
<form onSubmit={handleSubmit(onLogin)}>
<FormControl isInvalid={errors.name}>
<Box mb={"1rem"}>
<FormLabel>Adresse email</FormLabel>
<Input
id="email"
type="email"
placeholder="Adresse@email.com"
{...register("email", {
required: "This is required",
})}
/>
</Box>
<Box mb={"1rem"}>
<FormLabel>Mot de passe</FormLabel>
<Input
id="password"
type="password"
placeholder="Mot de passe"
{...register("password", {
required: "This is required",
})}
/>
</Box>
<Flex mt={"1rem"} w={"100%"}>
<Button onClick={redirect_home}>Retour</Button>
<Spacer />
<Button colorScheme="purple" type="submit">
Connexion
</Button>
</Flex>
</FormControl>
</form>
</Box>
</Flex>
);
const LeftSide = () => (
<Box flexBasis={"100%"}>
<Image
h={"100vh"}
w={"100%"}
src={"/couple_horizon.png"}
alt="couple looking at horizon"
/>
</Box>
);
return (
<Box>
<Flex gap={10}>
<LeftSide />
<RightSide />
</Flex>
</Box>
);
}
+11 -92
View File
@@ -1,102 +1,21 @@
import {
Box,
Button,
Flex,
FormControl,
FormLabel,
Heading,
Image,
Input,
Spacer,
} from '@chakra-ui/react';
import {useRouter} from 'next/router';
import {useForm} from 'react-hook-form';
import LoginForm from '@/components/form/LoginForm';
type FormValues = {
email: string
password: string
}
export default function Login() {
const {
handleSubmit,
register,
formState: {errors, isSubmitting},
} = useForm();
const router = useRouter();
const onLogin = async (values: FormValues) => {
alert(JSON.stringify(values, null, 2));
// faut voir ce qu'on fait quand on se connecte
};
const goHome = () => {
router.push('/');
};
const RightSide = () => (
<Flex
justify={'center'}
direction={'column'}
flexBasis={'100%'}
align={'center'}
>
<Heading mb={'2.5rem'}>Connexion</Heading>
<Box w={'25vw'}>
<form onSubmit={handleSubmit(onLogin)}>
<FormControl isInvalid={errors.name}>
<Box mb={'1rem'}>
<FormLabel>Adresse email</FormLabel>
<Input
id="email"
type="email"
placeholder="Adresse@email.com"
{...register('email', {
required: 'This is required',
})}
/>
</Box>
<Box mb={'1rem'}>
<FormLabel>Mot de passe</FormLabel>
<Input
id="pwd"
type="password"
placeholder="Mot de passe"
{...register('password', {
required: 'This is required',
})}
/>
</Box>
<Flex mt={'1rem'} w={'100%'}>
<Button onClick={goHome}>Retour</Button>
<Spacer/>
<Button colorScheme="purple" type="submit">Connexion</Button>
</Flex>
</FormControl>
</form>
</Box>
return (
<Flex gap={5} h={'100vh'} justify={'center'} alignItems={'center'}>
<Box flexBasis={'100%'}
display={{base: "none", md: "block"}}
h={"100%"}
bgImage={'/couple_horizon.png'}
bgSize={'cover'}
bgPos={'center'}
/>
<LoginForm/>
</Flex>
);
const LeftSide = () => (
<Box flexBasis={'100%'}>
<Image
h={'100vh'}
w={'100%'}
src={'/couple_horizon.png'}
alt="couple looking at horizon"
/>
</Box>
);
return (
<Box>
<Flex gap={10}>
<LeftSide/>
<RightSide/>
</Flex>
</Box>
);
}