Skip to content

Add cycle tracking safety boundaries - #2216

Merged
Asherlc merged 2 commits into
mainfrom
codex/issue-2168
Jul 27, 2026
Merged

Asherlc merged 2 commits into
mainfrom
codex/issue-2168

Conversation

@Asherlc

@Asherlc Asherlc commented Jul 27, 2026 •

Copy link
Copy Markdown
Owner

Closes #2168

Summary

  • define one shared cycle-tracking safety notice
  • render the notice persistently and accessibly on web and iOS
  • add exact contract and client tests plus a seeded mobile Storybook screen
  • mock the native date picker at the existing Storybook web boundary

Validation

  • pnpm test — 882 files passed, 14,117 tests passed, expected skips only
  • scoring, web, and mobile typechecks
  • targeted and repository Biome/lint policy stages
  • pnpm --filter dofek-mobile build-storybook
  • full pnpm lint reaches lint:analytics-sql, then local dbt/sqlfluff cannot connect to ClickHouse because the shared Docker VM is out of capacity; exact-head GitHub Actions is the approved remaining Docker-backed gate

Summary by Sourcery

Add a shared cycle-tracking safety notice and surface it alongside the estimated phase on web and mobile, with supporting tests and Storybook coverage.

New Features:

  • Expose a shared cycle-tracking safety notice string from the menstrual-cycle scoring module for reuse across clients.
  • Display an accessible tracking limitation notice next to the cycle phase estimate in the mobile app and web cycle page.
  • Add a mobile Storybook story for the cycle tracking screen with mocked TRPC data and a Storybook-specific date picker.

Documentation:

  • Document the menstrual-cycle module as providing shared safety copy and clarify that cycle phase estimates are non-clinical, following Apple's Cycle Tracking limitation copy.

Tests:

  • Add unit tests to assert the shared safety notice content and its rendering on both web and mobile cycle views.
  • Introduce Storybook configuration and mocks to support rendering the cycle tracking screen in isolation without native date picker dependencies.

Summary by cubic

Adds a shared cycle-tracking safety notice and shows it persistently beside the phase estimate on web and iOS. Aligns with Linear #2168 by stating estimates are not for birth control or diagnosis.

  • New Features
    • Centralized CYCLE_TRACKING_SAFETY_NOTICE in @dofek/scoring/menstrual-cycle.
    • Web: accessible “Tracking limitation” note (role="note", labeled) beside the phase card.
    • iOS: accessible notice with consistent styling in the Cycle screen.
    • Storybook (mobile): hardened Cycle screen story with mocked tRPC client/providers; aliased @react-native-community/datetimepicker to a lightweight display mock.
    • Tests: exact assertions for the notice content and rendering on web/mobile; unit test for the date picker mock.
    • Docs: updated packages/scoring/README.md to document the shared safety copy and reference Apple’s Cycle Tracking limitation.

Written for commit ce0942c. Summary will update on new commits.

Review in cubic

Copilot AI review requested due to automatic review settings July 27, 2026 18:29
@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@Asherlc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 147c9fad-b007-44f8-a922-0dfd70cd62d2

📥 Commits

Reviewing files that changed from the base of the PR and between 068cdeb and ce0942c.

📒 Files selected for processing (11)
  • packages/mobile/.storybook/main.ts
  • packages/mobile/.storybook/mocks/react-native-community-datetimepicker.test.tsx
  • packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx
  • packages/mobile/app/cycle.stories.tsx
  • packages/mobile/app/cycle.test.tsx
  • packages/mobile/app/cycle.tsx
  • packages/scoring/README.md
  • packages/scoring/src/menstrual-cycle.test.ts
  • packages/scoring/src/menstrual-cycle.ts
  • packages/web/src/routes/cycle.test.tsx
  • packages/web/src/routes/cycle.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Implements a shared cycle-tracking safety notice constant in the scoring package and wires it into both web and mobile cycle tracking UIs with accessible, persistent rendering, backed by unit tests, a seeded mobile Storybook screen, and a Storybook-specific mock for the native date picker.

File-Level Changes

Change Details Files
Introduce shared cycle-tracking safety notice constant in scoring and document its intended use.
  • Add CYCLE_TRACKING_SAFETY_NOTICE export to the menstrual-cycle scoring module with the exact limitation copy.
  • Add a dedicated unit test to assert the safety notice string is stable and correct.
  • Update the scoring README to mention the shared safety copy and clarify the non-clinical nature of cycle phase estimates with an external reference.
