Compare commits

...

1 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
e293bbae8c fix: renew expired subscription 2024-11-11 18:45:13 +02:00
6 changed files with 177 additions and 40 deletions

View File

@@ -32,6 +32,7 @@ import { BrandingTemplatesDrawer } from '@/containers/BrandingTemplates/Branding
import { DRAWERS } from '@/constants/drawers';
import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer';
import { NewSubscriptionDrawer } from '@/containers/Subscriptions/drawers/NewSubscriptionDrawer/NewSubscriptionDrawer';
/**
* Drawers container of the dashboard.
@@ -72,6 +73,7 @@ export default function DrawersContainer() {
<TaxRateDetailsDrawer name={DRAWERS.TAX_RATE_DETAILS} />
<CategorizeTransactionDrawer name={DRAWERS.CATEGORIZE_TRANSACTION} />
<ChangeSubscriptionPlanDrawer name={DRAWERS.CHANGE_SUBSCARIPTION_PLAN} />
<NewSubscriptionDrawer name={DRAWERS.NEW_SUBSCRIPTION_PLANS} />
<InvoiceCustomizeDrawer name={DRAWERS.INVOICE_CUSTOMIZE} />
<EstimateCustomizeDrawer name={DRAWERS.ESTIMATE_CUSTOMIZE} />
<ReceiptCustomizeDrawer name={DRAWERS.RECEIPT_CUSTOMIZE} />

View File

@@ -25,6 +25,7 @@ export enum DRAWERS {
TAX_RATE_DETAILS = 'tax-rate-detail-drawer',
CATEGORIZE_TRANSACTION = 'categorize-transaction',
CHANGE_SUBSCARIPTION_PLAN = 'change-subscription-plan',
NEW_SUBSCRIPTION_PLANS = 'NEW_SUBSCRIPTION_PLANS',
INVOICE_CUSTOMIZE = 'INVOICE_CUSTOMIZE',
ESTIMATE_CUSTOMIZE = 'ESTIMATE_CUSTOMIZE',
PAYMENT_RECEIPT_CUSTOMIZE = 'PAYMENT_RECEIPT_CUSTOMIZE',
@@ -34,5 +35,5 @@ export enum DRAWERS {
BRANDING_TEMPLATES = 'BRANDING_TEMPLATES',
PAYMENT_INVOICE_PREVIEW = 'PAYMENT_INVOICE_PREVIEW',
STRIPE_PAYMENT_INTEGRATION_EDIT = 'STRIPE_PAYMENT_INTEGRATION_EDIT',
INVOICE_SEND_MAIL = 'INVOICE_SEND_MAIL'
INVOICE_SEND_MAIL = 'INVOICE_SEND_MAIL',
}

View File

@@ -2,8 +2,8 @@
import * as R from 'ramda';
import clsx from 'classnames';
import { includes } from 'lodash';
import { Box, Group, Stack } from '@/components';
import { Button, Card, Classes, Intent, Text } from '@blueprintjs/core';
import { Box, Group, Stack } from '@/components';
import withAlertActions from '../Alert/withAlertActions';
import styles from './BillingSubscription.module.scss';
import withDrawerActions from '../Drawer/withDrawerActions';
@@ -18,12 +18,11 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
if (!mainSubscription) {
return null;
}
// Handle cancel subscription button click.
const handleCancelSubBtnClick = () => {
openAlert('cancel-main-subscription');
};
const handleResumeSubBtnClick = () => {
openAlert('resume-main-subscription');
};
// Handle update payment method button click.
const handleUpdatePaymentMethod = () => {
window.LemonSqueezy.Url.Open(
mainSubscription.lemonUrls?.updatePaymentMethod,
@@ -33,6 +32,10 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
const handleUpgradeBtnClick = () => {
openDrawer(DRAWERS.CHANGE_SUBSCARIPTION_PLAN);
};
// Handles renew the expired subscription.
const handleNewSubscriptionBtnClick = () => {
openDrawer(DRAWERS.NEW_SUBSCRIPTION_PLANS);
};
return (
<Card className={styles.root}>
@@ -66,50 +69,53 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
</Text>
<Stack align="flex-start" spacing={8} className={styles.actions}>
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleUpgradeBtnClick}
>
Upgrade the Plan
</Button>
{mainSubscription.canceled && (
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleResumeSubBtnClick}
onClick={handleNewSubscriptionBtnClick}
>
Resume Subscription
Renew Subscription
</Button>
)}
{!mainSubscription.canceled && (
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleCancelSubBtnClick}
>
Cancel Subscription
</Button>
<>
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleUpgradeBtnClick}
>
Upgrade the Plan
</Button>
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleCancelSubBtnClick}
>
Cancel Subscription
</Button>
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleUpdatePaymentMethod}
>
Change Payment Method
</Button>
</>
)}
<Button
minimal
small
inline
intent={Intent.PRIMARY}
onClick={handleUpdatePaymentMethod}
>
Change Payment Method
</Button>
</Stack>
<Group position={'apart'} style={{ marginTop: 'auto' }}>
<Group position={'apart'} mt={'auto'}>
<Group spacing={4}>
<Text className={styles.priceAmount}>
{mainSubscription.planPriceFormatted}
@@ -120,8 +126,8 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
{mainSubscription.planPeriod === 'month'
? 'mo'
: mainSubscription.planPeriod === 'year'
? 'yearly'
: ''}
? 'yearly'
: ''}
</Text>
)}
</Group>
@@ -130,10 +136,10 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
{mainSubscription.canceled && (
<Button
intent={Intent.PRIMARY}
onClick={handleResumeSubBtnClick}
onClick={handleNewSubscriptionBtnClick}
className={styles.subscribeButton}
>
Resume Subscription
Renew Subscription
</Button>
)}
</Box>

View File

@@ -0,0 +1,26 @@
import { Box } from "@/components";
import { SubscriptionPlansPeriodSwitcher } from "@/containers/Setup/SetupSubscription/SubscriptionPlansPeriodSwitcher";
import { Callout, Classes } from "@blueprintjs/core";
import { NewSubscriptionPlans } from "./NewSubscriptionPlans";
export function NewSubscriptionContent() {
return (
<Box className={Classes.DRAWER_BODY}>
<Box
maxWidth={1024}
margin="0 auto"
padding={'50px 20px 80px'}
>
<Callout style={{ marginBottom: '2rem' }} icon={null}>
Simple plans. Simple prices. Only pay for what you really need. All
plans come with award-winning 24/7 customer support. Prices do not
include applicable taxes.
</Callout>
<SubscriptionPlansPeriodSwitcher />
<NewSubscriptionPlans />
</Box>
</Box>
)
}

View File

@@ -0,0 +1,40 @@
// @ts-nocheck
import React, { lazy } from 'react';
import * as R from 'ramda';
import { Position } from '@blueprintjs/core';
import { Drawer, DrawerHeaderContent, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers';
import { DRAWERS } from '@/constants/drawers';
const NewSubscriptionContent = lazy(() =>
import('./NewSubscriptionContent').then((module) => ({
default: module.NewSubscriptionContent,
})),
);
function NewSubscriptionDrawerRoot({
name,
// #withDrawer
isOpen,
}) {
return (
<Drawer
isOpen={isOpen}
name={name}
size={'calc(100% - 5px)'}
position={Position.BOTTOM}
>
<DrawerSuspense>
<DrawerHeaderContent
name={DRAWERS.NEW_SUBSCRIPTION_PLANS}
title={'Renew Subscription Plan'}
/>
<NewSubscriptionContent />
</DrawerSuspense>
</Drawer>
);
}
export const NewSubscriptionDrawer = R.compose(withDrawers())(
NewSubscriptionDrawerRoot,
);

View File

@@ -0,0 +1,62 @@
// @ts-nocheck
import * as R from 'ramda';
import { Intent } from '@blueprintjs/core';
import { AppToaster, Group } from '@/components';
import { SubscriptionPlan } from '../../component/SubscriptionPlan';
import { SubscriptionPlansPeriod } from '@/store/plans/plans.reducer';
import { useSubscriptionPlans } from '@/hooks/constants/useSubscriptionPlans';
import { withSubscriptionPlanMapper } from '../../component/withSubscriptionPlanMapper';
import { useGetLemonSqueezyCheckout } from '@/hooks/query';
export function NewSubscriptionPlans() {
const subscriptionPlans = useSubscriptionPlans();
return (
<Group spacing={14} noWrap align="stretch">
{subscriptionPlans.map((plan, index) => (
<NewSubscriptionPlanMapped plan={plan} />
))}
</Group>
);
}
export const NewSubscriptionPlanMapped = R.compose(
withSubscriptionPlanMapper,
)(
({
monthlyVariantId,
annuallyVariantId,
plansPeriod,
...props
}) => {
const { mutateAsync: getLemonCheckout, isLoading } =
useGetLemonSqueezyCheckout();
// Handles the subscribe button click.
const handleSubscribe = () => {
const variantId =
plansPeriod === SubscriptionPlansPeriod.Monthly
? monthlyVariantId
: annuallyVariantId;
getLemonCheckout({ variantId })
.then((res) => {
const checkoutUrl = res.data.data.attributes.url;
window.LemonSqueezy.Url.Open(checkoutUrl);
})
.catch(() => {
AppToaster.show({
message: 'Something went wrong!',
intent: Intent.DANGER,
});
});
};
return (
<SubscriptionPlan
{...props}
onSubscribe={handleSubscribe}
subscribeButtonProps={{ loading: isLoading }}
/>
);
},
);