Skip to content

fix(mobile): enable habit submit button once a title is typed - #145

Merged
thomasluizon merged 1 commit into
mainfrom
fix/mobile-habit-submit-title-validation
Jun 6, 2026
Merged

fix(mobile): enable habit submit button once a title is typed#145
thomasluizon merged 1 commit into
mainfrom
fix/mobile-habit-submit-title-validation

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

Problem

After #144, the mobile Create Habit / Save Changes button stayed disabled even with the title filled in.

Root cause

The buttons gated on react-hook-form's formState.isValid, but the title is a buffered input (BufferedSheetInput) that keeps keystrokes in local state and only commits to the form on blur/submit. Confirmed against the installed RHF 7.77 source: in the default onSubmit mode, setValue(...) without shouldValidate re-broadcasts the cached isValid rather than recomputing it — so isValid never flipped and the button stayed disabled.

Web is unaffected: its inputs write to the form on every keystroke, and the registered-field onChange path recomputes isValid, so the same gate already works there.

Fix (mobile-only)

Observe the live title through BufferedSheetInput's existing (previously unused) onDraftChange hook and gate the button on a lightweight title-present boolean:

  • title-section.tsx / habit-form-fields.tsx — forward the title draft up as onTitlePresenceChange(hasTitle).
  • create-habit-modal.tsx / edit-habit-modal.tsx — gate submitDisabled on that boolean; seed it (false for create, from the prefilled title for edit).

A boolean (not the raw string) keeps modal re-renders to the empty↔filled flip only, preserving the buffer's purpose (lag-free typing on Android). The title is intentionally not routed through live validation (shouldValidate), which would run the resolver per keystroke and surface a "title required" field error web doesn't show.

Also fixes a latent edit-modal bug: clearing an existing title now disables Save (previously it stayed enabled).

This is behavioral parity with web (button disabled while title empty / saving); the differing mechanism is the buffered-input platform adapter, which web doesn't have.

Tests

  • habit-form-fields.test.tsx — typing/clearing the title emits onTitlePresenceChange(true|false) (incl. whitespace-trim).
  • create-habit-modal.test.tsx — submit button disabled with empty title, enabled once a title is present.
  • Full mobile suite: 391 passed. Typecheck + lint clean.

🤖 Generated with Claude Code

The Create Habit / Save Changes buttons gated on `formState.isValid`,
but the title is a buffered input that only commits to react-hook-form
on blur/submit. In the default onSubmit mode, `setValue` without
`shouldValidate` re-broadcasts the cached `isValid` instead of
recomputing it, so the button stayed disabled even with a title filled.
Web is unaffected: its inputs write to the form live, so the registered
field's onChange recomputes `isValid` and the same gate works.

Observe the live title draft through BufferedSheetInput's existing
onDraftChange hook and gate the button on a lightweight title-present
boolean. This preserves the buffer that keeps typing lag-free on
Android. Also seeds the boolean from the prefilled title in the edit
modal, fixing the latent case where clearing an existing title left
Save enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
orbit-ui-mobile-web Ignored Ignored Jun 6, 2026 6:33pm

@sonarqubecloud

sonarqubecloud Bot commented Jun 6, 2026

Copy link
Copy Markdown

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The root-cause diagnosis is correct and the fix is clean. BufferedSheetInput's onDraftChange was already wired to fire on every keystroke but was previously unused at the form-fields layer; threading it up to a lightweight titleFilled boolean sidesteps the stale isValid issue without running the Zod resolver per keystroke or surfacing a premature "title required" error. Both the create-modal (resets to false on close) and the edit-modal (seeded from the prefill title before mount) handle state initialisation correctly. Web is correctly untouched — its live-binding inputs already recompute isValid through the standard RHF onChange path, so the behavioral parity (button disabled while title is empty) is preserved by different platform-appropriate mechanisms, which is the allowed difference per CLAUDE.md. Tests cover the empty→filled flip and the whitespace-trim edge case. Solid fix.

@thomasluizon
thomasluizon merged commit 06469df into main Jun 6, 2026
8 checks passed
@thomasluizon
thomasluizon deleted the fix/mobile-habit-submit-title-validation branch June 6, 2026 18:38
thomasluizon added a commit that referenced this pull request Jun 15, 2026
…bmit gate (#175)

* fix(ui): UX/QA batch across web + mobile (26 items) + create-habit submit gate

Cross-platform UX/QA pass plus shared error localization. Highlights:
- Chat: voice-recording race fix; language picker moved to the chat header
- Calendar: tappable centered month nav, day-detail modal, centered muted
  legend, removed the "x/30 dias" summary
- Errors: backend errors render localized via ERROR_CODE_TO_KEY; login surfaces
  errors through a toast only (no reference code / inline yellow text)
- Retrospective: stats-dashboard + narrative UI with an empty-period state
- Upgrade: exact hero copy + Free/Pro two-column comparison
- Frequency: swipe carousel; streak-freeze celebration auto-dismisses;
  bad = red / overdue = yellow log dots on both platforms
- Preferences option legends relocated into the picker modal; AI-facts paginator
  inline with an icon select
- Support: removed name/email fields; advanced devs: deduped MCP tab
- Widget: fallback drawables + first-add render fix
- pt-BR naturalization across the locale (parity preserved at 1665/1665)
- fix(mobile): restore the title-presence submit gate on the create/edit habit
  modals. #172 reverted #145: with a buffered title input, setValue without
  shouldValidate re-broadcasts the cached onSubmit-mode isValid, so the button
  stayed disabled with a title filled. Gate on useWatch('title') instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(i18n): remove dead orbitMcp.claudeDesktop key

The desktop MCP tab was dropped (MCP_CONFIG_TABS no longer includes 'desktop'),
so this key has no remaining callers. Flagged by the PR review bot. Removed from
both locales; en/pt-BR parity preserved at 1664/1664.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant