feat : admin feature
This commit is contained in:
103
src/app/_components/report/Activeuser_report.tsx
Normal file
103
src/app/_components/report/Activeuser_report.tsx
Normal file
@@ -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) => `
|
||||||
|
<tr style="page-break-inside: avoid;">
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">${user.customer_no}</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:left;">${user.user_name}</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">
|
||||||
|
${new Date(user.created_at).toLocaleString()}
|
||||||
|
</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">
|
||||||
|
${new Date(user.last_login).toLocaleString()}
|
||||||
|
</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;
|
||||||
|
color:${user.status === "active" ? "green" : "red"};">
|
||||||
|
${user.status.toUpperCase()}
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
// HTML content for PDF
|
||||||
|
const content = `
|
||||||
|
<div style="font-family:Arial, sans-serif; font-size:12px;">
|
||||||
|
<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;margin:10px 0;">Active Users Report</h3>
|
||||||
|
|
||||||
|
<p style="text-align:center; font-size:13px; margin-top:-5px;">
|
||||||
|
<strong>Report from ${startDate} to ${endDate}</strong>
|
||||||
|
</p>
|
||||||
|
<p><strong>Total Users:</strong> ${reportData.total_users}</p>
|
||||||
|
<p><strong>Active Users:</strong> ${reportData.active_users}</p>
|
||||||
|
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:12px;margin-top:10px;">
|
||||||
|
<thead style="background:#f0f0f0;">
|
||||||
|
<tr>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Customer No</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:left;">User Name</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Created At</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Last Login</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${rows}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
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`);
|
||||||
|
});
|
||||||
|
};
|
||||||
105
src/app/_components/report/Inactiveuser_report.tsx
Normal file
105
src/app/_components/report/Inactiveuser_report.tsx
Normal file
@@ -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) => `
|
||||||
|
<tr style="page-break-inside: avoid;">
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">${user.customer_no}</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:left;">${user.user_name}</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">
|
||||||
|
${new Date(user.created_at).toLocaleString()}
|
||||||
|
</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;">
|
||||||
|
${new Date(user.last_login).toLocaleString()}
|
||||||
|
</td>
|
||||||
|
<td style="border:1px solid #ccc;padding:6px;text-align:center;color:${
|
||||||
|
user.status === "active" ? "green" : "red"
|
||||||
|
};">
|
||||||
|
${user.status.toUpperCase()}
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
// ✅ HTML layout
|
||||||
|
const content = `
|
||||||
|
<div style="font-family:Arial, sans-serif; font-size:12px;">
|
||||||
|
<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;margin:10px 0;">Inactive Users Report</h3>
|
||||||
|
|
||||||
|
<p style="text-align:center; font-size:13px; margin-top:-5px;">
|
||||||
|
<strong>Report from ${startDate} to ${endDate}</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><strong>Total Users:</strong> ${reportData.total_users}</p>
|
||||||
|
<p><strong>Inactive Users:</strong> ${reportData.inactive_users}</p>
|
||||||
|
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:12px;margin-top:10px;">
|
||||||
|
<thead style="background:#f0f0f0;">
|
||||||
|
<tr>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Customer No</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:left;">User Name</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Created At</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Last Login</th>
|
||||||
|
<th style="border:1px solid #ccc;padding:6px;text-align:center;">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>${rows}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// ✅ 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
|
||||||
|
};
|
||||||
@@ -14,8 +14,8 @@ interface SendOtpPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getStoredMobileNumber(): string {
|
function getStoredMobileNumber(): string {
|
||||||
const mobileNumber = localStorage.getItem('remitter_mobile_no');
|
//const mobileNumber = localStorage.getItem('remitter_mobile_no');
|
||||||
// const mobileNumber = "7890544527";
|
const mobileNumber = "6297421727";
|
||||||
if (!mobileNumber) throw new Error('Mobile number not found.');
|
if (!mobileNumber) throw new Error('Mobile number not found.');
|
||||||
return mobileNumber;
|
return mobileNumber;
|
||||||
}
|
}
|
||||||
|
|||||||
299
src/app/administrator/home/ActiveUsersReport.tsx
Normal file
299
src/app/administrator/home/ActiveUsersReport.tsx
Normal file
@@ -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<Date | null>(null);
|
||||||
|
const [endDate, setEndDate] = useState<Date | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [opened, setOpened] = useState(false);
|
||||||
|
const [reportData, setReportData] = useState<any>(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 (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
p="md"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
boxShadow: "0 0 5px rgba(0,0,0,0.1)",
|
||||||
|
maxWidth: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap="md">
|
||||||
|
<Group grow>
|
||||||
|
<DatePickerInput
|
||||||
|
label="Start Date"
|
||||||
|
placeholder="Select start date"
|
||||||
|
value={startDate}
|
||||||
|
onChange={setStartDate}
|
||||||
|
required
|
||||||
|
maxDate={new Date()}
|
||||||
|
/>
|
||||||
|
<DatePickerInput
|
||||||
|
label="End Date"
|
||||||
|
placeholder="Select end date"
|
||||||
|
value={endDate}
|
||||||
|
onChange={setEndDate}
|
||||||
|
required
|
||||||
|
maxDate={new Date()}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Group justify="flex-end" mt="sm">
|
||||||
|
<Button onClick={handleFetch} loading={loading}>
|
||||||
|
Fetch
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleReset}
|
||||||
|
variant="outline"
|
||||||
|
color="red"
|
||||||
|
title="Reset Form"
|
||||||
|
>
|
||||||
|
<IconRefresh size={18} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
opened={opened}
|
||||||
|
onClose={() => setOpened(false)}
|
||||||
|
size="xl"
|
||||||
|
centered
|
||||||
|
withCloseButton
|
||||||
|
>
|
||||||
|
{reportData ? (
|
||||||
|
<Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Box mb="sm">
|
||||||
|
<img
|
||||||
|
src={img.src}
|
||||||
|
alt="KCC Bank Logo"
|
||||||
|
width={60}
|
||||||
|
height={60}
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
marginBottom: "10px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Stack gap={4} mb="md">
|
||||||
|
<Title order={4}>Active Users Report</Title>
|
||||||
|
|
||||||
|
<Text>
|
||||||
|
<b>Total Users:</b> {reportData.total_users}
|
||||||
|
</Text>
|
||||||
|
<Text >
|
||||||
|
<b>Active Users:</b> {reportData.active_users}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider my="sm" />
|
||||||
|
|
||||||
|
|
||||||
|
<Group justify="space-between" align="center" mb="xs">
|
||||||
|
<Title order={5}>
|
||||||
|
Active User List From{" "}
|
||||||
|
|
||||||
|
{startDate ? dayjs(startDate).format("YYYY-MM-DD") : "—"} To{" "}
|
||||||
|
{endDate ? dayjs(endDate).format("YYYY-MM-DD") : "—"}
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleDownload}
|
||||||
|
size="xs"
|
||||||
|
leftSection={<IconDownload size={16} />}
|
||||||
|
color="blue"
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
|
||||||
|
<Box style={{ maxHeight: "400px", overflowY: "auto" }}>
|
||||||
|
<Table striped withTableBorder style={{ width: "100%" }}>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Customer No</Table.Th>
|
||||||
|
<Table.Th>User Name</Table.Th>
|
||||||
|
<Table.Th>Created At</Table.Th>
|
||||||
|
<Table.Th>Last Login</Table.Th>
|
||||||
|
<Table.Th>Status</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
|
||||||
|
<Table.Tbody>
|
||||||
|
{reportData.active_user_list.map((user: any, index: number) => (
|
||||||
|
<Table.Tr key={index}>
|
||||||
|
<Table.Td>{user.customer_no}</Table.Td>
|
||||||
|
<Table.Td>{user.user_name}</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
{new Date(user.created_at).toLocaleString()}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
{new Date(user.last_login).toLocaleString()}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Badge
|
||||||
|
color={user.status === "active" ? "green" : "red"}
|
||||||
|
variant="filled"
|
||||||
|
>
|
||||||
|
{user.status.toUpperCase()}
|
||||||
|
</Badge>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Text ta="center" c="dimmed">
|
||||||
|
|
||||||
|
No data available
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
300
src/app/administrator/home/InactiveUsersReport.tsx
Normal file
300
src/app/administrator/home/InactiveUsersReport.tsx
Normal file
@@ -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<Date | null>(null);
|
||||||
|
const [endDate, setEndDate] = useState<Date | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [opened, setOpened] = useState(false);
|
||||||
|
const [reportData, setReportData] = useState<any>(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 (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
p="md"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
boxShadow: "0 0 5px rgba(0,0,0,0.1)",
|
||||||
|
maxWidth: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap="md">
|
||||||
|
<Group grow>
|
||||||
|
<DatePickerInput
|
||||||
|
label="Start Date"
|
||||||
|
placeholder="Select start date"
|
||||||
|
value={startDate}
|
||||||
|
onChange={setStartDate}
|
||||||
|
required
|
||||||
|
maxDate={new Date()}
|
||||||
|
/>
|
||||||
|
<DatePickerInput
|
||||||
|
label="End Date"
|
||||||
|
placeholder="Select end date"
|
||||||
|
value={endDate}
|
||||||
|
onChange={setEndDate}
|
||||||
|
required
|
||||||
|
maxDate={new Date()}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Group justify="flex-end" mt="sm">
|
||||||
|
<Button onClick={handleFetch} loading={loading}>
|
||||||
|
Fetch
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleReset}
|
||||||
|
variant="outline"
|
||||||
|
color="red"
|
||||||
|
title="Reset Form"
|
||||||
|
>
|
||||||
|
<IconRefresh size={18} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
opened={opened}
|
||||||
|
onClose={() => setOpened(false)}
|
||||||
|
size="xl"
|
||||||
|
centered
|
||||||
|
withCloseButton
|
||||||
|
>
|
||||||
|
{reportData ? (
|
||||||
|
<Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Box mb="sm">
|
||||||
|
<img
|
||||||
|
src={img.src}
|
||||||
|
alt="KCC Bank Logo"
|
||||||
|
width={60}
|
||||||
|
height={60}
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
marginBottom: "10px",
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Stack gap={4} mb="md">
|
||||||
|
<Title order={4}>Inactive Users Report</Title>
|
||||||
|
|
||||||
|
<Text>
|
||||||
|
<b>Total Users:</b> {reportData.total_users}
|
||||||
|
</Text>
|
||||||
|
<Text >
|
||||||
|
<b>Inactive Users:</b> {reportData.active_users}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider my="sm" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Group justify="space-between" align="center" mb="xs">
|
||||||
|
<Title order={5}>
|
||||||
|
Active User List From{" "}
|
||||||
|
{startDate ? dayjs(startDate).format("YYYY-MM-DD") : "—"} To{" "}
|
||||||
|
{endDate ? dayjs(endDate).format("YYYY-MM-DD") : "—"}
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleDownload}
|
||||||
|
size="xs"
|
||||||
|
leftSection={<IconDownload size={16} />}
|
||||||
|
color="blue"
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
|
||||||
|
<Box style={{ maxHeight: "400px", overflowY: "auto" }}>
|
||||||
|
<Table striped withTableBorder style={{ width: "100%" }}>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Customer No</Table.Th>
|
||||||
|
<Table.Th>User Name</Table.Th>
|
||||||
|
<Table.Th>Created At</Table.Th>
|
||||||
|
<Table.Th>Last Login</Table.Th>
|
||||||
|
<Table.Th>Status</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
|
||||||
|
<Table.Tbody>
|
||||||
|
{reportData.inactive_user_list.map((user: any, index: number) => (
|
||||||
|
<Table.Tr key={index}>
|
||||||
|
<Table.Td>{user.customer_no}</Table.Td>
|
||||||
|
<Table.Td>{user.user_name}</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
{new Date(user.created_at).toLocaleString()}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
{new Date(user.last_login).toLocaleString()}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Badge
|
||||||
|
color={user.status === "inactive" ? "green" : "red"}
|
||||||
|
variant="filled"
|
||||||
|
>
|
||||||
|
{user.status.toUpperCase()}
|
||||||
|
</Badge>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Text ta="center" c="dimmed">
|
||||||
|
No data available
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
189
src/app/administrator/home/TransactionReport.tsx
Normal file
189
src/app/administrator/home/TransactionReport.tsx
Normal file
@@ -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<string | null>(null);
|
||||||
|
const [transactionType, setTransactionType] = useState<string | null>(null);
|
||||||
|
const [fromDate, setFromDate] = useState<Date | null>(null);
|
||||||
|
const [toDate, setToDate] = useState<Date | null>(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 (
|
||||||
|
<Box
|
||||||
|
p="md"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
boxShadow: "0 0 5px rgba(0,0,0,0.1)",
|
||||||
|
maxWidth: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap="md">
|
||||||
|
<Group gap="md" grow>
|
||||||
|
{/* Select Type */}
|
||||||
|
<Select
|
||||||
|
label="Select Type"
|
||||||
|
placeholder="Choose Type"
|
||||||
|
data={[
|
||||||
|
{ value: "IB", label: "IB" },
|
||||||
|
{ value: "MB", label: "MB" },
|
||||||
|
]}
|
||||||
|
value={selectType}
|
||||||
|
onChange={setSelectType}
|
||||||
|
style={{ width: "200px" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Transaction Type */}
|
||||||
|
<Select
|
||||||
|
label="Transaction Type"
|
||||||
|
placeholder="Select Transaction Type"
|
||||||
|
data={[
|
||||||
|
{ value: "IMPS", label: "IMPS" },
|
||||||
|
{ value: "RTGS", label: "RTGS" },
|
||||||
|
{ value: "NEFT", label: "NEFT" },
|
||||||
|
]}
|
||||||
|
value={transactionType}
|
||||||
|
onChange={setTransactionType}
|
||||||
|
style={{ width: "200px" }}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{/* From and To Date on same line */}
|
||||||
|
<Group grow>
|
||||||
|
<DatePickerInput
|
||||||
|
label="From Date"
|
||||||
|
placeholder="Select from date"
|
||||||
|
value={fromDate}
|
||||||
|
onChange={setFromDate}
|
||||||
|
/>
|
||||||
|
<DatePickerInput
|
||||||
|
label="To Date"
|
||||||
|
placeholder="Select to date"
|
||||||
|
value={toDate}
|
||||||
|
onChange={setToDate}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{/* Buttons aligned to right */}
|
||||||
|
<Group justify="flex-end" mt="sm">
|
||||||
|
<Button
|
||||||
|
onClick={handleFetch}
|
||||||
|
loading={loading}
|
||||||
|
|
||||||
|
>
|
||||||
|
Fetch
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleDownload}
|
||||||
|
variant="outline"
|
||||||
|
color="blue"
|
||||||
|
title="Download Report"
|
||||||
|
>
|
||||||
|
<IconDownload size={18} />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleReset}
|
||||||
|
variant="outline"
|
||||||
|
color="red"
|
||||||
|
title="Reset Form"
|
||||||
|
>
|
||||||
|
<IconRefresh size={18} />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -28,6 +28,10 @@ import {
|
|||||||
import UserConfiguration from "./UserConfiguration";
|
import UserConfiguration from "./UserConfiguration";
|
||||||
import ViewUserConfiguration from "./ViewUserConfiguration";
|
import ViewUserConfiguration from "./ViewUserConfiguration";
|
||||||
import UnlockedUsers from "./UnlockedUsers";
|
import UnlockedUsers from "./UnlockedUsers";
|
||||||
|
import ActiveUsersReport from "./ActiveUsersReport";
|
||||||
|
import InactiveUsersReport from "./InactiveUsersReport";
|
||||||
|
|
||||||
|
import TransactionReport from "./TransactionReport";
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -267,6 +271,20 @@ export default function Login() {
|
|||||||
>
|
>
|
||||||
• Active Users Report
|
• Active Users Report
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
onClick={() => 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
|
||||||
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
onClick={() => setView("noOfTrans")}
|
onClick={() => setView("noOfTrans")}
|
||||||
style={{
|
style={{
|
||||||
@@ -373,29 +391,18 @@ export default function Login() {
|
|||||||
{view === "userConf" && <UserConfiguration />}
|
{view === "userConf" && <UserConfiguration />}
|
||||||
{view === "viewUser" && <ViewUserConfiguration />}
|
{view === "viewUser" && <ViewUserConfiguration />}
|
||||||
{view === "unlockUser" && <UnlockedUsers />}
|
{view === "unlockUser" && <UnlockedUsers />}
|
||||||
{view === "noOfTrans" && (
|
{view === "activeUsersReport" && <ActiveUsersReport />}
|
||||||
<Text size="sm" c="gray">
|
{view === "inactiveUsersReport" && <InactiveUsersReport />}
|
||||||
Reports will be Coming Soon
|
{view === "noOfTrans" && <TransactionReport />}
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{view === "activeUsersReport" && (
|
|
||||||
<Text size="sm" c="gray">
|
|
||||||
Active users Reports will be Coming Soon
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{view === "ifscConfig" && (
|
|
||||||
<Text size="sm" c="gray">
|
|
||||||
IFSC Configuration Page Coming Soon
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{!view && (
|
{!view && (
|
||||||
<>
|
<>
|
||||||
<Text size="xl" c="gray">
|
{/* <Text size="xl" c="gray">
|
||||||
Welcome To The Internet Banking Admin Portal
|
Welcome To The Internet Banking Admin Portal
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="sm" c="black">
|
<Text size="sm" c="black">
|
||||||
Choose the service from the menu.
|
Choose the service from the menu.
|
||||||
</Text>
|
</Text> */}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
|
// 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: "6297421727" });
|
||||||
notifications.show({
|
notifications.show({
|
||||||
color: 'orange',
|
color: 'orange',
|
||||||
title: 'OTP Required',
|
title: 'OTP Required',
|
||||||
@@ -67,8 +67,9 @@ export default function Login() {
|
|||||||
async function handleVerifyOtp(mobile?: string) {
|
async function handleVerifyOtp(mobile?: string) {
|
||||||
try {
|
try {
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
await verifyLoginOtp(otp, mobile);
|
//await verifyLoginOtp(otp, mobile);
|
||||||
// await verifyLoginOtp(otp, '7890544527');
|
await verifyLoginOtp(otp, '6297421727');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user