196 lines
6.4 KiB
TypeScript
196 lines
6.4 KiB
TypeScript
"use client"
|
|
|
|
import classes from '../page.module.css';
|
|
import React, { useContext, useEffect, useState } from "react";
|
|
import { TextInput, Button, Container, Title, Image, SimpleGrid, LoadingOverlay, Avatar, Paper, Text, Group, Center } from "@mantine/core";
|
|
import image from '../helpdesk.png';
|
|
import { useForm, SubmitHandler } from "react-hook-form";
|
|
import axios, { AxiosError } from "axios";
|
|
import { notifications } from "@mantine/notifications";
|
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { useDisclosure } from "@mantine/hooks";
|
|
|
|
|
|
type OtpInput = {
|
|
OTP: number
|
|
}
|
|
|
|
type Result = {
|
|
ok?: boolean
|
|
message?: string
|
|
}
|
|
|
|
async function handleResendOTP() {
|
|
let otp;
|
|
try {
|
|
const response = await axios.get("/api/otp");
|
|
otp = response.data;
|
|
console.log('OTP resent successfully:', response.data);
|
|
// Object.assign(response.data);
|
|
// alert(response.data.message);
|
|
notifications.show({
|
|
color: 'green',
|
|
// title: error.code,
|
|
message: response.data.message
|
|
})
|
|
} catch (error: AxiosError | any) {
|
|
notifications.show({
|
|
color: 'red',
|
|
title: error.code,
|
|
message: error.message
|
|
})
|
|
}
|
|
return otp;
|
|
}
|
|
|
|
|
|
async function handleValidateOTP(OtpInput: OtpInput) {
|
|
let Result: Result = { ok: false }
|
|
try {
|
|
const response = await axios.post("/api/otp", OtpInput);
|
|
{
|
|
window.location.href = '/home'
|
|
}
|
|
Object.assign(Result, response.data);
|
|
} catch (error: AxiosError | any) {
|
|
// alert(error.response.data.error);
|
|
notifications.show({
|
|
withBorder: true,
|
|
color: 'red',
|
|
title: error.response.status,
|
|
message: error.response.data.error,
|
|
autoClose: 4000,
|
|
})
|
|
}
|
|
// For countdown reset every time after successful verification
|
|
sessionStorage.removeItem('countdown');
|
|
sessionStorage.removeItem('timerStart');
|
|
return Result;
|
|
}
|
|
|
|
export default function CheckOTP() {
|
|
const queryClient = useQueryClient();
|
|
const { register, handleSubmit, formState: { errors } } = useForm<OtpInput>();
|
|
const [countdown, setCountdown] = useState<number>(90);
|
|
const [timerActive, setTimerActive] = useState<boolean>(true);
|
|
|
|
const validateOTPMutation = useMutation<Result, AxiosError, OtpInput>({
|
|
mutationKey: ['validateOtp'],
|
|
mutationFn: handleValidateOTP,
|
|
})
|
|
const resendOTPMutation = useQuery({
|
|
queryKey: ['resendOTP'],
|
|
queryFn: handleResendOTP,
|
|
enabled: false,
|
|
})
|
|
////
|
|
useEffect(() => {
|
|
if (typeof window !== 'undefined') {
|
|
const savedCountdown = sessionStorage.getItem('countdown');
|
|
const savedStartTime = sessionStorage.getItem('timerStart');
|
|
|
|
if (savedCountdown && savedStartTime) {
|
|
const elapsedTime = Math.floor((Date.now() - parseInt(savedStartTime, 10)) / 1000);
|
|
const remainingTime = parseInt(savedCountdown, 10) - elapsedTime;
|
|
|
|
if (remainingTime > 0) {
|
|
setCountdown(remainingTime);
|
|
setTimerActive(true);
|
|
}
|
|
else {
|
|
setCountdown(0);
|
|
setTimerActive(false);
|
|
sessionStorage.removeItem('countdown');
|
|
sessionStorage.removeItem('timerStart');
|
|
}
|
|
} else {
|
|
sessionStorage.setItem('countdown', '90');
|
|
sessionStorage.setItem('timerStart', Date.now().toString());
|
|
setCountdown(90);
|
|
setTimerActive(true);
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
// Effect to manage the countdown timer
|
|
useEffect(() => {
|
|
if (!timerActive) return;
|
|
|
|
const interval = setInterval(() => {
|
|
setCountdown((prev) => {
|
|
if (prev <= 1) {
|
|
clearInterval(interval);
|
|
setTimerActive(false);
|
|
sessionStorage.removeItem('countdown');
|
|
sessionStorage.removeItem('timerStart');
|
|
return 0;
|
|
}
|
|
return prev - 1;
|
|
});
|
|
}, 1000);
|
|
|
|
return () => clearInterval(interval); // Cleanup interval on unmount
|
|
}, [timerActive]);
|
|
/////
|
|
const onSubmit: SubmitHandler<OtpInput> = async (OtpInput) => {
|
|
const Result = await validateOTPMutation.mutateAsync(OtpInput);
|
|
if (Result.ok)
|
|
await queryClient.refetchQueries({ queryKey: ['OTP'] });
|
|
};
|
|
|
|
const handleResend = async () => {
|
|
resendOTPMutation.refetch();
|
|
setCountdown(90);
|
|
setTimerActive(true);
|
|
sessionStorage.setItem('countdown', '90');
|
|
sessionStorage.setItem('timerStart', Date.now().toString());
|
|
}
|
|
|
|
const [opened, { open, close }] = useDisclosure(false);
|
|
|
|
return (
|
|
<Container className={classes.root}>
|
|
<SimpleGrid spacing={{ base: 40, sm: 80 }} cols={{ base: 1, sm: 2 }}>
|
|
<Image src={image.src} className={classes.mobileImage} />
|
|
<div>
|
|
<LoadingOverlay visible={validateOTPMutation.isPending || validateOTPMutation.data?.ok || resendOTPMutation.isLoading} />
|
|
<Paper component='form' className={classes.form} radius={0} p={30} onSubmit={handleSubmit(onSubmit)}>
|
|
<Avatar
|
|
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR-ZljkQXsXUP1-EwnIPZtVq_JWhwGUW7b0_eSMno-bag&s"
|
|
alt="Jacob Warnhalter"
|
|
radius="xxxl"
|
|
/>
|
|
<Title order={2} className={classes.title} ta="center" mt="md" mb={50}>
|
|
Customer Request Management
|
|
</Title>
|
|
<TextInput label="Enter One-time password(OTP) *"
|
|
placeholder="e.g. XXXXX"
|
|
size="md"
|
|
maxLength={6}
|
|
{...register('OTP', { required: true })} />
|
|
{errors.OTP && <Text c='red'>*Required</Text>}
|
|
<Center mt="lg">
|
|
<Text >{timerActive ? `Resend OTP in ${countdown}s` : 'Resend OTP Available'} </Text>
|
|
</Center>
|
|
<Group justify="center">
|
|
<Button mt="xl" size="md" type='submit' >
|
|
Validate OTP
|
|
</Button>
|
|
{validateOTPMutation.data?.message && <Text c='red' ta='center' pt={30}>{validateOTPMutation.data.message}</Text>}
|
|
<Button mt="xl" size="md" type='submit' color='blue' onClick={handleResend} disabled={timerActive} >
|
|
Resend OTP
|
|
</Button>
|
|
{/* {resendOTPMutation?.data?.message && <Text c='red' ta='center' pt={30}>{resendOTPMutation.data.message}</Text>} */}
|
|
</Group>
|
|
</Paper>
|
|
</div>
|
|
<Image src={image.src} className={classes.desktopImage} />
|
|
</SimpleGrid>
|
|
<footer justify-content='center' color='green'>Copyright © 2025 Tata Consultancy Services, All rights reserved.</footer>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
|
|
|