feat: make e-mandate screen responsive.

This commit is contained in:
2025-09-25 15:27:16 +05:30
parent 6beed098c2
commit 649fc5acea
3 changed files with 320 additions and 52 deletions

View File

@@ -266,6 +266,8 @@ export default function QuickPay() {
setOtp("");
setValidationStatus(null);
setBeneficiaryName(null);
setTimerActive(false);
setCountdown(180);
} else {
notifications.show({
title: "Error",
@@ -293,6 +295,8 @@ export default function QuickPay() {
setShowTxnPassword(false);
setShowOtpField(false);
setIsSubmitting(false);
setTimerActive(false);
setCountdown(180);
}
};

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect, memo, useRef } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Tooltip, Modal } from "@mantine/core";
import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Tooltip, Modal, Stack } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
@@ -88,7 +88,7 @@ export default function Login() {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Login-Type': 'emandate',
'X-Login-Type': 'emandate',
},
body: JSON.stringify({
customerNo: CIF,
@@ -112,7 +112,7 @@ export default function Login() {
}
setIsLogging(true);
if (response.ok) {
console.log(data);
// console.log(data);
const token = data.token;
localStorage.setItem("mandate_token", token);
// localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
@@ -160,50 +160,192 @@ export default function Login() {
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
{/* Header */}
<Box
component="header"
style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
position: "fixed",
top: 0,
left: 0,
width: "100%",
zIndex: 100,
display: "flex",
alignItems: "center",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}>
padding: "0.5rem 1rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}
>
{/* Logo */}
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: "100%", height: "auto", flexShrink: 0 }}
style={{
width: "60px", // fixed height for logo
height: "auto",
marginRight: "0.75rem",
flexShrink: 0,
}}
/>
<Title
order={2}
{/* Bank name + address stacked */}
<Box style={{ flex: 1, minWidth: 0 }}>
<Title
order={4}
style={{
fontFamily: "Roboto",
color: "white",
fontSize: "clamp(14px, 2vw, 20px)", // auto resizes
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
size="xs"
style={{
// backgroundColor: "#1f1f14",
fontFamily: "Roboto",
padding: "2px 6px",
borderRadius: "4px",
color: "white",
textShadow: "1px 1px 2px blue",
fontSize: "clamp(10px, 1.5vw, 13px)", // responsive text
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
</Box>
</Box>
<Box
component="header"
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
zIndex: 100,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "0.5rem 1rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}
>
{/* Logo */}
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '7%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
width: "60px",
height: "auto",
flexShrink: 0,
}}
/>
{/* Desktop: Title + Address */}
<Box
className="desktop-header"
style={{
display: "flex",
flexDirection: "column",
marginLeft: "1rem",
flex: 1,
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text size="sm" c="white"
<Title
order={4}
style={{
fontFamily: "Roboto",
color: "white",
fontSize: "clamp(14px, 2vw, 20px)",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
size="xs"
style={{
// backgroundColor: "#1f1f14",
fontFamily: "Roboto",
padding: "2px 6px",
borderRadius: "4px",
color: "white",
textShadow: "1px 1px 2px blue",
fontSize: "clamp(10px, 1.5vw, 13px)",
}}
>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
</Box>
{/* Mobile: only Logo + Bank Name */}
<Box
className="mobile-header"
style={{
backgroundColor: '#1f1f14',
fontFamily: 'Roboto',
position: 'absolute',
top: '59%',
left: '72%',
color: 'white',
textShadow: '1px 1px 2px blue',
display: "none",
flexDirection: "column",
alignItems: "flex-start",
marginLeft: "0.75rem",
}}
>
Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215
</Text>
<Title
order={5}
style={{
fontFamily: "Roboto",
color: "white",
fontSize: "16px",
}}
>
THE KANGRA CENTRAL
</Title>
<Title
order={5}
style={{
fontFamily: "Roboto",
color: "white",
fontSize: "16px",
}}
>
CO-OPERATIVE BANK LTD.
</Title>
</Box>
<style jsx>{`
@media (max-width: 768px) {
.desktop-header {
display: none;
}
.mobile-header {
display: flex;
}
}
@media (min-width: 769px) {
.desktop-header {
display: flex;
}
.mobile-header {
display: none;
}
}
`}
</style>
</Box>
<div style={{ marginTop: '10px' }}>
{/* Movable text */}
<Box
className="desktop-scroll-text"
style={{
width: "100%",
height: "0.5%",
@@ -232,19 +374,23 @@ export default function Login() {
</Text>
<style>
{`
@keyframes scroll-left {
0% { transform: translateX(0%); }
100% { transform: translateX(-100%); }
}
`}
@keyframes scroll-left {
0% { transform: translateX(0%); }
100% { transform: translateX(-100%); }
}
@media (max-width: 768px) {
.desktop-scroll-text { display: none; }
}
`}
</style>
</Box>
{/* Main */}
<div style={{
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
// background: 'linear-gradient(to right, #02081eff, #0a3d91)'
background: 'linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)'
}}>
<Box visibleFrom="md"
style={{
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
background: 'linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)'
}}>
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Image
fit="cover"
@@ -302,7 +448,81 @@ export default function Login() {
</form>
</Card>
</Box>
</div>
</Box>
{/* Mobile layout */}
<Box
hiddenFrom="md"
style={{
marginTop: "25%",
padding: "1rem",
background: "linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)",
minHeight: "80vh",
display: "flex",
justifyContent: "center",
alignItems: "flex-start",
}}
>
<Card shadow="md" padding="lg" radius="md" style={{ width: "100%" }}>
<form onSubmit={handleMandateLogin}>
<Text ta="center" fw={700} style={{ fontSize: "16px" }}>
E-Mandate Login
</Text>
<TextInput
label="User ID"
placeholder="Enter your CIF No"
value={CIF}
onInput={(e) => {
const input = e.currentTarget.value.replace(/\D/g, "");
if (input.length <= 11) SetCIF(input);
}}
withAsterisk
mt="sm"
/>
<PasswordInput
label="Password"
placeholder="Enter your password"
value={psw}
onChange={(e) => SetPsw(e.currentTarget.value)}
withAsterisk
mt="sm"
/>
<Group mt="sm" align="center" grow>
<Box
style={{
backgroundColor: "#fff",
fontSize: "16px",
textDecoration: "line-through",
padding: "4px 8px",
fontFamily: "cursive",
}}
>
{captcha}
</Box>
<Button size="xs" variant="light" onClick={regenerateCaptcha}>
Refresh
</Button>
</Group>
<TextInput
label="Enter CAPTCHA"
placeholder="Enter above text"
value={inputCaptcha}
onChange={(e) => setInputCaptcha(e.currentTarget.value)}
withAsterisk
mt="sm"
/>
<Button type="submit" fullWidth mt="md" disabled={isLogging}>
{isLogging ? "Logging..." : "Login"}
</Button>
</form>
</Card>
</Box>
{/* Footer */}
<Box
component="footer"

View File

@@ -183,7 +183,7 @@ export default function MandatePage() {
"Content-Type": "application/json",
},
body: JSON.stringify({
mobileNumber: '7890544527',
mobileNumber: localStorage.getItem("userMobNo"),
type: 'EMandate'
}),
});
@@ -213,20 +213,52 @@ export default function MandatePage() {
}
};
// Resend OTP
const handleResendOtp = async () => {
try {
const response = await fetch("/api/otp/send", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
mobileNumber: localStorage.getItem("userMobNo"),
type: "EMandate",
}),
});
if (!response.ok) throw new Error("Failed to resend OTP");
notifications.show({
withBorder: true,
color: "blue",
title: "OTP Resent",
message: "A new OTP has been sent to your registered mobile number.",
autoClose: 4000,
});
} catch {
notifications.show({
withBorder: true,
color: "red",
title: "Error",
message: "Failed to resend OTP. Please try again.",
autoClose: 5000,
});
}
};
// STEP 2: Verify OTP and complete action
const handleOtpSubmit = async () => {
// if (!otp) {
// notifications.show({
// withBorder: true,
// color: "red",
// title: "Invalid Input",
// message: "Please enter OTP before proceed",
// autoClose: 5000,
// });
// }
if (!otp) {
notifications.show({
withBorder: true,
color: "red",
title: "Invalid Input",
message: "Please enter OTP before proceed",
autoClose: 5000,
});
}
if (!pendingAction) return;
try {
const response = await fetch(`/api/otp/verify?mobileNumber=${7890544527}`, {
const response = await fetch(`/api/otp/verify?mobileNumber=${localStorage.getItem("userMobNo")}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -400,8 +432,8 @@ export default function MandatePage() {
</Box>
{/* OTP MODAL */}
<Modal opened={otpModalOpen} onClose={() => setOtpModalOpen(false)} title="Enter OTP" centered>
<Text mb="sm">An OTP has been sent to your registered mobile number.</Text>
<Modal opened={otpModalOpen} onClose={() => setOtpModalOpen(false)} title="OTP Verification" centered>
<Text mb="sm" size="sm" ta="center" c="green">An OTP has been sent to your registered mobile number.</Text>
<TextInput
label="OTP"
placeholder="Enter OTP"
@@ -413,7 +445,19 @@ export default function MandatePage() {
}}
/>
<Text size="xs">if you did not received the OTP in SMS,you can click click here to resend the SMS</Text>
<Text mt="md" size="xs" c="dimmed">
If you did not receive the OTP in SMS, you can{" "}
<Text
span
c="blue"
td="underline"
style={{ cursor: "pointer" }}
onClick={handleResendOtp}
>
click here to resend the SMS
</Text>
.
</Text>
<Group mt="md" grow>
<Button color="gray" onClick={() => setOtpModalOpen(false)}>
Cancel