refactor: unified transaction url.

feat: modify admin pages.
This commit is contained in:
2025-08-29 17:11:44 +05:30
parent bbbfcc52d2
commit 78c0fa6e95
9 changed files with 501 additions and 321 deletions

View File

@@ -9,13 +9,13 @@
"lint": "next lint"
},
"dependencies": {
"@mantine/carousel": "^7.4.0",
"@mantine/carousel": "^7.11.1",
"@mantine/charts": "^7.11.1",
"@mantine/core": "^7.8.1",
"@mantine/dates": "^7.8.1",
"@mantine/form": "^7.11.0",
"@mantine/hooks": "^7.8.1",
"@mantine/notifications": "^7.8.1",
"@mantine/core": "^7.11.1",
"@mantine/dates": "^7.11.1",
"@mantine/form": "^7.11.1",
"@mantine/hooks": "^7.11.1",
"@mantine/notifications": "^7.11.1",
"@tabler/icons-react": "^3.28.1",
"@tanstack/react-query": "^5.32.0",
"axios": "^1.6.8",

View File

@@ -146,7 +146,7 @@ export default function AccountStatementPage() {
{/* Left side form */}
<Grid.Col span={{ base: 12, md: 4 }}>
<Paper shadow="sm" radius="md" p="md" withBorder h={400}>
<Title order={4} mb="sm">Account Statement</Title>
<Title order={4} mb="sm">Account Transactions</Title>
<Select
label="Select Account Number"
placeholder="Choose account number"
@@ -176,7 +176,7 @@ export default function AccountStatementPage() {
{/* Right side transaction list */}
<Grid.Col span={{ base: 12, md: 8 }}>
<Paper shadow="sm" radius="md" p="md" withBorder h={400} style={{ display: 'flex', flexDirection: 'column' }}>
<Title order={5} mb="xs">Account Transaction Statement</Title>
<Title order={5} mb="xs">Account Transactions</Title>
<Text fw={500} fs="italic" >Account No : {selectedAccNo}</Text>
<Divider size="xs" />
<ScrollArea style={{ flex: 1 }}>

View File

@@ -338,7 +338,7 @@ export default function QuickPay() {
Quick Pay - Own Bank
</Title>
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
<div style={{ maxHeight: "290px", overflowY: "auto" }}>
<Stack gap="xs">
<Group grow>
<Select
@@ -498,6 +498,17 @@ export default function QuickPay() {
</Button>
</Group>
</Stack>
<Stack gap={1} mt="xs">
<Text size="xs" c="green">
Minimum Transfer Amount on this Day is Rs. 1.00
</Text>
<Text size="xs" c="green">
Maximum Transfer Limit per Day is Rs. 500000.00
</Text>
<Text size="xs" c="green">
Available Transfer Amount on this Day is Rs. 500000.00
</Text>
</Stack>
</div>
{/* ) : (
<div>

View File

@@ -7,6 +7,7 @@ import { useRouter } from "next/navigation";
import { generateOTP } from '@/app/OTPGenerator';
import SendToBeneficiaryOthers from "./sendBeneficiaryOthers";
interface accountData {
stAccountNo: string;
stAccountType: string;
@@ -257,6 +258,8 @@ export default function SendToBeneficiaryOwn() {
setIsSubmitting(false);
setShowTxnPassword(false);
setShowOtpField(false);
setOtp('');
setTxnPassword('');
}
};
@@ -311,7 +314,7 @@ export default function SendToBeneficiaryOwn() {
</Radio.Group>
{bankType === "own" ? (
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
<div style={{ maxHeight: "290px", overflowY: "auto" }}>
<Stack gap="xs">
<Group grow>
<Select
@@ -340,9 +343,7 @@ export default function SendToBeneficiaryOwn() {
readOnly
withAsterisk
/>
</Group>
<Group justify="space-between" >
<Text size="xs" c="green" style={{ visibility: selectedAccount ? "visible" : "hidden" }}>Available Balance :
{selectedAccount ? selectedAccount.stAvailableBalance : 0}
@@ -425,6 +426,20 @@ export default function SendToBeneficiaryOwn() {
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
</Button>
</Group>
<Stack gap={1} mt="xs">
<Text size="xs" c="green">
Minimum Transfer Amount on this Day is Rs. 1.00
</Text>
<Text size="xs" c="green">
Maximum Transfer Limit per Day is Rs. 500000.00
</Text>
<Text size="xs" c="green">
Available Transfer Amount on this Day is Rs. 500000.00
</Text>
<Text size="xs" c="red" fw={700}>
NOTE : Funds Transfer can be done only to previous added Beneficiary Accounts.
</Text>
</Stack>
</Stack>
</div>
) : (

View File

@@ -1,10 +1,11 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import { Button, Group, Modal, Paper, Radio, ScrollArea, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { Button, Divider, Group, List, Modal, Paper, Radio, ScrollArea, Select, Stack, Text, TextInput, ThemeIcon, Title } from "@mantine/core";
import { notifications } from "@mantine/notifications";
import { useRouter } from "next/navigation";
import { generateOTP } from '@/app/OTPGenerator';
import { IconAlertTriangle } from "@tabler/icons-react";
interface accountData {
stAccountNo: string;
@@ -17,6 +18,7 @@ export default function SendToBeneficiaryOthers() {
const [authorized, setAuthorized] = useState<boolean | null>(null);
const [accountData, setAccountData] = useState<accountData[]>([]);
const [beneficiaryData, setBeneficiaryData] = useState<any[]>([]);
const [showIntroModal, setShowIntroModal] = useState(true);
const [selectedAccNo, setSelectedAccNo] = useState<string | null>(null);
const [beneficiaryAcc, setBeneficiaryAcc] = useState<string | null>(null);
const [beneficiaryName, setBeneficiaryName] = useState<string | null>(null);
@@ -287,6 +289,8 @@ export default function SendToBeneficiaryOthers() {
setIsSubmitting(false);
setShowTxnPassword(false);
setShowOtpField(false);
setOtp('');
setTxnPassword('');
}
};
@@ -294,6 +298,58 @@ export default function SendToBeneficiaryOthers() {
return (
<>
<Modal
opened={showIntroModal}
onClose={() => setShowIntroModal(false)}
centered
withCloseButton={false} // force them to press OK
>
<Stack gap={1}>
<Title order={4} style={{ textAlign: "center" }}>Important Note</Title>
<Text size="sm"> <strong>IMPS</strong> is available 24X7. Limit: up to 5,00,000. Money is transfer instantly.</Text>
<Text size="sm"> <strong>NEFT</strong> is available 24x7. Can be used for any amount but not instant.</Text>
<Text size="sm"> <strong>RTGS</strong> is for 2,00,000 and above. Available during banking hours.As per directions of RBI, RTGS transactions are subjected to the following{" "}
<strong>Time Varying Tariff</strong> in addition to the existing <strong>RTGS</strong>
Commission. The tariff will be calculated based on the time of completion
of transaction.</Text>
<List
spacing="xs"
size="sm"
icon={
<ThemeIcon color="red" size={20} radius="xl">
<IconAlertTriangle size={14} />
</ThemeIcon>
}
>
<List.Item>
From <strong>09:00 hrs</strong> to <strong>12:00 hrs</strong> {" "}
<strong>0.00</strong>
</List.Item>
<List.Item>
After <strong>12:00 hrs</strong> up to <strong>15:30 hrs</strong> {" "}
<strong>1.00</strong>
</List.Item>
<List.Item>
After <strong>15:30 hrs</strong> <strong>5.00</strong>
</List.Item>
</List>
<Divider my="sm" variant="dashed" />
<Text size="xs" c="blue">
Minimum Transfer Amount on this Day is Rs. 1.00
</Text>
<Text size="xs" c="blue">
Maximum Transfer Limit per Day is Rs. 500000.00
</Text>
<Text size="xs" c="blue">
Available Transfer Amount on this Day is Rs. 500000.00
</Text>
<Group justify="flex-end" mt="md">
<Button color="blue" onClick={() => setShowIntroModal(false)}>
Okay
</Button>
</Group>
</Stack>
</Modal>
<Modal
opened={showConfirmModel}
onClose={() => setConfirmModel(false)}
@@ -330,7 +386,8 @@ export default function SendToBeneficiaryOthers() {
</Group>
</Modal>
{/* main content */}
<div style={{ maxHeight: "320px", overflowY: "auto" }}>
{!showIntroModal && (
<div style={{ maxHeight: "290px", overflowY: "auto" }}>
<Stack gap={5} justify="flex-start">
<Group grow gap='xs' >
<Select
@@ -455,8 +512,52 @@ export default function SendToBeneficiaryOthers() {
{!showTxnPassword && showOtpField ? "Validate the OTP" : showTxnPassword ? "Proceed to Pay" : "Proceed"}
</Button>
</Group>
<Stack gap={1} mt="xs">
{paymentMode === "RTGS" &&
<>
<Text size="xs" >
As per directions of RBI, RTGS transactions are subjected to the following{" "}
<strong>Time Varying Tariff</strong> in addition to the existing RTGS
Commission. The tariff will be calculated based on the time of completion
of transaction.
</Text>
<List
spacing="xs"
size="sm"
// icon={
// <ThemeIcon color="red" size={20} radius="xl">
// <IconAlertTriangle size={14} />
// </ThemeIcon>
// }
>
<List.Item>
From <strong>09:00 hrs</strong> to <strong>12:00 hrs</strong> {" "}
<strong>0.00</strong>
</List.Item>
<List.Item>
After <strong>12:00 hrs</strong> up to <strong>15:30 hrs</strong> {" "}
<strong>1.00</strong>
</List.Item>
<List.Item>
After <strong>15:30 hrs</strong> <strong>5.00</strong>
</List.Item>
</List>
</>
}
<Text size="xs" c="dimmed">
Minimum Transfer Limit per Day is Rs. 1.00
</Text>
<Text size="xs" c="dimmed">
Maximum Transfer Limit per Day is Rs. 500000.00
</Text>
<Text size="xs" c="dimmed">
Available Transfer Amount on this Day is Rs. 500000.00
</Text>
</Stack>
</Stack>
</div >
)}
</>
);
}

View File

@@ -13,6 +13,7 @@ import pnb from '@/app/image/bank_logo/pnb.jpg'
import axis from '@/app/image/bank_logo/axis.jpg'
import kccb from '@/app/image/bank_logo/kccb.jpg'
import logo from '@/app/image/bank_logo/bank.jpg';
import { IconTrash } from "@tabler/icons-react";
interface Beneficiary {
accountNo: string;
@@ -23,15 +24,31 @@ interface Beneficiary {
branchName: string;
}
const bankLogo: Record<string, StaticImageData> = {
"BANK OF INDIA": BOI,
"HDFC BANK LTD": hdfc,
"STATE BANK OF INDIA": sbi,
"ICICI BANK LTD": icici,
"PUNJAB NATIONAL BANK": pnb,
"AXIS BANK": axis,
"THE KANGRA CENTRAL CO-OP BANK LIMITED": kccb
export const getBankLogo = (bankName: string): StaticImageData | undefined => {
const name = bankName.toUpperCase();
if (name.includes("STATE BANK")) {
return sbi;
}
if (name.includes("PUNJAB NATIONAL")) {
return pnb;
}
if (name.includes("HDFC")) {
return hdfc;
}
if (name.includes("ICICI")) {
return icici;
}
if (name.includes("AXIS")) {
return axis;
}
if (name.includes("BANK OF INDIA")) {
return BOI;
}
if (name.includes("KANGRA")) {
return kccb;
}
return undefined; // fallback
};
export default function ViewBeneficiary() {
const router = useRouter();
@@ -95,11 +112,11 @@ export default function ViewBeneficiary() {
<Table.Thead>
<Table.Tr style={{ backgroundColor: "#3385ff" }}>
<Table.Th>Bank</Table.Th>
<Table.Th>Account No</Table.Th>
<Table.Th style={{ textAlign: "right" }}>Account No</Table.Th>
<Table.Th>Name</Table.Th>
<Table.Th>Type</Table.Th>
<Table.Th>IFSC</Table.Th>
{/* <Table.Th>Branch</Table.Th> */}
<Table.Th style={{ textAlign: "center" }}>IFSC</Table.Th>
<Table.Th style={{ textAlign: "center" }}>Action Icon</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
@@ -108,7 +125,7 @@ export default function ViewBeneficiary() {
<Table.Td>
<Group gap='sm'>
<Image
src={bankLogo[b.bankName] || logo}
src={getBankLogo(b.bankName) ??logo}
alt={b.bankName}
width={20}
height={15}
@@ -120,7 +137,7 @@ export default function ViewBeneficiary() {
<Table.Td>{b.name}</Table.Td>
<Table.Td>{b.accountType}</Table.Td>
<Table.Td style={{ textAlign: "center" }}>{b.ifscCode}</Table.Td>
{/* <Table.Td>{b.branchName}</Table.Td> */}
<Table.Td style={{ textAlign: "center" }}><IconTrash color="red"/></Table.Td>
</Table.Tr>
))}
</Table.Tbody>

View File

@@ -154,64 +154,85 @@ export default function UserConfiguration() {
</Box>
<Divider label='Rights' size="xs" />
<Stack>
<Group grow>
<Box>
<Text fw={500}>Internet Banking</Text>
<Group mt="xs">
<Stack gap="sm">
{/* Header row */}
<Group gap="xl">
<Box w={150}>
<Text fw={500}>Services</Text>
</Box>
<Box w={100}>
<Text fw={500}>Enable</Text>
</Box>
<Box w={120}>
<Text fw={500}>Transaction</Text>
</Box>
<Box w={100}>
<Text fw={500}>Read</Text>
</Box>
</Group>
{/* Internet Banking row */}
<Group gap="xl" align="center">
<Box w={150}>
<Text>Internet Banking</Text>
</Box>
<Box w={100}>
<Checkbox
label="Enabled"
checked={ibEnabled}
onChange={(e) => {
setIbEnabled(e.currentTarget.checked);
if (!e.currentTarget.checked) setIbAccess(""); // reset if disabled
if (!e.currentTarget.checked) setIbAccess("");
}}
/>
</Box>
<Box w={120}>
<Checkbox
label="Read"
disabled={!ibEnabled}
checked={ibAccess === "read"}
onChange={() => setIbAccess("read")}
/>
<Checkbox
label="Transaction"
disabled={!ibEnabled}
checked={ibAccess === "transaction"}
onChange={() => setIbAccess("transaction")}
/>
</Group>
</Box>
{/* Mobile Banking */}
<Box>
<Text fw={500}>Mobile Banking</Text>
<Group mt="xs">
<Box w={100}>
<Checkbox
disabled={!ibEnabled}
checked={ibAccess === "read"}
onChange={() => setIbAccess("read")}
/>
</Box>
</Group>
{/* Mobile Banking row */}
<Group gap="xl" align="center">
<Box w={150}>
<Text>Mobile Banking</Text>
</Box>
<Box w={100}>
<Checkbox
label="Enabled"
checked={mbEnabled}
onChange={(e) => {
setMbEnabled(e.currentTarget.checked);
if (!e.currentTarget.checked) setMbAccess(""); // reset if disabled
if (!e.currentTarget.checked) setMbAccess("");
}}
/>
</Box>
<Box w={120}>
<Checkbox
label="Read"
disabled={!mbEnabled}
checked={mbAccess === "read"}
onChange={() => setMbAccess("read")}
/>
<Checkbox
label="Transaction"
disabled={!mbEnabled}
checked={mbAccess === "transaction"}
onChange={() => setMbAccess("transaction")}
/>
</Group>
</Box>
<Box w={100}>
<Checkbox
disabled={!mbEnabled}
checked={mbAccess === "read"}
onChange={() => setMbAccess("read")}
/>
</Box>
</Group>
</Stack>
{accountError && (
<Text color="red" size="sm" mt="xs">{accountError}</Text>
<Text c="red" size="sm" mt="xs">{accountError}</Text>
)}
</>
@@ -229,8 +250,6 @@ export default function UserConfiguration() {
>
<Stack>
<TextInput label="CIF" value={CIF} readOnly disabled />
{/* <TextInput label="Internet Banking" value={internetBanking} readOnly disabled />
<TextInput label="Mobile Banking" value={mobileBanking} readOnly disabled /> */}
</Stack>
<Group p="right" mt="md">
<Button variant="default" onClick={() => setShowPreviewModal(false)}>Cancel</Button>

View File

@@ -5,8 +5,8 @@ import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from '@/app/image/logo.jpg';
import { IconLogout, IconUsers, IconUserScreen } from "@tabler/icons-react";
import logo from '@/app/image/logo1.jpg';
import { IconLogout, IconPhoneFilled, IconUsers, IconUserScreen } from "@tabler/icons-react";
import UserConfiguration from "./UserConfiguration";
export default function Login() {
@@ -82,33 +82,48 @@ export default function Login() {
if (authorized) {
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%", paddingTop: "5%" }}>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%",}}>
{/* Header */}
<Box style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
<Box
style={{
height: "60px",
position: 'relative',
width: '100%',
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)",
// border: "1px solid black"
}}>
background: "linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
}}
>
<Image
fit="cover"
src={logo}
component={NextImage}
alt="ebanking"
style={{ width: "40%", height: "100%", objectFit: "contain", marginLeft: 0 }}
style={{ width: "100%", height: "100%" }}
/>
<Title
order={2}
style={{
fontFamily: 'Roboto',
position: 'absolute',
top: '30%',
left: '6%',
color: 'White',
transition: "opacity 0.5s ease-in-out",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
style={{
position: 'absolute',
top: '50%',
left: '64%',
left: '80%',
color: 'white',
textShadow: '1px 1px 2px blue',
textShadow: '1px 1px 2px black',
}}
>
{/* <IconBuildingBank/> */}
Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215
<IconPhoneFilled size={20} /> Toll Free No : 1800-180-8008
</Text>
</Box>
{/* layout and */}

View File

@@ -5,7 +5,7 @@ import { notifications } from "@mantine/notifications";
import { Providers } from "@/app/providers";
import { useRouter } from "next/navigation";
import NextImage from "next/image";
import logo from '@/app/image/logo.jpg';
import logo from '@/app/image/logo1.jpg';
import frontPage from '@/app/image/admin_login.jpg';
import { generateCaptcha } from '@/app/captcha';
@@ -93,42 +93,53 @@ export default function Login() {
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%", paddingTop: "5%" }}>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%" }}>
{/* Header */}
<Box style={{
position: 'fixed', width: '100%', height: '12%', top: 0, left: 0, zIndex: 100,
display: "flex",
justifyContent: "flex-start",
background: "linear-gradient(15deg,rgba(2, 163, 85, 1) 55%, rgba(101, 101, 184, 1) 100%)",
// border: "1px solid black"
}}>
<Image
fit="cover"
src={logo}
component={NextImage}
alt="ebanking"
style={{ width: "40%", height: "100%", objectFit: "contain", marginLeft: 0 }}
/>
<Text
<Box
component="header"
style={{
position: 'absolute',
top: '50%',
left: '64%',
color: 'white',
textShadow: '1px 1px 2px blue',
width: "100%",
padding: "0.8rem 2rem",
background: "linear-gradient(15deg, rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
color: "white",
boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
position: "sticky",
top: 0,
zIndex: 100,
}}
>
{/* <IconBuildingBank/> */}
Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215
</Text>
</Box>
<Group gap="md">
<Image
src={logo}
component={NextImage}
fit="contain"
alt="ebanking"
style={{ width: "60px", height: "auto" }}
/>
<div>
<Title order={3} style={{ fontFamily: "Roboto", color: "white", marginBottom: 2 }}>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text size="xs" c="white" style={{ opacity: 0.85 }}>
Head Office: Dharmshala, Kangra (H.P), Pin: 176215
</Text>
</div>
</Group>
</Box>
{/* Main */}
<div style={{
display: "flex", height: "84vh", overflow: "hidden", position: "relative",
<Box style={{
flex: 1,
position: "relative",
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
overflow: "hidden",
background: 'linear-gradient(to right, #48ac64ff, #199444ff)'
}}>
<div style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Box style={{ flex: 1, backgroundColor: "#c1e0f0", position: "relative" }}>
<Image
fit="cover"
src={frontPage}
@@ -136,7 +147,7 @@ export default function Login() {
alt="ebanking"
style={{ width: "100%", height: "100%" }}
/>
</div>
</Box>
<Box w={{ base: "100%", md: "50%" }} p="lg">
<Card shadow="md" padding="xl" radius="md" style={{ maxWidth: 500, margin: "0 auto", height: '70vh', backdropFilter: 'blur(8px)' }}>
{/* @ts-ignore */}
@@ -158,14 +169,6 @@ export default function Login() {
withAsterisk
mt="sm"
/>
{/* <Box style={{ textAlign: "right"}}>
<Anchor
style={{ fontSize: "14px", color: "#1c7ed6", cursor: "pointer" }}
// onClick={() => router.push("/ValidateUser")}
>
Forgot Password?
</Anchor>
</Box> */}
<Group mt="sm" align="center">
<Box style={{ backgroundColor: "#fff", fontSize: "18px", textDecoration: "line-through", padding: "4px 8px", fontFamily: "cursive" }}>{captcha}</Box>
<Button size="xs" variant="light" onClick={regenerateCaptcha}>Refresh</Button>
@@ -185,8 +188,7 @@ export default function Login() {
</form>
</Card>
</Box>
</div>
</Box>
{/* Footer */}
<Box
component="footer"
@@ -200,7 +202,7 @@ export default function Login() {
© 2025 KCC Bank. All rights reserved.
</Text>
</Box>
</div>
</div>
</Providers>
);