mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
feat: pause, resume main subscription
This commit is contained in:
@@ -8,6 +8,7 @@ import SubscriptionService from '@/services/Subscription/SubscriptionService';
|
||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||
import BaseController from '../BaseController';
|
||||
import { LemonSqueezyService } from '@/services/Subscription/LemonSqueezyService';
|
||||
import { SubscriptionApplication } from '@/services/Subscription/SubscriptionApplication';
|
||||
|
||||
@Service()
|
||||
export class SubscriptionController extends BaseController {
|
||||
@@ -17,6 +18,9 @@ export class SubscriptionController extends BaseController {
|
||||
@Inject()
|
||||
private lemonSqueezyService: LemonSqueezyService;
|
||||
|
||||
@Inject()
|
||||
private subscriptionApp: SubscriptionApplication;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
@@ -33,6 +37,14 @@ export class SubscriptionController extends BaseController {
|
||||
this.validationResult,
|
||||
this.getCheckoutUrl.bind(this)
|
||||
);
|
||||
router.post('/cancel', asyncMiddleware(this.cancelSubscription.bind(this)));
|
||||
router.post('/resume', asyncMiddleware(this.resumeSubscription.bind(this)));
|
||||
router.post(
|
||||
'/change',
|
||||
[body('variant_id').exists().trim()],
|
||||
this.validationResult,
|
||||
asyncMiddleware(this.changeSubscriptionPlan.bind(this))
|
||||
);
|
||||
router.get('/', asyncMiddleware(this.getSubscriptions.bind(this)));
|
||||
|
||||
return router;
|
||||
@@ -85,4 +97,84 @@ export class SubscriptionController extends BaseController {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the subscription of the current organization.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
* @returns {Promise<Response|null>}
|
||||
*/
|
||||
private async cancelSubscription(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
const { tenantId } = req;
|
||||
|
||||
try {
|
||||
await this.subscriptionApp.cancelSubscription(tenantId, '455610');
|
||||
|
||||
return res.status(200).send({
|
||||
status: 200,
|
||||
message: 'The organization subscription has been canceled.',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the subscription of the current organization.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
* @returns {Promise<Response | null>}
|
||||
*/
|
||||
private async resumeSubscription(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
const { tenantId } = req;
|
||||
|
||||
try {
|
||||
await this.subscriptionApp.resumeSubscription(tenantId);
|
||||
|
||||
return res.status(200).send({
|
||||
status: 200,
|
||||
message: 'The organization subscription has been resumed.',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the main subscription plan of the current organization.
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {NextFunction} next
|
||||
* @returns {Promise<Response | null>}
|
||||
*/
|
||||
public async changeSubscriptionPlan(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
const { tenantId } = req;
|
||||
const body = this.matchedBodyData(req);
|
||||
|
||||
try {
|
||||
await this.subscriptionApp.changeSubscriptionPlan(
|
||||
tenantId,
|
||||
body.variantId
|
||||
);
|
||||
return res.status(200).send({
|
||||
message: 'The subscription plan has been changed.',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { cancelSubscription } from '@lemonsqueezy/lemonsqueezy.js';
|
||||
import { configureLemonSqueezy } from './utils';
|
||||
import { PlanSubscription } from '@/system/models';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
import { ERRORS, IOrganizationSubscriptionCanceled } from './types';
|
||||
|
||||
@Service()
|
||||
export class LemonCancelSubscription {
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Cancels the subscription of the given tenant.
|
||||
* @param {number} tenantId
|
||||
* @param {number} subscriptionId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async cancelSubscription(tenantId: number) {
|
||||
configureLemonSqueezy();
|
||||
|
||||
const subscription = await PlanSubscription.query().findOne({
|
||||
tenantId,
|
||||
slug: 'main',
|
||||
});
|
||||
if (!subscription) {
|
||||
throw new ServiceError(ERRORS.SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT);
|
||||
}
|
||||
const lemonSusbcriptionId = subscription.lemonSubscriptionId;
|
||||
const subscriptionId = subscription.id;
|
||||
const cancelledSub = await cancelSubscription(lemonSusbcriptionId);
|
||||
|
||||
if (cancelledSub.error) {
|
||||
throw new Error(cancelledSub.error.message);
|
||||
}
|
||||
await PlanSubscription.query().findById(subscriptionId).patch({
|
||||
canceledAt: new Date(),
|
||||
});
|
||||
// Triggers `onSubscriptionCanceled` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.subscription.onSubscriptionCanceled,
|
||||
{ tenantId, subscriptionId } as IOrganizationSubscriptionCanceled
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { updateSubscription } from '@lemonsqueezy/lemonsqueezy.js';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { PlanSubscription } from '@/system/models';
|
||||
import { configureLemonSqueezy } from './utils';
|
||||
import events from '@/subscribers/events';
|
||||
import { IOrganizationSubscriptionChanged } from './types';
|
||||
|
||||
@Service()
|
||||
export class LemonChangeSubscriptionPlan {
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Changes the given organization subscription plan.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} newVariantId - New variant id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async changeSubscriptionPlan(tenantId: number, newVariantId: number) {
|
||||
configureLemonSqueezy();
|
||||
|
||||
const subscription = await PlanSubscription.query().findOne({
|
||||
tenantId,
|
||||
slug: 'main',
|
||||
});
|
||||
const lemonSubscriptionId = subscription.lemonSubscriptionId;
|
||||
|
||||
// Send request to Lemon Squeezy to change the subscription.
|
||||
const updatedSub = await updateSubscription(lemonSubscriptionId, {
|
||||
variantId: newVariantId,
|
||||
});
|
||||
if (updatedSub.error) {
|
||||
throw new ServiceError('SOMETHING_WENT_WRONG');
|
||||
}
|
||||
// Triggers `onSubscriptionPlanChanged` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.subscription.onSubscriptionPlanChanged,
|
||||
{
|
||||
tenantId,
|
||||
lemonSubscriptionId,
|
||||
newVariantId,
|
||||
} as IOrganizationSubscriptionChanged
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { configureLemonSqueezy } from './utils';
|
||||
import { PlanSubscription } from '@/system/models';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { ERRORS, IOrganizationSubscriptionResumed } from './types';
|
||||
import { updateSubscription } from '@lemonsqueezy/lemonsqueezy.js';
|
||||
|
||||
@Service()
|
||||
export class LemonResumeSubscription {
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
/**
|
||||
* Resumes the main subscription of the given tenant.
|
||||
* @param {number} tenantId -
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async resumeSubscription(tenantId: number) {
|
||||
configureLemonSqueezy();
|
||||
|
||||
const subscription = await PlanSubscription.query().findOne({
|
||||
tenantId,
|
||||
slug: 'main',
|
||||
});
|
||||
if (!subscription) {
|
||||
throw new ServiceError(ERRORS.SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT);
|
||||
}
|
||||
const subscriptionId = subscription.id;
|
||||
const lemonSubscriptionId = subscription.lemonSubscriptionId;
|
||||
const returnedSub = await updateSubscription(lemonSubscriptionId, {
|
||||
cancelled: false,
|
||||
});
|
||||
if (returnedSub.error) {
|
||||
throw new ServiceError('');
|
||||
}
|
||||
// Update the subscription of the organization.
|
||||
await PlanSubscription.query().findById(subscriptionId).patch({
|
||||
canceledAt: null,
|
||||
});
|
||||
// Triggers `onSubscriptionCanceled` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.subscription.onSubscriptionResumed,
|
||||
{ tenantId, subscriptionId } as IOrganizationSubscriptionResumed
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { LemonCancelSubscription } from './LemonCancelSubscription';
|
||||
import { LemonChangeSubscriptionPlan } from './LemonChangeSubscriptionPlan';
|
||||
import { LemonResumeSubscription } from './LemonResumeSubscription';
|
||||
|
||||
@Service()
|
||||
export class SubscriptionApplication {
|
||||
@Inject()
|
||||
private cancelSubscriptionService: LemonCancelSubscription;
|
||||
|
||||
@Inject()
|
||||
private resumeSubscriptionService: LemonResumeSubscription;
|
||||
|
||||
@Inject()
|
||||
private changeSubscriptionPlanService: LemonChangeSubscriptionPlan;
|
||||
|
||||
/**
|
||||
* Cancels the subscription of the given tenant.
|
||||
* @param {number} tenantId
|
||||
* @param {string} id
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public cancelSubscription(tenantId: number, id: string) {
|
||||
return this.cancelSubscriptionService.cancelSubscription(tenantId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the subscription of the given tenant.
|
||||
* @param {number} tenantId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public resumeSubscription(tenantId: number) {
|
||||
return this.resumeSubscriptionService.resumeSubscription(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the given organization subscription plan.
|
||||
* @param {number} tenantId
|
||||
* @param {number} newVariantId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public changeSubscriptionPlan(tenantId: number, newVariantId: number) {
|
||||
return this.changeSubscriptionPlanService.changeSubscriptionPlan(
|
||||
tenantId,
|
||||
newVariantId
|
||||
);
|
||||
}
|
||||
}
|
||||
20
packages/server/src/services/Subscription/types.ts
Normal file
20
packages/server/src/services/Subscription/types.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const ERRORS = {
|
||||
SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT:
|
||||
'SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT',
|
||||
};
|
||||
|
||||
export interface IOrganizationSubscriptionChanged {
|
||||
tenantId: number;
|
||||
lemonSubscriptionId: string;
|
||||
newVariantId: number;
|
||||
}
|
||||
|
||||
export interface IOrganizationSubscriptionCanceled {
|
||||
tenantId: number;
|
||||
subscriptionId: string;
|
||||
}
|
||||
|
||||
export interface IOrganizationSubscriptionResumed {
|
||||
tenantId: number;
|
||||
subscriptionId: number;
|
||||
}
|
||||
@@ -40,6 +40,15 @@ export default {
|
||||
baseCurrencyUpdated: 'onOrganizationBaseCurrencyUpdated',
|
||||
},
|
||||
|
||||
/**
|
||||
* Organization subscription.
|
||||
*/
|
||||
subscription: {
|
||||
onSubscriptionCanceled: 'onSubscriptionCanceled',
|
||||
onSubscriptionResumed: 'onSubscriptionResumed',
|
||||
onSubscriptionPlanChanged: 'onSubscriptionPlanChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
* Tenants managment service.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
exports.up = function (knex) {
|
||||
return knex.schema.table('subscription_plan_subscriptions', (table) => {
|
||||
table.string('lemon_subscription_id').nullable();
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function (knex) {
|
||||
return knex.schema.table('subscription_plan_subscriptions', (table) => {
|
||||
table.dropColumn('lemon_subscription_id');
|
||||
});
|
||||
};
|
||||
@@ -4,6 +4,8 @@ import moment from 'moment';
|
||||
import SubscriptionPeriod from '@/services/Subscription/SubscriptionPeriod';
|
||||
|
||||
export default class PlanSubscription extends mixin(SystemModel) {
|
||||
lemonSubscriptionId: number;
|
||||
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,7 @@ import ProjectAlerts from '@/containers/Projects/containers/ProjectAlerts';
|
||||
import TaxRatesAlerts from '@/containers/TaxRates/alerts';
|
||||
import { CashflowAlerts } from '../CashFlow/CashflowAlerts';
|
||||
import { BankRulesAlerts } from '../Banking/Rules/RulesList/BankRulesAlerts';
|
||||
import { SubscriptionAlerts } from '../Subscriptions/alerts/alerts';
|
||||
|
||||
export default [
|
||||
...AccountsAlerts,
|
||||
@@ -56,5 +57,6 @@ export default [
|
||||
...ProjectAlerts,
|
||||
...TaxRatesAlerts,
|
||||
...CashflowAlerts,
|
||||
...BankRulesAlerts
|
||||
...BankRulesAlerts,
|
||||
...SubscriptionAlerts
|
||||
];
|
||||
|
||||
24
packages/webapp/src/containers/Subscriptions/BillingPage.tsx
Normal file
24
packages/webapp/src/containers/Subscriptions/BillingPage.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { Button } from '@blueprintjs/core';
|
||||
import withAlertActions from '../Alert/withAlertActions';
|
||||
|
||||
function BillingPageRoot({ openAlert }) {
|
||||
const handleCancelSubBtnClick = () => {
|
||||
openAlert('cancel-main-subscription');
|
||||
};
|
||||
const handleResumeSubBtnClick = () => {
|
||||
openAlert('resume-main-subscription');
|
||||
};
|
||||
const handleUpdatePaymentMethod = () => {};
|
||||
|
||||
return (
|
||||
<h1>
|
||||
<Button onClick={handleCancelSubBtnClick}>Cancel Subscription</Button>
|
||||
<Button onClick={handleResumeSubBtnClick}>Resume Subscription</Button>
|
||||
<Button>Update Payment Method</Button>
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(withAlertActions)(BillingPageRoot);
|
||||
@@ -0,0 +1,3 @@
|
||||
export function BillingPageBoot() {
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { AppToaster, FormattedMessage as T } from '@/components';
|
||||
|
||||
import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
|
||||
import { useCancelMainSubscription } from '@/hooks/query/subscription';
|
||||
|
||||
/**
|
||||
* Cancel Unlocking partial transactions alerts.
|
||||
*/
|
||||
function CancelMainSubscriptionAlert({
|
||||
name,
|
||||
|
||||
// #withAlertStoreConnect
|
||||
isOpen,
|
||||
payload: { module },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
}) {
|
||||
const { mutateAsync: cancelSubscription, isLoading } =
|
||||
useCancelMainSubscription();
|
||||
|
||||
// Handle cancel.
|
||||
const handleCancel = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
// Handle confirm.
|
||||
const handleConfirm = () => {
|
||||
const values = {
|
||||
module: module,
|
||||
};
|
||||
cancelSubscription()
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
message: 'The subscription has been cancel.',
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {},
|
||||
)
|
||||
.finally(() => {
|
||||
closeAlert(name);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={'Cancel Subscription'}
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirm}
|
||||
loading={isLoading}
|
||||
>
|
||||
<p>asdfsadf asdf asdfdsaf</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
)(CancelMainSubscriptionAlert);
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { AppToaster, FormattedMessage as T } from '@/components';
|
||||
|
||||
import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
||||
import { useResumeMainSubscription } from '@/hooks/query/subscription';
|
||||
|
||||
/**
|
||||
* Resume Unlocking partial transactions alerts.
|
||||
*/
|
||||
function ResumeMainSubscriptionAlert({
|
||||
name,
|
||||
|
||||
// #withAlertStoreConnect
|
||||
isOpen,
|
||||
payload: { module },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
}) {
|
||||
const { mutateAsync: resumeSubscription, isLoading } =
|
||||
useResumeMainSubscription();
|
||||
|
||||
// Handle cancel.
|
||||
const handleCancel = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
// Handle confirm.
|
||||
const handleConfirm = () => {
|
||||
const values = {
|
||||
module: module,
|
||||
};
|
||||
resumeSubscription()
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
message: 'The subscription has been resumed.',
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {},
|
||||
)
|
||||
.finally(() => {
|
||||
closeAlert(name);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={'Resume Subscription'}
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirm}
|
||||
loading={isLoading}
|
||||
>
|
||||
<p>asdfsadf asdf asdfdsaf</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
)(ResumeMainSubscriptionAlert);
|
||||
@@ -0,0 +1,23 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
const CancelMainSubscriptionAlert = React.lazy(
|
||||
() => import('./CancelMainSubscriptionAlert'),
|
||||
);
|
||||
const ResumeMainSubscriptionAlert = React.lazy(
|
||||
() => import('./ResumeMainSubscriptionAlert'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Subscription alert.
|
||||
*/
|
||||
export const SubscriptionAlerts = [
|
||||
{
|
||||
name: 'cancel-main-subscription',
|
||||
component: CancelMainSubscriptionAlert,
|
||||
},
|
||||
{
|
||||
name: 'resume-main-subscription',
|
||||
component: ResumeMainSubscriptionAlert,
|
||||
},
|
||||
];
|
||||
115
packages/webapp/src/hooks/query/subscription.tsx
Normal file
115
packages/webapp/src/hooks/query/subscription.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
useMutation,
|
||||
UseMutationOptions,
|
||||
UseMutationResult,
|
||||
useQueryClient,
|
||||
} from 'react-query';
|
||||
import useApiRequest from '../useRequest';
|
||||
|
||||
interface CancelMainSubscriptionValues {}
|
||||
interface CancelMainSubscriptionResponse {}
|
||||
|
||||
/**
|
||||
* Cancels the main subscription of the current organization.
|
||||
* @param {UseMutationOptions<CreateBankRuleValues, Error, CreateBankRuleValues>} options -
|
||||
* @returns {UseMutationResult<CreateBankRuleValues, Error, CreateBankRuleValues>}TCHES
|
||||
*/
|
||||
export function useCancelMainSubscription(
|
||||
options?: UseMutationOptions<
|
||||
CancelMainSubscriptionValues,
|
||||
Error,
|
||||
CancelMainSubscriptionResponse
|
||||
>,
|
||||
): UseMutationResult<
|
||||
CancelMainSubscriptionValues,
|
||||
Error,
|
||||
CancelMainSubscriptionResponse
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation<
|
||||
CancelMainSubscriptionValues,
|
||||
Error,
|
||||
CancelMainSubscriptionResponse
|
||||
>(
|
||||
(values) =>
|
||||
apiRequest.post(`/subscription/cancel`, values).then((res) => res.data),
|
||||
{
|
||||
...options,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
interface ResumeMainSubscriptionValues {}
|
||||
interface ResumeMainSubscriptionResponse {}
|
||||
|
||||
/**
|
||||
* Resumes the main subscription of the current organization.
|
||||
* @param {UseMutationOptions<CreateBankRuleValues, Error, CreateBankRuleValues>} options -
|
||||
* @returns {UseMutationResult<CreateBankRuleValues, Error, CreateBankRuleValues>}TCHES
|
||||
*/
|
||||
export function useResumeMainSubscription(
|
||||
options?: UseMutationOptions<
|
||||
ResumeMainSubscriptionValues,
|
||||
Error,
|
||||
ResumeMainSubscriptionResponse
|
||||
>,
|
||||
): UseMutationResult<
|
||||
ResumeMainSubscriptionValues,
|
||||
Error,
|
||||
ResumeMainSubscriptionResponse
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation<
|
||||
ResumeMainSubscriptionValues,
|
||||
Error,
|
||||
ResumeMainSubscriptionResponse
|
||||
>(
|
||||
(values) =>
|
||||
apiRequest.post(`/subscription/resume`, values).then((res) => res.data),
|
||||
{
|
||||
...options,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
interface ChangeMainSubscriptionPlanValues {
|
||||
variantId: string;
|
||||
}
|
||||
interface ChangeMainSubscriptionPlanResponse {}
|
||||
|
||||
/**
|
||||
* Changese the main subscription of the current organization.
|
||||
* @param {UseMutationOptions<ChangeMainSubscriptionPlanValues, Error, ChangeMainSubscriptionPlanResponse>} options -
|
||||
* @returns {UseMutationResult<ChangeMainSubscriptionPlanValues, Error, ChangeMainSubscriptionPlanResponse>}
|
||||
*/
|
||||
export function useChangeSubscriptionPlan(
|
||||
options?: UseMutationOptions<
|
||||
ChangeMainSubscriptionPlanValues,
|
||||
Error,
|
||||
ChangeMainSubscriptionPlanResponse
|
||||
>,
|
||||
): UseMutationResult<
|
||||
ChangeMainSubscriptionPlanValues,
|
||||
Error,
|
||||
ChangeMainSubscriptionPlanResponse
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation<
|
||||
ChangeMainSubscriptionPlanValues,
|
||||
Error,
|
||||
ChangeMainSubscriptionPlanResponse
|
||||
>(
|
||||
(values) =>
|
||||
apiRequest.post(`/subscription/change`, values).then((res) => res.data),
|
||||
{
|
||||
...options,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1231,6 +1231,13 @@ export const getDashboardRoutes = () => [
|
||||
breadcrumb: 'Bank Rules',
|
||||
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||
},
|
||||
{
|
||||
path: '/billing',
|
||||
component: lazy(() => import('@/containers/Subscriptions/BillingPage')),
|
||||
pageTitle: 'Billing',
|
||||
breadcrumb: 'Billing',
|
||||
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||
},
|
||||
// Homepage
|
||||
{
|
||||
path: `/`,
|
||||
|
||||
Reference in New Issue
Block a user