handle upgrad plan
This commit is contained in:
parent
b9bd4e7e18
commit
0acd733710
@ -12,7 +12,7 @@ const Profile = ({ data }) => {
|
|||||||
<div className="container-fuid">
|
<div className="container-fuid">
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 ">
|
<div className="col-12 my-2">
|
||||||
<div className="d-flex flex-wrap align-items-start position-relative ">
|
<div className="d-flex flex-wrap align-items-start position-relative ">
|
||||||
<div className=" d-flex align-items-start gap-2">
|
<div className=" d-flex align-items-start gap-2">
|
||||||
<img
|
<img
|
||||||
@ -32,20 +32,23 @@ const Profile = ({ data }) => {
|
|||||||
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"></i>
|
<i className="bx bx-edit bs-sm text-primary cursor-pointer"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="divider text-start">
|
|
||||||
<div className="divider-text">Profile</div>
|
|
||||||
</div>
|
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<div className="col rounded-2 bg-light justify-content-start p-2">
|
<div className="col rounded-2 bg-light justify-content-start p-2">
|
||||||
<p className="m-0">{data?.description}</p>
|
<p className="m-0">{data?.description}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="divider text-start my-1">
|
||||||
|
<div className="divider-text">Personal</div>
|
||||||
|
</div>
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
<div className="col-12 col-md-6 d-flex align-items-center">
|
<div className="col-12 col-md-6 d-flex align-items-center">
|
||||||
<i className="bx bx-sm bx-user me-1"></i>
|
<i className="bx bx-sm bx-user me-1"></i>
|
||||||
@ -64,56 +67,55 @@ const Profile = ({ data }) => {
|
|||||||
<span className="ms-2">{data.contactNumber}</span>
|
<span className="ms-2">{data.contactNumber}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 d-flex text-wrap align-items-start my-4 m-0">
|
<div className="col-12 d-flex text-wrap align-items-start my-2 m-0">
|
||||||
<i className="bx bx-sm bx-mark me-1"></i>
|
<i className="bx bx-sm bx-mark me-1"></i>
|
||||||
<span className="fw-semibold">Address:</span>
|
<span className="fw-semibold">Address:</span>
|
||||||
<span className="ms-2">{data.billingAddress}</span>
|
<span className="ms-2">{data.billingAddress}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="divider text-start ">
|
||||||
<div className="divider text-start">
|
|
||||||
<div className="divider-text">Organization</div>
|
<div className="divider-text">Organization</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 d-flex align-items-center">
|
<div className="col-12 d-flex align-items-center">
|
||||||
<i class="bx bx-sm bxs-building"></i>
|
<i className="bx bx-sm bxs-building"></i>
|
||||||
<span className="fw-semibold">Industry:</span>
|
<span className="fw-semibold">Industry:</span>
|
||||||
<span className="ms-2">{data.industry.name}</span>
|
<span className="ms-2">{data?.industry?.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
{data.taxId && (
|
{data?.taxId && (
|
||||||
<div className="col-12 col-md-6 d-flex align-items-center">
|
<div className="col-12 col-md-6 d-flex align-items-center">
|
||||||
<i className="bx bx-sm bx-id-card me-1"></i>
|
<i className="bx bx-sm bx-id-card me-1"></i>
|
||||||
<span className="fw-semibold">Tax Id:</span>
|
<span className="fw-semibold">Tax Id:</span>
|
||||||
<span className="ms-2">{data.taxId}</span>
|
<span className="ms-2">{data?.taxId}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="col-12 col-md-6 d-flex align-items-center my-4 m-0">
|
<div className="col-12 col-md-6 d-flex align-items-center my-4 m-0">
|
||||||
<i className="bx bx-sm bx-group me-1"></i>
|
<i className="bx bx-sm bx-group me-1"></i>
|
||||||
<span className="fw-semibold">Organization Size:</span>
|
<span className="fw-semibold">Organization Size:</span>
|
||||||
<span className="ms-2">{data.organizationSize}</span>
|
<span className="ms-2">{data?.organizationSize}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-6 d-flex align-items-center">
|
<div className="col-12 col-md-6 d-flex align-items-center">
|
||||||
<i className="bx bx-sm bxs-calendar"></i>
|
<i className="bx bx-sm bxs-calendar"></i>
|
||||||
<span className="fw-semibold">On-Boarding Date:</span>
|
<span className="fw-semibold">On-Boarding Date:</span>
|
||||||
<span className="ms-2">
|
<span className="ms-2">
|
||||||
{formatUTCToLocalTime(data.onBoardingDate)}
|
{formatUTCToLocalTime(data?.onBoardingDate)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table className="table table-bordered text-center text-nowrap table-responsive my-4">
|
<table className="table table-bordered text-center text-nowrap table-responsive my-4">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="1">
|
<td colSpan="1">
|
||||||
<strong>Status</strong>
|
<strong>Status</strong>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="1">
|
<td colSpan="1">
|
||||||
<strong>Active</strong>
|
<strong>Active</strong>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="1">
|
<td colSpan="1">
|
||||||
<strong>In-Progress</strong>
|
<strong>In-Progress</strong>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="1">
|
<td colSpan="1">
|
||||||
<strong>On Hold</strong>
|
<strong>On Hold</strong>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -150,13 +152,13 @@ const Profile = ({ data }) => {
|
|||||||
<div className="col-12 col-md-6 d-flex align-items-center">
|
<div className="col-12 col-md-6 d-flex align-items-center">
|
||||||
<i className="bx bx-sm bx-group me-1"></i>
|
<i className="bx bx-sm bx-group me-1"></i>
|
||||||
<span className="fw-semibold">Activite Employees:</span>
|
<span className="fw-semibold">Activite Employees:</span>
|
||||||
<span className="ms-2">{data.activeEmployees}</span>
|
<span className="ms-2">{data?.activeEmployees}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 col-md-6 d-flex align-items-center my-4 m-0">
|
<div className="col-12 col-md-6 d-flex align-items-center my-4 m-0">
|
||||||
<i className="bx bx-sm bx-group me-1"></i>
|
<i className="bx bx-sm bx-group me-1"></i>
|
||||||
<span className="fw-semibold">In-Active Employee:</span>
|
<span className="fw-semibold">In-Active Employee:</span>
|
||||||
<span className="ms-2">{data.inActiveEmployees}</span>
|
<span className="ms-2">{data?.inActiveEmployees}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -165,6 +167,4 @@ const Profile = ({ data }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default Profile;
|
export default Profile;
|
||||||
// <span className="badge text-bg-primary position-absolute top-0 end-0">
|
|
||||||
// {data?.tenantStatus?.name}
|
|
||||||
// </span>
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const SubScription = ({ onSubmitSubScription, onNext }) => {
|
|||||||
const [frequency, setFrequency] = useState(2);
|
const [frequency, setFrequency] = useState(2);
|
||||||
const [selectedPlanId, setSelectedPlanId] = useState(null);
|
const [selectedPlanId, setSelectedPlanId] = useState(null);
|
||||||
const selectedTenant = useSelector(
|
const selectedTenant = useSelector(
|
||||||
(store) => store.globalVariables.currentTenant
|
(store) => store.globalVariables.currentTenant?.data
|
||||||
);
|
);
|
||||||
const naviget = useNavigate();
|
const naviget = useNavigate();
|
||||||
const {
|
const {
|
||||||
@ -33,7 +33,7 @@ const SubScription = ({ onSubmitSubScription, onNext }) => {
|
|||||||
isPending,
|
isPending,
|
||||||
error,
|
error,
|
||||||
} = useAddSubscription(() => {
|
} = useAddSubscription(() => {
|
||||||
onNext();
|
naviget("/tenants")
|
||||||
});
|
});
|
||||||
const handleSubscriptionSubmit = async () => {
|
const handleSubscriptionSubmit = async () => {
|
||||||
const isValid = await trigger([
|
const isValid = await trigger([
|
||||||
|
|||||||
111
src/components/Tenanat/SubScriptionHistory.jsx
Normal file
111
src/components/Tenanat/SubScriptionHistory.jsx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { useTenantDetails } from "../../hooks/useTenant";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const SubScriptionHistory = ({ tenantId }) => {
|
||||||
|
const { data, isLoading, isError, error } = useTenantDetails(tenantId);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
// Tenant exists → set operationMode: 1
|
||||||
|
dispatch(setCurrentTenant({ operationMode: 1, data }));
|
||||||
|
} else {
|
||||||
|
// No tenant yet → set operationMode: 0
|
||||||
|
dispatch(setCurrentTenant({ operationMode: 0, data: null }));
|
||||||
|
}
|
||||||
|
}, [data, dispatch]);
|
||||||
|
|
||||||
|
const handleUpgradePlan = () => {
|
||||||
|
navigate("/tenants/new-tenant");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) return <div>Loading...</div>;
|
||||||
|
if (isError) return <div>{error}</div>;
|
||||||
|
|
||||||
|
const plan = data?.currentPlan;
|
||||||
|
|
||||||
|
// No subscription plan yet → show "Add Subscription" button
|
||||||
|
if (!plan) {
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<button className="btn btn-sm btn-success" onClick={handleUpgradePlan}>
|
||||||
|
Add Subscription
|
||||||
|
</button>
|
||||||
|
<div className="mt-2 text-center small">
|
||||||
|
<i className="bx bx-info-circle bx-xs"></i> Add your new subscription
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscription plan exists → show details
|
||||||
|
const today = new Date();
|
||||||
|
const start = new Date(plan.startDate);
|
||||||
|
const end = new Date(plan.endDate);
|
||||||
|
|
||||||
|
const totalDays = Math.ceil((end - start) / (1000 * 60 * 60 * 24));
|
||||||
|
const daysLeft = Math.max(0, Math.ceil((end - today) / (1000 * 60 * 60 * 24)));
|
||||||
|
const percentage = Math.min(
|
||||||
|
100,
|
||||||
|
Math.round(((totalDays - daysLeft) / totalDays) * 100)
|
||||||
|
);
|
||||||
|
|
||||||
|
const getProgressVariant = () => {
|
||||||
|
if (percentage < 50) return "success";
|
||||||
|
if (percentage < 80) return "warning";
|
||||||
|
return "danger";
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container-fluid p-2">
|
||||||
|
|
||||||
|
<div className="text-start mb-3">
|
||||||
|
<p className="fw-bold">Active Subscription</p>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-12 col-sm-8 border rounded p-3 shadow-sm">
|
||||||
|
<p className="text-primary fw-bold m-0">{plan.planName || "N/A"}</p>
|
||||||
|
|
||||||
|
<div className="d-flex justify-content-between align-items-end mt-2">
|
||||||
|
<div>
|
||||||
|
<h3 className="m-0">
|
||||||
|
{plan.currency?.symbol} {plan.price}
|
||||||
|
</h3>
|
||||||
|
<small className="text-muted">{plan.description}</small>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-success"
|
||||||
|
onClick={handleUpgradePlan}
|
||||||
|
>
|
||||||
|
Upgrade Plan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-3">
|
||||||
|
{/* Progress bar placeholder */}
|
||||||
|
<div className="d-flex justify-content-between small text-muted mt-1">
|
||||||
|
<span>{totalDays - daysLeft} days used</span>
|
||||||
|
<span>{daysLeft} days left</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-end mt-1 small text-muted">
|
||||||
|
Ends on {end.toLocaleDateString()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-start">
|
||||||
|
{/* Table */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SubScriptionHistory;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import ContactInfro from "./ContactInfro";
|
import ContactInfro from "./ContactInfro";
|
||||||
import SubScription from "./SubScription";
|
import SubScription from "./SubScription";
|
||||||
import OrganizationInfo from "./OrganizationInfo";
|
import OrganizationInfo from "./OrganizationInfo";
|
||||||
@ -12,12 +12,33 @@ import {
|
|||||||
tenantDefaultValues,
|
tenantDefaultValues,
|
||||||
} from "./TenantSchema";
|
} from "./TenantSchema";
|
||||||
import Congratulation from "./congratulation";
|
import Congratulation from "./congratulation";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
const TenantForm = () => {
|
const TenantForm = () => {
|
||||||
|
const HasSelectedCurrentTenant = useSelector(
|
||||||
|
(store) => store.globalVariables.currentTenant
|
||||||
|
);
|
||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
const [completedTabs, setCompletedTabs] = useState([]);
|
const [completedTabs, setCompletedTabs] = useState([]);
|
||||||
|
|
||||||
|
const PlanTextLabel = HasSelectedCurrentTenant?.operationMode === 1 ? "Upgrade Plan":"Select Plan"
|
||||||
|
|
||||||
|
// Jump to subscription if tenant already exists
|
||||||
|
useEffect(() => {
|
||||||
|
if (HasSelectedCurrentTenant) {
|
||||||
|
if (HasSelectedCurrentTenant.operationMode === 1) {
|
||||||
|
// Skip to subscription step
|
||||||
|
setActiveTab(2); // index for "SubScription"
|
||||||
|
setCompletedTabs([0, 1]); // mark previous steps as completed
|
||||||
|
} else if (HasSelectedCurrentTenant.operationMode === 0) {
|
||||||
|
// Start from the beginning (new tenant creation)
|
||||||
|
setActiveTab(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Default: no tenant selected
|
||||||
|
setActiveTab(0);
|
||||||
|
}
|
||||||
|
}, [HasSelectedCurrentTenant,activeTab]);
|
||||||
|
|
||||||
const tenantForm = useForm({
|
const tenantForm = useForm({
|
||||||
resolver: zodResolver(newTenantSchema),
|
resolver: zodResolver(newTenantSchema),
|
||||||
@ -35,24 +56,30 @@ const TenantForm = () => {
|
|||||||
const handleNext = async () => {
|
const handleNext = async () => {
|
||||||
const currentStepFields = getStepFields(activeTab);
|
const currentStepFields = getStepFields(activeTab);
|
||||||
const trigger = getCurrentTrigger();
|
const trigger = getCurrentTrigger();
|
||||||
|
|
||||||
const valid = await trigger(currentStepFields);
|
const valid = await trigger(currentStepFields);
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
setCompletedTabs((prev) => [...new Set([...prev, activeTab])]);
|
setCompletedTabs((prev) => [...new Set([...prev, activeTab])]);
|
||||||
setActiveTab((prev) => Math.min(prev + 1, newTenantConfig.length - 1));
|
|
||||||
|
setActiveTab((prev) => {
|
||||||
|
let nextStep = Math.min(prev + 1, newTenantConfig.length - 1);
|
||||||
|
if (HasSelectedCurrentTenant && nextStep === 2) {
|
||||||
|
nextStep = 3; // skip subscription if already upgraded
|
||||||
|
}
|
||||||
|
return nextStep;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handlePrev = () => {
|
|
||||||
setActiveTab((prev) => Math.max(prev - 1, 0));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const handlePrev = () => {
|
||||||
|
setActiveTab((prev) => Math.max(prev - 1, 0));
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmitTenant = (data) => {
|
const onSubmitTenant = (data) => {
|
||||||
console.log(data);
|
// console.log("Tenant Data:", data);
|
||||||
};
|
};
|
||||||
const onSubmitSubScription = (data) => {
|
const onSubmitSubScription = (data) => {
|
||||||
console.log(data);
|
// console.log("Subscription Data:", data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const newTenantConfig = [
|
const newTenantConfig = [
|
||||||
@ -66,15 +93,26 @@ const TenantForm = () => {
|
|||||||
name: "Organization",
|
name: "Organization",
|
||||||
icon: "bx bx-buildings bx-md",
|
icon: "bx bx-buildings bx-md",
|
||||||
subtitle: "Organization Details",
|
subtitle: "Organization Details",
|
||||||
component: <OrganizationInfo onNext={handleNext} onPrev={handlePrev} onSubmitTenant={onSubmitTenant} />,
|
component: (
|
||||||
|
<OrganizationInfo
|
||||||
|
onNext={handleNext}
|
||||||
|
onPrev={handlePrev}
|
||||||
|
onSubmitTenant={onSubmitTenant}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SubScription",
|
name: "SubScription",
|
||||||
icon: "bx bx-star bx-md",
|
icon: "bx bx-star bx-md",
|
||||||
subtitle: "Select a plan",
|
subtitle: PlanTextLabel,
|
||||||
component: <SubScription onSubmitSubScription={onSubmitSubScription} onNext={handleNext}/>,
|
component: (
|
||||||
|
<SubScription
|
||||||
|
onSubmitSubScription={onSubmitSubScription}
|
||||||
|
onNext={handleNext}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "congratulation",
|
name: "congratulation",
|
||||||
icon: "bx bx-star bx-md",
|
icon: "bx bx-star bx-md",
|
||||||
subtitle: "Select a plan",
|
subtitle: "Select a plan",
|
||||||
@ -83,45 +121,50 @@ const TenantForm = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const isSubscriptionTab = activeTab === 2;
|
const isSubscriptionTab = activeTab === 2;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="wizard-property-listing" className="bs-stepper horizontically mt-2">
|
<div id="wizard-property-listing" className="bs-stepper horizontically mt-2">
|
||||||
<div className="bs-stepper-header border-end text-start ">
|
<div className="bs-stepper-header border-end text-start ">
|
||||||
{newTenantConfig.filter((step) => step.name.toLowerCase() !== "congratulation").map((step, index) => {
|
{newTenantConfig
|
||||||
const isActive = activeTab === index;
|
.filter((step) => step.name.toLowerCase() !== "congratulation")
|
||||||
const isCompleted = completedTabs.includes(index);
|
.map((step, index) => {
|
||||||
|
const isActive = activeTab === index;
|
||||||
|
const isCompleted = completedTabs.includes(index);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={step.name}>
|
<React.Fragment key={step.name}>
|
||||||
<div
|
<div
|
||||||
className={`step ${isActive ? "active" : ""} ${
|
className={`step ${isActive ? "active" : ""} ${
|
||||||
isCompleted ? "crossed" : ""
|
isCompleted ? "crossed" : ""
|
||||||
}`}
|
}`}
|
||||||
data-target={`#step-${index}`}
|
data-target={`#step-${index}`}
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`step-trigger ${isActive ? "active" : ""}`}
|
|
||||||
onClick={() => setActiveTab(index)}
|
|
||||||
>
|
>
|
||||||
<span className="bs-stepper-circle">
|
<button
|
||||||
{isCompleted ? (
|
type="button"
|
||||||
<i className="bx bx-check"></i>
|
className={`step-trigger ${isActive ? "active" : ""}`}
|
||||||
) : (
|
// onClick={() => setActiveTab(index)}
|
||||||
<i className={step.icon}></i>
|
>
|
||||||
)}
|
<span className="bs-stepper-circle">
|
||||||
</span>
|
{isCompleted ? (
|
||||||
<span className="bs-stepper-label">
|
<i className="bx bx-check"></i>
|
||||||
<span className="bs-stepper-title">{step.name}</span>
|
) : (
|
||||||
<span className="bs-stepper-subtitle">{step.subtitle}</span>
|
<i className={step.icon}></i>
|
||||||
</span>
|
)}
|
||||||
</button>
|
</span>
|
||||||
</div>
|
<span className="bs-stepper-label">
|
||||||
{index < newTenantConfig.length - 1 && (
|
<span className="bs-stepper-title">{step.name}</span>
|
||||||
<div className="line text-primary"></div>
|
<span className="bs-stepper-subtitle">
|
||||||
)}
|
{step.subtitle}
|
||||||
</React.Fragment>
|
</span>
|
||||||
);
|
</span>
|
||||||
})}
|
</button>
|
||||||
|
</div>
|
||||||
|
{index < newTenantConfig.length - 1 && (
|
||||||
|
<div className="line text-primary"></div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bs-stepper-content py-2">
|
<div className="bs-stepper-content py-2">
|
||||||
|
|||||||
@ -12,10 +12,16 @@ export const newTenantSchema = z.object({
|
|||||||
organizationName: z.string().nonempty("Organization name is required"),
|
organizationName: z.string().nonempty("Organization name is required"),
|
||||||
officeNumber: z.string().nonempty("Office number is required"),
|
officeNumber: z.string().nonempty("Office number is required"),
|
||||||
contactNumber: z.string().nonempty("Contact number is required"),
|
contactNumber: z.string().nonempty("Contact number is required"),
|
||||||
onBoardingDate: z.coerce.date({
|
onBoardingDate: z.preprocess((val) => {
|
||||||
required_error: "Onboarding date is required",
|
if (typeof val === "string" && val.includes("-")) {
|
||||||
invalid_type_error: "Invalid date format",
|
const [day, month, year] = val.split("-");
|
||||||
}),
|
return new Date(`${year}-${month}-${day}`);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}, z.date({
|
||||||
|
required_error: "Onboarding date is required",
|
||||||
|
invalid_type_error: "Invalid date format",
|
||||||
|
})),
|
||||||
organizationSize: z.string().nonempty("Organization size is required"),
|
organizationSize: z.string().nonempty("Organization size is required"),
|
||||||
industryId: z.string().uuid("Invalid industry ID"),
|
industryId: z.string().uuid("Invalid industry ID"),
|
||||||
reference: z.string().nonempty("Reference is required"),
|
reference: z.string().nonempty("Reference is required"),
|
||||||
|
|||||||
@ -90,11 +90,11 @@ export const useCreateTenant = (onSuccessCallback)=>{
|
|||||||
},
|
},
|
||||||
onSuccess:(data,variables)=>{
|
onSuccess:(data,variables)=>{
|
||||||
showToast("Tenant Created SuccessFully","success")
|
showToast("Tenant Created SuccessFully","success")
|
||||||
dispatch(setCurrentTenant(data))
|
dispatch(setCurrentTenant({operationMode:0,data:data}))
|
||||||
if(onSuccessCallback) onSuccessCallback()
|
if(onSuccessCallback) onSuccessCallback()
|
||||||
},
|
},
|
||||||
onError:(error)=>{
|
onError:(error)=>{
|
||||||
showToast(error.response.message || error.message || `Something went wrong`,"error")
|
showToast(error.response.message || error?.response?.data?.errors || `Something went wrong`,"error")
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
@ -128,8 +128,8 @@ export const useAddSubscription =(onSuccessCallback)=>{
|
|||||||
queryClient.invalidateQueries({queryKey:["Tenants"]});
|
queryClient.invalidateQueries({queryKey:["Tenants"]});
|
||||||
if(onSuccessCallback) onSuccessCallback()
|
if(onSuccessCallback) onSuccessCallback()
|
||||||
},
|
},
|
||||||
onError:(error)=>{
|
onError:(error)=>{
|
||||||
showToast(error.response.message || error.message || `Something went wrong`,"error")
|
showToast(error.response.message || error.message || `Something went wrong`,"error")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import Organization from "../../components/Tenanat/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/Tenanat/EditProfile";
|
import EditProfile from "../../components/Tenanat/EditProfile";
|
||||||
|
import SubScriptionHistory from "../../components/Tenanat/SubScriptionHistory";
|
||||||
|
|
||||||
const TenantDetailsContext = createContext();
|
const TenantDetailsContext = createContext();
|
||||||
export const useTenantDetailsContext = () => useContext(TenantDetailsContext);
|
export const useTenantDetailsContext = () => useContext(TenantDetailsContext);
|
||||||
@ -32,12 +33,12 @@ const TenantDetails = () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
id: "navs-left-bill",
|
id: "navs-left-bill",
|
||||||
label: "Bill",
|
label: "Bills and Plan ",
|
||||||
icon: "bx bx-receipt",
|
icon: "bx bx-receipt",
|
||||||
iconSize: "bx-sm",
|
iconSize: "bx-sm",
|
||||||
content: (
|
content: (
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<ComingSoonPage />
|
<SubScriptionHistory tenantId={tenantId} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import {
|
|||||||
filterSchema,
|
filterSchema,
|
||||||
} from "../../components/Tenanat/TenantSchema";
|
} from "../../components/Tenanat/TenantSchema";
|
||||||
import TenantFilterPanel from "../../components/Tenanat/TenantFilterPanel";
|
import TenantFilterPanel from "../../components/Tenanat/TenantFilterPanel";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setCurrentTenant } from "../../slices/globalVariablesSlice";
|
||||||
|
|
||||||
// This is context that wrapping all components tenant releated , but must pass inside 'TenantContext.Provider'
|
// This is context that wrapping all components tenant releated , but must pass inside 'TenantContext.Provider'
|
||||||
export const TenantContext = createContext();
|
export const TenantContext = createContext();
|
||||||
@ -29,7 +31,8 @@ const TenantPage = () => {
|
|||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const [isRefetching,setRefetching] = useState(false)
|
const [isRefetching,setRefetching] = useState(false)
|
||||||
const [refetchFn, setRefetchFn] = useState(null);
|
const [refetchFn, setRefetchFn] = useState(null);
|
||||||
const [filters, setFilter] = useState();
|
const [filters, setFilter] = useState();
|
||||||
|
const dispatch = useDispatch()
|
||||||
const debouncedSearch = useDebounce(searchText, 500);
|
const debouncedSearch = useDebounce(searchText, 500);
|
||||||
const contextValue = {
|
const contextValue = {
|
||||||
};
|
};
|
||||||
@ -54,7 +57,10 @@ const TenantPage = () => {
|
|||||||
setOffcanvasContent("", null);
|
setOffcanvasContent("", null);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
const handleNewTenant =()=>{
|
||||||
|
dispatch(setCurrentTenant(null))
|
||||||
|
navigate("/tenants/new-tenant")
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<TenantContext.Provider value={contextValue}>
|
<TenantContext.Provider value={contextValue}>
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
@ -89,8 +95,8 @@ const TenantPage = () => {
|
|||||||
data-bs-placement="top"
|
data-bs-placement="top"
|
||||||
data-bs-custom-class="tooltip"
|
data-bs-custom-class="tooltip"
|
||||||
title="Add New Tenant"
|
title="Add New Tenant"
|
||||||
className="p-1 bg-primary rounded-circle"
|
className="p-1 bg-primary rounded-circle cursror-pointer"
|
||||||
onClick={() => navigate("/tenants/new-tenant")}
|
onClick={handleNewTenant}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus fs-4 text-white"></i>
|
<i className="bx bx-plus fs-4 text-white"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -76,6 +76,13 @@ export const TENANT_STATUS = [
|
|||||||
export const CONSTANT_TEXT = {
|
export const CONSTANT_TEXT = {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SUBSCRIPTION_PLAN_FREQUENCIES = {
|
||||||
|
0: "Monthly",
|
||||||
|
1:"Quatery",
|
||||||
|
2:"Half-Yearly",
|
||||||
|
3:"Yearly"
|
||||||
|
}
|
||||||
export const reference = [
|
export const reference = [
|
||||||
{ val: "google", name: "Google" },
|
{ val: "google", name: "Google" },
|
||||||
{ val: "frineds", name: "Friends" },
|
{ val: "frineds", name: "Friends" },
|
||||||
@ -90,4 +97,5 @@ export const orgSize = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||||
|
|
||||||
// export const BASE_URL = "https://api.marcoaiot.com";
|
// export const BASE_URL = "https://api.marcoaiot.com";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user