feat(onboarding): pick the birth place by level instead of by search
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled

The single search field asked people to type a place name and then judge
which of several near-identical results was theirs, which is the one thing
they cannot verify about their own birth record. Province, city and district
are now chosen from the dataset the app already ships, so there is nothing to
type and nothing to disambiguate.

Levels that offer no choice collapse: municipalities show one level, and
prefecture cities without districts stop at the city. A district can be left
as the city centre, which is accurate enough because the chart only needs
coordinates and a timezone.

The timezone is resolved once for the chosen place rather than on every
keystroke, through a dedicated route that both this picker and the Geoapify
path share.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-17 18:35:42 +08:00
parent e1db576284
commit 9dc2948ab6
13 changed files with 744 additions and 460 deletions
+11
View File
@@ -110,6 +110,17 @@ The base unit is 4px. Tokens are `--space-1: 4px`, `--space-2: 8px`, `--space-3:
- **Guided candidate states:** low confidence presents the saved candidate range and either another evidence question or a safe finish; medium confidence can save the range but never apply a representative minute; high confidence names both “候选时间” and “当前排盘使用时间” before explicit confirmation; ready states that the current chart time changed while the original report remains preserved. No state calls a candidate the true birth minute.
- **Guided responsive/accessibility contract:** body copy remains at least 14px, labels at least 12px, and all controls at least 44px. Focus is always visible, the composer is keyboard operable, semantic Chinese phrases remain together at 390px, and reduced-motion removes entrance translation while retaining state changes.
### Birth place picker
- **Composition:** three cascading Base UI Selects — province, city, district — over the bundled China administrative dataset. There is no free-text search and no overseas provider in this surface.
- **Level collapsing:** a level that offers no choice is not rendered. Municipalities and special administrative regions skip the repeated city level; prefecture cities without districts complete at the city; a province with neither lower level completes at the province.
- **Unsure escape hatch:** any city that has districts leads its district list with “不确定,用市区中心”, so browsing never dead-ends. A stored empty district resumes as that choice.
- **Precision copy:** the picker states that county-level precision is enough for a chart, so a village or township birth is not treated as missing data.
- **Value:** administrative codes, the node centre coordinate, and the IANA zone are all persisted. Coordinates come from the dataset; the zone is resolved once per chosen place through the chart engine rather than per keystroke.
- **States:** nothing chosen, partially chosen, resolving the zone, resolved, and zone service unavailable with an explicit retry. An unresolved zone is never reported upward as a usable birth place.
- **Saved profiles:** mounting an already-saved place neither refetches nor reports a change, so opening the profile dialog cannot look like a location edit. Changing the birth date does invalidate the stored offset and resolves the zone again.
- **Accessibility:** every level keeps a visible label, an explicit trigger name, and the 44px target from the select recipe; status text uses a polite live region.
### Birth date picker
- **Composition:** shadcn outline Button trigger, Base UI Popover, and a single-select React DayPicker Calendar.