Skip to content

Consistency and design changes light mode#1500

Open
Developing-Gamer wants to merge 68 commits into
devfrom
Consistency-and-design-changes-light-mode
Open

Consistency and design changes light mode#1500
Developing-Gamer wants to merge 68 commits into
devfrom
Consistency-and-design-changes-light-mode

Conversation

@Developing-Gamer
Copy link
Copy Markdown
Collaborator

@Developing-Gamer Developing-Gamer commented May 27, 2026

PR #1500 Visual Writeup

Visual assets hosted in this gist.

  • Base: dev
  • Head: Consistency-and-design-changes-light-mode
  • Dashboard dev server: http://localhost:8101
  • Viewport: 1920x1200
  • Screenshots: 74 referenced (18 surfaces x 2 themes x before/after, plus the attached Conversations create-dialog pair)
  • Red outlines appear only on after screenshots to mark the changed surface.

Summary

This PR refreshes light-mode consistency across dashboard surfaces and adds a dashboard-only Account Settings implementation. The screenshots below compare the base branch against the PR branch for every changed dashboard route/surface included in the scope.

Screenshot Matrix

Account Settings - Profile

Dashboard-only profile page redesign against the previous Stack handler page.

Theme Before After
Light account-profile-before-light.png account-profile-after-light.png
Dark account-profile-before-dark.png account-profile-after-dark.png

Account Settings - Emails & Auth

Email, password, passkey, OTP, and MFA settings shell.

Theme Before After
Light account-emails-auth-before-light.png account-emails-auth-after-light.png
Dark account-emails-auth-before-dark.png account-emails-auth-after-dark.png

Account Settings - Notifications

Notification preferences styling.

Theme Before After
Light account-notifications-before-light.png account-notifications-after-light.png
Dark account-notifications-before-dark.png account-notifications-after-dark.png

Account Settings - Active Sessions

Active session table and action styling.

Theme Before After
Light account-sessions-before-light.png account-sessions-after-light.png
Dark account-sessions-before-dark.png account-sessions-after-dark.png

Account Settings - Payments

Billing surface and account/team billing selector.

Theme Before After
Light account-payments-before-light.png account-payments-after-light.png
Dark account-payments-before-dark.png account-payments-after-dark.png

Account Settings - Settings

Sign out and account deletion settings.

Theme Before After
Light account-settings-before-light.png account-settings-after-light.png
Dark account-settings-before-dark.png account-settings-after-dark.png

Account Settings - Team

Team profile, members, and leave-team sections.

Theme Before After
Light account-team-before-light.png account-team-after-light.png
Dark account-team-before-dark.png account-team-after-dark.png

Account Settings - Create Team

Team creation form.

Theme Before After
Light account-team-create-before-light.png account-team-create-after-light.png
Dark account-team-create-before-dark.png account-team-create-after-dark.png

Analytics Queries

Touched analytics query page surface.

Theme Before After
Light analytics-queries-before-light.png analytics-queries-after-light.png
Dark analytics-queries-before-dark.png analytics-queries-after-dark.png

Analytics Tables

Analytics table/query controls and data-grid surface.

Theme Before After
Light analytics-tables-before-light.png analytics-tables-after-light.png
Dark analytics-tables-before-dark.png analytics-tables-after-dark.png

Auth Methods

Authentication method configuration surface.

Theme Before After
Light auth-methods-before-light.png auth-methods-after-light.png
Dark auth-methods-before-dark.png auth-methods-after-dark.png

Conversations

Support conversation UI surface.

Theme Before After
Light conversations-before-light.png conversations-after-light.png
Dark conversations-before-dark.png conversations-after-dark.png

Conversations - Create Dialog

Attached screenshots for the create conversation dialog.

Theme Before After
Light conversations-dialog-before-light.png conversations-dialog-after-light.png

Domains

Trusted domains alert/card styling.

Theme Before After
Light domains-before-light.png domains-after-light.png
Dark domains-before-dark.png domains-after-dark.png

Email Sent

Sent email and reputation card styling.

Theme Before After
Light email-sent-before-light.png email-sent-after-light.png
Dark email-sent-before-dark.png email-sent-after-dark.png

