Skip to content

feat(streaks): streak freezes — buy with Cores, auto-apply on miss#6340

Open
rebelchris wants to merge 13 commits into
mainfrom
feat/auto-streak-freeze
Open

feat(streaks): streak freezes — buy with Cores, auto-apply on miss#6340
rebelchris wants to merge 13 commits into
mainfrom
feat/auto-streak-freeze

Conversation

@rebelchris

@rebelchris rebelchris commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What

Adds streak freezes: users can buy freeze packs with Cores (cap 5) and they auto-apply when a day is missed, protecting the streak.

  • streak_freeze feature flag + GraphQL contract (freezesAvailable, freeze dates, products, purchase mutation)
  • Freeze inventory row in the streak popover + frozen-day rendering in the calendar
  • StreakFreezePurchaseModal (Cores purchase, cap-aware)
  • Settings → Customization → Streaks: freeze section with auto-apply opt-out (optOutStreakFreeze)
  • Upsell prompts on streak break (recover modal), after a successful restore when the stash is empty, and on milestone
  • New notification types: streak_freeze_used, streak_freeze_depleted
  • Fixes pre-existing strict-mode errors in useStreakRecover

Depends on

dailydotdev/daily-api feat/auto-streak-freeze (schema + auto-apply cron + notifications)

Test

  • pnpm --filter shared test streak suites green (27 tests)
  • Strict typecheck + lint clean on changed files

🤖 Generated with Claude Code

Preview domain

https://feat-auto-streak-freeze.preview.app.daily.dev

rebelchris and others added 8 commits July 16, 2026 19:19
Introduces the pinned backend contract for automated streak freezes:
featuresManagement flag, userStreak.freezesAvailable, streakFreezeProducts,
userStreakFreezeDates and purchaseStreakFreeze operations, plus new
LogEvent/Origin/TargetType/RequestKey entries. Existing UserStreak fixtures
are updated for the new required field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Exposes freezesAvailable, streak-freeze products, consumed freeze dates,
and a purchase mutation. Mirrors useStreakRecover's insufficient-funds
handling: an unaffordable pack redirects to the Cores page with an
origin + next param instead of calling the mutation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New LazyModal.StreakFreezePurchase presents the seeded packs (1/3/5) with
CoreIcon pricing, a selected-pack state, and a cap hint ("Max 5 freezes")
once freezesAvailable + pack quantity would exceed the cap. The purchase
button flips to "Buy Cores" when the balance can't cover the selected pack.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…opover

Adds a freeze-inventory row to the reading streak popover (count, CTA
copy that changes when the balance is zero, tap opens the purchase
modal), gated behind the feature flag + cores access. Past days that
consumed a freeze now render with the existing Freeze visual via a new
Streak.UsedFreeze state with a distinct tooltip ("A streak freeze was
used this day"), sourced from userStreakFreezeDates. Weekend auto-freeze
behavior is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
optOutStreakFreeze follows the optOutReadingStreak pattern exactly
(default false = auto-apply on) with its own toggle in SettingsContext.
The streaks settings page gains a "Streak freezes" section: current
count, a buy button that opens the purchase modal, and the
"Automatically use streak freezes" switch, gated behind the feature
flag + cores access.

Also fills in optOutAchievements/isGamificationEnabled fields that were
already missing from a few full SettingsContextData/RemoteSettings test
fixtures, surfaced by strict typecheck once optOutStreakFreeze was added
to the same object literals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a subtle secondary link below the restore CTA ("Get streak
freezes so this doesn't happen again") that opens the purchase modal.
Gated behind the feature flag + cores access so it never competes with
the primary restore action for ineligible users.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registers streak_freeze_used and streak_freeze_depleted in the
NotificationType enum, groups them into STREAK_KEYS and the Updates
filter category, and adds their settings copy to STREAK_NOTIFICATIONS.
Icon/copy are backend-driven and reuse the existing Streak icon type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extract StreakFreezeUpsell into a shared component, add it to the
milestone modal, and open the freeze purchase modal after a successful
restore when the user has no freezes left. Also drop the icon from the
popover freeze row and fix pre-existing strict-mode errors in
useStreakRecover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Jul 21, 2026 2:25pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Jul 21, 2026 2:25pm

Request Review

… types condition)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The transaction label assumed every product-linked transaction was an
award; freeze purchases now show the product name instead.

Co-Authored-By: Claude Fable 5 <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