Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /** * Settings BillingTab Stories — Family Coverage States * * Demonstrates how the billing tab in settings adapts when a free-tier * parent's children are covered by another parent's family subscription. */ import type { Meta, StoryObj } from '@storybook/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { billingKeys } from '@/lib/queryKeys' import { TIER_LIMITS, type TierName } from '@/lib/tier-limits' import type { TierResponse, FamilyCoverageResponse } from '@/hooks/useTier' import SettingsPage from './page' function tierData(tier: TierName): TierResponse { const limits = TIER_LIMITS[tier] return { tier, limits: { maxPracticeStudents: limits.maxPracticeStudents === Infinity ? null : limits.maxPracticeStudents, maxSessionMinutes: limits.maxSessionMinutes, maxSessionsPerWeek: limits.maxSessionsPerWeek === Infinity ? null : limits.maxSessionsPerWeek, maxOfflineParsingPerMonth: limits.maxOfflineParsingPerMonth, }, } } function createQC(tier: TierName, coverage: FamilyCoverageResponse) { const qc = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity } }, }) qc.setQueryData(billingKeys.tier(), tierData(tier)) qc.setQueryData(billingKeys.coverage(), coverage) return qc } /** * Provides a seeded QueryClient that overrides the global one from preview.tsx. * All other providers (Fullscreen, AudioManager, etc.) come from the global decorator. */ function Wrapper({ children, tier, coverage, }: { children: React.ReactNode tier: TierName coverage: FamilyCoverageResponse }) { const qc = createQC(tier, coverage) return <QueryClientProvider client={qc}>{children}</QueryClientProvider> } const meta: Meta<typeof SettingsPage> = { title: 'Pages/Settings/Billing Coverage', component: SettingsPage, parameters: { layout: 'fullscreen', nextjs: { appDirectory: true, navigation: { searchParams: { tab: 'billing' } }, }, }, tags: ['autodocs'], } export default meta type Story = StoryObj<typeof SettingsPage> /** * Free-tier parent with NO coverage — standard upgrade CTA. */ export const FreeNoCoverage: Story = { name: 'Free — No Coverage', render: () => ( <Wrapper tier="free" coverage={{ isCovered: false, coveredBy: null, coveredChildCount: 0, totalChildCount: 2 }} > <SettingsPage /> </Wrapper> ), } /** * Free-tier parent where ALL children are covered. * Shows "Covered" badge, coverage info row, and de-emphasized upgrade. */ export const FreeFullyCovered: Story = { name: 'Free — Fully Covered (2/2)', render: () => ( <Wrapper tier="free" coverage={{ isCovered: true, coveredBy: { userId: 'mom-id', name: 'Sarah' }, coveredChildCount: 2, totalChildCount: 2, }} > <SettingsPage /> </Wrapper> ), } /** * Free-tier parent where only SOME children are covered. * Shows "1 of 3 students covered by Sarah's Family Plan". */ export const FreePartiallyCovered: Story = { name: 'Free — Partially Covered (1/3)', render: () => ( <Wrapper tier="free" coverage={{ isCovered: true, coveredBy: { userId: 'mom-id', name: 'Sarah' }, coveredChildCount: 1, totalChildCount: 3, }} > <SettingsPage /> </Wrapper> ), } /** * Family-tier parent — shows "Manage Subscription", no coverage info. */ export const FamilyTier: Story = { name: 'Family — Own Subscription', render: () => ( <Wrapper tier="family" coverage={{ isCovered: false, coveredBy: null, coveredChildCount: 0, totalChildCount: 2 }} > <SettingsPage /> </Wrapper> ), } |