Skip to content

fix: cross-cutting SDK fixes#1577

Open
rohanchkrabrty wants to merge 8 commits intomainfrom
fix-cross-cuting
Open

fix: cross-cutting SDK fixes#1577
rohanchkrabrty wants to merge 8 commits intomainfrom
fix-cross-cuting

Conversation

@rohanchkrabrty
Copy link
Copy Markdown
Contributor

Summary

  • Fix column-width layout shift between loading and loaded state on members, projects, project details, and team details tables (apply table-layout: fixed and explicit header widths matching the service-accounts pattern).
  • Fix billing and plans pages: invoices loading state, plans table overflow, plan card and feature table styling, and confirm-cycle/plan-change dialogs.
  • Refactor service accounts view: details view, projects cell, project-access dialog, token hook (useServiceUserTokens), and column/dialog styling.
  • Add optional toast and theme support to the SDK provider; fix billing permission hook and view-container CSS.
  • Misc cleanup: update import paths, fix copy button usage, remove a stray console log, and tidy tsconfig/shared types.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Apr 28, 2026 10:18am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added permission-based access restrictions for billing features; users without update permissions see restricted access view.
    • Introduced checkout-based billing workflow, replacing previous dialog-based updates.
  • Improvements

    • Enhanced service account token management with improved caching and UI feedback.
    • Refined table layouts across members, projects, and teams views for better column alignment.
    • Improved loading states and skeleton placeholders for better user feedback during data fetching.
    • Optimized dialog designs and form interactions for cleaner UI presentation.

Walkthrough

Large-scale update refactoring billing access control, permissions integration, provider configuration, and table layouts. Introduces permission-based billing access, replaces billing details dialog with checkout flow, adds conditional theme/toast providers, implements service user token caching, standardizes table layouts across views, and updates imports to use path aliases.

Changes

