initially setup tenant manag. setup wizard-form and properly manage data. handle two sperate form with on wizard
This commit is contained in:
parent
5a209ae24e
commit
d48b4c4ef3
107
src/components/Tenanat/ContactInfro.jsx
Normal file
107
src/components/Tenanat/ContactInfro.jsx
Normal file
@ -0,0 +1,107 @@
|
||||
import React from "react";
|
||||
import Label from "../common/Label";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
const ContactInfro = ({ onNext }) => {
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
trigger,
|
||||
formState: { errors },
|
||||
} = useFormContext();
|
||||
|
||||
|
||||
const handleNext = async () => {
|
||||
const valid = await trigger([
|
||||
"firstName",
|
||||
"lastName",
|
||||
"email",
|
||||
"contactNumber",
|
||||
"billingAddress",
|
||||
]);
|
||||
if (valid) {
|
||||
onNext(); // go to next tab
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div class="row g-6">
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="firstName" required>
|
||||
First Name
|
||||
</Label>
|
||||
<input
|
||||
id="firstName"
|
||||
type="text"
|
||||
className={`form-control form-control-sm ${errors.firstName ? "is-invalid" : ""}`}
|
||||
{...register("firstName")}
|
||||
/>
|
||||
{errors.firstName && (
|
||||
<div className="invalid-feedback">{errors.firstName.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="lastName" required>
|
||||
Last Name
|
||||
</Label>
|
||||
<input
|
||||
id="lastName"
|
||||
type="text"
|
||||
className={`form-control form-control-sm ${errors.lastName ? "is-invalid" : ""}`}
|
||||
{...register("lastName")}
|
||||
/>
|
||||
{errors.lastName && (
|
||||
<div className="invalid-feedback">{errors.lastName.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="email" required>
|
||||
Email
|
||||
</Label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
className={`form-control form-control-sm ${errors.email ? "is-invalid" : ""}`}
|
||||
{...register("email")}
|
||||
/>
|
||||
{errors.email && (
|
||||
<div className="invalid-feedback">{errors.email.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="contactNumber" required>
|
||||
Contact Number
|
||||
</Label>
|
||||
<input
|
||||
id="contactNumber"
|
||||
type="text"
|
||||
className={`form-control form-control-sm ${errors.contactNumber ? "is-invalid" : ""}`}
|
||||
{...register("contactNumber")}
|
||||
/>
|
||||
{errors.contactNumber && (
|
||||
<div className="invalid-feedback">{errors.contactNumber.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<Label htmlFor="billingAddress" required>
|
||||
Billing Address
|
||||
</Label>
|
||||
<textarea
|
||||
id="billingAddress"
|
||||
className={`form-control ${errors.billingAddress ? "is-invalid" : ""}`}
|
||||
{...register("billingAddress")}
|
||||
rows={3}
|
||||
/>
|
||||
{errors.billingAddress && (
|
||||
<div className="invalid-feedback">{errors.billingAddress.message}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="d-flex justify-content-end mt-3">
|
||||
<button type="button" className="btn btn-primary" onClick={handleNext}>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactInfro;
|
234
src/components/Tenanat/OrganizationInfo.jsx
Normal file
234
src/components/Tenanat/OrganizationInfo.jsx
Normal file
@ -0,0 +1,234 @@
|
||||
import React from "react";
|
||||
import { useFormContext, Controller } from "react-hook-form";
|
||||
import Label from "../common/Label";
|
||||
import DatePicker from "../common/DatePicker";
|
||||
|
||||
const OrganizationInfo = ({ onNext, onPrev }) => {
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
trigger,
|
||||
formState: { errors },
|
||||
} = useFormContext();
|
||||
|
||||
const handleNext = async () => {
|
||||
const valid = await trigger([
|
||||
"organizationName",
|
||||
"officeNumber",
|
||||
"domainName",
|
||||
"description",
|
||||
"onBoardingDate",
|
||||
"organizationSize",
|
||||
"taxId",
|
||||
"industryId",
|
||||
"reference",
|
||||
"logoImage",
|
||||
]);
|
||||
if (valid) onNext();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="row g-6">
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="organizationName" required>
|
||||
Organization Name
|
||||
</Label>
|
||||
|
||||
<input
|
||||
id="organizationName"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.organizationName ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("organizationName")}
|
||||
/>
|
||||
{errors.organizationName && (
|
||||
<div className="invalid-feedback">
|
||||
{errors.organizationName.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="officeNumber" required>
|
||||
Office Number
|
||||
</Label>
|
||||
<input
|
||||
id="officeNumber"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.officeNumber ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("officeNumber")}
|
||||
/>
|
||||
{errors.officeNumber && (
|
||||
<div className="invalid-feedback">{errors.officeNumber.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="domainName" required>
|
||||
Domain Name
|
||||
</Label>
|
||||
<input
|
||||
id="domainName"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.domainName ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("domainName")}
|
||||
/>
|
||||
{errors.domainName && (
|
||||
<div className="invalid-feedback">{errors.domainName.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="taxId" required>
|
||||
Tax ID
|
||||
</Label>
|
||||
<input
|
||||
id="taxId"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.taxId ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("taxId")}
|
||||
/>
|
||||
{errors.taxId && (
|
||||
<div className="invalid-feedback">{errors.taxId.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="onBoardingDate" required>
|
||||
Onboarding Date
|
||||
</Label>
|
||||
{/* this will upcomming from main */}
|
||||
{/* <DatePicker
|
||||
name="onBoardingDate"
|
||||
control={control}
|
||||
placeholder="Select onboarding date"
|
||||
maxDate={new Date()}
|
||||
className={errors.onBoardingDate ? "is-invalid" : ""}
|
||||
/>
|
||||
{errors.onBoardingDate && (
|
||||
<div className="invalid-feedback">{errors.onBoardingDate.message}</div>
|
||||
)} */}
|
||||
|
||||
<label htmlFor="onBoardingDate" className="form-label">
|
||||
Onboarding Date <span className="text-danger">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
id="onBoardingDate"
|
||||
{...register("onBoardingDate")}
|
||||
className={`form-control form-control-sm ${
|
||||
errors.onBoardingDate ? "is-invalid" : ""
|
||||
}`}
|
||||
/>
|
||||
{errors.onBoardingDate && (
|
||||
<div className="invalid-feedback">
|
||||
{errors.onBoardingDate.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="organizationSize" required>
|
||||
Organization Size
|
||||
</Label>
|
||||
<input
|
||||
id="organizationSize"
|
||||
type="number"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.organizationSize ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("organizationSize")}
|
||||
/>
|
||||
{errors.organizationSize && (
|
||||
<div className="invalid-feedback">
|
||||
{errors.organizationSize.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="industryId" required>
|
||||
Industry
|
||||
</Label>
|
||||
<Controller
|
||||
name="industryId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
{...field}
|
||||
id="industryId"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.industryId ? "is-invalid" : ""
|
||||
}`}
|
||||
options={[
|
||||
{ label: "Tech", value: 1 },
|
||||
{ label: "Healthcare", value: 2 },
|
||||
]} // replace with your data
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.industryId && (
|
||||
<div className="invalid-feedback">{errors.industryId.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="reference">Reference</Label>
|
||||
<input
|
||||
id="reference"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.reference ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("reference")}
|
||||
/>
|
||||
{errors.reference && (
|
||||
<div className="invalid-feedback">{errors.reference.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-12">
|
||||
<Label htmlFor="description">Description</Label>
|
||||
<textarea
|
||||
id="description"
|
||||
rows={3}
|
||||
className={`form-control form-control-sm ${
|
||||
errors.description ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("description")}
|
||||
/>
|
||||
{errors.description && (
|
||||
<div className="invalid-feedback">{errors.description.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-sm-12">
|
||||
<Label htmlFor="logoImage">Logo Image</Label>
|
||||
<input
|
||||
id="logoImage"
|
||||
type="file"
|
||||
className={`form-control form-control-sm ${
|
||||
errors.logoImage ? "is-invalid" : ""
|
||||
}`}
|
||||
{...register("logoImage")}
|
||||
/>
|
||||
{errors.logoImage && (
|
||||
<div className="invalid-feedback">{errors.logoImage.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="d-flex justify-content-between mt-3">
|
||||
<button type="button" className="btn btn-secondary" onClick={onPrev}>
|
||||
Back
|
||||
</button>
|
||||
<button type="button" className="btn btn-primary" onClick={handleNext}>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrganizationInfo;
|
9
src/components/Tenanat/SubScription.jsx
Normal file
9
src/components/Tenanat/SubScription.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
const SubScription = () => {
|
||||
return (
|
||||
<div>SubScription</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SubScription
|
133
src/components/Tenanat/TenantForm.jsx
Normal file
133
src/components/Tenanat/TenantForm.jsx
Normal file
@ -0,0 +1,133 @@
|
||||
import React, { useState } from "react";
|
||||
import ContactInfro from "./ContactInfro";
|
||||
import SubScription from "./SubScription";
|
||||
import OrganizationInfo from "./OrganizationInfo";
|
||||
import { useForm, FormProvider } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
getStepFields,
|
||||
newTenantSchema,
|
||||
subscriptionDefaultValues,
|
||||
subscriptionSchema,
|
||||
tenantDefaultValues,
|
||||
} from "./TenantSchema";
|
||||
|
||||
const TenantForm = () => {
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const [completedTabs, setCompletedTabs] = useState([]);
|
||||
|
||||
const tenantForm = useForm({
|
||||
resolver: zodResolver(newTenantSchema),
|
||||
defaultValues: tenantDefaultValues,
|
||||
});
|
||||
|
||||
const subscriptionForm = useForm({
|
||||
resolver: zodResolver(subscriptionSchema),
|
||||
defaultValues: subscriptionDefaultValues,
|
||||
});
|
||||
|
||||
const getCurrentTrigger = () =>
|
||||
activeTab === 2 ? subscriptionForm.trigger : tenantForm.trigger;
|
||||
|
||||
const handleNext = async () => {
|
||||
const currentStepFields = getStepFields(activeTab);
|
||||
const trigger = getCurrentTrigger();
|
||||
|
||||
const valid = await trigger(currentStepFields);
|
||||
|
||||
if (valid) {
|
||||
setCompletedTabs((prev) => [...new Set([...prev, activeTab])]);
|
||||
setActiveTab((prev) => Math.min(prev + 1, newTenantConfig.length - 1));
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmitTenant = (data) => {
|
||||
console.log(data);
|
||||
};
|
||||
const onSubmitSubScription = () => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
const newTenantConfig = [
|
||||
{
|
||||
name: "Contact Info",
|
||||
icon: "bx bx-user bx-md",
|
||||
subtitle: "Provide Contact Details",
|
||||
component: <ContactInfro onNext={handleNext} />,
|
||||
},
|
||||
{
|
||||
name: "Organization",
|
||||
icon: "bx bx-home bx-md",
|
||||
subtitle: "Organization Details",
|
||||
component: <OrganizationInfo onNext={handleNext} />,
|
||||
},
|
||||
{
|
||||
name: "SubScription",
|
||||
icon: "bx bx-star bx-md",
|
||||
subtitle: "Select a plan",
|
||||
component: <SubScription />,
|
||||
},
|
||||
];
|
||||
|
||||
const isSubscriptionTab = activeTab === 2;
|
||||
return (
|
||||
<div id="wizard-property-listing" className="bs-stepper vertical mt-2">
|
||||
<div className="bs-stepper-header border-end text-start">
|
||||
{newTenantConfig.map((step, index) => {
|
||||
const isActive = activeTab === index;
|
||||
const isCompleted = completedTabs.includes(index);
|
||||
|
||||
return (
|
||||
<React.Fragment key={step.name}>
|
||||
<div
|
||||
className={`step ${isActive ? "active" : ""} ${
|
||||
isCompleted ? "crossed" : ""
|
||||
}`}
|
||||
data-target={`#step-${index}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`step-trigger ${isActive ? "active" : ""}`}
|
||||
onClick={() => setActiveTab(index)}
|
||||
>
|
||||
<span className="bs-stepper-circle">
|
||||
{isCompleted ? (
|
||||
<i className="bx bx-check"></i>
|
||||
) : (
|
||||
<i className={step.icon}></i>
|
||||
)}
|
||||
</span>
|
||||
<span className="bs-stepper-label">
|
||||
<span className="bs-stepper-title">{step.name}</span>
|
||||
<span className="bs-stepper-subtitle">{step.subtitle}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
{index < newTenantConfig.length - 1 && (
|
||||
<div className="line"></div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="bs-stepper-content">
|
||||
{isSubscriptionTab ? (
|
||||
<FormProvider {...subscriptionForm}>
|
||||
<form onSubmit={subscriptionForm.handleSubmit(onSubmitTenant)}>
|
||||
{newTenantConfig[activeTab].component}
|
||||
</form>
|
||||
</FormProvider>
|
||||
) : (
|
||||
<FormProvider {...tenantForm}>
|
||||
<form onSubmit={tenantForm.handleSubmit(onSubmitSubScription)}>
|
||||
{newTenantConfig[activeTab].component}
|
||||
</form>
|
||||
</FormProvider>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TenantForm;
|
100
src/components/Tenanat/TenantSchema.js
Normal file
100
src/components/Tenanat/TenantSchema.js
Normal file
@ -0,0 +1,100 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const newTenantSchema = z.object({
|
||||
firstName: z.string().nonempty("First name is required"),
|
||||
lastName: z.string().nonempty("Last name is required"),
|
||||
email: z.string().email("Invalid email address"),
|
||||
description: z.string().nonempty("Description is required"),
|
||||
domainName: z.string().nonempty("Domain name is required"),
|
||||
billingAddress: z.string().nonempty("Billing address is required"),
|
||||
taxId: z.string().nonempty("Tax ID is required"),
|
||||
logoImage: z.string().nonempty("Logo image is required"),
|
||||
organizationName: z.string().nonempty("Organization name is required"),
|
||||
officeNumber: z.string().nonempty("Office number is required"),
|
||||
contactNumber: z.string().nonempty("Contact number is required"),
|
||||
onBoardingDate: z.coerce.date({
|
||||
required_error: "Onboarding date is required",
|
||||
invalid_type_error: "Invalid date format",
|
||||
}),
|
||||
organizationSize: z.string().nonempty("Organization size is required"),
|
||||
industryId: z.string().uuid("Invalid industry ID"),
|
||||
reference: z.string().nonempty("Reference is required"),
|
||||
});
|
||||
|
||||
export const tenantDefaultValues = {
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
email: "",
|
||||
description: "",
|
||||
domainName: "",
|
||||
billingAddress: "",
|
||||
taxId: "",
|
||||
logoImage: "",
|
||||
organizationName: "",
|
||||
officeNumber: "",
|
||||
contactNumber: "",
|
||||
onBoardingDate: new Date(), // or `null` if you want it empty
|
||||
organizationSize: "",
|
||||
industryId: "", // should be a valid UUID if pre-filled
|
||||
reference: "",
|
||||
};
|
||||
|
||||
|
||||
export const subscriptionSchema = z.object({
|
||||
tenantId: z.string().uuid("Invalid tenant ID"),
|
||||
planId: z.string().uuid("Invalid plan ID"),
|
||||
currencyId: z.string().uuid("Invalid currency ID"),
|
||||
maxUsers: z
|
||||
.number({ invalid_type_error: "Max users must be a number" })
|
||||
.min(1, "At least one user is required"),
|
||||
frequency: z
|
||||
.number({ invalid_type_error: "Frequency must be a number" })
|
||||
.min(1, "Frequency must be at least 1"),
|
||||
isTrial: z.boolean(),
|
||||
autoRenew: z.boolean(),
|
||||
});
|
||||
|
||||
export const subscriptionDefaultValues = {
|
||||
tenantId: "", // should be a UUID
|
||||
planId: "", // should be a UUID
|
||||
currencyId: "", // should be a UUID
|
||||
maxUsers: 1,
|
||||
frequency: 1,
|
||||
isTrial: false,
|
||||
autoRenew: false,
|
||||
};
|
||||
|
||||
export const getStepFields = (stepIndex) => {
|
||||
const stepFieldMap = {
|
||||
0: [
|
||||
"firstName",
|
||||
"lastName",
|
||||
"email",
|
||||
"contactNumber",
|
||||
"billingAddress",
|
||||
],
|
||||
1: [
|
||||
"organizationName",
|
||||
"officeNumber",
|
||||
"domainName",
|
||||
"description",
|
||||
"onBoardingDate",
|
||||
"organizationSize",
|
||||
"taxId",
|
||||
"industryId",
|
||||
"reference",
|
||||
"logoImage",
|
||||
],
|
||||
2: [
|
||||
"tenantId",
|
||||
"planId",
|
||||
"currencyId",
|
||||
"maxUsers",
|
||||
"frequency",
|
||||
"isTrial",
|
||||
"autoRenew",
|
||||
],
|
||||
};
|
||||
|
||||
return stepFieldMap[stepIndex] || [];
|
||||
};
|
37
src/components/Tenanat/TenantsList.jsx
Normal file
37
src/components/Tenanat/TenantsList.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React, { useState } from "react";
|
||||
import { useTenants } from "../../hooks/useTenant";
|
||||
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||
|
||||
const TenantsList = () => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const { data, isLoading, isError, isInitialLoading, error } = useTenants(
|
||||
ITEMS_PER_PAGE,
|
||||
currentPage
|
||||
);
|
||||
|
||||
const paginate = (page) => {
|
||||
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
|
||||
setCurrentPage(page);
|
||||
}
|
||||
};
|
||||
|
||||
if (isInitialLoading)
|
||||
return (
|
||||
<div>
|
||||
<h1>Loading...</h1>
|
||||
</div>
|
||||
);
|
||||
if (isError) return <div>{error}</div>;
|
||||
return (
|
||||
<div className="card p-2">
|
||||
<div className="text-end">
|
||||
<button className="bt btn-sm btn-primary me-2">
|
||||
<span class="icon-base bx bx-pie-chart-alt me-1"></span>Create Tenant
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-datatable text-nowrap table-responsive"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TenantsList;
|
12
src/components/common/Label.jsx
Normal file
12
src/components/common/Label.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
const Label = ({ htmlFor, children, required = false, className = "" }) => {
|
||||
return (
|
||||
<label htmlFor={htmlFor} className={`form-label d-block ${className}`}>
|
||||
{children}
|
||||
{required && <span className="text-danger ms-1">*</span>}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
export default Label;
|
@ -73,9 +73,9 @@
|
||||
"link": "",
|
||||
"submenu": [
|
||||
{
|
||||
"text": "Users",
|
||||
"text": "Tenants",
|
||||
"available": true,
|
||||
"link": "/employees/"
|
||||
"link": "/tenants"
|
||||
},
|
||||
{
|
||||
"text": "Masters",
|
||||
|
22
src/hooks/useTenant.js
Normal file
22
src/hooks/useTenant.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { TenantRepository } from "../repositories/TenantRepository";
|
||||
|
||||
export const useTenants = (
|
||||
pageSize,
|
||||
pageNumber,
|
||||
filter,
|
||||
searchString = ""
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: ["Tenants", pageNumber, pageSize],
|
||||
queryFn: async () => {
|
||||
const response = await TenantRepository.getTenanatList(
|
||||
pageSize,
|
||||
pageNumber,
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
keepPreviousData: true,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
};
|
20
src/pages/Tenant/CreateTenant.jsx
Normal file
20
src/pages/Tenant/CreateTenant.jsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import Breadcrumb from '../../components/common/Breadcrumb'
|
||||
import TenantForm from '../../components/Tenanat/TenantForm'
|
||||
|
||||
const CreateTenant = () => {
|
||||
return (
|
||||
<div className='container-fluid'>
|
||||
<Breadcrumb
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Tenant", link: '/tenants' },
|
||||
{ label: "New Tenant", link: null },
|
||||
]}
|
||||
/>
|
||||
<TenantForm/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateTenant
|
21
src/pages/Tenant/TenantPage.jsx
Normal file
21
src/pages/Tenant/TenantPage.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
import Breadcrumb from '../../components/common/Breadcrumb'
|
||||
import TenantsList from '../../components/Tenanat/TenantsList'
|
||||
|
||||
const TenantPage = () => {
|
||||
return (
|
||||
<div className='container-fluid'>
|
||||
<Breadcrumb
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Tenant", link: null },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TenantsList />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TenantPage
|
10
src/repositories/TenantRepository.jsx
Normal file
10
src/repositories/TenantRepository.jsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { api } from "../utils/axiosClient";
|
||||
|
||||
export const TenantRepository = {
|
||||
|
||||
getTenanatList:(pageSize, pageNumber, filter,searchString)=>{
|
||||
const payloadJsonString = JSON.stringify(filter);
|
||||
return api.get(`/api/Tenant/list?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`)
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ import LegalInfoCard from "../pages/TermsAndConditions/LegalInfoCard";
|
||||
import ProtectedRoute from "./ProtectedRoute";
|
||||
import Directory from "../pages/Directory/Directory";
|
||||
import LoginWithOtp from "../pages/authentication/LoginWithOtp";
|
||||
import TenantPage from "../pages/Tenant/TenantPage";
|
||||
import CreateTenant from "../pages/Tenant/CreateTenant";
|
||||
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
@ -77,6 +79,8 @@ const router = createBrowserRouter(
|
||||
{ path: "/activities/reports", element: <Reports /> },
|
||||
{ path: "/gallary", element: <ImageGallary /> },
|
||||
{ path: "/masters", element: <MasterPage /> },
|
||||
{ path: "/tenants", element: <TenantPage /> },
|
||||
{ path: "/tenants/new-tenant", element: <CreateTenant /> },
|
||||
{ path: "/help/support", element: <Support /> },
|
||||
{ path: "/help/docs", element: <Documentation /> },
|
||||
{ path: "/help/connect", element: <Connect /> },
|
||||
|
Loading…
x
Reference in New Issue
Block a user