password reset implementation;
custom signin form
This commit is contained in:
135
pages/auth/reset-password.tsx
Normal file
135
pages/auth/reset-password.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
import { use, useEffect, useState } from 'react';
|
||||
import Layout from '../../components/layout';
|
||||
import axiosInstance from "../../src/axiosSecure";
|
||||
import common from '../../src/helpers/common';
|
||||
import { EventLogType } from '@prisma/client';
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function ResetPassword(req, res) {
|
||||
const [email, setEmail] = useState('');
|
||||
const [message, setMessage] = useState('');
|
||||
const [resetToken, setResetToken] = useState(req.query?.resetToken || '');
|
||||
const [isConfirmed, setIsConfirmed] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
useEffect(async () => {
|
||||
if (resetToken) {
|
||||
const prisma = common.getPrismaClient();
|
||||
let eventLog = await prisma.eventLog.findUnique({
|
||||
where: {
|
||||
content: resetToken,
|
||||
type: EventLogType.PasswordResetEmailConfirmed,
|
||||
date: {
|
||||
gt: new Date(new Date().getTime() - 24 * 60 * 60 * 1000) //24 hours
|
||||
}
|
||||
}
|
||||
});
|
||||
if (eventLog) {
|
||||
setIsConfirmed(true);
|
||||
}
|
||||
}
|
||||
}, [resetToken]);
|
||||
|
||||
const handleResetRequest = async (event) => {
|
||||
event.preventDefault();
|
||||
// Call your email API endpoint here
|
||||
try {
|
||||
const response = await axiosInstance.post('/api/email?action=account&emailaction=resetPassword', { email },
|
||||
{ headers: { 'Content-Type': 'application/json' } });
|
||||
if (response.data.message) {
|
||||
setMessage(response.data.message);
|
||||
} else {
|
||||
if (response.ok) {
|
||||
setMessage('Провери твоя имейл за инструкции как да промениш паролата си.');
|
||||
} else {
|
||||
if (response.error) {
|
||||
setMessage(response.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setMessage(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const setNewPassword = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
const prisma = common.getPrismaClient();
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
email
|
||||
}
|
||||
});
|
||||
if (!user) {
|
||||
throw new Error('Няма потребител с този имейл.');
|
||||
}
|
||||
|
||||
const passHash = await crypto.hash(event.target.newPassword.value, 10);
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
email
|
||||
},
|
||||
data: {
|
||||
passwordHashLocalAccount: passHash
|
||||
}
|
||||
});
|
||||
setMessage('Паролата беше успешно променена.');
|
||||
router.push('/auth/signin');
|
||||
|
||||
} catch (error) {
|
||||
setMessage(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="w-full max-w-md p-8 space-y-6 bg-white shadow-lg rounded-lg">
|
||||
<h1 className="text-xl font-bold text-center">Променете паролата си</h1>
|
||||
<form onSubmit={handleResetRequest} className="space-y-4">
|
||||
{!isConfirmed &&
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">имейл</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
required
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>}
|
||||
|
||||
{isConfirmed &&
|
||||
<div>
|
||||
<label htmlFor="newPassword" className="block text-sm font-medium text-gray-700">имейл</label>
|
||||
<input
|
||||
id="newPassword"
|
||||
type="password"
|
||||
required
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>}
|
||||
<div>
|
||||
<button type="submit" className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700">
|
||||
Изпрати линк за промяна на паролата
|
||||
</button>
|
||||
<button type="button" className="mt-4 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-blue-600 hover:text-blue-700 focus:outline-none"
|
||||
onClick={() => window.location.href = '/auth/signin'}
|
||||
>
|
||||
страница за вход
|
||||
</button>
|
||||
</div>
|
||||
{message && <div className="text-center text-sm text-gray-500">{message}</div>}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
@ -15,7 +15,7 @@ export default function SignIn({ csrfToken }) {
|
||||
|
||||
// Perform client-side validation if needed
|
||||
if (!email || !password) {
|
||||
setError('All fields are required');
|
||||
setError('Всички полета са задължителни');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -45,49 +45,52 @@ export default function SignIn({ csrfToken }) {
|
||||
<Layout>
|
||||
<div className="page">
|
||||
<div className="signin">
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="provider">
|
||||
{/* Button to sign in with Google */}
|
||||
<button onClick={() => signIn('google', { callbackUrl: '/dash' })}>
|
||||
<img loading="lazy" height="24" width="24" id="provider-logo" src="https://authjs.dev/img/providers/google.svg" alt="Google Logo" />
|
||||
Sign in with Google
|
||||
<div className="min-h-screen flex flex-col items-center justify-center">
|
||||
{/* SSO Providers */}
|
||||
<div className="space-y-4 w-full px-4">
|
||||
<button onClick={() => signIn('google', { callbackUrl: '/' })}
|
||||
className="flex items-center justify-center w-full py-2 px-4 border border-gray-300 rounded shadow-sm text-sm text-gray-700 bg-white hover:bg-gray-50">
|
||||
<img loading="lazy" height="24" width="24" alt="Google logo"
|
||||
src="https://authjs.dev/img/providers/google.svg" className="mr-2" />
|
||||
Влез чрез Google
|
||||
</button>
|
||||
{/* Add more buttons for other SSO providers here in similar style */}
|
||||
</div>
|
||||
<div className="provider">
|
||||
<form onSubmit={handleSubmit} className="w-full max-w-xs">
|
||||
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
|
||||
<div>
|
||||
<label htmlFor="email">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="border p-2 w-full"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="password">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="border p-2 w-full"
|
||||
/>
|
||||
</div>
|
||||
{error && <div className="text-red-500">{error}</div>}
|
||||
<button type="submit" className="bg-blue-500 text-white p-2 mt-4">
|
||||
Sign in
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="text-blue-500 p-2 mt-4"
|
||||
onClick={() => router.push('/auth/reset-password')}>
|
||||
Forgot password?
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Email and Password Form */}
|
||||
<form onSubmit={handleSubmit} className="mt-8 w-full max-w-xs px-4">
|
||||
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
|
||||
<div className="mb-4">
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">имейл</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700">парола</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
{error && <div className="text-red-500 text-sm">{error}</div>}
|
||||
<button type="submit" className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700">
|
||||
Влез
|
||||
</button>
|
||||
{/* <button
|
||||
type="button"
|
||||
className="mt-4 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-blue-600 hover:text-blue-700 focus:outline-none"
|
||||
onClick={() => router.push('/auth/reset-password')}>
|
||||
Забравена парола?
|
||||
</button> */}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user