Cohort / File(s) Summary
Billing Page & Views
web/apps/client-demo/src/pages/settings/Billing.tsx, web/sdk/react/views-new/billing/billing-view.tsx, web/sdk/react/views-new/billing/billing-view.module.css
Core billing page extraction of orgId and navigation callback wiring. BillingView now enforces permission-based access, gates invoices query on canSeeBilling, replaces dialog-based billing details updates with createCheckout mutation flow, and adds permission-based empty state. CSS rules simplified by removing link underline handling and dialog height constraints.
Billing Components
web/sdk/react/views-new/billing/components/billing-details-card.tsx, web/sdk/react/views-new/billing/components/billing-details-dialog.tsx, web/sdk/react/views-new/billing/components/confirm-cycle-switch-dialog.tsx, web/sdk/react/views-new/billing/components/invoices.tsx, web/sdk/react/views-new/billing/components/payment-issue.tsx, web/sdk/react/views-new/billing/components/payment-method-card.tsx, web/sdk/react/views-new/billing/components/upcoming-billing-cycle.tsx, web/sdk/react/views-new/billing/components/upcoming-plan-change-banner.tsx
Billing details card adds isActionLoading prop for checkout UI. Dialog component fully removed; replaced by server-side checkout flow. Cycle switch uses standardized Amount component with hideDecimals config. Invoices refactored to virtualized table layout with custom header and loading row count. Payment issue and upcoming plan change remove skeleton placeholders on load. Payment method card refactors skeleton rendering to full conditional sections.
Permissions & Provider Configuration
web/sdk/react/contexts/FrontierProvider.tsx, web/sdk/react/hooks/useBillingPermission.ts, web/sdk/shared/types.ts
FrontierProvider now accepts renderThemeProvider and renderToastProvider flags (both default true) with new OptionalProvider helper component for conditional provider wrapping. useBillingPermission hook extended to evaluate UpdatePermission alongside DeletePermission, returning new canSeeBilling boolean. FrontierProviderProps interface updated with two new optional boolean properties.
Service Accounts Core
web/sdk/react/views-new/service-accounts/service-accounts-view.tsx, web/sdk/react/views-new/service-accounts/service-accounts-view.module.css, web/sdk/react/views-new/service-accounts/service-account-details-view.tsx, web/sdk/react/views-new/service-accounts/service-account-details-view.module.css
Service accounts views updated to use SVG icon imports, apply fixed table layouts, and update loading state logic for missing org ID. Token display refactored to remove local copy state and integrate CopyButton component. Service account details view expands loading conditions and reorganizes token UI with hover-driven copy buttons. CSS updates manage dialog layout with fixed heights and inner flex containers.
Service Accounts Dialogs & Hooks
web/sdk/react/views-new/service-accounts/components/add-service-account-dialog.tsx, web/sdk/react/views-new/service-accounts/components/delete-service-account-dialog.tsx, web/sdk/react/views-new/service-accounts/components/delete-service-account-dialog.module.css, web/sdk/react/views-new/service-accounts/components/revoke-token-dialog.tsx, web/sdk/react/views-new/service-accounts/components/revoke-token-dialog.module.css, web/sdk/react/views-new/service-accounts/components/add-token-form.tsx, web/sdk/react/views-new/service-accounts/hooks/useServiceUserTokens.ts
New useServiceUserTokens hook added with fresh token caching and imperative cache helpers (addToken, removeToken, clearFreshTokens). Dialog components restructured with disabled close buttons and removed header sections. Add-service-account-dialog integrates cacheFreshServiceUserToken flow. Token form and dialogs updated to use path aliases. CSS modules introduce body border removal and button hover visibility.
Service Accounts Table & Columns
web/sdk/react/views-new/service-accounts/components/service-account-columns.tsx, web/sdk/react/views-new/service-accounts/components/service-account-columns.module.css, web/sdk/react/views-new/service-accounts/components/manage-project-access-dialog.tsx, web/sdk/react/views-new/service-accounts/components/projects-cell.tsx, web/sdk/react/views-new/service-accounts/components/projects-cell.module.css
Service account columns constrain table layout with fixed/max widths (48px actions, 600px projects, 300px createdAt). New CSS module hides actions on default and shows on hover. Manage project access dialog applies fixed column widths (40px checkbox, 180px access), tightens loading UI, and prevents role changes during updates. Projects cell refactored to use loading skeleton and tooltip-based full-text display with CSS-based width constraints.
Plans Components
web/sdk/react/views-new/plans/plans-view.tsx, web/sdk/react/views-new/plans/components/confirm-plan-change-dialog.tsx, web/sdk/react/views-new/plans/components/feature-table.tsx, web/sdk/react/views-new/plans/components/plan-card.tsx, web/sdk/react/views-new/plans/components/plan-card.module.css
Plans view refactors interval selection to use useMemo and intervalOverrides state, forwards isFeaturesLoading to feature table. Feature table adds isLoading prop with skeleton rendering. Plan card removes explicit valueInMinorUnits prop and adds CSS classes for interval tabs styling. Price confirmation dialog removes valueInMinorUnits override. New CSS classes for .intervalTabs, .intervalTabsList, .intervalTab.
Table Layout Standardization
web/sdk/react/components/view-container/view-container.module.css, web/sdk/react/views-new/members/members-view.tsx, web/sdk/react/views-new/members/members-view.module.css, web/sdk/react/views-new/members/components/member-columns.tsx, web/sdk/react/views-new/projects/projects-view.tsx, web/sdk/react/views-new/projects/projects-view.module.css, web/sdk/react/views-new/projects/project-details-view.tsx, web/sdk/react/views-new/projects/project-details-view.module.css, web/sdk/react/views-new/projects/components/member-columns.tsx, web/sdk/react/views-new/projects/components/project-columns.tsx, web/sdk/react/views-new/teams/team-details-view.tsx, web/sdk/react/views-new/teams/team-details-view.module.css, web/sdk/react/views-new/teams/components/member-columns.tsx
Consistent pattern applied across multiple views: new .table CSS class with table-layout: fixed added to module stylesheets, column definitions constrained with explicit width/max-width values (48px–600px ranges), and DataTable.Content extended with table: styles.table classNames mapping. View-container moves padding from outer container to inner content with box-sizing: border-box.
Minor Updates & Configuration
web/sdk/react/views-new/preferences/preferences-view.tsx, web/sdk/react/views-new/tokens/tokens-view.tsx, web/sdk/tsconfig.json
Preferences view removes debug console.log(theme) statement. Tokens view expands isLoading to include missing activeOrganization?.id. TypeScript configuration adds ~/utils path alias mapping to web/sdk/utils/index.ts.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #1518: Directly related to the client-demo Billing page changes; establishes the BillingView component and its onNavigateToPlans prop that this PR wires up.
  • PR #1511: Overlaps significantly on service-accounts feature modifications including routes, components, and views touched throughout this PR.
  • PR #1534: Directly related—adds the Plans route and page that the main PR's Billing page now navigates to via /${orgId}/settings/plans.

