configured tenant level login
This commit is contained in:
parent
aee510f527
commit
b9b3788dda
@ -1,12 +1,19 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from "react";
|
||||||
import { useOrganizationModal } from './hooks/useOrganization';
|
import { useOrganizationModal } from "./hooks/useOrganization";
|
||||||
import OrganizationModal from './components/Organization/OrganizationModal';
|
import OrganizationModal from "./components/Organization/OrganizationModal";
|
||||||
|
import { useAuthModal } from "./hooks/useAuth";
|
||||||
|
import SwitchTenant from "./pages/authentication/SwitchTenant";
|
||||||
|
|
||||||
const ModalProvider = () => {
|
const ModalProvider = () => {
|
||||||
const { isOpen,onClose } = useOrganizationModal();
|
const { isOpen, onClose } = useOrganizationModal();
|
||||||
|
const { isOpen: isAuthOpen } = useAuthModal();
|
||||||
return <>{isOpen && <OrganizationModal />}</>;
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isOpen && <OrganizationModal />}
|
||||||
|
{isAuthOpen && <SwitchTenant />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ModalProvider;
|
||||||
export default ModalProvider
|
|
@ -19,6 +19,7 @@ import { useProjectName } from "../../hooks/useProjects";
|
|||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import { MANAGE_PROJECT } from "../../utils/constants";
|
import { MANAGE_PROJECT } from "../../utils/constants";
|
||||||
|
import { useAuthModal } from "../../hooks/useAuth";
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const { profile } = useProfile();
|
const { profile } = useProfile();
|
||||||
@ -26,6 +27,7 @@ const Header = () => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { data, loading } = useMaster();
|
const { data, loading } = useMaster();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const {onOpen} = useAuthModal()
|
||||||
const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT);
|
const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT);
|
||||||
// {
|
// {
|
||||||
// console.log(location.pathname);
|
// console.log(location.pathname);
|
||||||
@ -455,6 +457,16 @@ const Header = () => {
|
|||||||
<span className="align-middle">Change Password</span>
|
<span className="align-middle">Change Password</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li onClick={()=>onOpen()}>
|
||||||
|
{" "}
|
||||||
|
<a
|
||||||
|
className="dropdown-item cusor-pointer"
|
||||||
|
>
|
||||||
|
<i className="bx bx-transfer-alt me-2"></i>
|
||||||
|
<span className="align-middle">Switch Tenant</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div className="dropdown-divider"></div>
|
<div className="dropdown-divider"></div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -1,39 +1,51 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
|
import {
|
||||||
|
Mutation,
|
||||||
|
useMutation,
|
||||||
|
useQuery,
|
||||||
|
useQueryClient,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import AuthRepository from "../repositories/AuthRepository.jsx";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
closeAuthModal,
|
||||||
|
openAuthModal,
|
||||||
|
} from "../slices/localVariablesSlice.jsx";
|
||||||
|
|
||||||
export const useTenantList = ({ autoFetch = true } = {}) => {
|
export const useTenants = () => {
|
||||||
const [data, setData] = useState([]);
|
return useQuery({
|
||||||
const [loading, setLoading] = useState(false);
|
queryKey: ["tenantlist"],
|
||||||
const [error, setError] = useState(null);
|
queryFn: async () => await AuthRepository.getTenantList(),
|
||||||
|
});
|
||||||
const fetchTenantList = useCallback(async () => {
|
|
||||||
setLoading(true);
|
|
||||||
setError(null);
|
|
||||||
try {
|
|
||||||
const response = setData(response.data || []);
|
|
||||||
} catch (err) {
|
|
||||||
setError(err);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (autoFetch) fetchTenantList();
|
|
||||||
}, [autoFetch, fetchTenantList]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
refetch: fetchTenantList, // manual trigger
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSelectTenant = (onSuccessCallBack) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
export const useTenants =()=>{
|
return useMutation({
|
||||||
get
|
mutationFn: async (tenantId) => {
|
||||||
return useQueery({
|
const res = await AuthRepository.selectTenant(tenantId);
|
||||||
queryKey:["tenantlist",localhost.get("orgJwtToken")],
|
return res.data;
|
||||||
queryFun:async()=> await AuthRepository.
|
},
|
||||||
})
|
onSuccess: (data) => {
|
||||||
}
|
localStorage.setItem("ltkn", data.token);
|
||||||
|
localStorage.setItem("rtkn", data.refreshToken);
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack();
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
showToast(error.message || "Error while creating project", "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAuthModal = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { isOpen } = useSelector((state) => state.localVariables.AuthModal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOpen,
|
||||||
|
onOpen: () => dispatch(openAuthModal()),
|
||||||
|
onClose: () => dispatch(closeAuthModal()),
|
||||||
|
};
|
||||||
|
};
|
@ -44,7 +44,7 @@ const LoginPage = () => {
|
|||||||
localStorage.setItem("jwtToken", response.data.token);
|
localStorage.setItem("jwtToken", response.data.token);
|
||||||
localStorage.setItem("refreshToken", response.data.refreshToken);
|
localStorage.setItem("refreshToken", response.data.refreshToken);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
navigate("/dashboard");
|
navigate("/auth/switch/org");
|
||||||
} else {
|
} else {
|
||||||
await AuthRepository.sendOTP({ email: data.username });
|
await AuthRepository.sendOTP({ email: data.username });
|
||||||
showToast("OTP has been sent to your email.", "success");
|
showToast("OTP has been sent to your email.", "success");
|
||||||
|
101
src/pages/authentication/SwitchTenant.jsx
Normal file
101
src/pages/authentication/SwitchTenant.jsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import Modal from "../../components/common/Modal";
|
||||||
|
import { useAuthModal, useSelectTenant, useTenants } from "../../hooks/useAuth";
|
||||||
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
import AuthRepository from "../../repositories/AuthRepository";
|
||||||
|
|
||||||
|
const SwitchTenant = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { profile } = useProfile();
|
||||||
|
const [pendingTenant, setPendingTenant] = useState(null);
|
||||||
|
const { isOpen, onClose, onOpen } = useAuthModal();
|
||||||
|
const { data, isLoading, isError, error } = useTenants();
|
||||||
|
const { mutate: chooseTenant, isPending } = useSelectTenant(() => {
|
||||||
|
onClose();
|
||||||
|
queryClient.clear();
|
||||||
|
|
||||||
|
// 2. Force fetch profile fresh for the new tenant
|
||||||
|
queryClient.fetchQuery({
|
||||||
|
queryKey: ["profile"],
|
||||||
|
queryFn: () => AuthRepository.profile(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const currentTenant = localStorage.getItem("ctnt");
|
||||||
|
const handleTenantselection = (tenantId) => {
|
||||||
|
setPendingTenant(tenantId);
|
||||||
|
localStorage.setItem("ctnt", tenantId);
|
||||||
|
chooseTenant(tenantId);
|
||||||
|
};
|
||||||
|
const contentBody = (
|
||||||
|
<div className="container text-black">
|
||||||
|
<p className=" fs-5">Switch Workplace</p>
|
||||||
|
<div className="row justify-content-center g-4">
|
||||||
|
{data?.data.map((tenant) => (
|
||||||
|
<div key={tenant.id} className="col-12 ">
|
||||||
|
<div
|
||||||
|
className={`d-flex flex-column flex-md-row gap-3 align-items-center align-items-md-start p-1 border ${
|
||||||
|
currentTenant === tenant.id ? "border-primary" : ""
|
||||||
|
} `}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="flex-shrink-0 text-center"
|
||||||
|
style={{
|
||||||
|
width: "80px",
|
||||||
|
aspectRatio: "1 / 1",
|
||||||
|
overflow: "hidden",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={tenant?.logoImage || "/assets/img/SP-Placeholdeer.svg"}
|
||||||
|
alt={tenant.name}
|
||||||
|
className="img-fluid"
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="d-flex flex-column text-start gap-2">
|
||||||
|
<p className="fs-5 text-muted fw-semibold mb-1">
|
||||||
|
{tenant?.name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="d-flex flex-wrap gap-2 align-items-center">
|
||||||
|
<p className="fw-semibold m-0">Industry:</p>
|
||||||
|
<p className="m-0">
|
||||||
|
{tenant?.industry?.name || "Not Available"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{tenant?.description && (
|
||||||
|
<p className="text-start text-wrap m-0">
|
||||||
|
{tenant?.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn btn-primary btn-sm mt-2 align-self-start"
|
||||||
|
onClick={() => handleTenantselection(tenant?.id)}
|
||||||
|
disabled={isPending && pendingTenant === tenant.id}
|
||||||
|
>
|
||||||
|
{isPending && pendingTenant === tenant.id
|
||||||
|
? "Please Wait.."
|
||||||
|
: "Go To Dashboard"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return <Modal isOpen={isOpen} onClose={onClose} body={contentBody} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SwitchTenant;
|
102
src/pages/authentication/TenantSelectionPage.jsx
Normal file
102
src/pages/authentication/TenantSelectionPage.jsx
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTenants, useSelectTenant } from "../../hooks/useAuth.jsx";
|
||||||
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import Dashboard from "../../components/Dashboard/Dashboard.jsx";
|
||||||
|
|
||||||
|
const TenantSelectionPage = () => {
|
||||||
|
const [pendingTenant, setPendingTenant] = useState(null);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { data, isLoading, isError, error } = useTenants();
|
||||||
|
const { mutate: chooseTenant, isPending } = useSelectTenant(() => {
|
||||||
|
navigate("/dashboard");
|
||||||
|
});
|
||||||
|
const handleTenantselection = (tenantId) => {
|
||||||
|
setPendingTenant(tenantId);
|
||||||
|
localStorage.setItem("ctnt", tenantId);
|
||||||
|
chooseTenant(tenantId);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (localStorage.getItem("ctnt")) {
|
||||||
|
return navigate("/dashboard");
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="container-fluid py-5 text-center">
|
||||||
|
<div className="spinner-border text-primary" role="status">
|
||||||
|
<span className="visually-hidden">Loading tenants...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container-fluid py-4">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="text-center mb-4">
|
||||||
|
<p className="fs-4 mb-1">Welcome</p>
|
||||||
|
<p className="fs-5">
|
||||||
|
Please select which dashboard you want to explore!!!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card Section */}
|
||||||
|
<div className="row justify-content-center g-4 m-auto">
|
||||||
|
{data?.data.map((tenant) => (
|
||||||
|
<div key={tenant.id} className="col-12 col-md-10 col-lg-8">
|
||||||
|
<div className="d-flex flex-column flex-md-row gap-5 align-items-center align-items-md-start p-3 border rounded shadow-sm bg-white h-100">
|
||||||
|
{/* Image */}
|
||||||
|
<div className="flex-shrink-0 text-center">
|
||||||
|
<img
|
||||||
|
src={tenant?.logoImage || "/assets/img/SP-Placeholdeer.svg"}
|
||||||
|
alt={tenant.name}
|
||||||
|
className="img-fluid"
|
||||||
|
style={{
|
||||||
|
maxWidth: "140px",
|
||||||
|
height: "auto",
|
||||||
|
aspectRatio: "3 / 2",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="d-flex flex-column text-start gap-2">
|
||||||
|
<p className="fs-5 text-muted fw-semibold mb-1">
|
||||||
|
{tenant?.name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="d-flex flex-wrap gap-2 align-items-center">
|
||||||
|
<p className="fw-semibold m-0">Industry:</p>
|
||||||
|
<p className="m-0">
|
||||||
|
{tenant?.industry?.name || "Not Available"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{tenant?.description && (
|
||||||
|
<p className="text-start text-wrap m-0">
|
||||||
|
{tenant?.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn btn-primary btn-sm mt-2 align-self-start"
|
||||||
|
onClick={() => handleTenantselection(tenant?.id)}
|
||||||
|
disabled={pendingTenant === tenant.id && isPending}
|
||||||
|
>
|
||||||
|
{isPending && pendingTenant === tenant.id
|
||||||
|
? "Please Wait.."
|
||||||
|
: "Go To Dashboard"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TenantSelectionPage;
|
@ -15,7 +15,9 @@ const AuthRepository = {
|
|||||||
logout: (data) => api.post("/api/auth/logout", data),
|
logout: (data) => api.post("/api/auth/logout", data),
|
||||||
profile: () => api.get("/api/user/profile"),
|
profile: () => api.get("/api/user/profile"),
|
||||||
changepassword: (data) => api.post("/api/auth/change-password", data),
|
changepassword: (data) => api.post("/api/auth/change-password", data),
|
||||||
appmenu:()=>api.get('/api/appmenu/get/menu')
|
appmenu: () => api.get('/api/appmenu/get/menu'),
|
||||||
|
selectTenant: (tenantId) => api.post(`/api/Auth/select-tenant/${tenantId}`),
|
||||||
|
getTenantList: () => api.get("/api/Auth/get/user/tenants"),
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ import { Navigate } from "react-router-dom";
|
|||||||
import CreateTenant from "../pages/Tenant/CreateTenant";
|
import CreateTenant from "../pages/Tenant/CreateTenant";
|
||||||
import OrganizationPage from "../pages/Organization/OrganizationPage";
|
import OrganizationPage from "../pages/Organization/OrganizationPage";
|
||||||
import LandingPage from "../pages/Home/LandingPage";
|
import LandingPage from "../pages/Home/LandingPage";
|
||||||
|
import TenantSelectionPage from "../pages/authentication/TenantSelectionPage";
|
||||||
const router = createBrowserRouter(
|
const router = createBrowserRouter(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -69,6 +70,7 @@ const router = createBrowserRouter(
|
|||||||
{ path: "/auth/changepassword", element: <ChangePasswordPage /> },
|
{ path: "/auth/changepassword", element: <ChangePasswordPage /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{ path: "/auth/switch/org", element: <TenantSelectionPage /> },
|
||||||
{
|
{
|
||||||
element: <ProtectedRoute />,
|
element: <ProtectedRoute />,
|
||||||
errorElement: <ErrorPage />,
|
errorElement: <ErrorPage />,
|
||||||
|
@ -3,54 +3,56 @@ import { createSlice } from "@reduxjs/toolkit";
|
|||||||
const localVariablesSlice = createSlice({
|
const localVariablesSlice = createSlice({
|
||||||
name: "localVariables",
|
name: "localVariables",
|
||||||
initialState: {
|
initialState: {
|
||||||
selectedMaster:"Application Role",
|
selectedMaster: "Application Role",
|
||||||
regularizationCount:0,
|
regularizationCount: 0,
|
||||||
defaultDateRange: {
|
defaultDateRange: {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
},
|
},
|
||||||
projectId: null,
|
projectId: null,
|
||||||
reload:false,
|
reload: false,
|
||||||
|
|
||||||
OrganizationModal:{
|
OrganizationModal: {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
orgData: null,
|
orgData: null,
|
||||||
prevStep:null,
|
prevStep: null,
|
||||||
startStep: 1,
|
startStep: 1,
|
||||||
flowType: "default",
|
flowType: "default",
|
||||||
}
|
},
|
||||||
|
|
||||||
|
AuthModal: {
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
changeMaster: (state, action) => {
|
changeMaster: (state, action) => {
|
||||||
state.selectedMaster = action.payload;
|
state.selectedMaster = action.payload;
|
||||||
},
|
},
|
||||||
updateRegularizationCount: (state, action) => {
|
updateRegularizationCount: (state, action) => {
|
||||||
state.regularizationCount = action.payload;
|
state.regularizationCount = action.payload;
|
||||||
},
|
},
|
||||||
setProjectId: (state, action) => {
|
setProjectId: (state, action) => {
|
||||||
localStorage.setItem("project",null)
|
localStorage.setItem("project", null);
|
||||||
state.projectId = action.payload;
|
state.projectId = action.payload;
|
||||||
localStorage.setItem("project",state.projectId || null)
|
localStorage.setItem("project", state.projectId || null);
|
||||||
},
|
},
|
||||||
refreshData: ( state, action ) =>
|
refreshData: (state, action) => {
|
||||||
{
|
state.reload = action.payload;
|
||||||
state.reload = action.payload
|
|
||||||
},
|
},
|
||||||
setDefaultDateRange: (state, action) => {
|
setDefaultDateRange: (state, action) => {
|
||||||
state.defaultDateRange = action.payload;
|
state.defaultDateRange = action.payload;
|
||||||
},
|
},
|
||||||
|
|
||||||
openOrgModal: (state, action) => {
|
openOrgModal: (state, action) => {
|
||||||
state.OrganizationModal.isOpen = true;
|
state.OrganizationModal.isOpen = true;
|
||||||
state.OrganizationModal.orgData = action.payload?.orgData || null;
|
state.OrganizationModal.orgData = action.payload?.orgData || null;
|
||||||
|
|
||||||
if (state.OrganizationModal.startStep) {
|
if (state.OrganizationModal.startStep) {
|
||||||
state.OrganizationModal.prevStep = state.OrganizationModal.startStep;
|
state.OrganizationModal.prevStep = state.OrganizationModal.startStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.OrganizationModal.startStep = action.payload?.startStep || 1;
|
state.OrganizationModal.startStep = action.payload?.startStep || 1;
|
||||||
state.OrganizationModal.flowType = action.payload?.flowType || "default";
|
state.OrganizationModal.flowType = action.payload?.flowType || "default";
|
||||||
},
|
},
|
||||||
closeOrgModal: (state) => {
|
closeOrgModal: (state) => {
|
||||||
state.OrganizationModal.isOpen = false;
|
state.OrganizationModal.isOpen = false;
|
||||||
@ -61,8 +63,26 @@ state.OrganizationModal.isOpen = true;
|
|||||||
toggleOrgModal: (state) => {
|
toggleOrgModal: (state) => {
|
||||||
state.OrganizationModal.isOpen = !state.OrganizationModal.isOpen;
|
state.OrganizationModal.isOpen = !state.OrganizationModal.isOpen;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openAuthModal: (state, action) => {
|
||||||
|
state.AuthModal.isOpen = true;
|
||||||
|
},
|
||||||
|
closeAuthModal: (state, action) => {
|
||||||
|
state.AuthModal.isOpen = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { changeMaster ,updateRegularizationCount,setProjectId,refreshData,setDefaultDateRange,openOrgModal,closeOrgModal,toggleOrgModal} = localVariablesSlice.actions;
|
export const {
|
||||||
export default localVariablesSlice.reducer;
|
changeMaster,
|
||||||
|
updateRegularizationCount,
|
||||||
|
setProjectId,
|
||||||
|
refreshData,
|
||||||
|
setDefaultDateRange,
|
||||||
|
openOrgModal,
|
||||||
|
closeOrgModal,
|
||||||
|
toggleOrgModal,
|
||||||
|
openAuthModal,
|
||||||
|
closeAuthModal,
|
||||||
|
} = localVariablesSlice.actions;
|
||||||
|
export default localVariablesSlice.reducer;
|
Loading…
x
Reference in New Issue
Block a user