diff --git a/src/assets/vendor/css/core.css b/src/assets/vendor/css/core.css index 70f4fb09..3a301b65 100644 --- a/src/assets/vendor/css/core.css +++ b/src/assets/vendor/css/core.css @@ -17596,6 +17596,31 @@ html:not([dir=rtl]) .toast.bs-toast .toast-header .btn-close { } } @media (min-width: 768px) { + /* width */ + + .w-md-auto { + width: auto !important; +} + +.w-md-20 { + width: 20% !important; +} + +.w-md-25 { + width: 25% !important; +} + +.w-md-50 { + width: 50% !important; +} + +.w-md-60 { + width: 60% !important; +} + +.w-md-75 { + width: 75% !important; +} .object-fit-md-contain { object-fit: contain !important; } diff --git a/src/components/Tenant/SubScriptionHistory.jsx b/src/components/Tenant/SubScriptionHistory.jsx index a587a84e..643d2be3 100644 --- a/src/components/Tenant/SubScriptionHistory.jsx +++ b/src/components/Tenant/SubScriptionHistory.jsx @@ -43,15 +43,14 @@ const SubScriptionHistory = ({ tenantId }) => { ); } - // Format dates + const end = plan?.endDate ? new Date(plan.endDate) : null; const today = new Date(); const daysLeft = end - ? Math.max(0, Math.ceil((end - today) / (1000 * 60 * 60 * 24))) + ? Math.max(0, Math.ceil((end - plan?.startDate) / (1000 * 60 * 60 * 24))) : 0; - // Render logic for subscription history table const renderSubscriptionHistory = () => { if (!subscriptionHistory || subscriptionHistory.length === 0) { return ( @@ -72,23 +71,35 @@ const SubScriptionHistory = ({ tenantId }) => { - - + - - + + + {sortedHistory.map((item) => ( - - - + + - - + + +
DateTypeInvoice AmountPlan NameActionDateStatusAction
{formatUTCToLocalTime(item?.createdAt)}{SUBSCRIPTION_PLAN_FREQUENCIES[item.frequency] || "N/A"} + {item.planName} {item.currency?.symbol || "₹"} {item.price} {item.planName} + + + {formatUTCToLocalTime(item?.createdAt)} by,{" "} + {item?.createdBy?.firstName} + + +
+

{" "} + Paid +
+
-
@@ -120,100 +130,172 @@ const SubScriptionHistory = ({ tenantId }) => { {/* Card-based view for smaller screens */} - ); }; return ( -
-
- {/* Left Card: Active Subscription */} -
-
-
-
Active Subscription
-
- -

- {plan.planName || "N/A"} -

- {plan.description && ( -

{plan.description}

- )} - -
-

- {plan.currency?.symbol || "₹"} {plan.price} -

- - {SUBSCRIPTION_PLAN_FREQUENCIES[plan.frequency] || ""} +
+
+
+
+

Current Plan

+ + You can update your plan anytime for best benifit from the product + and track your projct + +
+

Switch Plan

+
+
+
+
+ +
- -
-
- Activated Since:{" "} - {plan.startDate ? formatUTCToLocalTime(plan.startDate) : "N/A"} ( - {daysLeft} days left) +
+
+
+ {plan.planName || "N/A"} + + {" "} + {plan.currency?.symbol || "₹"} {plan.price} + + + {" "} + {SUBSCRIPTION_PLAN_FREQUENCIES[plan.frequency] || ""} + +
+ + +
-
- Ends on:{" "} - {plan.endDate ? formatUTCToLocalTime(plan.endDate) : "N/A"} +
+

+ Includes up to 100 userss, 10GB individual cloud storage and + access maximum features +

+
+ Activated Since:{" "} + + {" "} + {plan.startDate + ? formatUTCToLocalTime(plan.startDate) + : "N/A"}{" "} + ({daysLeft} days left) + +
- - {/* Features list */} -
-
Features
-
- {features?.modules && - Object.entries(features.modules).map(([key, mod]) => { - if (!mod?.name) return null; - return ( -
- - {mod.name} -
- ); - })} -
-
- -
- -
+
- {/* Right Card: Subscription History */} -
-
-
-
- History -
-
- {renderSubscriptionHistory()} +
+ +
+
+
+

Billing History

+ + Sumary on the payment history for the subscription plan of the + application +
+

Billing History

+
{renderSubscriptionHistory()}
); }; -export default SubScriptionHistory; \ No newline at end of file +export default SubScriptionHistory; + +//
+//
+// {/* Left Card: Active Subscription */} +//
+//
+//
+//
Active Subscription
+//
+ +//

+// {plan.planName || "N/A"} +//

+// {plan.description && ( +//

{plan.description}

+// )} + +//
+//

+// {plan.currency?.symbol || "₹"} {plan.price} +//

