Fix: design and few function

This commit is contained in:
2025-11-27 18:13:06 +05:30
parent 7460157b46
commit c1d0519c09
25 changed files with 1446 additions and 395 deletions

View File

@@ -108,7 +108,7 @@ export default function AccountDetails() {
if (!authorized) return null; if (!authorized) return null;
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={3} mb="md"> <Title order={3} mb="md">
Account Details Account Details
</Title> </Title>

View File

@@ -168,7 +168,7 @@ export default function AccountStatementPage() {
<Grid gutter="md"> <Grid gutter="md">
{/* Left side form */} {/* Left side form */}
<Grid.Col span={{ base: 12, md: 4 }}> <Grid.Col span={{ base: 12, md: 4 }}>
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={4} mb="sm">Account Transactions</Title> <Title order={4} mb="sm">Account Transactions</Title>
<Select <Select
label="Select Account Number" label="Select Account Number"
@@ -202,7 +202,7 @@ export default function AccountStatementPage() {
{/* Right side transaction list */} {/* Right side transaction list */}
<Grid.Col span={{ base: 12, md: 8 }}> <Grid.Col span={{ base: 12, md: 8 }}>
<Paper shadow="sm" radius="md" p="md" withBorder h={400} style={{ display: 'flex', flexDirection: 'column' }}> <Paper shadow="sm" radius="md" p="md" withBorder h={500} style={{ display: 'flex', flexDirection: 'column' }}>
<Title order={5} mb="xs">Account Transactions</Title> <Title order={5} mb="xs">Account Transactions</Title>
<Group justify="space-between" align="center" mt="sm"> <Group justify="space-between" align="center" mt="sm">
<div> <div>
@@ -291,13 +291,68 @@ export default function AccountStatementPage() {
) : ( ) : (
// ✅ Desktop View Table Layout // ✅ Desktop View Table Layout
<Table style={{ borderCollapse: "collapse", width: "100%" }}> <Table style={{ borderCollapse: "collapse", width: "100%" }}>
<thead style={{ backgroundColor: "#3385ff" }}> <thead
{/* <tr> style={{
<th style={{ ...cellStyle, textAlign: "left", color: "white" }}>Narration</th> background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
<th style={{ ...cellStyle, textAlign: "left", color: "white" }}>Date</th> position: "sticky",
<th style={{ ...cellStyle, textAlign: "right", color: "white" }}>Amount (₹)</th> top: 0,
<th style={{ ...cellStyle, textAlign: "right", color: "white" }}>Balance (₹)</th> zIndex: 5,
</tr> */} }}
>
<tr>
<th
style={{
...cellStyle,
textAlign: "left",
color: "white",
position: "sticky",
top: 0,
// background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
zIndex: 10,
}}
>
Narration
</th>
<th
style={{
...cellStyle,
textAlign: "left",
color: "white",
position: "sticky",
top: 0,
// background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
zIndex: 10,
}}
>
Date
</th>
<th
style={{
...cellStyle,
textAlign: "right",
color: "white",
position: "sticky",
top: 0,
// background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
zIndex: 10,
}}
>
Amount ()
</th>
<th
style={{
...cellStyle,
textAlign: "right",
color: "white",
position: "sticky",
top: 0,
// background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
zIndex: 10,
}}
>
Balance ()
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
{transactions.map((txn, i) => ( {transactions.map((txn, i) => (

View File

@@ -16,7 +16,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
const [drawerOpened, setDrawerOpened] = useState(false); const [drawerOpened, setDrawerOpened] = useState(false);
const links = [ const links = [
{ label: "Account Summary", href: "/accounts" }, { label: " Account Summary", href: "/accounts" },
{ label: "Account Statement ", href: "/accounts/account_statement" }, { label: "Account Statement ", href: "/accounts/account_statement" },
{ label: "Account Details", href: "/accounts/account_details" }, { label: "Account Details", href: "/accounts/account_details" },
]; ];
@@ -98,7 +98,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
color="white" color="white"
/> />
<Text fw={600} c="white"> <Text fw={600} c="white">
Send Money Accounts
</Text> </Text>
</Box> </Box>
@@ -131,7 +131,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
style={{ borderRadius: "50%" }} style={{ borderRadius: "50%" }}
/> />
<Text fw={700} ml="10px" style={{ fontSize: "19px", color: "#1565c0" }}> <Text fw={700} ml="10px" style={{ fontSize: "19px", color: "#1565c0" }}>
Send Money Accounts
</Text> </Text>
</Box> </Box>

View File

@@ -106,7 +106,7 @@ export default function AccountSummary() {
<ScrollArea> <ScrollArea>
<Table style={{ borderCollapse: "collapse", width: "100%" }}> <Table style={{ borderCollapse: "collapse", width: "100%" }}>
<thead> <thead>
<tr style={{ backgroundColor: "#3385ff" }}> <tr style={{ background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)", }}>
<th style={{ ...cellStyle, textAlign: "left" }}>Account Type</th> <th style={{ ...cellStyle, textAlign: "left" }}>Account Type</th>
<th style={{ ...cellStyle, textAlign: "right" }}>Account No.</th> <th style={{ ...cellStyle, textAlign: "right" }}>Account No.</th>
{title.includes("Deposit Accounts (INR)") ? {title.includes("Deposit Accounts (INR)") ?
@@ -124,7 +124,7 @@ export default function AccountSummary() {
if (!authorized) return null; if (!authorized) return null;
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title <Title
order={isMobile ? 4 : 3} order={isMobile ? 4 : 3}
mb="md" mb="md"
@@ -133,7 +133,7 @@ export default function AccountSummary() {
Account Summary Account Summary
</Title> </Title>
{/* Responsive layout: Group for desktop, Stack for mobile */} {/* Responsive layout: Group for desktop, Stack for mobile */}
{isMobile ? ( {isMobile ? (
<Stack gap="md"> <Stack gap="md">
{depositAccounts.length > 0 && {depositAccounts.length > 0 &&

View File

@@ -451,7 +451,7 @@ export default function AddBeneficiaryOthers() {
{!otpSent && ( {!otpSent && (
<Grid.Col > <Grid.Col >
<Group gap="sm"> <Group gap="sm">
<Button onClick={validateAndSendOtp} disabled={loading}>Validate</Button> <Button onClick={validateAndSendOtp} disabled={loading}>Validate</Button>
{loading && ( {loading && (
<> <>
<Loader size='sm' type="bars"></Loader> <Loader size='sm' type="bars"></Loader>
@@ -493,9 +493,9 @@ export default function AddBeneficiaryOthers() {
</Grid.Col > </Grid.Col >
<Grid.Col > <Grid.Col >
{!otpVerified ? ( {!otpVerified ? (
<Button onClick={verify_otp}>Validate OTP</Button> <Button onClick={verify_otp}>Validate OTP</Button>
) : ( ) : (
<Button color="blue" size="sm" onClick={AddBen}> <Button size="sm" onClick={AddBen}>
Add Add
</Button> </Button>
)} )}

View File

@@ -27,7 +27,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
/* Beneficiary Options */ /* Beneficiary Options */
const links = [ const links = [
{ label: "Add Beneficiary", href: "/beneficiary/add_beneficiary" }, { label: "Add Beneficiary", href: "/beneficiary" },
{ label: "View Beneficiary", href: "/beneficiary/view_beneficiary" }, { label: "View Beneficiary", href: "/beneficiary/view_beneficiary" },
]; ];

View File

@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import {TextInput,Button,Select,Title,Paper,Grid,Group,Radio,Text,PasswordInput} from '@mantine/core'; import {TextInput,Button,Select,Title,Paper,Grid,Group,Radio,Text,PasswordInput} from '@mantine/core';
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import AddBeneficiaryOthers from './addBeneficiaryOthers'; import AddBeneficiaryOthers from '@/app/(main)/beneficiary/add_beneficiary/addBeneficiaryOthers';
const bankOptions = [ const bankOptions = [

View File

@@ -165,7 +165,7 @@ export default function ViewBeneficiary() {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Login-Type": "IB", "X-Login-Type": "IB",
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
@@ -216,23 +216,42 @@ export default function ViewBeneficiary() {
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={400}>
<Title order={3} mb="md">My Beneficiaries</Title> <Group justify="space-between" align="center" mb="md" wrap="wrap">
<Title order={3}>My Beneficiaries</Title>
<Button
color="green"
variant="filled"
size="sm"
component="a"
href="/beneficiary"
style={{ minWidth: "150px" }}
>
+ Add Beneficiary
</Button>
</Group>
{beneficiaries.length === 0 ? ( {beneficiaries.length === 0 ? (
<Text>No beneficiaries found.</Text> <Text>No beneficiaries found.</Text>
) : ( ) : (
<> <>
<ScrollArea h={300} type="always"> <ScrollArea h={300} type="always">
<Table highlightOnHover withTableBorder stickyHeader style={{ borderCollapse: "collapse", width: "100%" }}> <Table highlightOnHover withTableBorder stickyHeader style={{ borderCollapse: "collapse", width: "100%" }}>
<Table.Thead> <thead style={{
<Table.Tr style={{ backgroundColor: "#3385ff" }}> background: "linear-gradient(56deg, rgba(24,140,186,1) 0%, rgba(62,230,132,1) 86%)",
<Table.Th>Bank</Table.Th> position: "sticky",
top: 0,
zIndex: 5,
}}>
<tr>
<Table.Th >Bank</Table.Th>
<Table.Th style={{ textAlign: "right" }}>Account No</Table.Th> <Table.Th style={{ textAlign: "right" }}>Account No</Table.Th>
<Table.Th>Name</Table.Th> <Table.Th >Name</Table.Th>
<Table.Th>Type</Table.Th> <Table.Th >Type</Table.Th>
<Table.Th style={{ textAlign: "center" }}>IFSC</Table.Th> <Table.Th style={{ textAlign: "center" }}>IFSC</Table.Th>
<Table.Th style={{ textAlign: "center" }}>Action Icon</Table.Th> <Table.Th style={{ textAlign: "center" }}>Action Icon</Table.Th>
</Table.Tr> </tr>
</Table.Thead> </thead>
<Table.Tbody> <Table.Tbody>
{beneficiaries.map((b, i) => ( {beneficiaries.map((b, i) => (
<Table.Tr key={i}> <Table.Tr key={i}>

View File

@@ -115,7 +115,7 @@ export default function QuickPay() {
}); });
const data = await response.json(); const data = await response.json();
if (response.ok && Array.isArray(data)) { if (response.ok && Array.isArray(data)) {
const filterSAaccount = data.filter((acc) => ['SA', 'SB'].includes(acc.stAccountType)); const filterSAaccount = data.filter((acc) => ['SA', 'SB','CC','OD','CA'].includes(acc.stAccountType));
setAccountData(filterSAaccount); setAccountData(filterSAaccount);
} }
} catch { } catch {
@@ -395,12 +395,12 @@ export default function QuickPay() {
</Group> </Group>
</Modal> </Modal>
{/* main content */} {/* main content */}
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={3} mb="md"> <Title order={3} mb="md">
Quick Pay - Own Bank Quick Pay - Own Bank
</Title> </Title>
<div style={{ maxHeight: "290px", overflowY: "auto" }}> <div style={{ maxHeight: "350px", overflowY: "auto" }}>
<Stack gap="xs"> <Stack gap="xs">
<Group grow> <Group grow>
<Select <Select

View File

@@ -143,7 +143,7 @@ export default function SendToBeneficiaryOwn() {
}); });
const data = await response.json(); const data = await response.json();
if (response.ok && Array.isArray(data)) { if (response.ok && Array.isArray(data)) {
const filterSAaccount = data.filter((acc) => ['SA', 'SB'].includes(acc.stAccountType)); const filterSAaccount = data.filter((acc) => ['SA', 'SB','CC','OD','CA'].includes(acc.stAccountType));
setAccountData(filterSAaccount); setAccountData(filterSAaccount);
} }
} catch { } catch {

View File

@@ -200,7 +200,7 @@ export default function SendToBeneficiaryOthers() {
}); });
const data = await response.json(); const data = await response.json();
if (response.ok && Array.isArray(data)) { if (response.ok && Array.isArray(data)) {
const filterSAaccount = data.filter((acc) => ['SA', 'SB'].includes(acc.stAccountType)); const filterSAaccount = data.filter((acc) => ['SA', 'SB','CC','OD','CA'].includes(acc.stAccountType));
setAccountData(filterSAaccount); setAccountData(filterSAaccount);
} }
} catch { } catch {

View File

@@ -21,6 +21,7 @@ export default function Home() {
const [authorized, SetAuthorized] = useState<boolean | null>(null); const [authorized, SetAuthorized] = useState<boolean | null>(null);
const router = useRouter(); const router = useRouter();
const isMobile = useMediaQuery("(max-width: 768px)"); const isMobile = useMediaQuery("(max-width: 768px)");
const [userName, setUserName] = useState<string>("");
const [accountData, SetAccountData] = useState<accountData[]>([]); const [accountData, SetAccountData] = useState<accountData[]>([]);
const depositAccounts = accountData.filter(acc => acc.stAccountType !== "LN"); const depositAccounts = accountData.filter(acc => acc.stAccountType !== "LN");
const [selectedDA, setSelectedDA] = useState(depositAccounts[0]?.stAccountNo || ""); const [selectedDA, setSelectedDA] = useState(depositAccounts[0]?.stAccountNo || "");
@@ -33,31 +34,31 @@ export default function Home() {
const [loadingAccountNo, setLoadingAccountNo] = useState<string | null>(null); const [loadingAccountNo, setLoadingAccountNo] = useState<string | null>(null);
// If back and forward button is clicked // If back and forward button is clicked
// useEffect(() => { useEffect(() => {
// window.history.pushState(null, "", window.location.href); window.history.pushState(null, "", window.location.href);
// const handlePopState = () => { const handlePopState = () => {
// localStorage.removeItem("access_token"); localStorage.removeItem("access_token");
// sessionStorage.removeItem("access_token"); sessionStorage.removeItem("access_token");
// localStorage.removeItem("remitter_name"); localStorage.removeItem("remitter_name");
// localStorage.removeItem("pswExpiryDate"); localStorage.removeItem("pswExpiryDate");
// localStorage.clear(); localStorage.clear();
// sessionStorage.clear(); sessionStorage.clear();
// router.push("/login"); router.push("/login");
// }; };
// const handleBeforeUnload = () => { const handleBeforeUnload = () => {
// // logout on tab close / refresh // logout on tab close / refresh
// localStorage.removeItem("access_token"); localStorage.removeItem("access_token");
// sessionStorage.removeItem("access_token"); sessionStorage.removeItem("access_token");
// localStorage.clear(); localStorage.clear();
// sessionStorage.clear(); sessionStorage.clear();
// }; };
// window.addEventListener("popstate", handlePopState); window.addEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("beforeunload", handleBeforeUnload);
// return () => { return () => {
// window.removeEventListener("popstate", handlePopState); window.removeEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("beforeunload", handleBeforeUnload);
// }; };
// }, []); }, []);
async function handleFetchUserDetails() { async function handleFetchUserDetails() {
try { try {
@@ -66,7 +67,7 @@ export default function Home() {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
"X-Login-Type": "IB", "X-Login-Type": "IB",
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`
}, },
}); });
@@ -117,6 +118,9 @@ export default function Home() {
useEffect(() => { useEffect(() => {
if (authorized) { if (authorized) {
handleFetchUserDetails(); handleFetchUserDetails();
const fullName = localStorage.getItem("remitter_name") || "User";
// const first = fullName.split(" ")[0];
setUserName(fullName);
} }
}, [authorized]); }, [authorized]);
@@ -124,38 +128,188 @@ export default function Home() {
return ( return (
<Providers> <Providers>
<Box p={isMobile ? "8px" : "10px"}> <Box p={isMobile ? "8px" : "10px"}>
<Title order={4} style={{ fontSize: isMobile ? "18px" : "22px" }}>
{/* ---------------------- 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 Accounts Overview
</Title> </Title>
{/* Show Balance Switch */}
<Text size="sm" c="dimmed" mb={isMobile ? 10 : 14}>
Your accounts at a glance
</Text>
{/* --------------------- SHOW BALANCE TOGGLE ---------------------- */}
<Group <Group
style={{ style={{
flex: 1, marginBottom: isMobile ? "10px" : "14px",
// padding: isMobile ? "5px" : "10px 10px 4px 10px",
marginLeft: isMobile ? 0 : "10px",
display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "flex-start", justifyContent: "flex-start",
height: "auto", gap: 10,
gap: isMobile ? 5 : 10,
}} }}
> >
<IconEye size={isMobile ? 16 : 20} /> <IconEye size={isMobile ? 16 : 20} />
<Text fw={700} style={{ fontFamily: "inter", fontSize: isMobile ? "14px" : "17px" }}> <Text fw={700} style={{ fontSize: isMobile ? "14px" : "18px" }}>
Show Balance Show Balance
</Text> </Text>
<Switch <Switch
size={isMobile ? "sm" : "md"} size={isMobile ? "sm" : "md"}
onLabel="ON"
offLabel="OFF"
checked={showBalance} checked={showBalance}
onChange={(event) => setShowBalance(event.currentTarget.checked)} onChange={(event) => setShowBalance(event.currentTarget.checked)}
/> />
</Group> </Group>
{/* Cards Section */} {/* ----------------------- DESKTOP VIEW ------------------------ */}
{isMobile ? ( {!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" }}> <Stack gap="md" style={{ width: "100%", marginTop: "10px" }}>
{/* Deposit Account Card */} {/* Deposit Account Card */}
<Paper <Paper
@@ -189,7 +343,7 @@ export default function Home() {
backgroundColor: "white", backgroundColor: "white",
color: "black", color: "black",
marginLeft: 5, marginLeft: 5,
width: "120px", width: "150px",
}, },
}} }}
/> />
@@ -262,7 +416,7 @@ export default function Home() {
backgroundColor: "white", backgroundColor: "white",
color: "black", color: "black",
marginLeft: 5, marginLeft: 5,
width: "120px", width: "150px",
}, },
}} }}
/> />
@@ -333,157 +487,19 @@ export default function Home() {
</Stack> </Stack>
</Paper> </Paper>
</Stack> </Stack>
) : (
<Group grow gap="md" style={{ width: "100%", marginTop: "10px" }}>
{/* Desktop Cards */}
{/* Deposit Account Card */}
<Paper p="md" radius="md" style={{ backgroundColor: "#c1e0f0", width: 350, height: 195, display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
<Group gap="xs">
<IconBuildingBank size={25} />
<Text fw={700}>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: 140,
},
}}
/>
) : (
<Text c="dimmed" size="sm" ml="sm">
No deposit account available
</Text>
)}
</Group>
{depositAccounts.length > 0 ? (
<>
<Text c="dimmed">{Number(selectedDAData?.stAccountNo || 0)}</Text>
<Title order={2} 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: 355, height: 195, display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
<Group gap="xs">
<IconBuildingBank size={25} />
<Text fw={700}>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: 30,
width: 140,
},
}}
/>
) : (
<Text c="dimmed" size="sm" ml="sm">
No loan account available
</Text>
)}
</Group>
{loanAccounts.length > 0 ? (
<>
<Text c="dimmed">{Number(selectedLNData?.stAccountNo || 0)}</Text>
<Title order={2} 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: 300, backgroundColor: "#FFFFFF", border: "1px solid grey" }}>
<Title order={5} mb="sm">
Quick Links
</Title>
<Stack gap="xs">
<Button variant="light" color="blue" fullWidth>
Loan EMI Calculator
</Button>
<Button variant="light" color="blue" fullWidth>
Branch Locator
</Button>
<Button variant="light" color="blue" fullWidth>
Customer Care
</Button>
<Button variant="light" color="blue" fullWidth>
FAQs
</Button>
</Stack>
</Paper>
</Group>
)} )}
{/* Notes Section */} {/* -------------------- NOTES SECTION (BOTTOM) --------------------- */}
<Box style={{ padding: "5px", display: "flex", justifyContent: "left" }}> <Box mt="md">
<Stack> <Stack>
<Text fw={700}> ** Book Balance includes uncleared effect.</Text> <Text fw={700}> ** Book Balance includes uncleared effect.</Text>
<Text fw={700}> ** Click on the &quot;Show Balance&quot; to display balance for the Deposit and Loan account.</Text> <Text fw={700}> ** Click "Show Balance" to display account balances.</Text>
<Text fw={400} c="red"> <Text fw={400} c="red">
** Your Password will expire in {PassExpiryRemains} days. ** Your Password will expire in {PassExpiryRemains} days.
</Text> </Text>
</Stack> </Stack>
</Box> </Box>
</Box> </Box>
</Providers> </Providers>
); );

View File

@@ -48,26 +48,26 @@ export default function RootLayout({ children }: { children: React.ReactNode })
}; };
// When reload and click on back then logout // When reload and click on back then logout
// useEffect(() => { useEffect(() => {
// // Push fake history state to trap navigation // Push fake history state to trap navigation
// window.history.pushState(null, "", window.location.href); window.history.pushState(null, "", window.location.href);
// const handlePopState = () => { const handlePopState = () => {
// doLogout(); // logout when back/forward pressed doLogout(); // logout when back/forward pressed
// }; };
// const handleBeforeUnload = (e: BeforeUnloadEvent) => { const handleBeforeUnload = (e: BeforeUnloadEvent) => {
// // logout on tab close / refresh // logout on tab close / refresh
// localStorage.removeItem("access_token"); localStorage.removeItem("access_token");
// sessionStorage.removeItem("access_token"); sessionStorage.removeItem("access_token");
// localStorage.clear(); localStorage.clear();
// sessionStorage.clear(); sessionStorage.clear();
// }; };
// window.addEventListener("popstate", handlePopState); window.addEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("beforeunload", handleBeforeUnload);
// return () => { return () => {
// window.removeEventListener("popstate", handlePopState); window.removeEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("beforeunload", handleBeforeUnload);
// }; };
// }, []); }, []);
useEffect(() => { useEffect(() => {
const token = localStorage.getItem("access_token"); const token = localStorage.getItem("access_token");
@@ -183,7 +183,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
{ href: "/home", label: "Home", icon: IconHome }, { href: "/home", label: "Home", icon: IconHome },
{ href: "/accounts", label: "Accounts", icon: IconWallet }, { href: "/accounts", label: "Accounts", icon: IconWallet },
{ href: "/funds_transfer", label: "Fund Transfer", icon: IconSend }, { href: "/funds_transfer", label: "Fund Transfer", icon: IconSend },
{ href: "/beneficiary/add_beneficiary", label: "Beneficiaries", icon: IconUsers }, { href: "/beneficiary", label: "Beneficiaries", icon: IconUsers },
{ href: "/settings", label: "Settings", icon: IconSettings }, { href: "/settings", label: "Settings", icon: IconSettings },
]; ];
@@ -200,154 +200,165 @@ export default function RootLayout({ children }: { children: React.ReactNode })
className={styles.header} className={styles.header}
style={{ style={{
width: "100%", width: "100%",
padding: "0.8rem 2rem", padding: isMobile ? "0.6rem 1rem" : "0.8rem 2rem",
background: darkMode background: darkMode
? "linear-gradient(15deg, rgba(229, 101, 22, 1) 55%, rgba(28, 28, 30, 1) 100%)" // Dark Mode Gradient ? "linear-gradient(15deg, rgba(229, 101, 22, 1) 55%, rgba(28, 28, 30, 1) 100%)"
: "linear-gradient(deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)", // Light Mode Gradient : "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
color: "white", color: "white",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)", boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
position: "sticky", position: "sticky",
top: 0, top: 0,
zIndex: 100, zIndex: 200, // ↑ Increased for stability
}} }}
> >
<Group gap="md"> <Group gap="md" wrap="nowrap">
<Image <Image
src={logo} src={logo}
component={NextImage} component={NextImage}
fit="contain" fit="contain"
alt="ebanking" alt="ebanking"
style={{ width: "60px", height: "auto" }} style={{
width: isMobile ? "40px" : "60px",
height: "auto",
}}
/> />
<div> <div>
<Title order={3} style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}> <Title
order={isMobile ? 4 : 3}
style={{
fontFamily: "Roboto",
color: "white",
marginBottom: 2,
fontSize: isMobile ? "14px" : "22px",
lineHeight: 1.2,
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD. THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title> </Title>
<Text size="xs" c="white" style={{ opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215 {!isMobile && (
</Text> <Text size="xs" c="white" style={{ opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
)}
</div> </div>
</Group> </Group>
{/* Dark/Light Mode Toggle using Moon and Sun Icons */} {/* USER BUTTON */}
<Group> <Popover
{/* <Button opened={userOpened}
onClick={toggleDarkMode} onChange={setUserOpened}
variant="subtle" position="bottom-end"
color={darkMode ? "yellow" : "blue"} withArrow
style={{ marginRight: 12 }} shadow="md"
> >
{darkMode ? <IconSun size={20} /> : <IconMoon size={20} />} <Popover.Target>
</Button> */} <Button
<Popover opened={userOpened} onChange={setUserOpened} position="bottom-end" withArrow shadow="md"> leftSection={<IconUserCircle size={isMobile ? 18 : 22} />}
<Popover.Target> variant="subtle"
onClick={() => setUserOpened((prev) => !prev)}
color='white'
style={{
fontWeight: 500,
padding: isMobile ? "4px 8px" : "6px 12px",
fontSize: isMobile ? "12px" : "14px",
}}
>
Welcome, {firstName}
</Button>
</Popover.Target>
<Popover.Dropdown style={{ minWidth: 230, padding: 15 }}>
<Stack gap="xs">
<Box>
<Text size="sm" fw={700}>{custname}</Text>
<Text size="xs" c="dimmed">Full Name</Text>
</Box>
<Box>
<Text size="sm">
{userLastLoginDetails
? new Date(userLastLoginDetails).toLocaleString()
: "N/A"}
</Text>
<Text size="xs" c="dimmed">Last Login</Text>
</Box>
<Divider />
<Button <Button
leftSection={<IconUserCircle size={22} />} leftSection={<IconLogout size={18} />}
variant="subtle" onClick={handleLogout}
onClick={() => setUserOpened((prev) => !prev)}
color='white'
style={{ fontWeight: 500 }}
> >
Welcome, {firstName} Logout
</Button> </Button>
</Popover.Target> </Stack>
</Popover.Dropdown>
<Popover.Dropdown style={{ minWidth: 230, padding: 15 }}> </Popover>
<Stack gap="xs">
<Box>
<Text size="sm" fw={700}>{custname}</Text>
<Text size="xs" c="dimmed">Full Name</Text>
</Box>
<Box>
<Text size="sm">
{userLastLoginDetails
? new Date(userLastLoginDetails).toLocaleString()
: "N/A"}
</Text>
<Text size="xs" c="dimmed">Last Login</Text>
</Box>
<Divider />
<Button
leftSection={<IconLogout size={18} />}
onClick={handleLogout}
>
Logout
</Button>
</Stack>
</Popover.Dropdown>
</Popover>
</Group>
</Box> </Box>
{/* WELCOME + NAV */} {/* NAVBAR — desktop unchanged, mobile scrollable */}
<Group <Group
style={{ style={{
// padding: "0.8rem",
background: "#d3f3bcff", background: "#d3f3bcff",
// borderRadius: 8,
boxShadow: "0 6px 6px rgba(0,0,0,0.06)", boxShadow: "0 6px 6px rgba(0,0,0,0.06)",
position:'sticky', position: "sticky",
top: 85, top: isMobile ? 60 : 85,
zIndex: 100, zIndex: 150,
/* MOBILE FIX 👉 make it scrollable */
overflowX: isMobile ? "auto" : "visible",
whiteSpace: isMobile ? "nowrap" : "normal",
padding: isMobile ? "6px 4px" : "0.8rem",
}} }}
> >
{navItems.map((item) => { {navItems.map((item) => {
const isActive = pathname.startsWith(item.href); const isActive = pathname.startsWith(item.href);
const Icon = item.icon; const Icon = item.icon;
return ( return (
<Link <Link key={item.href} href={item.href} style={{ textDecoration: "none" }}>
key={item.href}
href={item.href}
style={{ textDecoration: "none" }}
>
<Group <Group
gap={8} gap={8}
style={{ style={{
padding: "12px 24px", padding: isMobile ? "10px 14px" : "12px 24px",
// borderRadius: 10, // borderRadius: isMobile ? 6 : 8,
width: "100%", width: "100%",
transition: "0.2s ease", transition: "0.2s ease",
background: isActive ? "rgba(50, 159, 81, 1)" : "transparent", background: isActive ? "rgba(50, 159, 81, 1)" : "transparent",
color: isActive ? "#10a44bff" : "#3b3b3b", color: isActive ? "white" : "#3b3b3b",
fontWeight: isActive ? 600 : 500, fontWeight: isActive ? 600 : 500,
}} }}
> >
<Icon <Icon
size={18} size={isMobile ? 16 : 18}
color={isActive ? "#0f100fea" : "#3b3b3b"} color={isActive ? "white" : "#3b3b3b"}
/> />
<Text size={isMobile ? "xs" : "sm"} fw={500}>
<Text size="sm" c='black' fw={500}>
{item.label} {item.label}
</Text> </Text>
</Group> </Group>
</Link> </Link>
); );
})} })}
</Group> </Group>
{/* CHILDREN */} {/* CONTENT */}
<Box <Box
style={{ style={{
flex: 1, flex: 1,
backgroundColor: "#f5f7fa", backgroundColor: "#f5f7fa",
padding: "1.5rem", padding: isMobile ? "0.8rem" : "1.5rem",
}} }}
> >
<Box <Box
style={{ style={{
// maxWidth: "1200px",
margin: "0 auto", margin: "0 auto",
background: "white", background: "white",
padding: "1.8rem", padding: isMobile ? "1rem" : "1.8rem",
borderRadius: "12px", borderRadius: "12px",
boxShadow: "0 4px 12px rgba(0,0,0,0.08)", boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
minHeight: "75vh", minHeight: "75vh",
@@ -384,18 +395,19 @@ export default function RootLayout({ children }: { children: React.ReactNode })
</Stack> </Stack>
</Modal> </Modal>
{/* FOOTER */} {/* FOOTER (desktop same, mobile stacked) */}
<Box <Box
component="footer" component="footer"
style={(theme) => ({ style={{
borderTop: `1px solid `, backgroundColor: "rgba(60, 54, 74, 1)",
backgroundColor: 'rgba(60, 54, 74, 1)', paddingTop: "2rem",
paddingTop: '2rem', paddingBottom: "2rem",
paddingBottom: '2rem', color: "white",
})} }}
> >
<Container size="xl"> <Container size="xl">
<Grid> <Grid gutter="xl">
<Grid.Col span={{ base: 12, md: 4 }}> <Grid.Col span={{ base: 12, md: 4 }}>
<Group mb="md"> <Group mb="md">
<Box <Box
@@ -404,96 +416,68 @@ export default function RootLayout({ children }: { children: React.ReactNode })
height: 40, height: 40,
background: 'linear-gradient(135deg, #16a34a 0%, #10b981 100%)', background: 'linear-gradient(135deg, #16a34a 0%, #10b981 100%)',
borderRadius: '50%', borderRadius: '50%',
display: 'flex', overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
padding: 8,
}} }}
> >
<Image <Image
src={logo} src={logo}
component={NextImage} component={NextImage}
fit="cover" // This ensures the image covers the circle fit="cover"
alt="ebanking" alt="ebanking"
style={{ style={{
width: "100%", width: "100%",
height: "100%", height: "100%",
objectFit: "cover", // Ensures the logo covers the whole circular area borderRadius: "50%",
borderRadius: '50%',
}} }}
/> />
</Box> </Box>
<div> <div>
<Text size="sm" fw={500}> <Text size="sm" fw={500}>The Kangra Central</Text>
The Kangra Central
</Text>
<Text size="xs">Co-operative Bank Ltd</Text> <Text size="xs">Co-operative Bank Ltd</Text>
</div> </div>
</Group> </Group>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
Serving the community since inception. We are committed to providing quality Serving the community since inception.
banking services with personalized care and customer satisfaction.
</Text> </Text>
</Grid.Col> </Grid.Col>
<Grid.Col span={{ base: 12, md: 4 }}> <Grid.Col span={{ base: 12, md: 4 }}>
<Text size="sm" fw={500} mb="md"> <Text size="sm" fw={500} mb="md">Quick Links</Text>
Quick Links
</Text>
<Stack gap="xs"> <Stack gap="xs">
<Anchor href="#" size="sm" c="dimmed"> <Anchor href="#" size="sm" c="dimmed">About Us</Anchor>
About Us <Anchor href="#" size="sm" c="dimmed">Products & Services</Anchor>
</Anchor> <Anchor href="#" size="sm" c="dimmed">Help & Support</Anchor>
<Anchor href="#" size="sm" c="dimmed">
Products & Services
</Anchor>
<Anchor href="#" size="sm" c="dimmed">
Help & Support
</Anchor>
<Anchor href="#" size="sm" c="dimmed">
Terms & Conditions
</Anchor>
</Stack> </Stack>
</Grid.Col> </Grid.Col>
<Grid.Col span={{ base: 12, md: 4 }}> <Grid.Col span={{ base: 12, md: 4 }}>
<Text size="sm" fw={500} mb="md"> <Text size="sm" fw={500} mb="md">Contact Us</Text>
Contact Us
</Text>
<Stack gap="xs"> <Stack gap="xs">
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">Phone: +91-1800-1808008</Text>
Phone: +91-1800-1808008 <Text size="sm" c="dimmed">MonFri 10 AM 4 PM</Text>
</Text> <Text size="sm" c="dimmed">Sat 10 AM 2 PM</Text>
<Text size="sm" c="dimmed">
Hours: Mon-Fri 10:00 AM - 4:00 PM
</Text>
<Text size="sm" c="dimmed">
Sat 10:00 AM - 2:00 PM
</Text>
</Stack> </Stack>
</Grid.Col> </Grid.Col>
</Grid> </Grid>
<Text <Text
size="sm" size="sm"
c="dimmed" c="dimmed"
ta="center" ta="center"
// mt="xl" style={{ borderTop: "1px solid rgba(255,255,255,0.2)", marginTop: 20, paddingTop: 20 }}
// pt="xl"
style={(theme) => ({
borderTop: `1px solid `
})}
> >
© 2025 The Kangra Central Co-operative Bank Ltd. All rights reserved. | Privacy Policy | © 2025 The Kangra Central Co-operative Bank Ltd. All rights reserved.
Security
</Text> </Text>
</Container> </Container>
</Box> </Box>
</Box> </Box>
</Providers> </Providers>
</body> </body>
</html > </html>
); );
} }
} }

View File

@@ -240,7 +240,7 @@ export default function ChangePassword() {
}; };
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={3} mb="sm"> <Title order={3} mb="sm">
Change Transaction Password Change Transaction Password
</Title> </Title>

View File

@@ -107,7 +107,7 @@ export default function ViewProfile() {
); );
return ( return (
<Paper shadow="xs" radius="md" p="md" withBorder h={400}> <Paper shadow="xs" radius="md" p="md" withBorder h={500}>
<Title order={4} mb="sm"> <Title order={4} mb="sm">
View Profile View Profile
</Title> </Title>

View File

@@ -224,7 +224,7 @@ export default function SetTransactionLimit() {
}; };
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400}> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={3} mb="sm"> <Title order={3} mb="sm">
Set Transaction Limit Set Transaction Limit
</Title> </Title>
@@ -237,9 +237,13 @@ export default function SetTransactionLimit() {
value={limit} value={limit}
onChange={(e) => { onChange={(e) => {
const val = e.currentTarget.value; const val = e.currentTarget.value;
// Only allow digits
// Allow only digits AND max value 500000
if (/^\d*$/.test(val)) { if (/^\d*$/.test(val)) {
setLimit(val); const num = Number(val);
if (num <= 500000) {
setLimit(val);
}
} }
}} }}
leftSection={icon} leftSection={icon}
@@ -247,6 +251,7 @@ export default function SetTransactionLimit() {
mb="sm" mb="sm"
readOnly={step !== "form"} readOnly={step !== "form"}
/> />
</Group> </Group>
{dailyLimit !== null ? ( {dailyLimit !== null ? (
<Text size="xs" c="green"> <Text size="xs" c="green">

View File

@@ -240,7 +240,7 @@ export default function ChangePassword() {
}; };
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder h={400} > <Paper shadow="sm" radius="md" p="md" withBorder h={500} >
<Title order={3} mb="sm"> <Title order={3} mb="sm">
Set Transaction Password Set Transaction Password
</Title> </Title>

View File

@@ -261,7 +261,7 @@ export default function SetPreferredNameSimple() {
if (loading) return <Text>Loading...</Text>; if (loading) return <Text>Loading...</Text>;
return ( return (
<Paper shadow="sm" radius="md" p="md" withBorder> <Paper shadow="sm" radius="md" p="md" withBorder h={500}>
<Title order={3} mb="sm"> <Title order={3} mb="sm">
Set Preferred Name Set Preferred Name
</Title> </Title>

232
src/app/ATMLocator/page.tsx Normal file
View File

@@ -0,0 +1,232 @@
"use client";
import { useEffect, useState } from "react";
import { Box, Button, Group, Stack, Text, Paper, Collapse, Title, Image } from "@mantine/core";
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { useMediaQuery } from "@mantine/hooks";
import NextImage from "next/image";
import logo from "@/app/image/logo1.jpg";
export default function ATMListPage() {
const [atms, setAtms] = useState([]);
const [openedIndex, setOpenedIndex] = useState<number | null>(null);
const [authorized, setAuthorized] = useState<boolean | null>(null);
const isMobile = useMediaQuery("(max-width: 768px)");
const router = useRouter();
// ✔ Authorization Check
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
setAuthorized(false);
router.push("/login");
} else {
setAuthorized(true);
}
}, []);
// ✔ Fetch ATM Data
useEffect(() => {
async function fetchData() {
try {
const token = localStorage.getItem("access_token");
const response = await fetch("/api/atm", {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Login-Type": "IB",
Authorization: `Bearer ${token}`,
},
});
const result = await response.json();
const list = Array.isArray(result)
? result
: Array.isArray(result.data)
? result.data
: [];
setAtms(list);
} catch (error) {
console.error("ATM list API error:", error);
setAtms([]);
}
}
if (authorized) fetchData();
}, [authorized]);
// Wait until auth is checked
if (authorized === null) return null;
const toggleRow = (index: number) => {
setOpenedIndex((prev) => (prev === index ? null : index));
};
return (
<Box
style={{
height: "100vh",
display: "flex",
flexDirection: "column",
overflow: "hidden",
}}
>
{/* HEADER */}
<Box
component="header"
style={{
width: "100%",
padding: isMobile ? "0.6rem 1rem" : "0.8rem 2rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
color: "white",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
flexShrink: 0,
}}
>
<Group gap="md" wrap="nowrap" align="center">
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: isMobile ? "45px" : "60px", height: "auto" }}
/>
<div>
<Title
order={isMobile ? 4 : 3}
style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
{!isMobile && (
<Text size="xs" c="white" style={{ opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
)}
</div>
</Group>
</Box>
{/* SECOND FIXED BAR */}
<Box
style={{
width: "100%",
padding: isMobile ? "0.5rem 1rem" : "0.6rem 1.5rem",
background: "#ffffff",
borderBottom: "1px solid #ddd",
position: "sticky",
top: isMobile ? "65px" : "70px",
zIndex: 200,
display: "flex",
alignItems: "center",
}}
>
<Text
fw={700}
size={isMobile ? "md" : "lg"}
ta="center"
style={{ flex: 1 }}
>
List of Available ATMs
</Text>
<Button
variant="light"
color="red"
size={isMobile ? "xs" : "sm"}
onClick={() => window.close()}
style={{ marginLeft: "auto" }}
>
Close
</Button>
</Box>
{/* SCROLLABLE CONTENT */}
<Box
style={{
flex: 1,
overflowY: "auto",
padding: isMobile ? "0.5rem" : "1rem",
paddingTop: isMobile ? "60px" : "40px",
}}
>
<Stack>
{atms.map((atm: any, index: number) => {
const isOpen = openedIndex === index;
return (
<Paper
key={index}
p={isMobile ? "sm" : "md"}
radius="md"
withBorder
shadow="xs"
>
<Group justify="space-between" wrap="nowrap">
<Text fw={600} size={isMobile ? "sm" : "md"}>
{atm.name}
</Text>
<Button
variant="subtle"
size={isMobile ? "xs" : "md"}
onClick={() => toggleRow(index)}
leftSection={
isOpen ? <IconChevronUp size={18} /> : <IconChevronDown size={18} />
}
>
{isOpen ? "Hide" : "View"}
</Button>
</Group>
{/* ATM Extra Info */}
<Collapse in={isOpen}>
<Box mt="md" ml="md">
<Text size={isMobile ? "xs" : "sm"}>
<b>ATM Name:</b> {atm.name}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Availability:</b> 24x7
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Type:</b> Cash Withdrawal Only
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Status:</b>{" "}
<span style={{ color: "green", fontWeight: 600 }}>Active</span>
</Text>
</Box>
</Collapse>
</Paper>
);
})}
</Stack>
</Box>
{/* FOOTER */}
<Box
component="footer"
style={{
width: "100%",
textAlign: "center",
padding: isMobile ? "8px" : "12px 0",
background: "#ffffff",
borderTop: "1px solid #ddd",
flexShrink: 0,
}}
>
<Text size={isMobile ? "xs" : "sm"} c="dimmed">
© 2025 KCC Bank. All rights reserved.
</Text>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,254 @@
"use client";
import { useEffect, useState } from "react";
import { Box, Button, Group, Stack, Text, Paper, Collapse, Title, Image } from "@mantine/core";
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
import NextImage from 'next/image';
import logo from '@/app/image/logo1.jpg';
import { useRouter } from "next/navigation";
import { useMediaQuery } from "@mantine/hooks";
export default function BranchListPage() {
const [branches, setBranches] = useState([]);
const [openedIndex, setOpenedIndex] = useState<number | null>(null);
const [authorized, SetAuthorized] = useState<boolean | null>(null);
const isMobile = useMediaQuery("(max-width: 768px)");
const router = useRouter();
// Fetch branch API
useEffect(() => {
async function fetchData() {
try {
const token = localStorage.getItem("access_token");
const response = await fetch('api/branch', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
"X-Login-Type": "IB",
'Authorization': `Bearer ${token}`
},
});
const result = await response.json();
// Handle any response shape
const list =
Array.isArray(result) ? result :
Array.isArray(result.data) ? result.data :
Array.isArray(result.branches) ? result.branches :
[];
setBranches(list);
} catch (error) {
console.error("Error fetching branches:", error);
setBranches([]);
}
}
fetchData();
}, []);
useEffect(() => {
const token = localStorage.getItem("access_token");
if (!token) {
SetAuthorized(false);
router.push("/login");
}
else {
SetAuthorized(true);
}
}, []);
const toggleRow = (index: number) => {
setOpenedIndex((prev) => (prev === index ? null : index));
};
if (authorized === null) {
return null; // Prevent rendering until check is done
}
return (
<Box
style={{
height: "100vh",
display: "flex",
flexDirection: "column",
overflow: "hidden",
}}
>
{/* HEADER */}
<Box
component="header"
style={{
width: "100%",
padding: isMobile ? "0.6rem 1rem" : "0.8rem 2rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
alignItems: isMobile ? "flex-start" : "center",
justifyContent: "space-between",
color: "white",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
flexShrink: 0,
}}
>
<Group gap="md" wrap="nowrap" align="center">
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: isMobile ? "45px" : "60px", height: "auto" }}
/>
<div>
<Title
order={isMobile ? 4 : 3}
style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
{!isMobile && (
<Text size="xs" c="white" style={{ opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
)}
</div>
</Group>
</Box>
{/* SECOND FIXED BAR */}
<Box
style={{
width: "100%",
padding: isMobile ? "0.5rem 1rem" : "0.6rem 1.5rem",
background: "#ffffff",
borderBottom: "1px solid #ddd",
position: "sticky",
top: isMobile ? "65px" : "70px",
zIndex: 200,
display: "flex",
alignItems: "center",
}}
>
<Text
fw={700}
size={isMobile ? "md" : "lg"}
ta="center"
style={{ flex: 1 }}
>
List of Branches
</Text>
<Button
variant="light"
color="red"
size={isMobile ? "xs" : "sm"}
onClick={() => window.close()}
style={{ marginLeft: "auto" }}
>
Close
</Button>
</Box>
{/* SCROLLABLE CONTENT */}
<Box
style={{
flex: 1,
overflowY: "auto",
padding: isMobile ? "0.5rem" : "1rem",
paddingTop: isMobile ? "60px" : "40px",
boxShadow: "0 4px 12px rgba(0,0,0,0.08)"
}}>
<Stack>
{branches.map((branch: any, index: number) => {
const isOpen = openedIndex === index;
return (
<Paper
key={branch.branch_code}
p={isMobile ? "sm" : "md"}
radius="md"
withBorder
shadow="xs"
>
<Group justify="space-between" wrap="nowrap">
<Text fw={600} size={isMobile ? "sm" : "md"}>
{branch.branch_name}
</Text>
<Button
variant="subtle"
size={isMobile ? "xs" : "md"}
onClick={() => toggleRow(index)}
leftSection={
isOpen ? (
<IconChevronUp size={18} />
) : (
<IconChevronDown size={18} />
)
}
>
{isOpen ? "Hide" : "View"}
</Button>
</Group>
<Collapse in={isOpen} transitionDuration={200}>
<Box mt="md" ml="md">
<Text size={isMobile ? "xs" : "sm"}>
<b>Branch Code:</b> {branch.branch_code}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Zone:</b> {branch.zone}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Tehsil:</b> {branch.tehsil}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Block:</b> {branch.block}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>District:</b> {branch.distt_name}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<b>Pincode:</b> {branch.pincode}
</Text>
<Text size={isMobile ? "xs" : "sm"}>
<span style={{ fontWeight: 600, color: "black" }}>
Telephone:
</span>{" "}
<span style={{ color: "blue" }}>
{branch.telephone_no}
</span>
</Text>
</Box>
</Collapse>
</Paper>
);
})}
</Stack>
</Box>
{/* FOOTER */}
<Box
component="footer"
style={{
width: "100%",
textAlign: "center",
padding: isMobile ? "8px" : "12px 0",
background: "#ffffff",
borderTop: "1px solid #ddd",
flexShrink: 0,
}}
>
<Text size={isMobile ? "xs" : "sm"} c="dimmed">
© 2025 KCC Bank. All rights reserved.
</Text>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,243 @@
"use client";
import { useEffect, useState } from "react";
import {
Box,
Button,
Group,
Stack,
Text,
Paper,
Title,
Image,
} from "@mantine/core";
import { IconMail, IconPhone, IconChevronLeft } from "@tabler/icons-react";
import { useMediaQuery } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from "@/app/image/logo1.jpg";
export default function EnquiryPage() {
const isMobile = useMediaQuery("(max-width: 768px)");
const router = useRouter();
// FAKE CONTACT LIST — replace with your API if needed
const contacts = [
{
title: "Chairman",
email: "chairman@kccb.in",
phone: "01892-222677",
},
{
title: "Managing Director",
email: "md@kccb.in",
phone: "01892-224960",
},
{
title: "General Manager (West)",
email: "gmw@kccb.in",
phone: "01892-223280",
},
{
title: "General Manager (North)",
email: "gmn@kccb.in",
phone: "01892-224607",
},
];
return (
<Box
style={{
height: "100vh",
display: "flex",
flexDirection: "column",
overflow: "hidden",
}}
>
{/* HEADER */}
<Box
component="header"
style={{
width: "100%",
padding: isMobile ? "0.6rem 1rem" : "0.8rem 2rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
color: "white",
display: "flex",
alignItems: "center",
gap: "1rem",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
flexShrink: 0,
}}
>
<IconChevronLeft
size={28}
style={{ cursor: "pointer" }}
onClick={() => router.back()}
/>
<Group gap="md" wrap="nowrap" align="center">
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{
width: isMobile ? "45px" : "60px",
height: "auto",
}}
/>
<div>
<Title
order={isMobile ? 4 : 3}
style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
{!isMobile && (
<Text size="xs" style={{ color: "white", opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
)}
</div>
</Group>
</Box>
{/* SECOND BAR */}
<Box
style={{
width: "100%",
padding: isMobile ? "0.5rem 1rem" : "0.6rem 1.5rem",
background: "#ffffff",
borderBottom: "1px solid #ddd",
position: "sticky",
top: isMobile ? "65px" : "70px",
zIndex: 200,
display: "flex",
alignItems: "center",
}}
>
<Text
fw={700}
size={isMobile ? "md" : "lg"}
ta="center"
style={{ flex: 1 }}
>
Customer Care
</Text>
<Button
variant="light"
color="red"
size={isMobile ? "xs" : "sm"}
onClick={() => window.close()}
style={{ marginLeft: "auto" }}
>
Close
</Button>
</Box>
{/* BODY CONTENT */}
<Box
style={{
flex: 1,
overflowY: "auto",
padding: isMobile ? "1rem" : "2rem",
background: "#f8f9fa",
}}
>
<Box
style={{
width: "100%",
maxWidth: "1600px",
margin: "0 auto",
}}
>
{/* Complaint Form */}
<Paper
withBorder
p="md"
radius="md"
shadow="sm"
style={{
marginBottom: "1.5rem",
background: "white",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Text fw={600}>Complaint Form</Text>
<Button
size="xs"
variant="subtle"
onClick={() => window.open("https://kccbhp.bank.in/complaint-form/", "_blank")}
>
Register Complain
</Button>
</Paper>
{/* Key Contacts Title */}
<Text fw={700} size="lg" mb="sm">
Key Contacts
</Text>
{/* 2-COLUMN GRID */}
<Box
style={{
display: "grid",
gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr",
gap: "1.2rem",
}}
>
{contacts.map((contact, index) => (
<Paper
key={index}
withBorder
p="lg"
radius="md"
shadow="md"
style={{
background: "white",
minHeight: "120px",
}}
>
<Text fw={600} mb="xs" size="md">
{contact.title}
</Text>
<Group gap="xs" mb={6}>
<IconMail size={18} />
<Text size="sm">{contact.email}</Text>
</Group>
<Group gap="xs">
<IconPhone size={18} />
<Text size="sm">{contact.phone}</Text>
</Group>
</Paper>
))}
</Box>
</Box>
</Box>
{/* FOOTER */}
<Box
component="footer"
style={{
width: "100%",
textAlign: "center",
padding: isMobile ? "8px" : "12px 0",
background: "#ffffff",
borderTop: "1px solid #ddd",
flexShrink: 0,
}}
>
<Text size={isMobile ? "xs" : "sm"} c="dimmed">
© 2025 KCC Bank. All rights reserved.
</Text>
</Box>
</Box>
);
}

243
src/app/FAQs/page.tsx Normal file
View File

@@ -0,0 +1,243 @@
"use client";
import { useEffect, useState } from "react";
import {
Box,
Button,
Group,
Stack,
Text,
Paper,
Collapse,
Title,
Image,
} from "@mantine/core";
import { IconChevronLeft, IconChevronDown, IconChevronUp } from "@tabler/icons-react";
import { useMediaQuery } from "@mantine/hooks";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from "@/app/image/logo1.jpg";
export default function FAQPage() {
const isMobile = useMediaQuery("(max-width: 768px)");
const router = useRouter();
const [openedIndex, setOpenedIndex] = useState<number | null>(null);
const toggleRow = (index: number) => {
setOpenedIndex((prev) => (prev === index ? null : index));
};
// FAQ DATA
const faqs = [
{
question: "How do I log in to the Internet Banking portal?",
answer:
"Open the login page and enter your User ID and Password. You may also be required to verify using an OTP sent to your registered mobile number.",
},
{
question: "Is my banking information secure on this app?",
answer:
"Yes. All transactions are fully encrypted. We use multi-factor authentication, secure session management, and industry-standard protection mechanisms.",
},
{
question: "How can I check my account balance?",
answer:
"Go to the Accounts section after logging in. All your linked accounts and available balances will be displayed instantly.",
},
{
question: "Can I transfer money to other bank accounts?",
answer:
"Yes. You can transfer funds using NEFT, RTGS, IMPS, or within-bank transfers. Add a beneficiary before initiating a transfer.",
},
{
question: "How do I view my transaction history?",
answer:
"Open the 'Account Statement' or 'Transactions' tab. You can filter by date, download a PDF.",
},
// {
// question: "What should I do if I forget my Internet Banking password?",
// answer:
// "Use the 'Forgot Password' option on the login page and follow the steps to reset your password using OTP verification.",
// },
{
question: "How do I update my mobile number or email ID?",
answer:
"You can update your contact details by visiting your nearest branch.",
},
{
question: "What should I do if my account gets locked?",
answer:
"Your account may lock after multiple incorrect login attempts. To unlock your Internet Banking access, please visit your nearest KCC Bank branch or contact customer care.",
},
];
return (
<Box
style={{
height: "100vh",
display: "flex",
flexDirection: "column",
overflow: "hidden",
}}
>
{/* HEADER */}
<Box
component="header"
style={{
width: "100%",
padding: isMobile ? "0.6rem 1rem" : "0.8rem 2rem",
background:
"linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
color: "white",
display: "flex",
alignItems: "center",
gap: "1rem",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
flexShrink: 0,
}}
>
<IconChevronLeft
size={28}
style={{ cursor: "pointer" }}
onClick={() => router.back()}
/>
<Group gap="md" wrap="nowrap" align="center">
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{
width: isMobile ? "45px" : "60px",
height: "auto",
}}
/>
<div>
<Title
order={isMobile ? 4 : 3}
style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
{!isMobile && (
<Text size="xs" style={{ color: "white", opacity: 0.85 }}>
Head Office: Dharmshala, District Kangra (H.P), Pin: 176215
</Text>
)}
</div>
</Group>
</Box>
{/* SECOND BAR */}
<Box
style={{
width: "100%",
padding: isMobile ? "0.5rem 1rem" : "0.6rem 1.5rem",
background: "#ffffff",
borderBottom: "1px solid #ddd",
position: "sticky",
top: isMobile ? "65px" : "70px",
zIndex: 200,
display: "flex",
alignItems: "center",
}}
>
<Text
fw={700}
size={isMobile ? "md" : "lg"}
ta="center"
style={{ flex: 1 }}
>
Frequently Asked Questions
</Text>
<Button
variant="light"
color="red"
size={isMobile ? "xs" : "sm"}
onClick={() => window.close()}
style={{ marginLeft: "auto" }}
>
Close
</Button>
</Box>
{/* BODY CONTENT */}
<Box
style={{
flex: 1,
overflowY: "auto",
padding: isMobile ? "1rem" : "2rem",
background: "#f8f9fa",
}}
>
<Box
style={{
width: "100%",
maxWidth: "900px",
margin: "0 auto",
}}
>
<Stack>
{faqs.map((item, index) => {
const isOpen = openedIndex === index;
return (
<Paper
key={index}
withBorder
radius="md"
p="md"
shadow="xs"
style={{ cursor: "pointer", background: "white" }}
>
{/* QUESTION */}
<Group
justify="space-between"
onClick={() => toggleRow(index)}
>
<Text fw={600} size={isMobile ? "sm" : "md"}>
{item.question}
</Text>
{isOpen ? (
<IconChevronUp size={20} />
) : (
<IconChevronDown size={20} />
)}
</Group>
{/* ANSWER */}
<Collapse in={isOpen}>
<Text size={isMobile ? "xs" : "sm"} mt="sm" c="dimmed">
{item.answer}
</Text>
</Collapse>
</Paper>
);
})}
</Stack>
</Box>
</Box>
{/* FOOTER */}
<Box
component="footer"
style={{
width: "100%",
textAlign: "center",
padding: isMobile ? "8px" : "12px 0",
background: "#ffffff",
borderTop: "1px solid #ddd",
flexShrink: 0,
}}
>
<Text size={isMobile ? "xs" : "sm"} c="dimmed">
© 2025 KCC Bank. All rights reserved.
</Text>
</Box>
</Box>
);
}

View File

@@ -2,14 +2,14 @@
import { MantineColorsTuple, createTheme } from "@mantine/core"; import { MantineColorsTuple, createTheme } from "@mantine/core";
const KccbColors: MantineColorsTuple = [
"#e3f2fd", "#bbdefb", "#90caf9", "#64b5f6", "#42a5f5",
"#2196f3", "#1e88e5", "#1976d2", "#1565c0", "#0d47a1"
];
// const KccbColors: MantineColorsTuple = [ // const KccbColors: MantineColorsTuple = [
// "#e8f5e9", "#c8e6c9", "#a5d6a7", "#81c784", "#66bb6a", // Lighter greens // "#e3f2fd", "#bbdefb", "#90caf9", "#64b5f6", "#42a5f5",
// "#4caf50", "#43a047", "#388e3c", "#2c6f2c", "#1b5e20" // Darker greens // "#2196f3", "#1e88e5", "#1976d2", "#1565c0", "#0d47a1"
// ]; // ];
const KccbColors: MantineColorsTuple = [
"#e8f5e9", "#c8e6c9", "#a5d6a7", "#81c784", "#66bb6a", // Lighter greens
"#4caf50", "#43a047", "#388e3c", "#2c6f2c", "#1b5e20" // Darker greens
];
export const KccbTheme = createTheme({ export const KccbTheme = createTheme({

View File

@@ -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 = "7890544527";
if (!mobileNumber) throw new Error('Mobile number not found.'); if (!mobileNumber) throw new Error('Mobile number not found.');
return mobileNumber; return mobileNumber;
} }

View File

@@ -45,9 +45,9 @@ export default function Login() {
} }
try { try {
// await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
const maskedCIF = CIF?.replace(/.(?=.{3})/g, '*'); const maskedCIF = CIF?.replace(/.(?=.{3})/g, '*');
await sendOtp({ type: 'LOGIN_OTP', username: maskedCIF, mobileNumber: "7890544527" }); await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
// await sendOtp({ type: 'LOGIN_OTP', username: maskedCIF, mobileNumber: "7890544527" });
notifications.show({ notifications.show({
color: 'orange', color: 'orange',
title: 'OTP Required', title: 'OTP Required',
@@ -68,8 +68,8 @@ 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, '7890544527');
return true; return true;
} }
} }