feat : screen for user create and update
feat : unlocked users.
This commit is contained in:
@@ -14,8 +14,8 @@ interface SendOtpPayload {
|
||||
}
|
||||
|
||||
function getStoredMobileNumber(): string {
|
||||
const mobileNumber = localStorage.getItem('remitter_mobile_no');
|
||||
// const mobileNumber = "7890544527";
|
||||
// const mobileNumber = localStorage.getItem('remitter_mobile_no');
|
||||
const mobileNumber = "7890544527";
|
||||
if (!mobileNumber) throw new Error('Mobile number not found.');
|
||||
return mobileNumber;
|
||||
}
|
||||
|
||||
265
src/app/administrator/home/UnlockedUsers.tsx
Normal file
265
src/app/administrator/home/UnlockedUsers.tsx
Normal file
@@ -0,0 +1,265 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
TextInput,
|
||||
Button,
|
||||
Title,
|
||||
Stack,
|
||||
Group,
|
||||
Text,
|
||||
Paper,
|
||||
LoadingOverlay,
|
||||
Divider,
|
||||
Select,
|
||||
Center,
|
||||
} from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function UserUnlockPage() {
|
||||
const router = useRouter();
|
||||
const [CIF, setCIF] = useState("");
|
||||
const [username, setUsername] = useState("");
|
||||
const [userDetails, setUserDetails] = useState<any>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Redirect if not logged in
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("admin_access_token");
|
||||
if (!token) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
router.push("/administrator/login");
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
const checkAuth = () => {
|
||||
const token = localStorage.getItem("admin_access_token");
|
||||
if (!token) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
router.push("/administrator/login");
|
||||
return null;
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
// Fetch user info
|
||||
const handleSearch = async () => {
|
||||
setError(null);
|
||||
setUserDetails(null);
|
||||
|
||||
if (!CIF && !username) {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Missing Input",
|
||||
message: "Please enter either CIF number or username.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
const token = checkAuth();
|
||||
if (!token) return;
|
||||
|
||||
try {
|
||||
const query = CIF ? CIF : username;
|
||||
const response = await fetch(`/api/auth/admin/user/rights?CIF=${query}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok || !data?.customer_no) {
|
||||
setError("User not found or invalid CIF/username.");
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "User Not Found",
|
||||
message: "Invalid CIF or username.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setUserDetails(data);
|
||||
|
||||
notifications.show({
|
||||
color: data.locked ? "red" : "green",
|
||||
title: "User Found",
|
||||
message: `User ${data.customer_no} is currently ${data.locked ? "Locked 🔒" : "Unlocked 🔓"
|
||||
}`,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Error",
|
||||
message: "Failed to fetch user details.",
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 🔄 Unlock or lock user
|
||||
const handleStatusChange = async (value: string) => {
|
||||
if (!userDetails?.customer_no) return;
|
||||
const isUnlock = value === "unlocked";
|
||||
|
||||
const token = checkAuth();
|
||||
if (!token) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch("/api/auth/admin/user/unlock", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user: userDetails.customer_no, // can also be username if API supports
|
||||
action: !isUnlock, // false => unlock, true => lock
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
setUserDetails({ ...userDetails, locked: !isUnlock });
|
||||
notifications.show({
|
||||
color: "green",
|
||||
title: "Success",
|
||||
message: `User ${userDetails.customer_no} ${isUnlock ? "unlocked" : "locked"
|
||||
} successfully.`,
|
||||
});
|
||||
} else {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Failed",
|
||||
message: data.message || "Unable to update lock status.",
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Error",
|
||||
message: "Something went wrong while updating user status.",
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setCIF("");
|
||||
setUsername("");
|
||||
setUserDetails(null);
|
||||
setError(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title order={4}>User Unlock Management</Title>
|
||||
|
||||
<Paper p="md" mt="md" radius="md" withBorder>
|
||||
<LoadingOverlay visible={loading} zIndex={1000} />
|
||||
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="CIF Number"
|
||||
placeholder="Enter CIF Number"
|
||||
value={CIF}
|
||||
onChange={(e) => {
|
||||
const input = e.currentTarget.value.replace(/\D/g, "");
|
||||
if (input.length <= 11) setCIF(input);
|
||||
setError(null);
|
||||
}}
|
||||
disabled={!!username}
|
||||
/>
|
||||
|
||||
<Text c="dimmed" ta="center">
|
||||
OR
|
||||
</Text>
|
||||
|
||||
<TextInput
|
||||
label="Username"
|
||||
placeholder="Enter Username"
|
||||
value={username}
|
||||
onChange={(e) => {
|
||||
const sanitized = e.currentTarget.value.replace(/[^a-zA-Z0-9@_]/g, "");
|
||||
if (sanitized.length <= 15) setUsername(sanitized);
|
||||
setError(null);
|
||||
}}
|
||||
disabled={!!CIF}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
{error && (
|
||||
<Center mt="xs">
|
||||
<Text c="red" size="sm" fw={500}>
|
||||
{error}
|
||||
</Text>
|
||||
</Center>
|
||||
)}
|
||||
|
||||
<Group mt="md">
|
||||
<Button onClick={handleSearch} disabled={loading}>
|
||||
Search
|
||||
</Button>
|
||||
<Button variant="light" color="red" onClick={handleReset}>
|
||||
Reset
|
||||
</Button>
|
||||
</Group>
|
||||
</Paper>
|
||||
|
||||
{userDetails && (
|
||||
<Paper withBorder p="md" mt="xl" radius="md">
|
||||
<Stack gap="xs">
|
||||
<Divider label="User Details" labelPosition="center" />
|
||||
|
||||
<Text>
|
||||
<strong>Customer No:</strong> {userDetails.customer_no}
|
||||
</Text>
|
||||
|
||||
<Text>
|
||||
<strong>Registration Status:</strong>{" "}
|
||||
{userDetails.last_login === null ? (
|
||||
<Text span c="red" fw={600}>
|
||||
Not Registered
|
||||
</Text>
|
||||
) : (
|
||||
<Text span c="green" fw={600}>
|
||||
Registered
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<Select
|
||||
label="Locked Status"
|
||||
value={userDetails.locked ? "locked" : "unlocked"}
|
||||
data={[
|
||||
{ value: "locked", label: "Locked 🔒" },
|
||||
{ value: "unlocked", label: "Unlocked 🔓" },
|
||||
]}
|
||||
onChange={(value) => {
|
||||
if (!value) return;
|
||||
handleStatusChange(value);
|
||||
}}
|
||||
mt="md"
|
||||
disabled={!userDetails.locked} // only allow change if locked
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -15,10 +15,11 @@ import {
|
||||
Paper,
|
||||
Tabs,
|
||||
ScrollArea,
|
||||
Center,
|
||||
} from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { IconGavel, IconUser } from "@tabler/icons-react";
|
||||
import { IconGavel, IconHome, IconUser } from "@tabler/icons-react";
|
||||
|
||||
export default function UserConfiguration() {
|
||||
const router = useRouter();
|
||||
@@ -32,11 +33,15 @@ export default function UserConfiguration() {
|
||||
const [ibAccess, setIbAccess] = useState<"2" | "1" | null>(null);
|
||||
const [mbEnabled, setMbEnabled] = useState(false);
|
||||
const [mbAccess, setMbAccess] = useState<"2" | "1" | null>(null);
|
||||
const [ibLimit, setIbLimit] = useState("");
|
||||
const [mbLimit, setMbLimit] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const isValidated = !!userDetails;
|
||||
const canSubmit =
|
||||
isValidated && savingsAccount && userDetails?.mobile && confirmedPreview;
|
||||
|
||||
// 🔹 Fetch both user details and rights
|
||||
const handleValidate = async () => {
|
||||
if (!CIF) {
|
||||
notifications.show({
|
||||
@@ -60,10 +65,14 @@ export default function UserConfiguration() {
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
if (response.ok && Array.isArray(data) && data.length > 0) {
|
||||
const saAccount = data.find((acc) => acc.stAccountType === "SA");
|
||||
if (!response.ok || !Array.isArray(data) || data.length === 0) {
|
||||
|
||||
setError("User not present or invalid CIF number.");
|
||||
}
|
||||
const saAccount = data.find(
|
||||
(acc: { stAccountType: string; }) => acc.stAccountType === "SA" || acc.stAccountType === "SB"
|
||||
);
|
||||
setSavingsAccount(saAccount?.stAccountNo ?? null);
|
||||
|
||||
const user = data[0];
|
||||
@@ -73,30 +82,52 @@ export default function UserConfiguration() {
|
||||
mobile: user.mobileno ?? null,
|
||||
address: user.custaddress,
|
||||
activeAccount: user.activeAccounts,
|
||||
branchNo: user.stBranchNo,
|
||||
dateOfBirth: user.custdob,
|
||||
pinCode: user.pincode,
|
||||
});
|
||||
} else {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Validation Failed",
|
||||
message: "User not found",
|
||||
});
|
||||
// Fetch existing rights if any
|
||||
const rightsRes = await fetch(
|
||||
`/api/auth/admin/user/rights?CIF=${CIF}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
} catch (err) {
|
||||
);
|
||||
|
||||
if (rightsRes.ok) {
|
||||
const rights = await rightsRes.json();
|
||||
if (rights?.ib_access_level || rights?.mb_access_level) {
|
||||
// populate existing rights
|
||||
if (rights.ib_access_level) {
|
||||
setIbEnabled(true);
|
||||
setIbAccess(rights.ib_access_level as "1" | "2");
|
||||
setIbLimit(rights.inb_limit_amount?.toString() || "");
|
||||
}
|
||||
if (rights.mb_access_level) {
|
||||
setMbEnabled(true);
|
||||
setMbAccess(rights.mb_access_level as "1" | "2");
|
||||
setMbLimit(rights.mobile_limit_amount?.toString() || "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Validation Failed",
|
||||
message: "User not found",
|
||||
});
|
||||
setError("User not present or invalid CIF number.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Preview before submit
|
||||
const handlePreview = () => {
|
||||
if (!savingsAccount || !userDetails?.mobile) {
|
||||
return;
|
||||
}
|
||||
if (!savingsAccount || !userDetails?.mobile) return;
|
||||
if (!ibAccess && !mbAccess) {
|
||||
notifications.show({
|
||||
title: "Rights Required",
|
||||
@@ -106,12 +137,20 @@ export default function UserConfiguration() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if ((ibEnabled && !ibLimit) || (mbEnabled && !mbLimit)) {
|
||||
notifications.show({
|
||||
title: "Limit Required",
|
||||
message: "Please enter fund transfer limits for enabled services.",
|
||||
color: "red",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setShowPreviewModal(true);
|
||||
};
|
||||
|
||||
// Submit or update rights
|
||||
const handleSubmit = async () => {
|
||||
if (!canSubmit) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem("admin_access_token");
|
||||
const response = await fetch("/api/auth/admin/user/rights", {
|
||||
@@ -125,52 +164,58 @@ export default function UserConfiguration() {
|
||||
CIF,
|
||||
ib_access_level: ibAccess,
|
||||
mb_access_level: mbAccess,
|
||||
ib_limit: ibLimit ? parseInt(ibLimit) : 0,
|
||||
mb_limit: mbLimit ? parseInt(mbLimit) : 0,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
if (data?.otp) {
|
||||
// Registration case
|
||||
await fetch('/api/otp/send', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json',"X-Login-Type": "Admin", },
|
||||
await fetch("/api/otp/send", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mobileNumber: userDetails.mobile,
|
||||
type: 'REGISTRATION',
|
||||
type: "REGISTRATION",
|
||||
userOtp: data.otp,
|
||||
}),
|
||||
});
|
||||
notifications.show({
|
||||
color: 'blue',
|
||||
title: 'Submitted',
|
||||
color: "blue",
|
||||
title: "Submitted",
|
||||
message: `User ${CIF} rights submitted successfully. OTP sent to the user.`,
|
||||
});
|
||||
}
|
||||
else if (data?.message) {
|
||||
// Rights update case
|
||||
await fetch('/api/otp/send', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json',"X-Login-Type": "Admin", },
|
||||
} else if (data?.message) {
|
||||
await fetch("/api/otp/send", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mobileNumber: userDetails.mobile,
|
||||
type: 'RIGHT_UPDATE',
|
||||
type: "RIGHT_UPDATE",
|
||||
}),
|
||||
});
|
||||
notifications.show({
|
||||
color: 'blue',
|
||||
title: 'Submitted',
|
||||
color: "blue",
|
||||
title: "Updated",
|
||||
message: `User ${CIF} rights updated successfully. Confirmation sent to the user.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (response.status === 401 || data.message === "invalid or expired token") {
|
||||
} else if (
|
||||
response.status === 401 ||
|
||||
data.message === "invalid or expired token"
|
||||
) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
router.push("/administrator/login");
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
notifications.show({
|
||||
color: "red",
|
||||
@@ -190,20 +235,19 @@ export default function UserConfiguration() {
|
||||
setConfirmedPreview(false);
|
||||
setIbEnabled(false);
|
||||
setIbAccess(null);
|
||||
setIbLimit("");
|
||||
setMbEnabled(false);
|
||||
setMbAccess(null);
|
||||
setMbLimit("");
|
||||
};
|
||||
|
||||
const handleMainAction = () => {
|
||||
if (!isValidated) {
|
||||
handleValidate();
|
||||
} else if (!confirmedPreview) {
|
||||
handlePreview();
|
||||
} else {
|
||||
handleSubmit();
|
||||
}
|
||||
if (!isValidated) handleValidate();
|
||||
else if (!confirmedPreview) handlePreview();
|
||||
else handleSubmit();
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title order={4}>User Configuration</Title>
|
||||
@@ -223,16 +267,26 @@ export default function UserConfiguration() {
|
||||
value={CIF}
|
||||
onChange={(e) => {
|
||||
const input = e.currentTarget.value.replace(/\D/g, "");
|
||||
if (input.length <= 11) setCIF(input);
|
||||
if (input.length <= 11)
|
||||
setCIF(input);
|
||||
setError(null);
|
||||
}}
|
||||
disabled={isValidated}
|
||||
withAsterisk
|
||||
/>
|
||||
{error && (
|
||||
<Center mt="xl">
|
||||
<Text c="red" fw={500} size="md">
|
||||
{error}
|
||||
</Text>
|
||||
</Center>
|
||||
)}
|
||||
|
||||
{isValidated && (
|
||||
<Tabs defaultValue="details" mt="md" variant="outline">
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="details" leftSection={<IconUser size={12} />}>User Details</Tabs.Tab>
|
||||
<Tabs.Tab value="address" leftSection={<IconHome size={12} />}>Address</Tabs.Tab>
|
||||
<Tabs.Tab value="rights" leftSection={<IconGavel size={12} />}>Rights</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
@@ -241,24 +295,32 @@ export default function UserConfiguration() {
|
||||
<Paper withBorder p="md" radius="md">
|
||||
<Stack>
|
||||
<Group grow>
|
||||
<Text fw={700} >User ID:</Text>
|
||||
<Text c="dimmed">{userDetails?.userId ?? "N/A"}</Text>
|
||||
<Text fw={700} >ID:</Text>
|
||||
<Text>{userDetails?.userId ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >User Name:</Text>
|
||||
<Text fw={700} >Branch:</Text>
|
||||
<Text>{userDetails?.branchNo ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >Name:</Text>
|
||||
<Text>{userDetails?.name ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >Mobile Number:</Text>
|
||||
<Text c="dimmed">{userDetails?.mobile ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >User Address:</Text>
|
||||
<Text>{userDetails?.address ?? "N/A"}</Text>
|
||||
<Text fw={700} >Date of Birth:</Text>
|
||||
<Text>
|
||||
{userDetails?.dateOfBirth
|
||||
? `${userDetails.dateOfBirth.slice(0, 2)}/${userDetails.dateOfBirth.slice(2, 4)}/${userDetails.dateOfBirth.slice(4)}`
|
||||
: "N/A"}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >Savings Account:</Text>
|
||||
<Text c="blue">{savingsAccount ?? "N/A"}</Text>
|
||||
<Text c="blue">
|
||||
{Array.isArray(savingsAccount)
|
||||
? savingsAccount.join(", ")
|
||||
: savingsAccount ?? "N/A"}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700}>Active Accounts:</Text>
|
||||
@@ -269,9 +331,31 @@ export default function UserConfiguration() {
|
||||
</ScrollArea>
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel value="address" pt="xs">
|
||||
<ScrollArea h={250} type="auto" offsetScrollbars>
|
||||
<Paper withBorder p="md" radius="md">
|
||||
<Stack>
|
||||
<Group grow>
|
||||
<Text fw={700} >Address:</Text>
|
||||
<Text>{userDetails?.address ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >Pincode:</Text>
|
||||
<Text>{userDetails?.pinCode ?? "N/A"}</Text>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Text fw={700} >Mobile Number:</Text>
|
||||
<Text>{userDetails?.mobile ?? "N/A"}</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</ScrollArea>
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel value="rights" pt="xs">
|
||||
<Stack gap="sm">
|
||||
<Group gap="xl" align="center">
|
||||
<Stack gap="md">
|
||||
{/* Internet Banking Section */}
|
||||
<Group>
|
||||
<Box w={150}>
|
||||
<Text fw={700}>Internet Banking</Text>
|
||||
</Box>
|
||||
@@ -281,7 +365,10 @@ export default function UserConfiguration() {
|
||||
checked={ibEnabled}
|
||||
onChange={(e) => {
|
||||
setIbEnabled(e.currentTarget.checked);
|
||||
if (!e.currentTarget.checked) setIbAccess(null);
|
||||
if (!e.currentTarget.checked) {
|
||||
setIbAccess(null);
|
||||
setIbLimit("");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -302,8 +389,25 @@ export default function UserConfiguration() {
|
||||
/>
|
||||
</Box>
|
||||
</Group>
|
||||
<Group align="center" gap="sm">
|
||||
<Text fw={700}>
|
||||
Fund Transfer Limit for Internet Banking
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder="Enter Amount"
|
||||
value={ibLimit}
|
||||
onChange={(e) => {
|
||||
const val = e.currentTarget.value;
|
||||
if (val === "" || (/^\d{0,7}$/.test(val))) {
|
||||
setIbLimit(val);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
<Group gap="xl" align="center">
|
||||
<Divider my="sm" labelPosition="center" />
|
||||
|
||||
<Group >
|
||||
<Box w={150}>
|
||||
<Text fw={700}>Mobile Banking</Text>
|
||||
</Box>
|
||||
@@ -313,7 +417,10 @@ export default function UserConfiguration() {
|
||||
checked={mbEnabled}
|
||||
onChange={(e) => {
|
||||
setMbEnabled(e.currentTarget.checked);
|
||||
if (!e.currentTarget.checked) setMbAccess(null);
|
||||
if (!e.currentTarget.checked) {
|
||||
setMbAccess(null);
|
||||
setMbLimit("");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -334,6 +441,21 @@ export default function UserConfiguration() {
|
||||
/>
|
||||
</Box>
|
||||
</Group>
|
||||
<Group align="center" gap="sm">
|
||||
<Text fw={700}>
|
||||
Fund Transfer Limit for Mobile Banking
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder="Enter Amount"
|
||||
value={mbLimit}
|
||||
onChange={(e) => {
|
||||
const val = e.currentTarget.value;
|
||||
if (val === "" || (/^\d{0,7}$/.test(val))) {
|
||||
setMbLimit(val);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
@@ -355,9 +477,12 @@ export default function UserConfiguration() {
|
||||
<Text>
|
||||
<strong>Mobile Number:</strong> {userDetails?.mobile ?? "N/A"}
|
||||
</Text>
|
||||
|
||||
<Divider label="Rights" size="xs" />
|
||||
|
||||
{/* Internet Banking Section */}
|
||||
<TextInput
|
||||
label="Internet Banking"
|
||||
label="Internet Banking Access"
|
||||
value={
|
||||
ibAccess === "1"
|
||||
? "Transaction"
|
||||
@@ -367,8 +492,16 @@ export default function UserConfiguration() {
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Mobile Banking"
|
||||
label="Internet Banking Limit"
|
||||
value={ibLimit || "N/A"}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
{/* Mobile Banking Section */}
|
||||
<TextInput
|
||||
label="Mobile Banking Access"
|
||||
value={
|
||||
mbAccess === "1"
|
||||
? "Transaction"
|
||||
@@ -378,7 +511,14 @@ export default function UserConfiguration() {
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Mobile Banking Limit"
|
||||
value={mbLimit || "N/A"}
|
||||
readOnly
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Group justify="right" mt="md">
|
||||
<Button variant="default" onClick={() => setShowPreviewModal(false)}>
|
||||
Cancel
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
LoadingOverlay,
|
||||
Box,
|
||||
Paper,
|
||||
Center,
|
||||
} from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
|
||||
@@ -27,35 +28,34 @@ export default function ViewUserRights() {
|
||||
const [CIFNo, setCIFNo] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [userData, setUserData] = useState<UserRights | null>(null);
|
||||
const [detailsExpanded, setDetailsExpanded] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleSearch = async () => {
|
||||
setError(null);
|
||||
if (!CIFNo) {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Required",
|
||||
message: "Please enter CIF Number.",
|
||||
title: "CIF Missing",
|
||||
message: "Please enter a CIF number to proceed.",
|
||||
});
|
||||
setUserData(null);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
setUserData(null);
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem("admin_access_token");
|
||||
const response = await fetch(
|
||||
`/api/auth/admin/user/rights?CIF=${CIFNo}`,
|
||||
{
|
||||
const response = await fetch(`/api/auth/admin/user/rights?CIF=${CIFNo}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data) {
|
||||
setUserData({
|
||||
customer_no: data.customer_no,
|
||||
@@ -66,18 +66,10 @@ export default function ViewUserRights() {
|
||||
mbAccess: data.mb_access_level,
|
||||
});
|
||||
} else {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Not Found",
|
||||
message: "No user rights found for this identifier.",
|
||||
});
|
||||
setError("User not present or invalid CIF number.");
|
||||
}
|
||||
} catch (err) {
|
||||
notifications.show({
|
||||
color: "red",
|
||||
title: "Failed",
|
||||
message: "Error fetching user rights",
|
||||
});
|
||||
setError("Error fetching user rights. Please try again.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -89,15 +81,15 @@ export default function ViewUserRights() {
|
||||
<Title order={4}>View User Rights</Title>
|
||||
<Group mt="sm">
|
||||
<TextInput
|
||||
// label="Enter CIF No"
|
||||
placeholder="Enter CIF Number"
|
||||
value={CIFNo}
|
||||
onInput={(e) => {
|
||||
const input = e.currentTarget.value.replace(/\D/g, "");
|
||||
if (input.length <= 11) {
|
||||
setCIFNo(input);
|
||||
setUserData(null)
|
||||
};
|
||||
setUserData(null);
|
||||
setError(null);
|
||||
}
|
||||
}}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
@@ -106,6 +98,15 @@ export default function ViewUserRights() {
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
{/* Error message in center */}
|
||||
{error && (
|
||||
<Center mt="xl">
|
||||
<Text c="red" fw={500} size="md">
|
||||
{error}
|
||||
</Text>
|
||||
</Center>
|
||||
)}
|
||||
|
||||
{userData && (
|
||||
<>
|
||||
<Divider size="xs" label="User Info" mt="md" />
|
||||
@@ -119,35 +120,57 @@ export default function ViewUserRights() {
|
||||
>
|
||||
<Stack gap="sm">
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>CIF Number:</Text>
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>
|
||||
CIF Number:
|
||||
</Text>
|
||||
<Text size="md">{userData.customer_no}</Text>
|
||||
</Group>
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed">User Created :</Text>
|
||||
<Text size="md">{new Date(userData.created_at).toLocaleString()}</Text>
|
||||
<Text size="sm" fw={500} c="dimmed">
|
||||
User Created :
|
||||
</Text>
|
||||
<Text size="md">
|
||||
{new Date(userData.created_at).toLocaleString()}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed">User Status:</Text>
|
||||
<Text size="md" c="green">Active</Text>
|
||||
<Text size="sm" fw={500} c="dimmed">
|
||||
User Status:
|
||||
</Text>
|
||||
<Text size="md" c="green">
|
||||
Active
|
||||
</Text>
|
||||
</Group>
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed">User Registered Status:</Text>
|
||||
<Text size="md" c={userData.is_first_login ? "orange" : "green"}>
|
||||
{userData.is_first_login ? "Not Registered" : "Registered"}
|
||||
<Text size="sm" fw={500} c="dimmed">
|
||||
User Registered Status:
|
||||
</Text>
|
||||
<Text
|
||||
size="md"
|
||||
c={userData.is_first_login ? "orange" : "green"}
|
||||
>
|
||||
{userData.is_first_login
|
||||
? "Not Registered"
|
||||
: "Registered"}
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
<Divider label="Rights" size="xs" mt="md" />
|
||||
<Paper style={{
|
||||
<Paper
|
||||
style={{
|
||||
border: "1px solid #47C44D",
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginTop: 8,
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Stack gap="sm" mt="sm">
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>Internet Banking Rights:</Text>
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>
|
||||
Internet Banking Rights:
|
||||
</Text>
|
||||
<Text size="md">
|
||||
{userData.ibAccess === "1"
|
||||
? "Transaction Mode"
|
||||
@@ -157,7 +180,9 @@ export default function ViewUserRights() {
|
||||
</Text>
|
||||
</Group>
|
||||
<Group justify="space-between">
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>Mobile Banking Rights:</Text>
|
||||
<Text size="sm" fw={500} c="dimmed" w={150}>
|
||||
Mobile Banking Rights:
|
||||
</Text>
|
||||
<Text size="md">
|
||||
{userData.mbAccess === "1"
|
||||
? "Transaction Mode"
|
||||
@@ -169,8 +194,7 @@ export default function ViewUserRights() {
|
||||
</Stack>
|
||||
</Paper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,50 +1,67 @@
|
||||
"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 [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 handleFetchUserDetails(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
const token = localStorage.getItem("admin_access_token");
|
||||
const response = await fetch('/api/auth/admin/admin_details', {
|
||||
method: 'GET',
|
||||
const response = await fetch("/api/auth/admin/admin_details", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
"X-Login-Type": "Admin",
|
||||
'Authorization': `Bearer ${token}`
|
||||
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') {
|
||||
} else if (response.status === 401 || data.message === "invalid or expired token") {
|
||||
localStorage.removeItem("admin_access_token");
|
||||
router.push('/administrator/login');
|
||||
}
|
||||
else {
|
||||
router.push("/administrator/login");
|
||||
} else {
|
||||
notifications.show({
|
||||
withBorder: true,
|
||||
color: "red",
|
||||
@@ -63,7 +80,9 @@ export default function Login() {
|
||||
} else {
|
||||
SetAuthorized(true);
|
||||
const fetchLoginTime = async () => {
|
||||
const result = await handleFetchUserDetails({ preventDefault: () => { } } as React.FormEvent);
|
||||
const result = await handleFetchUserDetails({
|
||||
preventDefault: () => { },
|
||||
} as React.FormEvent);
|
||||
if (result) {
|
||||
setLastLoginDetails(result.last_login);
|
||||
setName(result.name);
|
||||
@@ -73,29 +92,21 @@ export default function Login() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleClick = (type: 'UserConf' | 'ViewUser' | 'logout') => {
|
||||
if (type === 'UserConf') {
|
||||
setView('userConf');
|
||||
} else if (type === 'ViewUser') {
|
||||
setView('view');
|
||||
}
|
||||
};
|
||||
|
||||
if (!authorized) return null;
|
||||
|
||||
if (authorized) {
|
||||
return (
|
||||
<Providers>
|
||||
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%", }}>
|
||||
<div style={{ backgroundColor: "#f8f9fa", width: "100%", height: "100%" }}>
|
||||
{/* Header */}
|
||||
<Box
|
||||
style={{
|
||||
height: "60px",
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
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%)",
|
||||
background:
|
||||
"linear-gradient(15deg,rgba(10, 114, 40, 1) 55%, rgba(101, 101, 184, 1) 100%)",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
@@ -108,76 +119,214 @@ export default function Login() {
|
||||
<Title
|
||||
order={2}
|
||||
style={{
|
||||
fontFamily: 'Roboto',
|
||||
position: 'absolute',
|
||||
top: '30%',
|
||||
left: '6%',
|
||||
color: 'White',
|
||||
transition: "opacity 0.5s ease-in-out",
|
||||
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',
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "80%",
|
||||
color: "white",
|
||||
textShadow: "1px 1px 2px black",
|
||||
}}
|
||||
>
|
||||
<IconPhoneFilled size={20} /> Toll Free No : 1800-180-8008
|
||||
<IconPhoneFilled size={18} /> Toll Free No : 1800-180-8008
|
||||
</Text>
|
||||
</Box>
|
||||
{/* layout and */}
|
||||
<Box style={{ display: 'flex', height: '90vh' }}>
|
||||
{/* Sidebar manually placed under header */}
|
||||
|
||||
{/* Layout */}
|
||||
<Box style={{ display: "flex", height: "90vh" }}>
|
||||
{/* Sidebar */}
|
||||
<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',
|
||||
width: 240,
|
||||
background: "#02a355",
|
||||
padding: "0.75rem",
|
||||
borderRight: "1px solid #ccc",
|
||||
color: "white",
|
||||
fontSize: "13px",
|
||||
}}
|
||||
>
|
||||
<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
|
||||
<Title order={4} c="white" style={{ textAlign: "center", marginBottom: "6px" }}>
|
||||
Admin Portal
|
||||
</Title>
|
||||
<Divider my="xs" color="rgba(255,255,255,0.3)" />
|
||||
|
||||
{/* 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>
|
||||
<Text td="underline" variant="light" style={{ cursor: 'pointer' }} onClick={() => handleClick('ViewUser')}>
|
||||
<IconEye size="15" /> View User Configuration
|
||||
</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>
|
||||
|
||||
{/* 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>
|
||||
<Text td="underline" variant="light" style={{ cursor: 'pointer' }} onClick={handleLogout}>
|
||||
<IconLogout size="15" /> Logout
|
||||
</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>
|
||||
|
||||
{/* 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"}
|
||||
<Divider size="xs" color="#99c2ff" />
|
||||
<Text size="xs" style={{ textAlign: "center" }}>
|
||||
© 2025 The Kangra Central Co-Operative Bank
|
||||
</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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ export default function Login() {
|
||||
}
|
||||
|
||||
try {
|
||||
await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
|
||||
// await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: "7890544527" });
|
||||
// await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: mobile });
|
||||
await sendOtp({ type: 'LOGIN_OTP', username: CIF, mobileNumber: "7890544527" });
|
||||
notifications.show({
|
||||
color: 'orange',
|
||||
title: 'OTP Required',
|
||||
@@ -67,8 +67,8 @@ export default function Login() {
|
||||
async function handleVerifyOtp(mobile?: string) {
|
||||
try {
|
||||
if (mobile) {
|
||||
await verifyLoginOtp(otp, mobile);
|
||||
// await verifyLoginOtp(otp, '7890544527');
|
||||
// await verifyLoginOtp(otp, mobile);
|
||||
await verifyLoginOtp(otp, '7890544527');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user