feat : make general changes for download account statement.

This commit is contained in:
2025-09-10 11:38:50 +05:30
parent 14e6ef97bc
commit 3a006bf3c1
9 changed files with 156 additions and 153 deletions

View File

@@ -207,7 +207,10 @@ export default function AccountStatementPage() {
size={22}
style={{ cursor: "pointer" }}
onClick={() =>
generatePDF(selectedAccNo || "", availableBalance || "0", transactions)
generatePDF(selectedAccNo || "", availableBalance || "0", transactions,
localStorage.getItem("remitter_name") || "",
startDate ? dayjs(startDate).format("DD/MM/YYYY") : "",
endDate ? dayjs(endDate).format("DD/MM/YYYY") : "")
}
/>
<IconFileSpreadsheet
@@ -217,7 +220,7 @@ export default function AccountStatementPage() {
generateCSV(selectedAccNo || "NA", availableBalance || "0.00", transactions)
}
/>
</Group>
</Group>

View File

@@ -41,20 +41,18 @@ export default function Home() {
sessionStorage.clear();
router.push("/login");
};
// const handleBeforeUnload = () => {
// // logout on tab close / refresh
// localStorage.removeItem("access_token");
// sessionStorage.removeItem("access_token");
// localStorage.removeItem("remitter_name");
// localStorage.removeItem("pswExpiryDate");
// localStorage.clear();
// sessionStorage.clear();
// };
const handleBeforeUnload = () => {
// logout on tab close / refresh
localStorage.removeItem("access_token");
sessionStorage.removeItem("access_token");
localStorage.clear();
sessionStorage.clear();
};
window.addEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("beforeunload", handleBeforeUnload);
};
}, []);

View File

@@ -9,9 +9,6 @@ import logo from '@/app/image/logo1.jpg';
import NextImage from 'next/image';
import { notifications } from '@mantine/notifications';
import { useDisclosure } from '@mantine/hooks';
import { Dialog } from '@mantine/core';
export default function RootLayout({ children }: { children: React.ReactNode }) {
const router = useRouter();
@@ -89,18 +86,16 @@ export default function RootLayout({ children }: { children: React.ReactNode })
};
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
// logout on tab close / refresh
// localStorage.removeItem("access_token");
// sessionStorage.removeItem("access_token");
// localStorage.removeItem("remitter_name");
// localStorage.removeItem("pswExpiryDate");
// localStorage.clear();
// sessionStorage.clear();
localStorage.removeItem("access_token");
sessionStorage.removeItem("access_token");
localStorage.clear();
sessionStorage.clear();
};
window.addEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("beforeunload", handleBeforeUnload);
};
}, []);
@@ -276,7 +271,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Button variant="default" onClick={close}>
Cancel
</Button>
<Button color="red" onClick={handleLogout}>
<Button onClick={handleLogout}>
Logout
</Button>
</Group>

View File

@@ -120,18 +120,18 @@ export default function ForgetLoginPwd() {
}
}
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
SetAuthorized(false);
router.push("/login");
}
else {
SetAuthorized(true);
}
}, []);
// useEffect(() => {
// const token = localStorage.getItem("access_token");
// if (!token) {
// SetAuthorized(false);
// router.push("/login");
// }
// else {
// SetAuthorized(true);
// }
// }, []);
if (authorized) {
// if (authorized) {
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
@@ -265,5 +265,5 @@ export default function ForgetLoginPwd() {
</div>
</Providers >
);
}
// }
}

View File

@@ -1,62 +0,0 @@
.root {
width: 100vw;
height: 100vh;
}
.title {
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
font-family:
Greycliff CF,
var(--mantine-font-family);
}
.mobileImage {
@media (min-width: 48em) {
display: none;
}
}
.desktopImage {
object-fit: cover;
width: 100%;
height: 100%;
@media (max-width: 47.99em) {
display: none;
}
}
.carousel-wrapper {
width: 100%;
max-width: 800px;
margin: 0 auto;
overflow: hidden;
}
.gradient-control {
width: 15%;
height: 100%;
position: absolute;
top: 0;
z-index: 2;
background-color: transparent;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.6;
color: white;
pointer-events: all;
}
/* First control is left */
.gradient-control:first-of-type {
left: 0;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.0001));
}
/* Last control is right */
.gradient-control:last-of-type {
right: 0;
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.0001));
}

View File

