feat : make general changes for download account statement.
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 >
|
||||
);
|
||||
}
|
||||
// }
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user