mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
Compare commits
2 Commits
fix-renew-
...
add-mail-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0517b3e430 | ||
|
|
4c67d2e321 |
@@ -32,7 +32,6 @@ import { BrandingTemplatesDrawer } from '@/containers/BrandingTemplates/Branding
|
|||||||
|
|
||||||
import { DRAWERS } from '@/constants/drawers';
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer';
|
import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer';
|
||||||
import { NewSubscriptionDrawer } from '@/containers/Subscriptions/drawers/NewSubscriptionDrawer/NewSubscriptionDrawer';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drawers container of the dashboard.
|
* Drawers container of the dashboard.
|
||||||
@@ -73,7 +72,6 @@ export default function DrawersContainer() {
|
|||||||
<TaxRateDetailsDrawer name={DRAWERS.TAX_RATE_DETAILS} />
|
<TaxRateDetailsDrawer name={DRAWERS.TAX_RATE_DETAILS} />
|
||||||
<CategorizeTransactionDrawer name={DRAWERS.CATEGORIZE_TRANSACTION} />
|
<CategorizeTransactionDrawer name={DRAWERS.CATEGORIZE_TRANSACTION} />
|
||||||
<ChangeSubscriptionPlanDrawer name={DRAWERS.CHANGE_SUBSCARIPTION_PLAN} />
|
<ChangeSubscriptionPlanDrawer name={DRAWERS.CHANGE_SUBSCARIPTION_PLAN} />
|
||||||
<NewSubscriptionDrawer name={DRAWERS.NEW_SUBSCRIPTION_PLANS} />
|
|
||||||
<InvoiceCustomizeDrawer name={DRAWERS.INVOICE_CUSTOMIZE} />
|
<InvoiceCustomizeDrawer name={DRAWERS.INVOICE_CUSTOMIZE} />
|
||||||
<EstimateCustomizeDrawer name={DRAWERS.ESTIMATE_CUSTOMIZE} />
|
<EstimateCustomizeDrawer name={DRAWERS.ESTIMATE_CUSTOMIZE} />
|
||||||
<ReceiptCustomizeDrawer name={DRAWERS.RECEIPT_CUSTOMIZE} />
|
<ReceiptCustomizeDrawer name={DRAWERS.RECEIPT_CUSTOMIZE} />
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export enum DRAWERS {
|
|||||||
TAX_RATE_DETAILS = 'tax-rate-detail-drawer',
|
TAX_RATE_DETAILS = 'tax-rate-detail-drawer',
|
||||||
CATEGORIZE_TRANSACTION = 'categorize-transaction',
|
CATEGORIZE_TRANSACTION = 'categorize-transaction',
|
||||||
CHANGE_SUBSCARIPTION_PLAN = 'change-subscription-plan',
|
CHANGE_SUBSCARIPTION_PLAN = 'change-subscription-plan',
|
||||||
NEW_SUBSCRIPTION_PLANS = 'NEW_SUBSCRIPTION_PLANS',
|
|
||||||
INVOICE_CUSTOMIZE = 'INVOICE_CUSTOMIZE',
|
INVOICE_CUSTOMIZE = 'INVOICE_CUSTOMIZE',
|
||||||
ESTIMATE_CUSTOMIZE = 'ESTIMATE_CUSTOMIZE',
|
ESTIMATE_CUSTOMIZE = 'ESTIMATE_CUSTOMIZE',
|
||||||
PAYMENT_RECEIPT_CUSTOMIZE = 'PAYMENT_RECEIPT_CUSTOMIZE',
|
PAYMENT_RECEIPT_CUSTOMIZE = 'PAYMENT_RECEIPT_CUSTOMIZE',
|
||||||
@@ -35,5 +34,5 @@ export enum DRAWERS {
|
|||||||
BRANDING_TEMPLATES = 'BRANDING_TEMPLATES',
|
BRANDING_TEMPLATES = 'BRANDING_TEMPLATES',
|
||||||
PAYMENT_INVOICE_PREVIEW = 'PAYMENT_INVOICE_PREVIEW',
|
PAYMENT_INVOICE_PREVIEW = 'PAYMENT_INVOICE_PREVIEW',
|
||||||
STRIPE_PAYMENT_INTEGRATION_EDIT = 'STRIPE_PAYMENT_INTEGRATION_EDIT',
|
STRIPE_PAYMENT_INTEGRATION_EDIT = 'STRIPE_PAYMENT_INTEGRATION_EDIT',
|
||||||
INVOICE_SEND_MAIL = 'INVOICE_SEND_MAIL',
|
INVOICE_SEND_MAIL = 'INVOICE_SEND_MAIL'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import { includes } from 'lodash';
|
import { includes } from 'lodash';
|
||||||
import { Button, Card, Classes, Intent, Text } from '@blueprintjs/core';
|
|
||||||
import { Box, Group, Stack } from '@/components';
|
import { Box, Group, Stack } from '@/components';
|
||||||
|
import { Button, Card, Classes, Intent, Text } from '@blueprintjs/core';
|
||||||
import withAlertActions from '../Alert/withAlertActions';
|
import withAlertActions from '../Alert/withAlertActions';
|
||||||
import styles from './BillingSubscription.module.scss';
|
import styles from './BillingSubscription.module.scss';
|
||||||
import withDrawerActions from '../Drawer/withDrawerActions';
|
import withDrawerActions from '../Drawer/withDrawerActions';
|
||||||
@@ -18,11 +18,12 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
|
|||||||
if (!mainSubscription) {
|
if (!mainSubscription) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Handle cancel subscription button click.
|
|
||||||
const handleCancelSubBtnClick = () => {
|
const handleCancelSubBtnClick = () => {
|
||||||
openAlert('cancel-main-subscription');
|
openAlert('cancel-main-subscription');
|
||||||
};
|
};
|
||||||
// Handle update payment method button click.
|
const handleResumeSubBtnClick = () => {
|
||||||
|
openAlert('resume-main-subscription');
|
||||||
|
};
|
||||||
const handleUpdatePaymentMethod = () => {
|
const handleUpdatePaymentMethod = () => {
|
||||||
window.LemonSqueezy.Url.Open(
|
window.LemonSqueezy.Url.Open(
|
||||||
mainSubscription.lemonUrls?.updatePaymentMethod,
|
mainSubscription.lemonUrls?.updatePaymentMethod,
|
||||||
@@ -32,10 +33,6 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
|
|||||||
const handleUpgradeBtnClick = () => {
|
const handleUpgradeBtnClick = () => {
|
||||||
openDrawer(DRAWERS.CHANGE_SUBSCARIPTION_PLAN);
|
openDrawer(DRAWERS.CHANGE_SUBSCARIPTION_PLAN);
|
||||||
};
|
};
|
||||||
// Handles renew the expired subscription.
|
|
||||||
const handleNewSubscriptionBtnClick = () => {
|
|
||||||
openDrawer(DRAWERS.NEW_SUBSCRIPTION_PLANS);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={styles.root}>
|
<Card className={styles.root}>
|
||||||
@@ -69,53 +66,50 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Stack align="flex-start" spacing={8} className={styles.actions}>
|
<Stack align="flex-start" spacing={8} className={styles.actions}>
|
||||||
|
<Button
|
||||||
|
minimal
|
||||||
|
small
|
||||||
|
inline
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
onClick={handleUpgradeBtnClick}
|
||||||
|
>
|
||||||
|
Upgrade the Plan
|
||||||
|
</Button>
|
||||||
|
|
||||||
{mainSubscription.canceled && (
|
{mainSubscription.canceled && (
|
||||||
<Button
|
<Button
|
||||||
minimal
|
minimal
|
||||||
small
|
small
|
||||||
inline
|
inline
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
onClick={handleNewSubscriptionBtnClick}
|
onClick={handleResumeSubBtnClick}
|
||||||
>
|
>
|
||||||
Renew Subscription
|
Resume Subscription
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!mainSubscription.canceled && (
|
{!mainSubscription.canceled && (
|
||||||
<>
|
<Button
|
||||||
<Button
|
minimal
|
||||||
minimal
|
small
|
||||||
small
|
inline
|
||||||
inline
|
intent={Intent.PRIMARY}
|
||||||
intent={Intent.PRIMARY}
|
onClick={handleCancelSubBtnClick}
|
||||||
onClick={handleUpgradeBtnClick}
|
>
|
||||||
>
|
Cancel Subscription
|
||||||
Upgrade the Plan
|
</Button>
|
||||||
</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>
|
</Stack>
|
||||||
|
|
||||||
<Group position={'apart'} mt={'auto'}>
|
<Group position={'apart'} style={{ marginTop: 'auto' }}>
|
||||||
<Group spacing={4}>
|
<Group spacing={4}>
|
||||||
<Text className={styles.priceAmount}>
|
<Text className={styles.priceAmount}>
|
||||||
{mainSubscription.planPriceFormatted}
|
{mainSubscription.planPriceFormatted}
|
||||||
@@ -126,8 +120,8 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
|
|||||||
{mainSubscription.planPeriod === 'month'
|
{mainSubscription.planPeriod === 'month'
|
||||||
? 'mo'
|
? 'mo'
|
||||||
: mainSubscription.planPeriod === 'year'
|
: mainSubscription.planPeriod === 'year'
|
||||||
? 'yearly'
|
? 'yearly'
|
||||||
: ''}
|
: ''}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
@@ -136,10 +130,10 @@ function SubscriptionRoot({ openAlert, openDrawer }) {
|
|||||||
{mainSubscription.canceled && (
|
{mainSubscription.canceled && (
|
||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
onClick={handleNewSubscriptionBtnClick}
|
onClick={handleResumeSubBtnClick}
|
||||||
className={styles.subscribeButton}
|
className={styles.subscribeButton}
|
||||||
>
|
>
|
||||||
Renew Subscription
|
Resume Subscription
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// @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,
|
|
||||||
);
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// @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 }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
export interface InvoicePaymentEmailSchemaProps {
|
||||||
|
companyName: string;
|
||||||
|
companyLogoUri: string;
|
||||||
|
|
||||||
|
total: string;
|
||||||
|
currencyCode: string;
|
||||||
|
|
||||||
|
dueDate: string;
|
||||||
|
paymentUrl: string;
|
||||||
|
|
||||||
|
invoiceNumber: string;
|
||||||
|
invoiceDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InvoicePaymentEmailSchema({
|
||||||
|
companyName,
|
||||||
|
companyLogoUri,
|
||||||
|
|
||||||
|
currencyCode,
|
||||||
|
total,
|
||||||
|
|
||||||
|
paymentUrl,
|
||||||
|
dueDate,
|
||||||
|
|
||||||
|
invoiceDate,
|
||||||
|
invoiceNumber
|
||||||
|
}: InvoicePaymentEmailSchemaProps) {
|
||||||
|
return (
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{`
|
||||||
|
{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "Invoice",
|
||||||
|
"description": "Invoice for services rendered",
|
||||||
|
"paymentStatus": "http://schema.org/PaymentDue",
|
||||||
|
"totalPaymentDue": {
|
||||||
|
"@type": "MonetaryAmount",
|
||||||
|
"currency": "${currencyCode}",
|
||||||
|
"value": "${total}"
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "${companyName}",
|
||||||
|
"logo": "${companyLogoUri}",
|
||||||
|
"telephone": "+1234567890"
|
||||||
|
},
|
||||||
|
"paymentDueDate": "${dueDate}",
|
||||||
|
"paymentUrl": "${paymentUrl}",
|
||||||
|
"referencesOrder": {
|
||||||
|
"@type": "Order",
|
||||||
|
"orderNumber": "${invoiceNumber}",
|
||||||
|
"orderStatus": "http://schema.org/OrderPaymentDue",
|
||||||
|
"orderDate": "${invoiceDate}"
|
||||||
|
},
|
||||||
|
"potentialAction": {
|
||||||
|
"@type": "ViewAction",
|
||||||
|
"target": "${paymentUrl}",
|
||||||
|
"name": "View and Pay Invoice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</script>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user