feat : screen for user create and update

feat : unlocked users.
This commit is contained in:
2025-11-04 13:05:00 +05:30
parent 96b505a38c
commit 26b9eff409
6 changed files with 982 additions and 404 deletions

View File

@@ -1,183 +1,332 @@
"use client";
import React, { useState, useEffect } from "react";
import { Text, Box, Image, Button, Stack, Divider, Title } from "@mantine/core";
import {
Text,
Box,
Image,
Stack,
Divider,
Title,
Collapse,
Group,
UnstyledButton,
} from "@mantine/core";
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/logo1.jpg';
import { IconEye, IconLogout, IconPhoneFilled, IconUsers, IconUserScreen } from "@tabler/icons-react";
import logo from "@/app/image/logo1.jpg";
import {
IconLogout,
IconPhoneFilled,
IconUsers,
IconChevronDown,
IconChevronUp,
IconSettings,
} from "@tabler/icons-react";
import UserConfiguration from "./UserConfiguration";
import ViewUserConfiguration from "./ViewUserConfiguration";
import UnlockedUsers from "./UnlockedUsers";
export default function Login() {
const router = useRouter();
const [authorized, SetAuthorized] = useState<boolean | null>(null);
const [view, setView] = useState<'userConf' | 'view' | null>(null);
const [lastLoginDetails, setLastLoginDetails] = useState(null);
const [name, setName] = useState(null);
const router = useRouter();
const [authorized, SetAuthorized] = useState<boolean | null>(null);
const [view, setView] = useState<string | null>(null);
const [name, setName] = useState<string | null>(null);
const [lastLoginDetails, setLastLoginDetails] = useState<string | null>(null);
const [userMenuOpen, setUserMenuOpen] = useState(true);
const [configMenuOpen, setConfigMenuOpen] = useState(false);
async function handleLogout(e: React.FormEvent) {
e.preventDefault();
localStorage.removeItem("admin_access_token");
localStorage.clear();
sessionStorage.clear();
router.push("/administrator/login");
async function handleLogout(e: React.FormEvent) {
e.preventDefault();
localStorage.clear();
sessionStorage.clear();
router.push("/administrator/login");
}
async function handleFetchUserDetails(e: React.FormEvent) {
e.preventDefault();
const token = localStorage.getItem("admin_access_token");
const response = await fetch("/api/auth/admin/admin_details", {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Login-Type": "Admin",
Authorization: `Bearer ${token}`,
},
});
const data = await response.json();
if (response.ok) {
return data;
} else if (response.status === 401 || data.message === "invalid or expired token") {
localStorage.removeItem("admin_access_token");
router.push("/administrator/login");
} else {
notifications.show({
withBorder: true,
color: "red",
title: "Please try again later",
message: "Unable to fetch timestamp, please try again later",
autoClose: 5000,
});
}
async function handleFetchUserDetails(e: React.FormEvent) {
e.preventDefault();
const token = localStorage.getItem("admin_access_token");
const response = await fetch('/api/auth/admin/admin_details', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
"X-Login-Type": "Admin",
'Authorization': `Bearer ${token}`
},
});
const data = await response.json();
// console.log(data)
if (response.ok) {
return data;
}
else if (response.status === 401 || data.message === 'invalid or expired token') {
localStorage.removeItem("admin_access_token");
router.push('/administrator/login');
}
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 token = localStorage.getItem("admin_access_token");
if (!token) {
SetAuthorized(false);
router.push("/administrator/login/");
} else {
SetAuthorized(true);
const fetchLoginTime = async () => {
const result = await handleFetchUserDetails({
preventDefault: () => { },
} as React.FormEvent);
if (result) {
setLastLoginDetails(result.last_login);
setName(result.name);
}
};
fetchLoginTime();
}
}, []);
useEffect(() => {
const token = localStorage.getItem("admin_access_token");
if (!token) {
SetAuthorized(false);
router.push("/administrator/login/");
} else {
SetAuthorized(true);
const fetchLoginTime = async () => {
const result = await handleFetchUserDetails({ preventDefault: () => { } } as React.FormEvent);
if (result) {
setLastLoginDetails(result.last_login);
setName(result.name);
}
};
fetchLoginTime();
}
}, []);
if (!authorized) return null;
const handleClick = (type: 'UserConf' | 'ViewUser' | 'logout') => {
if (type === 'UserConf') {
setView('userConf');
} else if (type === 'ViewUser') {
setView('view');
}
};
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%" }}>
{/* Header */}
<Box
style={{
height: "60px",
position: "relative",
width: "100%",
display: "flex",
justifyContent: "flex-start",
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: "100%", height: "100%" }}
/>
<Title
order={2}
style={{
fontFamily: "Roboto",
position: "absolute",
top: "30%",
left: "6%",
color: "White",
}}
>
THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.
</Title>
<Text
style={{
position: "absolute",
top: "50%",
left: "80%",
color: "white",
textShadow: "1px 1px 2px black",
}}
>
<IconPhoneFilled size={18} /> Toll Free No : 1800-180-8008
</Text>
</Box>
if (!authorized) return null;
{/* Layout */}
<Box style={{ display: "flex", height: "90vh" }}>
{/* Sidebar */}
<Box
style={{
width: 240,
background: "#02a355",
padding: "0.75rem",
borderRight: "1px solid #ccc",
color: "white",
fontSize: "13px",
}}
>
<Title order={4} c="white" style={{ textAlign: "center", marginBottom: "6px" }}>
Admin Portal
</Title>
<Divider my="xs" color="rgba(255,255,255,0.3)" />
if (authorized) {
return (
<Providers>
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%", }}>
{/* Header */}
<Box
style={{
height: "60px",
position: 'relative',
width: '100%',
display: "flex",
justifyContent: "flex-start",
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: "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: '80%',
color: 'white',
textShadow: '1px 1px 2px black',
}}
>
<IconPhoneFilled size={20} /> Toll Free No : 1800-180-8008
</Text>
</Box>
{/* layout and */}
<Box style={{ display: 'flex', height: '90vh' }}>
{/* Sidebar manually placed under header */}
<Box
style={{
width: 250,
background: "#ebf5f5ff",
// background: "linear-gradient(90deg,rgba(42, 123, 155, 1) 0%, rgba(87, 199, 133, 1) 30%)",
padding: '1rem',
borderRight: '1px solid #ccc',
}}
>
<Title order={3} style={{ textAlign: 'center' }}>Admin Portal</Title>
<Divider my="xs" label="Menu" labelPosition="center" />
<Stack>
<Text td="underline" variant="light" style={{ cursor: 'pointer' }} onClick={() => handleClick('UserConf')}>
<IconUsers size="15" /> User Configuration
</Text>
<Text td="underline" variant="light" style={{ cursor: 'pointer' }} onClick={() => handleClick('ViewUser')}>
<IconEye size="15" /> View User Configuration
</Text>
<Text td="underline" variant="light" style={{ cursor: 'pointer' }} onClick={handleLogout}>
<IconLogout size="15" /> Logout
</Text>
</Stack>
</Box>
{/* User Maintenance */}
<UnstyledButton
onClick={() => setUserMenuOpen(!userMenuOpen)}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
padding: "5px 6px",
borderRadius: "4px",
backgroundColor: "rgba(255,255,255,0.1)",
color: "white",
fontSize: "13px",
}}
>
<Group gap="xs">
<IconUsers size={15} />
<Text fw={600} size="sm">
User Maintenance
</Text>
</Group>
{userMenuOpen ? <IconChevronUp size={15} /> : <IconChevronDown size={15} />}
</UnstyledButton>
<Collapse in={userMenuOpen}>
<Stack gap={2} pl="md" mt={4}>
<Box
onClick={() => setView("userConf")}
style={{
cursor: "pointer",
color: view === "userConf" ? "#02a355" : "white",
backgroundColor: view === "userConf" ? "white" : "transparent",
borderRadius: "3px",
padding: "3px 6px",
transition: "0.2s",
}}
>
User Create / Update
</Box>
<Box
onClick={() => setView("viewUser")}
style={{
cursor: "pointer",
color: view === "viewUser" ? "#02a355" : "white",
backgroundColor: view === "viewUser" ? "white" : "transparent",
borderRadius: "3px",
padding: "3px 6px",
transition: "0.2s",
}}
>
Users Status
</Box>
<Box
onClick={() => setView("unlockUser")}
style={{
cursor: "pointer",
color: view === "unlockUser" ? "#02a355" : "white",
backgroundColor: view === "unlockUser" ? "white" : "transparent",
borderRadius: "3px",
padding: "3px 6px",
transition: "0.2s",
}}
>
User Unlock
</Box>
</Stack>
</Collapse>
{/* Main Content Area */}
<Stack style={{ flex: 1, padding: '1rem' }}>
<Box>
<Text c="Blue" size="lg" fs='italic'>Welcome ,{name} </Text>
<Text size="xs" c="gray" style={{ fontFamily: "inter", fontSize: '13px' }}>
Last logged in at {lastLoginDetails ? new Date(lastLoginDetails).toLocaleString() : "N/A"}
</Text>
</Box>
<Box>
{view === 'userConf' && <UserConfiguration />}
{view === 'view' && <Text size="xl"><ViewUserConfiguration /></Text>}
{!view &&
<Text size="xl">Welcome To The Admin Portal</Text>
}
</Box>
</Stack>
</Box>
<Divider size="xs" color='#99c2ff' />
<Text size="sm" style={{ textAlign: "center" }}>© 2025 The Kangra Central Co-Operative Bank</Text>
</div>
</Providers>
);
}
{/* Configuration */}
<UnstyledButton
onClick={() => setConfigMenuOpen(!configMenuOpen)}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
padding: "5px 6px",
marginTop: "8px",
borderRadius: "4px",
backgroundColor: "rgba(255,255,255,0.1)",
color: "white",
fontSize: "13px",
}}
>
<Group gap="xs">
<IconSettings size={15} />
<Text fw={600} size="sm">
Configuration
</Text>
</Group>
{configMenuOpen ? <IconChevronUp size={15} /> : <IconChevronDown size={15} />}
</UnstyledButton>
<Collapse in={configMenuOpen}>
<Stack gap={2} pl="md" mt={4}>
<Box
onClick={() => setView("ifscConfig")}
style={{
cursor: "pointer",
color: view === "ifscConfig" ? "#02a355" : "white",
backgroundColor: view === "ifscConfig" ? "white" : "transparent",
borderRadius: "3px",
padding: "3px 6px",
transition: "0.2s",
}}
>
IFSC Configuration
</Box>
</Stack>
</Collapse>
<Divider my="xs" color="rgba(255,255,255,0.3)" />
<Text
onClick={handleLogout}
style={{
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "4px",
color: "white",
marginTop: "8px",
fontSize: "13px",
}}
>
<IconLogout size={14} /> Logout
</Text>
</Box>
{/* Main Content */}
<Stack style={{ flex: 1, padding: "1rem" }}>
<Box>
<Text c="Blue" size="sm" fs="italic">
Welcome, {name}
</Text>
<Text size="xs" c="gray" style={{ fontFamily: "inter" }}>
Last logged in at{" "}
{lastLoginDetails
? new Date(lastLoginDetails).toLocaleString()
: "N/A"}
</Text>
</Box>
<Box>
{view === "userConf" && <UserConfiguration />}
{view === "viewUser" && <ViewUserConfiguration />}
{view === "unlockUser" && <UnlockedUsers />}
{view === "ifscConfig" && (
<Text size="sm" c="gray">
IFSC Configuration Page Coming Soon
</Text>
)}
{!view && (
<>
<Text size="xl" c="gray">
Welcome To The Internet Banking Admin Portal
</Text>
<Text size="sm" c="black">
Choose the service from the menu.
</Text>
</>
)}
</Box>
</Stack>
</Box>
<Divider size="xs" color="#99c2ff" />
<Text size="xs" style={{ textAlign: "center" }}>
© 2025 The Kangra Central Co-Operative Bank
</Text>
</div>
</Providers>
);
}