Launch Checklist

Launch checklist page surface.

Theme Before After
Light launch-checklist-before-light.png launch-checklist-after-light.png
Dark launch-checklist-before-dark.png launch-checklist-after-dark.png

Payment Products

Products/items payment page surface.

Theme Before After
Light payments-products-before-light.png payments-products-after-light.png
Dark payments-products-before-dark.png payments-products-after-dark.png

Session Replays

Session replay page layout.

Theme Before After
Light session-replays-before-light.png session-replays-after-light.png
Dark session-replays-before-dark.png session-replays-after-dark.png

Sign-up Rules

Sign-up rules page surface.

Theme Before After
Light sign-up-rules-before-light.png sign-up-rules-after-light.png
Dark sign-up-rules-before-dark.png sign-up-rules-after-dark.png

Summary by CodeRabbit

Release Notes

  • New Features

    • Added comprehensive account settings dashboard with profile management, email and authentication settings, active sessions monitoring, API key generation and management, payment methods, notification preferences, and team creation/management.
    • Introduced user profile image editing with circular cropping and compression.
    • Added multi-factor authentication (MFA) setup via TOTP QR codes.
    • Enabled team-based API key management and team member invitations.
  • Design Improvements

    • Refined UI styling across analytics, forms, and dialogs for better visual hierarchy.
    • Enhanced dark mode support throughout dashboard components.
    • Improved responsive layouts and spacing on dashboard pages.

Developing-Gamer and others added 30 commits May 27, 2026 12:31
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
Contributor

@N2D4 N2D4 left a comment

Choose a reason for hiding this comment

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

please fix the screenshots to include all the changes you have (and update the skill you used to prevent it from happening again)

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: 1

Caution

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

⚠️ Outside diff range comments (2)
apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx (2)

416-428: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing error handling for cancel subscription.

The okButton.onClick handler for cancellation doesn't catch errors from stackApp.cancelSubscription. Unlike the switch plan handler (lines 449-458) which uses Result.fromThrowingAsync and returns "prevent-close" on failure, this handler will silently fail and close the dialog if the API call throws.

Suggested fix using the same pattern as switch handler
             okButton={{
               label: "Cancel subscription",
               onClick: async () => {
                 if (!cancelTarget) return;
                 const { productId, subscriptionId } = cancelTarget;
-                if (props.customerType === "team") {
-                  await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });
-                } else {
-                  await stackApp.cancelSubscription({ productId, subscriptionId });
+                const result = await Result.fromThrowingAsync(async () => {
+                  if (props.customerType === "team") {
+                    await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });
+                  } else {
+                    await stackApp.cancelSubscription({ productId, subscriptionId });
+                  }
+                });
+                if (result.status === "error") {
+                  handleAsyncError(result.error);
+                  return "prevent-close";
                 }
                 setCancelTarget(null);
               },
             }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`
around lines 416 - 428, The cancel dialog's okButton.onClick handler lacks error
handling and will close the dialog on exceptions; wrap the cancel call to
stackApp.cancelSubscription in the same Result.fromThrowingAsync pattern used in
the switch-plan handler, e.g., call Result.fromThrowingAsync(() =>
stackApp.cancelSubscription(...)) with the same branching for props.customerType
(use teamId when props.customerType === "team"), check the Result for isErr and
return "prevent-close" on failure, and only call setCancelTarget(null) when the
Result is ok to avoid silently closing on errors.

122-122: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Dark mode detection may not reflect actual theme state.

Checking document.documentElement.style["color-scheme"] only inspects inline styles. If dark mode is applied via CSS classes (Tailwind's dark: convention), this won't detect it. Consider using a theme context/hook or checking window.matchMedia('(prefers-color-scheme: dark)').

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`
at line 122, The current darkMode detection using the inline style check (const
darkMode = "color-scheme" in document.documentElement.style &&
document.documentElement.style["color-scheme"] === "dark") will miss class-based
themes; replace it in payments-panel.tsx by reading a reliable source such as a
theme hook/context (e.g., useTheme or similar) or, if no context exists, use a
combination of window.matchMedia('(prefers-color-scheme: dark)') and
document.documentElement.classList.contains('dark') to determine dark mode, and
update the variable/usage of darkMode accordingly (keep the identifier darkMode
so callers like the PaymentsPanel component continue to work).
🧹 Nitpick comments (3)
apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx (3)

