From f3a8ab289f626627fc0876360e2e7fd692417d6e Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 26 Mar 2023 19:28:15 +0000 Subject: [PATCH] feat: use actual data in billing and usage --- .../queries/get-billing-and-usage.ee.ts | 32 +-- packages/types/index.d.ts | 29 +++ packages/web/src/components/AppBar/index.tsx | 3 - .../web/src/components/LoginForm/index.tsx | 2 +- .../UsageDataInformation/index.ee.tsx | 188 +++++++++++------- .../queries/get-billing-and-usage.ee.ts | 39 ++++ .../src/hooks/useBillingAndUsageData.ee.ts | 37 ++++ packages/web/src/locales/en.json | 12 +- .../BillingAndUsageSettings/index.ee.tsx | 1 - 9 files changed, 240 insertions(+), 103 deletions(-) create mode 100644 packages/web/src/graphql/queries/get-billing-and-usage.ee.ts create mode 100644 packages/web/src/hooks/useBillingAndUsageData.ee.ts diff --git a/packages/backend/src/graphql/queries/get-billing-and-usage.ee.ts b/packages/backend/src/graphql/queries/get-billing-and-usage.ee.ts index 5e4cbe2d..ae6ed957 100644 --- a/packages/backend/src/graphql/queries/get-billing-and-usage.ee.ts +++ b/packages/backend/src/graphql/queries/get-billing-and-usage.ee.ts @@ -1,31 +1,11 @@ +import { DateTime } from 'luxon'; +import { TSubscription } from '@automatisch/types'; + import Context from '../../types/express/context'; import Billing from '../../helpers/billing/index.ee'; import Execution from '../../models/execution'; import ExecutionStep from '../../models/execution-step'; import Subscription from '../../models/subscription.ee'; -import { DateTime } from 'luxon'; - -type BillingCardAction = { - type: string; - text: string; - src?: string | null; -}; - -type ComputedSubscription = { - status: string; - monthlyQuota: { - title: string; - action: BillingCardAction; - }; - nextBillDate: { - title: string; - action: BillingCardAction; - }; - nextBillAmount: { - title: string; - action: BillingCardAction; - }; -}; const getBillingAndUsage = async ( _parent: unknown, @@ -36,7 +16,7 @@ const getBillingAndUsage = async ( 'subscription' ); - const subscription: ComputedSubscription = persistedSubscription + const subscription = persistedSubscription ? paidSubscription(persistedSubscription) : freeTrialSubscription(); @@ -48,7 +28,7 @@ const getBillingAndUsage = async ( }; }; -const paidSubscription = (subscription: Subscription): ComputedSubscription => { +const paidSubscription = (subscription: Subscription): TSubscription => { const currentPlan = Billing.paddlePlans.find( (plan) => plan.productId === subscription.paddlePlanId ); @@ -81,7 +61,7 @@ const paidSubscription = (subscription: Subscription): ComputedSubscription => { }; }; -const freeTrialSubscription = (): ComputedSubscription => { +const freeTrialSubscription = (): TSubscription => { return { status: null, monthlyQuota: { diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 7b3df670..40be642a 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -339,6 +339,35 @@ export type TPaymentPlan = { productId: string; } +export type TSubscription = { + status: string; + monthlyQuota: { + title: string; + action: BillingCardAction; + }; + nextBillDate: { + title: string; + action: BillingCardAction; + }; + nextBillAmount: { + title: string; + action: BillingCardAction; + }; +} + +type TBillingCardAction = TBillingTextCardAction | TBillingLinkCardAction; + +type TBillingTextCardAction = { + type: 'text'; + text: string; +} + +type TBillingLinkCardAction = { + type: 'link'; + text: string; + src: string; +} + declare module 'axios' { interface AxiosResponse { httpError?: IJSONObject; diff --git a/packages/web/src/components/AppBar/index.tsx b/packages/web/src/components/AppBar/index.tsx index dfb4f4d1..cf32768a 100644 --- a/packages/web/src/components/AppBar/index.tsx +++ b/packages/web/src/components/AppBar/index.tsx @@ -12,7 +12,6 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import * as URLS from 'config/urls'; import AccountDropdownMenu from 'components/AccountDropdownMenu'; -import UsageAlert from 'components/UsageAlert/index.ee'; import Container from 'components/Container'; import { FormattedMessage } from 'react-intl'; import { Link } from './style'; @@ -82,8 +81,6 @@ export default function AppBar(props: AppBarProps): React.ReactElement { - - - {isCloud && str[0].toUpperCase() + str.slice(1, str.length); + +type BillingCardProps = { + name: string; + title?: string; + action?: TBillingCardAction; +}; + +function BillingCard(props: BillingCardProps) { + const { name, title = '', action } = props; + + return ( + theme.palette.background.default, + }} + > + + + {name} + + + + {title} + + + + + + + + ); +} + +function Action(props: { action?: TBillingCardAction }) { + const { action } = props; + if (!action) return ; + + const { text, type } = action; + + if (type === 'link') { + if (action.src.startsWith('http')) { + return ( + + ) + } else { + return ( + + ); + } + } + + if (type === 'text') { + return ( + + {text} + + ); + } + + return ; +} export default function UsageDataInformation() { - const usageData = useUsageData(); + const formatMessage = useFormatMessage(); + const billingAndUsageData = useBillingAndUsageData(); return ( - + - Subscription plan + {formatMessage('usageDataInformation.subscriptionPlan')} - {/* */} + + {billingAndUsageData?.subscription?.status && ( + + )} + + - theme.palette.background.default, - }} - > - - - Monthly quota - - - Free trial - - - - - - + - theme.palette.background.default, - }} - > - - - Next bill amount - - - - --- - - - - - {/* */} - - + - theme.palette.background.default, - }} - > - - - Next bill date - - - --- - - - - - {/* */} - - + + - Your usage + {formatMessage('usageDataInformation.yourUsage')} @@ -112,7 +160,7 @@ export default function UsageDataInformation() { variant="subtitle2" sx={{ color: 'text.secondary', mt: 1 }} > - Last 30 days total usage + {formatMessage('usageDataInformation.yourUsageDescription')} @@ -129,14 +177,14 @@ export default function UsageDataInformation() { variant="subtitle2" sx={{ color: 'text.secondary', mt: 2, fontWeight: 500 }} > - Tasks + {formatMessage('usageDataInformation.yourUsageTasks')} - 12300 + {billingAndUsageData?.usage.task} @@ -148,9 +196,9 @@ export default function UsageDataInformation() { to={URLS.SETTINGS_PLAN_UPGRADE} size="small" variant="contained" - sx={{ mt: 2 }} + sx={{ mt: 2, alignSelf: 'flex-end' }} > - Upgrade + {formatMessage('usageDataInformation.upgrade')} diff --git a/packages/web/src/graphql/queries/get-billing-and-usage.ee.ts b/packages/web/src/graphql/queries/get-billing-and-usage.ee.ts new file mode 100644 index 00000000..a30d9abd --- /dev/null +++ b/packages/web/src/graphql/queries/get-billing-and-usage.ee.ts @@ -0,0 +1,39 @@ +import { gql } from '@apollo/client'; + +export const GET_BILLING_AND_USAGE = gql` + query GetBillingAndUsage { + getBillingAndUsage { + subscription { + status + monthlyQuota { + title + action { + type + text + src + } + } + nextBillDate { + title + action { + type + text + src + } + } + nextBillAmount { + title + action { + type + text + src + } + } + } + usage { + task + } + } + } +`; + diff --git a/packages/web/src/hooks/useBillingAndUsageData.ee.ts b/packages/web/src/hooks/useBillingAndUsageData.ee.ts new file mode 100644 index 00000000..0d16ca2b --- /dev/null +++ b/packages/web/src/hooks/useBillingAndUsageData.ee.ts @@ -0,0 +1,37 @@ +import { useQuery } from '@apollo/client'; +import { DateTime } from 'luxon'; +import { TSubscription } from '@automatisch/types'; + +import { GET_BILLING_AND_USAGE } from 'graphql/queries/get-billing-and-usage.ee'; + +function transform(billingAndUsageData: NonNullable) { + const nextBillDate = billingAndUsageData.subscription.nextBillDate; + const nextBillDateTitle = nextBillDate.title; + const relativeNextBillDateTitle = nextBillDateTitle ? DateTime.fromMillis(Number(nextBillDateTitle)).toFormat('LLL dd, yyyy') as string : ''; + + return { + ...billingAndUsageData, + subscription: { + ...billingAndUsageData.subscription, + nextBillDate: { + ...billingAndUsageData.subscription.nextBillDate, + title: relativeNextBillDateTitle, + } + } + }; +} + +type UseBillingAndUsageDataReturn = { + subscription: TSubscription, + usage: { + task: number; + } +} | null; + +export default function useBillingAndUsageData(): UseBillingAndUsageDataReturn { + const { data, loading } = useQuery(GET_BILLING_AND_USAGE); + + if (loading) return null; + + return transform(data.getBillingAndUsage); +} diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index c860fb3e..e183f58c 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -140,5 +140,13 @@ "usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})", "usageAlert.viewPlans": "View plans", "jsonViewer.noDataFound": "We couldn't find anything matching your search", - "planUpgrade.title": "Upgrade your plan" -} + "planUpgrade.title": "Upgrade your plan", + "usageDataInformation.subscriptionPlan": "Subscription plan", + "usageDataInformation.monthlyQuota": "Monthly quota", + "usageDataInformation.nextBillAmount": "Next bill amount", + "usageDataInformation.nextBillDate": "Next bill date", + "usageDataInformation.yourUsage": "Your usage", + "usageDataInformation.yourUsageDescription": "Last 30 days total usage", + "usageDataInformation.yourUsageTasks": "Tasks", + "usageDataInformation.upgrade": "Upgrade" +} \ No newline at end of file diff --git a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx index 3b5383e4..62a7de4f 100644 --- a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx +++ b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx @@ -4,7 +4,6 @@ import Grid from '@mui/material/Grid'; import * as URLS from 'config/urls'; import UsageDataInformation from 'components/UsageDataInformation/index.ee'; -import UpgradeFreeTrial from 'components/UpgradeFreeTrial/index.ee'; import PageTitle from 'components/PageTitle'; import Container from 'components/Container'; import useFormatMessage from 'hooks/useFormatMessage';