+// +// {SUBSCRIPTION_PLAN_FREQUENCIES[plan.frequency] || ""} +// +//
+ +//
+//
+// Activated Since:{" "} +// {plan.startDate ? formatUTCToLocalTime(plan.startDate) : "N/A"} ( +// {daysLeft} days left) +//
+//
+// Ends on:{" "} +// {plan.endDate ? formatUTCToLocalTime(plan.endDate) : "N/A"} +//
+//
+ +// {/* Features list */} +//
+//
Features
+//
+// {features?.modules && +// Object.entries(features.modules).map(([key, mod]) => { +// if (!mod?.name) return null; +// return ( +//
+// +// {mod.name} +//
+// ); +// })} +//
+//
+ +//
+// +//
+//
+//
+ +//
+//
+//
+//
+// History +//
+//
+// {renderSubscriptionHistory()} +//
+//
+//
+//
diff --git a/src/components/UserSubscription/ProcessedPayment.jsx b/src/components/UserSubscription/ProcessedPayment.jsx index 9f7ed25b..c08c813c 100644 --- a/src/components/UserSubscription/ProcessedPayment.jsx +++ b/src/components/UserSubscription/ProcessedPayment.jsx @@ -37,7 +37,10 @@ const ProcessedPayment = ({ const { data: plans, isError: isPlanError, - isLoading,isError,isRefetching,refetch + isLoading, + isError, + isRefetching, + refetch, } = useSubscription(frequency); useEffect(() => { if (!plans || !selectedPlanId) return; @@ -77,7 +80,11 @@ const ProcessedPayment = ({ alert("Failed to load Razorpay SDK"); return; } - MakePayment({ amount: selectedPlan?.price }); + let price = 0; + price = + frequencyLabel(selectedPlan?.frequency, true, true)?.planDurationInInt * + selectedPlan?.price; + MakePayment({ amount: price }); }; const handleRetry = () => { @@ -188,21 +195,27 @@ const ProcessedPayment = ({
- {selectedPlan?.planName} + {selectedPlan?.description}
- - {selectedPlan?.currency?.symbol} {selectedPlan?.price}{" "} - /{frequencyLabel(frequency, false)} + + Price -{" "} + + {selectedPlan.currency?.symbol} {selectedPlan.price}{" "} + per {frequencyLabel(frequency)} +
- - {selectedPlan?.description} - +
+ {selectedPlan?.planName} + + billed {frequencyLabel(frequency, true)} + +
)} @@ -307,11 +320,18 @@ const ProcessedPayment = ({
Total Price
- {formatFigure(selectedPlan?.price, { - type: "currency", - currency: - selectedPlan?.currency.currencyCode, - })} + {formatFigure( + frequencyLabel( + selectedPlan?.frequency, + true, + true + )?.planDurationInInt * price, + { + type: "currency", + currency: + selectedPlan?.currency.currencyCode, + } + )}
@@ -375,26 +395,28 @@ const ProcessedPayment = ({ )}
-
+
+
diff --git a/src/components/UserSubscription/SelectPlan.jsx b/src/components/UserSubscription/SelectPlan.jsx index 71b85f5e..e60abc38 100644 --- a/src/components/UserSubscription/SelectPlan.jsx +++ b/src/components/UserSubscription/SelectPlan.jsx @@ -6,9 +6,12 @@ import { formatFigure, frequencyLabel } from "../../utils/appUtils"; import { setSelfTenant } from "../../slices/localVariablesSlice"; import SelectedPlanSkeleton from "./SelectedPlanSkeleton"; import { error } from "pdf-lib"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { CouponDiscount } from "../../pages/Home/HomeSchema"; const SelectPlan = ({ currentStep, setStepStatus, onNext }) => { - const { frequency, planName } = useParams(); + const { frequency, planId } = useParams(); const [selectedFrequency, setSelectedFrequency] = useState( parseInt(frequency) ); @@ -17,7 +20,7 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => { const client = useSelector( (store) => store.localVariables.selfTenant.details ); - const [selectedPlan, setSelectedPlan] = useState(planName); + const [selectedPlan, setSelectedPlan] = useState(planId); const [currentPlan, setCurrentPlan] = useState(null); const [failPayment, setFailPayment] = useState(null); @@ -30,25 +33,51 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => { isRefetching, } = useSubscription(selectedFrequency); - const handleChange = (e) => setSelectedPlan(e.target.value); + const handleChange = (e) => { + setSelectedPlan(e.target.value); + }; useEffect(() => { - if (!plans || !selectedPlan) return; - const selected = plans.find((p) => p.planName === selectedPlan); - if (selected) { - setCurrentPlan(selected); - dispatch( - setSelfTenant({ planId: selected.id, frequency: selectedFrequency }) - ); - } - }, [plans, selectedPlan, dispatch, selectedFrequency]); + if (!plans || plans.length === 0) return; + + // Prefer route param if exists, else default to first plan + const matchingPlan = plans.find((p) => p.planId === planId) || plans[0]; + + setSelectedPlan(matchingPlan.id); + setCurrentPlan(matchingPlan); + + // Dispatch correct plan + frequency only once data is ready + dispatch( + setSelfTenant({ + planId: matchingPlan.id, + frequency: selectedFrequency, + }) + ); + }, [plans, selectedFrequency, planId, dispatch]); const handleNextStep = () => { - dispatch(setSelfTenant({ frequency: selectedFrequency })); + if (!selectedPlan) { + toast.warning("Please select a plan before continuing."); + return; + } + + dispatch( + setSelfTenant({ + planId: selectedPlan, + frequency: selectedFrequency, + }) + ); + setStepStatus((prev) => ({ ...prev, 2: "success" })); onNext(); }; + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ resolver: zodResolver(CouponDiscount) }); + return (
@@ -171,51 +200,59 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => { ) : ( <> -
+
{plans?.map((plan) => ( -
- + + + Price -{" "} + + {plan.currency?.symbol} {plan.price} per{" "} + {frequencyLabel(selectedFrequency)} + + + + billed {frequencyLabel(selectedFrequency, true)} + + + +
-
- ))} -
+ ))} +
{selectedPlan && (
{(() => { const selected = plans?.find( - (p) => p.planName === selectedPlan + (p) => p.id === selectedPlan ); if (!selected) return null; @@ -251,7 +288,6 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => {
-
Included Features
@@ -275,7 +311,6 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => {
))}
-
Support
@@ -299,8 +334,29 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => { )} - -
+
+
+ +
+
+ {" "} + +
+
+ {/* {errors.coupon && ({error.coupon.message})} */}{" "} + + Currently, no coupon codes are available!{" "} + +
Duration
@@ -312,10 +368,17 @@ const SelectPlan = ({ currentStep, setStepStatus, onNext }) => {
Total Price
- {formatFigure(price, { - type: "currency", - currency: currency.currencyCode, - })} + {formatFigure( + frequencyLabel( + selectedFrequency, + true, + true + )?.planDurationInInt * price, + { + type: "currency", + currency: currency.currencyCode, + } + )}
diff --git a/src/components/UserSubscription/SubscriptionLayout.jsx b/src/components/UserSubscription/SubscriptionLayout.jsx index a9145a3d..bf37176b 100644 --- a/src/components/UserSubscription/SubscriptionLayout.jsx +++ b/src/components/UserSubscription/SubscriptionLayout.jsx @@ -8,7 +8,7 @@ const SubscriptionLayout = ({ }) => { return (
-
    +
      {configStep.map((step, index) => { const stepNumber = index + 1; const status = stepStatus[stepNumber] || "pending"; diff --git a/src/pages/Home/HomeSchema.jsx b/src/pages/Home/HomeSchema.jsx index 53f14edc..2343b788 100644 --- a/src/pages/Home/HomeSchema.jsx +++ b/src/pages/Home/HomeSchema.jsx @@ -24,4 +24,8 @@ export const OrganizationSchema = z.object({ export const OrganizationDefaultValue = { -} \ No newline at end of file +} + +export const CouponDiscount = z.object({ + coupon:z.string().optional() +}) \ No newline at end of file diff --git a/src/pages/Home/MakeSubscription.jsx b/src/pages/Home/MakeSubscription.jsx index 7173b51c..12456155 100644 --- a/src/pages/Home/MakeSubscription.jsx +++ b/src/pages/Home/MakeSubscription.jsx @@ -8,7 +8,7 @@ import SelectPlan from "../../components/UserSubscription/SelectPlan"; import Review from "../../components/UserSubscription/Review"; const MakeSubscription = () => { - const [currentStep, setCurrentStep] = useState(1); + const [currentStep, setCurrentStep] = useState(2); const [responsePayment, setResponsePayment] = useState(null); const [stepStatus, setStepStatus] = useState({ diff --git a/src/pages/Home/SubscriptionPlans.jsx b/src/pages/Home/SubscriptionPlans.jsx index f7725946..17faa7a4 100644 --- a/src/pages/Home/SubscriptionPlans.jsx +++ b/src/pages/Home/SubscriptionPlans.jsx @@ -113,7 +113,7 @@ const SubscriptionPlans = () => { {/* Button */}
      Subscribe diff --git a/src/pages/Tenant/TenantDetails.jsx b/src/pages/Tenant/TenantDetails.jsx index d799522e..26e3ca90 100644 --- a/src/pages/Tenant/TenantDetails.jsx +++ b/src/pages/Tenant/TenantDetails.jsx @@ -122,8 +122,8 @@ const TenantDetails = ({ /> )} -
      -
        +
        +
          {tabs.map((tab, index) => (