Skip to content

Collect gender during onboarding and from existing users - #641

Merged
Ohmarkg merged 3 commits into
mainfrom
gender-collection
Sep 1, 2026
Merged

Collect gender during onboarding and from existing users#641
Ohmarkg merged 3 commits into
mainfrom
gender-collection

Conversation

@vickrumsukhlani

Copy link
Copy Markdown
Collaborator

Summary

Adds gender collection to the app, stored on PrivateUserInfo.gender (private — not shown on a user's profile).

  • New onboarding step. SetupGender sits between academic information and resume in ProfileSetupStack, making profile setup six steps. Options come from the new GENDER_OPTIONS in src/types/user.ts: Male / Female / Other / Prefer not to say. Since "Prefer not to say" is the opt-out, the step has no skip button and every user who reaches it writes a value.
  • Backfill for existing users. Accounts created before this step never pass through ProfileSetup again, so GenderPromptModal is mounted in MainStack and shown when gender === undefined. It has no close button and an inert setVisible, so neither a backdrop tap nor the Android back button dismisses it. It writes to Firestore first and only then updates AsyncStorage + UserContext, so a failed write leaves the prompt open rather than silently claiming success. Once new-user onboarding has been live long enough, the component and its mount can be deleted.
  • Refactor. The progress dashes at the top of each setup screen were five hardcoded <View>s repeated per screen. Extracted into a ProgressDashes component driven by TOTAL_SETUP_STEPS, so adding the sixth step didn't mean editing all five screens.
  • Dropped the stale shpe-app-web/app/types/user.ts sync comment from src/types/user.ts — that project was removed in 6e8c922.

Test plan

  • New account: run through profile setup, confirm the gender step appears after academic info, that Continue is disabled until a selection is made, and that the value lands in Firestore.
  • Existing account with no gender: confirm the modal appears on entering the main app, cannot be dismissed by backdrop tap or Android back, and does not reappear after saving (including after a fresh launch).
  • Existing account with a gender already set: confirm no modal.
  • Airplane mode: confirm the save error shows and the prompt stays open.
  • Check the modal in both light and dark mode.

npx tsc --noEmit reports no new errors in the touched files (the repo has pre-existing errors elsewhere).

🤖 Generated with Claude Code

https://claude.ai/code/session_01T9reuKppqcRRaeTGPyxPbV

Add a SetupGender step to profile setup between academic information and
resume, writing the selection to PrivateUserInfo.gender. "Prefer not to
say" is the opt-out, so the step cannot be skipped and every user who
sees it writes a value.

Existing accounts never pass through ProfileSetup again, so
GenderPromptModal is mounted in MainStack to collect the value in-app.
It renders only when gender is undefined and cannot be dismissed, and
it writes to Firestore before updating local state so a failed write
leaves the prompt open.

Also extract the profile-setup progress dashes into a ProgressDashes
component so adding the sixth step did not mean editing every screen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9reuKppqcRRaeTGPyxPbV
Comment thread src/components/GenderPromptModal.tsx
Comment thread src/screens/onboarding/ProfileSetup.tsx
vickrumsukhlani and others added 2 commits August 31, 2026 22:12
Brings up the Firebase Auth and Firestore emulators in a container so the app
can be developed and tested without touching the production project.

- firebase-emulator/Dockerfile pre-downloads the emulator JARs at image build
  time so `up` does not refetch them per container.
- firebase-emulator/start.sh passes --import only when saved state exists,
  because Firebase treats a missing import directory as a fatal error on a
  clean checkout. It lives in its own file rather than inline in the compose
  command because a YAML folded scalar silently splits the flags onto
  separate lines.
- docker-compose.yml sets stop_signal: SIGINT so --export-on-exit actually
  flushes; Compose sends SIGTERM by default, which loses the data.
- firebase-emulator/seed.js writes two idempotent accounts, one with a gender
  value and one without, so the existing-user gender prompt can be exercised
  locally. It refuses to run unless FIRESTORE_EMULATOR_HOST is set.
- firebase.json exposes the UI, hub, and logging ports on 0.0.0.0 so they are
  reachable from the host.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J7Xu8Pxwqs2czY79M239vU
Both gender pickers left their options tappable during the save. Because the
handler closes over the value that was selected when it was pressed, changing
the selection mid-write meant the highlighted option could end up different
from what was actually stored: the popup then closes and the onboarding screen
advances, so there is no chance to correct it.

Marking the options disabled while loading matches the Save/Continue buttons,
which were already guarded, and the opacity-50 treatment follows the existing
idiom in SettingsComponents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J7Xu8Pxwqs2czY79M239vU

@Ohmarkg Ohmarkg left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm

@Ohmarkg
Ohmarkg merged commit 29d9747 into main Sep 1, 2026
1 check failed
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