From 102364675136d6d11adf907ddb7dfbbf96e01ffc Mon Sep 17 00:00:00 2001 From: "tomosa.sarkar" Date: Sat, 12 Jul 2025 17:59:30 +0530 Subject: [PATCH] Fix: layout of the application Feat: Create page for account Summary --- src/app/(main)/accounts/layout.tsx | 56 ++++ src/app/(main)/accounts/page.tsx | 105 +++++++ .../funds_transfer}/layout.tsx | 0 .../funds_transfer}/page.tsx | 0 src/app/(main)/home/page.tsx | 273 ++++++++++++++++++ src/app/(main)/home/statementModel.tsx | 51 ++++ src/app/(main)/layout.tsx | 174 +++++++++++ src/app/LayoutWithSidebar.tsx | 56 ---- src/app/home/layout.tsx | 89 ------ src/app/home/page.tsx | 192 ------------ src/app/layout/page.tsx | 71 ----- src/app/page.tsx | 1 - 12 files changed, 659 insertions(+), 409 deletions(-) create mode 100644 src/app/(main)/accounts/layout.tsx create mode 100644 src/app/(main)/accounts/page.tsx rename src/app/{home/FundsTransfer => (main)/funds_transfer}/layout.tsx (100%) rename src/app/{home/FundsTransfer => (main)/funds_transfer}/page.tsx (100%) create mode 100644 src/app/(main)/home/page.tsx create mode 100644 src/app/(main)/home/statementModel.tsx create mode 100644 src/app/(main)/layout.tsx delete mode 100644 src/app/LayoutWithSidebar.tsx delete mode 100644 src/app/home/layout.tsx delete mode 100644 src/app/home/page.tsx delete mode 100644 src/app/layout/page.tsx diff --git a/src/app/(main)/accounts/layout.tsx b/src/app/(main)/accounts/layout.tsx new file mode 100644 index 0000000..01eaef8 --- /dev/null +++ b/src/app/(main)/accounts/layout.tsx @@ -0,0 +1,56 @@ +"use client"; +import { Divider, Stack, Text } from '@mantine/core'; +import { usePathname } from 'next/navigation'; +import Link from 'next/link'; +import React from 'react'; + +export default function Layout({ children }: { children: React.ReactNode }) { + const pathname = usePathname(); // get current route + + const links = [ + { label: "Account Summary", href: "/accounts" }, + { label: "Statement of Account", href: "/accounts/account_statement" }, + ]; + + return ( +
+
+ + + Accounts + + + + + {links.map(link => { + const isActive = pathname === link.href || pathname.startsWith(link.href + '/'); + return ( + + {link.label} + + ); + })} + +
+ +
+ {children} +
+
+ ); +} diff --git a/src/app/(main)/accounts/page.tsx b/src/app/(main)/accounts/page.tsx new file mode 100644 index 0000000..d04687f --- /dev/null +++ b/src/app/(main)/accounts/page.tsx @@ -0,0 +1,105 @@ +"use client"; + +import { Paper, ScrollArea, Table, Text, Title } from "@mantine/core"; +import { notifications } from "@mantine/notifications"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +interface accountData { + stAccountNo: string; + stAccountType: string; + stAvailableBalance: string; + custname: string; +} + +export default function SavingsAccount() { + const router = useRouter(); + const [authorized, setAuthorized] = useState(null); + const [accountData, setAccountData] = useState([]); + + async function FetchAccountDetails() { + try { + const token = localStorage.getItem("access_token"); + const response = await fetch("/api/customer", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + const data = await response.json(); + if (response.ok && Array.isArray(data)) { + setAccountData(data); + } + } catch { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later", + message: "Unable to Fetch, Please try again later", + autoClose: 5000, + }); + } + } + + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + setAuthorized(false); + router.push("/login"); + } else { + setAuthorized(true); + } + }, []); + + useEffect(() => { + if (authorized) { + FetchAccountDetails(); + } + }, [authorized]); + + const cellStyle = { + border: "1px solid #ccc", + padding: "10px", + }; + + const rows = accountData.map((acc, index) => ( + + {acc.custname} + {acc.stAccountType} + {acc.stAccountNo} + + {parseFloat(acc.stAvailableBalance).toLocaleString("en-IN", { + minimumFractionDigits: 2, + })} + + + )); + + if (authorized) { + return ( + + + Account Summary (Currency - INR) + + + + + + + + + + + + {rows} +
Customer NameAccount TypeAccount No.Book Balance
+
+ + * Book Balance includes uncleared effects. + +
+ ); + } + return null; +} diff --git a/src/app/home/FundsTransfer/layout.tsx b/src/app/(main)/funds_transfer/layout.tsx similarity index 100% rename from src/app/home/FundsTransfer/layout.tsx rename to src/app/(main)/funds_transfer/layout.tsx diff --git a/src/app/home/FundsTransfer/page.tsx b/src/app/(main)/funds_transfer/page.tsx similarity index 100% rename from src/app/home/FundsTransfer/page.tsx rename to src/app/(main)/funds_transfer/page.tsx diff --git a/src/app/(main)/home/page.tsx b/src/app/(main)/home/page.tsx new file mode 100644 index 0000000..c4db9ba --- /dev/null +++ b/src/app/(main)/home/page.tsx @@ -0,0 +1,273 @@ +"use client"; + +import React from 'react'; +import { Button, Input, Group, Stack, Text, Title, Box, Select, Paper, Switch } from '@mantine/core'; +import { IconBuildingBank, IconEye } from '@tabler/icons-react'; +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; + stAccountType: string; + stAvailableBalance: string; + custname: string; + activeAccounts: string; +} + +interface statementData { + name: string; + date: string; + amount: string; + type: string; +} + +export default function Home() { + const [authorized, SetAuthorized] = useState(null); + const router = useRouter(); + const [accountData, SetAccountData] = useState([]); + const depositAccounts = accountData.filter(acc => acc.stAccountType !== "LN"); + const [selectedDA, setSelectedDA] = useState(depositAccounts[0]?.stAccountNo || ""); + const selectedDAData = depositAccounts.find(acc => acc.stAccountNo === selectedDA); + const loanAccounts = accountData.filter(acc => acc.stAccountType === "LN"); + const [selectedLN, setSelectedLN] = useState(loanAccounts[0]?.stAccountNo || ""); + const selectedLNData = loanAccounts.find(acc => acc.stAccountNo === selectedLN); + const [showBalance, setShowBalance] = useState(false); + const [openStatement, setOpenStatement] = useState(false); + const [statementData, setStatementData] = useState(null); + const [loading, setLoading] = useState(false); + + + async function handleFetchUserDetails() { + // e.preventDefault(); + try { + const token = localStorage.getItem("access_token"); + const response = await fetch('api/customer', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + }); + const data = await response.json(); + if (response.ok && Array.isArray(data)) { + SetAccountData(data); + if (data.length > 0) { + const firstDeposit = data.find(acc => acc.stAccountType !== "LN"); + const firstLoan = data.find(acc => acc.stAccountType === "LN"); + if (firstDeposit) setSelectedDA(firstDeposit.stAccountNo); + if (firstLoan) setSelectedLN(firstLoan.stAccountNo); + } + } + else { throw new Error(); } + } + catch { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later", + message: "Unable to Fetch, Please try again later", + autoClose: 5000, + }); + } + } + + async function handleGetAccountStatement(accountNo: string) { + // 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); + } + } + + + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + SetAuthorized(false); + router.push("/login"); + } + else { + SetAuthorized(true); + } + }, []); + + useEffect(() => { + if (authorized) { + handleFetchUserDetails(); + } + }, [authorized]); + + if (authorized) { + return ( + +
+ Accounts Overview + + + Show Balance + setShowBalance(event.currentTarget.checked)} /> + +
+ + + + + Deposit Account + ({ + 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 + } + }} + /> + + {Number(selectedLNData?.stAccountNo || 0)} + + {showBalance ? `₹${Number(selectedLNData?.stAvailableBalance || 0).toLocaleString('en-IN')}` : "****"} + + + setOpenStatement(false)} + loading={loading} + data={statementData} error={''} /> + + + Important Links + {/* Loan EMI Calculator */} + + + + + + + {/* + + + + + */} + + +
+
+ + Send Money + + + + + + +
+
+
+ ); + } +} \ No newline at end of file diff --git a/src/app/(main)/home/statementModel.tsx b/src/app/(main)/home/statementModel.tsx new file mode 100644 index 0000000..a22844e --- /dev/null +++ b/src/app/(main)/home/statementModel.tsx @@ -0,0 +1,51 @@ +'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 = ({ + opened, + onClose, + loading, + error, + data, +}) => { + return ( + + {loading && } + {error && {error}} + + {!loading && !error && data && data.length > 0 && ( +
+ {data.map((item, index) => ( +
+ Date: {item.date} + Type: {item.type} + Amount: ₹{item.amount} +
+ ))} +
+ )} + + {!loading && !error && data && data.length === 0 && ( + No transactions found. + )} +
+ ); +}; + +export default StatementModal; + \ No newline at end of file diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx new file mode 100644 index 0000000..a25f268 --- /dev/null +++ b/src/app/(main)/layout.tsx @@ -0,0 +1,174 @@ +"use client"; +import React, { useEffect, useState } from 'react'; +import { Box, Button, Divider, Group, Image, Stack, Text, Title } from '@mantine/core'; +import { IconBook, IconCurrencyRupee, IconHome, IconLogout, IconPhoneFilled, IconSettings } from '@tabler/icons-react'; +import Link from 'next/link'; +import { useRouter, usePathname } from "next/navigation"; +import { Providers } from '../providers'; +import logo from '@/app/image/logo.jpg'; +import NextImage from 'next/image'; +import { notifications } from '@mantine/notifications'; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + const router = useRouter(); + const pathname = usePathname(); + const [userLastLoginDetails, setUserLastLoginDetails] = useState(null); + + async function handleLogout(e: React.FormEvent) { + e.preventDefault(); + localStorage.removeItem("access_token"); + router.push("/login"); + } + + async function handleFetchUserDetails(e: React.FormEvent) { + e.preventDefault(); + const token = localStorage.getItem("access_token"); + const response = await fetch('api/auth/user_details', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + }); + const data = await response.json(); + if (response.ok) { + return data; + } else { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later", + message: "Unable to fetch timestamp, please try again later", + autoClose: 5000, + }); + } + } + + useEffect(() => { + const fetchLoginTime = async () => { + const result = await handleFetchUserDetails({ preventDefault: () => {} } as React.FormEvent); + if (result) { + setUserLastLoginDetails(result.last_login); + } + }; + fetchLoginTime(); + }, []); + + const navItems = [ + { href: "/home", label: "Home", icon: IconHome }, + { href: "/accounts", label: "Accounts", icon: IconBook }, + { href: "/funds_transfer", label: "Send Money", icon: IconCurrencyRupee }, + { href: "/settings", label: "Settings", icon: IconSettings }, + ]; + + return ( + + + +
+ + ebanking + + Toll Free No : 1800-180-8008 + + + +
+ + + Welcome, Rajat Kumar Maharana + + + Last logged in at {userLastLoginDetails ? new Date(userLastLoginDetails).toLocaleString() : "N/A"} + + + + + {navItems.map((item) => { + const isActive = pathname === item.href; + const Icon = item.icon; + return ( + + + + ); + })} + + +
+ + + +
+ {children} +
+ + + + + + © 2025 Kangra Central Co-Operative Bank + + +
+
+ + + ); +} + \ No newline at end of file diff --git a/src/app/LayoutWithSidebar.tsx b/src/app/LayoutWithSidebar.tsx deleted file mode 100644 index 24bf7e6..0000000 --- a/src/app/LayoutWithSidebar.tsx +++ /dev/null @@ -1,56 +0,0 @@ -'use client'; - -import React from 'react'; -import { - AppShell, - Navbar, - Title, - Stack, - Text, - Box, - Button, -} from '@mantine/core'; - -interface LayoutProps { - children: React.ReactNode; -} - -const Sidebar = () => ( - - - - Funds Transfer - - - - - - - - -); - -const LayoutWithSidebar: React.FC = ({ children }) => { - return ( - } - styles={{ - main: { - backgroundColor: '#ffffff', - minHeight: '100vh', - }, - }} - > - {children} - - ); -}; - -export default LayoutWithSidebar; diff --git a/src/app/home/layout.tsx b/src/app/home/layout.tsx deleted file mode 100644 index 73ffcc3..0000000 --- a/src/app/home/layout.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client"; -import React from 'react'; -import { Box, Button, Divider, Flex, Group, Image, Text } from '@mantine/core'; -import { IconBook, IconCurrencyRupee, IconHome, IconLogout, IconPhoneFilled, IconSettings } from '@tabler/icons-react'; -import Link from 'next/link'; -import { useRouter } from "next/navigation"; -import { Providers } from '../providers'; -import logo from '@/app/image/logo.jpg'; -import NextImage from 'next/image'; - -export default function RootLayout({ children }: { children: React.ReactNode }) { - const router = useRouter(); - - async function handleLogout(e: React.FormEvent) { - e.preventDefault(); - localStorage.removeItem("access_token"); - router.push("/login") - } - return ( - - - -
- {/* Image -Logo */} - - ebanking - - - Toll Free No : 1800-180-8008 - - -
- - - - - - - - - - - - - - - - - -
- -
{children}
- - {/* Footer */} - - © 2025 Kangra Central Co- Operative Bank - -
-
- - - ); -} diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx deleted file mode 100644 index a1548a0..0000000 --- a/src/app/home/page.tsx +++ /dev/null @@ -1,192 +0,0 @@ -"use client"; - -import React from 'react'; -import { Button, Input, Group, Stack, Text, Title, Box, Select, Paper,Switch} from '@mantine/core'; -import { IconBuildingBank, IconEye} from '@tabler/icons-react'; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; -import { Providers } from "../providers"; - - -export default function Home() { - const [authorized, SetAuthorized] = useState(null); - const router = useRouter(); - const accountData = [ - { "stAccountNo": "50078975412", "stAccountType": "SA", "stAvailableBalance": "10000.0" }, - { "stAccountNo": "50078975413", "stAccountType": "SA", "stAvailableBalance": "12000.0" }, - { "stAccountNo": "50078975414", "stAccountType": "SA", "stAvailableBalance": "14000.0" }, - { "stAccountNo": "60078975412", "stAccountType": "LN", "stAvailableBalance": "100000.0" }, - { "stAccountNo": "60078975413", "stAccountType": "LN", "stAvailableBalance": "120000.0" } - ] - const depositAccounts = accountData.filter(acc => acc.stAccountType === "SA"); - const [selectedDA, setSelectedDA] = useState(depositAccounts[0]?.stAccountNo || ""); - const selectedDAData = depositAccounts.find(acc => acc.stAccountNo === selectedDA); - const loanAccounts = accountData.filter(acc => acc.stAccountType === "LN"); - const [selectedLN, setSelectedLN] = useState(loanAccounts[0]?.stAccountNo || ""); - const selectedLNData = loanAccounts.find(acc => acc.stAccountNo === selectedLN); - const [showBalance, setShowBalance] = useState(false); - - async function handleLogout(e: React.FormEvent) { - e.preventDefault(); - localStorage.removeItem("access_token"); - router.push("/login") - } - useEffect(() => { - const token = localStorage.getItem("access_token"); - if (!token) { - SetAuthorized(false); - router.push("/login"); - } - else { - SetAuthorized(true); - } - }, []); - -if (authorized) { - return ( - -
-
- Welcome, Rajat Kumar Maharana - {/*   */} - Last logged in at 29/06/25, 05:35 PM -
- - - Show Balance - setShowBalance(event.currentTarget.checked)} /> - -
- - - - - - Deposit Account - ({ - value: acc.stAccountNo, - label: acc.stAccountNo - }))} - value={selectedLN} - // @ts-ignore - onChange={setSelectedLN} - size="xs" - styles={{ - input: { - backgroundColor: "white", - color: "black", - marginLeft: 25, - width: 125 - } - }} - /> - - {Number(selectedLNData?.stAccountNo || 0)} - - {showBalance ? `₹${Number(selectedLNData?.stAvailableBalance || 0).toLocaleString('en-IN')}` : "****"} - - - - - Important Links - {/* Loan EMI Calculator */} - - - - - - - {/* - - - - - */} - - -
-
- - Send Money - - - - - - -
-
-
- ); -} -} \ No newline at end of file diff --git a/src/app/layout/page.tsx b/src/app/layout/page.tsx deleted file mode 100644 index 22efd05..0000000 --- a/src/app/layout/page.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import { - AppShell, - Box, - Button, - Flex, - Group, - Image, - Stack, - Text, -} from '@mantine/core'; - -export default function DashboardLayout() { - return ( - - {/* Header */} - - - Logo - Fund Transfer Portal - - - - {/* Sidebar + Content */} - - - {/* Sidebar */} - - - - - - - - - {/* Main content */} - - {/* You can import your FundTransferForm component here */} - Welcome to the Transfer Page - - - - - {/* Footer */} - - - - © 2025 Your Company - - - - - ); -} diff --git a/src/app/page.tsx b/src/app/page.tsx index cd81b84..26d4aff 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,6 @@ import { redirect } from "next/navigation"; export default function Root() { - //redirect('/home') redirect('/login') } \ No newline at end of file