@@ -157,14 +157,10 @@ export default function SetLoginPwd() {
router.push("/login");
}
}
useEffect(() => {
const loadCaptcha = async () => {
const newCaptcha = await generateCaptcha();
setCaptcha(newCaptcha);
};
loadCaptcha();
useEffect(() => {
regenerateCaptcha();
}, []);
useEffect(() => {
let interval: number | undefined;
if (timerActive && countdown > 0) {
@@ -195,7 +191,7 @@ export default function SetLoginPwd() {
if (authorized) {
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "auto", paddingTop: "5%" }}>
<div style={{ backgroundColor: "#f8f9fa", width: "auto", height: "auto", paddingTop: "5%" }}>
<Box style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",

View File

@@ -1,10 +1,10 @@
"use client";
import React, { useState } from "react";
import React, { useEffect, useState ,useRef } from "react";
import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import NextImage from "next/image";
import logo from '@/app/image/logo.jpg';
import logo from '@/app/image/logo1.jpg';
import changePwdImage from '@/app/image/changepw.png';
import { useRouter } from "next/navigation";
import { generateOTP } from '@/app/OTPGenerator';
@@ -16,6 +16,7 @@ export default function ValidateUser() {
const [mobileNumber, setMobileNumber] = useState("");
const [isCifValidated, setIsCifValidated] = useState(false);
const [generateOtp, setGenerateOtp] = useState("");
const headerRef = useRef<HTMLHeadingElement>(null);
const validUsers = [
{ cif: "11111111111", mobile: "7890544527" },
@@ -72,7 +73,7 @@ export default function ValidateUser() {
};
const handleSubmitOtp = () => {
if(!otp){
if (!otp) {
notifications.show({
title: "Invalid OTP",
message: "Please Enter OTP Before You Submit.",
@@ -100,17 +101,72 @@ export default function ValidateUser() {
}
useEffect(() => {
const headerData = [
"THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.",
"कांगड़ा केन्द्रीय सहकारी बैंक सीमित",
];
let index = 0;
const interval = setInterval(() => {
index = (index + 1) % headerData.length;
if (headerRef.current) {
headerRef.current.textContent = headerData[index];
}
}, 2000);
return () => clearInterval(interval);
}, []);
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", paddingTop: "5%" }}>
<Box style={{
position: 'fixed', width: '100%', height: '15%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)"
}}>
<Image fit="cover" src={logo} component={NextImage} alt="ebanking"
style={{ width: "100%", height: "100%" }} />
<Box
style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}>
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: "100%", height: "auto", flexShrink: 0 }}
/>
<Title ref={headerRef}
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '7%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text size="sm" c="white"
style={{
backgroundColor: '#1f1f14',
fontFamily: 'Roboto',
position: 'absolute',
top: '59%',
left: '72%',
color: 'white',
textShadow: '1px 1px 2px blue',
}}
>
Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215
</Text>
{/* <Box style={{ position: "absolute", right: "1rem", top: "50%", transform: 'translateY(-50%)' }}>
<Tooltip
label='Head Office : Dharmshala, District: Kangra(H.P), Pin: 176215'
position="right"
withArrow>
<IconBuildingBank size={40} style={{ cursor: "pointer", color: "white" }} />
</Tooltip>
</Box> */}
</Box>
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center", columnGap: "5rem" }} bg="#c1e0f0">
<Image h="85vh" fit="contain" component={NextImage} src={changePwdImage} alt="Change Password Image" />
@@ -123,10 +179,10 @@ export default function ValidateUser() {
// @ts-ignore
<Text align="center"> Welcome {" "}{Cif}</Text>
)}
<form onSubmit={(e)=>{
<form onSubmit={(e) => {
e.preventDefault();
isCifValidated?handleSubmitOtp():handleValidateUser(e);
}}>
isCifValidated ? handleSubmitOtp() : handleValidateUser(e);
}}>
<TextInput
label="Enter Your CIF Number"
placeholder="Enter your CIF"

View File

@@ -5,29 +5,18 @@ export const generatePDF = (
accountNo: string,
balance: string,
txns: any[],
customerName: string,
periodFrom: string,
periodTo: string
) => {
const html2pdf = require("html2pdf.js");
// Header with logo + bank name + generated date
const headerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<div style="display:flex;align-items:center;gap:10px;">
<img src="/logo.jpg" alt="Bank Logo" style="height:50px;" />
<h2 style="margin:0;">The Kangra Central Co Operative Bank</h2>
</div>
<div style="font-size:12px;color:#555;">
Report generated: ${dayjs().format("DD/MM/YYYY HH:mm")}
</div>
</div>
<hr/>
`;
// Table rows
// Build rows
const rows = txns.map(
(t: any) => `
<tr style="page-break-inside: avoid;">
<td style="border:1px solid #ccc;padding:6px;text-align:center;">${t.date}</td>
<td style="border:1px solid #ccc;padding:6px;text-align:left;">${t.name}</td>
<td style="border:1px solid #ccc;padding:6px;text-align:left;">${t.date}</td>
<td style="border:1px solid #ccc;padding:6px;text-align:right;color:${t.type === "DR" ? "red" : "green"
}">
${parseFloat(t.amount).toLocaleString("en-IN", {
@@ -38,20 +27,34 @@ export const generatePDF = (
`
);
// Content for first page
const content = `
<div style="font-family:Arial, sans-serif;">
${headerHTML}
<h3 style ="text-align:center;">Account Statement</h3>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<div style="display:flex;align-items:center;gap:10px;">
<img src="/logo.jpg" alt="Bank Logo" style="height:50px;" />
<h2 style="margin:0;">The Kangra Central Co Operative Bank</h2>
</div>
<div style="font-size:12px;color:#555;">
Report generated: ${dayjs().format("DD/MM/YYYY HH:mm")}
</div>
</div>
<hr/>
<h3 style="text-align:center;">Account Statement</h3>
<p><strong>Account No:</strong> ${accountNo}</p>
<p><strong>Available Balance:</strong> ${parseFloat(
balance
).toLocaleString("en-IN", { minimumFractionDigits: 2 })}</p>
<p><strong>Account Holder:</strong> ${customerName}</p>
<p><strong>Statement Period:</strong> ${periodFrom} to ${periodTo}</p>
<p><strong>Available Balance:</strong> ₹ ${parseFloat(balance).toLocaleString(
"en-IN",
{ minimumFractionDigits: 2 }
)}</p>
<table style="width:100%;border-collapse:collapse;font-size:12px;margin-top:10px;page-break-inside:auto;">
<thead style="background:#f0f0f0;">
<tr>
<th style="border:1px solid #ccc;padding:6px;text-align:left;">Name</th>
<th style="border:1px solid #ccc;padding:6px;text-align:left;">Date</th>
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Date</th>
<th style="border:1px solid #ccc;padding:6px;text-align:left;">Description</th>
<th style="border:1px solid #ccc;padding:6px;text-align:right;">Amount (₹)</th>
</tr>
</thead>
@@ -59,15 +62,12 @@ export const generatePDF = (
${rows.join("")}
</tbody>
</table>
<div style="height:40px;"></div>
</div>
`;
// PDF options
const opt = {
margin: [10, 10, 20, 10], // bottom margin for page count
filename: `AccountStatement_${accountNo}.pdf`,
margin: [20, 10, 20, 10],
filename: `AccountStatement_${accountNo}_${dayjs().format("DD/MM/YYYY HH:mm")}.pdf`,
image: { type: "jpeg", quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
@@ -81,12 +81,29 @@ export const generatePDF = (
.get("pdf")
.then((pdf: any) => {
const totalPages = pdf.internal.getNumberOfPages();
for (let i = 1; i <= totalPages; i++) {
const pageWidth = pdf.internal.pageSize.getWidth();
for (let i = 2; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
// ✅ Left side Account No
pdf.setFont("helvetica", "bold");
// pdf.text(`Account No: ${accountNo}`, 15, 18);
// ✅ Centered Statement Period
pdf.text(
`Statement Period: ${periodFrom} to ${periodTo}`,
pageWidth / 2,
18,
{ align: "center" }
);
// Footer page numbers
pdf.setFontSize(9);
pdf.text(
`Page ${i} of ${totalPages}`,
pdf.internal.pageSize.getWidth() - 40,
pageWidth - 40,
pdf.internal.pageSize.getHeight() - 10
);
}

View File

@@ -126,7 +126,7 @@ export default function ViewUserRights() {
<Text size="md">{new Date(userData.created_at).toLocaleString()}</Text>
</Group>
<Group justify="space-between">
<Text size="sm" fw={500} c="dimmed">User Active Status:</Text>
<Text size="sm" fw={500} c="dimmed">User Status:</Text>
<Text size="md" c="green">Active</Text>
</Group>
<Group justify="space-between">