reactored code to use formfields and formselects
This commit is contained in:
parent
962102d44c
commit
9f4059e2c6
21
src/components/FieldError.jsx
Normal file
21
src/components/FieldError.jsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
|
||||||
|
function FieldError({ text }) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
className="text-sm text-error ml-3 pt-1"
|
||||||
|
initial={{ y: 15, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
exit={{ y: 15, opacity: 0 }}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldError.propTypes = {
|
||||||
|
text: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FieldError;
|
@ -2,13 +2,16 @@ 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 }) {
|
function FormField({ label, children, icon, variant }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex items-center">
|
||||||
<label className="mr-4 text-lg text-black dark:text-primary-dark md:w-[30%] xl:w-[20%] 2xl:w-[17%]">
|
<label className={clsx(
|
||||||
|
"mr-20 text-lg text-black dark:text-primary-dark whitespace-nowrap",
|
||||||
|
variant === 'long' && "sm:w-[5%]"
|
||||||
|
)}>
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
<div className="flex w-full gap-4 items-center">
|
<div className={clsx("flex w-full gap-4 items-center", variant === 'long' && 'gap-10')}>
|
||||||
{children}
|
{children}
|
||||||
{icon && (
|
{icon && (
|
||||||
<motion.div
|
<motion.div
|
||||||
@ -29,7 +32,8 @@ function FormField({ label, children, icon }) {
|
|||||||
FormField.propTypes = {
|
FormField.propTypes = {
|
||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
icon: PropTypes.object.isRequired,
|
icon: PropTypes.object,
|
||||||
|
variant: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FormField;
|
export default FormField;
|
||||||
|
11
src/components/FormHeader.jsx
Normal file
11
src/components/FormHeader.jsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
function FormHeader({ text }) {
|
||||||
|
return <h1 className="text-2xl font-medium text-primary py-2">{text}</h1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormHeader.propTypes = {
|
||||||
|
text: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormHeader;
|
@ -1,8 +1,11 @@
|
|||||||
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";
|
||||||
|
|
||||||
function FormInput({
|
function FormInput({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
placeholder,
|
||||||
valid = true,
|
valid = true,
|
||||||
maxLength = 17,
|
maxLength = 17,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
@ -14,10 +17,14 @@ function FormInput({
|
|||||||
<input
|
<input
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
value={value}
|
value={value}
|
||||||
className={`w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`}
|
className={clsx(
|
||||||
|
`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"
|
||||||
|
)}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
type={type}
|
type={type}
|
||||||
maxLength={maxLength}
|
maxLength={maxLength}
|
||||||
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{!valid && (
|
{!valid && (
|
||||||
@ -44,6 +51,7 @@ FormInput.propTypes = {
|
|||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
maxLength: PropTypes.number,
|
maxLength: PropTypes.number,
|
||||||
valid: PropTypes.bool,
|
valid: PropTypes.bool,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FormInput;
|
export default FormInput;
|
||||||
|
@ -1,40 +1,32 @@
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { motion, AnimatePresence } from "motion/react";
|
import { AnimatePresence } from "motion/react";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import FieldError from "./FieldError";
|
||||||
|
|
||||||
function FormSelect({ value, onChange, options, className, valid = true }) {
|
function FormSelect({ value, onChange, options, className, valid = true }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<select
|
<select
|
||||||
value={value}
|
value={value}
|
||||||
className={
|
className={clsx(
|
||||||
"w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey " +
|
`w-72 h-10 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey ${className}`,
|
||||||
className
|
!valid && "border-error"
|
||||||
}
|
|
||||||
onChange={onChange}
|
|
||||||
>
|
|
||||||
<option disabled value="">
|
|
||||||
Select
|
|
||||||
</option>
|
|
||||||
{options.map(({ value, label }) => (
|
|
||||||
<option key={value} value={value}>
|
|
||||||
{label}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
<AnimatePresence>
|
|
||||||
{!valid && (
|
|
||||||
<motion.div
|
|
||||||
className="text-sm text-error ml-3 pt-1"
|
|
||||||
initial={{ y: 15, opacity: 0 }}
|
|
||||||
animate={{ y: 0, opacity: 1 }}
|
|
||||||
exit={{ y: 15, opacity: 0 }}
|
|
||||||
key="cabinetIdError"
|
|
||||||
>
|
|
||||||
Invalid Value
|
|
||||||
</motion.div>
|
|
||||||
)}
|
)}
|
||||||
|
onChange={onChange}
|
||||||
|
>
|
||||||
|
<option disabled value="">
|
||||||
|
Select
|
||||||
|
</option>
|
||||||
|
{options.map(({ value, label }) => (
|
||||||
|
<option key={value} value={value}>
|
||||||
|
{label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<AnimatePresence>
|
||||||
|
{!valid && <FieldError text={"Invalid value"} />}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/components/ProductModal.jsx
Normal file
35
src/components/ProductModal.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { motion } from "motion/react";
|
||||||
|
import ProductListTable from "./ProductListTable";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
function ProductModal({ productInfo, handleProductSelect }) {
|
||||||
|
return (
|
||||||
|
<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={{ y: 15, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
exit={{ y: 15, opacity: 0 }}
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductModal.propTypes = {
|
||||||
|
productInfo: PropTypes.object.isRequired,
|
||||||
|
handleProductSelect: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductModal;
|
@ -1,8 +1,6 @@
|
|||||||
import { AnimatePresence } from "motion/react";
|
import { AnimatePresence } from "motion/react";
|
||||||
import clsx from "clsx";
|
import { PackageSearch, UserSearch } from "lucide-react";
|
||||||
import { PackageSearch, Copy, UserSearch } from "lucide-react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { motion } from "motion/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";
|
||||||
@ -10,17 +8,14 @@ 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 ProductListTable from "../components/ProductListTable";
|
import Notification from "../components/Notification";
|
||||||
|
import ProductModal from "../components/ProductModal";
|
||||||
|
import FormHeader from "../components/FormHeader";
|
||||||
|
|
||||||
function AccountCreation() {
|
function AccountCreation() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [notification] = useState({
|
const [notification] = useState({ message: "", type: "" });
|
||||||
visible: false,
|
|
||||||
message: "",
|
|
||||||
type: "",
|
|
||||||
});
|
|
||||||
const [showProductModal, setShowProductModal] = useState(false);
|
const [showProductModal, setShowProductModal] = useState(false);
|
||||||
const [submitting] = useState(false);
|
|
||||||
const [accountDetails, setAccountDetails] = useState({
|
const [accountDetails, setAccountDetails] = useState({
|
||||||
productCode: "",
|
productCode: "",
|
||||||
interestCategory: "",
|
interestCategory: "",
|
||||||
@ -48,6 +43,8 @@ function AccountCreation() {
|
|||||||
const newAccountDetails = { ...accountDetails };
|
const newAccountDetails = { ...accountDetails };
|
||||||
newAccountDetails.productCode = product.productCode;
|
newAccountDetails.productCode = product.productCode;
|
||||||
newAccountDetails.interestCategory = product.interestCategory;
|
newAccountDetails.interestCategory = product.interestCategory;
|
||||||
|
newAccountDetails.productCodeValid = true;
|
||||||
|
newAccountDetails.interestCategoryValid = true;
|
||||||
setAccountDetails(newAccountDetails);
|
setAccountDetails(newAccountDetails);
|
||||||
setShowProductModal(false);
|
setShowProductModal(false);
|
||||||
};
|
};
|
||||||
@ -181,36 +178,8 @@ function AccountCreation() {
|
|||||||
}
|
}
|
||||||
console.log("Form is valid", accountDetails);
|
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={{ y: 15, opacity: 0 }}
|
|
||||||
animate={{ y: 0, opacity: 1 }}
|
|
||||||
exit={{ y: 15, opacity: 0 }}
|
|
||||||
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 renderField = (field) => {
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
value: accountDetails[field.name],
|
value: accountDetails[field.name],
|
||||||
valid: accountDetails[`${field.name}Valid`],
|
valid: accountDetails[`${field.name}Valid`],
|
||||||
@ -221,7 +190,6 @@ function AccountCreation() {
|
|||||||
setAccountDetails(newAccountDetails);
|
setAccountDetails(newAccountDetails);
|
||||||
},
|
},
|
||||||
maxLength: field.maxLength,
|
maxLength: field.maxLength,
|
||||||
className: clsx(!accountDetails[`${field.name}Valid`] && "border-error"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -242,59 +210,32 @@ function AccountCreation() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{notification.visible && (
|
{notification.message !== "" && <Notification {...notification} />}
|
||||||
<motion.div
|
</AnimatePresence>
|
||||||
initial={{ y: 15, opacity: 0 }}
|
|
||||||
animate={{ y: 0, opacity: 1 }}
|
<AnimatePresence>
|
||||||
exit={{ y: 15, opacity: 0 }}
|
{showProductModal && (
|
||||||
className={clsx(
|
<ProductModal
|
||||||
"p-4 mb-8 font-body text-center text-xl rounded-2xl flex items-center justify-center gap-2",
|
productInfo={productInfo}
|
||||||
notification.type === "error"
|
handleProductSelect={handleProductSelect}
|
||||||
? "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>
|
</AnimatePresence>
|
||||||
{renderProductModal()}
|
|
||||||
<FormBox title="Account Creation" disabled={submitting}>
|
<FormBox title="Account Creation" >
|
||||||
<div className="p-2 pt-7 ">
|
<div className="p-2 pt-7 ">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h1 className="text-2xl font-medium text-primary py-2">
|
<FormHeader text={"Account Details"}/>
|
||||||
Account Details
|
{accountDetailsFields.map(renderField)}
|
||||||
</h1>
|
|
||||||
{accountDetailsFields.map(renerField)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h1 className="text-2xl font-medium text-primary py-2 pt-6">
|
<FormHeader text={"Additional Details"}/>
|
||||||
Additional Details
|
{additionalDetailsFields.map(renderField)}
|
||||||
</h1>
|
|
||||||
{additionalDetailsFields.map(renerField)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button text={t("submit")} onClick={handleSubmit} />
|
||||||
text={t("submit")}
|
|
||||||
onClick={handleSubmit}
|
|
||||||
disabled={submitting}
|
|
||||||
/>
|
|
||||||
</FormBox>
|
</FormBox>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import clsx from "clsx";
|
import { useToast } from "../hooks/useToast";
|
||||||
|
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 { useToast } from "../hooks/useToast";
|
|
||||||
import { lockerService } from "../services/locker.service";
|
import { lockerService } from "../services/locker.service";
|
||||||
import { AnimatePresence } from "motion/react";
|
import { AnimatePresence } from "motion/react";
|
||||||
import { useLoading } from "../hooks/useLoading";
|
|
||||||
import Notification from "../components/Notification";
|
import Notification from "../components/Notification";
|
||||||
|
import FormField from "../components/FormField";
|
||||||
|
import FormInput from "../components/FormInput";
|
||||||
|
import FormSelect from "../components/FormSelect";
|
||||||
|
|
||||||
function LockersRegistration() {
|
function LockersRegistration() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const showToast = useToast();
|
|
||||||
const { setIsLoading } = useLoading();
|
const { setIsLoading } = useLoading();
|
||||||
const noOfLockers = location.state?.noOfLockers;
|
const [notification, setNotification] = useState({ message: "", type: "" });
|
||||||
|
|
||||||
|
const noOfLockers = location.state?.noOfLockers;
|
||||||
const cabinetId = location.state?.cabinetId;
|
const cabinetId = location.state?.cabinetId;
|
||||||
const [submitting, setSubmitting] = useState(false);
|
|
||||||
const [notification, setNotification] = useState({
|
|
||||||
message: "",
|
|
||||||
type: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const initLockers = Array(noOfLockers ? parseInt(noOfLockers) : 0)
|
const initLockers = Array(noOfLockers ? parseInt(noOfLockers) : 0)
|
||||||
.fill()
|
.fill()
|
||||||
@ -31,12 +29,14 @@ function LockersRegistration() {
|
|||||||
sizeValid: true,
|
sizeValid: true,
|
||||||
keyIdValid: true,
|
keyIdValid: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const [lockerValues, setLockerValues] = useState(initLockers);
|
const [lockerValues, setLockerValues] = useState(initLockers);
|
||||||
if(!location.state) {
|
|
||||||
return <></>
|
if (!location.state) {
|
||||||
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
console.log("submitting");
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const idRegex = /^[A-Z]{2}[0-9]{4}$/;
|
const idRegex = /^[A-Z]{2}[0-9]{4}$/;
|
||||||
let valid = true;
|
let valid = true;
|
||||||
@ -92,16 +92,10 @@ function LockersRegistration() {
|
|||||||
setLockerValues(newValues);
|
setLockerValues(newValues);
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const errorMessage =
|
|
||||||
duplicateLockerIds.length || duplicateKeyIds.length
|
|
||||||
? "Please ensure all IDs are unique."
|
|
||||||
: "Inavlid Ids";
|
|
||||||
showToast(errorMessage, "error");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setSubmitting(true);
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const response = await lockerService.registerLockers(
|
const response = await lockerService.registerLockers(
|
||||||
cabinetId,
|
cabinetId,
|
||||||
@ -120,84 +114,50 @@ function LockersRegistration() {
|
|||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setSubmitting(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const lockerDetails = lockerValues.map((locker, index) => {
|
const lockerDetails = lockerValues.map((locker, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} className="flex gap-12 items-center">
|
<FormField key={index} label={`Locker ${index + 1}`} variant="long">
|
||||||
<label className="text-lg text-bold dark:text-primary-dark">{`Locker ${
|
<FormInput
|
||||||
index + 1
|
|
||||||
}`}</label>
|
|
||||||
|
|
||||||
<input
|
|
||||||
value={locker.id}
|
value={locker.id}
|
||||||
disabled={submitting}
|
onChange={ e => {
|
||||||
className={clsx(
|
|
||||||
"w-64 h-9 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey",
|
|
||||||
!locker.idValid && "border-error text-error"
|
|
||||||
)}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newValues = [...lockerValues];
|
const newValues = [...lockerValues];
|
||||||
newValues[index] = {
|
newValues[index].id = e.target.value;
|
||||||
...newValues[index],
|
newValues[index].idValid = true;
|
||||||
id: e.target.value.toUpperCase(),
|
|
||||||
idValid: true,
|
|
||||||
};
|
|
||||||
setLockerValues(newValues);
|
setLockerValues(newValues);
|
||||||
}}
|
}}
|
||||||
placeholder="Locker ID"
|
valid={locker.idValid}
|
||||||
type="text"
|
placeholder={"Locker Id"}
|
||||||
maxLength={6}
|
|
||||||
/>
|
/>
|
||||||
|
<FormSelect
|
||||||
<select
|
|
||||||
value={locker.size}
|
value={locker.size}
|
||||||
disabled={submitting}
|
onChange={e => {
|
||||||
className={clsx(
|
|
||||||
"w-64 h-9 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey",
|
|
||||||
!locker.sizeValid && "border-error"
|
|
||||||
)}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newValues = [...lockerValues];
|
const newValues = [...lockerValues];
|
||||||
newValues[index] = {
|
newValues[index].size = e.target.value;
|
||||||
...newValues[index],
|
newValues[index].sizeValid = true;
|
||||||
size: e.target.value,
|
|
||||||
sizeValid: true,
|
|
||||||
};
|
|
||||||
setLockerValues(newValues);
|
setLockerValues(newValues);
|
||||||
}}
|
}}
|
||||||
>
|
valid={locker.sizeValid}
|
||||||
<option value="" disabled>
|
options={[
|
||||||
Size
|
{label: 'Small', value: '1'},
|
||||||
</option>
|
{label: 'Medium', value: '2'},
|
||||||
<option value="small">Small</option>
|
{label: 'Large', value: '3'}
|
||||||
<option value="medium">Medium</option>
|
]}
|
||||||
<option value="large">Large</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input
|
|
||||||
value={locker.keyId}
|
|
||||||
disabled={submitting}
|
|
||||||
className={clsx(
|
|
||||||
"w-64 h-9 px-2 rounded-full dark:bg-white dark:text-grey border-2 text-grey focus:outline-grey",
|
|
||||||
!locker.keyIdValid && "border-error"
|
|
||||||
)}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newValues = [...lockerValues];
|
|
||||||
newValues[index] = {
|
|
||||||
...newValues[index],
|
|
||||||
keyId: e.target.value.toUpperCase(),
|
|
||||||
keyIdValid: true,
|
|
||||||
};
|
|
||||||
setLockerValues(newValues);
|
|
||||||
}}
|
|
||||||
placeholder="Key ID"
|
|
||||||
type="text"
|
|
||||||
maxLength={6}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
<FormInput
|
||||||
|
value={locker.keyId}
|
||||||
|
onChange={ e => {
|
||||||
|
const newValues = [...lockerValues];
|
||||||
|
newValues[index].keyId = e.target.value;
|
||||||
|
newValues[index].keyIdValid = true;
|
||||||
|
setLockerValues(newValues);
|
||||||
|
}}
|
||||||
|
valid={locker.keyIdValid}
|
||||||
|
placeholder={"Locker Key Id"}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -210,13 +170,12 @@ function LockersRegistration() {
|
|||||||
{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" disabled={submitting}>
|
<FormBox title="Locker Registration">
|
||||||
<div className="px-4 pt-7 text-2xl font-bold text-primary dark:text-primary-dark">
|
<div className="px-4 pt-7 text-2xl font-bold text-primary dark:text-primary-dark">
|
||||||
{cabinetId}
|
{cabinetId}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4 p-4">{lockerDetails}</div>
|
<div className="flex flex-col gap-4 p-4">{lockerDetails}</div>
|
||||||
<Button
|
<Button
|
||||||
disabled={submitting}
|
|
||||||
text="Register"
|
text="Register"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
handleSubmit(e);
|
handleSubmit(e);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user