diff --git a/instruction.txt b/instruction.txt index 429ac69..97256ac 100644 --- a/instruction.txt +++ b/instruction.txt @@ -19,5 +19,18 @@ For database: - password : kmobile - SELECT * FROM users; - \x + - \d -- all tables details - \d users; -- see the data type of column - - \c kmobile_banking kmobile_app_rw -- alter the user \ No newline at end of file + - \c kmobile_banking kmobile_app_rw -- alter the user + - grant select,insert,update,delete on table admin to kmobile_app_rw; -- give read write access to a table + + ______________________________________________________________________ + + How to connect through linux machine? + - run the bat file. + - shh username@localhost + - give your password + +Copy local machine to linux machine : +- scp -P 9022 Smsservice/smsserviceapplication.jar @localhost:/home/ +- ssh nabanita@localhost -p 9022 \ No newline at end of file diff --git a/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx b/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx index 30ab2e3..c014506 100644 --- a/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx +++ b/src/app/(main)/funds_transfer/add_beneficiary/addBeneficiaryOthers.tsx @@ -11,6 +11,7 @@ import { Group, Radio, Text, + PasswordInput, } from '@mantine/core'; import { notifications } from '@mantine/notifications'; @@ -339,9 +340,9 @@ const AddBeneficiaryOthers: React.FC = () => { // disabled={isVisibilityLocked} readOnly={isVisibilityLocked} required - // onCopy={(e) => e.preventDefault()} - // onPaste={(e) => e.preventDefault()} - // onCut={(e) => e.preventDefault()} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} /> {validationStatus === "error" && ( @@ -380,7 +381,7 @@ const AddBeneficiaryOthers: React.FC = () => { {otpSent && ( <> - { // disabled={isVisibilityLocked} readOnly={isVisibilityLocked} required - // onCopy={(e) => e.preventDefault()} - // onPaste={(e) => e.preventDefault()} - // onCut={(e) => e.preventDefault()} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} /> {validationStatus === "error" && ( @@ -294,7 +295,7 @@ const AddBeneficiary: React.FC = () => { {otpSent && ( <> - e.preventDefault()} - // onPaste={(e) => e.preventDefault()} - // onCut={(e) => e.preventDefault()} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} withAsterisk readOnly={isVisibilityLocked} /> @@ -418,7 +418,7 @@ export default function QuickPay() { {showOtpField && ( - (null); const [userLastLoginDetails, setUserLastLoginDetails] = useState(null); + const [custname, setCustname] = useState(null); async function handleLogout(e: React.FormEvent) { e.preventDefault(); localStorage.removeItem("access_token"); router.push("/login"); } + + async function handleFetchUserName() { + 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)) { + if (data.length > 0) { + const name = data[0].custname; + setCustname(name); + } + } 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, + }); + } + } + useEffect(() => { const token = localStorage.getItem("access_token"); if (!token) { @@ -28,6 +60,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) } else { SetAuthorized(true); + handleFetchUserName(); } }, []); @@ -44,8 +77,8 @@ export default function RootLayout({ children }: { children: React.ReactNode }) const data = await response.json(); 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') { // console.log(data); localStorage.removeItem("access_token"); router.push('/login'); @@ -125,7 +158,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) > - Welcome, Rajat Kumar Maharana + Welcome, {custname ?? null} Last logged in at {userLastLoginDetails ? new Date(userLastLoginDetails).toLocaleString() : "N/A"} diff --git a/src/app/ForgetPassword/page.tsx b/src/app/ForgetPassword/page.tsx new file mode 100644 index 0000000..4a4e132 --- /dev/null +++ b/src/app/ForgetPassword/page.tsx @@ -0,0 +1,266 @@ +"use client"; +import React, { useState, useEffect } from "react"; +import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } 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/logo.jpg'; +import changePwdImage from '@/app/image/changepw.png'; +// import CaptchaImage from './CaptchaImage'; +import { IconEye, IconEyeOff, IconLock, IconLogout } from '@tabler/icons-react'; + +export default function ForgetLoginPwd() { + const router = useRouter(); + const [authorized, SetAuthorized] = useState(null); + const [captcha, setCaptcha] = useState(""); + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [captchaInput, setCaptchaInput] = useState(''); + const [captchaError, setCaptchaError] = useState(''); + const [confirmVisible, setConfirmVisible] = useState(false); + const toggleConfirmVisibility = () => setConfirmVisible((v) => !v); + const icon = ; + + async function handleLogout(e: React.FormEvent) { + e.preventDefault(); + localStorage.removeItem("access_token"); + router.push("/login") + } + + useEffect(() => { + generateCaptcha(); + }, []); + + const generateCaptcha = () => { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < 6; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + setCaptcha(result); + setCaptchaInput(''); + setCaptchaError(''); + }; + + async function handleSetLoginPassword(e: React.FormEvent) { + e.preventDefault(); + const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/; + if (!password || !confirmPassword) { + notifications.show({ + withBorder: true, + color: "red", + title: "Both password fields are required.", + message: "Both password fields are required.", + autoClose: 5000, + }); + return; + // alert("Both password fields are required."); + } else if (password !== confirmPassword) { + // alert("Passwords do not match."); + notifications.show({ + withBorder: true, + color: "red", + title: "Passwords do not match.", + message: "Passwords do not match.", + autoClose: 5000, + }); + return; + } + else if (!pwdRegex.test(password)) { + // alert("Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long."); + notifications.show({ + withBorder: true, + color: "red", + title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", + message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", + autoClose: 5000, + }); + return; + } + else if (captchaInput !== captcha) { + setCaptchaError("Incorrect CAPTCHA."); + return; + } + const token = localStorage.getItem("access_token"); + const response = await fetch('api/auth/login_password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ + login_password: password, + }), + }); + const data = await response.json(); + if (response.ok) { + console.log(data); + notifications.show({ + withBorder: true, + color: "green", + title: "Login Password has been set", + message: "Login Password has been set", + autoClose: 5000, + }); + router.push("/SetTxn"); + } + else { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later ", + message: "Please try again later ", + autoClose: 5000, + }); + router.push("/login"); + } + } + + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + SetAuthorized(false); + router.push("/login"); + } + else { + SetAuthorized(true); + } + }, []); + + if (authorized) { + return ( + +
+ + ebanking + + +
+ + Change Password Image + + + Set Login Password + +
+ setPassword(e.currentTarget.value)} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} + /> + + setConfirmPassword(e.currentTarget.value)} + type={confirmVisible ? 'text' : 'password'} + // rightSection={ + // + // } + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} + + /> + + {/* CAPTCHA */} +
+ +
+ {/* */} + +
+ setCaptchaInput(e.currentTarget.value)} + required + /> + {captchaError &&

{captchaError}

} +
+ + + +

+ + + Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. + + +
+
+
+ + + © 2025 Kangra Central Co-Operative Bank + + +
+
+
+ ); + } +} \ No newline at end of file diff --git a/src/app/validate_user/page.tsx b/src/app/ValidateUser/page.tsx similarity index 100% rename from src/app/validate_user/page.tsx rename to src/app/ValidateUser/page.tsx diff --git a/src/app/administrator/home/UserConfiguration.tsx b/src/app/administrator/home/UserConfiguration.tsx new file mode 100644 index 0000000..d280f74 --- /dev/null +++ b/src/app/administrator/home/UserConfiguration.tsx @@ -0,0 +1,243 @@ +import React, { useState } from 'react'; +import { TextInput, Button, Title, Stack, Radio, Group, Text, Divider, LoadingOverlay, Box, Modal, Card, Checkbox } from '@mantine/core'; +import { notifications } from '@mantine/notifications'; + +export default function UserConfiguration() { + const [CIF, setCIF] = useState(''); + const [userDetails, setUserDetails] = useState(null); + const [loading, setLoading] = useState(false); + const [savingsAccount, setSavingsAccount] = useState(null); + const [accountError, setAccountError] = useState(''); + const [detailsExpanded, setDetailsExpanded] = useState(true); + const [showPreviewModal, setShowPreviewModal] = useState(false); + const [confirmedPreview, setConfirmedPreview] = useState(false); + const [ibEnabled, setIbEnabled] = useState(false); + const [ibAccess,setIbAccess] =useState<"read"|"transaction"|"">(""); + const [mbEnabled, setMbEnabled] = useState(false); + const [mbAccess,setMbAccess] =useState<"read"|"transaction"|"">(""); + const isValidated = !!userDetails; + const canSubmit = isValidated && !!savingsAccount && confirmedPreview; + + const handleValidate = async () => { + if (!CIF) { + notifications.show({ + color: 'red', + title: 'CIF Missing', + message: 'Please enter a CIF number to proceed.' + }); + return; + } + setLoading(true); + setAccountError(''); + setSavingsAccount(null); + setUserDetails(null); + + try { + const token = localStorage.getItem("admin_access_token"); + const response = await fetch(`/api/auth/admin/fetch/customer_details?CIF=${CIF}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + }); + + const data = await response.json(); + if (response.ok && Array.isArray(data) && data.length > 0) { + const saAccount = data.find(acc => acc.stAccountType === 'SA'); + console.log(saAccount); + if (saAccount) { + setSavingsAccount(saAccount.stAccountNo); + } else { + setAccountError('At least one savings account is required for requesting.'); + } + + const user = data[0]; + setUserDetails({ + name: user.custname, + userId: user.id, + mobile: user.mobileno, + address: user.custaddress, + activeAccount: user.activeAccounts, + }); + } else { + throw new Error('User not found or data format incorrect'); + } + } catch (err: any) { + notifications.show({ + color: 'red', + title: 'Validation Failed', + message: 'User not found', + }); + } finally { + setLoading(false); + } + }; + + const handleSubmit = () => { + if (!canSubmit) { + notifications.show({ + color: 'red', + title: 'Required', + message: 'One savings account is required for enable rights', + }); + return; + } + else { + const rightsData = { + CIF, + // internetBanking, + // mobileBanking, + }; + console.log('Submitting rights:', rightsData); + notifications.show({ + color: 'blue', + title: 'Submitted', + message: `User -${CIF} rights submitted successfully.`, + }); + } + setSavingsAccount(null); + setUserDetails(null); + setCIF(''); + }; + + const handleMainAction = () => { + if (!isValidated) { + handleValidate(); + } else if (!confirmedPreview) { + setShowPreviewModal(true); + } else if (isValidated && confirmedPreview) { + handleSubmit(); + } + }; + + return ( + + + User Configuration + { + const input = e.currentTarget.value.replace(/\D/g, ''); + if (input.length <= 11) setCIF(input); + }} + disabled={isValidated} + withAsterisk /> + + {isValidated && ( + <> + + + + Preview User Details + + + + {detailsExpanded && ( + <> + + + + + + + + + + + + )} + + + + + + + Internet Banking + + { + setIbEnabled(e.currentTarget.checked); + if (!e.currentTarget.checked) setIbAccess(""); // reset if disabled + }} + /> + setIbAccess("read")} + /> + setIbAccess("transaction")} + /> + + + + {/* Mobile Banking */} + + Mobile Banking + + { + setMbEnabled(e.currentTarget.checked); + if (!e.currentTarget.checked) setMbAccess(""); // reset if disabled + }} + /> + setMbAccess("read")} + /> + setMbAccess("transaction")} + /> + + + + + {accountError && ( + {accountError} + )} + + + )} + + + + setShowPreviewModal(false)} + title="Confirm User Rights" + centered + > + + + {/* + */} + + + + + + + + + ); +} \ No newline at end of file diff --git a/src/app/administrator/home/page.tsx b/src/app/administrator/home/page.tsx new file mode 100644 index 0000000..8a7ccb5 --- /dev/null +++ b/src/app/administrator/home/page.tsx @@ -0,0 +1,162 @@ +"use client"; +import React, { useState, useEffect } from "react"; +import { Text, Box, Image, Button, Stack, Divider, Title } 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/logo.jpg'; +import { IconLogout, IconUsers, IconUserScreen } from "@tabler/icons-react"; +import UserConfiguration from "./UserConfiguration"; + +export default function Login() { + const router = useRouter(); + const [authorized, SetAuthorized] = useState(null); + const [view, setView] = useState<'userConf' | 'view' | null>(null); + const [lastLoginDetails, setLastLoginDetails] = useState(null); + const [name, setName] = useState(null); + + async function handleLogout(e: React.FormEvent) { + e.preventDefault(); + localStorage.removeItem("admin_access_token"); + 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', + '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(); + } + }, []); + + const handleClick = (type: 'UserConf' | 'ViewUser' | 'logout') => { + if (type === 'UserConf') { + setView('userConf'); + } else if (type === 'ViewUser') { + setView('view'); + } + }; + + if (!authorized) return null; + + if (authorized) { + return ( + +
+ {/* Header */} + + ebanking + + {/* */} + Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215 + + + {/* layout and */} + + {/* Sidebar manually placed under header */} + + Admin Portal + + + handleClick('UserConf')}> + User Configuration + + handleClick('ViewUser')}> + View Users + + + Logout + + + + + {/* Main Content Area */} + + + Welcome ,{name} + + Last logged in at {lastLoginDetails ? new Date(lastLoginDetails).toLocaleString() : "N/A"} + + + + {view === 'userConf' && } + {view === 'view' && view} + {!view && + Welcome To The Admin Portal + } + + + +
+
+ ); + } +} diff --git a/src/app/administrator/login/page.tsx b/src/app/administrator/login/page.tsx new file mode 100644 index 0000000..63ff00a --- /dev/null +++ b/src/app/administrator/login/page.tsx @@ -0,0 +1,207 @@ +"use client"; +import React, { useState, useEffect } from "react"; +import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Box, Image } 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/logo.jpg'; +import frontPage from '@/app/image/admin_login.jpg'; +import { generateCaptcha } from '@/app/captcha'; + +export default function Login() { + const router = useRouter(); + const [error, setError] = useState(null); + const [userName, setUserName] = useState(""); + const [psw, SetPsw] = useState(""); + const [captcha, setCaptcha] = useState(""); + const [inputCaptcha, setInputCaptcha] = useState(""); + const [isLogging, setIsLogging] = useState(false); + + + useEffect(() => { + const loadCaptcha = async () => { + const newCaptcha = await generateCaptcha(); + setCaptcha(newCaptcha); + }; + loadCaptcha(); + }, []); + + const regenerateCaptcha = () => { + // setCaptcha(generateCaptcha()); + const loadCaptcha = async () => { + const newCaptcha = await generateCaptcha(); + setCaptcha(newCaptcha); + }; + loadCaptcha(); + setInputCaptcha(""); + }; + + async function handleLogin(e: React.FormEvent) { + e.preventDefault(); + if (!userName || !psw || !captcha) { + notifications.show({ + withBorder: true, + color: "red", + title: "Field Blank", + message: "Please enter all mandatory details", + autoClose: 5000, + }); + return; + } + if (inputCaptcha !== captcha) { + notifications.show({ + withBorder: true, + color: "red", + title: "Captcha Error", + message: "Please enter the correct captcha", + autoClose: 5000, + }); + regenerateCaptcha(); + return; + } + const response = await fetch('/api/auth/admin/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + userName: userName, + password: psw, + }), + }); + const data = await response.json(); + setIsLogging(true); + if (response.ok) { + console.log(data); + const token = data.token; + localStorage.setItem("admin_access_token", token); + router.push("/administrator/home"); + + } + else { + setIsLogging(false); + notifications.show({ + withBorder: true, + color: "red", + title: "Wrong User Id or Password", + message: "Wrong User Id or Password", + autoClose: 5000, + }); + } + } + + return ( + +
+ {/* Header */} + + ebanking + + {/* */} + Head Office : Dharmshala, District: Kangra(H.P), Pincode: 176215 + + +
+ {/* Main */} +
+
+ ebanking +
+ + + {/* @ts-ignore */} + Admin Portal +
+ setUserName(e.currentTarget.value)} + error={error} + withAsterisk + /> + SetPsw(e.currentTarget.value)} + withAsterisk + mt="sm" + /> + {/* + router.push("/ValidateUser")} + > + Forgot Password? + + */} + + {captcha} + + + + setInputCaptcha(e.currentTarget.value)} + withAsterisk + mt="sm" + /> + + +
+
+
+ + {/* Footer */} + + + © 2025 KCC Bank. All rights reserved. + + +
+
+
+ ); +} diff --git a/src/app/image/admin_login.jpg b/src/app/image/admin_login.jpg new file mode 100644 index 0000000..63c1b6f Binary files /dev/null and b/src/app/image/admin_login.jpg differ diff --git a/src/app/image/ib_admin_front_page.jpg b/src/app/image/ib_admin_front_page.jpg new file mode 100644 index 0000000..b1d4865 Binary files /dev/null and b/src/app/image/ib_admin_front_page.jpg differ diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 97db7a0..3e8bf23 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -52,6 +52,7 @@ export default function Login() { message: "Please enter the correct captcha", autoClose: 5000, }); + regenerateCaptcha(); return; } const response = await fetch('api/auth/login', { @@ -198,7 +199,7 @@ export default function Login() { router.push("/validate_user")} + onClick={() => router.push("/ValidateUser")} > Forgot Password?