305 lines
9.1 KiB
JavaScript
305 lines
9.1 KiB
JavaScript
import { AnimatePresence } from "motion/react";
|
|
import clsx from "clsx";
|
|
import { PackageSearch, Copy, UserSearch } from "lucide-react";
|
|
import { useState } from "react";
|
|
import { motion } from "motion/react";
|
|
import FormBox from "../components/FormBox";
|
|
import { useTranslation } from "react-i18next";
|
|
import FormField from "../components/FormField";
|
|
import FormInput from "../components/FormInput";
|
|
import FormSelect from "../components/FormSelect";
|
|
import Button from "../components/Button";
|
|
import { useToast } from "../hooks/useToast";
|
|
import productInfo from "../util/productList";
|
|
import ProductListTable from "../components/ProductListTable";
|
|
|
|
function AccountCreation() {
|
|
const { t } = useTranslation();
|
|
const showToast = useToast();
|
|
const [notification] = useState({
|
|
visible: false,
|
|
message: "",
|
|
type: "",
|
|
});
|
|
const [showProductModal, setShowProductModal] = useState(false);
|
|
const [submitting] = useState(false);
|
|
const [accountDetails, setAccountDetails] = useState({
|
|
productCode: "",
|
|
interestCategory: "",
|
|
segmentCode: "",
|
|
accountHolderType: "",
|
|
primaryCifNumber: "",
|
|
nomineeCifNumber: "",
|
|
activityCode: "",
|
|
customerType: "",
|
|
collateralFDAccount: "",
|
|
rentPayAccount: "",
|
|
productCodeValid: true,
|
|
interestCategoryValid: true,
|
|
segmentCodeValid: true,
|
|
accountHolderTypeValid: true,
|
|
primaryCifNumberValid: true,
|
|
nomineeCifNumberValid: true,
|
|
activityCodeValid: true,
|
|
customerTypeValid: true,
|
|
collateralFDAccountValid: true,
|
|
rentPayAccountValid: true,
|
|
});
|
|
|
|
const handleProductSelect = (product) => {
|
|
const newAccountDetails = { ...accountDetails };
|
|
newAccountDetails.productCode = product.productCode;
|
|
newAccountDetails.interestCategory = product.interestCategory;
|
|
setAccountDetails(newAccountDetails);
|
|
setShowProductModal(false);
|
|
};
|
|
|
|
const accountDetailsFields = [
|
|
{
|
|
label: t("productCode"),
|
|
name: "productCode",
|
|
type: "input",
|
|
subType: "number",
|
|
readOnly: true,
|
|
validate: (value) => value !== "",
|
|
icon: {
|
|
icon: <PackageSearch size={18} />,
|
|
onClick: () => setShowProductModal(true),
|
|
},
|
|
},
|
|
{
|
|
label: t("interestCategory"),
|
|
name: "interestCategory",
|
|
type: "input",
|
|
subType: "number",
|
|
readOnly: true,
|
|
validate: (value) => value !== "",
|
|
},
|
|
{
|
|
label: t("segmentCode"),
|
|
name: "segmentCode",
|
|
type: "select",
|
|
options: [
|
|
{ value: "0706", label: "0706: Individual" },
|
|
{ value: "0306", label: "0306: Staff" },
|
|
{ value: "5003", label: "5003: Senior Citizen" },
|
|
{ value: "5010", label: "5010: SHG" },
|
|
{ value: "5000", label: "5000: Bank" },
|
|
{ value: "5009", label: "5009: Institutions" },
|
|
{ value: "5050", label: "5050: Others" },
|
|
{ value: "5007", label: "5007: Society" },
|
|
],
|
|
validate: (value) => value !== "",
|
|
},
|
|
{
|
|
label: t("accountHolderType"),
|
|
name: "accountHolderType",
|
|
type: "select",
|
|
options: [
|
|
{ value: "1", label: "Single" },
|
|
{ value: "2", label: "Joint" },
|
|
],
|
|
validate: (value) => value === "1" || value === "2",
|
|
},
|
|
{
|
|
label: t("primaryCifNumber"),
|
|
name: "primaryCifNumber",
|
|
type: "input",
|
|
subType: "number",
|
|
maxLength: 17,
|
|
validate: (value) => /^[0-9]{17}$/.test(value),
|
|
icon: { icon: <UserSearch size={18} /> },
|
|
},
|
|
{
|
|
label: t("nomineeCifNumber"),
|
|
name: "nomineeCifNumber",
|
|
type: "input",
|
|
subType: "number",
|
|
maxLength: 17,
|
|
validate: (value) => /^[0-9]{17}$/.test(value),
|
|
},
|
|
];
|
|
const additionalDetailsFields = [
|
|
{
|
|
label: t("activityCode"),
|
|
name: "activityCode",
|
|
type: "select",
|
|
options: [
|
|
{ value: "0701", label: "Direct Agriculture" },
|
|
{ value: "0702", label: "Indirect Agriculture" },
|
|
{ value: "0703", label: "Agricultural Services Unit" },
|
|
{ value: "0704", label: "Farm Irrigation" },
|
|
{ value: "0705", label: "Fruits & Vegetables" },
|
|
{ value: "0706", label: "Non-Agriculture" },
|
|
],
|
|
validate: (value) => value !== "",
|
|
},
|
|
{
|
|
label: t("customerType"),
|
|
name: "customerType",
|
|
type: "select",
|
|
options: [
|
|
{ value: "0709", label: "Individual" },
|
|
{ value: "0701", label: "Corporate" },
|
|
],
|
|
validate: (value) => value === "0709" || value === "0701",
|
|
},
|
|
{
|
|
label: t("collateralFDAccount"),
|
|
name: "collateralFDAccount",
|
|
type: "input",
|
|
subType: "number",
|
|
maxLength: 17,
|
|
validate: (value) => /^[0-9]{17}$/.test(value),
|
|
},
|
|
{
|
|
label: t("rentPayAccount"),
|
|
name: "rentPayAccount",
|
|
type: "input",
|
|
subType: "number",
|
|
maxLength: 17,
|
|
validate: (value) => /^[0-9]{17}$/.test(value),
|
|
},
|
|
];
|
|
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault();
|
|
let isValid = true;
|
|
const newValidationState = { ...accountDetails };
|
|
|
|
// Validate account details fields
|
|
[...accountDetailsFields, ...additionalDetailsFields].forEach((field) => {
|
|
if (field.validate) {
|
|
const fieldIsValid = field.validate(accountDetails[field.name]);
|
|
newValidationState[`${field.name}Valid`] = fieldIsValid;
|
|
if (!fieldIsValid) isValid = false;
|
|
}
|
|
});
|
|
|
|
setAccountDetails(newValidationState);
|
|
|
|
if (!isValid) {
|
|
showToast("Highlighted fields are invalid", "error");
|
|
return;
|
|
}
|
|
console.log("Form is valid", accountDetails);
|
|
};
|
|
const renderProductModal = () => {
|
|
return (
|
|
<AnimatePresence mode="popLayout">
|
|
{showProductModal && (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
key="productList"
|
|
className="fixed z-50 inset-0 flex items-center justify-center bg-black/50"
|
|
>
|
|
<motion.div
|
|
initial={{ scale: 0.8 }}
|
|
animate={{ scale: 1 }}
|
|
exit={{ scale: 0.8 }}
|
|
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>
|
|
<ProductListTable
|
|
productInfo={productInfo}
|
|
onSelectProduct={handleProductSelect}
|
|
/>
|
|
</motion.div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
};
|
|
|
|
const renerField = (field) => {
|
|
const commonProps = {
|
|
value: accountDetails[field.name],
|
|
onChange: (e) => {
|
|
const newAccountDetails = { ...accountDetails };
|
|
newAccountDetails[field.name] = e.target.value;
|
|
newAccountDetails[`${field.name}Valid`] = true;
|
|
setAccountDetails(newAccountDetails);
|
|
},
|
|
maxLength: field.maxLength,
|
|
className: clsx(!accountDetails[`${field.name}Valid`] && "border-error"),
|
|
};
|
|
|
|
return (
|
|
<FormField key={field.name} label={field.label} icon={field.icon}>
|
|
{field.type === "input" ? (
|
|
<FormInput
|
|
{...commonProps}
|
|
type={field.subType}
|
|
readOnly={field.readOnly}
|
|
/>
|
|
) : (
|
|
<FormSelect {...commonProps} options={field.options} />
|
|
)}
|
|
</FormField>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<AnimatePresence>
|
|
{notification.visible && (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className={clsx(
|
|
"p-4 mb-8 font-body text-center text-xl rounded-2xl flex items-center justify-center gap-2",
|
|
notification.type === "error"
|
|
? "bg-error-surface text-error"
|
|
: "bg-success-surface text-success"
|
|
)}
|
|
>
|
|
{notification.message.split(":").map((msg, index) => {
|
|
return index === 1 ? (
|
|
<span key={index} className="border-b border-dashed">
|
|
{msg}
|
|
</span>
|
|
) : (
|
|
<span key={index}>{msg}</span>
|
|
);
|
|
})}
|
|
<Copy
|
|
cursor={"pointer"}
|
|
size={15}
|
|
onClick={navigator.clipboard.writeText(
|
|
notification.message.split(":")[1].trim()
|
|
)}
|
|
/>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
{renderProductModal()}
|
|
<FormBox title="Account Creation" disabled={submitting}>
|
|
<div className="p-2 pt-7 ">
|
|
<div className="flex flex-col gap-4">
|
|
<h1 className="text-2xl font-medium text-primary py-2">
|
|
Account Details
|
|
</h1>
|
|
{accountDetailsFields.map(renerField)}
|
|
</div>
|
|
<div className="flex flex-col gap-4">
|
|
<h1 className="text-2xl font-medium text-primary py-2 pt-6">
|
|
Additional Details
|
|
</h1>
|
|
{additionalDetailsFields.map(renerField)}
|
|
</div>
|
|
</div>
|
|
<Button
|
|
text={t("submit")}
|
|
onClick={handleSubmit}
|
|
disabled={submitting}
|
|
/>
|
|
</FormBox>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default AccountCreation;
|