Skip to content

chore: UX Fixes#26643

Merged
pumfleet merged 38 commits intomainfrom
ux
Jan 13, 2026
Merged

chore: UX Fixes#26643
pumfleet merged 38 commits intomainfrom
ux

Conversation

@pumfleet
Copy link
Contributor

@pumfleet pumfleet commented Jan 9, 2026

This is a PR full of minor UI/UX fixes identified as part of the UX audit.


Summary by cubic

A sweep of UI/UX polish across Event Types, Workflows, Profiles, Embed, and Tables to make common actions clearer and faster. Highlights include an inline search with actions, a smarter Create button, improved uploads, and consistent copy.

  • UI Improvements

    • Event Types: moved search inline with the Create button; clearer "(hidden)" badge; removed "no more results" message.
    • Create: added a dropdown when multiple creation options exist.
    • Workflows: tighter step spacing, minimal delete button, SMS hint shown only on SMS steps, title layout tweak.
    • Profiles: scroll-to-top on load; improved logo/banner upload UX; button alignment fixes.
  • Bug Fixes

    • Fixed delete dialog behavior.
    • Updated saved filters behavior in tables.
    • Routing forms: corrected identifier field and standardized option labels to sentence case.
    • Members list now shows names; spacing adjustments.
    • TextField and form input styling fixes for addons and full-width inputs.

Written for commit 34de07d. Summary will update on new commits.


Updates since last revision

Addressed Cubic AI review feedback (confidence 9+ issues):

  • TextField.tsx: Replaced hardcoded text-gray-500 with semantic text-muted color token for hint text styling to maintain design system consistency and theming support
  • event-types.e2e.ts: Replaced text locator text="Organizer phone number" with resilient data-testid="location-select-item-organizer_phone_number" selector per E2E best practices
  • manage-booking-questions.e2e.ts: Replaced text locator text="Long text" with resilient page.getByTestId("select-option-textarea") selector per E2E best practices

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - no documentation changes required.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. TextField hint styling: Navigate to any form with hint text and verify the hint appears with proper muted color in both light and dark themes
  2. E2E tests: Run yarn e2e apps/web/playwright/event-types.e2e.ts and yarn e2e apps/web/playwright/manage-booking-questions.e2e.ts to verify the tests pass with the new data-testid selectors

Human Review Checklist

  • Verify TextField hint text color (text-muted) renders correctly in both light and dark modes
  • Confirm location-select-item-organizer_phone_number data-testid exists in LocationSelect component
  • Confirm select-option-textarea data-testid exists in SelectField component (see packages/ui/components/form/select/components.tsx:56)
  • Verify E2E tests pass in CI

Link to Devin run: https://app.devin.ai/sessions/f52bbc36d7ba4e99bbaec5b295428264

@pumfleet pumfleet requested review from a team as code owners January 9, 2026 20:40
Copy link
Contributor

@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.

6 issues found across 24 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/ui/components/form/inputs/TextField.tsx">

<violation number="1" location="packages/ui/components/form/inputs/TextField.tsx:261">
P2: Hardcoded `text-gray-500` breaks the design system pattern. The codebase uses semantic color tokens (`text-default`, `text-muted`, `text-subtle`). Use `text-muted` for hint text to maintain theming consistency.</violation>

<violation number="2" location="packages/ui/components/form/inputs/TextField.tsx:262">
P2: Hardcoded `text-gray-500` breaks the design system pattern. Use a semantic color token like `text-muted` to match the parent div and maintain theming consistency.</violation>
</file>

<file name="apps/web/modules/embed/components/Embed.tsx">

<violation number="1" location="apps/web/modules/embed/components/Embed.tsx:1287">
P2: Hardcoded text "Embed theme" should be localized using `t()` function for consistency with other labels in this component (e.g., `t("layout")`, `t("duration")`). Consider adding a translation key like `"embed_theme"` and using `{t("embed_theme")}`.</violation>
</file>

<file name="apps/web/modules/ee/organizations/profile.tsx">

<violation number="1" location="apps/web/modules/ee/organizations/profile.tsx:386">
P2: Using `document.querySelector` with programmatic click on a hidden element is fragile and non-idiomatic in React. Consider using a ref or lifting the dialog state up to control visibility directly. If the BannerUploader exposes a way to control its dialog state, use that instead of DOM manipulation. The current approach creates tight coupling to the `data-testid` attribute and silently fails if the element isn't found.</violation>
</file>

<file name="apps/web/modules/event-types/views/event-types-listing-view.tsx">

<violation number="1" location="apps/web/modules/event-types/views/event-types-listing-view.tsx:221">
P2: Hardcoded "(hidden)" text violates localization requirements. Use `t("hidden")` instead of the literal string to ensure proper internationalization.</violation>
</file>

<file name="apps/web/modules/ee/teams/components/createButton/CreateButton.tsx">

