feat: api integration for account tab
fix: layout design feat : add screen for account tab
This commit is contained in:
222
src/app/(main)/accounts/account_statement/accountStatement.tsx
Normal file
222
src/app/(main)/accounts/account_statement/accountStatement.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
"use client";
|
||||
import { Paper, Select, Title, Button, Text, Grid, ScrollArea, Table, Divider } from "@mantine/core";
|
||||
import { DateInput } from '@mantine/dates';
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import dayjs from 'dayjs';
|
||||
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
dayjs.extend(isSameOrAfter);
|
||||
dayjs.extend(isSameOrBefore);
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
export default function AccountStatementPage() {
|
||||
const [accountOptions, setAccountOptions] = useState<{ value: string; label: string }[]>([]);
|
||||
const [selectedAccNo, setSelectedAccNo] = useState<string | null>(null);
|
||||
const [startDate, setStartDate] = useState<Date | null>(null);
|
||||
const [endDate, setEndDate] = useState<Date | null>(null);
|
||||
const [transactions, setTransactions] = useState<any[]>([]);
|
||||
const searchParams = useSearchParams();
|
||||
const passedAccNo = searchParams.get("accNo");
|
||||
|
||||
useEffect(() => {
|
||||
const saved = sessionStorage.getItem("accountData");
|
||||
if (saved) {
|
||||
const parsed = JSON.parse(saved);
|
||||
const options = parsed.map((acc: any) => ({
|
||||
label: `${acc.stAccountNo} - ${acc.stAccountType}`,
|
||||
value: acc.stAccountNo,
|
||||
}));
|
||||
setAccountOptions(options);
|
||||
if (passedAccNo) {
|
||||
setSelectedAccNo(passedAccNo);
|
||||
//Automatically fetch last 5 transactions if accNo is passed
|
||||
const token = localStorage.getItem("access_token");
|
||||
fetch(`/api/transactions/account/${passedAccNo}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (Array.isArray(data)) {
|
||||
const last5 = data.slice(-5).reverse();
|
||||
setTransactions(last5);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Fetch Failed",
|
||||
message: "Could not load recent transactions.",
|
||||
autoClose: 5000,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [passedAccNo]);
|
||||
|
||||
|
||||
const handleAccountTransaction = async () => {
|
||||
if (!selectedAccNo || !startDate || !endDate) {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Missing field",
|
||||
message: "Please select Account number,Start date and End date",
|
||||
autoClose: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const start = dayjs(startDate);
|
||||
const end = dayjs(endDate);
|
||||
const today = dayjs().startOf('day');
|
||||
if (end.isAfter(today)) {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Invalid End Date",
|
||||
message: "End date can not be the future date.",
|
||||
autoClose: 4000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (start.isAfter(end)) {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Invalid Start Date",
|
||||
message: "Start date can not be less than end date",
|
||||
autoClose: 4000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (end.diff(start, "day") > 60) {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Invalid Date range",
|
||||
message: "End date must be within 60 days from start date",
|
||||
autoClose: 4000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = localStorage.getItem("access_token");
|
||||
const response = await fetch(`/api/transactions/account/${selectedAccNo}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok && Array.isArray(data)) {
|
||||
const filterData = data.filter((txn: any) => {
|
||||
const txnDate = dayjs(txn.date, 'DD/MM/YYYY');
|
||||
return txnDate.isSameOrAfter(start) && txnDate.isSameOrBefore(end);
|
||||
});
|
||||
setTransactions(filterData);
|
||||
}
|
||||
} catch {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Please try again later",
|
||||
message: "Unable to Fetch Account Transaction, Please try again later",
|
||||
autoClose: 5000,
|
||||
});
|
||||
}
|
||||
};
|
||||
const cellStyle = {
|
||||
border: "1px solid #ccc",
|
||||
padding: "8px",
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid gutter="md">
|
||||
{/* 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>
|
||||
<Select
|
||||
label="Select Account Number"
|
||||
placeholder="Choose account number"
|
||||
data={accountOptions}
|
||||
value={selectedAccNo}
|
||||
onChange={setSelectedAccNo}
|
||||
searchable
|
||||
/>
|
||||
<DateInput
|
||||
label="Start Date"
|
||||
value={startDate}
|
||||
onChange={setStartDate}
|
||||
placeholder="Enter start date"
|
||||
/>
|
||||
<DateInput
|
||||
label="End Date"
|
||||
value={endDate}
|
||||
onChange={setEndDate}
|
||||
placeholder="Enter end date"
|
||||
/>
|
||||
<Button fullWidth mt="md" onClick={handleAccountTransaction}>
|
||||
Proceed
|
||||
</Button>
|
||||
</Paper>
|
||||
</Grid.Col>
|
||||
|
||||
{/* 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>
|
||||
<Text fw={500} fs="italic" >Account No : {selectedAccNo}</Text>
|
||||
<Divider size="xs" />
|
||||
<ScrollArea style={{ flex: 1 }}>
|
||||
{transactions.length === 0 ? (
|
||||
<p>No transactions found.</p>
|
||||
) : (
|
||||
<>
|
||||
<Text fs="italic" c='#228be6' ta='center'>
|
||||
{!startDate && !endDate ? 'Last 5 Transactions'
|
||||
: startDate && endDate ? `Transactions from ${dayjs(startDate).format("DD/MM/YYYY")} to ${dayjs(endDate).format("DD/MM/YYYY")}`
|
||||
: ""}
|
||||
</Text>
|
||||
<Table style={{ borderCollapse: "collapse", width: '100%' }}>
|
||||
<thead style={{ backgroundColor: "#3385ff" }}>
|
||||
{/* <tr>
|
||||
<th style={{ ...cellStyle, position: 'sticky', textAlign: "left" }}>Name</th>
|
||||
<th style={{ ...cellStyle, position: 'sticky', textAlign: "left" }}>Date</th>
|
||||
<th style={{ ...cellStyle, position: 'sticky', textAlign: "left" }}>Type</th>
|
||||
<th style={{ ...cellStyle, position: 'sticky', textAlign: "left" }}>Amount(₹)</th>
|
||||
</tr> */}
|
||||
</thead>
|
||||
<tbody style={{ maxHeight: '250px', overflowY: 'auto', width: '100%' }}>
|
||||
{transactions.map((txn, i) => (
|
||||
<tr key={i}>
|
||||
<td style={{ ...cellStyle, textAlign: "left" }}> {txn.name || "—"}</td>
|
||||
<td style={{ ...cellStyle, textAlign: "left" }}>{txn.date || "—"}</td>
|
||||
{/* <td style={{ ...cellStyle, textAlign: "left" }}>{txn.type}</td> */}
|
||||
<td style={{ ...cellStyle, textAlign: "left", color: txn.type === "DR" ? "#e03131" : "#2f9e44" }}>
|
||||
{parseFloat(txn.amount).toLocaleString("en-IN", {
|
||||
minimumFractionDigits: 2,
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</Paper>
|
||||
</Grid.Col >
|
||||
</Grid >
|
||||
);
|
||||
}
|
||||
|
||||
|
28
src/app/(main)/accounts/account_statement/page.tsx
Normal file
28
src/app/(main)/accounts/account_statement/page.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
import { Suspense, useEffect, useState } from "react";
|
||||
import AccountStatementPage from "./accountStatement";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function AccountStatement() {
|
||||
const [authorized, SetAuthorized] = useState<boolean | null>(null);
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (!token) {
|
||||
SetAuthorized(false);
|
||||
router.push("/login");
|
||||
}
|
||||
else {
|
||||
SetAuthorized(true);
|
||||
}
|
||||
}, []);
|
||||
if (authorized) {
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<AccountStatementPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,55 +2,70 @@
|
||||
import { Divider, Stack, Text } from '@mantine/core';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname(); // get current route
|
||||
const [authorized, SetAuthorized] = useState<boolean | null>(null);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const links = [
|
||||
{ label: "Account Summary", href: "/accounts" },
|
||||
{ label: "Statement of Account", href: "/accounts/account_statement" },
|
||||
];
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (!token) {
|
||||
SetAuthorized(false);
|
||||
router.push("/login");
|
||||
}
|
||||
else {
|
||||
SetAuthorized(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", height: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
width: "15%",
|
||||
backgroundColor: '#c5e4f9',
|
||||
borderRight: "1px solid #ccc",
|
||||
}}
|
||||
>
|
||||
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
|
||||
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
|
||||
Accounts
|
||||
</Text>
|
||||
</Stack>
|
||||
if (authorized) {
|
||||
return (
|
||||
<div style={{ display: "flex", height: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
width: "16%",
|
||||
backgroundColor: '#c5e4f9',
|
||||
borderRight: "1px solid #ccc",
|
||||
}}
|
||||
>
|
||||
<Stack style={{ background: '#228be6', height: '10%', alignItems: 'center' }}>
|
||||
<Text fw={700} fs="italic" c='white' style={{ textAlign: 'center', marginTop: '10px' }}>
|
||||
Accounts
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Stack gap="sm" justify="flex-start" style={{ padding: '1rem' }}>
|
||||
{links.map(link => {
|
||||
const isActive = pathname === link.href || pathname.startsWith(link.href + '/');
|
||||
return (
|
||||
<Text
|
||||
key={link.href}
|
||||
component={Link}
|
||||
href={link.href}
|
||||
c={isActive ? 'darkblue' : 'blue'}
|
||||
style={{
|
||||
textDecoration: isActive ? 'underline' : 'none',
|
||||
fontWeight: isActive ? 600 : 400,
|
||||
}}
|
||||
>
|
||||
{link.label}
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
<Stack gap="sm" justify="flex-start" style={{ padding: '1rem' }}>
|
||||
{links.map(link => {
|
||||
const isActive = pathname === link.href;
|
||||
return (
|
||||
<Text
|
||||
key={link.href}
|
||||
component={Link}
|
||||
href={link.href}
|
||||
c={isActive ? 'darkblue' : 'blue'}
|
||||
style={{
|
||||
textDecoration: isActive ? 'underline' : 'none',
|
||||
fontWeight: isActive ? 600 : 400,
|
||||
}}
|
||||
>
|
||||
{link.label}
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, padding: '1rem' }}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, padding: '1rem' }}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ interface accountData {
|
||||
custname: string;
|
||||
}
|
||||
|
||||
export default function SavingsAccount() {
|
||||
export default function AccountSummary() {
|
||||
const router = useRouter();
|
||||
const [authorized, setAuthorized] = useState<boolean | null>(null);
|
||||
const [accountData, setAccountData] = useState<accountData[]>([]);
|
||||
@@ -30,6 +30,7 @@ export default function SavingsAccount() {
|
||||
const data = await response.json();
|
||||
if (response.ok && Array.isArray(data)) {
|
||||
setAccountData(data);
|
||||
sessionStorage.setItem('accountData',JSON.stringify(data))
|
||||
}
|
||||
} catch {
|
||||
notifications.show({
|
||||
@@ -67,7 +68,9 @@ export default function SavingsAccount() {
|
||||
<tr key={index}>
|
||||
<td style={{ ...cellStyle, textAlign: "left" }}>{acc.custname}</td>
|
||||
<td style={{ ...cellStyle, textAlign: "left" }}>{acc.stAccountType}</td>
|
||||
<td style={{ ...cellStyle, textAlign: "right" }}>{acc.stAccountNo}</td>
|
||||
<td style={{ ...cellStyle, textAlign: "right", color: '#1c7ed6', cursor: "pointer" }}
|
||||
onClick={() => router.push(`/accounts/account_statement?accNo=${acc.stAccountNo}`)}>
|
||||
{acc.stAccountNo}</td>
|
||||
<td style={{ ...cellStyle, textAlign: "right" }}>
|
||||
{parseFloat(acc.stAvailableBalance).toLocaleString("en-IN", {
|
||||
minimumFractionDigits: 2,
|
||||
|
@@ -7,7 +7,6 @@ import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Providers } from "../../providers";
|
||||
import { notifications } from '@mantine/notifications';
|
||||
import StatementModel from './statementModel';
|
||||
|
||||
interface accountData {
|
||||
stAccountNo: string;
|
||||
@@ -17,13 +16,6 @@ interface accountData {
|
||||
activeAccounts: string;
|
||||
}
|
||||
|
||||
interface statementData {
|
||||
name: string;
|
||||
date: string;
|
||||
amount: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [authorized, SetAuthorized] = useState<boolean | null>(null);
|
||||
const router = useRouter();
|
||||
@@ -35,9 +27,6 @@ export default function Home() {
|
||||
const [selectedLN, setSelectedLN] = useState(loanAccounts[0]?.stAccountNo || "");
|
||||
const selectedLNData = loanAccounts.find(acc => acc.stAccountNo === selectedLN);
|
||||
const [showBalance, setShowBalance] = useState(false);
|
||||
const [openStatement, setOpenStatement] = useState(false);
|
||||
const [statementData, setStatementData] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
|
||||
async function handleFetchUserDetails() {
|
||||
@@ -75,40 +64,9 @@ export default function Home() {
|
||||
}
|
||||
|
||||
async function handleGetAccountStatement(accountNo: string) {
|
||||
// e.preventDefault();
|
||||
setOpenStatement(true);
|
||||
setLoading(true);
|
||||
try {
|
||||
const token = localStorage.getItem("access_token");
|
||||
const response = await fetch(`api//transactions/account/${accountNo}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
console.log(data);
|
||||
setStatementData(data);
|
||||
}
|
||||
else { throw new Error(); }
|
||||
}
|
||||
catch {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
title: "Please try again later",
|
||||
message: "Unable to Fetch the statement, Please try again later",
|
||||
autoClose: 5000,
|
||||
});
|
||||
}
|
||||
finally {
|
||||
setLoading(false);
|
||||
}
|
||||
router.push(`/accounts/account_statement?accNo=${accountNo}`);
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (!token) {
|
||||
@@ -140,7 +98,7 @@ export default function Home() {
|
||||
</Group>
|
||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "flex-start", marginLeft: '15px' }}>
|
||||
<Group grow gap="xl">
|
||||
<Paper p="md" radius="md" style={{ backgroundColor: '#c1e0f0', width: 350}}>
|
||||
<Paper p="md" radius="md" style={{ backgroundColor: '#c1e0f0', width: 350 }}>
|
||||
<Group gap='xs'>
|
||||
<IconBuildingBank size={25} />
|
||||
<Text fw={700}>Deposit Account</Text>
|
||||
@@ -168,13 +126,7 @@ export default function Home() {
|
||||
<Title order={2} mt="md">
|
||||
{showBalance ? `₹${Number(selectedDAData?.stAvailableBalance || 0).toLocaleString('en-IN')}` : "****"}
|
||||
</Title>
|
||||
|
||||
<Button fullWidth mt="xs" onClick={() => handleGetAccountStatement(selectedDA)}>Get Statement</Button>
|
||||
<StatementModel
|
||||
opened={openStatement}
|
||||
onClose={() => setOpenStatement(false)}
|
||||
loading={loading}
|
||||
data={statementData} error={''} />
|
||||
</Paper>
|
||||
<Paper p="md" radius="md" style={{ backgroundColor: '#c1e0f0', width: 350 }}>
|
||||
<Group gap='xs'>
|
||||
@@ -205,11 +157,6 @@ export default function Home() {
|
||||
{showBalance ? `₹${Number(selectedLNData?.stAvailableBalance || 0).toLocaleString('en-IN')}` : "****"}
|
||||
</Title>
|
||||
<Button fullWidth mt="xs" onClick={() => handleGetAccountStatement(selectedLN)}>Get Statement</Button>
|
||||
<StatementModel
|
||||
opened={openStatement}
|
||||
onClose={() => setOpenStatement(false)}
|
||||
loading={loading}
|
||||
data={statementData} error={''} />
|
||||
</Paper>
|
||||
<Paper p="md" radius="md" style={{ width: 300, backgroundColor: '#FFFFFF', marginLeft: '130px', border: '1px solid grey' }}>
|
||||
<Title order={5} mb="sm">Important Links</Title>
|
||||
|
@@ -1,51 +0,0 @@
|
||||
'use client';
|
||||
import React from "react";
|
||||
import { Modal, Text, Loader } from "@mantine/core";
|
||||
|
||||
type StatementItem = {
|
||||
date: string;
|
||||
type: string;
|
||||
amount: number;
|
||||
};
|
||||
|
||||
interface StatementModalProps {
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
loading: boolean;
|
||||
error: string;
|
||||
data: StatementItem[] | null;
|
||||
}
|
||||
|
||||
const StatementModal: React.FC<StatementModalProps> = ({
|
||||
opened,
|
||||
onClose,
|
||||
loading,
|
||||
error,
|
||||
data,
|
||||
}) => {
|
||||
return (
|
||||
<Modal opened={opened} onClose={onClose} title="Account Statement" size="lg">
|
||||
{loading && <Loader />}
|
||||
{error && <Text c="red">{error}</Text>}
|
||||
|
||||
{!loading && !error && data && data.length > 0 && (
|
||||
<div>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} style={{ marginBottom: 10 }}>
|
||||
<Text>Date: {item.date}</Text>
|
||||
<Text>Type: {item.type}</Text>
|
||||
<Text>Amount: ₹{item.amount}</Text>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && data && data.length === 0 && (
|
||||
<Text>No transactions found.</Text>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatementModal;
|
||||
|
@@ -12,6 +12,7 @@ import { notifications } from '@mantine/notifications';
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const [authorized, SetAuthorized] = useState<boolean | null>(null);
|
||||
const [userLastLoginDetails, setUserLastLoginDetails] = useState(null);
|
||||
|
||||
async function handleLogout(e: React.FormEvent) {
|
||||
@@ -19,6 +20,16 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
localStorage.removeItem("access_token");
|
||||
router.push("/login");
|
||||
}
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("access_token");
|
||||
if (!token) {
|
||||
SetAuthorized(false);
|
||||
router.push("/login");
|
||||
}
|
||||
else {
|
||||
SetAuthorized(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function handleFetchUserDetails(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
@@ -46,7 +57,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
|
||||
useEffect(() => {
|
||||
const fetchLoginTime = async () => {
|
||||
const result = await handleFetchUserDetails({ preventDefault: () => {} } as React.FormEvent);
|
||||
const result = await handleFetchUserDetails({ preventDefault: () => { } } as React.FormEvent);
|
||||
if (result) {
|
||||
setUserLastLoginDetails(result.last_login);
|
||||
}
|
||||
@@ -61,114 +72,115 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
{ href: "/settings", label: "Settings", icon: IconSettings },
|
||||
];
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Providers>
|
||||
<div style={{ backgroundColor: "#e6ffff", height: "100vh", display: "flex", flexDirection: "column", padding: 0, margin: 0 }}>
|
||||
<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%)",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
fit="cover"
|
||||
src={logo}
|
||||
component={NextImage}
|
||||
alt="ebanking"
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
/>
|
||||
<Text
|
||||
if (authorized) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Providers>
|
||||
<div style={{ backgroundColor: "#e6ffff", height: "100vh", display: "flex", flexDirection: "column", padding: 0, margin: 0 }}>
|
||||
<Box
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '80%',
|
||||
color: 'white',
|
||||
textShadow: '1px 1px 2px black',
|
||||
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%)",
|
||||
}}
|
||||
>
|
||||
<IconPhoneFilled size={20} /> Toll Free No : 1800-180-8008
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
padding: '0.5rem 1rem',
|
||||
display: "flex",
|
||||
justifyContent: 'space-between',
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Stack gap={0} align="flex-start">
|
||||
<Title order={4} style={{ fontFamily: "inter", fontSize: '22px' }}>
|
||||
Welcome, Rajat Kumar Maharana
|
||||
</Title>
|
||||
<Text size="xs" c="gray" style={{ fontFamily: "inter", fontSize: '13px' }}>
|
||||
Last logged in at {userLastLoginDetails ? new Date(userLastLoginDetails).toLocaleString() : "N/A"}
|
||||
<Image
|
||||
fit="cover"
|
||||
src={logo}
|
||||
component={NextImage}
|
||||
alt="ebanking"
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '80%',
|
||||
color: 'white',
|
||||
textShadow: '1px 1px 2px black',
|
||||
}}
|
||||
>
|
||||
<IconPhoneFilled size={20} /> Toll Free No : 1800-180-8008
|
||||
</Text>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
<Group mt="md" gap="sm">
|
||||
{navItems.map((item) => {
|
||||
const isActive = pathname === item.href;
|
||||
const Icon = item.icon;
|
||||
return (
|
||||
<Link key={item.href} href={item.href}>
|
||||
<Button
|
||||
leftSection={<Icon size={20} />}
|
||||
variant={isActive ? "light" : "subtle"}
|
||||
color={isActive ? "blue" : undefined}
|
||||
>
|
||||
{item.label}
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
<Button leftSection={<IconLogout size={20} />} variant="subtle" onClick={handleLogout}>
|
||||
Logout
|
||||
</Button>
|
||||
</Group>
|
||||
<div
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
padding: '0.5rem 1rem',
|
||||
display: "flex",
|
||||
justifyContent: 'space-between',
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Stack gap={0} align="flex-start">
|
||||
<Title order={4} style={{ fontFamily: "inter", fontSize: '22px' }}>
|
||||
Welcome, Rajat Kumar Maharana
|
||||
</Title>
|
||||
<Text size="xs" c="gray" style={{ fontFamily: "inter", fontSize: '13px' }}>
|
||||
Last logged in at {userLastLoginDetails ? new Date(userLastLoginDetails).toLocaleString() : "N/A"}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Group mt="md" gap="sm">
|
||||
{navItems.map((item) => {
|
||||
const isActive = pathname.startsWith(item.href);
|
||||
const Icon = item.icon;
|
||||
return (
|
||||
<Link key={item.href} href={item.href}>
|
||||
<Button
|
||||
leftSection={<Icon size={20} />}
|
||||
variant={isActive ? "light" : "subtle"}
|
||||
color={isActive ? "blue" : undefined}
|
||||
>
|
||||
{item.label}
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
<Button leftSection={<IconLogout size={20} />} variant="subtle" onClick={handleLogout}>
|
||||
Logout
|
||||
</Button>
|
||||
</Group>
|
||||
</div>
|
||||
|
||||
<Divider size="xs" color='#99c2ff' />
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
overflowY: "auto",
|
||||
borderTop: '1px solid #ddd',
|
||||
borderBottom: '1px solid #ddd',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<Divider size="xs" color='blue' />
|
||||
|
||||
<Box
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#f8f9fa",
|
||||
marginTop: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<Text c="dimmed" size="xs">
|
||||
© 2025 Kangra Central Co-Operative Bank
|
||||
</Text>
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
<Divider size="xs" color='#99c2ff' />
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
overflowY: "auto",
|
||||
borderTop: '1px solid #ddd',
|
||||
borderBottom: '1px solid #ddd',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<Divider size="xs" color='blue' />
|
||||
|
||||
<Box
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#f8f9fa",
|
||||
marginTop: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<Text c="dimmed" size="xs">
|
||||
© 2025 Kangra Central Co-Operative Bank
|
||||
</Text>
|
||||
</Box>
|
||||
</div>
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user