packages/scoring/src/menstrual-cycle.ts
packages/scoring/src/menstrual-cycle.test.ts
packages/scoring/README.md
Render the cycle-tracking safety notice in the web cycle page with accessible semantics and test coverage.
  • Import the shared safety notice from the scoring module into the web cycle route.
  • Add an aside element beside the phase estimate with ARIA role and label to expose the notice as an accessibility note.
  • Style the notice using existing design tokens for borders, background, and typography.
  • Add a unit test that seeds a current phase response and asserts the note role, label, and exact safety text content.
packages/web/src/routes/cycle.tsx
packages/web/src/routes/cycle.test.tsx
Render the cycle-tracking safety notice in the mobile cycle screen with accessible labels and test coverage.
  • Import the shared safety notice into the mobile cycle screen and render a dedicated View containing a title and body text near the phase estimate.
  • Provide an accessibilityLabel that announces both the notice context and the safety copy to screen readers.
  • Add styles for the safety notice container and text to visually separate it from surrounding content using the theme colors.
  • Add a test that seeds phase data and asserts the accessibility label matches the expected safety notice text.
packages/mobile/app/cycle.tsx
packages/mobile/app/cycle.test.tsx
Enhance mobile Storybook support for the cycle tracking screen with seeded data and a mocked date picker boundary.
  • Register a Storybook alias so @react-native-community/datetimepicker is resolved to a local mock in the mobile Storybook Vite config.
  • Implement a lightweight Storybook-specific DateTimePicker mock that renders a pressable, styled date display instead of the native picker.
  • Add a mobile CycleScreen Storybook story that seeds current phase and period history responses via a mocked TRPC link and wraps the screen in the appropriate TRPC and React Query providers.
packages/mobile/.storybook/main.ts
packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx
packages/mobile/app/cycle.stories.tsx

Assessment against linked issues

Issue Objective Addressed Explanation
#2168 Define shared safety copy for cycle tracking that explicitly states predictions are tracking estimates only and must not be used for birth control or diagnosis. ✅
#2168 Display the safety notice prominently and accessibly near cycle phase forecasts in both the web and mobile cycle tracking UIs. ✅
#2168 Document and test the new safety notice so its text and presence are enforced across clients. ✅

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Surface shared cycle-tracking safety notice on web and mobile

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Export a shared cycle-tracking safety notice from the scoring menstrual-cycle module.
• Render an accessible “Tracking limitation” notice beside phase estimates on web and iOS.
• Add contract/client tests plus Storybook coverage, including a mocked native date picker.
Diagram

graph TD
  A["@dofek/scoring menstrual-cycle"] --> B["Safety notice const"] --> C["Web CyclePage"]
  B --> D["Mobile CycleScreen"]
  E["Mobile Storybook config"] --> F["DateTimePicker mock"] --> D
  G["Cycle Story (mock TRPC)"] --> D
  H["Web & Mobile tests"] --> C
  H --> D
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Client-owned copy (duplicate string in web/mobile)
  • ➕ Avoids expanding the scoring module API surface
  • ➕ Lets each client tailor formatting and localization independently
  • ➖ High risk of drift/inconsistency across platforms
  • ➖ Harder to enforce legal/safety wording updates globally
2. Centralize in i18n/translation layer (shared key + per-locale strings)
  • ➕ Best path for localization and future copy changes
  • ➕ Keeps scoring module focused on computation rather than copy
  • ➖ More plumbing work now (keys, catalogs, client wiring)
  • ➖ Still needs governance to keep wording consistent across apps

Recommendation: The PR’s approach (single exported constant from a shared module) is a good near-term tradeoff: it guarantees identical safety language across web and mobile with minimal wiring. If/when localization becomes a requirement, migrating this string to the i18n layer (keeping the same semantics and tests) would be the most scalable next step.

Files changed (10) +226 / -5

Enhancement (3) +40 / -2
cycle.tsxRender tracking limitation notice on the Cycle screen +28/-1

Render tracking limitation notice on the Cycle screen

• Imports the shared safety notice constant and displays a persistent “Tracking limitation” panel beneath the phase estimate section. Adds an accessibilityLabel that prefixes the shared copy for screen readers, plus styling for the notice container and text.

packages/mobile/app/cycle.tsx

