Merge pull request #1025 from automatisch/make-billing-and-usage-dynamic
feat: use actual data in billing and usage
This commit is contained in:
@@ -8,10 +8,8 @@ echo "Configuring backend environment variables..."
|
|||||||
cd packages/backend
|
cd packages/backend
|
||||||
rm -rf .env
|
rm -rf .env
|
||||||
echo "
|
echo "
|
||||||
HOST=localhost
|
|
||||||
PROTOCOL=http
|
|
||||||
PORT=$BACKEND_PORT
|
PORT=$BACKEND_PORT
|
||||||
WEB_APP_URL=https://$CODESPACE_NAME-$WEB_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
|
WEB_APP_URL=http://localhost:$WEB_PORT
|
||||||
APP_ENV=development
|
APP_ENV=development
|
||||||
POSTGRES_DATABASE=automatisch
|
POSTGRES_DATABASE=automatisch
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
@@ -30,8 +28,7 @@ cd packages/web
|
|||||||
rm -rf .env
|
rm -rf .env
|
||||||
echo "
|
echo "
|
||||||
PORT=$WEB_PORT
|
PORT=$WEB_PORT
|
||||||
REACT_APP_GRAPHQL_URL=https://$CODESPACE_NAME-$BACKEND_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/graphql
|
REACT_APP_GRAPHQL_URL=http://localhost:$BACKEND_PORT/graphql
|
||||||
REACT_APP_BASE_URL=https://$CODESPACE_NAME-$WEB_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
|
|
||||||
REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io
|
REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io
|
||||||
" >> .env
|
" >> .env
|
||||||
cd $CURRENT_DIR
|
cd $CURRENT_DIR
|
||||||
|
@@ -21,10 +21,18 @@ services:
|
|||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
ports:
|
||||||
|
- '5432:5432'
|
||||||
|
expose:
|
||||||
|
- 5432
|
||||||
redis:
|
redis:
|
||||||
image: 'redis:7.0.4-alpine'
|
image: 'redis:7.0.4-alpine'
|
||||||
volumes:
|
volumes:
|
||||||
- redis_data:/data
|
- redis_data:/data
|
||||||
|
ports:
|
||||||
|
- '6379:6379'
|
||||||
|
expose:
|
||||||
|
- 6379
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
@@ -1,31 +1,11 @@
|
|||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { TSubscription } from '@automatisch/types';
|
||||||
|
|
||||||
import Context from '../../types/express/context';
|
import Context from '../../types/express/context';
|
||||||
import Billing from '../../helpers/billing/index.ee';
|
import Billing from '../../helpers/billing/index.ee';
|
||||||
import Execution from '../../models/execution';
|
import Execution from '../../models/execution';
|
||||||
import ExecutionStep from '../../models/execution-step';
|
import ExecutionStep from '../../models/execution-step';
|
||||||
import Subscription from '../../models/subscription.ee';
|
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 (
|
const getBillingAndUsage = async (
|
||||||
_parent: unknown,
|
_parent: unknown,
|
||||||
@@ -36,7 +16,7 @@ const getBillingAndUsage = async (
|
|||||||
'subscription'
|
'subscription'
|
||||||
);
|
);
|
||||||
|
|
||||||
const subscription: ComputedSubscription = persistedSubscription
|
const subscription = persistedSubscription
|
||||||
? paidSubscription(persistedSubscription)
|
? paidSubscription(persistedSubscription)
|
||||||
: freeTrialSubscription();
|
: freeTrialSubscription();
|
||||||
|
|
||||||
@@ -48,7 +28,7 @@ const getBillingAndUsage = async (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const paidSubscription = (subscription: Subscription): ComputedSubscription => {
|
const paidSubscription = (subscription: Subscription): TSubscription => {
|
||||||
const currentPlan = Billing.paddlePlans.find(
|
const currentPlan = Billing.paddlePlans.find(
|
||||||
(plan) => plan.productId === subscription.paddlePlanId
|
(plan) => plan.productId === subscription.paddlePlanId
|
||||||
);
|
);
|
||||||
@@ -81,7 +61,7 @@ const paidSubscription = (subscription: Subscription): ComputedSubscription => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const freeTrialSubscription = (): ComputedSubscription => {
|
const freeTrialSubscription = (): TSubscription => {
|
||||||
return {
|
return {
|
||||||
status: null,
|
status: null,
|
||||||
monthlyQuota: {
|
monthlyQuota: {
|
||||||
|
29
packages/types/index.d.ts
vendored
29
packages/types/index.d.ts
vendored
@@ -339,6 +339,35 @@ export type TPaymentPlan = {
|
|||||||
productId: string;
|
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' {
|
declare module 'axios' {
|
||||||
interface AxiosResponse {
|
interface AxiosResponse {
|
||||||
httpError?: IJSONObject;
|
httpError?: IJSONObject;
|
||||||
|
@@ -12,7 +12,6 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
|||||||
|
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
import AccountDropdownMenu from 'components/AccountDropdownMenu';
|
import AccountDropdownMenu from 'components/AccountDropdownMenu';
|
||||||
import UsageAlert from 'components/UsageAlert/index.ee';
|
|
||||||
import Container from 'components/Container';
|
import Container from 'components/Container';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Link } from './style';
|
import { Link } from './style';
|
||||||
@@ -82,8 +81,6 @@ export default function AppBar(props: AppBarProps): React.ReactElement {
|
|||||||
</Toolbar>
|
</Toolbar>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<UsageAlert />
|
|
||||||
|
|
||||||
<AccountDropdownMenu
|
<AccountDropdownMenu
|
||||||
anchorEl={accountMenuAnchorElement}
|
anchorEl={accountMenuAnchorElement}
|
||||||
id={accountMenuId}
|
id={accountMenuId}
|
||||||
|
@@ -78,7 +78,7 @@ function LoginForm() {
|
|||||||
sx={{ mb: 1 }}
|
sx={{ mb: 1 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isCloud &&<Link
|
{isCloud && <Link
|
||||||
component={RouterLink}
|
component={RouterLink}
|
||||||
to={URLS.FORGOT_PASSWORD}
|
to={URLS.FORGOT_PASSWORD}
|
||||||
underline="none"
|
underline="none"
|
||||||
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
|
import Chip from '@mui/material/Chip';
|
||||||
import Card from '@mui/material/Card';
|
import Card from '@mui/material/Card';
|
||||||
import CardActions from '@mui/material/CardActions';
|
import CardActions from '@mui/material/CardActions';
|
||||||
import CardContent from '@mui/material/CardContent';
|
import CardContent from '@mui/material/CardContent';
|
||||||
@@ -9,23 +10,113 @@ import Divider from '@mui/material/Divider';
|
|||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
|
|
||||||
|
import { TBillingCardAction } from '@automatisch/types';
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
import useUsageData from 'hooks/useUsageData.ee';
|
import useBillingAndUsageData from 'hooks/useBillingAndUsageData.ee';
|
||||||
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
|
||||||
|
const capitalize = (str: string) => 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 (
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
backgroundColor: (theme) => theme.palette.background.default,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="subtitle2" sx={{ pb: 0.5 }}>
|
||||||
|
{name}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="h6" fontWeight="bold">
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
|
||||||
|
<CardActions>
|
||||||
|
<Action action={action} />
|
||||||
|
</CardActions>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Action(props: { action?: TBillingCardAction }) {
|
||||||
|
const { action } = props;
|
||||||
|
if (!action) return <React.Fragment />;
|
||||||
|
|
||||||
|
const { text, type } = action;
|
||||||
|
|
||||||
|
if (type === 'link') {
|
||||||
|
if (action.src.startsWith('http')) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
href={action.src}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
component={Link}
|
||||||
|
to={action.src}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'text') {
|
||||||
|
return (
|
||||||
|
<Typography variant="subtitle2" pb={1}>
|
||||||
|
{text}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <React.Fragment />;
|
||||||
|
}
|
||||||
|
|
||||||
export default function UsageDataInformation() {
|
export default function UsageDataInformation() {
|
||||||
const usageData = useUsageData();
|
const formatMessage = useFormatMessage();
|
||||||
|
const billingAndUsageData = useBillingAndUsageData();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Card sx={{ mb: 3, p: 2 }}>
|
<Card sx={{ mb: 3, p: 2 }}>
|
||||||
<CardContent>
|
<CardContent sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<Box sx={{ mb: 1, display: 'flex', justifyContent: 'space-between' }}>
|
<Box sx={{ mb: 1, display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<Typography variant="h6" fontWeight="bold">
|
<Typography variant="h6" fontWeight="bold">
|
||||||
Subscription plan
|
{formatMessage('usageDataInformation.subscriptionPlan')}
|
||||||
</Typography>
|
</Typography>
|
||||||
{/* <Chip label="Active" color="success" /> */}
|
|
||||||
|
{billingAndUsageData?.subscription?.status && (
|
||||||
|
<Chip
|
||||||
|
label={capitalize(billingAndUsageData?.subscription?.status)}
|
||||||
|
color="success"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider sx={{ mb: 3 }} />
|
<Divider sx={{ mb: 3 }} />
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
item
|
item
|
||||||
@@ -35,76 +126,33 @@ export default function UsageDataInformation() {
|
|||||||
alignItems="stretch"
|
alignItems="stretch"
|
||||||
>
|
>
|
||||||
<Grid item xs={12} md={4}>
|
<Grid item xs={12} md={4}>
|
||||||
<Card
|
<BillingCard
|
||||||
sx={{
|
name={formatMessage('usageDataInformation.monthlyQuota')}
|
||||||
height: '100%',
|
title={billingAndUsageData?.subscription?.monthlyQuota.title}
|
||||||
backgroundColor: (theme) => theme.palette.background.default,
|
action={billingAndUsageData?.subscription?.monthlyQuota.action}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
<Typography variant="subtitle2" sx={{ pb: 0.5 }}>
|
|
||||||
Monthly quota
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h6" fontWeight="bold">
|
|
||||||
Free trial
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
|
||||||
<CardActions>
|
|
||||||
<Button size="small">Upgrade plan</Button>
|
|
||||||
</CardActions>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} md={4}>
|
<Grid item xs={12} md={4}>
|
||||||
<Card
|
<BillingCard
|
||||||
sx={{
|
name={formatMessage('usageDataInformation.nextBillAmount')}
|
||||||
height: '100%',
|
title={billingAndUsageData?.subscription?.nextBillAmount.title}
|
||||||
backgroundColor: (theme) => theme.palette.background.default,
|
action={billingAndUsageData?.subscription?.nextBillAmount.action}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
<Typography variant="subtitle2" sx={{ pb: 0.5 }}>
|
|
||||||
Next bill amount
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Typography variant="h6" fontWeight="bold">
|
|
||||||
---
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
|
||||||
|
|
||||||
<CardActions>
|
|
||||||
{/* <Button size="small">Update billing info</Button> */}
|
|
||||||
</CardActions>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} md={4}>
|
<Grid item xs={12} md={4}>
|
||||||
<Card
|
<BillingCard
|
||||||
sx={{
|
name={formatMessage('usageDataInformation.nextBillDate')}
|
||||||
height: '100%',
|
title={billingAndUsageData?.subscription?.nextBillDate.title}
|
||||||
backgroundColor: (theme) => theme.palette.background.default,
|
action={billingAndUsageData?.subscription?.nextBillDate.action}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
<Typography variant="subtitle2" sx={{ pb: 0.5 }}>
|
|
||||||
Next bill date
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="h6" fontWeight="bold">
|
|
||||||
---
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
|
||||||
|
|
||||||
<CardActions>
|
|
||||||
{/* <Button disabled size="small">
|
|
||||||
monthly billing
|
|
||||||
</Button> */}
|
|
||||||
</CardActions>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h6" fontWeight="bold">
|
<Typography variant="h6" fontWeight="bold">
|
||||||
Your usage
|
{formatMessage('usageDataInformation.yourUsage')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
@@ -112,7 +160,7 @@ export default function UsageDataInformation() {
|
|||||||
variant="subtitle2"
|
variant="subtitle2"
|
||||||
sx={{ color: 'text.secondary', mt: 1 }}
|
sx={{ color: 'text.secondary', mt: 1 }}
|
||||||
>
|
>
|
||||||
Last 30 days total usage
|
{formatMessage('usageDataInformation.yourUsageDescription')}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -129,14 +177,14 @@ export default function UsageDataInformation() {
|
|||||||
variant="subtitle2"
|
variant="subtitle2"
|
||||||
sx={{ color: 'text.secondary', mt: 2, fontWeight: 500 }}
|
sx={{ color: 'text.secondary', mt: 2, fontWeight: 500 }}
|
||||||
>
|
>
|
||||||
Tasks
|
{formatMessage('usageDataInformation.yourUsageTasks')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="subtitle2"
|
variant="subtitle2"
|
||||||
sx={{ color: 'text.secondary', mt: 2, fontWeight: 500 }}
|
sx={{ color: 'text.secondary', mt: 2, fontWeight: 500 }}
|
||||||
>
|
>
|
||||||
12300
|
{billingAndUsageData?.usage.task}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -148,9 +196,9 @@ export default function UsageDataInformation() {
|
|||||||
to={URLS.SETTINGS_PLAN_UPGRADE}
|
to={URLS.SETTINGS_PLAN_UPGRADE}
|
||||||
size="small"
|
size="small"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{ mt: 2 }}
|
sx={{ mt: 2, alignSelf: 'flex-end' }}
|
||||||
>
|
>
|
||||||
Upgrade
|
{formatMessage('usageDataInformation.upgrade')}
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
39
packages/web/src/graphql/queries/get-billing-and-usage.ee.ts
Normal file
39
packages/web/src/graphql/queries/get-billing-and-usage.ee.ts
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
37
packages/web/src/hooks/useBillingAndUsageData.ee.ts
Normal file
37
packages/web/src/hooks/useBillingAndUsageData.ee.ts
Normal file
@@ -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<UseBillingAndUsageDataReturn>) {
|
||||||
|
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);
|
||||||
|
}
|
@@ -140,5 +140,13 @@
|
|||||||
"usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})",
|
"usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})",
|
||||||
"usageAlert.viewPlans": "View plans",
|
"usageAlert.viewPlans": "View plans",
|
||||||
"jsonViewer.noDataFound": "We couldn't find anything matching your search",
|
"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"
|
||||||
|
}
|
@@ -4,7 +4,6 @@ import Grid from '@mui/material/Grid';
|
|||||||
|
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
import UsageDataInformation from 'components/UsageDataInformation/index.ee';
|
import UsageDataInformation from 'components/UsageDataInformation/index.ee';
|
||||||
import UpgradeFreeTrial from 'components/UpgradeFreeTrial/index.ee';
|
|
||||||
import PageTitle from 'components/PageTitle';
|
import PageTitle from 'components/PageTitle';
|
||||||
import Container from 'components/Container';
|
import Container from 'components/Container';
|
||||||
import useFormatMessage from 'hooks/useFormatMessage';
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
Reference in New Issue
Block a user