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 = ` +
+
+
+ Bank Logo +

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}

+ + + + + + + + + + + + + ${rows} + +
Customer NoUser NameCreated AtLast LoginStatus
+
+ `; + + 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 = ` +
+
+
+ Bank Logo +

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}

+ + + + + + + + + + + + ${rows} +
Customer NoUser NameCreated AtLast LoginStatus
+
+ `; + + // ✅ 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 ? ( + + + + + KCC Bank Logo + + + + + 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") : "—"} + + + + + + + + + + + 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 ? ( + + + + + KCC Bank Logo + + + + + 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") : "—"} + + + + + + + + + + + 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 */} + + + + {/* 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; } }