menstrual-cycle.tsExport CYCLE_TRACKING_SAFETY_NOTICE from scoring module +3/-0

Export CYCLE_TRACKING_SAFETY_NOTICE from scoring module

• Adds a new exported constant containing the tracking-only safety boundary text. Keeps the copy colocated with other menstrual-cycle display/metadata exports for reuse by clients.

packages/scoring/src/menstrual-cycle.ts

cycle.tsxRender tracking limitation notice on the web Cycle page +9/-1

Render tracking limitation notice on the web Cycle page

• Imports the shared safety notice constant and renders it in an <aside> with role="note" and an aria-label. Places the notice near the current phase estimate with consistent styling.

packages/web/src/routes/cycle.tsx

Tests (4) +135 / -1
cycle.stories.tsxSeeded Cycle screen Storybook story with mocked TRPC +95/-0

Seeded Cycle screen Storybook story with mocked TRPC

• Adds a fullscreen CycleTracking Storybook story that renders the real Cycle screen inside TRPC + React Query providers. Uses a custom TRPC link to return deterministic currentPhase and history data.

packages/mobile/app/cycle.stories.tsx

cycle.test.tsxTest mobile safety notice accessibility label +17/-0

Test mobile safety notice accessibility label

• Adds a unit test asserting the tracking-only safety notice is present when a phase estimate exists. Verifies the notice via getByLabelText to enforce accessible labeling.

packages/mobile/app/cycle.test.tsx

menstrual-cycle.test.tsAdd contract test for shared safety notice constant +9/-1

Add contract test for shared safety notice constant

• Introduces a dedicated test that asserts the exact CYCLE_TRACKING_SAFETY_NOTICE string value. This locks the cross-client contract for safety wording.

packages/scoring/src/menstrual-cycle.test.ts

cycle.test.tsxTest web safety notice rendering and semantics +14/-0

Test web safety notice rendering and semantics

• Adds a test that asserts the safety notice renders beside the phase estimate when data is present. Verifies semantics via role="note" and an accessible name.

packages/web/src/routes/cycle.test.tsx

Documentation (1) +4 / -2
README.mdDocument menstrual-cycle module as shared safety copy source +4/-2

Document menstrual-cycle module as shared safety copy source

• Updates scoring module documentation to note that menstrual-cycle provides shared safety copy. Adds context linking the boundary language to Apple’s Cycle Tracking limitation guidance.

packages/scoring/README.md

Other (2) +47 / -0
main.tsAlias native DateTimePicker to a Storybook mock +4/-0

Alias native DateTimePicker to a Storybook mock

• Adds a Vite alias mapping @react-native-community/datetimepicker to a local mock implementation for Storybook builds. This prevents native module dependencies from breaking Storybook rendering.

packages/mobile/.storybook/main.ts

react-native-community-datetimepicker.tsxAdd Storybook-safe DateTimePicker replacement +43/-0

Add Storybook-safe DateTimePicker replacement

• Introduces a lightweight Pressable-based DateTimePicker mock that displays the selected date. Keeps accessibility label/role support while avoiding native picker behavior in Storybook.

packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx

@github-actions

github-actions Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Mobile Preview

Scan to open on device:

QR code for dofek://preview/pr-2216

Channel pr-2216
Deep Link dofek://preview/pr-2216
Commit 360ba10

To test on device:

  1. Build and install the preview client: PREVIEW_CHANNEL=pr-2216 pnpm expo prebuild --clean -p ios
  2. Or tap deep link on an existing preview build: dofek://preview/pr-2216

Each PR gets its own channel. Build a preview client with PREVIEW_CHANNEL=pr-{N} to test.

@github-actions

github-actions Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Storybook previews for 360ba101 are ready:

This comment updates automatically on each PR push.

@qodo-code-review

qodo-code-review Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 178 rules

Grey Divider


Remediation recommended

1. QueryClient missing staleTime ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
CycleStoryFrame creates a separate QueryClient without configuring staleTime, which diverges
from the app’s canonical React Query defaults. This can lead to inconsistent caching behavior across
environments and violates the requirement to align staleTime with the central defaults (or justify
overrides).
Code

packages/mobile/app/cycle.stories.tsx[R60-66]