Suggested reviewers

  • rsbh
  • rohilsurana
  • paanSinghCoder
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 25047222899

Coverage remained the same at 42.353%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 37069
Covered Lines: 15700
Line Coverage: 42.35%
Coverage Strength: 11.76 hits per line

💛 - Coveralls

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
web/sdk/react/views-new/tokens/tokens-view.tsx (1)

82-90: ⚠️ Potential issue | 🟠 Major

Avoid indefinite loading when there is no active organization.

With the new !activeOrganization?.id clause, the view can stay in loading mode forever after org resolution completes but no org exists, which keeps skeletons and disables actions indefinitely.

💡 Proposed fix
-  const isLoading =
-    !activeOrganization?.id ||
-    isActiveOrganizationLoading ||
-    isBillingAccountLoading ||
-    isTokensLoading ||
-    isPermissionsFetching;
+  const hasActiveOrganization = Boolean(activeOrganization?.id);
+  const isLoading =
+    isActiveOrganizationLoading ||
+    (hasActiveOrganization &&
+      (isBillingAccountLoading || isTokensLoading || isPermissionsFetching));

-  const isTxnDataLoading = isLoading || isTransactionsListLoading;
+  const isTxnDataLoading =
+    isLoading || (hasActiveOrganization && isTransactionsListLoading);
web/sdk/react/views-new/billing/components/payment-method-card.tsx (1)

116-126: ⚠️ Potential issue | 🟡 Minor

Don't show the auth tooltip while the action is loading.

Inside this branch the user is already allowed, so isBtnDisabled only reflects the pending mutation. Wrapping the loading button with AuthTooltipMessage tells authorized users they lack access immediately after clicking.

Proposed fix
-        {!isLoading && isAllowed ? (
-          isBtnDisabled ? (
-            <Tooltip>
-              <Tooltip.Trigger render={<span />}>
-                {actionBtn}
-              </Tooltip.Trigger>
-              <Tooltip.Content>
-                {AuthTooltipMessage}
-              </Tooltip.Content>
-            </Tooltip>
-          ) : actionBtn
-        ) : null}
+        {!isLoading && isAllowed ? actionBtn : null}
web/sdk/react/views-new/billing/components/invoices.tsx (1)

195-222: ⚠️ Potential issue | 🟠 Major

Keep incremental pagination out of the table loading flag.

Line 195 treats isFetchingNextPage as a full-table load. With onLoadMore wired up, every pagination request can push the table back into its loading state and hide already rendered invoices instead of appending smoothly.

Proposed fix
-  const loading = (!activeOrganization?.id || isLoading || isFetchingNextPage) && !isError;
+  const loading = (!activeOrganization?.id || isLoading) && !isError;
🧹 Nitpick comments (2)
web/sdk/react/views-new/service-accounts/components/projects-cell.module.css (1)

9-11: Prevent tooltip overflow on long unbroken names.

max-width alone may still overflow when a project name has no natural breakpoints. Add wrapping behavior for safer rendering.

Suggested patch
 .tooltipContent {
   max-width: 550px;
+  overflow-wrap: anywhere;
 }
web/sdk/react/views-new/service-accounts/hooks/useServiceUserTokens.ts (1)

123-129: Consider exposing query error state.

The hook currently only exposes isLoading, but the underlying useQuery also provides error and isError. Consumers might benefit from being able to display error states when the token fetch fails.

