added eslint and prettier and formatted the whole codebase

This commit is contained in:
asif
2025-08-25 02:00:54 +05:30
parent 700a9261a8
commit f400490b65
54 changed files with 1119 additions and 969 deletions

7
.prettierrc Normal file
View File

@@ -0,0 +1,7 @@
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5"
}

View File

@@ -1,8 +1,10 @@
import js from '@eslint/js' import js from '@eslint/js';
import globals from 'globals' import globals from 'globals';
import react from 'eslint-plugin-react' import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks' import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh' import reactRefresh from 'eslint-plugin-react-refresh';
import prettier from 'eslint-plugin-prettier';
import prettierConfig from 'eslint-config-prettier';
export default [ export default [
{ ignores: ['dist'] }, { ignores: ['dist'] },
@@ -22,17 +24,17 @@ export default [
react, react,
'react-hooks': reactHooks, 'react-hooks': reactHooks,
'react-refresh': reactRefresh, 'react-refresh': reactRefresh,
prettier,
}, },
rules: { rules: {
...js.configs.recommended.rules, ...js.configs.recommended.rules,
...react.configs.recommended.rules, ...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules, ...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules, ...reactHooks.configs.recommended.rules,
...prettierConfig.rules,
'react/jsx-no-target-blank': 'off', 'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [ 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'warn', 'prettier/prettier': 'error',
{ allowConstantExport: true },
],
}, },
}, },
] ];

115
package-lock.json generated
View File

@@ -28,11 +28,14 @@
"@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^9.9.0", "eslint": "^9.9.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-react": "^7.35.0", "eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9", "eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0", "globals": "^15.9.0",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.6.2",
"tailwindcss": "^3.4.13", "tailwindcss": "^3.4.13",
"vite": "^5.4.1" "vite": "^5.4.1"
} }
@@ -1090,6 +1093,19 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.19.2", "version": "1.19.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
@@ -2492,6 +2508,53 @@
} }
} }
}, },
"node_modules/eslint-config-prettier": {
"version": "10.1.8",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
"funding": {
"url": "https://opencollective.com/eslint-config-prettier"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz",
"integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.11.7"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-react": { "node_modules/eslint-plugin-react": {
"version": "7.37.0", "version": "7.37.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz",
@@ -2738,6 +2801,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
@@ -4655,6 +4725,35 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5371,6 +5470,22 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/synckit": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "3.4.13", "version": "3.4.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",

View File

@@ -7,6 +7,7 @@
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"lint": "eslint .", "lint": "eslint .",
"format": "prettier --write .",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
@@ -30,11 +31,14 @@
"@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^9.9.0", "eslint": "^9.9.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-react": "^7.35.0", "eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9", "eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0", "globals": "^15.9.0",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.6.2",
"tailwindcss": "^3.4.13", "tailwindcss": "^3.4.13",
"vite": "^5.4.1" "vite": "^5.4.1"
} }

View File

@@ -3,4 +3,4 @@ export default {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
} };

View File

@@ -36,7 +36,7 @@
"myIntimation": "আমার বিজ্ঞপ্তি", "myIntimation": "আমার বিজ্ঞপ্তি",
"changePassword": "পাসওয়ার্ড পরিবর্তন", "changePassword": "পাসওয়ার্ড পরিবর্তন",
"resetLogin": "লগইন স্ট্যাটাস রিসেট করুন", "resetLogin": "লগইন স্ট্যাটাস রিসেট করুন",
"currentDate" : "{{val, datetime}}", "currentDate": "{{val, datetime}}",
"notifications": "বিজ্ঞপ্তি", "notifications": "বিজ্ঞপ্তি",
"holidayList": "ছুটির তালিকা", "holidayList": "ছুটির তালিকা",
"information": "তথ্য", "information": "তথ্য",

View File

@@ -37,7 +37,7 @@
"myIntimation": "My Intimation", "myIntimation": "My Intimation",
"changePassword": "Change Password", "changePassword": "Change Password",
"resetLogin": "Reset Login Status", "resetLogin": "Reset Login Status",
"currentDate" : "{{val, datetime}}", "currentDate": "{{val, datetime}}",
"notifications": "Notification", "notifications": "Notification",
"holidayList": "Holiday List", "holidayList": "Holiday List",
"information": "Information", "information": "Information",

View File

@@ -37,7 +37,7 @@
"myIntimation": "मेरा सूचितकरण", "myIntimation": "मेरा सूचितकरण",
"changePassword": "पासवर्ड बदलें", "changePassword": "पासवर्ड बदलें",
"resetLogin": "लॉगिन स्थिति रीसेट करें", "resetLogin": "लॉगिन स्थिति रीसेट करें",
"currentDate" : "{{val, datetime}}", "currentDate": "{{val, datetime}}",
"notifications": "सूचना", "notifications": "सूचना",
"holidayList": "छुट्टी की सूची", "holidayList": "छुट्टी की सूची",
"information": "जानकारी", "information": "जानकारी",

View File