387-387: 💤 Low value

Prefer explicit error over non-null assertion.

product.id! uses a non-null assertion. While the preceding canSwitchPlans check ensures product.id is truthy, the guidelines prefer defensive patterns.

Suggested fix
-                        onClick={() => openSwitchDialog(product.id!, product.switchOptions?.[0]?.productId ?? null)}
+                        onClick={() => {
+                          if (product.id == null) throw new Error("product.id should be defined when canSwitchPlans is true");
+                          openSwitchDialog(product.id, product.switchOptions?.[0]?.productId ?? null);
+                        }}

As per coding guidelines: "Code defensively by preferring ?? throwErr(...) over non-null assertions with explicit error messages explaining the assumption."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`
at line 387, The onClick handler uses a non-null assertion product.id! when
calling openSwitchDialog; replace the assertion with a defensive null-coalescing
check so a clear error is thrown if product.id is unexpectedly null/undefined
(e.g., use product.id ?? throwErr('Expected product.id to be defined in onClick
for openSwitchDialog') or throw new Error(...) and pass that value into
openSwitchDialog), keep the same fallback logic for
product.switchOptions?.[0]?.productId, and ensure this change is applied where
openSwitchDialog is invoked (reference: openSwitchDialog, canSwitchPlans,
product.switchOptions).

481-485: 💤 Low value

Multiple uses of any type.

Lines 481 and 517 use explicit any type annotations (option: any, invoices as any[], invoice: any). These should use the defined types or have proper type definitions added.

Suggested fix
-                      {switchOptions.map((option: any) => (
+                      {switchOptions.map((option) => (
-                {(invoices as any[]).map((invoice: any, index: number) => {
+                {invoices.map((invoice, index) => {

As per coding guidelines: "Avoid using the any type."

Also applies to: 517-517

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`
around lines 481 - 485, Replace the use of `any` by defining and using concrete
types: create a SwitchOption type (e.g., with productId and displayName) and
change the map callback to `switchOptions.map((option: SwitchOption) => ...)`
for the SelectItem rendering, and replace `invoices as any[]` and `invoice: any`
with a proper Invoice interface (e.g., Invoice { id, amount, date, ... }) and
use `invoices: Invoice[]` and `invoice: Invoice` wherever they are referenced;
update any imports/props/signatures that provide these values (e.g., the prop or
state that holds `switchOptions` and `invoices`) so the compiler infers the
correct types throughout.

34-34: ⚡ Quick win

Avoid any type for invoice list.

CustomerInvoicesList = any[] bypasses type safety. Define a proper invoice type based on expected properties used in the component (e.g., createdAt, status, amountTotal, hostedInvoiceUrl).

Suggested type definition
-type CustomerInvoicesList = any[];
+type CustomerInvoice = {
+  createdAt: Date | string;
+  status: CustomerInvoiceStatus;
+  amountTotal: number | null;
+  hostedInvoiceUrl: string | null;
+};
+type CustomerInvoicesList = CustomerInvoice[];

As per coding guidelines: "Avoid using the any type; when necessary, leave a comment explaining why and why the type system fails in that case."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`
at line 34, Replace the broad alias CustomerInvoicesList = any[] with a concrete
invoice interface (e.g., interface CustomerInvoice { id?: string; createdAt:
string | number | Date; status: string; amountTotal: number; hostedInvoiceUrl?:
string; /* add other used fields */ }) and then type CustomerInvoicesList =
CustomerInvoice[]; update usages in payments-panel.tsx (components/functions
referencing CustomerInvoicesList) to use the new interface and adjust
nullable/optional types where the component expects them; if any fields truly
cannot be typed, add an inline comment explaining why and limit use of any to
that specific field only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`:
- Around line 304-355: Render the "Payment method" Section regardless of
defaultPaymentMethod instead of gating it; inside the Section, show the existing
card UI when defaultPaymentMethod is truthy (use
formatPaymentMethod(defaultPaymentMethod)) and otherwise show a placeholder text
like "No payment method on file" and an "Add card" button (instead of "Update")
that calls openPaymentDialog; keep the existing ActionDialog/payment form flow
(paymentDialogOpen, openPaymentDialog, closePaymentDialog,
setupIntentClientSecret, setupIntentStripeAccountId, stripePromise, Elements,
SetDefaultPaymentMethodForm and
props.customer.setDefaultPaymentMethodFromSetupIntent) so users can add a new
card when no default exists, or optionally gate the content based on
billing.hasCustomer if that condition is required.

