feat: show account AI usage
CI and Deploy / test (push) Successful in 2m40s
CI and Deploy / deploy (push) Successful in 50s

This commit is contained in:
cesnimda
2026-07-31 00:08:41 +02:00
parent 2126a2db5c
commit 9f16a5675a
4 changed files with 93 additions and 0 deletions
@@ -0,0 +1,47 @@
import React, { useEffect, useState } from "react";
import { Alert, Box, LinearProgress, Paper, Skeleton, Stack, Typography } from "@mui/material";
import { api } from "../api";
type Usage = {
currentMonth: { calls: number; estimatedTokens: number };
plan: string;
monthlyCallLimit: number;
monthlyTokenLimit: number;
};
export default function AiUsageCard() {
const [usage, setUsage] = useState<Usage | null>(null);
const [failed, setFailed] = useState(false);
useEffect(() => {
let active = true;
api.get<Usage>("/ai/usage")
.then((response) => { if (active) setUsage(response.data); })
.catch(() => { if (active) setFailed(true); });
return () => { active = false; };
}, []);
if (failed) return <Alert severity="warning">AI usage is temporarily unavailable.</Alert>;
if (!usage) return <Skeleton variant="rounded" height={150} />;
const callsPercent = Math.min(100, usage.currentMonth.calls / usage.monthlyCallLimit * 100);
const tokensPercent = Math.min(100, usage.currentMonth.estimatedTokens / usage.monthlyTokenLimit * 100);
return (
<Paper sx={{ p: 2.5, borderRadius: 4, border: "none" }}>
<Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: 2 }}>
<Typography variant="overline" sx={{ color: "text.secondary", fontWeight: 800 }}>AI usage</Typography>
<Typography variant="caption" sx={{ textTransform: "capitalize", fontWeight: 700 }}>{usage.plan} plan</Typography>
</Stack>
<Box sx={{ mb: 2 }}>
<Typography variant="body2">{usage.currentMonth.calls.toLocaleString()} of {usage.monthlyCallLimit.toLocaleString()} generations this month</Typography>
<LinearProgress variant="determinate" value={callsPercent} aria-label="Monthly AI generations used" sx={{ mt: 0.75, height: 7, borderRadius: 99 }} />
</Box>
<Box>
<Typography variant="body2">{usage.currentMonth.estimatedTokens.toLocaleString()} of {usage.monthlyTokenLimit.toLocaleString()} estimated tokens</Typography>
<LinearProgress variant="determinate" value={tokensPercent} aria-label="Monthly AI tokens used" sx={{ mt: 0.75, height: 7, borderRadius: 99 }} />
</Box>
<Typography variant="caption" color="text.secondary" sx={{ display: "block", mt: 1.5 }}>Limits reset at the start of each calendar month.</Typography>
</Paper>
);
}
@@ -22,6 +22,7 @@ import ImportExportJobs from "./ImportExportJobs";
import RulesSettingsCard from "./RulesSettingsCard";
import BackupCard from "./BackupCard";
import QuickCaptureCard from "./QuickCaptureCard";
import AiUsageCard from "./AiUsageCard";
import { ThemeModePref } from "../themePrefs";
import { useI18n } from "../i18n/I18nProvider";
@@ -197,6 +198,7 @@ export default function SettingsView({
</Box>
</SectionCard>
<AiUsageCard />
<QuickCaptureCard />
<SectionCard title="Connected accounts" subtitle="Manage inbox connections separately from your account and security settings.">
<Button variant="outlined" onClick={() => navigate("/settings/connected-accounts")}>Manage connected accounts</Button>