@@ -1,13 +1,13 @@
import { useLocation, useOutlet } from "react-router"; import { useLocation, useOutlet } from 'react-router';
import { useState } from "react"; import { useState } from 'react';
import Header from "./components/Header"; import Header from './components/Header';
import Footer from "./components/Footer"; import Footer from './components/Footer';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import { motion } from "motion/react"; import { motion } from 'motion/react';
import { ToastProvider } from "./contexts/Toast"; import { ToastProvider } from './contexts/Toast';
import { useLoading } from "./hooks/useLoading"; import { useLoading } from './hooks/useLoading';
import LoadingBar from "./components/LoadingBar"; import LoadingBar from './components/LoadingBar';
import { LoadingProvider } from "./contexts/Loading"; import { LoadingProvider } from './contexts/Loading';
const AnimatedOutlet = () => { const AnimatedOutlet = () => {
const o = useOutlet(); const o = useOutlet();

View File

@@ -3,16 +3,15 @@ import DarkModeToggle from './DarkModeToggle';
import LanguageSelector from './LanguageSelector'; import LanguageSelector from './LanguageSelector';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
function AppTitle() { function AppTitle() {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div className='flex items-center justify-between pt-3 pb-5'> <div className="flex items-center justify-between pt-3 pb-5">
<div className='flex items-center gap-5'> <div className="flex items-center gap-5">
<img src={IpksLogo} alt="IPKS Logo" className="h-16" /> <img src={IpksLogo} alt="IPKS Logo" className="h-16" />
<h1 className="font-bold text-title font-display">{t('appName')}</h1> <h1 className="font-bold text-title font-display">{t('appName')}</h1>
</div> </div>
<div className='flex items-center gap-2'> <div className="flex items-center gap-2">
<DarkModeToggle /> <DarkModeToggle />
<LanguageSelector /> <LanguageSelector />
</div> </div>

View File

@@ -1,31 +1,30 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import BannerInfoElement from "./BannerInfoElement"; import BannerInfoElement from './BannerInfoElement';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
function BannerInfo({info}) { function BannerInfo({ info }) {
const {t} = useTranslation(); const { t } = useTranslation();
const infoElements = Object.keys(info).map((key) => ( const infoElements = Object.keys(info).map((key) => (
<BannerInfoElement key={key} title={t(key)} description={t(info[key])} /> <BannerInfoElement key={key} title={t(key)} description={t(info[key])} />
)) ));
infoElements.push( infoElements.push(
<BannerInfoElement <BannerInfoElement
key="date" key="date"
title={t('date')} title={t('date')}
description={t('currentDate',{val: new Date(), formatParams: { description={t('currentDate', {
val: { month: 'long', day: '2-digit', year: 'numeric'}, val: new Date(),
},})} formatParams: {
val: { month: 'long', day: '2-digit', year: 'numeric' },
},
})}
/> />
); );
return ( return <div className="flex justify-between pb-1">{infoElements}</div>;
<div className="flex justify-between pb-1">
{infoElements}
</div>
)
} }
BannerInfo.propTypes = { BannerInfo.propTypes = {
info: PropTypes.object.isRequired info: PropTypes.object.isRequired,
} };
export default BannerInfo; export default BannerInfo;

View File

@@ -2,16 +2,16 @@ import PropTypes from 'prop-types';
function BannerInfoElement({ title, description }) { function BannerInfoElement({ title, description }) {
return ( return (
<div className='font-body'> <div className="font-body">
<div className='text-base '>{title}</div> <div className="text-base ">{title}</div>
<div className='text-[18px] font-medium'>{description}</div> <div className="text-[18px] font-medium">{description}</div>
</div> </div>
); );
} }
BannerInfoElement.propTypes = { BannerInfoElement.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired description: PropTypes.string.isRequired,
}; };
export default BannerInfoElement; export default BannerInfoElement;

View File

@@ -2,18 +2,21 @@ import PropTypes from 'prop-types';
import { motion } from 'motion/react'; import { motion } from 'motion/react';
import clsx from 'clsx'; import clsx from 'clsx';
function Button({text, onClick, disabled}) { function Button({ text, onClick, disabled }) {
return ( return (
<motion.button <motion.button
whileHover={!disabled && { scale: 1.05 }} whileHover={!disabled && { scale: 1.05 }}
whileTap={!disabled && { scale: 0.95 }} whileTap={!disabled && { scale: 0.95 }}
className={clsx("px-12 py-2 text-lg text-white dark:text-primary-dark rounded-full bg-primary dark:bg-secondary-dark", disabled && "bg-[#cccccc] dark:bg-[#cccccc]")} className={clsx(
'px-12 py-2 text-lg text-white dark:text-primary-dark rounded-full bg-primary dark:bg-secondary-dark',
disabled && 'bg-[#cccccc] dark:bg-[#cccccc]'
)}
onClick={onClick} onClick={onClick}
disabled={disabled} disabled={disabled}
> >
{text} {text}
</motion.button> </motion.button>
) );
} }
Button.propTypes = { Button.propTypes = {

View File

@@ -17,7 +17,7 @@ const DarkModeToggle = () => {
}, [darkMode]); }, [darkMode]);
const toggleDarkMode = () => { const toggleDarkMode = () => {
setDarkMode(prevMode => !prevMode); setDarkMode((prevMode) => !prevMode);
}; };
return ( return (

View File

@@ -1,5 +1,5 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { motion } from "motion/react"; import { motion } from 'motion/react';
function FieldError({ text }) { function FieldError({ text }) {
return ( return (

View File

@@ -1,6 +1,6 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
function FieldsWrapper({ children, className = "" }) { function FieldsWrapper({ children, className = '' }) {
return <div className={`flex flex-col gap-4 m-2 my-7 ${className}`}>{children}</div>; return <div className={`flex flex-col gap-4 m-2 my-7 ${className}`}>{children}</div>;
} }

View File

@@ -1,21 +1,21 @@
import { PropTypes } from "prop-types"; import { PropTypes } from 'prop-types';
import clsx from "clsx"; import clsx from 'clsx';
function FormBox({ title, children, alt = false }) { function FormBox({ title, children, alt = false }) {
return ( return (
<form <form
className={clsx( className={clsx(
alt alt
? "bg-secondary-variant dark:bg-secondary-variant-dark border-secondary-variant dark:border-secondary-variant-dark" ? 'bg-secondary-variant dark:bg-secondary-variant-dark border-secondary-variant dark:border-secondary-variant-dark'
: "bg-surface-variant dark:bg-surface-variant-dark", : 'bg-surface-variant dark:bg-surface-variant-dark',
"transition-color-mode font-body border-secondary dark:border-secondary-dark border-2 p-4 rounded-3xl relative h-full" 'transition-color-mode font-body border-secondary dark:border-secondary-dark border-2 p-4 rounded-3xl relative h-full'
)} )}
> >
<label <label
className={clsx( className={clsx(
alt && alt &&
"bg-surface dark:bg-surface-dark border-3 border-secondary-variant dark:border-secondary-variant-dark", 'bg-surface dark:bg-surface-dark border-3 border-secondary-variant dark:border-secondary-variant-dark',
"font-body absolute left-11 -top-4 bg-secondary dark:bg-secondary-dark text-primary dark:text-primary-dark font-medium py-1 px-4 rounded-full z-20" 'font-body absolute left-11 -top-4 bg-secondary dark:bg-secondary-dark text-primary dark:text-primary-dark font-medium py-1 px-4 rounded-full z-20'
)} )}
> >
{title} {title}

View File

@@ -1,30 +1,35 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { motion } from "motion/react"; import { motion } from 'motion/react';
import clsx from "clsx"; import clsx from 'clsx';
function FormField({ label, children, icon, variant }) { function FormField({ label, children, icon, variant }) {
return ( return (
<div className="flex items-center"> <div className="flex items-center">
<label className={clsx( <label
"mr-20 text-lg text-black dark:text-primary-dark whitespace-nowrap", className={clsx(
variant === 'long' && "sm:w-[5%]" 'mr-20 text-lg text-black dark:text-primary-dark whitespace-nowrap',
)}> variant === 'long' && 'sm:w-[5%]'
)}
>
{label} {label}
</label> </label>
<div className={clsx("flex w-full gap-4 items-center", variant === 'long' && 'gap-10')}> <div className={clsx('flex w-full gap-4 items-center', variant === 'long' && 'gap-10')}>
{children} {children}
{icon && ( {icon && (
<motion.div <motion.div
whileHover={{ scale: 1.1 }} whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }} whileTap={{ scale: 0.9 }}
className={clsx(icon.mode === "plain" ? "text-[#444]" : "bg-primary rounded-full p-2 text-white cursor-pointer")} className={clsx(
icon.mode === 'plain'
? 'text-[#444]'
: 'bg-primary rounded-full p-2 text-white cursor-pointer'
)}
onClick={icon.onClick} onClick={icon.onClick}
> >
{icon.icon} {icon.icon}
</motion.div> </motion.div>
)} )}
</div> </div>
</div> </div>
); );
} }
@@ -33,7 +38,7 @@ FormField.propTypes = {
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
icon: PropTypes.object, icon: PropTypes.object,
variant: PropTypes.string variant: PropTypes.string,
}; };
export default FormField; export default FormField;

View File

@@ -1,11 +1,11 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
function FormHeader({ text }) { function FormHeader({ text }) {
return <h1 className="text-2xl font-medium text-primary mt-5">{text}</h1>; return <h1 className="text-2xl font-medium text-primary mt-5">{text}</h1>;
} }
FormHeader.propTypes = { FormHeader.propTypes = {
text: PropTypes.string.isRequired text: PropTypes.string.isRequired,
} };
export default FormHeader; export default FormHeader;

View File

@@ -1,15 +1,15 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { motion, AnimatePresence } from "motion/react"; import { motion, AnimatePresence } from 'motion/react';
import clsx from "clsx"; import clsx from 'clsx';
function FormInput({ props, valid = true, className = "" }) { function FormInput({ props, valid = true, className = '' }) {
return ( return (
<div> <div>
<input <input
{...props} {...props}
className={clsx( className={clsx(
`w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`, `w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`,
!valid && "border-error" !valid && 'border-error'
)} )}
/> />
<AnimatePresence> <AnimatePresence>

View File

@@ -1,10 +1,10 @@
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import clsx from "clsx"; import clsx from 'clsx';
import FieldError from "./FieldError"; import FieldError from './FieldError';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
function FormSelect({ props, valid = true, className = "", options }) { function FormSelect({ props, valid = true, className = '', options }) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div> <div>
@@ -12,11 +12,11 @@ function FormSelect({ props, valid = true, className = "", options }) {
{...props} {...props}
className={clsx( className={clsx(
`w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`, `w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`,
!valid && "border-error" !valid && 'border-error'
)} )}
> >
<option disabled value=""> <option disabled value="">
{t("select")} {t('select')}
</option> </option>
{options?.map(({ value, label }) => ( {options?.map(({ value, label }) => (
<option key={value} value={value}> <option key={value} value={value}>
@@ -24,9 +24,7 @@ function FormSelect({ props, valid = true, className = "", options }) {
</option> </option>
))} ))}
</select> </select>
<AnimatePresence> <AnimatePresence>{!valid && <FieldError text={'Invalid value'} />}</AnimatePresence>
{!valid && <FieldError text={"Invalid value"} />}
</AnimatePresence>
</div> </div>
); );
} }

View File

@@ -1,43 +1,52 @@
import { getUserInfoFromSession } from "../util/util"; import { getUserInfoFromSession } from '../util/util';
import AppTitle from "./AppTitle"; import AppTitle from './AppTitle';
import BannerInfo from "./BannerInfo"; import BannerInfo from './BannerInfo';
import MenuBar from "./MenuBar"; import MenuBar from './MenuBar';
import Separator from "./Separator"; import Separator from './Separator';
function Header() { function Header() {
const userInfo = getUserInfoFromSession(); const userInfo = getUserInfoFromSession();
const menuItems = [ const menuItems = [
{ name: "home", submenu: [], path: "/" }, { name: 'home', submenu: [], path: '/' },
{ {
name: "moduleList", name: 'moduleList',
submenu: [ submenu: [
{ name: "kcc", path: "kcc" }, { name: 'kcc', path: 'kcc' },
{ name: "trading", path: "trading" }, { name: 'trading', path: 'trading' },
{ name: "asset", path: "asset" }, { name: 'asset', path: 'asset' },
{ name: "selfHelpGroup", path: "shg" }, { name: 'selfHelpGroup', path: 'shg' },
{ name: "deposit", path: "deposit" }, { name: 'deposit', path: 'deposit' },
{ name: "loan", path: "loan" }, { name: 'loan', path: 'loan' },
{ name: "share", path: "share" }, { name: 'share', path: 'share' },
], ],
}, },
{ name: "enquiry", submenu: [{ name: "lockerEnquiry", path: "locker-enquiry" }, { name: "accountEnquiry", path: "account-enquiry" }] },
{ {
name: "lockerOperation", name: 'enquiry',
submenu: [ submenu: [
{ name: "accountCreation", path: "operation/account" }, { name: 'lockerEnquiry', path: 'locker-enquiry' },
{ name: "cabinetMaintenance", path: "operation/cabinet" }, { name: 'accountEnquiry', path: 'account-enquiry' },
{ name: "lockerMaintenance", path: "operation/locker" },
{ name: "chargeManagement", path: "operation/charge-management" },
{ name: "checkInOutManagement", path: "operation/check-in-out" },
{ name: "accountSurrender", path: "operation/account-surrender" }
], ],
}, },
{ name: "worklist", submenu: [{ name: "myIntimation", path: "my-intimation" }] },
{ {
name: "userManagement", name: 'lockerOperation',
submenu: [{ name: "resetLogin", path: "reset-login" }, { name: "changePassword", path: "change-password" }], submenu: [
{ name: 'accountCreation', path: 'operation/account' },
{ name: 'cabinetMaintenance', path: 'operation/cabinet' },
{ name: 'lockerMaintenance', path: 'operation/locker' },
{ name: 'chargeManagement', path: 'operation/charge-management' },
{ name: 'checkInOutManagement', path: 'operation/check-in-out' },
{ name: 'accountSurrender', path: 'operation/account-surrender' },
],
}, },
{ name: "logout", submenu: [] }, { name: 'worklist', submenu: [{ name: 'myIntimation', path: 'my-intimation' }] },
{
name: 'userManagement',
submenu: [
{ name: 'resetLogin', path: 'reset-login' },
{ name: 'changePassword', path: 'change-password' },
],
},
{ name: 'logout', submenu: [] },
]; ];
return ( return (
@@ -47,7 +56,7 @@ function Header() {
<Separator /> <Separator />
<MenuBar menuItems={menuItems} /> <MenuBar menuItems={menuItems} />
</div> </div>
) );
} }
export default Header; export default Header;

View File

@@ -9,7 +9,12 @@ const LanguageSelector = () => {
return ( return (
<div> <div>
<select className='rounded-md font-body bg-secondary dark:bg-secondary-dark focus:outline-none' id="language-select" onChange={changeLanguage} value={i18n.language}> <select
className="rounded-md font-body bg-secondary dark:bg-secondary-dark focus:outline-none"
id="language-select"
onChange={changeLanguage}
value={i18n.language}
>
<option value="en">English</option> <option value="en">English</option>
<option value="bn"></option> <option value="bn"></option>
<option value="hi">ि</option> <option value="hi">ि</option>

View File

@@ -1,12 +1,12 @@
import { motion } from "framer-motion"; import { motion } from 'framer-motion';
function LoadingBar() { function LoadingBar() {
return ( return (
<div className="h-1 bg-grey relative overflow-hidden"> <div className="h-1 bg-grey relative overflow-hidden">
<motion.div <motion.div
className="bg-primary dark:bg-primary-dark w-full h-full rounded-sm absolute" className="bg-primary dark:bg-primary-dark w-full h-full rounded-sm absolute"
animate={{ x: ["-100%", "100%"] }} animate={{ x: ['-100%', '100%'] }}
transition={{ repeat: Infinity, duration: 2, ease: "anticipate" }} transition={{ repeat: Infinity, duration: 2, ease: 'anticipate' }}
></motion.div> ></motion.div>
</div> </div>
); );

View File

@@ -1,9 +1,9 @@
import { Link } from "react-router-dom"; import { Link } from 'react-router-dom';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import clsx from "clsx"; import clsx from 'clsx';
import { useState } from "react"; import { useState } from 'react';
import { AnimatePresence, motion } from "motion/react"; import { AnimatePresence, motion } from 'motion/react';
function SubMenu({ items, isVisible, onLinkClick }) { function SubMenu({ items, isVisible, onLinkClick }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -13,12 +13,12 @@ function SubMenu({ items, isVisible, onLinkClick }) {
<div> <div>
<motion.div <motion.div
className={clsx( className={clsx(
"absolute left-0 z-50 shadow-sm top-full border-t-3 border-primary dark:border-primary-dark bg-secondary dark:bg-secondary-dark rounded-2xl shadow-surface-variant-dark dark:shadow-primary" 'absolute left-0 z-50 shadow-sm top-full border-t-3 border-primary dark:border-primary-dark bg-secondary dark:bg-secondary-dark rounded-2xl shadow-surface-variant-dark dark:shadow-primary'
)} )}
initial={{ y: 15, opacity: 0 }} initial={{ y: 15, opacity: 0 }}
animate={{ y: 0, opacity: 1 }} animate={{ y: 0, opacity: 1 }}
exit={{ y: 15, opacity: 0 }} exit={{ y: 15, opacity: 0 }}
transition={{ duration: 0.3, type: "spring" }} transition={{ duration: 0.3, type: 'spring' }}
> >
{items.map((subItem, index) => ( {items.map((subItem, index) => (
<div <div

View File

@@ -1,7 +1,7 @@
import clsx from "clsx"; import clsx from 'clsx';
import { Copy } from "lucide-react"; import { Copy } from 'lucide-react';
import { motion } from "motion/react"; import { motion } from 'motion/react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
function Notification({ message, type }) { function Notification({ message, type }) {
return ( return (
@@ -10,17 +10,17 @@ function Notification({ message, type }) {
animate={{ y: 0, opacity: 1 }} animate={{ y: 0, opacity: 1 }}
exit={{ y: 15, opacity: 0 }} exit={{ y: 15, opacity: 0 }}
className={clsx( className={clsx(
"p-2 pl-8 mb-8 font-body text-lg border-2 rounded-3xl flex items-center gap-2", 'p-2 pl-8 mb-8 font-body text-lg border-2 rounded-3xl flex items-center gap-2',
type === "error" type === 'error'
? "bg-error-surface text-white border-error" ? 'bg-error-surface text-white border-error'
: type === "success" : type === 'success'
? "bg-success text-white border-green-700" ? 'bg-success text-white border-green-700'
: type === "warning" : type === 'warning'
? "bg-warning-surface text-white border-warning" ? 'bg-warning-surface text-white border-warning'
: "" : ''
)} )}
> >
{message.split(":").map((msg, index) => { {message.split(':').map((msg, index) => {
return index === 1 ? ( return index === 1 ? (
<span key={index} className="border-b border-dashed"> <span key={index} className="border-b border-dashed">
{msg} {msg}
@@ -29,11 +29,11 @@ function Notification({ message, type }) {
<span key={index}>{msg}</span> <span key={index}>{msg}</span>
); );
})} })}
{message.split(":")[1] && ( {message.split(':')[1] && (
<Copy <Copy
cursor={"pointer"} cursor={'pointer'}
size={15} size={15}
onClick={navigator.clipboard.writeText(message.split(":")[1].trim())} onClick={navigator.clipboard.writeText(message.split(':')[1].trim())}
/> />
)} )}
</motion.div> </motion.div>

View File

@@ -1,5 +1,5 @@
import clsx from "clsx"; import clsx from 'clsx';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
function ProductListTable({ productInfo, onSelectProduct }) { function ProductListTable({ productInfo, onSelectProduct }) {
return ( return (
@@ -29,32 +29,32 @@ function ProductListTable({ productInfo, onSelectProduct }) {
> >
<td <td
className={clsx( className={clsx(
"border border-l-2 border-primary p-2", 'border border-l-2 border-primary p-2',
idx === productInfo.length - 1 && "rounded-bl-2xl border-b-2" idx === productInfo.length - 1 && 'rounded-bl-2xl border-b-2'
)} )}
> >
{prod.productCode} {prod.productCode}
</td> </td>
<td <td
className={clsx( className={clsx(
"border border-primary p-2", 'border border-primary p-2',
idx === productInfo.length - 1 && "border-b-2" idx === productInfo.length - 1 && 'border-b-2'
)} )}
> >
{prod.productCodeDescription} {prod.productCodeDescription}
</td> </td>
<td <td
className={clsx( className={clsx(
"border border-primary p-2", 'border border-primary p-2',
idx === productInfo.length - 1 && "border-b-2" idx === productInfo.length - 1 && 'border-b-2'
)} )}
> >
{prod.interestCategory} {prod.interestCategory}
</td> </td>
<td <td
className={clsx( className={clsx(
"border border-r-2 border-primary p-2", 'border border-r-2 border-primary p-2',
idx === productInfo.length - 1 && "rounded-br-2xl border-b-2" idx === productInfo.length - 1 && 'rounded-br-2xl border-b-2'
)} )}
> >
{prod.interestCategoryDescription} {prod.interestCategoryDescription}

View File

@@ -1,6 +1,6 @@
import { motion } from "motion/react"; import { motion } from 'motion/react';
import ProductListTable from "./ProductListTable"; import ProductListTable from './ProductListTable';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
function ProductModal({ productInfo, handleProductSelect }) { function ProductModal({ productInfo, handleProductSelect }) {
return ( return (
@@ -18,10 +18,7 @@ function ProductModal({ productInfo, handleProductSelect }) {
className="flex flex-col items-center bg-white p-4 py-8 rounded-3xl w-[60%] max-h-[80%] overflow-auto font-body" className="flex flex-col items-center bg-white p-4 py-8 rounded-3xl w-[60%] max-h-[80%] overflow-auto font-body"
> >
<h2 className="text-xl mb-4">Select Product</h2> <h2 className="text-xl mb-4">Select Product</h2>
<ProductListTable <ProductListTable productInfo={productInfo} onSelectProduct={handleProductSelect} />
productInfo={productInfo}
onSelectProduct={handleProductSelect}
/>
</motion.div> </motion.div>
</motion.div> </motion.div>
); );

View File

@@ -3,7 +3,7 @@ function Separator() {
<div className="h-[2px]"> <div className="h-[2px]">
<div className="w-full h-full bg-white rounded-md dark:bg-primary-dark"></div> <div className="w-full h-full bg-white rounded-md dark:bg-primary-dark"></div>
</div> </div>
) );
} }
export default Separator; export default Separator;

View File

@@ -16,4 +16,3 @@ export function LoadingProvider({ children }) {
LoadingProvider.propTypes = { LoadingProvider.propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
}; };

View File

@@ -1,22 +1,22 @@
import { createContext, useState } from "react"; import { createContext, useState } from 'react';
import { CircleAlert, X, CircleX, Check } from "lucide-react"; import { CircleAlert, X, CircleX, Check } from 'lucide-react';
import { toTitleCase } from "../util/util"; import { toTitleCase } from '../util/util';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
export const ToastContext = createContext(); export const ToastContext = createContext();
export const ToastProvider = ({ children }) => { export const ToastProvider = ({ children }) => {
const [toast, setToast] = useState({ show: false, message: "", type: "" }); const [toast, setToast] = useState({ show: false, message: '', type: '' });
const playAudio = (type) => { const playAudio = (type) => {
let audioSrc; let audioSrc;
if(type === "warning") audioSrc = "/audio/warning.mp3"; if (type === 'warning') audioSrc = '/audio/warning.mp3';
else if (type === "error") audioSrc = "/audio/error.mp3"; else if (type === 'error') audioSrc = '/audio/error.mp3';
if (audioSrc) { if (audioSrc) {
const audio = new Audio(audioSrc); const audio = new Audio(audioSrc);
audio.play().catch((error) => console.error("Error playing audio:", error)); audio.play().catch((error) => console.error('Error playing audio:', error));
} }
}; };
@@ -24,28 +24,28 @@ export const ToastProvider = ({ children }) => {
playAudio(type); playAudio(type);
setToast({ show: true, message, type }); setToast({ show: true, message, type });
setTimeout(() => { setTimeout(() => {
setToast({ show: false, message: "", type: "" }); setToast({ show: false, message: '', type: '' });
}, 7000); }, 7000);
}; };
let toastIcon; let toastIcon;
let surfaceColor; let surfaceColor;
let borderColor; let borderColor;
if(toast.type === "warning") { if (toast.type === 'warning') {
toastIcon = <CircleAlert size={30} fill="#EA7000" stroke="#FDF1E5" />; toastIcon = <CircleAlert size={30} fill="#EA7000" stroke="#FDF1E5" />;
surfaceColor = "bg-warning-surface"; surfaceColor = 'bg-warning-surface';
borderColor = "border-warning"; borderColor = 'border-warning';
} else if(toast.type === "success") { } else if (toast.type === 'success') {
toastIcon = <Check size={30} color="green"/>; toastIcon = <Check size={30} color="green" />;
surfaceColor = "bg-success-surface"; surfaceColor = 'bg-success-surface';
borderColor = "border-success"; borderColor = 'border-success';
} else if (toast.type === "error") { } else if (toast.type === 'error') {
toastIcon = <CircleX size={30} fill="#E5254B" stroke="#FCE9ED" />; toastIcon = <CircleX size={30} fill="#E5254B" stroke="#FCE9ED" />;
surfaceColor = "bg-error-surface"; surfaceColor = 'bg-error-surface';
borderColor = "border-error"; borderColor = 'border-error';
} }
return ( return (
<ToastContext.Provider value={ showToast }> <ToastContext.Provider value={showToast}>
{children} {children}
{toast.show && ( {toast.show && (
<div <div
@@ -57,7 +57,7 @@ export const ToastProvider = ({ children }) => {
<div className="text-lg text-onToast">{toTitleCase(toast.type)}</div> <div className="text-lg text-onToast">{toTitleCase(toast.type)}</div>
<div className="text-sm font-body">{toast.message}</div> <div className="text-sm font-body">{toast.message}</div>
</div> </div>
<X onClick={() => setToast({ show: false, message: "", type: "" })}/> <X onClick={() => setToast({ show: false, message: '', type: '' })} />
</div> </div>
)} )}
</ToastContext.Provider> </ToastContext.Provider>

View File

@@ -1,4 +1,4 @@
import { useContext } from "react"; import { useContext } from 'react';
import { LoadingContext } from "../contexts/Loading"; import { LoadingContext } from '../contexts/Loading';
export const useLoading = () => useContext(LoadingContext); export const useLoading = () => useContext(LoadingContext);

View File

@@ -1,4 +1,4 @@
import { useContext } from "react"; import { useContext } from 'react';
import { ToastContext } from "../contexts/Toast"; import { ToastContext } from '../contexts/Toast';
export const useToast = () => useContext(ToastContext); export const useToast = () => useContext(ToastContext);

View File

@@ -1,25 +1,25 @@
import { StrictMode } from "react"; import { StrictMode } from 'react';
import { createRoot } from "react-dom/client"; import { createRoot } from 'react-dom/client';
import App from "./App.jsx"; import App from './App.jsx';
import "./index.css"; import './index.css';
import "./i18n"; import './i18n';
import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Home from "./pages/Home.jsx"; import Home from './pages/Home.jsx';
import CabinetMaintenace from "./pages/CabinetMaintenance.jsx"; import CabinetMaintenace from './pages/CabinetMaintenance.jsx';
import CabinetCreation from "./pages/CabinetCreation.jsx"; import CabinetCreation from './pages/CabinetCreation.jsx';
import LockersRegistration from "./pages/LockersRegistration.jsx"; import LockersRegistration from './pages/LockersRegistration.jsx';
import AccountCreation from "./pages/AccountCreation.jsx"; import AccountCreation from './pages/AccountCreation.jsx';
import LockerMaintenance from "./pages/LockerMaintenance.jsx"; import LockerMaintenance from './pages/LockerMaintenance.jsx';
import LockerStatus from "./pages/LockerStatus.jsx"; import LockerStatus from './pages/LockerStatus.jsx';
import KeySwap from "./pages/KeySwap.jsx"; import KeySwap from './pages/KeySwap.jsx';
import ChargeManagement from "./pages/ChargeManagement.jsx"; import ChargeManagement from './pages/ChargeManagement.jsx';
import ChargeEdit from "./pages/ChargeEdit.jsx"; import ChargeEdit from './pages/ChargeEdit.jsx';
import CheckInOutManagement from "./pages/CheckInOutManagement.jsx"; import CheckInOutManagement from './pages/CheckInOutManagement.jsx';
import CheckInOutLog from "./pages/CheckInOutLog.jsx"; import CheckInOutLog from './pages/CheckInOutLog.jsx';
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
path: "/", path: '/',
element: <App />, element: <App />,
children: [ children: [
{ {
@@ -27,54 +27,54 @@ const router = createBrowserRouter([
element: <Home />, element: <Home />,
}, },
{ {
path: "operation/cabinet", path: 'operation/cabinet',
element: <CabinetMaintenace />, element: <CabinetMaintenace />,
}, },
{ {
path: "operation/cabinet/create", path: 'operation/cabinet/create',
element: <CabinetCreation />, element: <CabinetCreation />,
}, },
{ {
path: "operation/cabinet/create/register-lockers", path: 'operation/cabinet/create/register-lockers',
element: <LockersRegistration />, element: <LockersRegistration />,
}, },
{ {
path: "operation/account", path: 'operation/account',
element: <AccountCreation />, element: <AccountCreation />,
}, },
{ {
path: "operation/locker", path: 'operation/locker',
element: <LockerMaintenance />, element: <LockerMaintenance />,
}, },
{ {
path: "operation/locker/status", path: 'operation/locker/status',
element: <LockerStatus />, element: <LockerStatus />,
}, },
{ {
path: "operation/locker/key-swap", path: 'operation/locker/key-swap',
element: <KeySwap />, element: <KeySwap />,
}, },
{ {
path: "operation/charge-management", path: 'operation/charge-management',
element: <ChargeManagement />, element: <ChargeManagement />,
}, },
{ {
path: "operation/charge-management/change", path: 'operation/charge-management/change',
element: <ChargeEdit />, element: <ChargeEdit />,
}, },
{ {
path: "operation/check-in-out", path: 'operation/check-in-out',
element: <CheckInOutManagement /> element: <CheckInOutManagement />,
}, },
{ {
path: "operation/check-in-out/log", path: 'operation/check-in-out/log',
element: <CheckInOutLog /> element: <CheckInOutLog />,
} },
], ],
}, },
]); ]);
createRoot(document.getElementById("root")).render( createRoot(document.getElementById('root')).render(
<StrictMode> <StrictMode>
<RouterProvider router={router} /> <RouterProvider router={router} />
</StrictMode> </StrictMode>

View File

@@ -1,33 +1,33 @@
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import { PackageSearch, UserSearch } from "lucide-react"; import { PackageSearch, UserSearch } from 'lucide-react';
import { useState } from "react"; import { useState } from 'react';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import Button from "../components/Button"; import Button from '../components/Button';
import productInfo from "../util/productList"; import productInfo from '../util/productList';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import ProductModal from "../components/ProductModal"; import ProductModal from '../components/ProductModal';
import FormHeader from "../components/FormHeader"; import FormHeader from '../components/FormHeader';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function AccountCreation() { function AccountCreation() {
const { t } = useTranslation(); const { t } = useTranslation();
const [notification] = useState({ message: "", type: "" }); const [notification] = useState({ message: '', type: '' });
const [showProductModal, setShowProductModal] = useState(false); const [showProductModal, setShowProductModal] = useState(false);
const [accountDetails, setAccountDetails] = useState({ const [accountDetails, setAccountDetails] = useState({
productCode: "", productCode: '',
interestCategory: "", interestCategory: '',
segmentCode: "", segmentCode: '',
accountHolderType: "", accountHolderType: '',
primaryCifNumber: "", primaryCifNumber: '',
nomineeCifNumber: "", nomineeCifNumber: '',
activityCode: "", activityCode: '',
customerType: "", customerType: '',
collateralFDAccount: "", collateralFDAccount: '',
rentPayAccount: "", rentPayAccount: '',
productCodeValid: true, productCodeValid: true,
interestCategoryValid: true, interestCategoryValid: true,
segmentCodeValid: true, segmentCodeValid: true,
@@ -52,107 +52,107 @@ function AccountCreation() {
const accountDetailsFields = [ const accountDetailsFields = [
{ {
label: t("productCode"), label: t('productCode'),
name: "productCode", name: 'productCode',
type: "input", type: 'input',
subType: "number", subType: 'number',
readOnly: true, readOnly: true,
validate: (value) => value !== "", validate: (value) => value !== '',
icon: { icon: {
icon: <PackageSearch size={18} />, icon: <PackageSearch size={18} />,
onClick: () => setShowProductModal(true), onClick: () => setShowProductModal(true),
}, },
}, },
{ {
label: t("interestCategory"), label: t('interestCategory'),
name: "interestCategory", name: 'interestCategory',
type: "input", type: 'input',
subType: "number", subType: 'number',
readOnly: true, readOnly: true,
validate: (value) => value !== "", validate: (value) => value !== '',
}, },
{ {
label: t("segmentCode"), label: t('segmentCode'),
name: "segmentCode", name: 'segmentCode',
type: "select", type: 'select',
options: [ options: [
{ value: "0706", label: "0706: Individual" }, { value: '0706', label: '0706: Individual' },
{ value: "0306", label: "0306: Staff" }, { value: '0306', label: '0306: Staff' },
{ value: "5003", label: "5003: Senior Citizen" }, { value: '5003', label: '5003: Senior Citizen' },
{ value: "5010", label: "5010: SHG" }, { value: '5010', label: '5010: SHG' },
{ value: "5000", label: "5000: Bank" }, { value: '5000', label: '5000: Bank' },
{ value: "5009", label: "5009: Institutions" }, { value: '5009', label: '5009: Institutions' },
{ value: "5050", label: "5050: Others" }, { value: '5050', label: '5050: Others' },
{ value: "5007", label: "5007: Society" }, { value: '5007', label: '5007: Society' },
], ],
validate: (value) => value !== "", validate: (value) => value !== '',
}, },
{ {
label: t("accountHolderType"), label: t('accountHolderType'),
name: "accountHolderType", name: 'accountHolderType',
type: "select", type: 'select',
options: [ options: [
{ value: "1", label: "Single" }, { value: '1', label: 'Single' },
{ value: "2", label: "Joint" }, { value: '2', label: 'Joint' },
], ],
validate: (value) => value === "1" || value === "2", validate: (value) => value === '1' || value === '2',
}, },
{ {
label: t("primaryCifNumber"), label: t('primaryCifNumber'),
name: "primaryCifNumber", name: 'primaryCifNumber',
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 17, maxLength: 17,
validate: (value) => /^[0-9]{17}$/.test(value), validate: (value) => /^[0-9]{17}$/.test(value),
icon: { icon: <UserSearch size={18} /> }, icon: { icon: <UserSearch size={18} /> },
}, },
{ {
label: t("nomineeCifNumber"), label: t('nomineeCifNumber'),
name: "nomineeCifNumber", name: 'nomineeCifNumber',
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 17, maxLength: 17,
validate: (value) => /^[0-9]{17}$/.test(value), validate: (value) => /^[0-9]{17}$/.test(value),
}, },
]; ];
const additionalDetailsFields = [ const additionalDetailsFields = [
{ {
label: t("activityCode"), label: t('activityCode'),
name: "activityCode", name: 'activityCode',
type: "select", type: 'select',
options: [ options: [
{ value: "0701", label: "Direct Agriculture" }, { value: '0701', label: 'Direct Agriculture' },
{ value: "0702", label: "Indirect Agriculture" }, { value: '0702', label: 'Indirect Agriculture' },
{ value: "0703", label: "Agricultural Services Unit" }, { value: '0703', label: 'Agricultural Services Unit' },
{ value: "0704", label: "Farm Irrigation" }, { value: '0704', label: 'Farm Irrigation' },
{ value: "0705", label: "Fruits & Vegetables" }, { value: '0705', label: 'Fruits & Vegetables' },
{ value: "0706", label: "Non-Agriculture" }, { value: '0706', label: 'Non-Agriculture' },
], ],
validate: (value) => value !== "", validate: (value) => value !== '',
}, },
{ {
label: t("customerType"), label: t('customerType'),
name: "customerType", name: 'customerType',
type: "select", type: 'select',
options: [ options: [
{ value: "0709", label: "Individual" }, { value: '0709', label: 'Individual' },
{ value: "0701", label: "Corporate" }, { value: '0701', label: 'Corporate' },
], ],
validate: (value) => value === "0709" || value === "0701", validate: (value) => value === '0709' || value === '0701',
}, },
{ {
label: t("collateralFDAccount"), label: t('collateralFDAccount'),
name: "collateralFDAccount", name: 'collateralFDAccount',
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 17, maxLength: 17,
validate: (value) => /^[0-9]{17}$/.test(value), validate: (value) => /^[0-9]{17}$/.test(value),
}, },
{ {
label: t("rentPayAccount"), label: t('rentPayAccount'),
name: "rentPayAccount", name: 'rentPayAccount',
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 17, maxLength: 17,
validate: (value) => /^[0-9]{17}$/.test(value), validate: (value) => /^[0-9]{17}$/.test(value),
}, },
@@ -177,7 +177,7 @@ function AccountCreation() {
if (!isValid) { if (!isValid) {
return; return;
} }
console.log("Form is valid", accountDetails); console.log('Form is valid', accountDetails);
}; };
const renderField = (field) => { const renderField = (field) => {
@@ -197,14 +197,10 @@ function AccountCreation() {
return ( return (
<FormField key={field.name} label={field.label} icon={field.icon}> <FormField key={field.name} label={field.label} icon={field.icon}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} valid={valid} /> <FormInput props={commonProps} valid={valid} />
) : ( ) : (
<FormSelect <FormSelect props={commonProps} valid={valid} options={field.options} />
props={commonProps}
valid={valid}
options={field.options}
/>
)} )}
</FormField> </FormField>
); );
@@ -213,26 +209,23 @@ function AccountCreation() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<AnimatePresence> <AnimatePresence>
{showProductModal && ( {showProductModal && (
<ProductModal <ProductModal productInfo={productInfo} handleProductSelect={handleProductSelect} />
productInfo={productInfo}
handleProductSelect={handleProductSelect}
/>
)} )}
</AnimatePresence> </AnimatePresence>
<FormBox title="Account Creation"> <FormBox title="Account Creation">
<FieldsWrapper> <FieldsWrapper>
<FormHeader text={"Account Details"} /> <FormHeader text={'Account Details'} />
{accountDetailsFields.map(renderField)} {accountDetailsFields.map(renderField)}
<FormHeader text={"Additional Details"} /> <FormHeader text={'Additional Details'} />
{additionalDetailsFields.map(renderField)} {additionalDetailsFields.map(renderField)}
</FieldsWrapper> </FieldsWrapper>
<Button text={t("submit")} onClick={handleSubmit} /> <Button text={t('submit')} onClick={handleSubmit} />
</FormBox> </FormBox>
</div> </div>
); );

View File

@@ -1,21 +1,21 @@
import { useState } from "react"; import { useState } from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Button from "../components/Button"; import Button from '../components/Button';
import { useNavigate } from "react-router-dom"; import { useNavigate } from 'react-router-dom';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
function CabinetCreation() { function CabinetCreation() {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const [cabinetDetails, setCabinetDetails] = useState({ const [cabinetDetails, setCabinetDetails] = useState({
cabinetId: "", cabinetId: '',
cabinetIdValid: true, cabinetIdValid: true,
cabinetKeyId: "", cabinetKeyId: '',
cabinetKeyIdValid: true, cabinetKeyIdValid: true,
noOfLockers: 0, noOfLockers: 0,
noOfLockersValid: true, noOfLockersValid: true,
@@ -24,21 +24,21 @@ function CabinetCreation() {
const handleNext = (e) => { const handleNext = (e) => {
e.preventDefault(); e.preventDefault();
let isFormValid = true; let isFormValid = true;
const newValues = {...cabinetDetails}; const newValues = { ...cabinetDetails };
formFields.forEach(field => { formFields.forEach((field) => {
if(field.validate) { if (field.validate) {
const isFieldValid = field.validate(cabinetDetails[field.name]) const isFieldValid = field.validate(cabinetDetails[field.name]);
newValues[`${field.name}Valid`] = isFieldValid; newValues[`${field.name}Valid`] = isFieldValid;
if(!isFieldValid) isFormValid = false; if (!isFieldValid) isFormValid = false;
} }
}); });
if(!isFormValid) { if (!isFormValid) {
setCabinetDetails(newValues); setCabinetDetails(newValues);
return; return;
} }
navigate("register-lockers", { navigate('register-lockers', {
state: { state: {
cabinetId: cabinetDetails.cabinetId, cabinetId: cabinetDetails.cabinetId,
cabinetKeyId: cabinetDetails.cabinetKeyId, cabinetKeyId: cabinetDetails.cabinetKeyId,
@@ -49,25 +49,25 @@ function CabinetCreation() {
const formFields = [ const formFields = [
{ {
name: "cabinetId", name: 'cabinetId',
label: t("cabinetId"), label: t('cabinetId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
validate: v => /^\w{2}\d{4}$/.test(v) validate: (v) => /^\w{2}\d{4}$/.test(v),
}, },
{ {
name: "cabinetKeyId", name: 'cabinetKeyId',
label: t("cabinetKeyId"), label: t('cabinetKeyId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
validate: v => /^\w{2}\d{4}$/.test(v) validate: (v) => /^\w{2}\d{4}$/.test(v),
}, },
{ {
name: "noOfLockers", name: 'noOfLockers',
label: t("noOfLockers"), label: t('noOfLockers'),
type: "input", type: 'input',
subType: "number", subType: 'number',
validate: v => parseInt(v) > 0 validate: (v) => parseInt(v) > 0,
}, },
]; ];
@@ -87,24 +87,18 @@ function CabinetCreation() {
return ( return (
<FormField key={field.name} label={field.label}> <FormField key={field.name} label={field.label}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} valid={valid} /> <FormInput props={commonProps} valid={valid} />
) : ( ) : (
<FormSelect <FormSelect props={commonProps} valid={valid} options={field.options} />
props={commonProps}
valid={valid}
options={field.options}
/>
)} )}
</FormField> </FormField>
); );
}; };
return ( return (
<FormBox title={t("cabinetCreation")}> <FormBox title={t('cabinetCreation')}>
<FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
{formFields.map(renderField)}
</FieldsWrapper>
<Button text={t('next')} onClick={handleNext} /> <Button text={t('next')} onClick={handleNext} />
</FormBox> </FormBox>
); );

View File

@@ -1,21 +1,21 @@
import { useState } from "react"; import { useState } from 'react';
import { useNavigate } from "react-router-dom"; import { useNavigate } from 'react-router-dom';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Button from "../components/Button"; import Button from '../components/Button';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
function CabinetMaintenace() { function CabinetMaintenace() {
const navigate = useNavigate(); const navigate = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const [operation, setOperation] = useState({ value: "", valid: true }); const [operation, setOperation] = useState({ value: '', valid: true });
const handleNext = (e) => { const handleNext = (e) => {
e.preventDefault(); e.preventDefault();
if (operation.value === "") { if (operation.value === '') {
setOperation({ value: operation.value, valid: false }); setOperation({ value: operation.value, valid: false });
} }
navigate(operation.value); navigate(operation.value);
@@ -23,10 +23,10 @@ function CabinetMaintenace() {
const formFields = [ const formFields = [
{ {
name: "value", name: 'value',
label: t("operation"), label: t('operation'),
options: [{ label: t("create"), value: "create" }], options: [{ label: t('create'), value: 'create' }],
type: "select", type: 'select',
}, },
]; ];
@@ -43,7 +43,7 @@ function CabinetMaintenace() {
const options = field.options; const options = field.options;
return ( return (
<FormField label={field.label}> <FormField label={field.label}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} /> <FormInput props={commonProps} />
) : ( ) : (
<FormSelect props={commonProps} options={options} /> <FormSelect props={commonProps} options={options} />
@@ -54,9 +54,9 @@ function CabinetMaintenace() {
return ( return (
<div> <div>
<FormBox title={t("cabinetMaintenance")}> <FormBox title={t('cabinetMaintenance')}>
<FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
<Button text={t("next")} onClick={(e) => handleNext(e)} /> <Button text={t('next')} onClick={(e) => handleNext(e)} />
</FormBox> </FormBox>
</div> </div>
); );

View File

@@ -1,27 +1,27 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from 'react';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import Button from "../components/Button"; import Button from '../components/Button';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { useLocation } from "react-router-dom"; import { useLocation } from 'react-router-dom';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import { Pencil } from "lucide-react"; import { Pencil } from 'lucide-react';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function ChargeEdit() { function ChargeEdit() {
const [chargeDetails, setChargeDetails] = useState({ const [chargeDetails, setChargeDetails] = useState({
rentAmount: "", rentAmount: '',
rentAmountEdit: false, rentAmountEdit: false,
penaltyAmount: "", penaltyAmount: '',
penaltyAmountEdit: false, penaltyAmountEdit: false,
}); });
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const { setIsLoading } = useLoading(); const { setIsLoading } = useLoading();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -33,10 +33,7 @@ function ChargeEdit() {
const fetchCharges = async () => { const fetchCharges = async () => {
try { try {
setIsLoading(true); setIsLoading(true);
const response = await lockerService.getCharges( const response = await lockerService.getCharges(productCode, interestCategory);
productCode,
interestCategory
);
if (response.status === 200) { if (response.status === 200) {
const { rent, penalty } = response.data; const { rent, penalty } = response.data;
setChargeDetails({ setChargeDetails({
@@ -48,14 +45,14 @@ function ChargeEdit() {
} else { } else {
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "error", type: 'error',
}); });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setNotification({ setNotification({
message: error.message, message: error.message,
type: "error", type: 'error',
}); });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
@@ -70,28 +67,28 @@ function ChargeEdit() {
const formFields = [ const formFields = [
{ {
name: "rentAmount", name: 'rentAmount',
label: "Rent Amount", label: 'Rent Amount',
type: "input", type: 'input',
subType: "number", subType: 'number',
readOnly: !chargeDetails.rentAmountEdit, readOnly: !chargeDetails.rentAmountEdit,
icon: { icon: {
icon: <Pencil size={22} />, icon: <Pencil size={22} />,
mode: "plain", mode: 'plain',
onClick: () => { onClick: () => {
setChargeDetails({ ...chargeDetails, rentAmountEdit: true }); setChargeDetails({ ...chargeDetails, rentAmountEdit: true });
}, },
}, },
}, },
{ {
name: "penaltyAmount", name: 'penaltyAmount',
label: "Penalty Amount", label: 'Penalty Amount',
type: "input", type: 'input',
subType: "number", subType: 'number',
readOnly: !chargeDetails.penaltyAmountEdit, readOnly: !chargeDetails.penaltyAmountEdit,
icon: { icon: {
icon: <Pencil size={22} />, icon: <Pencil size={22} />,
mode: "plain", mode: 'plain',
onClick: () => { onClick: () => {
setChargeDetails({ ...chargeDetails, penaltyAmountEdit: true }); setChargeDetails({ ...chargeDetails, penaltyAmountEdit: true });
}, },
@@ -113,19 +110,19 @@ function ChargeEdit() {
if (response.status === 200) { if (response.status === 200) {
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "success", type: 'success',
}); });
} else { } else {
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "error", type: 'error',
}); });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setNotification({ setNotification({
message: error.message, message: error.message,
type: "error", type: 'error',
}); });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
@@ -145,17 +142,13 @@ function ChargeEdit() {
type: field.subType, type: field.subType,
}; };
const className = field.readOnly ? "bg-grey/[0.3]" : ""; const className = field.readOnly ? 'bg-grey/[0.3]' : '';
return ( return (
<FormField key={field.name} label={field.label} icon={field.icon}> <FormField key={field.name} label={field.label} icon={field.icon}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} className={className} /> <FormInput props={commonProps} className={className} />
) : ( ) : (
<FormSelect <FormSelect props={commonProps} options={field.options} className={className} />
props={commonProps}
options={field.options}
className={className}
/>
)} )}
</FormField> </FormField>
); );
@@ -164,17 +157,15 @@ function ChargeEdit() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<FormBox title={t("chargeEdit")}> <FormBox title={t('chargeEdit')}>
<FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
<Button <Button
text={t("submit")} text={t('submit')}
onClick={handleSubmit} onClick={handleSubmit}
disabled={ disabled={!chargeDetails.rentAmountEdit && !chargeDetails.penaltyAmountEdit}
!chargeDetails.rentAmountEdit && !chargeDetails.penaltyAmountEdit
}
/> />
</FormBox> </FormBox>
</div> </div>

View File

@@ -1,13 +1,13 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import Button from "../components/Button"; import Button from '../components/Button';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import { useNavigate } from "react-router-dom"; import { useNavigate } from 'react-router-dom';
import { useState } from "react"; import { useState } from 'react';
import { useToast } from "../hooks/useToast"; import { useToast } from '../hooks/useToast';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function ChargeManagement() { function ChargeManagement() {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -15,26 +15,26 @@ function ChargeManagement() {
const showToast = useToast(); const showToast = useToast();
const [productDetails, setProductDetails] = useState({ const [productDetails, setProductDetails] = useState({
productCode: "", productCode: '',
interestCategory: "", interestCategory: '',
productCodeValid: true, productCodeValid: true,
interestCategoryValid: true, interestCategoryValid: true,
}); });
const formFields = [ const formFields = [
{ {
name: "productCode", name: 'productCode',
label: t("productCode"), label: t('productCode'),
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 4, maxLength: 4,
validate: (value) => /^[0-9]{4}/.test(value), validate: (value) => /^[0-9]{4}/.test(value),
}, },
{ {
name: "interestCategory", name: 'interestCategory',
label: t("interestCategory"), label: t('interestCategory'),
type: "input", type: 'input',
subType: "number", subType: 'number',
maxLength: 4, maxLength: 4,
validate: (value) => /^[0-9]{4}/.test(value), validate: (value) => /^[0-9]{4}/.test(value),
}, },
@@ -54,11 +54,11 @@ function ChargeManagement() {
if (!isValid) { if (!isValid) {
setProductDetails(newProductDetails); setProductDetails(newProductDetails);
showToast(t("highlightedFieldsInvalid"), "error"); showToast(t('highlightedFieldsInvalid'), 'error');
return; return;
} }
navigate("change", { navigate('change', {
state: { state: {
productCode: productDetails.productCode, productCode: productDetails.productCode,
interestCategory: productDetails.interestCategory, interestCategory: productDetails.interestCategory,
@@ -71,8 +71,8 @@ function ChargeManagement() {
value: productDetails[field.name], value: productDetails[field.name],
onChange: (e) => { onChange: (e) => {
const newLockerDetails = { ...productDetails }; const newLockerDetails = { ...productDetails };
if (field.subType === "number") { if (field.subType === 'number') {
e.target.value = e.target.value.replace(/\D/g, ""); e.target.value = e.target.value.replace(/\D/g, '');
if (e.target.value.length > field.maxLength) { if (e.target.value.length > field.maxLength) {
return; return;
} }
@@ -89,11 +89,8 @@ function ChargeManagement() {
const valid = productDetails[`${field.name}Valid`]; const valid = productDetails[`${field.name}Valid`];
return ( return (
<FormField key={field.name} label={field.label} icon={field.icon}> <FormField key={field.name} label={field.label} icon={field.icon}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput <FormInput props={commonProps} valid={valid} />
props={commonProps}
valid={valid}
/>
) : ( ) : (
<FormSelect props={commonProps} valid={valid} options={field.options} /> <FormSelect props={commonProps} valid={valid} options={field.options} />
)} )}
@@ -102,11 +99,9 @@ function ChargeManagement() {
}; };
return ( return (
<FormBox title={t("chargeManagement")}> <FormBox title={t('chargeManagement')}>
<FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
{formFields.map(renderField)} <Button text={t('submit')} onClick={handleSubmit} />
</FieldsWrapper>
<Button text={t("submit")} onClick={handleSubmit} />
</FormBox> </FormBox>
); );
} }

View File

@@ -1,16 +1,16 @@
import { useState } from "react"; import { useState } from 'react';
import { useLocation } from "react-router-dom"; import { useLocation } from 'react-router-dom';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Button from "../components/Button"; import Button from '../components/Button';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import { useToast } from "../hooks/useToast"; import { useToast } from '../hooks/useToast';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
function CheckInOutLog() { function CheckInOutLog() {
const [time, setTime] = useState(null); const [time, setTime] = useState(null);
const [checkType, setCheckType] = useState(""); const [checkType, setCheckType] = useState('');
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const location = useLocation(); const location = useLocation();
const showToast = useToast(); const showToast = useToast();
@@ -19,27 +19,23 @@ function CheckInOutLog() {
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
if (time === null || checkType === "") { if (time === null || checkType === '') {
showToast("Please fill in all fields", "error"); showToast('Please fill in all fields', 'error');
return; return;
} }
// Add your logic here // Add your logic here
try { try {
setIsLoading(true); setIsLoading(true);
const response = await lockerService.checkInOut( const response = await lockerService.checkInOut(accountNumber, time, checkType);
accountNumber,
time,
checkType
);
if (response.status === 200) { if (response.status === 200) {
setNotification({ message: response.data.message, type: "success" }); setNotification({ message: response.data.message, type: 'success' });
} else { } else {
console.log(response); console.log(response);
setNotification({ message: response.data.message, type: "error" }); setNotification({ message: response.data.message, type: 'error' });
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
setNotification({ message: error.message, type: "error" }); setNotification({ message: error.message, type: 'error' });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -47,16 +43,14 @@ function CheckInOutLog() {
return ( return (
<div> <div>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
<FormBox title="Check In/Out Log"> <FormBox title="Check In/Out Log">
<div className="px-4 pt-7 text-2xl font-display font-bold text-primary dark:text-primary-dark"> <div className="px-4 pt-7 text-2xl font-display font-bold text-primary dark:text-primary-dark">
{accountNumber} {accountNumber}
</div> </div>
<div className="p-2 pt-7 flex flex-col gap-4"> <div className="p-2 pt-7 flex flex-col gap-4">
<div className="flex"> <div className="flex">
<label className="mr-4 text-lg text-black dark:text-primary-dark w-[10%]"> <label className="mr-4 text-lg text-black dark:text-primary-dark w-[10%]">Time</label>
Time
</label>
<input <input
type="time" type="time"
className="w-1/5 h-10 px-2 rounded-full dark:bg-grey dark:text-primary-dark border-2 focus:outline-grey border-grey text-black" className="w-1/5 h-10 px-2 rounded-full dark:bg-grey dark:text-primary-dark border-2 focus:outline-grey border-grey text-black"

View File

@@ -1,20 +1,20 @@
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import { useState } from "react"; import { useState } from 'react';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import { Search } from "lucide-react"; import { Search } from 'lucide-react';
import Button from "../components/Button"; import Button from '../components/Button';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import { useToast } from "../hooks/useToast"; import { useToast } from '../hooks/useToast';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
import { useNavigate } from "react-router-dom"; import { useNavigate } from 'react-router-dom';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function CheckInOutManagement() { function CheckInOutManagement() {
const [accountNumber, setAccountNumber] = useState(""); const [accountNumber, setAccountNumber] = useState('');
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const showToast = useToast(); const showToast = useToast();
const { setIsLoading } = useLoading(); const { setIsLoading } = useLoading();
@@ -22,8 +22,8 @@ function CheckInOutManagement() {
const handleNext = async (e) => { const handleNext = async (e) => {
e.preventDefault(); e.preventDefault();
if (accountNumber === "") { if (accountNumber === '') {
showToast("Account Number is required", "error"); showToast('Account Number is required', 'error');
return; return;
} }
try { try {
@@ -33,26 +33,26 @@ function CheckInOutManagement() {
if (response.status === 200) { if (response.status === 200) {
const data = response.data; const data = response.data;
if (data.code === 1) { if (data.code === 1) {
navigate("log", { state: { accountNumber } }); navigate('log', { state: { accountNumber } });
} else if (data.code === 2) { } else if (data.code === 2) {
setNotification({ setNotification({
visible: true, visible: true,
message: message:
"Monthly access limit exceeded. A fine will be charged for each additional access.", 'Monthly access limit exceeded. A fine will be charged for each additional access.',
type: "warning", type: 'warning',
}); });
} else if (data.code === 3) { } else if (data.code === 3) {
setNotification({ setNotification({
visible: true, visible: true,
message: message:
"Rent for this account is due. Please pay the rent amount in full to access the locker.", 'Rent for this account is due. Please pay the rent amount in full to access the locker.',
type: "error", type: 'error',
}); });
} }
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
setNotification(error.message, "error"); setNotification(error.message, 'error');
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -60,7 +60,7 @@ function CheckInOutManagement() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{ notification.message !== "" && <Notification {...notification} /> } {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<FormBox title="Check In/Out"> <FormBox title="Check In/Out">
<FieldsWrapper> <FieldsWrapper>
@@ -70,7 +70,7 @@ function CheckInOutManagement() {
> >
<FormInput <FormInput
props={{ props={{
type: "text", type: 'text',
value: accountNumber, value: accountNumber,
onChange: (e) => setAccountNumber(e.target.value), onChange: (e) => setAccountNumber(e.target.value),
}} }}

View File

@@ -1,11 +1,20 @@
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { getUserInfoFromSession } from "../util/util"; import { getUserInfoFromSession } from '../util/util';
function Home() { function Home() {
const { t } = useTranslation(); const { t } = useTranslation();
const holidayList = [{ date: '23 May, 2024', name: 'Buddha Purnima' }, { date: '15 June, 2024', name: 'Raja Sankranti' }]; const holidayList = [
const homePageNotifications = ['hpn_complete_before_31', 'hpn_npa', 'hpn_helpdesk_contact', 'hpn_rupay_kcc_time', 'hpn_rupay_kcc_atm']; { date: '23 May, 2024', name: 'Buddha Purnima' },
{ date: '15 June, 2024', name: 'Raja Sankranti' },
];
const homePageNotifications = [
'hpn_complete_before_31',
'hpn_npa',
'hpn_helpdesk_contact',
'hpn_rupay_kcc_time',
'hpn_rupay_kcc_atm',
];
const userInformation = getUserInfoFromSession(); const userInformation = getUserInfoFromSession();
return ( return (
@@ -15,7 +24,12 @@ function Home() {
<FormBox title={t('holidayList')} alt={true}> <FormBox title={t('holidayList')} alt={true}>
<ul className="px-4 list-disc list-inside"> <ul className="px-4 list-disc list-inside">
{holidayList.map((holiday, index) => ( {holidayList.map((holiday, index) => (
<li key={index} className="py-2 font-body text-surface dark:text-surface-dark text-lg/loose">{t(holiday.date)} - {t(holiday.name)}</li> <li
key={index}
className="py-2 font-body text-surface dark:text-surface-dark text-lg/loose"
>
{t(holiday.date)} - {t(holiday.name)}
</li>
))} ))}
</ul> </ul>
</FormBox> </FormBox>
@@ -23,11 +37,14 @@ function Home() {
<div className="flex-grow"> <div className="flex-grow">
<FormBox title={t('information')}> <FormBox title={t('information')}>
<ul className="px-4 list-disc list-inside"> <ul className="px-4 list-disc list-inside">
{ {Object.keys(userInformation).map((key, index) => (
Object.keys(userInformation).map((key, index) => ( <li
<li key={index} className="py-2 font-body text-surface-dark dark:text-surface text-lg/loose">{t(key)}: {t(userInformation[key])}</li> key={index}
)) className="py-2 font-body text-surface-dark dark:text-surface text-lg/loose"
} >
{t(key)}: {t(userInformation[key])}
</li>
))}
</ul> </ul>
</FormBox> </FormBox>
</div> </div>
@@ -37,7 +54,12 @@ function Home() {
<FormBox title={t('notifications')}> <FormBox title={t('notifications')}>
<ul className="px-4 list-disc list-inside"> <ul className="px-4 list-disc list-inside">
{homePageNotifications.map((notification, index) => ( {homePageNotifications.map((notification, index) => (
<li key={index} className="py-2 font-body text-surface-dark dark:text-surface text-lg/relaxed">{t(notification)}</li> <li
key={index}
className="py-2 font-body text-surface-dark dark:text-surface text-lg/relaxed"
>
{t(notification)}
</li>
))} ))}
</ul> </ul>
</FormBox> </FormBox>

View File

@@ -1,29 +1,29 @@
import { useState } from "react"; import { useState } from 'react';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { useToast } from "../hooks/useToast"; import { useToast } from '../hooks/useToast';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import Button from "../components/Button"; import Button from '../components/Button';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function KeySwap() { function KeySwap() {
const { t } = useTranslation(); const { t } = useTranslation();
const showToast = useToast(); const showToast = useToast();
const { isLoading, setIsLoading } = useLoading(); const { isLoading, setIsLoading } = useLoading();
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const [keySwapDetails, setKeySwapDetails] = useState({ const [keySwapDetails, setKeySwapDetails] = useState({
cabinetId: "", cabinetId: '',
lockerId: "", lockerId: '',
reason: "", reason: '',
oldKey: "", oldKey: '',
newKey: "", newKey: '',
newKeyConfirm: "", newKeyConfirm: '',
cabinetIdValid: true, cabinetIdValid: true,
lockerIdValid: true, lockerIdValid: true,
reasonValid: true, reasonValid: true,
@@ -34,52 +34,52 @@ function KeySwap() {
const formFields = [ const formFields = [
{ {
name: "cabinetId", name: 'cabinetId',
label: t("cabinetId"), label: t('cabinetId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "lockerId", name: 'lockerId',
label: t("lockerId"), label: t('lockerId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "reason", name: 'reason',
label: t("reasonForChange"), label: t('reasonForChange'),
type: "input", type: 'input',
maxLength: 50, maxLength: 50,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => value !== "", validate: (value) => value !== '',
}, },
{ {
name: "oldKey", name: 'oldKey',
label: t("oldKeyId"), label: t('oldKeyId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "newKey", name: 'newKey',
label: t("newKeyId"), label: t('newKeyId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "newKeyConfirm", name: 'newKeyConfirm',
label: t("confirmNewKeyId"), label: t('confirmNewKeyId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => value !== "" && value === keySwapDetails.newKey, validate: (value) => value !== '' && value === keySwapDetails.newKey,
}, },
]; ];
@@ -98,7 +98,7 @@ function KeySwap() {
} }
if (!valid) { if (!valid) {
showToast(t("highlightedFieldsInvalid"), "error"); showToast(t('highlightedFieldsInvalid'), 'error');
return; return;
} }
@@ -114,18 +114,18 @@ function KeySwap() {
if (response.status === 200) { if (response.status === 200) {
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "success", type: 'success',
}); });
} else { } else {
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "error", type: 'error',
}); });
} }
} catch (error) { } catch (error) {
setNotification({ setNotification({
message: error.message, message: error.message,
type: "error", type: 'error',
}); });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
@@ -148,14 +148,10 @@ function KeySwap() {
const valid = keySwapDetails[`${field.name}Valid`]; const valid = keySwapDetails[`${field.name}Valid`];
return ( return (
<FormField key={field.name} label={field.label} icon={field.icon}> <FormField key={field.name} label={field.label} icon={field.icon}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} valid={valid} /> <FormInput props={commonProps} valid={valid} />
) : ( ) : (
<FormSelect <FormSelect props={commonProps} valid={valid} options={field.options} />
props={commonProps}
valid={valid}
options={field.options}
/>
)} )}
</FormField> </FormField>
); );
@@ -164,11 +160,11 @@ function KeySwap() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<FormBox title={t("lockerStatus")}> <FormBox title={t('lockerStatus')}>
<FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
<Button text={t("submit")} onClick={handleKeySwap} /> <Button text={t('submit')} onClick={handleKeySwap} />
</FormBox> </FormBox>
</div> </div>
); );

View File

@@ -1,21 +1,21 @@
import { useState } from "react"; import { useState } from 'react';
import { useNavigate } from "react-router-dom"; import { useNavigate } from 'react-router-dom';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Button from "../components/Button"; import Button from '../components/Button';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function LockerMaintenance() { function LockerMaintenance() {
const navigate = useNavigate(); const navigate = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const [operation, setOperation] = useState({ value: "", valid: true }); const [operation, setOperation] = useState({ value: '', valid: true });
const handleNext = (e) => { const handleNext = (e) => {
e.preventDefault(); e.preventDefault();
if (operation.value === "") { if (operation.value === '') {
setOperation({ value: operation.value, valid: false }); setOperation({ value: operation.value, valid: false });
} }
navigate(operation.value); navigate(operation.value);
@@ -23,13 +23,13 @@ function LockerMaintenance() {
const formFields = [ const formFields = [
{ {
name: "value", name: 'value',
label: t("operation"), label: t('operation'),
options: [ options: [
{ label: t("status"), value: "status" }, { label: t('status'), value: 'status' },
{ label: t("keySwap"), value: "key-swap" }, { label: t('keySwap'), value: 'key-swap' },
], ],
type: "select", type: 'select',
}, },
]; ];
@@ -46,7 +46,7 @@ function LockerMaintenance() {
const options = field.options; const options = field.options;
return ( return (
<FormField label={field.label}> <FormField label={field.label}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} /> <FormInput props={commonProps} />
) : ( ) : (
<FormSelect props={commonProps} options={options} /> <FormSelect props={commonProps} options={options} />
@@ -57,9 +57,9 @@ function LockerMaintenance() {
return ( return (
<div> <div>
<FormBox title={t("lockerMaintenance")}> <FormBox title={t('lockerMaintenance')}>
<FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
<Button text={t("next")} onClick={(e) => handleNext(e)} /> <Button text={t('next')} onClick={(e) => handleNext(e)} />
</FormBox> </FormBox>
</div> </div>
); );

View File

@@ -1,56 +1,56 @@
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { useState } from "react"; import { useState } from 'react';
import Button from "../components/Button"; import Button from '../components/Button';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function LockerStatus() { function LockerStatus() {
const { t } = useTranslation(); const { t } = useTranslation();
const [lockerDetails, setLockerDetails] = useState({ const [lockerDetails, setLockerDetails] = useState({
cabinetId: "", cabinetId: '',
lockerId: "", lockerId: '',
status: "", status: '',
cabinetIdValid: true, cabinetIdValid: true,
lockerIdValid: true, lockerIdValid: true,
statusValid: true, statusValid: true,
}); });
const { isLoading, setIsLoading } = useLoading(); const { isLoading, setIsLoading } = useLoading();
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const formFields = [ const formFields = [
{ {
name: "cabinetId", name: 'cabinetId',
label: t("cabinetId"), label: t('cabinetId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "lockerId", name: 'lockerId',
label: t("lockerId"), label: t('lockerId'),
type: "input", type: 'input',
maxLength: 6, maxLength: 6,
readOnly: isLoading, readOnly: isLoading,
validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}/.test(value),
}, },
{ {
name: "status", name: 'status',
label: t("status"), label: t('status'),
type: "select", type: 'select',
readOnly: isLoading, readOnly: isLoading,
options: [ options: [
{ value: "open", label: t("open") }, { value: 'open', label: t('open') },
{ value: "close", label: t("close") }, { value: 'close', label: t('close') },
], ],
validate: (value) => value !== "", validate: (value) => value !== '',
}, },
]; ];
@@ -83,12 +83,12 @@ function LockerStatus() {
); );
setNotification({ setNotification({
message: response.data.message, message: response.data.message,
type: "success", type: 'success',
}); });
} catch (error) { } catch (error) {
setNotification({ setNotification({
message: error.message, message: error.message,
type: "error", type: 'error',
}); });
} finally { } finally {
setIsLoading(false); setIsLoading(false);
@@ -111,7 +111,7 @@ function LockerStatus() {
const valid = lockerDetails[`${field.name}Valid`]; const valid = lockerDetails[`${field.name}Valid`];
return ( return (
<FormField key={field.name} label={field.label} icon={field.icon}> <FormField key={field.name} label={field.label} icon={field.icon}>
{field.type === "input" ? ( {field.type === 'input' ? (
<FormInput props={commonProps} valid={valid} /> <FormInput props={commonProps} valid={valid} />
) : ( ) : (
<FormSelect props={commonProps} options={field.options} /> <FormSelect props={commonProps} options={field.options} />
@@ -123,12 +123,12 @@ function LockerStatus() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<FormBox title={t("lockerStatus")}> <FormBox title={t('lockerStatus')}>
<FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper> <FieldsWrapper>{formFields.map(renderField)}</FieldsWrapper>
<Button text={t("submit")} onClick={handleSubmit} /> <Button text={t('submit')} onClick={handleSubmit} />
</FormBox> </FormBox>
</div> </div>
); );

View File

@@ -1,21 +1,21 @@
import { useLocation } from "react-router-dom"; import { useLocation } from 'react-router-dom';
import { useState } from "react"; import { useState } from 'react';
import { useLoading } from "../hooks/useLoading"; import { useLoading } from '../hooks/useLoading';
import FormBox from "../components/FormBox"; import FormBox from '../components/FormBox';
import Button from "../components/Button"; import Button from '../components/Button';
import { lockerService } from "../services/locker.service"; import { lockerService } from '../services/locker.service';
import { AnimatePresence } from "motion/react"; import { AnimatePresence } from 'motion/react';
import Notification from "../components/Notification"; import Notification from '../components/Notification';
import FormField from "../components/FormField"; import FormField from '../components/FormField';
import FormInput from "../components/FormInput"; import FormInput from '../components/FormInput';
import FormSelect from "../components/FormSelect"; import FormSelect from '../components/FormSelect';
import FormHeader from "../components/FormHeader"; import FormHeader from '../components/FormHeader';
import FieldsWrapper from "../components/FieldsWrapper"; import FieldsWrapper from '../components/FieldsWrapper';
function LockersRegistration() { function LockersRegistration() {
const location = useLocation(); const location = useLocation();
const { setIsLoading } = useLoading(); const { setIsLoading } = useLoading();
const [notification, setNotification] = useState({ message: "", type: "" }); const [notification, setNotification] = useState({ message: '', type: '' });
const noOfLockers = location.state?.noOfLockers; const noOfLockers = location.state?.noOfLockers;
const cabinetId = location.state?.cabinetId; const cabinetId = location.state?.cabinetId;
@@ -23,9 +23,9 @@ function LockersRegistration() {
const initLockers = Array(noOfLockers) const initLockers = Array(noOfLockers)
.fill() .fill()
.map(() => ({ .map(() => ({
id: "", id: '',
size: "", size: '',
keyId: "", keyId: '',
idValid: true, idValid: true,
sizeValid: true, sizeValid: true,
keyIdValid: true, keyIdValid: true,
@@ -49,18 +49,14 @@ function LockersRegistration() {
}; };
// Find duplicates // Find duplicates
const duplicateLockerIds = findDuplicates(lockerValues, "id"); const duplicateLockerIds = findDuplicates(lockerValues, 'id');
const duplicateKeyIds = findDuplicates(lockerValues, "keyId"); const duplicateKeyIds = findDuplicates(lockerValues, 'keyId');
const newValues = lockerValues.map((locker) => { const newValues = lockerValues.map((locker) => {
const newLocker = { ...locker }; const newLocker = { ...locker };
// Check ID // Check ID
if ( if (locker.id === '' || !idRegex.test(locker.id) || duplicateLockerIds.includes(locker.id)) {
locker.id === "" ||
!idRegex.test(locker.id) ||
duplicateLockerIds.includes(locker.id)
) {
newLocker.idValid = false; newLocker.idValid = false;
valid = false; valid = false;
} else { } else {
@@ -68,7 +64,7 @@ function LockersRegistration() {
} }
// Check size // Check size
if (locker.size === "") { if (locker.size === '') {
newLocker.sizeValid = false; newLocker.sizeValid = false;
valid = false; valid = false;
} else { } else {
@@ -77,7 +73,7 @@ function LockersRegistration() {
// Check keyId // Check keyId
if ( if (
locker.keyId === "" || locker.keyId === '' ||
!idRegex.test(locker.keyId) || !idRegex.test(locker.keyId) ||
duplicateKeyIds.includes(locker.keyId) duplicateKeyIds.includes(locker.keyId)
) { ) {
@@ -98,19 +94,16 @@ function LockersRegistration() {
try { try {
setIsLoading(true); setIsLoading(true);
const response = await lockerService.registerLockers( const response = await lockerService.registerLockers(cabinetId, lockerValues);
cabinetId,
lockerValues
);
setNotification({ setNotification({
message: `Cabinet creation successful. Cabinet ID: ${response.data.cabinetId}`, message: `Cabinet creation successful. Cabinet ID: ${response.data.cabinetId}`,
type: "success", type: 'success',
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setNotification({ setNotification({
message: `Error registering lockers. ${error.message}`, message: `Error registering lockers. ${error.message}`,
type: "error", type: 'error',
}); });
return; return;
} finally { } finally {
@@ -120,29 +113,29 @@ function LockersRegistration() {
const formRow = [ const formRow = [
{ {
label: "Locker ID", label: 'Locker ID',
type: "input", type: 'input',
subType: "text", subType: 'text',
name: "id", name: 'id',
maxLength: 6, maxLength: 6,
validate: (value) => /^[A-Z]{2}[0-9]{4}$/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}$/.test(value),
}, },
{ {
label: "Size", label: 'Size',
type: "select", type: 'select',
subType: "text", subType: 'text',
name: "size", name: 'size',
options: [ options: [
{ label: "Small", value: "1" }, { label: 'Small', value: '1' },
{ label: "Medium", value: "2" }, { label: 'Medium', value: '2' },
{ label: "Large", value: "3" }, { label: 'Large', value: '3' },
], ],
}, },
{ {
label: "Key ID", label: 'Key ID',
type: "input", type: 'input',
subType: "text", subType: 'text',
name: "keyId", name: 'keyId',
maxLength: 6, maxLength: 6,
validate: (value) => /^[A-Z]{2}[0-9]{4}$/.test(value), validate: (value) => /^[A-Z]{2}[0-9]{4}$/.test(value),
}, },
@@ -162,7 +155,7 @@ function LockersRegistration() {
const valid = lockerValues[`${field.name}Valid`]; const valid = lockerValues[`${field.name}Valid`];
return field.type === "input" ? ( return field.type === 'input' ? (
<FormInput key={field.name} props={commonProps} valid={valid} /> <FormInput key={field.name} props={commonProps} valid={valid} />
) : ( ) : (
<FormSelect key={field.name} props={commonProps} valid={valid} options={field.options} /> <FormSelect key={field.name} props={commonProps} valid={valid} options={field.options} />
@@ -181,17 +174,15 @@ function LockersRegistration() {
return ( return (
<div> <div>
<AnimatePresence> <AnimatePresence>
{notification.message !== "" && <Notification {...notification} />} {notification.message !== '' && <Notification {...notification} />}
</AnimatePresence> </AnimatePresence>
<div className="relative"> <div className="relative">
{notification.type === "success" && ( {notification.type === 'success' && (
<div className="absolute inset-0 bg-[#fff]/50 z-10 rounded-3xl" /> <div className="absolute inset-0 bg-[#fff]/50 z-10 rounded-3xl" />
)} )}
<FormBox title="Locker Registration"> <FormBox title="Locker Registration">
<FormHeader text={cabinetId} /> <FormHeader text={cabinetId} />
<FieldsWrapper className=""> <FieldsWrapper className="">{formFields.map(renderFormFields)}</FieldsWrapper>
{formFields.map(renderFormFields)}
</FieldsWrapper>
<Button text="Register" onClick={handleSubmit} /> <Button text="Register" onClick={handleSubmit} />
</FormBox> </FormBox>
</div> </div>

View File

@@ -1,10 +1,10 @@
import axios from 'axios'; import axios from 'axios';
const api = axios.create({ const api = axios.create({
baseURL: "http://localhost:8081/api/v1", baseURL: 'http://localhost:8081/api/v1',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
} },
}); });
export default api; export default api;

View File

@@ -1,8 +1,8 @@
import api from "./api"; import api from './api';
export const lockerService = { export const lockerService = {
registerLockers: async (cabinetId, lockers) => { registerLockers: async (cabinetId, lockers) => {
return api.post("/cabinet", { return api.post('/cabinet', {
cabinetId, cabinetId,
lockers: lockers.map(({ id, size, keyId }) => ({ lockers: lockers.map(({ id, size, keyId }) => ({
id, id,

View File

@@ -1,8 +1,43 @@
const productInfo = [ const productInfo = [
{ productCode: '3001', productCodeDescription: 'RECURRING DEPOSIT', interestCategory: '1004', interestCategoryDescription: 'NON MEMBER - SENIOR CITIZEN', payableGl: '16010', paidGl: '62110' }, {
{ productCode: '1101', productCodeDescription: 'CURRENT ACCOUNT', interestCategory: '1009', interestCategoryDescription: 'GENERAL', payableGl: '16018', paidGl: '62115' }, productCode: '3001',
{ productCode: '1101', productCodeDescription: 'SAVINGS DEPOSIT', interestCategory: '1007', interestCategoryDescription: 'NON MEMBER', payableGl: '16301', paidGl: '62117' }, productCodeDescription: 'RECURRING DEPOSIT',
{ productCode: '2002', productCodeDescription: 'CASH CERTIFICATE -GENERAL', interestCategory: '1047', interestCategoryDescription: 'COMPOUNDING', payableGl: '16011', paidGl: '62111' }, interestCategory: '1004',
{ productCode: '2002', productCodeDescription: 'CASH CERTIFICATE', interestCategory: '1005', interestCategoryDescription: 'NON MEMBER - SENIOR CITIZEN', payableGl: '16011', paidGl: '62111' }, interestCategoryDescription: 'NON MEMBER - SENIOR CITIZEN',
] payableGl: '16010',
export default productInfo; paidGl: '62110',
},
{
productCode: '1101',
productCodeDescription: 'CURRENT ACCOUNT',
interestCategory: '1009',
interestCategoryDescription: 'GENERAL',
payableGl: '16018',
paidGl: '62115',
},
{
productCode: '1101',
productCodeDescription: 'SAVINGS DEPOSIT',
interestCategory: '1007',
interestCategoryDescription: 'NON MEMBER',
payableGl: '16301',
paidGl: '62117',
},
{
productCode: '2002',
productCodeDescription: 'CASH CERTIFICATE -GENERAL',
interestCategory: '1047',
interestCategoryDescription: 'COMPOUNDING',
payableGl: '16011',
paidGl: '62111',
},
{
productCode: '2002',
productCodeDescription: 'CASH CERTIFICATE',
interestCategory: '1005',
interestCategoryDescription: 'NON MEMBER - SENIOR CITIZEN',
payableGl: '16011',
paidGl: '62111',
},
];
export default productInfo;

View File

@@ -1,14 +1,16 @@
const getUserInfoFromSession = () => { const getUserInfoFromSession = () => {
return { return {
username: "Rajesh Kumar", username: 'Rajesh Kumar',
pacsName: "Demo SKUS Ltd.", pacsName: 'Demo SKUS Ltd.',
userType: "pacsTeller", userType: 'pacsTeller',
moduleName: "locker", moduleName: 'locker',
} };
} };
const toTitleCase = (str) => { const toTitleCase = (str) => {
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); return str.replace(/\w\S*/g, function (txt) {
} return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
};
export { getUserInfoFromSession, toTitleCase }; export { getUserInfoFromSession, toTitleCase };

View File

@@ -1,9 +1,6 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: [ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
darkMode: 'selector', darkMode: 'selector',
theme: { theme: {
colors: { colors: {
@@ -13,7 +10,7 @@ export default {
error: { error: {
DEFAULT: '#A14444', DEFAULT: '#A14444',
dark: '#E5254B', dark: '#E5254B',
surface: {DEFAULT: '#D26464', dark: '#FCE9ED'} surface: { DEFAULT: '#D26464', dark: '#FCE9ED' },
}, },
onToast: { onToast: {
DEFAULT: '#646564', DEFAULT: '#646564',
@@ -22,22 +19,22 @@ export default {
warning: { warning: {
DEFAULT: '#A5A513', DEFAULT: '#A5A513',
dark: '#EA7000', dark: '#EA7000',
surface: {DEFAULT: '#C8C820', dark: '#FDF1E5'} surface: { DEFAULT: '#C8C820', dark: '#FDF1E5' },
}, },
success: { success: {
DEFAULT: '#038100', DEFAULT: '#038100',
dark: '#038100', dark: '#038100',
surface: {DEFAULT: '#E6F2E5', dark: '#E6F2E5'} surface: { DEFAULT: '#E6F2E5', dark: '#E6F2E5' },
}, },
transparent: 'transparent', transparent: 'transparent',
primary: { primary: {
DEFAULT: '#008C46', DEFAULT: '#008C46',
dark: '#E6F4E1' dark: '#E6F4E1',
}, },
secondary: { secondary: {
DEFAULT: '#B1E1B3', DEFAULT: '#B1E1B3',
dark: '#7DBD80', dark: '#7DBD80',
variant: {DEFAULT: '#80AE82', dark: '#5B875D'} variant: { DEFAULT: '#80AE82', dark: '#5B875D' },
}, },
tertiary: { tertiary: {
DEFAULT: '#f2f2df', DEFAULT: '#f2f2df',
@@ -46,17 +43,16 @@ export default {
surface: { surface: {
DEFAULT: '#F6F6F6', DEFAULT: '#F6F6F6',
dark: '#2d332d', dark: '#2d332d',
variant: {DEFAULT: '#F4FFF4', dark: '#2b372c'} variant: { DEFAULT: '#F4FFF4', dark: '#2b372c' },
}, },
}, },
fontFamily: { fontFamily: {
display: ['Montserrat', 'sans-serif'], display: ['Montserrat', 'sans-serif'],
body: ['Rubik', 'Noto Sans','Noto Sans Bengali', 'sans-serif'], body: ['Rubik', 'Noto Sans', 'Noto Sans Bengali', 'sans-serif'],
}, },
extend: { extend: {
borderWidth: { borderWidth: {
'3': '3px', 3: '3px',
}, },
fontSize: { fontSize: {
title: '40px', title: '40px',
@@ -75,7 +71,7 @@ export default {
'30%': { width: '30%' }, '30%': { width: '30%' },
'80%': { width: '10%' }, '80%': { width: '10%' },
'100%': { left: '100%' }, '100%': { left: '100%' },
} },
}, },
}, },
}, },
@@ -84,5 +80,4 @@ export default {
addVariant('second-last', '&:nth-last-child(2)'); addVariant('second-last', '&:nth-last-child(2)');
}, },
], ],
} };

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
}) });