diff --git a/src/app/_components/report/Activeuser_report.tsx b/src/app/_components/report/Activeuser_report.tsx
new file mode 100644
index 0000000..099c7c5
--- /dev/null
+++ b/src/app/_components/report/Activeuser_report.tsx
@@ -0,0 +1,103 @@
+"use client";
+import dayjs from "dayjs";
+
+export const generateActiveUsersPDF = (reportData: any, startDate: string, endDate: string) => {
+ const html2pdf = require("html2pdf.js");
+
+ // Build rows from user list
+ const rows = reportData.active_user_list
+ .map(
+ (user: any) => `
+
+ | ${user.customer_no} |
+ ${user.user_name} |
+
+ ${new Date(user.created_at).toLocaleString()}
+ |
+
+ ${new Date(user.last_login).toLocaleString()}
+ |
+
+ ${user.status.toUpperCase()}
+ |
+
`
+ )
+ .join("");
+
+ // HTML content for PDF
+ const content = `
+
+
+
+

+
The Kangra Central Co Operative Bank
+
+
+ Report generated: ${dayjs().format("DD/MM/YYYY HH:mm")}
+
+
+
+
+
Active Users Report
+
+
+ Report from ${startDate} to ${endDate}
+
+
Total Users: ${reportData.total_users}
+
Active Users: ${reportData.active_users}
+
+
+
+
+ | Customer No |
+ User Name |
+ Created At |
+ Last Login |
+ Status |
+
+
+
+ ${rows}
+
+
+
+ `;
+
+ const opt = {
+ margin: [20, 10, 20, 10],
+ filename: `ActiveUsersReport_${dayjs().format("DDMMYYYY_HHmm")}.pdf`,
+ image: { type: "jpeg", quality: 0.98 },
+ html2canvas: { scale: 2 },
+ jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
+ pagebreak: { mode: ["avoid-all", "css", "legacy"] },
+ };
+
+ // ✅ Properly call .save() INSIDE the .then()
+ html2pdf()
+ .set(opt)
+ .from(content)
+ .toPdf()
+ .get("pdf")
+ .then((pdf: any) => {
+ const totalPages = pdf.internal.getNumberOfPages();
+ const pageWidth = pdf.internal.pageSize.getWidth();
+
+ for (let i = 2; i <= totalPages; i++) {
+ pdf.setPage(i);
+ pdf.setFontSize(10);
+ pdf.setFont("helvetica", "bold");
+
+ pdf.text("Active Users Report", pageWidth / 2, 18, { align: "center" });
+ pdf.setFontSize(9);
+ pdf.text(
+ `Page ${i} of ${totalPages}`,
+ pageWidth - 40,
+ pdf.internal.pageSize.getHeight() - 10
+ );
+ }
+
+ // ✅ Save PDF here
+ pdf.save(`ActiveUsersReport_${dayjs().format("DDMMYYYY_HHmm")}.pdf`);
+ });
+};
diff --git a/src/app/_components/report/Inactiveuser_report.tsx b/src/app/_components/report/Inactiveuser_report.tsx
new file mode 100644
index 0000000..f2738ae
--- /dev/null
+++ b/src/app/_components/report/Inactiveuser_report.tsx
@@ -0,0 +1,105 @@
+"use client";
+import dayjs from "dayjs";
+
+export const generateInactiveUsersPDF = (
+ reportData: any,
+ startDate: string,
+ endDate: string
+) => {
+ const html2pdf = require("html2pdf.js");
+
+ // ✅ Use correct list (change to 'active_user_list' if needed)
+ const userList = reportData.inactive_user_list || reportData.active_user_list || [];
+
+ // Build table rows
+ const rows = userList
+ .map(
+ (user: any) => `
+
+ | ${user.customer_no} |
+ ${user.user_name} |
+
+ ${new Date(user.created_at).toLocaleString()}
+ |
+
+ ${new Date(user.last_login).toLocaleString()}
+ |
+
+ ${user.status.toUpperCase()}
+ |
+
`
+ )
+ .join("");
+
+ // ✅ HTML layout
+ const content = `
+
+
+
+

+
The Kangra Central Co Operative Bank
+
+
+ Report generated: ${dayjs().format("DD/MM/YYYY HH:mm")}
+
+
+
+
+
Inactive Users Report
+
+
+ Report from ${startDate} to ${endDate}
+
+
+
Total Users: ${reportData.total_users}
+
Inactive Users: ${reportData.inactive_users}
+
+
+
+
+ | Customer No |
+ User Name |
+ Created At |
+ Last Login |
+ Status |
+
+
+ ${rows}
+
+
+ `;
+
+ // ✅ Options — fix margin type
+ const opt = {
+ margin: [20, 10, 20, 10] as [number, number, number, number],
+ filename: `InactiveUsersReport_${dayjs().format("DDMMYYYY_HHmm")}.pdf`,
+ image: { type: "jpeg", quality: 0.98 },
+ html2canvas: { scale: 2 },
+ jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
+ pagebreak: { mode: ["avoid-all", "css", "legacy"] },
+ };
+
+ // ✅ Proper html2pdf chain
+ html2pdf()
+ .set(opt)
+ .from(content)
+ .toPdf()
+ .get("pdf")
+ .then((pdf: any) => {
+ const totalPages = pdf.internal.getNumberOfPages();
+ const pageWidth = pdf.internal.pageSize.getWidth();
+
+ for (let i = 1; i <= totalPages; i++) {
+ pdf.setPage(i);
+ pdf.setFontSize(9);
+ pdf.text(
+ `Page ${i} of ${totalPages}`,
+ pageWidth - 40,
+ pdf.internal.pageSize.getHeight() - 10
+ );
+ }
+ })
+ .save(); // ✅ this triggers the download
+};
diff --git a/src/app/_util/otp.ts b/src/app/_util/otp.ts
index 7a70463..8a0d146 100644
--- a/src/app/_util/otp.ts
+++ b/src/app/_util/otp.ts
@@ -14,8 +14,8 @@ interface SendOtpPayload {
}
function getStoredMobileNumber(): string {
- const mobileNumber = localStorage.getItem('remitter_mobile_no');
- // const mobileNumber = "7890544527";
+ //const mobileNumber = localStorage.getItem('remitter_mobile_no');
+ const mobileNumber = "6297421727";
if (!mobileNumber) throw new Error('Mobile number not found.');
return mobileNumber;
}
diff --git a/src/app/administrator/home/ActiveUsersReport.tsx b/src/app/administrator/home/ActiveUsersReport.tsx
new file mode 100644
index 0000000..47cd7aa
--- /dev/null
+++ b/src/app/administrator/home/ActiveUsersReport.tsx
@@ -0,0 +1,299 @@
+"use client";
+import React, { useState } from "react";
+import {
+ Box,
+ Button,
+ Group,
+ Stack,
+ Modal,
+ Table,
+ Text,
+ Title,
+ Divider,
+ Badge,
+} from "@mantine/core";
+import Image from "next/image";
+import img from '@/app/image/logo1.jpg'
+import { DatePickerInput } from "@mantine/dates";
+
+import { IconDownload, IconRefresh } from "@tabler/icons-react";
+import { notifications } from "@mantine/notifications";
+import { generateActiveUsersPDF } from "@/app/_components/report/Activeuser_report";
+import dayjs from "dayjs";
+
+export default function ActiveUsersReport() {
+ const [startDate, setStartDate] = useState(null);
+ const [endDate, setEndDate] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [opened, setOpened] = useState(false);
+ const [reportData, setReportData] = useState(null);
+
+ const handleFetch = async () => {
+ if (!startDate || !endDate) {
+ notifications.show({
+ color: "red",
+ title: "Missing Dates",
+ message: "Please select both start and end dates.",
+ });
+ return;
+ }
+
+ // const monthDiff =
+ // (endDate.getFullYear() - startDate.getFullYear()) * 12 +
+ // (endDate.getMonth() - startDate.getMonth());
+ const monthDiff = dayjs(endDate).diff(dayjs(startDate), "month", true);
+
+ if (monthDiff > 3) {
+ notifications.show({
+ color: "red",
+ title: "Invalid Range",
+ message: "You can only fetch reports up to 3 months at a time.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const token = localStorage.getItem("admin_access_token");
+ const response = await fetch(`/api/report/active_users`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Login-Type": "Admin",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ from_date: dayjs(startDate).format("YYYY-MM-DD"),
+ to_date: dayjs(endDate).format("YYYY-MM-DD"),
+ }),
+ });
+
+ const data = await response.json(); // Expected format from your backend
+ console.log(data);
+ if (response.ok) {
+ setReportData(data);
+ setOpened(true);
+ notifications.show({
+ withBorder: true,
+ color: "green",
+ title: "Success",
+ message: "Report fetched successfully",
+ autoClose: 5000,
+ });
+ } else {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Error",
+ message: data?.error || "Failed to fetch report",
+ autoClose: 5000,
+ });
+ }
+ } catch (error) {
+ notifications.show({
+ title: "Error",
+ message: "Something went wrong while fetching report",
+ color: "red",
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Download button inside modal
+ const handleDownload = () => {
+ if (!reportData) {
+ notifications.show({
+ color: "red",
+ title: "No Data",
+ message: "No report data to download.",
+ });
+ return;
+ }
+
+ // Call your external PDF generator
+ generateActiveUsersPDF(
+ reportData,
+ dayjs(startDate).format("YYYY-MM-DD"),
+ dayjs(endDate).format("YYYY-MM-DD")
+ );
+
+ notifications.show({
+ color: "blue",
+ title: "Download",
+ message: "PDF downloaded successfully.",
+ });
+ };
+
+
+ // Reset button
+ const handleReset = () => {
+ setStartDate(null);
+ setEndDate(null);
+ setReportData(null);
+ notifications.show({
+ color: "yellow",
+ title: "Form Reset",
+ message: "Dates cleared successfully.",
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setOpened(false)}
+ size="xl"
+ centered
+ withCloseButton
+ >
+ {reportData ? (
+
+
+
+
+
+
+
+
+
+ Active Users Report
+
+
+ Total Users: {reportData.total_users}
+
+
+ Active Users: {reportData.active_users}
+
+
+
+
+
+
+
+
+
+ Active User List From{" "}
+
+ {startDate ? dayjs(startDate).format("YYYY-MM-DD") : "—"} To{" "}
+ {endDate ? dayjs(endDate).format("YYYY-MM-DD") : "—"}
+
+
+ }
+ color="blue"
+ variant="light"
+ >
+ Download
+
+
+
+
+
+
+
+
+ Customer No
+ User Name
+ Created At
+ Last Login
+ Status
+
+
+
+
+ {reportData.active_user_list.map((user: any, index: number) => (
+
+ {user.customer_no}
+ {user.user_name}
+
+ {new Date(user.created_at).toLocaleString()}
+
+
+ {new Date(user.last_login).toLocaleString()}
+
+
+
+ {user.status.toUpperCase()}
+
+
+
+ ))}
+
+
+
+
+ ) : (
+
+
+ No data available
+
+ )}
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/administrator/home/InactiveUsersReport.tsx b/src/app/administrator/home/InactiveUsersReport.tsx
new file mode 100644
index 0000000..58d7677
--- /dev/null
+++ b/src/app/administrator/home/InactiveUsersReport.tsx
@@ -0,0 +1,300 @@
+"use client";
+import React, { useState } from "react";
+import {
+ Box,
+ Button,
+ Group,
+ Stack,
+ Modal,
+ Table,
+ Text,
+ Title,
+ Divider,
+ Badge,
+} from "@mantine/core";
+import Image from "next/image";
+import img from '@/app/image/logo1.jpg'
+import { DatePickerInput } from "@mantine/dates";
+
+import { IconDownload, IconRefresh } from "@tabler/icons-react";
+import { notifications } from "@mantine/notifications";
+import { generateInactiveUsersPDF } from "@/app/_components/report/Inactiveuser_report";
+import dayjs from "dayjs";
+
+export default function InactiveUsersReport() {
+ const [startDate, setStartDate] = useState(null);
+ const [endDate, setEndDate] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [opened, setOpened] = useState(false);
+ const [reportData, setReportData] = useState(null);
+
+ const handleFetch = async () => {
+ if (!startDate || !endDate) {
+ notifications.show({
+ color: "red",
+ title: "Missing Dates",
+ message: "Please select both start and end dates.",
+ });
+ return;
+ }
+
+ // const monthDiff =
+ // (endDate.getFullYear() - startDate.getFullYear()) * 12 +
+ // (endDate.getMonth() - startDate.getMonth());
+ const monthDiff = dayjs(endDate).diff(dayjs(startDate), "month", true);
+
+ if (monthDiff > 3) {
+ notifications.show({
+ color: "red",
+ title: "Invalid Range",
+ message: "You can only fetch reports up to 3 months at a time.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const token = localStorage.getItem("admin_access_token");
+ const response = await fetch(`/api/report/in-active_users`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Login-Type": "Admin",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ from_date: dayjs(startDate).format("YYYY-MM-DD"),
+ to_date: dayjs(endDate).format("YYYY-MM-DD"),
+ }),
+ });
+
+ const data = await response.json(); // Expected format from your backend
+ console.log(data);
+ if (response.ok) {
+ setReportData(data);
+ setOpened(true);
+ notifications.show({
+ withBorder: true,
+ color: "green",
+ title: "Success",
+ message: "Report fetched successfully",
+ autoClose: 5000,
+ });
+ } else {
+ notifications.show({
+ withBorder: true,
+ color: "red",
+ title: "Error",
+ message: data?.error || "Failed to fetch report",
+ autoClose: 5000,
+ });
+ }
+ } catch (error) {
+ notifications.show({
+ title: "Error",
+ message: "Something went wrong while fetching report",
+ color: "red",
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Download button inside modal
+ const handleDownload = () => {
+ if (!reportData) {
+ notifications.show({
+ color: "red",
+ title: "No Data",
+ message: "No report data to download.",
+ });
+ return;
+ }
+
+ // Call your external PDF generator
+ generateInactiveUsersPDF(
+ reportData,
+ dayjs(startDate).format("YYYY-MM-DD"),
+ dayjs(endDate).format("YYYY-MM-DD")
+ );
+
+ notifications.show({
+ color: "blue",
+ title: "Download",
+ message: "PDF downloaded successfully.",
+ });
+ };
+
+
+ // Reset button
+ const handleReset = () => {
+ setStartDate(null);
+ setEndDate(null);
+ setReportData(null);
+ notifications.show({
+ color: "yellow",
+ title: "Form Reset",
+ message: "Dates cleared successfully.",
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setOpened(false)}
+ size="xl"
+ centered
+ withCloseButton
+ >
+ {reportData ? (
+
+
+
+
+
+
+
+
+
+ Inactive Users Report
+
+
+ Total Users: {reportData.total_users}
+
+
+ Inactive Users: {reportData.active_users}
+
+
+
+
+
+
+
+
+
+
+
+ Active User List From{" "}
+ {startDate ? dayjs(startDate).format("YYYY-MM-DD") : "—"} To{" "}
+ {endDate ? dayjs(endDate).format("YYYY-MM-DD") : "—"}
+
+
+ }
+ color="blue"
+ variant="light"
+ >
+ Download
+
+
+
+
+
+
+
+
+ Customer No
+ User Name
+ Created At
+ Last Login
+ Status
+
+
+
+
+ {reportData.inactive_user_list.map((user: any, index: number) => (
+
+ {user.customer_no}
+ {user.user_name}
+
+ {new Date(user.created_at).toLocaleString()}
+
+
+ {new Date(user.last_login).toLocaleString()}
+
+
+
+ {user.status.toUpperCase()}
+
+
+
+ ))}
+
+
+
+
+ ) : (
+
+ No data available
+
+ )}
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/administrator/home/TransactionReport.tsx b/src/app/administrator/home/TransactionReport.tsx
new file mode 100644
index 0000000..2c3e96d
--- /dev/null
+++ b/src/app/administrator/home/TransactionReport.tsx
@@ -0,0 +1,189 @@
+"use client";
+import React, { useState } from "react";
+import { Box, Button, Group, Stack, Select } from "@mantine/core";
+import { DatePickerInput } from "@mantine/dates";
+import { IconDownload, IconRefresh } from "@tabler/icons-react";
+import { notifications } from "@mantine/notifications";
+
+export default function TransactionReport() {
+ const [selectType, setSelectType] = useState(null);
+ const [transactionType, setTransactionType] = useState(null);
+ const [fromDate, setFromDate] = useState(null);
+ const [toDate, setToDate] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ // 🔹 Fetch logic
+ const handleFetch = async () => {
+ if (!selectType || !transactionType || !fromDate || !toDate) {
+ notifications.show({
+ color: "red",
+ title: "Missing Fields",
+ message: "Please fill all fields before fetching report.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const response = await fetch(
+ `/api/reports/transactions?type=${selectType}&txnType=${transactionType}&start=${fromDate.toISOString()}&end=${toDate.toISOString()}`
+ );
+ if (!response.ok) throw new Error("Failed to fetch report");
+ const data = await response.json();
+ console.log("Fetched Transaction Report:", data);
+ notifications.show({
+ color: "green",
+ title: "Success",
+ message: "Transaction report fetched successfully!",
+ });
+ } catch (err) {
+ notifications.show({
+ color: "red",
+ title: "Error",
+ message: "Unable to fetch transaction report. Try again later.",
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Download logic with 3-month validation
+ const handleDownload = () => {
+ if (!selectType || !transactionType || !fromDate || !toDate) {
+ notifications.show({
+ color: "red",
+ title: "Missing Fields",
+ message: "Please fill all fields before downloading report.",
+ });
+ return;
+ }
+
+ const monthDiff =
+ (toDate.getFullYear() - fromDate.getFullYear()) * 12 +
+ (toDate.getMonth() - fromDate.getMonth());
+
+ if (monthDiff > 3) {
+ notifications.show({
+ color: "red",
+ title: "Invalid Range",
+ message: "You can only download reports up to 3 months at a time.",
+ });
+ return;
+ }
+
+ notifications.show({
+ color: "blue",
+ title: "Download Started",
+ message: "Downloading transaction report...",
+ });
+
+ // Add your actual download API logic here
+ console.log("Downloading report:", {
+ selectType,
+ transactionType,
+ fromDate,
+ toDate,
+ });
+ };
+
+ // Reset logic
+ const handleReset = () => {
+ setSelectType(null);
+ setTransactionType(null);
+ setFromDate(null);
+ setToDate(null);
+ notifications.show({
+ color: "yellow",
+ title: "Form Reset",
+ message: "All fields cleared successfully.",
+ });
+ };
+
+ return (
+
+
+
+ {/* Select Type */}
+
+
+ {/* Transaction Type */}
+
+
+
+ {/* From and To Date on same line */}
+
+
+
+
+
+ {/* Buttons aligned to right */}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/administrator/home/page.tsx b/src/app/administrator/home/page.tsx
index fcab96f..629fc6e 100644
--- a/src/app/administrator/home/page.tsx
+++ b/src/app/administrator/home/page.tsx
@@ -28,6 +28,10 @@ import {
import UserConfiguration from "./UserConfiguration";
import ViewUserConfiguration from "./ViewUserConfiguration";
import UnlockedUsers from "./UnlockedUsers";
+import ActiveUsersReport from "./ActiveUsersReport";
+import InactiveUsersReport from "./InactiveUsersReport";
+
+import TransactionReport from "./TransactionReport";
export default function Login() {
const router = useRouter();
@@ -267,6 +271,20 @@ export default function Login() {
>
• Active Users Report
+
+ setView("inactiveUsersReport")}
+ style={{
+ cursor: "pointer",
+ color: view === "inactiveUsersReport" ? "#02a355" : "white",
+ backgroundColor: view === "inactiveUsersReport" ? "white" : "transparent",
+ borderRadius: "3px",
+ padding: "3px 6px",
+ transition: "0.2s",
+ }}
+ >
+ • Inactive Users Report
+
setView("noOfTrans")}
style={{
@@ -373,29 +391,18 @@ export default function Login() {
{view === "userConf" && }
{view === "viewUser" && }
{view === "unlockUser" && }
- {view === "noOfTrans" && (
-
- Reports will be Coming Soon
-
- )}
- {view === "activeUsersReport" && (
-
- Active users Reports will be Coming Soon
-
- )}
- {view === "ifscConfig" && (
-
- IFSC Configuration Page Coming Soon
-
- )}
+ {view === "activeUsersReport" && }
+ {view === "inactiveUsersReport" && }
+ {view === "noOfTrans" && }
+
{!view && (
<>
-
+ {/*
Welcome To The Internet Banking Admin Portal
Choose the service from the menu.
-
+ */}
>
)}
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 3f4d0c5..6ea388a 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -45,8 +45,8 @@ export default function Login() {
}
try {
- await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
- // await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: "7890544527" });
+ // await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
+ await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: "6297421727" });
notifications.show({
color: 'orange',
title: 'OTP Required',
@@ -67,8 +67,9 @@ export default function Login() {
async function handleVerifyOtp(mobile?: string) {
try {
if (mobile) {
- await verifyLoginOtp(otp, mobile);
- // await verifyLoginOtp(otp, '7890544527');
+ //await verifyLoginOtp(otp, mobile);
+ await verifyLoginOtp(otp, '6297421727');
+
return true;
}
}