Update done
This commit is contained in:
parent
7c1ec18262
commit
153cb984df
@ -31,7 +31,7 @@ const RadioInput: React.FC<Props> = ({ options = [], name, onChange }) => {
|
||||
<label
|
||||
id={name}
|
||||
className={classNames(
|
||||
"flex font-semibold items-center space-x-2",
|
||||
"flex items-center space-x-2",
|
||||
option?.disabled ? "text-[#8A8A8A]" : ""
|
||||
)}
|
||||
>
|
||||
|
284
src/components/atoms/ReactDoesMultiSelectInput.tsx
Normal file
284
src/components/atoms/ReactDoesMultiSelectInput.tsx
Normal file
@ -0,0 +1,284 @@
|
||||
import { ErrorMessage, useField } from "formik";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
interface Option {
|
||||
label: {
|
||||
name: string;
|
||||
mobile: string;
|
||||
nid: string;
|
||||
brn: string;
|
||||
};
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface DropdownProps {
|
||||
options: Option[];
|
||||
onChange?: (selectedOptions: any) => void;
|
||||
isArray?: boolean;
|
||||
disabled?: boolean;
|
||||
hidePills?: boolean;
|
||||
disableSelectAll?: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const ReactDoesMultiSelectInput: React.FC<DropdownProps> = ({
|
||||
name,
|
||||
options,
|
||||
onChange,
|
||||
hidePills = false,
|
||||
disableSelectAll = false,
|
||||
}) => {
|
||||
const showPillsSection = !hidePills;
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const [searchTerm, setSearchTerm] = useState<string>("");
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const [field, , helpers] = useField(name);
|
||||
|
||||
const fieldValues = field.value ?? "";
|
||||
const isArray = Array.isArray(fieldValues);
|
||||
const processedFieldValue = isArray ? fieldValues : fieldValues.split(",");
|
||||
|
||||
const selectedOptions = options.filter((item) =>
|
||||
processedFieldValue.includes(item.value)
|
||||
);
|
||||
|
||||
const handleOnChange = (selectedData: any) => {
|
||||
const value = isArray ? selectedData : selectedData.join(",");
|
||||
helpers.setValue(value);
|
||||
if (typeof onChange === "function") {
|
||||
onChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOption = (option: Option) => {
|
||||
const index = selectedOptions.findIndex(
|
||||
(selectedOption) => selectedOption.value === option.value
|
||||
);
|
||||
|
||||
if (index === -1) {
|
||||
handleOnChange([...processedFieldValue, option.value].filter((i) => i));
|
||||
} else {
|
||||
handleOnChange(
|
||||
processedFieldValue.filter(
|
||||
(selectedOption: any) => selectedOption !== option.value
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOptionClick = (
|
||||
event: React.MouseEvent<HTMLDivElement>,
|
||||
option: Option
|
||||
) => {
|
||||
event.stopPropagation(); // Prevents event from propagating to parent elements
|
||||
toggleOption(option);
|
||||
// setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleSelectAll = () => {
|
||||
let selectedData;
|
||||
if (searchTerm) {
|
||||
selectedData = filteredOptions.map((item) => item.value);
|
||||
} else {
|
||||
selectedData = options.map((item) => item.value);
|
||||
}
|
||||
handleOnChange(selectedData);
|
||||
};
|
||||
|
||||
const handleClearAll = () => {
|
||||
handleOnChange([]);
|
||||
};
|
||||
|
||||
const filteredOptions = options.filter((option) =>
|
||||
option.label.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<fieldset>
|
||||
<div className="space-y-1" ref={dropdownRef}>
|
||||
<div className="relative block text-left w-full">
|
||||
<div className="rounded-md shadow-sm flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
className={`flex w-full rounded-md border z-30 border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:border-blue-300 focus:ring focus:ring-blue-200 ${
|
||||
showPillsSection ? "justify-start" : "justify-start"
|
||||
}`}
|
||||
onClick={() => setIsOpen((prev) => !prev)}
|
||||
>
|
||||
{showPillsSection ? (
|
||||
<>
|
||||
<span className="flex gap-1 flex-wrap w-full max-h-24 overflow-auto">
|
||||
{selectedOptions.map((option, index) => (
|
||||
<div className="flex" key={index}>
|
||||
<div className=" bg-slate-200 py-[1px] px-1 text-[12px] rounded rounded-tr-none rounded-br-none">
|
||||
{option.label.name}
|
||||
</div>
|
||||
<div
|
||||
className="group flex items-center bg-slate-300 hover:bg-red-200 rounded-tr rounded-br px-[2px]"
|
||||
onClick={(event) => handleOptionClick(event, option)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={2}
|
||||
stroke="currentColor"
|
||||
className="w-4 h-4 group-hover:text-red-800"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 18 18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{selectedOptions.length === 0 && (
|
||||
<p className="text-start">Select options</p>
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<span>
|
||||
{selectedOptions.length > 0 ? (
|
||||
<span>
|
||||
{selectedOptions.length > 0
|
||||
? `Selected ${selectedOptions.length} of ${options.length}`
|
||||
: "Select"}
|
||||
</span>
|
||||
) : (
|
||||
<p className="text-start">Select options</p>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{isOpen && (
|
||||
<>
|
||||
<div
|
||||
className={`origin-top-right z-50 absolute right-0 mt-2 w-full rounded-md shadow-lg border-blue-300 bg-slate-50 ring-1 ring-black ring-opacity-5 focus:outline-none`}
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
>
|
||||
<div className="p-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
className="border rounded-md px-2 py-1 text-sm w-full focus:outline-none focus:border-blue-300 focus:ring focus:ring-blue-200"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="pb-1 max-h-60 overflow-auto" role="none">
|
||||
{!disableSelectAll && (
|
||||
<div className="block w-full text-center border-b px-4 py-2 text-sm hover:bg-gray-100">
|
||||
{filteredOptions.length === 0 ? (
|
||||
"No options"
|
||||
) : selectedOptions.length > 0 ? (
|
||||
<div className="text-left" onClick={handleClearAll}>
|
||||
Clear All
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-left" onClick={handleSelectAll}>
|
||||
Select All
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredOptions.map((option) => (
|
||||
<div
|
||||
key={option.value}
|
||||
className={`block w-full text-left px-4 py-2 text-sm border-b last:border-b-0 hover:cursor-pointer ${
|
||||
selectedOptions.some(
|
||||
(selectedOption) =>
|
||||
selectedOption.value === option.value
|
||||
)
|
||||
? "bg-blue-100 border-blue-400"
|
||||
: "hover:bg-gray-100"
|
||||
}`}
|
||||
role="menuitem"
|
||||
onClick={(event) => handleOptionClick(event, option)}
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedOptions.some(
|
||||
(selectedOption) =>
|
||||
selectedOption.value === option.value
|
||||
)}
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<p> {option.label.name}</p>
|
||||
{option.label.mobile && (
|
||||
<p> Mobile: {option.label.mobile}</p>
|
||||
)}
|
||||
{option.label.nid && (
|
||||
<p> NID: {option.label.nid}</p>
|
||||
)}
|
||||
{option.label.brn && (
|
||||
<p> BRN: {option.label.brn}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{selectedOptions.some(
|
||||
(selectedOption) =>
|
||||
selectedOption.value === option.value
|
||||
) && (
|
||||
<div
|
||||
className="group"
|
||||
onClick={(event) =>
|
||||
handleOptionClick(event, option)
|
||||
}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={2}
|
||||
stroke="currentColor"
|
||||
className="w-4 h-4 group-hover:text-red-800"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M6 18 18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<small className="text-red-500">
|
||||
<ErrorMessage name={name} />
|
||||
</small>
|
||||
</div>
|
||||
</fieldset>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReactDoesMultiSelectInput;
|
56
src/components/molecules/FormikDoseMultiReactSelect.tsx
Normal file
56
src/components/molecules/FormikDoseMultiReactSelect.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import InputWrapper from "../atoms/InputWrapper";
|
||||
import ReactDoesMultiSelectInput from "../atoms/ReactDoesMultiSelectInput";
|
||||
type Props = {
|
||||
label: string;
|
||||
isRequired?: boolean;
|
||||
horizontal?: boolean;
|
||||
name: string;
|
||||
disabled?: boolean;
|
||||
isArray?: boolean;
|
||||
hidePills?: boolean;
|
||||
disableSelectAll?: boolean;
|
||||
options: {
|
||||
label: {
|
||||
name: string;
|
||||
mobile: string;
|
||||
nid: string;
|
||||
brn: string;
|
||||
};
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
onChange?: (selectedOptions: any) => void;
|
||||
};
|
||||
const FormikDoseMultiReactSelect: React.FC<Props> = ({
|
||||
label,
|
||||
options,
|
||||
isRequired = false,
|
||||
disabled = false,
|
||||
horizontal = false,
|
||||
isArray = false,
|
||||
hidePills = false,
|
||||
disableSelectAll = false,
|
||||
name,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<InputWrapper
|
||||
isRequired={isRequired}
|
||||
label={label}
|
||||
disabled={disabled}
|
||||
horizontal={horizontal}
|
||||
>
|
||||
<ReactDoesMultiSelectInput
|
||||
isArray={isArray}
|
||||
name={name}
|
||||
options={options}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
disableSelectAll={disableSelectAll}
|
||||
hidePills={hidePills}
|
||||
/>
|
||||
</InputWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormikDoseMultiReactSelect;
|
@ -1,2 +1,2 @@
|
||||
import * as yup from "yup";
|
||||
export const YUP = yup;
|
||||
export const YUP: any = yup;
|
||||
|
@ -55,8 +55,8 @@ const OCVDoseList = ({
|
||||
<ScrollToTop />
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-end">
|
||||
<Link to="/ocv-management/dose-1-form">
|
||||
<SubmitBtn title="Dose 1 Form" />
|
||||
<Link to={`/ocv-management/dose-${numOfDose}-form`}>
|
||||
<SubmitBtn title={`Dose ${numOfDose} Form`} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="bg-white px-3 py-6 rounded-2xl">
|
||||
|
269
src/pages/ocvManagement/dose2Fom/Dose2Form.tsx
Normal file
269
src/pages/ocvManagement/dose2Fom/Dose2Form.tsx
Normal file
@ -0,0 +1,269 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { Form, Formik } from "formik";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import useOcvManagement from "../../../apis/useOcvManagement";
|
||||
import DangerAlert from "../../../components/atoms/DangerAlert";
|
||||
import ScrollToTop from "../../../components/atoms/ScrollToTop";
|
||||
import SubmitBtn from "../../../components/atoms/SubmitBtn";
|
||||
import FormikDoseMultiReactSelect from "../../../components/molecules/FormikDoseMultiReactSelect";
|
||||
import FormikRadio from "../../../components/molecules/FormikRadio";
|
||||
import FormikText from "../../../components/molecules/FormikText";
|
||||
import { YUP as Yup } from "../../../constant/yup";
|
||||
import Sidebar from "../../../layouts/Sidebar";
|
||||
import OcvLocationManagement from "../components/OcvLocationManagement";
|
||||
|
||||
const initialFormValues = {
|
||||
type: "location", // can be 'location' or 'identity'
|
||||
division: "",
|
||||
district: "",
|
||||
upazila: "",
|
||||
paurasava: "",
|
||||
union_name: "",
|
||||
ward: "",
|
||||
id: "",
|
||||
};
|
||||
|
||||
const Dose2Form = () => {
|
||||
const [isFormVisible, setFormVisible] = useState(true); // State to toggle form visibility
|
||||
const [formKey, setFormKey] = useState(0); // State to force form reset
|
||||
const { updateSecondOcvDoses, ocvDosesList } = useOcvManagement();
|
||||
|
||||
// Mutation for fetching doses list
|
||||
const {
|
||||
isLoading: isLoadingDoses,
|
||||
error: dosesError,
|
||||
mutateAsync: fetchOcvDoses,
|
||||
data: dosesData = [],
|
||||
} = useMutation(ocvDosesList, {
|
||||
onSuccess: () => setFormVisible(false), // Hide form when data is successfully fetched
|
||||
});
|
||||
|
||||
// Mutation for updating the second OCV doses
|
||||
const {
|
||||
isLoading: isLoadingUpdate,
|
||||
error: updateError,
|
||||
mutateAsync: updateSecondDose,
|
||||
} = useMutation(updateSecondOcvDoses, {
|
||||
onSuccess: () => {
|
||||
toast.success("Dose updated successfully");
|
||||
},
|
||||
});
|
||||
|
||||
// Helper function to extract ID from string (split by "___")
|
||||
const extractID = (data: string) => data?.split("___")[0] ?? "";
|
||||
|
||||
// Handle form submission for registering second dose
|
||||
const handleSecondDoseSubmit = async (values: any) => {
|
||||
const payload = {
|
||||
divison_id: extractID(values.division),
|
||||
district_id: extractID(values.district),
|
||||
paurasava_id: extractID(values.paurasava),
|
||||
union_id: extractID(values.union_name),
|
||||
upazila_id: extractID(values.upazila),
|
||||
ward_id: extractID(values.ward),
|
||||
dose: 2,
|
||||
id: values.id,
|
||||
};
|
||||
await fetchOcvDoses(payload);
|
||||
};
|
||||
|
||||
// Handle form submission for updating dose details
|
||||
const handleUpdateDoseSubmit = async (values: any) => {
|
||||
const { beneficiary, date } = values;
|
||||
const ids = beneficiary.split(",").map((id: string) => ({
|
||||
id: Number(id),
|
||||
date,
|
||||
}));
|
||||
await updateSecondDose(ids);
|
||||
};
|
||||
|
||||
// Function to reset form and display initial form again
|
||||
const handleAddNew = () => {
|
||||
setFormKey((prevKey) => prevKey + 1); // Force reset Formik form
|
||||
setFormVisible(true); // Show the initial form again
|
||||
};
|
||||
|
||||
return (
|
||||
<Sidebar title="Dose 2 Form">
|
||||
<ScrollToTop />
|
||||
<div className="space-y-4">
|
||||
{isFormVisible ? (
|
||||
// Render the form if no data has been fetched
|
||||
<div className="bg-white px-8 py-8 rounded-2xl shadow-sm space-y-4 max-w-3xl mx-auto">
|
||||
<p className="text-center font-semibold">
|
||||
Register 2nd Dose Beneficiary
|
||||
</p>
|
||||
|
||||
<Formik
|
||||
key={formKey} // Use key to force a full form reset when necessary
|
||||
initialValues={initialFormValues}
|
||||
onSubmit={handleSecondDoseSubmit}
|
||||
// validationSchema={Yup.object({
|
||||
// type: Yup.string()
|
||||
// .oneOf(
|
||||
// ["location", "identity"],
|
||||
// "Type must be either location or identity"
|
||||
// )
|
||||
// .required("Type is required"),
|
||||
// id: Yup.string()
|
||||
// .required("ID is required")
|
||||
// .test(
|
||||
// "id-required",
|
||||
// "ID is required when type is identity",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "identity" ? !!value : true; // Required if type is 'identity'
|
||||
// }
|
||||
// ),
|
||||
// division: Yup.string().test(
|
||||
// "division-required",
|
||||
// "Division is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// district: Yup.string().test(
|
||||
// "district-required",
|
||||
// "District is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// upazila: Yup.string().test(
|
||||
// "upazila-required",
|
||||
// "Upazila is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// paurasava: Yup.string().test(
|
||||
// "paurasava-required",
|
||||
// "Paurasava is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// union_name: Yup.string().test(
|
||||
// "union-name-required",
|
||||
// "Union name is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// ward: Yup.string().test(
|
||||
// "ward-required",
|
||||
// "Ward is required when type is location",
|
||||
// function (value: any) {
|
||||
// const { type } = this.parent as FormData; // Ensure type safety
|
||||
// return type === "location" ? !!value : true; // Required if type is 'location'
|
||||
// }
|
||||
// ),
|
||||
// })}
|
||||
enableReinitialize
|
||||
>
|
||||
{({ values }) => (
|
||||
<fieldset disabled={isLoadingDoses}>
|
||||
<Form className="space-y-8">
|
||||
<DangerAlert error={dosesError} />
|
||||
|
||||
<FormikRadio
|
||||
label="Identification Type"
|
||||
isRequired
|
||||
name="type"
|
||||
options={[
|
||||
{ label: "By Area", value: "location" },
|
||||
{
|
||||
label: "By NID/BRN/Mobile Number",
|
||||
value: "identity",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{values.type === "location" ? (
|
||||
<>
|
||||
<p className="font-medium underline">Location</p>
|
||||
<OcvLocationManagement />
|
||||
</>
|
||||
) : (
|
||||
<FormikText label="NID/BRN/Mobile Number" name="id" />
|
||||
)}
|
||||
|
||||
<div className="flex justify-around items-center gap-4">
|
||||
<SubmitBtn title="Searchss" loading={isLoadingDoses} />
|
||||
</div>
|
||||
</Form>
|
||||
</fieldset>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
) : (
|
||||
// Render this section if data has been fetched
|
||||
dosesData.length > 0 && (
|
||||
<div className="bg-white px-8 py-8 rounded-2xl shadow-sm space-y-4 max-w-3xl mx-auto">
|
||||
<Formik
|
||||
initialValues={{ beneficiary: "", date: "" }}
|
||||
onSubmit={handleUpdateDoseSubmit}
|
||||
enableReinitialize
|
||||
validationSchema={Yup.object({
|
||||
beneficiary: Yup.string().required("Beneficiary is required"),
|
||||
date: Yup.string().required("Date is required"),
|
||||
})}
|
||||
>
|
||||
{() => (
|
||||
<fieldset disabled={isLoadingUpdate}>
|
||||
<Form className="space-y-8">
|
||||
<DangerAlert error={updateError} />
|
||||
|
||||
<FormikDoseMultiReactSelect
|
||||
label="Choose Beneficiary"
|
||||
isRequired
|
||||
name="beneficiary"
|
||||
options={dosesData.map(
|
||||
(item: {
|
||||
id: number;
|
||||
firstName: string;
|
||||
mobile: string;
|
||||
nid: string;
|
||||
brn: string;
|
||||
}) => ({
|
||||
value: String(item.id),
|
||||
label: {
|
||||
name: item.firstName,
|
||||
mobile: item.mobile ?? "",
|
||||
nid: item.nid,
|
||||
brn: item.brn,
|
||||
},
|
||||
})
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormikText label="Date" name="date" type="date" />
|
||||
|
||||
<div className="flex justify-around items-center gap-4">
|
||||
<SubmitBtn title="Submit" loading={isLoadingUpdate} />
|
||||
<SubmitBtn
|
||||
title="Add New"
|
||||
loading={isLoadingUpdate}
|
||||
secondary
|
||||
click={handleAddNew}
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
</fieldset>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</Sidebar>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dose2Form;
|
@ -30,6 +30,7 @@ import DoseDetailsPage from "../pages/ocvManagement/DoseDetailsPage.tsx";
|
||||
import OCVDose1List from "../pages/ocvManagement/OCVDose1List.tsx";
|
||||
import OCVDose2List from "../pages/ocvManagement/OCVDose2List.tsx";
|
||||
import Dose1Form from "../pages/ocvManagement/dose1Fom/Dose1Form.tsx";
|
||||
import Dose2Form from "../pages/ocvManagement/dose2Fom/Dose2Form.tsx";
|
||||
import Dashboard from "../pages/stages/Dashboard.tsx";
|
||||
import Login from "../pages/stages/Login";
|
||||
import { ROLES } from "./authRoutes";
|
||||
@ -161,6 +162,18 @@ const routes: RouteInterface[] = [
|
||||
ROLES.UPAZILA_MANAGER,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/ocv-management/dose-2-form",
|
||||
element: <Dose2Form />,
|
||||
isPublic: false,
|
||||
isProtected: true,
|
||||
roles: [
|
||||
ROLES.ADMIN,
|
||||
ROLES.MANAGER,
|
||||
ROLES.DATA_MANAGER,
|
||||
ROLES.UPAZILA_MANAGER,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/ocv-management/dose-1-list",
|
||||
element: <OCVDose1List />,
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"noImplicitAny": false,
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
@ -20,6 +21,7 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user