From fa80e5f34fefab9c73e32f93e6d6d95bc90324e9 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 16 Jan 2026 10:59:06 -0300 Subject: [PATCH 01/10] feat(frontend): add subscription limit info to Usage and Billing pages - Add card-based layout with icons to UsageChartTotals component - Display API calls limit alongside total usage (X / Y format) - Add Subscription Limits section to BillingTab showing all limits - Hide Audit Log and Feature History when not available (value = 0) Closes #5404 Co-Authored-By: Claude Opus 4.5 --- .../common/services/useOrganisationUsage.ts | 1 + .../usage/components/UsageChartTotals.tsx | 103 ++++++++++++------ .../pages/OrganisationUsagePage.tsx | 9 +- .../organisation-settings/tabs/BillingTab.tsx | 82 +++++++++++++- 4 files changed, 162 insertions(+), 33 deletions(-) diff --git a/frontend/common/services/useOrganisationUsage.ts b/frontend/common/services/useOrganisationUsage.ts index c8e34bad4754..6023148b05df 100644 --- a/frontend/common/services/useOrganisationUsage.ts +++ b/frontend/common/services/useOrganisationUsage.ts @@ -34,6 +34,7 @@ export const organisationUsageService = service environmentDocument += v.environment_document || 0 identities += v.identities || 0 }) + return { events_list: data, totals: { diff --git a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx index 7e5f2409945f..50d2e79825f1 100644 --- a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx +++ b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx @@ -3,17 +3,22 @@ import Utils from 'common/utils/utils' import { IonIcon } from '@ionic/react' import { checkmarkSharp } from 'ionicons/icons' import { Res } from 'common/types/responses' +import Icon, { IconName } from 'components/Icon' type LegendItemType = { title: string value: number + limit?: number | null selection: string[] onChange: (v: string) => void colour?: string + icon: IconName } const LegendItem: FC = ({ colour, + icon, + limit, onChange, selection, title, @@ -23,29 +28,43 @@ const LegendItem: FC = ({ return null } return ( -
-

{Utils.numberWithCommas(value)}

-
onChange(title)} - > +
+
+ +
+
+

{title}

+

+ {Utils.numberWithCommas(value)} + {limit !== null && limit !== undefined && ( + + {' '} + / {Utils.numberWithCommas(limit)} + + )} +

