tenant and subscript form full setup
This commit is contained in:
parent
1dc038c965
commit
34b429c28c
@ -24,7 +24,7 @@ const ContactInfro = ({ onNext }) => {
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div class="row g-6">
|
||||
<div className="row g-6">
|
||||
<div className="col-sm-6">
|
||||
<Label htmlFor="firstName" required>
|
||||
First Name
|
||||
|
@ -6,24 +6,25 @@ useEffect(()=>{
|
||||
setFrequency(selected)
|
||||
},[selected])
|
||||
return (
|
||||
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-sm">
|
||||
<div className='text-center mt-6'>
|
||||
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 0 ? 'active btn-primary text-white' : ''}`}
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 0 ? 'active btn-secondary text-white' : ''}`}
|
||||
onClick={() => setSelected(0)}
|
||||
>
|
||||
Monthly
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 1? 'active btn-primary text-white' : ''}`}
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 1? 'active btn-secondary text-white' : ''}`}
|
||||
onClick={() => setSelected(1)}
|
||||
>
|
||||
Quaterly
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 2 ? 'active btn-primary text-white' : ''}`}
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 2 ? 'active btn-secondary text-white' : ''}`}
|
||||
onClick={() => setSelected(2)}
|
||||
>
|
||||
Half-Yearly
|
||||
@ -31,12 +32,13 @@ useEffect(()=>{
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 3 ? 'active btn-primary text-white' : ''}`}
|
||||
className={`btn px-4 py-2 rounded-0 ${selected === 3 ? 'active btn-secondary text-white' : ''}`}
|
||||
onClick={() => setSelected(3)}
|
||||
>
|
||||
Yearly
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,80 +1,199 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useSubscriptionPlan } from "../../hooks/useTenant";
|
||||
import SegmentedControl from "./SegmentedControl";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { CONSTANT_TEXT } from "../../utils/constants";
|
||||
import Label from "../common/Label";
|
||||
|
||||
const SubScription = ({ onSubmitSubScription }) => {
|
||||
const [frequency, setFrequency] = useState(2);
|
||||
const [selectedPlanId, setSelectedPlanId] = useState(null);
|
||||
|
||||
const {
|
||||
data: plans = [],
|
||||
isError,
|
||||
isLoading,
|
||||
} = useSubscriptionPlan(frequency);
|
||||
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
getValues,
|
||||
trigger,
|
||||
formState: { errors },
|
||||
} = useFormContext();
|
||||
|
||||
|
||||
const handleSubscriptionSubmit = async () => {
|
||||
const isValid = await trigger([
|
||||
"planId",
|
||||
"currencyId",
|
||||
"maxUsers",
|
||||
"frequency",
|
||||
"isTrial",
|
||||
"autoRenew",
|
||||
]);
|
||||
|
||||
if (isValid) {
|
||||
const payload = getValues();
|
||||
onSubmitSubScription(payload);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePlanSelection = (plan) => {
|
||||
setSelectedPlanId(plan.id);
|
||||
setValue("planId", plan.id);
|
||||
setValue("currencyId", plan.currency?.id);
|
||||
setValue("frequency", frequency);
|
||||
};
|
||||
|
||||
const selectedPlan = plans.find((p) => p.id === selectedPlanId);
|
||||
|
||||
const SubScription = () => {
|
||||
const [Frequency, setFrequency] = useState(3);
|
||||
const[selectedPlanId,setSelectedPlanId] = useState()
|
||||
const { data, isError, isLoading } = useSubscriptionPlan(Frequency);
|
||||
console.log(Frequency);
|
||||
return (
|
||||
<div className="text-start">
|
||||
<SegmentedControl setFrequency={setFrequency} />
|
||||
|
||||
{!isLoading && !isError && data.length > 0 && (
|
||||
<>
|
||||
<div className="row g-1 my-1">
|
||||
{data.map((plan) => (
|
||||
<div key={plan.id} className="col-md-6">
|
||||
{!isLoading && !isError && plans.length > 0 && (
|
||||
<div className="row g-4 my-6">
|
||||
{plans.map((plan) => {
|
||||
const isSelected = plan.id === selectedPlanId;
|
||||
|
||||
return (
|
||||
<div key={plan.id} className="col-md-4">
|
||||
<div
|
||||
className={`card h-100 shadow-sm cursor-pointer ${
|
||||
selectedPlanId === plan.id ? "border-primary border-2" : ""
|
||||
className={`card h-100 shadow-none border-1 cursor-pointer ${
|
||||
isSelected ? "border-primary border-2" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedPlanId(plan.id)}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => handlePlanSelection(plan)}
|
||||
>
|
||||
<div className="card-body d-flex flex-column">
|
||||
<div className="card-body d-flex flex-column p-3">
|
||||
<div className="d-flex align-items-center gap-3 mb-3">
|
||||
<i
|
||||
className="bx bxs-package"
|
||||
style={{ fontSize: "40px", color: "#6366f1" }}
|
||||
></i>
|
||||
<i className="bx bxs-package text-primary fs-1"></i>
|
||||
<div>
|
||||
<h5 className="card-title fw-bold mb-1">
|
||||
<p className="card-title fs-4 fw-bold mb-1">
|
||||
{plan.planName}
|
||||
</h5>
|
||||
</p>
|
||||
<p className="text-muted mb-0">{plan.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="fw-bold mt-auto mb-3">
|
||||
{plan.currency?.symbol}
|
||||
{plan.price}
|
||||
{/* <small className="fs-6 fw-normal">
|
||||
/{selectedBilling.label.toLowerCase()}
|
||||
</small> */}
|
||||
</h2>
|
||||
<h4 className="fw-semibold mt-auto mb-3">
|
||||
{plan.currency?.symbol} {plan.price}
|
||||
</h4>
|
||||
|
||||
<ul className="list-unstyled mb-4">
|
||||
<li className="mb-2">
|
||||
<i className="bx bx-check text-success me-2"></i>
|
||||
Max Users: {plan.maxUser}
|
||||
<ul className="list-unstyled d-flex gap-4 flex-wrap mb-2">
|
||||
<li className="d-flex align-items-center">
|
||||
<i className="bx bx-check-double text-success me-1"></i>
|
||||
Max Users {plan.maxUser}
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<i className="bx bx-check text-success me-2"></i>
|
||||
Storage: {plan.maxStorage} MB
|
||||
<li className="d-flex align-items-center">
|
||||
<i className="bx bx-check-double text-success me-2"></i>
|
||||
Storage {plan.maxStorage} MB
|
||||
</li>
|
||||
<li className="mb-2">
|
||||
<i className="bx bx-check text-success me-2"></i>
|
||||
Trial Days: {plan.trialDays}
|
||||
<li className="d-flex align-items-center">
|
||||
<i className="bx bx-check-double text-success me-2"></i>
|
||||
Trial Days {plan.trialDays}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<div className="divider my-3">
|
||||
<div className="divider-text card-text text-uppercase text-muted small">
|
||||
Features
|
||||
</div>
|
||||
</div>
|
||||
{Object.entries(plan.features.modules)
|
||||
.filter(([key]) => key !== "id")
|
||||
.map(([key, mod]) => (
|
||||
<div
|
||||
key={key}
|
||||
className="mb-2 d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
className={`bx bx-check bx-xs rounded-circle text-white ${
|
||||
mod.enabled ? "bg-success" : "bg-secondary"
|
||||
}`}
|
||||
></i>
|
||||
<small className="ms-2">{mod.name}</small>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className={`btn mt-auto ${
|
||||
selectedPlanId === plan.id
|
||||
? "btn-primary"
|
||||
: "btn-outline-primary"
|
||||
className={`btn mt-3 ${
|
||||
isSelected ? "btn-primary" : "btn-outline-primary"
|
||||
}`}
|
||||
onClick={() => setSelectedPlanId(plan.id)}
|
||||
onClick={() => handlePlanSelection(plan)}
|
||||
>
|
||||
{selectedPlanId === plan.id ? "Selected" : "Get Plan"}
|
||||
{isSelected ? "Selected" : "Select Plan"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Form Inputs */}
|
||||
<div className="row g-2 mt-3">
|
||||
<div className="col-sm-4">
|
||||
<Label htmlFor="maxUsers" required> Team Size</Label>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control form-control-sm"
|
||||
{...register("maxUsers", {
|
||||
valueAsNumber: true,
|
||||
min: { value: 1, message: "Team size must be at least 1" },
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-12">
|
||||
<div className="d-flex justify-content-between">
|
||||
<label className="form-label fw-semibold d-block">
|
||||
Enable auto renew
|
||||
</label>
|
||||
<label className="switch switch-square switch-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="switch-input"
|
||||
{...register("autoRenew")}
|
||||
/>
|
||||
<span className="switch-toggle-slider">
|
||||
<span className="switch-on">
|
||||
<i className="icon-base bx bx-check"></i>
|
||||
</span>
|
||||
<span className="switch-off">
|
||||
<i className="icon-base bx bx-x"></i>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<small className="text-secondary text-tiny">
|
||||
{CONSTANT_TEXT.RenewsubscriptionLabel}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
{Object.keys(errors).length > 0 && (
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{Object.entries(errors).map(([key, error]) => (
|
||||
<div key={key} className="danger-text">
|
||||
{error?.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="d-flex text-center mt-4">
|
||||
<button
|
||||
onClick={handleSubscriptionSubmit}
|
||||
className="btn btn-primary"
|
||||
type="button"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -46,7 +46,7 @@ const TenantForm = () => {
|
||||
const onSubmitTenant = (data) => {
|
||||
console.log(data);
|
||||
};
|
||||
const onSubmitSubScription = () => {
|
||||
const onSubmitSubScription = (data) => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
@ -67,13 +67,13 @@ const TenantForm = () => {
|
||||
name: "SubScription",
|
||||
icon: "bx bx-star bx-md",
|
||||
subtitle: "Select a plan",
|
||||
component: <SubScription />,
|
||||
component: <SubScription onSubmitSubScription={onSubmitSubScription} />,
|
||||
},
|
||||
];
|
||||
|
||||
const isSubscriptionTab = activeTab === 2;
|
||||
return (
|
||||
<div id="wizard-property-listing" className="bs-stepper vertical mt-2">
|
||||
<div id="wizard-property-listing" className="bs-stepper horizontically mt-2">
|
||||
<div className="bs-stepper-header border-end text-start ">
|
||||
{newTenantConfig.map((step, index) => {
|
||||
const isActive = activeTab === index;
|
||||
@ -113,7 +113,7 @@ const TenantForm = () => {
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="bs-stepper-content">
|
||||
<div className="bs-stepper-content py-2">
|
||||
{isSubscriptionTab ? (
|
||||
<FormProvider {...subscriptionForm}>
|
||||
<form onSubmit={subscriptionForm.handleSubmit(onSubmitTenant)}>
|
||||
|
@ -41,12 +41,12 @@ export const tenantDefaultValues = {
|
||||
|
||||
|
||||
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"),
|
||||
// tenantId: z.string().uuid("Invalid tenant ID"),
|
||||
planId: z.string().min(1,{message:"Please select Plan"}),
|
||||
currencyId: z.string().uuid("Invalid currency"),
|
||||
maxUsers: z
|
||||
.number({ invalid_type_error: "Max users must be a number" })
|
||||
.min(1, "At least one user is required"),
|
||||
.number({ invalid_type_error: " Must be a number" })
|
||||
.min(1, "Team size is required and must be greater than zero"),
|
||||
frequency: z
|
||||
.number({ invalid_type_error: "Frequency must be a number" })
|
||||
.min(1, "Frequency must be at least 1"),
|
||||
@ -55,9 +55,9 @@ export const subscriptionSchema = z.object({
|
||||
});
|
||||
|
||||
export const subscriptionDefaultValues = {
|
||||
tenantId: "", // should be a UUID
|
||||
planId: "", // should be a UUID
|
||||
currencyId: "", // should be a UUID
|
||||
// tenantId: "",
|
||||
planId: "",
|
||||
currencyId: "",
|
||||
maxUsers: 1,
|
||||
frequency: 1,
|
||||
isTrial: false,
|
||||
|
@ -64,5 +64,13 @@ export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8"
|
||||
// 1 - Expense Manage
|
||||
export const EXPENSE_MANAGEMENT = "a4e25142-449b-4334-a6e5-22f70e4732d7"
|
||||
|
||||
|
||||
export const BASIC_PLAN = "08ddd43e-ca62-4cf4-8d7b-569a364307f4"
|
||||
|
||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||
// export const BASE_URL = "https://api.marcoaiot.com";
|
||||
|
||||
|
||||
export const CONSTANT_TEXT = {
|
||||
RenewsubscriptionLabel : " This option; if checked, will renew your productive subscription, if the current plan expires. However, this might prevent you from"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user