added self Tenant Profile
This commit is contained in:
parent
735e766215
commit
4ab33fd5fd
@ -5,9 +5,12 @@ import GlobalModel from "../common/GlobalModel";
|
|||||||
import { useTenantContext } from "../../pages/Tenant/TenantPage";
|
import { useTenantContext } from "../../pages/Tenant/TenantPage";
|
||||||
import { useTenantDetailsContext } from "../../pages/Tenant/TenantDetails";
|
import { useTenantDetailsContext } from "../../pages/Tenant/TenantDetails";
|
||||||
import IconButton from "../common/IconButton";
|
import IconButton from "../common/IconButton";
|
||||||
|
import { hasUserPermission } from "../../utils/authUtils";
|
||||||
|
import { MANAGE_TENANTS } from "../../utils/constants";
|
||||||
|
|
||||||
const Profile = ({ data }) => {
|
const Profile = ({ data }) => {
|
||||||
const {setEditTenant} = useTenantDetailsContext()
|
const {setEditTenant} = useTenantDetailsContext()
|
||||||
|
const canUpdateTenant = hasUserPermission(MANAGE_TENANTS)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container-fuid">
|
<div className="container-fuid">
|
||||||
@ -33,12 +36,12 @@ const Profile = ({ data }) => {
|
|||||||
<i className="bx bx-globe text-primary bx-xs me-1"></i>
|
<i className="bx bx-globe text-primary bx-xs me-1"></i>
|
||||||
<span>{data?.domainName}</span>
|
<span>{data?.domainName}</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
{canUpdateTenant && ( <span
|
||||||
className="position-absolute top-0 end-0 cursor-auto"
|
className="position-absolute top-0 end-0 cursor-auto"
|
||||||
onClick={() => setEditTenant(true)}
|
onClick={() => setEditTenant(true)}
|
||||||
>
|
>
|
||||||
<i className="bx bx-edit bs-sm text-primary cursor-pointer"></i>
|
<i className="bx bx-edit bs-sm text-primary cursor-pointer"></i>
|
||||||
</span>
|
</span>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,9 @@ import { useDispatch } from "react-redux";
|
|||||||
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
import { SUBSCRIPTION_PLAN_FREQUENCIES } from "../../utils/constants";
|
import { MANAGE_TENANTS, SUBSCRIPTION_PLAN_FREQUENCIES } from "../../utils/constants";
|
||||||
|
import { useHasAnyPermission } from "../../hooks/useExpense";
|
||||||
|
|
||||||
|
|
||||||
const SubScriptionHistory = ({ tenantId }) => {
|
const SubScriptionHistory = ({ tenantId }) => {
|
||||||
const { data, isLoading, isError, error } = useTenantDetails(tenantId);
|
const { data, isLoading, isError, error } = useTenantDetails(tenantId);
|
||||||
|
@ -63,7 +63,7 @@ export const subscriptionSchema = z.object({
|
|||||||
.min(1, "Team size is required and must be greater than zero"),
|
.min(1, "Team size is required and must be greater than zero"),
|
||||||
frequency: z
|
frequency: z
|
||||||
.number({ invalid_type_error: "Frequency must be a number" })
|
.number({ invalid_type_error: "Frequency must be a number" })
|
||||||
.min(1, "Frequency must be at least 1"),
|
.min(0, "Frequency must be at least 1"),
|
||||||
isTrial: z.boolean(),
|
isTrial: z.boolean(),
|
||||||
autoRenew: z.boolean(),
|
autoRenew: z.boolean(),
|
||||||
});
|
});
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
{
|
{
|
||||||
"text": "Tenant",
|
"text": "Tenant",
|
||||||
"available": true,
|
"available": true,
|
||||||
"link": "/tenants/"
|
"link": "/tenants"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "Masters",
|
"text": "Masters",
|
||||||
|
@ -55,6 +55,7 @@ export const useTenantDetails = (id) => {
|
|||||||
const response = await TenantRepository.getTenantDetails(id);
|
const response = await TenantRepository.getTenantDetails(id);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
enabled:!!id
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
35
src/pages/Tenant/SelfTenantDetails.jsx
Normal file
35
src/pages/Tenant/SelfTenantDetails.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import React, { useEffect, useMemo } from "react";
|
||||||
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
|
import TenantDetails from "./TenantDetails";
|
||||||
|
import { hasUserPermission } from "../../utils/authUtils";
|
||||||
|
import { VIEW_TENANTS } from "../../utils/constants";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const SelfTenantDetails = () => {
|
||||||
|
const { profile, loading } = useProfile();
|
||||||
|
const tenantId = profile?.employeeInfo?.tenantId;
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const isSelfTenantView = hasUserPermission(VIEW_TENANTS);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isSelfTenantView) {
|
||||||
|
navigate("/tenants");
|
||||||
|
}
|
||||||
|
}, [isSelfTenantView, navigate]);
|
||||||
|
|
||||||
|
if (loading || !tenantId) {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TenantDetails
|
||||||
|
tenantId={tenantId}
|
||||||
|
wrapInContainer={true}
|
||||||
|
showBreadcrumb={true}
|
||||||
|
iTSelf={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelfTenantDetails;
|
||||||
|
|
8
src/pages/Tenant/SuperTenantDetails.jsx
Normal file
8
src/pages/Tenant/SuperTenantDetails.jsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import React from "react";
|
||||||
|
import TenantDetails from "./TenantDetails";
|
||||||
|
|
||||||
|
const SuperTenantDetails = () => {
|
||||||
|
return <TenantDetails wrapInContainer showBreadcrumb iTSelf={false} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SuperTenantDetails;
|
@ -1,10 +1,8 @@
|
|||||||
import React, { createContext, useContext,useState } from "react";
|
import React, { createContext, useContext, useState, useMemo } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
import Profile from "../../components/Tenant/Profile";
|
import Profile from "../../components/Tenant/Profile";
|
||||||
|
|
||||||
import { useTenantDetails } from "../../hooks/useTenant";
|
import { useTenantDetails } from "../../hooks/useTenant";
|
||||||
import Organization from "../../components/Tenant/Organization";
|
|
||||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||||
import GlobalModel from "../../components/common/GlobalModel";
|
import GlobalModel from "../../components/common/GlobalModel";
|
||||||
import EditProfile from "../../components/Tenant/EditProfile";
|
import EditProfile from "../../components/Tenant/EditProfile";
|
||||||
@ -13,109 +11,142 @@ import SubScriptionHistory from "../../components/Tenant/SubScriptionHistory";
|
|||||||
const TenantDetailsContext = createContext();
|
const TenantDetailsContext = createContext();
|
||||||
export const useTenantDetailsContext = () => useContext(TenantDetailsContext);
|
export const useTenantDetailsContext = () => useContext(TenantDetailsContext);
|
||||||
|
|
||||||
|
const TenantDetails = ({
|
||||||
const TenantDetails = () => {
|
tenantId: tenantIdProp,
|
||||||
const { tenantId } = useParams();
|
wrapInContainer = true,
|
||||||
const { data, isLoading, isError, error } = useTenantDetails(tenantId);
|
showBreadcrumb = true,
|
||||||
|
iTSelf = true
|
||||||
|
}) => {
|
||||||
|
const { tenantId: tenantIdFromUrl } = useParams();
|
||||||
|
const activeTenantId = tenantIdFromUrl || tenantIdProp;
|
||||||
|
const { data, isLoading, isError, error } = useTenantDetails(activeTenantId);
|
||||||
const [editTenant, setEditTenant] = useState(false);
|
const [editTenant, setEditTenant] = useState(false);
|
||||||
const contextValues ={
|
const contextValues = useMemo(
|
||||||
setEditTenant,editTenant
|
() => ({ editTenant, setEditTenant }),
|
||||||
}
|
[editTenant]
|
||||||
|
);
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{
|
|
||||||
id: "navs-left-home",
|
|
||||||
label: "Profile",
|
|
||||||
icon: "bx bx-user-circle",
|
|
||||||
iconSize: "bx-sm",
|
|
||||||
content: <Profile data={data} />,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
id: "navs-left-bill",
|
|
||||||
label: "Bills and Plan ",
|
|
||||||
icon: "bx bx-receipt",
|
|
||||||
iconSize: "bx-sm",
|
|
||||||
content: (
|
|
||||||
<div className="text-center">
|
|
||||||
<SubScriptionHistory tenantId={tenantId} />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
id: "navs-left-messages",
|
|
||||||
label: "Messages",
|
|
||||||
icon: "bx bx-message-rounded",
|
|
||||||
iconSize: "bx-sm",
|
|
||||||
content: (
|
|
||||||
<div className="text-center">
|
|
||||||
<ComingSoonPage />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
|
const tabs = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: "navs-left-home",
|
||||||
|
label: "Profile",
|
||||||
|
icon: "bx bx-user-circle",
|
||||||
|
iconSize: "bx-sm",
|
||||||
|
content: <Profile data={data} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "navs-left-bill",
|
||||||
|
label: "Bills and Plan",
|
||||||
|
icon: "bx bx-receipt",
|
||||||
|
iconSize: "bx-sm",
|
||||||
|
content: (
|
||||||
|
<div className="text-center">
|
||||||
|
<SubScriptionHistory tenantId={activeTenantId} />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "navs-left-messages",
|
||||||
|
label: "Messages",
|
||||||
|
icon: "bx bx-message-rounded",
|
||||||
|
iconSize: "bx-sm",
|
||||||
|
content: (
|
||||||
|
<div className="text-center">
|
||||||
|
<ComingSoonPage />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[data, activeTenantId]
|
||||||
|
);
|
||||||
|
if (!activeTenantId) return <div className="my-4">No tenant selected.</div>;
|
||||||
if (isLoading) return <div className="my-4">Loading...</div>;
|
if (isLoading) return <div className="my-4">Loading...</div>;
|
||||||
if (isError) return <div className="my-3">{error.message}</div>;
|
if (isError) return <div className="my-3">{error?.message}</div>;
|
||||||
|
|
||||||
|
|
||||||
|
const Shell = ({ children }) =>
|
||||||
|
wrapInContainer ? (
|
||||||
|
<div className="container-fluid py-0">{children}</div>
|
||||||
|
) : (
|
||||||
|
<>{children}</>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TenantDetailsContext.Provider value={contextValues}>
|
<TenantDetailsContext.Provider value={contextValues}>
|
||||||
<div className="container-fluid py-0">
|
<Shell>
|
||||||
<Breadcrumb
|
{showBreadcrumb && (
|
||||||
data={[
|
<Breadcrumb
|
||||||
{ label: "Home", link: "/dashboard" },
|
data={
|
||||||
{ label: "Tenant", link: "/tenants" },
|
iTSelf
|
||||||
{ label: "Tenant Details", link: null },
|
? [
|
||||||
]}
|
{ label: "Home", link: "/dashboard" },
|
||||||
/>
|
{ label: "Tenant Details", link: null },
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ label: "Home", link: "/dashboard" },
|
||||||
|
{ label: "Tenant", link: "/tenants" },
|
||||||
|
{ label: "Tenant Details", link: null },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="nav-align-left nav-tabs-shadow mb-6">
|
<div className="nav-align-left nav-tabs-shadow mb-6">
|
||||||
<ul className="nav nav-tabs py-2 page-min-h" role="tablist">
|
<ul className="nav nav-tabs py-2 page-min-h" role="tablist">
|
||||||
{tabs.map((tab, index) => (
|
{tabs.map((tab, index) => (
|
||||||
<li key={tab.id} className="nav-item">
|
<li key={tab.id} className="nav-item">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`nav-link d-flex align-items-center text-tiny gap-2 ${
|
className={`nav-link d-flex align-items-center text-tiny gap-2 ${
|
||||||
index === 0 ? "active" : ""
|
index === 0 ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
role="tab"
|
role="tab"
|
||||||
data-bs-toggle="tab"
|
data-bs-toggle="tab"
|
||||||
data-bs-target={`#${tab.id}`}
|
data-bs-target={`#${tab.id}`}
|
||||||
aria-controls={tab.id}
|
aria-controls={tab.id}
|
||||||
aria-selected={index === 0}
|
aria-selected={index === 0}
|
||||||
>
|
>
|
||||||
{tab.icon && <i className={`${tab.icon} ${tab.iconSize}`} />}
|
{tab.icon && (
|
||||||
{tab.label}
|
<i className={`${tab.icon} ${tab.iconSize}`} />
|
||||||
</button>
|
)}
|
||||||
</li>
|
{tab.label}
|
||||||
))}
|
</button>
|
||||||
</ul>
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div className="tab-content">
|
<div className="tab-content">
|
||||||
{tabs.map((tab, index) => (
|
{tabs.map((tab, index) => (
|
||||||
<div
|
<div
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
className={`tab-pane fade ${
|
className={`tab-pane fade ${
|
||||||
index === 0 ? "show active" : ""
|
index === 0 ? "show active" : ""
|
||||||
} text-start`}
|
} text-start`}
|
||||||
id={tab.id}
|
id={tab.id}
|
||||||
>
|
>
|
||||||
{tab.content}
|
{tab.content}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
</Shell>
|
||||||
</div>
|
</TenantDetailsContext.Provider>
|
||||||
|
|
||||||
</div>
|
{editTenant && (
|
||||||
</TenantDetailsContext.Provider>
|
<GlobalModel
|
||||||
{editTenant && (
|
size="lg"
|
||||||
<GlobalModel size="lg" isOpen={editTenant} closeModal={()=>setEditTenant(false)}>
|
isOpen={editTenant}
|
||||||
<EditProfile TenantId={tenantId} onClose={()=>setEditTenant(false)}/>
|
closeModal={() => setEditTenant(false)}
|
||||||
|
>
|
||||||
|
<EditProfile
|
||||||
|
TenantId={activeTenantId}
|
||||||
|
onClose={() => setEditTenant(false)}
|
||||||
|
/>
|
||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,70 +1,118 @@
|
|||||||
import React, { useState, createContext, useEffect, useContext } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
createContext,
|
||||||
|
useEffect,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
} from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
// ------Components-------
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
|
// ------ Components -------
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
import TenantsList from "../../components/Tenant/TenantsList";
|
import TenantsList from "../../components/Tenant/TenantsList";
|
||||||
import { useNavigate } from "react-router-dom";
|
import TenantFilterPanel from "../../components/Tenant/TenantFilterPanel";
|
||||||
|
|
||||||
|
// ------ Context & Utils -------
|
||||||
import { useDebounce } from "../../utils/appUtils";
|
import { useDebounce } from "../../utils/appUtils";
|
||||||
import { useFab } from "../../Context/FabContext";
|
import { useFab } from "../../Context/FabContext";
|
||||||
|
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
||||||
|
import { hasUserPermission } from "../../utils/authUtils";
|
||||||
|
|
||||||
//---------- Schema and defaultValues----
|
// ------ Schema -------
|
||||||
import {
|
import {
|
||||||
defaultFilterValues,
|
defaultFilterValues,
|
||||||
filterSchema,
|
filterSchema,
|
||||||
} from "../../components/Tenant/TenantSchema";
|
} from "../../components/Tenant/TenantSchema";
|
||||||
import TenantFilterPanel from "../../components/Tenant/TenantFilterPanel";
|
|
||||||
import { useDispatch } from "react-redux";
|
|
||||||
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
|
||||||
import { hasUserPermission } from "../../utils/authUtils";
|
|
||||||
import { SUPPER_TENANT, VIEW_TENANTS } from "../../utils/constants";
|
|
||||||
|
|
||||||
// This is context that wrapping all components tenant releated , but must pass inside 'TenantContext.Provider'
|
// ------ Constants -------
|
||||||
|
import {
|
||||||
|
MANAGE_TENANTS,
|
||||||
|
SUPPER_TENANT,
|
||||||
|
VIEW_TENANTS,
|
||||||
|
} from "../../utils/constants";
|
||||||
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
|
|
||||||
|
// ---------- Context ----------
|
||||||
export const TenantContext = createContext();
|
export const TenantContext = createContext();
|
||||||
export const useTenantContext = () => {
|
export const useTenantContext = () => {
|
||||||
const context = useContext(TenantContext);
|
const context = useContext(TenantContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error("useTenantContext must be used within an TenantProvider");
|
throw new Error(
|
||||||
|
"useTenantContext must be used within a TenantContext.Provider"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TenantPage = () => {
|
const TenantPage = () => {
|
||||||
const [searchText, setSearchText] = useState("");
|
const dispatch = useDispatch();
|
||||||
const [isRefetching,setRefetching] = useState(false)
|
|
||||||
const [refetchFn, setRefetchFn] = useState(null);
|
|
||||||
const [filters, setFilter] = useState();
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
const debouncedSearch = useDebounce(searchText, 500);
|
|
||||||
const contextValue = {
|
|
||||||
};
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const IsSupperTenant = hasUserPermission(SUPPER_TENANT)
|
const { profile } = useProfile();
|
||||||
const IsViewTenant = hasUserPermission(VIEW_TENANTS)
|
|
||||||
|
|
||||||
|
// ---------- State ----------
|
||||||
|
const [searchText, setSearchText] = useState("");
|
||||||
|
const [isRefetching, setIsRefetching] = useState(false);
|
||||||
|
const [refetchFn, setRefetchFn] = useState(null);
|
||||||
|
const [filters, setFilters] = useState();
|
||||||
|
|
||||||
|
// ---------- Hooks ----------
|
||||||
|
const debouncedSearch = useDebounce(searchText, 500);
|
||||||
const { setOffcanvasContent, setShowTrigger } = useFab();
|
const { setOffcanvasContent, setShowTrigger } = useFab();
|
||||||
|
|
||||||
// This Hook allow us to right-side bar for filter Tenants
|
const isSuperTenant = hasUserPermission(SUPPER_TENANT);
|
||||||
|
const canManageTenants = hasUserPermission(MANAGE_TENANTS);
|
||||||
|
const isSelfTenant = hasUserPermission(VIEW_TENANTS);
|
||||||
|
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
resolver: zodResolver(filterSchema),
|
resolver: zodResolver(filterSchema),
|
||||||
defaultValues: defaultFilterValues,
|
defaultValues: defaultFilterValues,
|
||||||
});
|
});
|
||||||
|
const { reset } = methods;
|
||||||
|
|
||||||
const { reset } = methods;
|
const handleApplyFilters = useCallback((values) => {
|
||||||
|
setFilters(values);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const filterPanelElement = useMemo(
|
||||||
|
() => <TenantFilterPanel onApply={handleApplyFilters} />,
|
||||||
|
[handleApplyFilters]
|
||||||
|
);
|
||||||
|
console.log(isSelfTenant)
|
||||||
|
// ---------- Fab Filter Panel ----------
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!isSuperTenant) return;
|
||||||
setShowTrigger(true);
|
setShowTrigger(true);
|
||||||
setOffcanvasContent("Tenant Filters", <TenantFilterPanel onApply={setFilter}
|
setOffcanvasContent("Tenant Filters", filterPanelElement);
|
||||||
/>);
|
|
||||||
return () => {
|
return () => {
|
||||||
setShowTrigger(false);
|
setShowTrigger(false);
|
||||||
setOffcanvasContent("", null);
|
setOffcanvasContent("", null);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [isSuperTenant, filterPanelElement, profile]);
|
||||||
const handleNewTenant =()=>{
|
|
||||||
dispatch(setCurrentTenant(null))
|
// ---------- Redirect for Self Tenant ----------
|
||||||
navigate("/tenants/new-tenant")
|
useEffect(() => {
|
||||||
}
|
if (!isSuperTenant && isSelfTenant) {
|
||||||
|
// Delay navigation to next tick to avoid "update during render" warning
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate("/tenant/self");
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}, [isSuperTenant, isSelfTenant, navigate]);
|
||||||
|
|
||||||
|
// ---------- Handlers ----------
|
||||||
|
const handleNewTenant = () => {
|
||||||
|
dispatch(setCurrentTenant(null));
|
||||||
|
navigate("/tenants/new-tenant");
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- Context Value ----------
|
||||||
|
const contextValue = {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TenantContext.Provider value={contextValue}>
|
<TenantContext.Provider value={contextValue}>
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
@ -75,49 +123,65 @@ const handleNewTenant =()=>{
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="card d-flex p-2">
|
{/* Super Tenant Actions */}
|
||||||
<div className="row align-items-center">
|
{isSuperTenant && (
|
||||||
<div className="col-6 col-md-6 col-lg-3 mb-md-0">
|
<div className="card d-flex p-2">
|
||||||
<input
|
<div className="row align-items-center">
|
||||||
type="search"
|
{/* Search */}
|
||||||
value={searchText}
|
<div className="col-6 col-md-6 col-lg-3 mb-md-0">
|
||||||
onChange={(e)=>setSearchText(e.target.value)}
|
<input
|
||||||
className="form-control form-control-sm"
|
type="search"
|
||||||
placeholder="Search Tenant"
|
value={searchText}
|
||||||
/>
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
</div>
|
className="form-control form-control-sm"
|
||||||
|
placeholder="Search Tenant"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="col-6 col-md-6 col-lg-9 text-end cursor-pointer">
|
{/* Actions */}
|
||||||
<span className="text-tiny text-muted p-1 border-0 bg-none lead mx-3 " disabled={isRefetching} onClick={() => refetchFn && refetchFn()}>
|
<div className="col-6 col-md-6 col-lg-9 text-end">
|
||||||
Refresh <i className={`bx bx-refresh ms-1 ${isRefetching ? "bx-spin":""}`}></i>
|
<span
|
||||||
</span>
|
className="text-tiny text-muted p-1 border-0 bg-none lead mx-3 cursor-pointer"
|
||||||
|
disabled={isRefetching}
|
||||||
|
onClick={() => refetchFn && refetchFn()}
|
||||||
|
>
|
||||||
|
Refresh{" "}
|
||||||
|
<i
|
||||||
|
className={`bx bx-refresh ms-1 ${
|
||||||
|
isRefetching ? "bx-spin" : ""
|
||||||
|
}`}
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
{IsSupperTenant && (
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-bs-toggle="tooltip"
|
title="Add New Tenant"
|
||||||
data-bs-offset="0,8"
|
className="p-1 bg-primary rounded-circle cursor-pointer"
|
||||||
data-bs-placement="top"
|
onClick={handleNewTenant}
|
||||||
data-bs-custom-class="tooltip"
|
>
|
||||||
title="Add New Tenant"
|
<i className="bx bx-plus fs-4 text-white"></i>
|
||||||
className="p-1 bg-primary rounded-circle cursror-pointer"
|
</button>
|
||||||
onClick={handleNewTenant}
|
</div>
|
||||||
>
|
|
||||||
<i className="bx bx-plus fs-4 text-white"></i>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
{IsViewTenant ? (<TenantsList filters={filters} searchText={debouncedSearch} setIsRefetching={setRefetching}
|
|
||||||
setRefetchFn={setRefetchFn}
|
|
||||||
/>):(
|
|
||||||
<div className="text-center my-2">
|
|
||||||
<i className="fa-solid fa-triangle-exclamation fs-5"></i>
|
|
||||||
<p>Access Denied: You don't have permission to perform this action. !</p>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
|
|
||||||
|
{/* Tenant List or Access Denied */}
|
||||||
|
{isSuperTenant ? (
|
||||||
|
<TenantsList
|
||||||
|
filters={filters}
|
||||||
|
searchText={debouncedSearch}
|
||||||
|
setIsRefetching={setIsRefetching}
|
||||||
|
setRefetchFn={setRefetchFn}
|
||||||
|
/>
|
||||||
|
) : !isSelfTenant ? (
|
||||||
|
<div className="card text-center my-4 p-2">
|
||||||
|
<i className="fa-solid fa-triangle-exclamation fs-5"></i>
|
||||||
|
<p>
|
||||||
|
Access Denied: You don't have permission to perform this action!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</TenantContext.Provider>
|
</TenantContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -42,14 +42,16 @@ import TenantPage from "../pages/Tenant/TenantPage";
|
|||||||
import CreateTenant from "../pages/Tenant/CreateTenant";
|
import CreateTenant from "../pages/Tenant/CreateTenant";
|
||||||
import ExpensePage from "../pages/Expense/ExpensePage";
|
import ExpensePage from "../pages/Expense/ExpensePage";
|
||||||
import TenantDetails from "../pages/Tenant/TenantDetails";
|
import TenantDetails from "../pages/Tenant/TenantDetails";
|
||||||
|
import SelfTenantDetails from "../pages/Tenant/SelfTenantDetails";
|
||||||
|
import SuperTenantDetails from "../pages/Tenant/SuperTenantDetails";
|
||||||
|
|
||||||
const router = createBrowserRouter(
|
const router = createBrowserRouter(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
element: <AuthLayout />,
|
element: <AuthLayout />,
|
||||||
children: [
|
children: [
|
||||||
{path: "/auth/login", element: <LoginPage />},
|
{ path: "/auth/login", element: <LoginPage /> },
|
||||||
{path: "/auth/login-otp", element: <LoginWithOtp />},
|
{ path: "/auth/login-otp", element: <LoginWithOtp /> },
|
||||||
{ path: "/auth/reqest/demo", element: <RegisterPage /> },
|
{ path: "/auth/reqest/demo", element: <RegisterPage /> },
|
||||||
{ path: "/auth/forgot-password", element: <ForgotPasswordPage /> },
|
{ path: "/auth/forgot-password", element: <ForgotPasswordPage /> },
|
||||||
{ path: "/reset-password", element: <ResetPasswordPage /> },
|
{ path: "/reset-password", element: <ResetPasswordPage /> },
|
||||||
@ -82,9 +84,10 @@ const router = createBrowserRouter(
|
|||||||
{ path: "/gallary", element: <ImageGallary /> },
|
{ path: "/gallary", element: <ImageGallary /> },
|
||||||
{ path: "/expenses", element: <ExpensePage /> },
|
{ path: "/expenses", element: <ExpensePage /> },
|
||||||
{ path: "/masters", element: <MasterPage /> },
|
{ path: "/masters", element: <MasterPage /> },
|
||||||
{ path: "/tenants", element: <TenantPage /> },
|
{ path: "/tenants", element: <TenantPage /> },
|
||||||
{ path: "/tenants/new-tenant", element: <CreateTenant /> },
|
{ path: "/tenants/new-tenant", element: <CreateTenant /> },
|
||||||
{ path: "/tenant/:tenantId", element: <TenantDetails /> },
|
{ path: "/tenant/:tenantId", element: <SuperTenantDetails /> },
|
||||||
|
{ path: "/tenant/self", element: <SelfTenantDetails /> },
|
||||||
{ path: "/help/support", element: <Support /> },
|
{ path: "/help/support", element: <Support /> },
|
||||||
{ path: "/help/docs", element: <Documentation /> },
|
{ path: "/help/docs", element: <Documentation /> },
|
||||||
{ path: "/help/connect", element: <Connect /> },
|
{ path: "/help/connect", element: <Connect /> },
|
||||||
|
@ -96,10 +96,10 @@ export const reference = [
|
|||||||
{ val: "root tenant", name: "Root Tenant" },
|
{ val: "root tenant", name: "Root Tenant" },
|
||||||
];
|
];
|
||||||
export const orgSize = [
|
export const orgSize = [
|
||||||
{ val: "50", name: "1-50" },
|
{ val: "1-50", name: "1-50" },
|
||||||
{ val: "100", name: "51-100" },
|
{ val: "51-100", name: "51-100" },
|
||||||
{ val: "500", name: "101-500" },
|
{ val: "101-500", name: "101-500" },
|
||||||
{ val: "600", name: "500+" },
|
{ val: "500+", name: "500+" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user