+function CycleStoryFrame() {
+  const queryClient = useMemo(
+    () =>
+      new QueryClient({
+        defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
+      }),
+    [],
Relevance

⭐⭐⭐ High

Repo pins QueryClient defaults incl. staleTime; Storybook QueryClients are configured to match app
behavior.

PR-#1525
PR-#1958

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checklist requires staleTime to match the central App defaults (or have an inline
justification). The app’s shared query client sets staleTime to 5 minutes, while the new Storybook
QueryClient omits staleTime entirely, creating a divergent default with no justification.

Rule 721949: Align query staleTime configuration with App.tsx defaults
packages/mobile/app/cycle.stories.tsx[60-66]
packages/mobile/lib/query-client.ts[5-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`packages/mobile/app/cycle.stories.tsx` creates a new `QueryClient` without setting `defaultOptions.queries.staleTime`, which causes it to use React Query’s default `staleTime` (typically `0`) rather than the app’s shared default.

## Issue Context
The mobile app’s canonical query client config sets `defaultOptions.queries.staleTime` to `1000 * 60 * 5`. Storybook should either reuse the canonical client (preferred) or explicitly set the same `staleTime` (or document/justify why it differs).

## Fix Focus Areas
- packages/mobile/app/cycle.stories.tsx[60-66]
- packages/mobile/lib/query-client.ts[5-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Silent Storybook tRPC gaps ✓ Resolved 🐞 Bug ☼ Reliability
Description
packages/mobile/app/cycle.stories.tsx completes the observable without emitting or erroring for any
unhandled tRPC operation path, which silently hides missing Storybook setup and can make
interactions (e.g., logPeriod) behave incorrectly or not at all. This reduces Storybook reliability
and makes future additions to CycleScreen harder to diagnose.
Code

packages/mobile/app/cycle.stories.tsx[R42-56]

+function createMockObservable(path: string): OperationResultObservable<AppRouter, unknown> {
+  const result: OperationResultObservable<AppRouter, unknown> = {
+    subscribe(observer) {
+      if (path === "menstrualCycle.currentPhase") {
+        observer.next?.({ result: { data: currentPhase } });
+      } else if (path === "menstrualCycle.history") {
+        observer.next?.({ result: { data: periodHistory } });
+      }
+      observer.complete?.();
+      return { unsubscribe() {} };
+    },
+    pipe() {
+      return result;
+    },
+  };
Relevance

⭐⭐⭐ High

Strong precedent: team accepted throwing/failing fast on unhandled Storybook tRPC paths.

PR-#2051

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The CycleTracking story only emits data for menstrualCycle.currentPhase and
menstrualCycle.history; all other paths just complete, making missing story setup invisible.
CycleScreen defines additional tRPC operations (notably menstrualCycle.logPeriod mutation) which
would not be handled by this mock if triggered. This is a known recurring Storybook issue pattern in
this repo and was previously addressed by throwing on unhandled paths.

packages/mobile/app/cycle.stories.tsx[36-56]
packages/mobile/app/cycle.tsx[18-33]
PR-#2051

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The CycleTracking Storybook mock tRPC link only responds to two query paths and otherwise completes without sending a `next` value or an error. This can silently mask missing mocks and make interactions (like mutations) unpredictable or broken in Storybook.

### Issue Context
`CycleScreen` issues multiple tRPC operations (queries + a mutation). The story should either:
- explicitly handle the known operations it intends to support, and
- fail fast (throw / observer.error) for anything else.

### Fix Focus Areas
- packages/mobile/app/cycle.stories.tsx[36-58]
- packages/mobile/app/cycle.tsx[18-33]

### Suggested change
Add an `else` branch that throws an error including the `path` (and optionally `op.type`) similar to the already-accepted activities Storybook pattern. Optionally, explicitly handle `menstrualCycle.logPeriod` by returning a deterministic `{ ok: true }`-style payload if you want the button interaction to work in Storybook.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Hardcoded safety notice styling ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new safety notice and Storybook date picker mock styles hardcode visual constants (e.g., border
radius, padding/spacing, and font sizes) instead of using shared design tokens. This violates the
design-token requirement for production UI code and increases the risk that UI styling becomes
inconsistent or drifts between app and Storybook.
Code

packages/mobile/app/cycle.tsx[R228-246]

+  safetyNotice: {
+    backgroundColor: colors.surfaceSecondary,
+    borderColor: colors.border,
+    borderRadius: 10,
+    borderWidth: StyleSheet.hairlineWidth,
+    gap: 4,
+    marginTop: 12,
+    padding: 12,
+  },
+  safetyNoticeTitle: {
+    color: colors.text,
+    fontSize: 14,
+    fontWeight: "600",
+  },
+  safetyNoticeText: {
+    color: colors.textSecondary,
+    fontSize: 14,
+    lineHeight: 20,
+  },
Relevance

⭐⭐ Medium

Tokenizing RN style constants can be subjective; some precedent for using shared spacing/units, but
not decisive.

PR-#824
PR-#1963

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The compliance rule flags hardcoded visual constants in UI code as violations when tokenized
alternatives exist. In the cited safetyNotice* styles and the Storybook mock’s
StyleSheet.create, multiple numeric literals are introduced for spacing/layout, radius, and
typography, despite the project exposing shared spacing, radius, and fontSize design tokens
via packages/mobile/theme.ts (re-exported from @dofek/scoring/tokens) that should be used
instead of literals.

Rule 721961: Use design tokens instead of hardcoded visual constants
packages/mobile/app/cycle.tsx[228-246]
packages/mobile/theme.ts[8-19]
packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx[30-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Replace hardcoded spacing, radius, and typography numeric literals introduced in the cycle tracking safety notice styles and the Storybook date picker mock with shared design tokens to comply with the design-token rule and keep styling consistent across production UI and Storybook.

## Issue Context
The repo provides shared design tokens through `packages/mobile/theme.ts`, which re-exports `spacing`, `radius`, and `fontSize` from `@dofek/scoring/tokens`. Both production screen styles (cycle tracking safety notice) and Storybook/mock components should use these token values rather than hardcoded constants to prevent inconsistencies and UI drift.

## Fix Focus Areas
- packages/mobile/app/cycle.tsx[228-246]
- packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx[30-42]
- packages/mobile/theme.ts[8-19]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Date picker mock drops onChange ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The Storybook DateTimePicker mock renders a Pressable with button semantics but provides no way to
invoke the real DateTimePicker interaction (it ignores onChange), so CycleScreen’s date selection
cannot be exercised in Storybook. This makes Storybook interaction behavior misleading and blocks
testing the log-period flow in the story.
Code

packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx[R9-27]

+export default function StorybookDateTimePicker({
+  accessibilityLabel,
+  value,
+}: StorybookDateTimePickerProps) {
+  return (
+    <Pressable
+      accessibilityLabel={accessibilityLabel}
+      accessibilityRole="button"
+      style={styles.picker}
+    >
+      <Text style={styles.text}>
+        {value.toLocaleDateString("en-CA", {
+          year: "numeric",
+          month: "2-digit",
+          day: "2-digit",
+        })}
+      </Text>
+    </Pressable>
+  );
Relevance

⭐⭐⭐ High

Storybook mocks are expected to support real interactions; similar Storybook mock reliability fixes
were accepted.

PR-#2051
PR-#732

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
CycleScreen passes an onChange handler to DateTimePicker to update state, but the Storybook mock
component never accepts or calls onChange, so the interaction path cannot work within Storybook
when the alias is active.

packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx[4-27]
packages/mobile/app/cycle.tsx[100-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Storybook replacement for `@react-native-community/datetimepicker` is non-interactive: it accepts only `value`/`accessibilityLabel` and never calls the `onChange` callback that the real component provides.

### Issue Context
`CycleScreen` relies on `onChange` to update `startDate`. In Storybook, the date picker is replaced with this mock, so changing the date cannot be simulated.

### Fix Focus Areas
- packages/mobile/.storybook/mocks/react-native-community-datetimepicker.tsx[4-27]
- packages/mobile/app/cycle.tsx[100-110]

### Suggested change
Update the mock props to accept `onChange?: (event: unknown, date?: Date) => void` (and any other required props you care about), and wire `Pressable`’s `onPress` to call `onChange(null, value)` or `onChange(null, new Date(value.getTime() + 86400000))` so Storybook users can exercise the flow.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread packages/mobile/app/cycle.stories.tsx
Comment thread packages/mobile/app/cycle.tsx
Comment thread packages/mobile/app/cycle.stories.tsx
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@Asherlc
Asherlc merged commit d4c8bcf into main Jul 27, 2026
101 checks passed
@Asherlc
Asherlc deleted the codex/issue-2168 branch July 27, 2026 18:59
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.

[CYCLE-04] No visible reminder that cycle prediction is not contraception/diagnosis

2 participants