<violation number="1" location="apps/web/modules/ee/teams/components/createButton/CreateButton.tsx:99">
P2: The chevron-down icon is misleading here. This button branch (when `!hasTeams && !platform`) doesn't provide dropdown functionality - it only uses `options[0]`. The `EndIcon` suggests users can select from multiple options, but clicking won't show a dropdown. Consider removing this `EndIcon` from the non-dropdown button, or restructuring to show a dropdown when `hasMultipleOptions` is true regardless of team/platform status.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

{embedParams.embedTabName !== EmbedTabName.ATOM_REACT && (
<Label className="mb-6">
<div className="mb-2">EmbedTheme</div>
<div className="mb-2">Embed theme</div>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 9, 2026

Choose a reason for hiding this comment

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

P2: Hardcoded text "Embed theme" should be localized using t() function for consistency with other labels in this component (e.g., t("layout"), t("duration")). Consider adding a translation key like "embed_theme" and using {t("embed_theme")}.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/modules/embed/components/Embed.tsx, line 1287:

<comment>Hardcoded text "Embed theme" should be localized using `t()` function for consistency with other labels in this component (e.g., `t("layout")`, `t("duration")`). Consider adding a translation key like `"embed_theme"` and using `{t("embed_theme")}`.</comment>

<file context>
@@ -1126,13 +1275,16 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
                       {embedParams.embedTabName !== EmbedTabName.ATOM_REACT && (
                         <Label className="mb-6">
-                          <div className="mb-2">EmbedTheme</div>
+                          <div className="mb-2">Embed theme</div>
                           <Select
                             className="w-full"
</file context>
Fix with Cubic

StartIcon="upload"
onClick={() => {
// Trigger the BannerUploader dialog
const triggerButton = document.querySelector(
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 9, 2026

Choose a reason for hiding this comment

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

P2: Using document.querySelector with programmatic click on a hidden element is fragile and non-idiomatic in React. Consider using a ref or lifting the dialog state up to control visibility directly. If the BannerUploader exposes a way to control its dialog state, use that instead of DOM manipulation. The current approach creates tight coupling to the data-testid attribute and silently fails if the element isn't found.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/modules/ee/organizations/profile.tsx, line 386:

<comment>Using `document.querySelector` with programmatic click on a hidden element is fragile and non-idiomatic in React. Consider using a ref or lifting the dialog state up to control visibility directly. If the BannerUploader exposes a way to control its dialog state, use that instead of DOM manipulation. The current approach creates tight coupling to the `data-testid` attribute and silently fails if the element isn't found.</comment>

<file context>
@@ -239,119 +257,171 @@ const OrgProfileForm = ({ defaultValues }: { defaultValues: FormValues }) => {
+                            StartIcon="upload"
+                            onClick={() => {
+                              // Trigger the BannerUploader dialog
+                              const triggerButton = document.querySelector(
+                                '[data-testid="open-upload-banner-dialog"]'
+                              ) as HTMLButtonElement;
</file context>
Fix with Cubic

}
data-testid="create-button"
StartIcon="plus"
EndIcon={hasMultipleOptions ? "chevron-down" : undefined}
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 9, 2026

Choose a reason for hiding this comment

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

P2: The chevron-down icon is misleading here. This button branch (when !hasTeams && !platform) doesn't provide dropdown functionality - it only uses options[0]. The EndIcon suggests users can select from multiple options, but clicking won't show a dropdown. Consider removing this EndIcon from the non-dropdown button, or restructuring to show a dropdown when hasMultipleOptions is true regardless of team/platform status.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/modules/ee/teams/components/createButton/CreateButton.tsx, line 99:

<comment>The chevron-down icon is misleading here. This button branch (when `!hasTeams && !platform`) doesn't provide dropdown functionality - it only uses `options[0]`. The `EndIcon` suggests users can select from multiple options, but clicking won't show a dropdown. Consider removing this `EndIcon` from the non-dropdown button, or restructuring to show a dropdown when `hasMultipleOptions` is true regardless of team/platform status.</comment>

<file context>
@@ -92,10 +96,15 @@ export function CreateButton(props: CreateBtnProps) {
           }
           data-testid="create-button"
           StartIcon="plus"
+          EndIcon={hasMultipleOptions ? "chevron-down" : undefined}
           loading={isPending}
           variant={disableMobileButton ? "button" : "fab"}
</file context>
Fix with Cubic

@vercel
Copy link

vercel bot commented Jan 9, 2026

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

4 Skipped Deployments
Project Deployment Review Updated (UTC)
api-v2 Ignored Ignored Preview Jan 13, 2026 7:44am
cal Ignored Ignored Jan 13, 2026 7:44am
cal-companion Ignored Ignored Preview Jan 13, 2026 7:44am
cal-eu Ignored Ignored Jan 13, 2026 7:44am

@pumfleet
Copy link
Contributor Author

pumfleet commented Jan 9, 2026

oh I think I messed that first one up when I fixed the merge conflict. will try and fix

@pumfleet
Copy link
Contributor Author

pumfleet commented Jan 9, 2026

I think I fixed it @pedroccastro - can you confirm? I couldn't see the error again locally when testing after making the fix

@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

E2E results are ready!

Copy link
Contributor

@pedroccastro pedroccastro left a comment

Choose a reason for hiding this comment

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

Hey @pumfleet! Type checks and unit tests now passing!

Great work on the UX improvements, the search being inline will probably make it easier for users. The sentence case standardization makes it feel more polished.

Found a few things during local testing that might need a quick look:

1. TextField missing borders (without addons)

Inputs without addons (like the Title field in Add new event type dialog) are missing their borders. The URL field with the addon looks fine.

Likely cause: In TextField.tsx, the Input component (without addon) now receives border-0 bg-transparent in className, which overrides the border from inputStyles. This was probably copied from the input inside the addon wrapper (where border-0 is correct since the wrapper provides the border).

title_event title_add_event

2. Hidden badge styling

The hidden indicator changed from a Badge component to plain text (hidden). A couple of things:

  • Lost the {t("hidden")} localization (now hardcoded English)
  • Uses text-gray-400 instead of design tokens
hidden_badge hidden_dark

3. Mobile FAB showing two "+" icons

On mobile, when there are multiple team options, the FAB button shows two "+" icons instead of one.

Likely cause: The PR added EndIcon="chevron-down" to CreateButton. The core Button component has a quirk where both StartIcon and EndIcon render as "+" on mobile FAB variant.

double_plus

Let me know if you'd like more details on any of these!

export const FieldTypes = [
{
label: "Short Text",
label: "Short text",
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we use i18n for labels instead of harcoded strings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally we should - but I wanted to keep this PR simple

const _cookies = await cookies();

const session = await getServerSession({ req: buildLegacyRequest(_headers, _cookies) });
const session = await getServerSession({
Copy link
Contributor

Choose a reason for hiding this comment

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

We would have to update the skeleton loader on this page as we moved the search input to the top

Screen.Recording.2026-01-10.at.6.24.10.PM.mov

@keithwillcode keithwillcode added the core area: core, team members only label Jan 10, 2026
@pumfleet
Copy link
Contributor Author

Screenshot 2026-01-12 at 4 31 44 PM Screenshot 2026-01-12 at 4 31 58 PM

FAB fixed

Hidden translation string fixed

Text fields fixed

@pedroccastro
Copy link
Contributor

Hey @pumfleet! Thanks for addressing the previous feedback, the TextField borders and FAB icon issues are now fixed! 🎉

Did another round of local testing and the UX improvements are looking good!
Found one small thing that might need a quick look:

Create button size inconsistency

The size="sm" was removed from the button for users without teams (line 92), but kept for users with teams/dropdown (line 120). This makes the button appear slightly larger for solo users compared to team members.

smaller_button_1 larger_button_2

Also noticed there are 2 minor merge conflicts to resolve:

  • apps/web/public/static/locales/en/common.json
  • packages/ui/components/dialog/ConfirmationDialogContent.tsx

Both look straightforward (copy text difference and a mt-1 vs mt-2 margin).

Let me know if you'd like more details!

pumfleet and others added 5 commits January 12, 2026 19:35
Copy link
Contributor

@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 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/playwright/event-types.e2e.ts">

<violation number="1" location="apps/web/playwright/event-types.e2e.ts:226">
P1: Rule violated: **E2E Tests Best Practices**

Replace the new text locators that click the “Organizer phone number” option with resilient selectors (e.g., data-testid or role-based queries) to comply with the E2E Tests Best Practices rule.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@github-actions
Copy link
Contributor

Devin AI is addressing Cubic AI's review feedback

A Devin session has been created to address the issues identified by Cubic AI.

View Devin Session

devin-ai-integration bot and others added 2 commits January 13, 2026 03:32
- Replace hardcoded text-gray-500 with text-muted in TextField.tsx hint section
- Replace text locator with data-testid in E2E test for location select

Co-Authored-By: unknown <>
- Use data-testid selectors for location options (more reliable than text)
- Update field identifiers in routing-forms tests to match new labels
- Fix Long text selector in manage-booking-questions test
Copy link
Contributor

@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 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/playwright/manage-booking-questions.e2e.ts">

<violation number="1" location="apps/web/playwright/manage-booking-questions.e2e.ts:762">
P2: Rule violated: **E2E Tests Best Practices**

Replace the `text="Long text"` locator with a resilient selector (e.g., add/use a dedicated `data-testid` and query it via `getByTestId`) to comply with the E2E selector guideline and avoid brittle text matching.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@github-actions
Copy link
Contributor

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session

devin-ai-integration bot and others added 2 commits January 13, 2026 04:17
…s E2E test

Replace fragile text="Long text" locator with resilient
page.getByTestId("select-option-textarea") selector per E2E best practices.

Addresses Cubic AI review feedback (confidence 9/10).

Co-Authored-By: unknown <>
Copy link
Contributor

@pedroccastro pedroccastro left a comment

Choose a reason for hiding this comment

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

Nice! 🚀

@pumfleet pumfleet merged commit 7c66f33 into main Jan 13, 2026
48 of 49 checks passed
@pumfleet pumfleet deleted the ux branch January 13, 2026 05:56
@vercel vercel bot temporarily deployed to Preview – dev January 13, 2026 07:43 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only ready-for-e2e size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants