setup organization modal, it seprated form another becuase this modal can open anywhere at one hook
This commit is contained in:
parent
18698a67e3
commit
012a89b3ea
@ -4,6 +4,7 @@ import { ToastContainer } from "react-toastify";
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||
import { queryClient } from "./layouts/AuthLayout";
|
||||
import ModalProvider from "./ModalProvider";
|
||||
|
||||
|
||||
|
||||
@ -11,6 +12,7 @@ const App = () => {
|
||||
return (
|
||||
<div className="app">
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ModalProvider/>
|
||||
<DireProvider>
|
||||
<AppRoutes />
|
||||
</DireProvider>
|
||||
|
@ -1,112 +0,0 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
|
||||
const ModalContext = createContext();
|
||||
|
||||
export const useModal = () => useContext(ModalContext);
|
||||
|
||||
// ModalProvider to manage modal state and expose functionality to the rest of the app
|
||||
export const ModalProvider = ({ children }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [modalContent, setModalContent] = useState(null);
|
||||
const [onSubmit, setOnSubmit] = useState(null);
|
||||
const [modalSize, setModalSize] = useState("lg");
|
||||
|
||||
// Ref to track the modal content element
|
||||
const modalRef = useRef(null);
|
||||
|
||||
const openModal = (content, onSubmitCallback, size = "lg") => {
|
||||
setModalContent(content); // Set modal content dynamically
|
||||
setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically
|
||||
setIsOpen(true); // Open the modal
|
||||
setModalSize(size); // Set the modal size
|
||||
};
|
||||
|
||||
// Function to close the modal
|
||||
const closeModal = () => {
|
||||
setIsOpen(false); // Close the modal
|
||||
setModalContent(null); // Clear modal content
|
||||
setOnSubmit(null); // Clear the submit callback
|
||||
setModalSize("lg"); // Reset modal size
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleEscape = (event) => {
|
||||
if (event.key === "Escape") {
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", handleEscape);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleEscape);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
if (modalRef.current && !modalRef.current.contains(event.target)) {
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ModalContext.Provider
|
||||
value={{
|
||||
isOpen,
|
||||
openModal,
|
||||
closeModal,
|
||||
modalContent,
|
||||
modalSize,
|
||||
onSubmit,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
{isOpen && (
|
||||
<div style={overlayStyles}>
|
||||
<div
|
||||
ref={modalRef}
|
||||
style={{
|
||||
...modalStyles,
|
||||
maxWidth: modalSize === "sm" ? "400px" : "800px",
|
||||
}}
|
||||
>
|
||||
<div>{modalContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const overlayStyles = {
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 1050,
|
||||
};
|
||||
|
||||
const modalStyles = {
|
||||
backgroundColor: "white",
|
||||
padding: "20px",
|
||||
borderRadius: "5px",
|
||||
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
||||
width: "90%",
|
||||
maxWidth: "800px",
|
||||
};
|
14
src/ModalProvider.jsx
Normal file
14
src/ModalProvider.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react'
|
||||
import Modal from './components/common/Modal'
|
||||
import ManageOrganization from './components/Organization/ManageOrganization'
|
||||
|
||||
const ModalProvider = () => {
|
||||
return (
|
||||
<>
|
||||
|
||||
<ManageOrganization/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalProvider
|
76
src/components/Organization/ManageOrganization.jsx
Normal file
76
src/components/Organization/ManageOrganization.jsx
Normal file
@ -0,0 +1,76 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import React from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import {
|
||||
defaultOrganizationValues,
|
||||
organizationSchema,
|
||||
} from "./OrganizationSchema";
|
||||
import Modal from "../common/Modal";
|
||||
import { useOrganization } from "../../hooks/useDirectory";
|
||||
import { useOrganizationModal } from "../../hooks/useOrganization";
|
||||
import Label from "../common/Label";
|
||||
|
||||
const ManageOrganization = () => {
|
||||
const orgModal = useOrganizationModal();
|
||||
const method = useForm({
|
||||
resolver: zodResolver(organizationSchema),
|
||||
defaultValues: defaultOrganizationValues,
|
||||
});
|
||||
|
||||
const { handleSubmit, watch, register } = method;
|
||||
|
||||
const onSubmit = () => {};
|
||||
|
||||
const contentBody = (
|
||||
<FormProvider {...method}>
|
||||
<form className="form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organization" required>
|
||||
Organization Name
|
||||
</Label>
|
||||
<input className="form-control form-control-sm" />
|
||||
</div>
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organization" required>
|
||||
Contact Person
|
||||
</Label>
|
||||
<input className="form-control form-control-sm" />
|
||||
</div>
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organization" required>
|
||||
Contact Number
|
||||
</Label>
|
||||
<input className="form-control form-control-sm" />
|
||||
</div>
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organization" required>
|
||||
Email Address
|
||||
</Label>
|
||||
<input className="form-control form-control-sm" />
|
||||
</div>
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organization" required>
|
||||
Address
|
||||
</Label>
|
||||
<textarea className="form-control form-control-sm" rows={2} />
|
||||
</div>
|
||||
<div className="d-flex justify-content-end gap-2 my-2">
|
||||
<button className="btn btn-sm btn-secondary">Cancel</button>
|
||||
<button className="btn btn-sm btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
return (
|
||||
<Modal
|
||||
isOpen={orgModal.isOpen}
|
||||
onClose={orgModal.onClose}
|
||||
onSubmit={onSubmit}
|
||||
title={"Manage organization"}
|
||||
actionLabel={"Submit"}
|
||||
body={contentBody}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManageOrganization;
|
32
src/components/Organization/OrganizationSchema.js
Normal file
32
src/components/Organization/OrganizationSchema.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { array, z } from "zod";
|
||||
|
||||
const phoneRegex = /^\+?[1-9]\d{6,14}$/;
|
||||
|
||||
export const organizationSchema = z.object({
|
||||
organizationName: z.string().min(1, { message: "Name is required" }),
|
||||
contactPhone: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(7)
|
||||
.max(20)
|
||||
.regex(phoneRegex, { message: "Invalid phone number" }),
|
||||
contactPerson: z.string().min(1, { message: "Person name required" }),
|
||||
address: z.string().min(1, { message: "Address is required!" }),
|
||||
email: z
|
||||
.string()
|
||||
.min(1, { message: "Email is required" })
|
||||
.email("Invalid email address"),
|
||||
listOfServiceId: z
|
||||
.array(z.string())
|
||||
.min(1, { message: "Please insert service id" }),
|
||||
});
|
||||
|
||||
|
||||
export const defaultOrganizationValues = {
|
||||
organizationSchema:"",
|
||||
contactPhone:"",
|
||||
contactPerson:"",
|
||||
address:"",
|
||||
email:"",
|
||||
listOfServiceId:[]
|
||||
}
|
@ -1,26 +1,21 @@
|
||||
import XIcon from "@/assets/XIcons";
|
||||
|
||||
import { useCallback } from "react";
|
||||
import Button from "./Button";
|
||||
|
||||
const Modal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSubmit,
|
||||
title,
|
||||
body,
|
||||
footer,
|
||||
actionLabel,
|
||||
disabled,
|
||||
size="md",
|
||||
position="top",
|
||||
}) => {
|
||||
const handleClose = useCallback(() => {
|
||||
if (disabled) return;
|
||||
onClose();
|
||||
}, [disabled, onClose]);
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
if (disabled) return;
|
||||
onSubmit();
|
||||
}, [disabled, onSubmit]);
|
||||
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
@ -31,10 +26,10 @@ const Modal = ({
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
>
|
||||
<div className="modal-dialog modal-lg modal-dialog-centered" role="document">
|
||||
<div className="modal-content bg-dark text-white shadow-lg">
|
||||
<div className={`modal-dialog modal-${size} modal-dialog-${position}`} role="document">
|
||||
<div className="modal-content text-white shadow-lg">
|
||||
{/* Header */}
|
||||
<div className="modal-header border-0">
|
||||
<div className="modal-header pb-2 border-0">
|
||||
<h5 className="modal-title">{title}</h5>
|
||||
<button
|
||||
type="button"
|
||||
@ -42,25 +37,15 @@ const Modal = ({
|
||||
onClick={handleClose}
|
||||
aria-label="Close"
|
||||
>
|
||||
<XIcon color="white" size={20} />
|
||||
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="modal-body">{body}</div>
|
||||
<div className="modal-body pt-0">{body}</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="modal-footer border-0 d-flex flex-column gap-2">
|
||||
<Button
|
||||
disabled={disabled}
|
||||
secondary
|
||||
fullWidth
|
||||
large
|
||||
label={actionLabel}
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
{footer}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { toggleOrgModal,openOrgModal,closeOrgModal } from "../slices/localVariablesSlice";
|
||||
|
||||
|
||||
export const useOrganizationModal = () => {
|
||||
const dispatch = useDispatch();
|
||||
const isOpen = useSelector((state) => state.localVariables.OrganizationModal.isOpen);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
onOpen: () => dispatch(openOrgModal()),
|
||||
onClose: () => dispatch(closeOrgModal()),
|
||||
Togggle:()=> dispatch(toggleOrgModal(isOpen))
|
||||
};
|
||||
};
|
||||
|
@ -2,11 +2,9 @@
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
// import { MasterDataProvider } from "./provider/MasterDataContext";
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './store/store';
|
||||
import { ModalProvider } from './ModalContext.jsx';
|
||||
import { ChangePasswordProvider } from './components/Context/ChangePasswordContext.jsx';
|
||||
import { ModalProvider1 } from './pages/Gallary/ModalContext.jsx';
|
||||
|
||||
@ -15,15 +13,12 @@ createRoot(document.getElementById('root')!).render(
|
||||
// <StrictMode>
|
||||
// <MasterDataProvider>
|
||||
<Provider store={ store }>
|
||||
<ModalProvider>
|
||||
<ChangePasswordProvider >
|
||||
<ModalProvider1>
|
||||
<App />
|
||||
</ModalProvider1>
|
||||
</ChangePasswordProvider>
|
||||
</ModalProvider>
|
||||
</Provider>
|
||||
// </MasterDataProvider>
|
||||
|
||||
// </StrictMode>,
|
||||
)
|
||||
|
@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||
import { useOrganizationModal } from "../../hooks/useOrganization";
|
||||
|
||||
const OrganizationPage = () => {
|
||||
const orgModal = useOrganizationModal()
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<Breadcrumb
|
||||
data={[{ label: "Home", link: "/" }, { label: "Organizations" }]}
|
||||
/>
|
||||
<div className="card my-3 px-sm-2 px-0">
|
||||
<div className="card-body py-2 px-3">
|
||||
<div className="row align-items-center">
|
||||
<div className="col-6 ">
|
||||
<div className="d-flex align-items-center">
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm w-auto"
|
||||
placeholder="Search Organization"
|
||||
aria-describedby="search-label"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-6 text-end mt-2 mt-sm-0">
|
||||
<button
|
||||
type="button"
|
||||
className="p-1 me-1 m-sm-0 bg-primary rounded-circle"
|
||||
title="Add New Organization"
|
||||
onClick={()=>orgModal.onOpen()}
|
||||
>
|
||||
<i className="bx bx-plus fs-4 text-white"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrganizationPage;
|
@ -49,7 +49,9 @@ import MainResetPasswordPage from "../pages/authentication/MainResetPasswordPage
|
||||
import TenantPage from "../pages/Tenant/TenantPage";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import CreateTenant from "../pages/Tenant/CreateTenant";
|
||||
import LandingPage from "../pages/Home/LandingPage";
|
||||
import SuperTenantDetails from "../pages/Tenant/SuperTenantDetails";
|
||||
import SelfTenantDetails from "../pages/Tenant/SelfTenantDetails";
|
||||
import OrganizationPage from "../pages/Organization/OrganizationPage";
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
{
|
||||
@ -96,6 +98,7 @@ const router = createBrowserRouter(
|
||||
{ path: "/tenants/new-tenant", element: <CreateTenant /> },
|
||||
{ path: "/tenant/:tenantId", element: <SuperTenantDetails /> },
|
||||
{ path: "/tenant/self", element: <SelfTenantDetails /> },
|
||||
{ path: "/organizations", element: <OrganizationPage /> },
|
||||
{ path: "/help/support", element: <Support /> },
|
||||
{ path: "/help/docs", element: <Documentation /> },
|
||||
{ path: "/help/connect", element: <Connect /> },
|
||||
|
@ -49,5 +49,5 @@ const localVariablesSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { changeMaster ,updateRegularizationCount,setProjectId,refreshData,setDefaultDateRange} = localVariablesSlice.actions;
|
||||
export const { changeMaster ,updateRegularizationCount,setProjectId,refreshData,setDefaultDateRange,openOrgModal,closeOrgModal,toggleOrgModal} = localVariablesSlice.actions;
|
||||
export default localVariablesSlice.reducer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user