💡 Optional enhancement to expose error state
-  const { data: tokensData, isLoading } = useQuery(
+  const { data: tokensData, isLoading, error, isError } = useQuery(
     FrontierServiceQueries.listServiceUserTokens,
     ...
   );
   
   return {
     tokens,
     isLoading,
+    error,
+    isError,
     addToken,
     removeToken,
     clearFreshTokens
   };

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a572a24e-1ee7-4664-8240-6126253bc949

📥 Commits

Reviewing files that changed from the base of the PR and between d11eb4e and 9668eef.

📒 Files selected for processing (51)
  • web/apps/client-demo/src/pages/settings/Billing.tsx
  • web/sdk/react/components/view-container/view-container.module.css
  • web/sdk/react/contexts/FrontierProvider.tsx
  • web/sdk/react/hooks/useBillingPermission.ts
  • web/sdk/react/views-new/billing/billing-view.module.css
  • web/sdk/react/views-new/billing/billing-view.tsx
  • web/sdk/react/views-new/billing/components/billing-details-card.tsx
  • web/sdk/react/views-new/billing/components/billing-details-dialog.tsx
  • web/sdk/react/views-new/billing/components/confirm-cycle-switch-dialog.tsx
  • web/sdk/react/views-new/billing/components/invoices.tsx
  • web/sdk/react/views-new/billing/components/payment-issue.tsx
  • web/sdk/react/views-new/billing/components/payment-method-card.tsx
  • web/sdk/react/views-new/billing/components/upcoming-billing-cycle.tsx
  • web/sdk/react/views-new/billing/components/upcoming-plan-change-banner.tsx
  • web/sdk/react/views-new/members/components/member-columns.tsx
  • web/sdk/react/views-new/members/members-view.module.css
  • web/sdk/react/views-new/members/members-view.tsx
  • web/sdk/react/views-new/plans/components/confirm-plan-change-dialog.tsx
  • web/sdk/react/views-new/plans/components/feature-table.tsx
  • web/sdk/react/views-new/plans/components/plan-card.module.css
  • web/sdk/react/views-new/plans/components/plan-card.tsx
  • web/sdk/react/views-new/plans/plans-view.tsx
  • web/sdk/react/views-new/preferences/preferences-view.tsx
  • web/sdk/react/views-new/projects/components/member-columns.tsx
  • web/sdk/react/views-new/projects/components/project-columns.tsx
  • web/sdk/react/views-new/projects/project-details-view.module.css
  • web/sdk/react/views-new/projects/project-details-view.tsx
  • web/sdk/react/views-new/projects/projects-view.module.css
  • web/sdk/react/views-new/projects/projects-view.tsx
  • web/sdk/react/views-new/service-accounts/components/add-service-account-dialog.tsx
  • web/sdk/react/views-new/service-accounts/components/add-token-form.tsx
  • web/sdk/react/views-new/service-accounts/components/delete-service-account-dialog.module.css
  • web/sdk/react/views-new/service-accounts/components/delete-service-account-dialog.tsx
  • web/sdk/react/views-new/service-accounts/components/manage-project-access-dialog.tsx
  • web/sdk/react/views-new/service-accounts/components/projects-cell.module.css
  • web/sdk/react/views-new/service-accounts/components/projects-cell.tsx
  • web/sdk/react/views-new/service-accounts/components/revoke-token-dialog.module.css
  • web/sdk/react/views-new/service-accounts/components/revoke-token-dialog.tsx
  • web/sdk/react/views-new/service-accounts/components/service-account-columns.module.css
  • web/sdk/react/views-new/service-accounts/components/service-account-columns.tsx
  • web/sdk/react/views-new/service-accounts/hooks/useServiceUserTokens.ts
  • web/sdk/react/views-new/service-accounts/service-account-details-view.module.css
  • web/sdk/react/views-new/service-accounts/service-account-details-view.tsx
  • web/sdk/react/views-new/service-accounts/service-accounts-view.module.css
  • web/sdk/react/views-new/service-accounts/service-accounts-view.tsx
  • web/sdk/react/views-new/teams/components/member-columns.tsx
  • web/sdk/react/views-new/teams/team-details-view.module.css
  • web/sdk/react/views-new/teams/team-details-view.tsx
  • web/sdk/react/views-new/tokens/tokens-view.tsx
  • web/sdk/shared/types.ts
  • web/sdk/tsconfig.json
💤 Files with no reviewable changes (3)
  • web/sdk/react/views-new/plans/components/confirm-plan-change-dialog.tsx
  • web/sdk/react/views-new/preferences/preferences-view.tsx
  • web/sdk/react/views-new/billing/components/billing-details-dialog.tsx

Comment on lines +5 to +7
const { orgId } = useParams<{ orgId: string }>();
const navigate = useNavigate();
return <BillingView onNavigateToPlans={() => navigate(`/${orgId}/settings/plans`)} />;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard missing orgId before navigation.

If orgId is absent, this can route to an invalid path (/undefined/settings/plans).

Suggested fix
 export default function Billing() {
   const { orgId } = useParams<{ orgId: string }>();
   const navigate = useNavigate();
-  return <BillingView onNavigateToPlans={() => navigate(`/${orgId}/settings/plans`)} />;
+  return (
+    <BillingView
+      onNavigateToPlans={() => {
+        if (!orgId) return;
+        navigate(`/${orgId}/settings/plans`);
+      }}
+    />
+  );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { orgId } = useParams<{ orgId: string }>();
const navigate = useNavigate();
return <BillingView onNavigateToPlans={() => navigate(`/${orgId}/settings/plans`)} />;
const { orgId } = useParams<{ orgId: string }>();
const navigate = useNavigate();
return (
<BillingView
onNavigateToPlans={() => {
if (!orgId) return;
navigate(`/${orgId}/settings/plans`);
}}
/>
);

Comment on lines +114 to +157
const handleBillingDetailsUpdateClick = useCallback(async () => {
const orgId = activeOrganization?.id || '';
if (!orgId) return;

try {
const query = qs.stringify(
{
details: btoa(
qs.stringify({
organization_id: orgId,
type: 'billing'
})
),
checkout_id: '{{.CheckoutID}}'
},
{ encode: false }
);
const cancel_url = `${config?.billing?.cancelUrl}?${query}`;
const success_url = `${config?.billing?.successUrl}?${query}`;

const resp = await createCheckoutMutation(
create(CreateCheckoutRequestSchema, {
orgId,
cancelUrl: cancel_url,
successUrl: success_url,
setupBody: {
paymentMethod: false,
customerPortal: true
}
})
);
const checkoutUrl = resp?.checkoutSession?.checkoutUrl;
if (checkoutUrl) {
window.location.href = checkoutUrl;
}
} catch (err) {
console.error(err);
}
}, [
activeOrganization?.id,
createCheckoutMutation,
config?.billing?.cancelUrl,
config?.billing?.successUrl
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard the checkout flow when billing redirect URLs are missing.

Lines 131-138 build cancelUrl and successUrl even when the billing config is absent. That turns into undefined?... URLs and sends a broken checkout request at runtime. Bail out early, or disable the action, until both URLs are configured.

Proposed fix
   const handleBillingDetailsUpdateClick = useCallback(async () => {
     const orgId = activeOrganization?.id || '';
-    if (!orgId) return;
+    const cancelUrl = config?.billing?.cancelUrl;
+    const successUrl = config?.billing?.successUrl;
+    if (!orgId || !cancelUrl || !successUrl) {
+      toastManager.add({
+        title: 'Billing is not configured',
+        description: 'Missing billing redirect URLs.',
+        type: 'error'
+      });
+      return;
+    }

     try {
       const query = qs.stringify(
         {
@@
         },
         { encode: false }
       );
-      const cancel_url = `${config?.billing?.cancelUrl}?${query}`;
-      const success_url = `${config?.billing?.successUrl}?${query}`;
+      const cancel_url = `${cancelUrl}?${query}`;
+      const success_url = `${successUrl}?${query}`;

const btnText =
billingAccount?.email || billingAccount?.name ? 'Update' : 'Add details';
const isButtonDisabled = isLoading || disabled;
const isButtonDisabled = isLoading || disabled || isActionLoading;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Separate “action in progress” from “restricted” disable state.

isActionLoading is currently treated the same as permission/support-restricted disable state, which can show the “Contact support…” tooltip while the request is simply in progress.

Suggested fix
-  const isButtonDisabled = isLoading || disabled || isActionLoading;
+  const isRestricted = isLoading || disabled;
+  const isButtonDisabled = isRestricted || isActionLoading;
...
-            <Tooltip.Trigger
-              disabled={!isButtonDisabled}
+            <Tooltip.Trigger
+              disabled={!isRestricted}
               render={<span />}
             >
...
-            {isButtonDisabled && (
+            {isRestricted && (
               <Tooltip.Content>
                 Contact support to update your billing address.
               </Tooltip.Content>
             )}

Also applies to: 49-50

Comment on lines +103 to +120
const selectedIntervals = useMemo<Record<string, IntervalKeys>>(() => {
const result: Record<string, IntervalKeys> = {};
groupedPlans.forEach(plan => {
if (selectedIntervals[plan.slug]) return;
const planIntervals = Object.values(plan.intervals)
if (intervalOverrides[plan.slug]) {
result[plan.slug] = intervalOverrides[plan.slug];
return;
}
const sortedIntervals = Object.values(plan.intervals)
.sort((a, b) => a.weightage - b.weightage)
.map(i => i.interval);
const activePlanInterval = Object.values(plan.intervals).find(
p => p.planId === activeSubscription?.planId
);
defaults[plan.slug] =
activePlanInterval?.interval || planIntervals[0] || 'year';
result[plan.slug] =
activePlanInterval?.interval || sortedIntervals[0] || 'year';
});

if (Object.keys(defaults).length > 0) {
setSelectedIntervals(prev => ({ ...prev, ...defaults }));
}
}, [groupedPlans, activeSubscription?.planId]);
return result;
}, [groupedPlans, activeSubscription?.planId, intervalOverrides]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate saved interval overrides before reusing them.

Line 106 re-applies any cached override blindly. After an org switch or a plans refresh, that override can point to an interval the current plan.intervals map no longer has, which leaves selectedIntervals[plan.slug] invalid and can desync the card/table state. Fall back to the derived default when the override is no longer available.

Proposed fix
   const selectedIntervals = useMemo<Record<string, IntervalKeys>>(() => {
     const result: Record<string, IntervalKeys> = {};
     groupedPlans.forEach(plan => {
-      if (intervalOverrides[plan.slug]) {
-        result[plan.slug] = intervalOverrides[plan.slug];
+      const override = intervalOverrides[plan.slug];
+      if (override && plan.intervals[override]) {
+        result[plan.slug] = override;
         return;
       }
       const sortedIntervals = Object.values(plan.intervals)
         .sort((a, b) => a.weightage - b.weightage)
         .map(i => i.interval);

Comment on lines +36 to +38
if (isLoading) {
return <Skeleton height="16px" width="200px" />;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Match loading placeholder width with final text width.

At Line 37, the skeleton is 200px, while loaded text is constrained to 400px (styles.text). This can still cause load→loaded visual jitter in the column.

Suggested patch
-  if (isLoading) {
-    return <Skeleton height="16px" width="200px" />;
-  }
+  if (isLoading) {
+    return <Skeleton height="16px" width="400px" />;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isLoading) {
return <Skeleton height="16px" width="200px" />;
}
if (isLoading) {
return <Skeleton height="16px" width="400px" />;
}

Comment on lines +1 to +7
.actionsCell {
visibility: hidden;
}

tr:hover .actionsCell {
visibility: visible;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hover-only action reveal makes row actions inaccessible for keyboard/touch users.

With visibility: hidden by default and reveal only on tr:hover, keyboard users cannot reliably discover/activate the action button, and touch devices may never show it. This is an accessibility blocker.

Suggested fix
 .actionsCell {
   visibility: hidden;
 }

-tr:hover .actionsCell {
+tr:hover .actionsCell,
+tr:focus-within .actionsCell,
+.actionsCell:focus-within {
   visibility: visible;
 }
+
+@media (hover: none) {
+  .actionsCell {
+    visibility: visible;
+  }
+}

@rohanchkrabrty rohanchkrabrty changed the title fix: cross-cutting SDK fixes for billing, plans, and tables fix: cross-cutting SDK fixes Apr 28, 2026
@rohanchkrabrty rohanchkrabrty changed the base branch from main to fix-billing-pages April 28, 2026 10:31
Base automatically changed from fix-billing-pages to main April 28, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants