refactor: add usage limit and update card style

This commit is contained in:
moonrailgun 2024-11-08 01:57:35 +08:00
parent 71f75c27dd
commit 34f9fe6957
3 changed files with 82 additions and 79 deletions

View File

@ -10,6 +10,7 @@ import { CommonHeader } from '@/components/CommonHeader';
import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Card, CardContent, CardHeader } from '@/components/ui/card';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { formatNumber } from '@/utils/common'; import { formatNumber } from '@/utils/common';
import { UsageCard } from '@/components/UsageCard';
export const Route = createFileRoute('/settings/usage')({ export const Route = createFileRoute('/settings/usage')({
beforeLoad: routeAuthBeforeLoad, beforeLoad: routeAuthBeforeLoad,
@ -34,6 +35,10 @@ function PageComponent() {
endAt: endDate.valueOf(), endAt: endDate.valueOf(),
}); });
const { data: limit } = trpc.billing.limit.useQuery({
workspaceId,
});
return ( return (
<CommonWrapper header={<CommonHeader title={t('Usage')} />}> <CommonWrapper header={<CommonHeader title={t('Usage')} />}>
<ScrollArea className="h-full overflow-hidden p-4"> <ScrollArea className="h-full overflow-hidden p-4">
@ -49,85 +54,61 @@ function PageComponent() {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3"> <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Website Count')}
{t('Website Count')} current={serviceCountData?.website ?? 0}
</CardHeader> limit={limit?.maxWebsiteCount}
<CardContent>{serviceCountData?.website ?? 0}</CardContent> />
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Monitor Count')}
{t('Monitor Count')} current={serviceCountData?.monitor ?? 0}
</CardHeader> />
<CardContent>{serviceCountData?.monitor ?? 0}</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Survey Count')}
{t('Survey Count')} current={serviceCountData?.survey ?? 0}
</CardHeader> />
<CardContent>{serviceCountData?.survey ?? 0}</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Page Count')}
{t('Page Count')} current={serviceCountData?.page ?? 0}
</CardHeader> />
<CardContent>{serviceCountData?.page ?? 0}</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Feed Channel Count')}
{t('Feed Channel Count')} current={serviceCountData?.feed ?? 0}
</CardHeader> limit={limit?.maxFeedChannelCount}
<CardContent>{serviceCountData?.feed ?? 0}</CardContent> />
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Website Accepted Count')}
{t('Website Accepted Count')} current={billingUsageData?.websiteAcceptedCount ?? 0}
</CardHeader> />
<CardContent>
{formatNumber(billingUsageData?.websiteAcceptedCount ?? 0)}
</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Website Event Count')}
{t('Website Event Count')} current={billingUsageData?.websiteEventCount ?? 0}
</CardHeader> limit={limit?.maxWebsiteEventCount}
<CardContent> />
{formatNumber(billingUsageData?.websiteEventCount ?? 0)}
</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Monitor Execution Count')}
{t('Monitor Execution Count')} current={billingUsageData?.monitorExecutionCount ?? 0}
</CardHeader> limit={limit?.maxMonitorExecutionCount}
<CardContent> />
{formatNumber(billingUsageData?.monitorExecutionCount ?? 0)}
</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Survey Count')}
{t('Survey Count')} current={billingUsageData?.surveyCount ?? 0}
</CardHeader> limit={limit?.maxSurveyCount}
<CardContent> />
{formatNumber(billingUsageData?.surveyCount ?? 0)}
</CardContent>
</Card>
<Card className="flex-1"> <UsageCard
<CardHeader className="text-muted-foreground"> title={t('Feed Event Count')}
{t('Feed Event Count')} current={billingUsageData?.feedEventCount ?? 0}
</CardHeader> limit={limit?.maxFeedEventCount}
<CardContent> />
{formatNumber(billingUsageData?.feedEventCount ?? 0)}
</CardContent>
</Card>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>

View File

@ -1,13 +1,16 @@
import { WorkspaceSubscriptionTier } from '@prisma/client'; import { WorkspaceSubscriptionTier } from '@prisma/client';
import { z } from 'zod';
interface TierLimit { export const TierLimitSchema = z.object({
maxWebsiteCount: number; maxWebsiteCount: z.number(),
maxWebsiteEventCount: number; maxWebsiteEventCount: z.number(),
maxMonitorExecutionCount: number; maxMonitorExecutionCount: z.number(),
maxSurveyCount: number; maxSurveyCount: z.number(),
maxFeedChannelCount: number; maxFeedChannelCount: z.number(),
maxFeedEventCount: number; maxFeedEventCount: z.number(),
} });
type TierLimit = z.infer<typeof TierLimitSchema>;
/** /**
* Limit, Every month * Limit, Every month

View File

@ -16,7 +16,11 @@ import {
SubscriptionTierType, SubscriptionTierType,
} from '../../model/billing/index.js'; } from '../../model/billing/index.js';
import { LemonSqueezySubscriptionModelSchema } from '../../prisma/zod/lemonsqueezysubscription.js'; import { LemonSqueezySubscriptionModelSchema } from '../../prisma/zod/lemonsqueezysubscription.js';
import { getWorkspaceUsage } from '../../model/billing/workspace.js'; import {
getWorkspaceSubscription,
getWorkspaceUsage,
} from '../../model/billing/workspace.js';
import { getTierLimit, TierLimitSchema } from '../../model/billing/limit.js';
export const billingRouter = router({ export const billingRouter = router({
usage: workspaceProcedure usage: workspaceProcedure
@ -47,6 +51,21 @@ export const billingRouter = router({
return getWorkspaceUsage(workspaceId, startAt, endAt); return getWorkspaceUsage(workspaceId, startAt, endAt);
}), }),
limit: workspaceProcedure
.meta(
buildBillingOpenapi({
method: 'GET',
path: '/limit',
description: 'get workspace subscription limit',
})
)
.output(TierLimitSchema)
.query(async ({ input }) => {
const { workspaceId } = input;
const tier = await getWorkspaceSubscription(workspaceId);
return getTierLimit(tier);
}),
currentSubscription: workspaceProcedure currentSubscription: workspaceProcedure
.meta( .meta(
buildBillingOpenapi({ buildBillingOpenapi({