---

Outside diff comments:
In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`:
- Around line 416-428: The cancel dialog's okButton.onClick handler lacks error
handling and will close the dialog on exceptions; wrap the cancel call to
stackApp.cancelSubscription in the same Result.fromThrowingAsync pattern used in
the switch-plan handler, e.g., call Result.fromThrowingAsync(() =>
stackApp.cancelSubscription(...)) with the same branching for props.customerType
(use teamId when props.customerType === "team"), check the Result for isErr and
return "prevent-close" on failure, and only call setCancelTarget(null) when the
Result is ok to avoid silently closing on errors.
- Line 122: The current darkMode detection using the inline style check (const
darkMode = "color-scheme" in document.documentElement.style &&
document.documentElement.style["color-scheme"] === "dark") will miss class-based
themes; replace it in payments-panel.tsx by reading a reliable source such as a
theme hook/context (e.g., useTheme or similar) or, if no context exists, use a
combination of window.matchMedia('(prefers-color-scheme: dark)') and
document.documentElement.classList.contains('dark') to determine dark mode, and
update the variable/usage of darkMode accordingly (keep the identifier darkMode
so callers like the PaymentsPanel component continue to work).

---

Nitpick comments:
In
`@apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx`:
- Line 387: The onClick handler uses a non-null assertion product.id! when
calling openSwitchDialog; replace the assertion with a defensive null-coalescing
check so a clear error is thrown if product.id is unexpectedly null/undefined
(e.g., use product.id ?? throwErr('Expected product.id to be defined in onClick
for openSwitchDialog') or throw new Error(...) and pass that value into
openSwitchDialog), keep the same fallback logic for
product.switchOptions?.[0]?.productId, and ensure this change is applied where
openSwitchDialog is invoked (reference: openSwitchDialog, canSwitchPlans,
product.switchOptions).
- Around line 481-485: Replace the use of `any` by defining and using concrete
types: create a SwitchOption type (e.g., with productId and displayName) and
change the map callback to `switchOptions.map((option: SwitchOption) => ...)`
for the SelectItem rendering, and replace `invoices as any[]` and `invoice: any`
with a proper Invoice interface (e.g., Invoice { id, amount, date, ... }) and
use `invoices: Invoice[]` and `invoice: Invoice` wherever they are referenced;
update any imports/props/signatures that provide these values (e.g., the prop or
state that holds `switchOptions` and `invoices`) so the compiler infers the
correct types throughout.
- Line 34: Replace the broad alias CustomerInvoicesList = any[] with a concrete
invoice interface (e.g., interface CustomerInvoice { id?: string; createdAt:
string | number | Date; status: string; amountTotal: number; hostedInvoiceUrl?:
string; /* add other used fields */ }) and then type CustomerInvoicesList =
CustomerInvoice[]; update usages in payments-panel.tsx (components/functions
referencing CustomerInvoicesList) to use the new interface and adjust
nullable/optional types where the component expects them; if any fields truly
cannot be typed, add an inline comment explaining why and limit use of any to
that specific field only.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 65812383-c783-45e5-88d5-d82b4f1341c0

📥 Commits

Reviewing files that changed from the base of the PR and between ae410d5 and c3b2810.

📒 Files selected for processing (2)
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/conversations/page-client.tsx
  • apps/dashboard/src/components/dashboard-account-settings/payments/payments-panel.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/conversations/page-client.tsx

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

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.

3 participants