feat: make e-mandate screen responsive.
This commit is contained in:
@@ -266,6 +266,8 @@ export default function QuickPay() {
|
|||||||
setOtp("");
|
setOtp("");
|
||||||
setValidationStatus(null);
|
setValidationStatus(null);
|
||||||
setBeneficiaryName(null);
|
setBeneficiaryName(null);
|
||||||
|
setTimerActive(false);
|
||||||
|
setCountdown(180);
|
||||||
} else {
|
} else {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
@@ -293,6 +295,8 @@ export default function QuickPay() {
|
|||||||
setShowTxnPassword(false);
|
setShowTxnPassword(false);
|
||||||
setShowOtpField(false);
|
setShowOtpField(false);
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
|
setTimerActive(false);
|
||||||
|
setCountdown(180);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState, useEffect, memo, useRef } from "react";
|
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 { notifications } from "@mantine/notifications";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
@@ -112,7 +112,7 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
setIsLogging(true);
|
setIsLogging(true);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
const token = data.token;
|
const token = data.token;
|
||||||
localStorage.setItem("mandate_token", token);
|
localStorage.setItem("mandate_token", token);
|
||||||
// localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
|
// localStorage.setItem("pswExpiryDate", data.loginPswExpiry);
|
||||||
@@ -160,50 +160,192 @@ export default function Login() {
|
|||||||
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
|
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Box
|
<Box
|
||||||
|
component="header"
|
||||||
style={{
|
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",
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
justifyContent: "flex-start",
|
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
|
<Image
|
||||||
src={logo}
|
src={logo}
|
||||||
component={NextImage}
|
component={NextImage}
|
||||||
fit="contain"
|
fit="contain"
|
||||||
alt="ebanking"
|
alt="ebanking"
|
||||||
style={{ width: "100%", height: "auto", flexShrink: 0 }}
|
|
||||||
/>
|
|
||||||
<Title
|
|
||||||
order={2}
|
|
||||||
style={{
|
style={{
|
||||||
fontFamily: 'Roboto',
|
width: "60px", // fixed height for logo
|
||||||
position: 'absolute',
|
height: "auto",
|
||||||
top: '30%',
|
marginRight: "0.75rem",
|
||||||
left: '7%',
|
flexShrink: 0,
|
||||||
color: 'White',
|
}}
|
||||||
transition: "opacity 0.5s ease-in-out",
|
/>
|
||||||
|
|
||||||
|
{/* 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.
|
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
|
||||||
</Title>
|
</Title>
|
||||||
<Text size="sm" c="white"
|
<Text
|
||||||
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: '#1f1f14',
|
// backgroundColor: "#1f1f14",
|
||||||
fontFamily: 'Roboto',
|
fontFamily: "Roboto",
|
||||||
position: 'absolute',
|
padding: "2px 6px",
|
||||||
top: '59%',
|
borderRadius: "4px",
|
||||||
left: '72%',
|
color: "white",
|
||||||
color: 'white',
|
textShadow: "1px 1px 2px blue",
|
||||||
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
|
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</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={{
|
||||||
|
width: "60px",
|
||||||
|
height: "auto",
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Desktop: Title + Address */}
|
||||||
|
<Box
|
||||||
|
className="desktop-header"
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
marginLeft: "1rem",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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={{
|
||||||
|
display: "none",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
marginLeft: "0.75rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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' }}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
{/* Movable text */}
|
{/* Movable text */}
|
||||||
<Box
|
<Box
|
||||||
|
className="desktop-scroll-text"
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "0.5%",
|
height: "0.5%",
|
||||||
@@ -236,13 +378,17 @@ export default function Login() {
|
|||||||
0% { transform: translateX(0%); }
|
0% { transform: translateX(0%); }
|
||||||
100% { transform: translateX(-100%); }
|
100% { transform: translateX(-100%); }
|
||||||
}
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.desktop-scroll-text { display: none; }
|
||||||
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Main */}
|
{/* Main */}
|
||||||
<div style={{
|
<Box visibleFrom="md"
|
||||||
|
style={{
|
||||||
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
|
display: "flex", height: "75vh", overflow: "hidden", position: "relative",
|
||||||
// background: 'linear-gradient(to right, #02081eff, #0a3d91)'
|
|
||||||
background: 'linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)'
|
background: 'linear-gradient(179deg, #3faa56ff 49%, #3aa760ff 80%)'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
|
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
|
||||||
@@ -302,7 +448,81 @@ export default function Login() {
|
|||||||
</form>
|
</form>
|
||||||
</Card>
|
</Card>
|
||||||
</Box>
|
</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 */}
|
{/* Footer */}
|
||||||
<Box
|
<Box
|
||||||
component="footer"
|
component="footer"
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export default function MandatePage() {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
mobileNumber: '7890544527',
|
mobileNumber: localStorage.getItem("userMobNo"),
|
||||||
type: 'EMandate'
|
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
|
// STEP 2: Verify OTP and complete action
|
||||||
const handleOtpSubmit = async () => {
|
const handleOtpSubmit = async () => {
|
||||||
// if (!otp) {
|
if (!otp) {
|
||||||
// notifications.show({
|
notifications.show({
|
||||||
// withBorder: true,
|
withBorder: true,
|
||||||
// color: "red",
|
color: "red",
|
||||||
// title: "Invalid Input",
|
title: "Invalid Input",
|
||||||
// message: "Please enter OTP before proceed",
|
message: "Please enter OTP before proceed",
|
||||||
// autoClose: 5000,
|
autoClose: 5000,
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
if (!pendingAction) return;
|
if (!pendingAction) return;
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/otp/verify?mobileNumber=${7890544527}`, {
|
const response = await fetch(`/api/otp/verify?mobileNumber=${localStorage.getItem("userMobNo")}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -400,8 +432,8 @@ export default function MandatePage() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* OTP MODAL */}
|
{/* OTP MODAL */}
|
||||||
<Modal opened={otpModalOpen} onClose={() => setOtpModalOpen(false)} title="Enter OTP" centered>
|
<Modal opened={otpModalOpen} onClose={() => setOtpModalOpen(false)} title="OTP Verification" centered>
|
||||||
<Text mb="sm">An OTP has been sent to your registered mobile number.</Text>
|
<Text mb="sm" size="sm" ta="center" c="green">An OTP has been sent to your registered mobile number.</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="OTP"
|
label="OTP"
|
||||||
placeholder="Enter 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>
|
<Group mt="md" grow>
|
||||||
<Button color="gray" onClick={() => setOtpModalOpen(false)}>
|
<Button color="gray" onClick={() => setOtpModalOpen(false)}>
|
||||||
Cancel
|
Cancel
|
||||||
|
|||||||
Reference in New Issue
Block a user