Files
IB/src/app/(main)/home/page.tsx
2025-12-06 13:54:20 +05:30

516 lines
26 KiB
TypeScript

"use client";
import React, { useEffect, useState } from 'react';
import { Button, Input, Group, Stack, Text, Title, Box, Select, Paper, Switch } from '@mantine/core';
import { IconBuildingBank, IconEye, IconLink } from '@tabler/icons-react';
import { useRouter } from "next/navigation";
import { Providers } from "../../providers";
import { notifications } from '@mantine/notifications';
import dayjs from 'dayjs';
import { useMediaQuery } from '@mantine/hooks';
interface accountData {
stAccountNo: string;
stAccountType: string;
stAvailableBalance: string;
custname: string;
activeAccounts: string;
}
export default function Home() {
const [authorized, SetAuthorized] = useState<boolean | null>(null);
const router = useRouter();
const isMobile = useMediaQuery("(max-width: 768px)");
const [userName, setUserName] = useState<string>("");
const [accountData, SetAccountData] = useState<accountData[]>([]);
const depositAccounts = accountData.filter(acc => acc.stAccountType !== "LN");
const [selectedDA, setSelectedDA] = useState(depositAccounts[0]?.stAccountNo || "");
const selectedDAData = depositAccounts.find(acc => acc.stAccountNo === selectedDA);
const loanAccounts = accountData.filter(acc => acc.stAccountType === "LN");
const [selectedLN, setSelectedLN] = useState(loanAccounts[0]?.stAccountNo || "");
const selectedLNData = loanAccounts.find(acc => acc.stAccountNo === selectedLN);
const [showBalance, setShowBalance] = useState(false);
const PassExpiryRemains = (dayjs(localStorage.getItem("pswExpiryDate"))).diff(dayjs(), "day")
const [loadingAccountNo, setLoadingAccountNo] = useState<string | null>(null);
// If back and forward button is clicked
useEffect(() => {
window.history.pushState(null, "", window.location.href);
const handlePopState = () => {
localStorage.removeItem("access_token");
sessionStorage.removeItem("access_token");
localStorage.removeItem("remitter_name");
localStorage.removeItem("pswExpiryDate");
localStorage.clear();
sessionStorage.clear();
router.push("/login");
};
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);
return () => {
window.removeEventListener("popstate", handlePopState);
window.addEventListener("beforeunload", handleBeforeUnload);
};
}, []);
async function handleFetchUserDetails() {
try {
const token = localStorage.getItem("access_token");
const response = await fetch('api/customer', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
"X-Login-Type": "IB",
'Authorization': `Bearer ${token}`
},
});
const data = await response.json();
if (response.ok && Array.isArray(data)) {
SetAccountData(data);
sessionStorage.setItem("accountData", JSON.stringify(data));
if (data.length > 0) {
const firstDeposit = data.find(acc => acc.stAccountType !== "LN");
const firstLoan = data.find(acc => acc.stAccountType === "LN");
if (firstDeposit) setSelectedDA(firstDeposit.stAccountNo);
if (firstLoan) setSelectedLN(firstLoan.stAccountNo);
}
} else {
throw new Error();
}
} catch {
notifications.show({
withBorder: true,
color: "red",
title: "Please try again later",
message: "Unable to Fetch, Please try again later",
autoClose: 5000,
});
}
}
async function handleGetAccountStatement(accountNo: string) {
if (loadingAccountNo) return;
setLoadingAccountNo(accountNo);
// simulate loading delay
setTimeout(() => {
router.push(`/accounts/account_statement?accNo=${accountNo}`);
setLoadingAccountNo(null);
}, 6000);
}
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
SetAuthorized(false);
router.push("/login");
} else {
SetAuthorized(true);
}
}, []);
useEffect(() => {
if (authorized) {
handleFetchUserDetails();
const fullName = localStorage.getItem("remitter_name") || "User";
// const first = fullName.split(" ")[0];
setUserName(fullName);
}
}, [authorized]);
if (authorized) {
return (
<Providers>
<Box p={isMobile ? "8px" : "10px"}>
{/* ---------------------- WELCOME CARD ---------------------- */}
<Title
order={2}
style={{
marginTop: "4px",
fontSize: isMobile ? "20px" : "28px",
fontWeight: 800,
background: "linear-gradient(56deg, rgba(16,114,152,1) 0%, rgba(62,230,132,1) 86%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
}}
>
Welcome, {userName}
</Title>
{/* -------------------- ACCOUNT OVERVIEW HEADER -------------------- */}
<Title
order={4}
style={{
fontSize: isMobile ? "18px" : "22px",
marginTop: isMobile ? "6px" : "10px", // ⭐ ADD THIS GAP
}}
>
Accounts Overview
</Title>
<Text size="sm" c="dimmed" mb={isMobile ? 10 : 14}>
Your accounts at a glance
</Text>
{/* --------------------- SHOW BALANCE TOGGLE ---------------------- */}
<Group
style={{
marginBottom: isMobile ? "10px" : "14px",
alignItems: "center",
justifyContent: "flex-start",
gap: 10,
}}
>
<IconEye size={isMobile ? 16 : 20} />
<Text fw={700} style={{ fontSize: isMobile ? "14px" : "18px" }}>
Show Balance
</Text>
<Switch
size={isMobile ? "sm" : "md"}
checked={showBalance}
onChange={(event) => setShowBalance(event.currentTarget.checked)}
/>
</Group>
{/* ----------------------- DESKTOP VIEW ------------------------ */}
{!isMobile && (
<Group align="flex-start" grow gap="md">
{/* ----------------------- DEPOSIT CARD ----------------------- */}
<Paper p="md" radius="md"
style={{
background: "linear-gradient(56deg,rgba(179,214,227,1) 0%, rgba(142,230,179,1) 86%)",
height: 195,
display: "flex",
flexDirection: "column",
justifyContent: "space-between"
}}
>
<Group gap="xs">
<IconBuildingBank size={25} />
<Text fw={700}>Deposit Account</Text>
<Select
data={depositAccounts.map((acc) => ({
value: acc.stAccountNo,
label: `${acc.stAccountType}- ${acc.stAccountNo}`,
}))}
value={selectedDA}
// @ts-ignore
onChange={setSelectedDA}
size="xs"
styles={{
input: { backgroundColor: "white", color: "black", marginLeft: 5, width: 140 }
}}
/>
</Group>
<Text c="dimmed">{selectedDAData?.stAccountNo}</Text>
<Title order={2}>
{showBalance
? `${Number(selectedDAData?.stAvailableBalance || 0).toLocaleString("en-IN")}`
: "****"}
</Title>
<Button
fullWidth
disabled={loadingAccountNo === selectedDA}
onClick={() => handleGetAccountStatement(selectedDA)}
>
{loadingAccountNo === selectedDA ? "Loading...Please Wait" : "Get Statement"}
</Button>
</Paper>
{/* ----------------------- LOAN CARD ----------------------- */}
<Paper p="md" radius="md"
style={{
background: "linear-gradient(56deg,rgba(179,214,227,1) 0%, rgba(142,230,179,1) 86%)",
height: 195,
display: "flex",
flexDirection: "column",
justifyContent: "space-between"
}}
>
<Group gap="xs">
<IconBuildingBank size={25} />
<Text fw={700}>Loan Account</Text>
<Select
data={loanAccounts.map((acc) => ({
value: acc.stAccountNo,
label: `${acc.stAccountType}- ${acc.stAccountNo}`,
}))}
value={selectedLN}
// @ts-ignore
onChange={setSelectedLN}
size="xs"
styles={{
input: { backgroundColor: "white", color: "black", marginLeft: 30, width: 140 }
}}
/>
</Group>
<Text c="dimmed">{selectedLNData?.stAccountNo}</Text>
<Title order={2}>
{showBalance
? `${Number(selectedLNData?.stAvailableBalance || 0).toLocaleString("en-IN")}`
: "****"}
</Title>
<Button
fullWidth
disabled={loadingAccountNo === selectedLN}
onClick={() => handleGetAccountStatement(selectedLN)}
>
{loadingAccountNo === selectedLN ? "Loading...Please Wait" : "Get Statement"}
</Button>
</Paper>
{/* ----------------------- QUICK LINKS ----------------------- */}
<Paper p="md" radius="md" style={{ width: 300, backgroundColor: "#FFFFFF", border: "1px solid grey" }}>
<Title order={5} mb="sm">Quick Links</Title>
<Stack gap="xs">
<Button
variant="light"
color="green"
fullWidth
onClick={() => window.open("https://kccbhp.bank.in/about-us/history-of-kccb/", "_blank")}
>
About Us
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/BranchLocator" target="_blank">
Branch Locator
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/ATMLocator" target="_blank">
ATM Locator
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/CustomerCare" target="_blank">
Customer Care
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/FAQs" target="_blank">
FAQs
</Button>
</Stack>
</Paper>
</Group>
)}
{/* ----------------------- MOBILE VERSION STAYS SAME ----------------------- */}
{isMobile && (
<Stack gap="md" style={{ width: "100%", marginTop: "10px" }}>
{/* Deposit Account Card */}
<Paper
p="md"
radius="md"
style={{
backgroundColor: "#c1e0f0",
width: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
}}
>
<Group gap="xs">
<IconBuildingBank size={20} />
<Text fw={700} style={{ fontSize: "14px" }}>
Deposit Account
</Text>
{depositAccounts.length > 0 ? (
<Select
data={depositAccounts.map((acc) => ({
value: acc.stAccountNo,
label: `${acc.stAccountType}- ${acc.stAccountNo}`,
}))}
value={selectedDA}
// @ts-ignore
onChange={setSelectedDA}
size="xs"
styles={{
input: {
backgroundColor: "white",
color: "black",
marginLeft: 5,
width: "150px",
},
}}
/>
) : (
<Text c="dimmed" size="sm" ml="sm">
No deposit account available
</Text>
)}
</Group>
{depositAccounts.length > 0 ? (
<>
<Text c="dimmed" style={{ fontSize: "12px" }}>
{Number(selectedDAData?.stAccountNo || 0)}
</Text>
<Title order={4} mt="md">
{showBalance
? `${Number(selectedDAData?.stAvailableBalance || 0).toLocaleString("en-IN")}`
: "****"}
</Title>
<Button fullWidth mt="xs"
// loading={loadingAccountNo === selectedDA}
disabled={loadingAccountNo === selectedDA}
onClick={() => handleGetAccountStatement(selectedDA)}
>
{loadingAccountNo === selectedDA ? "Loading...Please Wait" : "Get Statement"}
</Button>
</>
) : (
<>
<Text c="dimmed" mt="md">
Apply for a deposit account to get started
</Text>
<Button fullWidth mt="xs">
Apply Now
</Button>
</>
)}
</Paper>
{/* Loan Account Card */}
<Paper
p="md"
radius="md"
style={{
backgroundColor: "#c1e0f0",
width: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
}}
>
<Group gap="xs">
<IconBuildingBank size={20} />
<Text fw={700} style={{ fontSize: "14px" }}>
Loan Account
</Text>
{loanAccounts.length > 0 ? (
<Select
data={loanAccounts.map((acc) => ({
value: acc.stAccountNo,
label: `${acc.stAccountType}- ${acc.stAccountNo}`,
}))}
value={selectedLN}
// @ts-ignore
onChange={setSelectedLN}
size="xs"
styles={{
input: {
backgroundColor: "white",
color: "black",
marginLeft: 5,
width: "150px",
},
}}
/>
) : (
<Text c="dimmed" size="sm" ml="sm">
No loan account available
</Text>
)}
</Group>
{loanAccounts.length > 0 ? (
<>
<Text c="dimmed" style={{ fontSize: "12px" }}>
{Number(selectedLNData?.stAccountNo || 0)}
</Text>
<Title order={4} mt="md">
{showBalance
? `${Number(selectedLNData?.stAvailableBalance || 0).toLocaleString("en-IN")}`
: "****"}
</Title>
<Button fullWidth mt="xs"
// loading={loadingAccountNo === selectedLN}
disabled={loadingAccountNo === selectedLN}
onClick={() => handleGetAccountStatement(selectedLN)}
>
{/* Get Statement */}
{loadingAccountNo === selectedLN ? "Loading...Please Wait" : "Get Statement"}
</Button>
</>
) : (
<>
<Text c="dimmed" mt="md">
Apply for a loan account to get started
</Text>
<Button fullWidth mt="xs">
Apply Now
</Button>
</>
)}
</Paper>
{/* Important Links Card */}
<Paper
p="md"
radius="md"
style={{
width: "100%",
backgroundColor: "#FFFFFF",
border: "1px solid grey",
}}
>
<Title order={5} mb="sm">
Quick Links
</Title>
<Stack gap="xs">
<Button
variant="light"
color="green"
fullWidth
onClick={() => window.open("https://kccbhp.bank.in/about-us/history-of-kccb/", "_blank")}
>
About Us
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/BranchLocator" target="_blank">
Branch Locator
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/ATMLocator" target="_blank">
ATM Locator
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/CustomerCare" target="_blank">
Customer Care
</Button>
<Button variant="light" color="green" fullWidth component="a" href="/FAQs" target="_blank">
FAQs
</Button>
</Stack>
</Paper>
</Stack>
)}
{/* -------------------- NOTES SECTION (BOTTOM) --------------------- */}
<Box mt="md">
<Stack>
<Text fw={700}> ** Book Balance includes uncleared effect.</Text>
<Text fw={700}> ** Click &quot;Show Balance&quot; to display account balances.</Text>
<Text fw={400} c="red">
** Your Password will expire in {PassExpiryRemains} days.
</Text>
</Stack>
</Box>
</Box>
</Providers>
);
}
return null;
}