Merge pull request #1058 from automatisch/remove-payment-plans
chore: remove payment plan model and related functionality
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import appConfig from '../../config/app';
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!appConfig.isCloud) return;
|
||||||
|
|
||||||
|
return knex.schema.dropTable('payment_plans');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (!appConfig.isCloud) return;
|
||||||
|
|
||||||
|
return knex.schema.createTable('payment_plans', (table) => {
|
||||||
|
table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()'));
|
||||||
|
table.string('name').notNullable();
|
||||||
|
table.integer('task_count').notNullable();
|
||||||
|
table.uuid('user_id').references('id').inTable('users');
|
||||||
|
table.string('stripe_customer_id');
|
||||||
|
table.string('stripe_subscription_id');
|
||||||
|
table.timestamp('current_period_started_at').nullable();
|
||||||
|
table.timestamp('current_period_ends_at').nullable();
|
||||||
|
table.timestamp('deleted_at').nullable();
|
||||||
|
table.timestamps(true, true);
|
||||||
|
});
|
||||||
|
}
|
@@ -1,33 +0,0 @@
|
|||||||
import appConfig from '../../config/app';
|
|
||||||
import Context from '../../types/express/context';
|
|
||||||
|
|
||||||
// TODO: remove as getBillingAndUsageData query has been introduced
|
|
||||||
const getUsageData = async (
|
|
||||||
_parent: unknown,
|
|
||||||
_params: unknown,
|
|
||||||
context: Context
|
|
||||||
) => {
|
|
||||||
if (!appConfig.isCloud) return;
|
|
||||||
|
|
||||||
const usageData = await context.currentUser
|
|
||||||
.$relatedQuery('currentUsageData')
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const subscription = await usageData
|
|
||||||
.$relatedQuery('subscription')
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const plan = subscription.plan;
|
|
||||||
|
|
||||||
const computedUsageData = {
|
|
||||||
name: plan.name,
|
|
||||||
allowedTaskCount: plan.quota,
|
|
||||||
consumedTaskCount: usageData.consumedTaskCount,
|
|
||||||
remainingTaskCount: plan.quota - usageData.consumedTaskCount,
|
|
||||||
nextResetAt: usageData.nextResetAt,
|
|
||||||
};
|
|
||||||
|
|
||||||
return computedUsageData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getUsageData;
|
|
@@ -11,7 +11,6 @@ import getExecutionSteps from './queries/get-execution-steps';
|
|||||||
import getDynamicData from './queries/get-dynamic-data';
|
import getDynamicData from './queries/get-dynamic-data';
|
||||||
import getDynamicFields from './queries/get-dynamic-fields';
|
import getDynamicFields from './queries/get-dynamic-fields';
|
||||||
import getCurrentUser from './queries/get-current-user';
|
import getCurrentUser from './queries/get-current-user';
|
||||||
import getUsageData from './queries/get-usage-data.ee';
|
|
||||||
import getPaymentPlans from './queries/get-payment-plans.ee';
|
import getPaymentPlans from './queries/get-payment-plans.ee';
|
||||||
import getPaddleInfo from './queries/get-paddle-info.ee';
|
import getPaddleInfo from './queries/get-paddle-info.ee';
|
||||||
import getBillingAndUsage from './queries/get-billing-and-usage.ee';
|
import getBillingAndUsage from './queries/get-billing-and-usage.ee';
|
||||||
@@ -35,7 +34,6 @@ const queryResolvers = {
|
|||||||
getDynamicData,
|
getDynamicData,
|
||||||
getDynamicFields,
|
getDynamicFields,
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
getUsageData,
|
|
||||||
getPaymentPlans,
|
getPaymentPlans,
|
||||||
getPaddleInfo,
|
getPaddleInfo,
|
||||||
getBillingAndUsage,
|
getBillingAndUsage,
|
||||||
|
@@ -34,7 +34,6 @@ type Query {
|
|||||||
parameters: JSONObject
|
parameters: JSONObject
|
||||||
): [SubstepArgument]
|
): [SubstepArgument]
|
||||||
getCurrentUser: User
|
getCurrentUser: User
|
||||||
getUsageData: GetUsageData
|
|
||||||
getPaymentPlans: [PaymentPlan]
|
getPaymentPlans: [PaymentPlan]
|
||||||
getPaddleInfo: GetPaddleInfo
|
getPaddleInfo: GetPaddleInfo
|
||||||
getBillingAndUsage: GetBillingAndUsage
|
getBillingAndUsage: GetBillingAndUsage
|
||||||
@@ -529,14 +528,6 @@ type Usage {
|
|||||||
task: Int
|
task: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetUsageData {
|
|
||||||
name: String
|
|
||||||
allowedTaskCount: Int
|
|
||||||
consumedTaskCount: Int
|
|
||||||
remainingTaskCount: Int
|
|
||||||
nextResetAt: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetPaddleInfo {
|
type GetPaddleInfo {
|
||||||
sandbox: Boolean
|
sandbox: Boolean
|
||||||
vendorId: Int
|
vendorId: Int
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
import Base from './base';
|
|
||||||
import User from './user';
|
|
||||||
|
|
||||||
class PaymentPlan extends Base {
|
|
||||||
id!: string;
|
|
||||||
name!: string;
|
|
||||||
taskCount: number;
|
|
||||||
userId!: string;
|
|
||||||
stripeCustomerId!: string;
|
|
||||||
stripeSubscriptionId!: string;
|
|
||||||
currentPeriodStartedAt!: string;
|
|
||||||
currentPeriodEndsAt!: string;
|
|
||||||
user?: User;
|
|
||||||
|
|
||||||
static tableName = 'payment_plans';
|
|
||||||
|
|
||||||
static jsonSchema = {
|
|
||||||
type: 'object',
|
|
||||||
required: [
|
|
||||||
'name',
|
|
||||||
'taskCount',
|
|
||||||
'userId',
|
|
||||||
'stripeCustomerId',
|
|
||||||
'stripeSubscriptionId',
|
|
||||||
'currentPeriodStartedAt',
|
|
||||||
'currentPeriodEndsAt',
|
|
||||||
],
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
id: { type: 'string', format: 'uuid' },
|
|
||||||
name: { type: 'string' },
|
|
||||||
taskCount: { type: 'integer' },
|
|
||||||
userId: { type: 'string', format: 'uuid' },
|
|
||||||
stripeCustomerId: { type: 'string' },
|
|
||||||
stripeSubscriptionId: { type: 'string' },
|
|
||||||
currentPeriodStartedAt: { type: 'string' },
|
|
||||||
currentPeriodEndsAt: { type: 'string' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static relationMappings = () => ({
|
|
||||||
user: {
|
|
||||||
relation: Base.BelongsToOneRelation,
|
|
||||||
modelClass: User,
|
|
||||||
join: {
|
|
||||||
from: 'payment_plans.user_id',
|
|
||||||
to: 'users.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PaymentPlan;
|
|
@@ -1,54 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import Alert from '@mui/material/Alert';
|
|
||||||
import Snackbar from '@mui/material/Snackbar';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import Stack from '@mui/material/Stack';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import LinearProgress from '@mui/material/LinearProgress';
|
|
||||||
|
|
||||||
import useFormatMessage from 'hooks/useFormatMessage';
|
|
||||||
import useUsageAlert from 'hooks/useUsageAlert.ee';
|
|
||||||
|
|
||||||
export default function UsageAlert() {
|
|
||||||
const formatMessage = useFormatMessage();
|
|
||||||
const usageAlert = useUsageAlert();
|
|
||||||
|
|
||||||
if (!usageAlert.showAlert) return (<React.Fragment />);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Snackbar
|
|
||||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
|
||||||
open
|
|
||||||
>
|
|
||||||
<Alert
|
|
||||||
icon={false}
|
|
||||||
sx={{ fontWeight: 500, minWidth: 410 }}
|
|
||||||
severity={usageAlert.hasExceededLimit ? 'error' : 'warning'}
|
|
||||||
>
|
|
||||||
<Stack direction="row" gap={4} mb={1}>
|
|
||||||
<Typography
|
|
||||||
variant="subtitle2"
|
|
||||||
sx={{ display: 'flex', alignItems: 'center' }}
|
|
||||||
>
|
|
||||||
{usageAlert.alertMessage}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
component={Link}
|
|
||||||
size="small"
|
|
||||||
to={usageAlert.url}
|
|
||||||
sx={{ minWidth: 100 }}
|
|
||||||
>
|
|
||||||
{formatMessage('usageAlert.viewPlans')}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<LinearProgress
|
|
||||||
variant="determinate"
|
|
||||||
value={usageAlert.consumptionPercentage}
|
|
||||||
/>
|
|
||||||
</Alert>
|
|
||||||
</Snackbar>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,14 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
|
|
||||||
export const GET_USAGE_DATA = gql`
|
|
||||||
query GetUsageData {
|
|
||||||
getUsageData {
|
|
||||||
name
|
|
||||||
allowedTaskCount
|
|
||||||
consumedTaskCount
|
|
||||||
remainingTaskCount
|
|
||||||
nextResetAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
@@ -1,47 +0,0 @@
|
|||||||
import * as URLS from 'config/urls';
|
|
||||||
import useFormatMessage from './useFormatMessage';
|
|
||||||
import useUsageData from './useUsageData.ee';
|
|
||||||
|
|
||||||
type UseUsageAlertReturn = {
|
|
||||||
showAlert: true;
|
|
||||||
hasExceededLimit: boolean;
|
|
||||||
alertMessage: string;
|
|
||||||
url: string;
|
|
||||||
consumptionPercentage: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type UseUsageNoAlertReturn = {
|
|
||||||
showAlert: false;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function useUsageAlert(): UseUsageAlertReturn | UseUsageNoAlertReturn {
|
|
||||||
const {
|
|
||||||
allowedTaskCount,
|
|
||||||
consumedTaskCount,
|
|
||||||
nextResetAt,
|
|
||||||
loading
|
|
||||||
} = useUsageData();
|
|
||||||
const formatMessage = useFormatMessage();
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return { showAlert: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
const withinUsageThreshold = consumedTaskCount > allowedTaskCount * 0.7;
|
|
||||||
const consumptionPercentage = consumedTaskCount / allowedTaskCount * 100;
|
|
||||||
const hasExceededLimit = consumedTaskCount >= allowedTaskCount;
|
|
||||||
|
|
||||||
const alertMessage = formatMessage('usageAlert.informationText', {
|
|
||||||
allowedTaskCount,
|
|
||||||
consumedTaskCount,
|
|
||||||
relativeResetDate: nextResetAt?.toRelative(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
showAlert: withinUsageThreshold,
|
|
||||||
hasExceededLimit,
|
|
||||||
alertMessage,
|
|
||||||
consumptionPercentage,
|
|
||||||
url: URLS.SETTINGS_PLAN_UPGRADE,
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
import { useQuery } from '@apollo/client';
|
|
||||||
import { DateTime } from 'luxon';
|
|
||||||
|
|
||||||
import { GET_USAGE_DATA } from 'graphql/queries/get-usage-data.ee';
|
|
||||||
|
|
||||||
type UseUsageDataReturn = {
|
|
||||||
name: string;
|
|
||||||
allowedTaskCount: number;
|
|
||||||
consumedTaskCount: number;
|
|
||||||
remainingTaskCount: number;
|
|
||||||
nextResetAt: DateTime;
|
|
||||||
loading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function useUsageData(): UseUsageDataReturn {
|
|
||||||
const { data, loading } = useQuery(GET_USAGE_DATA);
|
|
||||||
|
|
||||||
const usageData = data?.getUsageData;
|
|
||||||
const nextResetAt = usageData?.nextResetAt;
|
|
||||||
const nextResetAtDateTimeObject = nextResetAt && DateTime.fromMillis(Number(nextResetAt));
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: usageData?.name,
|
|
||||||
allowedTaskCount: usageData?.allowedTaskCount,
|
|
||||||
consumedTaskCount: usageData?.consumedTaskCount,
|
|
||||||
remainingTaskCount: usageData?.remainingTaskCount,
|
|
||||||
nextResetAt: nextResetAtDateTimeObject,
|
|
||||||
loading
|
|
||||||
};
|
|
||||||
}
|
|
Reference in New Issue
Block a user