{!!colour && (
onChange(title)} > - {selection.includes(title) && ( - - )} +
+ {selection.includes(title) && ( + + )} +
+ Visible
)} - {title}
) @@ -57,11 +76,13 @@ export interface UsageChartTotalsProps { updateSelection: (key: string) => void colours: string[] withColor?: boolean + maxApiCalls?: number | null } const UsageChartTotals: FC = ({ colours, data, + maxApiCalls, selection, updateSelection, withColor = true, @@ -70,47 +91,67 @@ const UsageChartTotals: FC = ({ return null } - const totalItems = [ + const totalItems: Array<{ + colour: string | undefined + icon: IconName + limit: number | null | undefined + title: string + value: number + }> = [ { colour: colours[0], + icon: 'features', + limit: undefined, title: 'Flags', value: data.totals.flags, }, { colour: colours[1], + icon: 'person', + limit: undefined, title: 'Identities', value: data.totals.identities, }, { colour: colours[2], + icon: 'file-text', + limit: undefined, title: 'Environment Document', value: data.totals.environmentDocument, }, { colour: colours[3], + icon: 'layers', + limit: undefined, title: 'Traits', value: data.totals.traits, }, { colour: undefined, + icon: 'bar-chart', + limit: maxApiCalls, title: 'Total API Calls', value: data.totals.total, }, ] return ( -
- {totalItems.map((item) => ( - - ))} -
+ + + {totalItems.map((item) => ( + + ))} + + ) } diff --git a/frontend/web/components/pages/OrganisationUsagePage.tsx b/frontend/web/components/pages/OrganisationUsagePage.tsx index f34f067887c7..c62676a5e567 100644 --- a/frontend/web/components/pages/OrganisationUsagePage.tsx +++ b/frontend/web/components/pages/OrganisationUsagePage.tsx @@ -12,6 +12,7 @@ import AccountStore from 'common/stores/account-store' import { planNames } from 'common/utils/utils' import { Req } from 'common/types/requests' import { useGetOrganisationUsageQuery } from 'common/services/useOrganisationUsage' +import { useGetSubscriptionMetadataQuery } from 'common/services/useSubscriptionMetadata' import UsageChartFilters from 'components/organisation-settings/usage/components/UsageChartFilters' import UsageChartTotals from 'components/organisation-settings/usage/components/UsageChartTotals' @@ -27,7 +28,7 @@ const OrganisationUsagePage: FC = () => { } const params = new URLSearchParams(location.search) return params.get('p') === 'user-agents' ? 'user-agents' : 'global' - }, [location.search]) + }, [isSdkViewEnabled, location.search]) const [chartsView, setChartsView] = useState<'global' | 'user-agents'>( getInitialView(), @@ -62,6 +63,11 @@ const OrganisationUsagePage: FC = () => { { skip: !organisationId }, ) + const { data: subscriptionMeta } = useGetSubscriptionMetadataQuery( + { id: organisationId?.toString() || '' }, + { skip: !organisationId }, + ) + // Aggregate usage events by date, summing metrics across all client types const chartData = useMemo(() => { const consolidated = Object.values( @@ -161,6 +167,7 @@ const OrganisationUsagePage: FC = () => { updateSelection={updateSelection} colours={colours} withColor={chartsView !== 'user-agents'} + maxApiCalls={subscriptionMeta?.max_api_calls} /> {chartsView === 'user-agents' ? ( diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index 63dcf9392bc0..e57a33a17cb9 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -14,9 +14,27 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { id: String(organisation.id), }) - const { chargebee_email } = subscriptionMeta || {} + const { + audit_log_visibility_days, + chargebee_email, + feature_history_visibility_days, + max_api_calls, + max_projects, + max_seats, + } = subscriptionMeta || {} const planName = Utils.getPlanName(organisation.subscription?.plan) || 'Free' + const formatLimit = (value: number | null | undefined): string => { + if (value === null || value === undefined) return 'Unlimited' + return Utils.numberWithCommas(value) + } + + const formatDays = (value: number | null | undefined): string => { + if (value === null || value === undefined) return 'Unlimited' + if (value === 0) return 'Not available' + return `${value} days` + } + return (
@@ -74,6 +92,68 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { )}
+ {subscriptionMeta && ( + <> +
Subscription Limits
+ + + +
+ +
+
+

API Calls

+

{formatLimit(max_api_calls)}

+
+
+ +
+ +
+
+

Team Seats

+

{formatLimit(max_seats)}

+
+
+ +
+ +
+
+

Projects

+

{formatLimit(max_projects)}

+
+
+ {!!audit_log_visibility_days && ( + +
+ +
+
+

Audit Log

+

+ {formatDays(audit_log_visibility_days)} +

+
+
+ )} + {!!feature_history_visibility_days && ( + +
+ +
+
+

Feature History

+

+ {formatDays(feature_history_visibility_days)} +

+
+
+ )} +
+
+ + )}
Manage Payment Plan
From c7b1079f876301480260d4a2dfcefca42af69077 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 16 Jan 2026 11:45:06 -0300 Subject: [PATCH 02/10] refactor(frontend): extract LimitItem component and remove inline styles - Create reusable LimitItem component to reduce code duplication - Remove inline CSS styles in favour of Bootstrap utility classes Co-Authored-By: Claude Opus 4.5 --- .../organisation-settings/tabs/BillingTab.tsx | 96 +++++++++---------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index e57a33a17cb9..571b5b45f57b 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -1,10 +1,28 @@ -import React from 'react' +import React, { FC } from 'react' import { Organisation } from 'common/types/responses' -import Icon from 'components/Icon' +import Icon, { IconName } from 'components/Icon' import Utils from 'common/utils/utils' import Payment from 'components/modals/Payment' import { useGetSubscriptionMetadataQuery } from 'common/services/useSubscriptionMetadata' +type LimitItemProps = { + icon: IconName + label: string + value: string +} + +const LimitItem: FC = ({ icon, label, value }) => ( + +
+ +
+
+

{label}

+

{value}

+
+
+) + type BillingTabProps = { organisation: Organisation } @@ -97,58 +115,34 @@ export const BillingTab = ({ organisation }: BillingTabProps) => {
Subscription Limits
- -
- -
-
-

API Calls

-

{formatLimit(max_api_calls)}

-
-
- -
- -
-
-

Team Seats

-

{formatLimit(max_seats)}

-
-
- -
- -
-
-

Projects

-

{formatLimit(max_projects)}

-
-
+ + + {!!audit_log_visibility_days && ( - -
- -
-
-

Audit Log

-

- {formatDays(audit_log_visibility_days)} -

-
-
+ )} {!!feature_history_visibility_days && ( - -
- -
-
-

Feature History

-

- {formatDays(feature_history_visibility_days)} -

-
-
+ )}
From 9371b7d2f25402dcfdada165994d4a0f456ea9dd Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 16 Jan 2026 12:08:50 -0300 Subject: [PATCH 03/10] style(frontend): increase spacing between subscription limit items Co-Authored-By: Claude Opus 4.5 --- .../components/pages/organisation-settings/tabs/BillingTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index 571b5b45f57b..a06c96b68286 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -114,7 +114,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { <>
Subscription Limits
- + Date: Fri, 16 Jan 2026 12:36:58 -0300 Subject: [PATCH 04/10] fix(frontend): wrap Feature History behind feature_versioning flag Address PR feedback: - Feature History limit is now only shown when feature_versioning flag is enabled - null values already display as 'Unlimited' for all limit values Co-Authored-By: Claude Opus 4.5 --- .../organisation-settings/tabs/BillingTab.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index a06c96b68286..5ac7b70d3029 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -137,13 +137,14 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { value={formatDays(audit_log_visibility_days)} /> )} - {!!feature_history_visibility_days && ( - - )} + {Utils.getFlagsmithHasFeature('feature_versioning') && + !!feature_history_visibility_days && ( + + )} From 86875219fcfeb46e0e822d98aed7c3ece315f3da Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 16 Jan 2026 12:39:50 -0300 Subject: [PATCH 05/10] fix(frontend): show Unlimited for null audit log and feature history values - Change condition from !!value to value !== 0 - null values now display as 'Unlimited' instead of being hidden - 0 values are still hidden (not available) Co-Authored-By: Claude Opus 4.5 --- .../pages/organisation-settings/tabs/BillingTab.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index 5ac7b70d3029..d45b2e60f0a7 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -130,7 +130,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { label='Projects' value={formatLimit(max_projects)} /> - {!!audit_log_visibility_days && ( + {audit_log_visibility_days !== 0 && ( { /> )} {Utils.getFlagsmithHasFeature('feature_versioning') && - !!feature_history_visibility_days && ( + feature_history_visibility_days !== 0 && ( Date: Mon, 19 Jan 2026 08:04:56 -0300 Subject: [PATCH 06/10] refactor(frontend): simplify subscription limit items with filter pattern - Remove LimitItemConfig type, use LimitItemProps[] with filter - Extract showAuditLog and showFeatureHistory conditions - Use ternary with undefined and filter instead of spread arrays Co-Authored-By: Claude Opus 4.5 --- .../common/services/useOrganisationUsage.ts | 1 - .../organisation-settings/tabs/BillingTab.tsx | 65 ++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/frontend/common/services/useOrganisationUsage.ts b/frontend/common/services/useOrganisationUsage.ts index 6023148b05df..c8e34bad4754 100644 --- a/frontend/common/services/useOrganisationUsage.ts +++ b/frontend/common/services/useOrganisationUsage.ts @@ -34,7 +34,6 @@ export const organisationUsageService = service environmentDocument += v.environment_document || 0 identities += v.identities || 0 }) - return { events_list: data, totals: { diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index d45b2e60f0a7..196c97b9b655 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -29,7 +29,7 @@ type BillingTabProps = { export const BillingTab = ({ organisation }: BillingTabProps) => { const { data: subscriptionMeta } = useGetSubscriptionMetadataQuery({ - id: String(organisation.id), + id: organisation.id, }) const { @@ -53,6 +53,35 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { return `${value} days` } + const showAuditLog = audit_log_visibility_days !== 0 + const showFeatureHistory = + Utils.getFlagsmithHasFeature('feature_versioning') && + feature_history_visibility_days !== 0 + + const limitItems: LimitItemProps[] = [ + { + icon: 'bar-chart', + label: 'API Calls', + value: formatLimit(max_api_calls), + }, + { icon: 'people', label: 'Team Seats', value: formatLimit(max_seats) }, + { icon: 'layers', label: 'Projects', value: formatLimit(max_projects) }, + showAuditLog + ? { + icon: 'list', + label: 'Audit Log', + value: formatDays(audit_log_visibility_days), + } + : undefined, + showFeatureHistory + ? { + icon: 'clock', + label: 'Feature History', + value: formatDays(feature_history_visibility_days), + } + : undefined, + ].filter((item): item is LimitItemProps => item !== undefined) + return (
@@ -115,36 +144,14 @@ export const BillingTab = ({ organisation }: BillingTabProps) => {
Subscription Limits
- - - - {audit_log_visibility_days !== 0 && ( + {limitItems.map((item) => ( - )} - {Utils.getFlagsmithHasFeature('feature_versioning') && - feature_history_visibility_days !== 0 && ( - - )} + ))} From a42e29040c3346d4abcb432dd5fe0bea3cf101f9 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 19 Jan 2026 08:32:49 -0300 Subject: [PATCH 07/10] refactor(frontend): fix types and remove nested Row wrappers - Fix organisationId type from string to number in OrganisationUsagePage - Remove unnecessary nested Row components in UsageChartTotals and BillingTab - Combine CSS classes for cleaner markup Co-Authored-By: Claude Opus 4.5 --- .../usage/components/UsageChartTotals.tsx | 28 +++++++++---------- .../pages/OrganisationUsagePage.tsx | 6 ++-- .../organisation-settings/tabs/BillingTab.tsx | 20 ++++++------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx index 50d2e79825f1..e77f017a51f2 100644 --- a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx +++ b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx @@ -136,21 +136,19 @@ const UsageChartTotals: FC = ({ ] return ( - - - {totalItems.map((item) => ( - - ))} - + + {totalItems.map((item) => ( + + ))} ) } diff --git a/frontend/web/components/pages/OrganisationUsagePage.tsx b/frontend/web/components/pages/OrganisationUsagePage.tsx index c62676a5e567..9e3df27809f4 100644 --- a/frontend/web/components/pages/OrganisationUsagePage.tsx +++ b/frontend/web/components/pages/OrganisationUsagePage.tsx @@ -57,14 +57,14 @@ const OrganisationUsagePage: FC = () => { { billing_period: billingPeriod, environmentId: environment, - organisationId: organisationId?.toString() || '', + organisationId: organisationId || 0, projectId: project, }, { skip: !organisationId }, ) const { data: subscriptionMeta } = useGetSubscriptionMetadataQuery( - { id: organisationId?.toString() || '' }, + { id: organisationId || 0 }, { skip: !organisationId }, ) @@ -152,7 +152,7 @@ const OrganisationUsagePage: FC = () => { )} > { {subscriptionMeta && ( <>
Subscription Limits
- - - {limitItems.map((item) => ( - - ))} - + + {limitItems.map((item) => ( + + ))} )} From c6ce08945612e8799ce68f08b468c299152b2f4c Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 19 Jan 2026 10:25:12 -0300 Subject: [PATCH 08/10] fix(frontend): address PR review comments for subscription limits - Add text-white class to checkmark icon container to fix colour inheritance - Add row-gap-4 for better vertical spacing in subscription limits section Co-Authored-By: Claude Opus 4.5 --- .../organisation-settings/usage/components/UsageChartTotals.tsx | 2 +- .../components/pages/organisation-settings/tabs/BillingTab.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx index e77f017a51f2..048e82dcab66 100644 --- a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx +++ b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx @@ -49,7 +49,7 @@ const LegendItem: FC = ({ onClick={() => onChange(title)} >
{ {subscriptionMeta && ( <>
Subscription Limits
- + {limitItems.map((item) => ( Date: Mon, 19 Jan 2026 10:58:30 -0300 Subject: [PATCH 09/10] refactor(frontend): consolidate LimitItem and LegendItem into shared StatItem - Create reusable StatItem component in components/StatItem.tsx - Support both static display and interactive visibility toggle modes - Update UsageChartTotals to use StatItem with visibilityToggle prop - Update BillingTab to use StatItem for subscription limits display - Removes code duplication and ensures consistent styling Co-Authored-By: Claude Opus 4.5 --- frontend/web/components/StatItem.tsx | 76 +++++++++++++ .../usage/components/UsageChartTotals.tsx | 103 ++++-------------- .../organisation-settings/tabs/BillingTab.tsx | 31 ++---- 3 files changed, 106 insertions(+), 104 deletions(-) create mode 100644 frontend/web/components/StatItem.tsx diff --git a/frontend/web/components/StatItem.tsx b/frontend/web/components/StatItem.tsx new file mode 100644 index 000000000000..fb2bf7a740cc --- /dev/null +++ b/frontend/web/components/StatItem.tsx @@ -0,0 +1,76 @@ +import React, { FC } from 'react' +import { IonIcon } from '@ionic/react' +import { checkmarkSharp } from 'ionicons/icons' +import Icon, { IconName } from './Icon' +import Utils from 'common/utils/utils' + +type VisibilityToggleProps = { + colour: string + isVisible: boolean + onToggle: () => void +} + +export type StatItemProps = { + icon: IconName + label: string + value: string | number + // Optional: for displaying limits (e.g., "1,000 / 10,000") + limit?: number | null + // Optional: for visibility toggle in charts + visibilityToggle?: VisibilityToggleProps +} + +const StatItem: FC = ({ + icon, + label, + limit, + value, + visibilityToggle, +}) => { + const formattedValue = + typeof value === 'number' ? Utils.numberWithCommas(value) : value + + return ( +
+
+ +
+
+

{label}

+

+ {formattedValue} + {limit !== null && limit !== undefined && ( + + {' '} + / {Utils.numberWithCommas(limit)} + + )} +

+ {visibilityToggle && ( +
+
+ {visibilityToggle.isVisible && ( + + )} +
+ Visible +
+ )} +
+
+ ) +} + +export default StatItem diff --git a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx index 048e82dcab66..24e8492be58c 100644 --- a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx +++ b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx @@ -1,74 +1,7 @@ import React, { FC } from 'react' -import Utils from 'common/utils/utils' -import { IonIcon } from '@ionic/react' -import { checkmarkSharp } from 'ionicons/icons' import { Res } from 'common/types/responses' -import Icon, { IconName } from 'components/Icon' - -type LegendItemType = { - title: string - value: number - limit?: number | null - selection: string[] - onChange: (v: string) => void - colour?: string - icon: IconName -} - -const LegendItem: FC = ({ - colour, - icon, - limit, - onChange, - selection, - title, - value, -}) => { - if (!value) { - return null - } - return ( -
-
- -
-
-

{title}

-

- {Utils.numberWithCommas(value)} - {limit !== null && limit !== undefined && ( - - {' '} - / {Utils.numberWithCommas(limit)} - - )} -

- {!!colour && ( -
onChange(title)} - > -
- {selection.includes(title) && ( - - )} -
- Visible -
- )} -
-
- ) -} +import { IconName } from 'components/Icon' +import StatItem from 'components/StatItem' export interface UsageChartTotalsProps { data: Res['organisationUsage'] | undefined @@ -137,18 +70,26 @@ const UsageChartTotals: FC = ({ return ( - {totalItems.map((item) => ( - - ))} + {totalItems + .filter((item) => item.value) + .map((item) => ( + updateSelection(item.title), + } + : undefined + } + /> + ))} ) } diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index 1a386f5c5070..66c8765d8bdd 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -1,27 +1,10 @@ -import React, { FC } from 'react' +import React from 'react' import { Organisation } from 'common/types/responses' -import Icon, { IconName } from 'components/Icon' +import Icon from 'components/Icon' import Utils from 'common/utils/utils' import Payment from 'components/modals/Payment' import { useGetSubscriptionMetadataQuery } from 'common/services/useSubscriptionMetadata' - -type LimitItemProps = { - icon: IconName - label: string - value: string -} - -const LimitItem: FC = ({ icon, label, value }) => ( - -
- -
-
-

{label}

-

{value}

-
-
-) +import StatItem, { StatItemProps } from 'components/StatItem' type BillingTabProps = { organisation: Organisation @@ -58,7 +41,9 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { Utils.getFlagsmithHasFeature('feature_versioning') && feature_history_visibility_days !== 0 - const limitItems: LimitItemProps[] = [ + type LimitItem = Pick & { value: string } + + const limitItems: LimitItem[] = [ { icon: 'bar-chart', label: 'API Calls', @@ -80,7 +65,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { value: formatDays(feature_history_visibility_days), } : undefined, - ].filter((item): item is LimitItemProps => item !== undefined) + ].filter((item): item is LimitItem => item !== undefined) return (
@@ -144,7 +129,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => {
Subscription Limits
{limitItems.map((item) => ( - Date: Mon, 19 Jan 2026 11:35:40 -0300 Subject: [PATCH 10/10] refactor(frontend): address code review feedback - Move LimitItem type outside component function in BillingTab - Extract TotalItem type in UsageChartTotals for better readability - Add visibility-checkbox CSS class to replace inline styles - Add accessibility attributes to visibility toggle: - role="checkbox", aria-checked, aria-label - tabIndex for keyboard navigation - onKeyDown handler for Enter/Space keys Co-Authored-By: Claude Opus 4.5 --- frontend/web/components/StatItem.tsx | 24 ++++++++++++------- .../usage/components/UsageChartTotals.tsx | 16 +++++++------ .../organisation-settings/tabs/BillingTab.tsx | 16 ++++++------- frontend/web/styles/project/_panel.scss | 11 +++++++++ 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/frontend/web/components/StatItem.tsx b/frontend/web/components/StatItem.tsx index fb2bf7a740cc..8f19017e759b 100644 --- a/frontend/web/components/StatItem.tsx +++ b/frontend/web/components/StatItem.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react' +import React, { FC, KeyboardEvent } from 'react' import { IonIcon } from '@ionic/react' import { checkmarkSharp } from 'ionicons/icons' import Icon, { IconName } from './Icon' @@ -30,6 +30,13 @@ const StatItem: FC = ({ const formattedValue = typeof value === 'number' ? Utils.numberWithCommas(value) : value + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + visibilityToggle?.onToggle() + } + } + return (
@@ -48,18 +55,17 @@ const StatItem: FC = ({ {visibilityToggle && (
{visibilityToggle.isVisible && ( diff --git a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx index 24e8492be58c..e29a9d6f90c1 100644 --- a/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx +++ b/frontend/web/components/organisation-settings/usage/components/UsageChartTotals.tsx @@ -3,6 +3,14 @@ import { Res } from 'common/types/responses' import { IconName } from 'components/Icon' import StatItem from 'components/StatItem' +type TotalItem = { + colour: string | undefined + icon: IconName + limit: number | null | undefined + title: string + value: number +} + export interface UsageChartTotalsProps { data: Res['organisationUsage'] | undefined selection: string[] @@ -24,13 +32,7 @@ const UsageChartTotals: FC = ({ return null } - const totalItems: Array<{ - colour: string | undefined - icon: IconName - limit: number | null | undefined - title: string - value: number - }> = [ + const totalItems: TotalItem[] = [ { colour: colours[0], icon: 'features', diff --git a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx index 66c8765d8bdd..0531f1f7d18f 100644 --- a/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx +++ b/frontend/web/components/pages/organisation-settings/tabs/BillingTab.tsx @@ -10,6 +10,8 @@ type BillingTabProps = { organisation: Organisation } +type LimitItem = Pick & { value: string } + export const BillingTab = ({ organisation }: BillingTabProps) => { const { data: subscriptionMeta } = useGetSubscriptionMetadataQuery({ id: organisation.id, @@ -41,8 +43,6 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { Utils.getFlagsmithHasFeature('feature_versioning') && feature_history_visibility_days !== 0 - type LimitItem = Pick & { value: string } - const limitItems: LimitItem[] = [ { icon: 'bar-chart', @@ -69,11 +69,11 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { return (
- +
- +
- +
@@ -84,7 +84,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => {
- +

ID @@ -111,7 +111,7 @@ export const BillingTab = ({ organisation }: BillingTabProps) => { )}

-
+
{organisation.subscription?.subscription_id && (