Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
226 commits
Select commit Hold shift + click to select a range
d468464
refactor(billing): complete billing facade with resubscribe/topup + s…
dante01yoon Jun 3, 2026
99b5107
fix(billing): make workspace topup a pass-through to avoid double bal…
dante01yoon Jun 4, 2026
5efb45b
Merge branch 'main' into jaewon/fe-904-b2-complete-the-billing-facade…
dante01yoon Jun 4, 2026
30e0e0b
feat(billing): add team-plan CreditSlider component (5 fixed stops)
dante01yoon Jun 4, 2026
a0f2445
fix(billing): i18n CreditSlider labels to satisfy no-raw-text lint
dante01yoon Jun 4, 2026
39854ae
feat(billing): align CreditSlider with DES-197 (discount, credit tick…
dante01yoon Jun 5, 2026
71d1ece
test(billing): mock resubscribe via useBillingContext facade
dante01yoon Jun 5, 2026
e1bad82
feat(billing): add UnifiedPricingTable + dispatch behind teamWorkspac…
dante01yoon Jun 5, 2026
dfd08cd
[automated] Apply ESLint and Oxfmt fixes
actions-user Jun 5, 2026
f25ef17
feat(billing): add UnifiedPricingTable stories + initialPlanMode prop
dante01yoon Jun 5, 2026
a013d4b
test(storybook): mock useBillingContext so UnifiedPricingTable renders
dante01yoon Jun 5, 2026
6cadc4e
feat(billing): align CreditSlider price + Save badge with DES-197, an…
dante01yoon Jun 5, 2026
72507cf
fix(billing): keep CreditSlider price on one row, wrap the Save badge…
dante01yoon Jun 5, 2026
2fd8f68
feat(billing): make CreditSlider stops prop-driven (stops + defaultSt…
dante01yoon Jun 5, 2026
ff4a690
fix(billing): clamp CreditSlider fallback index, add disabled-state test
dante01yoon Jun 8, 2026
7c4ffb3
Merge branch 'jaewon/fe-935-team-plan-credit-slider' into jaewon/fe-9…
dante01yoon Jun 9, 2026
0c6ca27
feat(billing): close DES-197 design gaps in UnifiedPricingTable (FE-934)
dante01yoon Jun 9, 2026
8b5e7d4
fix(billing): match DES-197 dialog surfaces + personal price unit
dante01yoon Jun 9, 2026
ff628e4
fix(billing): expose raw ISO dates from the legacy billing adapter
dante01yoon Jun 10, 2026
4b3b6a8
test(billing): cover facade resubscribe/topup per review
dante01yoon Jun 10, 2026
f737d9b
feat(billing): unify credits into a facade-driven CreditsTile (FE-964)
dante01yoon Jun 9, 2026
e12d3d7
test(billing): e2e for the Plan & Credits CreditsTile (FE-964)
dante01yoon Jun 9, 2026
e4ff4be
feat(billing): finalize CreditsTile layout to DES-247 (FE-964)
dante01yoon Jun 10, 2026
b695686
feat(billing): add DES-247 responsive variants to CreditsTile (FE-964)
dante01yoon Jun 10, 2026
5924dd9
fix(billing): repoint SubscribeButton + PostHog tier to the billing f…
dante01yoon Jun 4, 2026
9e48c13
fix(billing): repoint balance refresh to the facade fetchBalance
dante01yoon Jun 10, 2026
fb6e847
fix(billing): repoint FreeTierDialogContent renewal date to the facade
dante01yoon Jun 10, 2026
b37884c
fix(billing): repoint CurrentUserPopoverLegacy to the billing facade
dante01yoon Jun 10, 2026
261406d
fix(billing): repoint PricingTable subscription state to the facade
dante01yoon Jun 10, 2026
26be182
test(billing): enable workspaces flag via remote config in cloud e2e
dante01yoon Jun 10, 2026
605b685
feat(workspace): redesign Members invite UI to DES-186 (FE-768)
dante01yoon Jun 10, 2026
250a617
feat(billing): align confirm screens to DES-197 β€” drop /member, comfy…
dante01yoon Jun 10, 2026
68a548e
feat(billing): add 'You're all set' success step to unified checkout …
dante01yoon Jun 10, 2026
6f92f38
feat(billing): align workspace Plan & Credits panel to DES-186 (FE-768)
dante01yoon Jun 10, 2026
920e43a
test(billing): storybook stories for checkout confirm/success steps (…
dante01yoon Jun 10, 2026
6898024
fix(workspace): align Members header actions and single-member gating…
dante01yoon Jun 10, 2026
d3f0759
feat(workspace): align switcher popover and copy to DES-246 (FE-769)
dante01yoon Jun 10, 2026
b80768f
test(workspace): cover switcher placement, badge removal, DES-246 copy
dante01yoon Jun 10, 2026
2174f5b
feat(workspace): match create-workspace dialog surface to DES-246
dante01yoon Jun 11, 2026
2ccb689
feat(workspace): promote/demote members via Change role menu (FE-770)
dante01yoon Jun 11, 2026
992da60
feat(billing): add DES-247 empty states to the CreditsTile (FE-964)
dante01yoon Jun 11, 2026
5a7ff04
fix(workspace): raise DropdownMenu above modal z-index sequence (FE-770)
dante01yoon Jun 11, 2026
a7b284c
feat(billing): role-aware run-lock for cancelled/inactive team plans …
dante01yoon Jun 11, 2026
93d6c5c
fix(workspace): drop ghost icon slot for icon-less dropdown items (FE…
dante01yoon Jun 11, 2026
391f9e4
test(billing): e2e regression for facade-driven billing surfaces (FE-…
dante01yoon Jun 11, 2026
4d414ca
fix(billing): route subscription/sign-in/credit preconditions to moda…
dante01yoon Jun 11, 2026
b75ebde
Merge branch 'main' into jaewon/fe-904-b2-complete-the-billing-facade…
DrJKL Jun 11, 2026
99d817d
refactor(billing): remove narration comments per review (FE-904)
dante01yoon Jun 11, 2026
51a064b
fix(billing): refresh workspace billing status after completed top-up…
dante01yoon Jun 11, 2026
ffc8521
refactor(billing): unify cancel-status polling into billingOperationS…
dante01yoon Jun 11, 2026
8fa27a7
feat(billing): downgrade-to-personal member-removal confirm flow (FE-…
dante01yoon Jun 11, 2026
4b7a51e
test(workspace): e2e for member role change user stories (FE-770)
dante01yoon Jun 11, 2026
2ca2360
Merge remote-tracking branch 'origin/jaewon/fe-904-b2-complete-the-bi…
dante01yoon Jun 11, 2026
85eb4ea
Merge remote-tracking branch 'origin/jaewon/fe-964-build-unified-cred…
dante01yoon Jun 11, 2026
e90b261
Merge remote-tracking branch 'origin/jaewon/fe-768-plan-credits-panel…
dante01yoon Jun 11, 2026
c06bb29
Merge remote-tracking branch 'origin/jaewon/fe-768-members-invite-ui'…
dante01yoon Jun 11, 2026
ac3e816
Merge remote-tracking branch 'origin/jaewon/fe-770-promote-demote-wor…
dante01yoon Jun 11, 2026
edfe2e6
Merge remote-tracking branch 'origin/jaewon/fe-934-unified-pricing-ta…
dante01yoon Jun 11, 2026
a2b84ec
Merge remote-tracking branch 'origin/jaewon/fe-769-updates-to-misc-ux…
dante01yoon Jun 11, 2026
2199864
Merge remote-tracking branch 'origin/jaewon/fe-932-refresh-workspace-…
dante01yoon Jun 11, 2026
1ac4f27
Merge remote-tracking branch 'origin/jaewon/fe-970-b8-unify-the-two-b…
dante01yoon Jun 11, 2026
5d882c6
fix(billing): void floating startOperation promise after FE-932/FE-97…
dante01yoon Jun 11, 2026
cca62e7
Merge remote-tracking branch 'origin/jaewon/fe-978-team-plan-cancel-i…
dante01yoon Jun 11, 2026
1b187e8
Merge remote-tracking branch 'origin/jaewon/fe-878-bug-subscription-r…
dante01yoon Jun 11, 2026
271d3ea
Merge remote-tracking branch 'origin/jaewon/fe-977-team-plan-downgrad…
dante01yoon Jun 11, 2026
bd46941
fix(billing): always settle the billing op terminal promise (FE-970)
dante01yoon Jun 11, 2026
594145d
fix(billing): validate and complete the downgrade subscribe flow (FE-…
dante01yoon Jun 11, 2026
64b4410
fix(billing): align plan-change confirm to DES-197 β€” equal plan colum…
dante01yoon Jun 11, 2026
c7da424
feat(billing): render team 'Confirm your payment' step from the slide…
dante01yoon Jun 11, 2026
1ce8c58
fix(billing): harden downgrade fast-path and payment-tab failure mode…
dante01yoon Jun 11, 2026
61085d5
Merge remote-tracking branch 'origin/main' into jaewon/fe-934-unified…
dante01yoon Jun 12, 2026
e00b8cf
docs(billing): tighten FE-977 downgrade comments
dante01yoon Jun 12, 2026
bdfd94d
test(billing): cover cancel dialog error/success flow (FE-970)
dante01yoon Jun 12, 2026
5248add
Merge remote-tracking branch 'origin/jaewon/fe-768-members-invite-ui'…
dante01yoon Jun 12, 2026
cd48dc9
feat(billing): inline "Invite your team" block on team-upgrade succes…
dante01yoon Jun 12, 2026
11b5460
test(workspace): isolate member-panel test refs + use owner fixtures …
dante01yoon Jun 12, 2026
c5fd2a4
test(billing): type checkout-step story fixtures to the preview contr…
dante01yoon Jun 12, 2026
893d734
Merge commit 'e7e60537a5' into jaewon/fe-991-e2e-integration-pass-for…
dante01yoon Jun 12, 2026
e2f48b6
Merge commit 'a7734f1734' into jaewon/fe-991-e2e-integration-pass-for…
dante01yoon Jun 12, 2026
ef1d629
Merge commit 'dfac66a2bc' into jaewon/fe-991-e2e-integration-pass-for…
dante01yoon Jun 12, 2026
5681b5d
Merge commit 'cebae667ce' into jaewon/fe-991-e2e-integration-pass-for…
dante01yoon Jun 12, 2026
232310e
Merge commit '853c1164ba' into jaewon/fe-991-e2e-integration-pass-for…
dante01yoon Jun 12, 2026
9c6dd9c
fix(billing): place struck 'before' price to the right of the current…
dante01yoon Jun 12, 2026
8526c5c
feat(billing): add Yearly/Monthly toggle to the team plan (FE-934)
dante01yoon Jun 12, 2026
4e596e5
test(billing): in-app mock harness for preview testing (FE-991, do no…
dante01yoon Jun 12, 2026
c9b77dd
feat(billing): sync FE-934 fixes into the integration preview
dante01yoon Jun 12, 2026
b1d5ff8
Merge branch 'main' into jaewon/fe-934-unified-pricing-table
dante01yoon Jun 12, 2026
6583e65
feat(workspace): creator-only canManageSubscriptionLifecycle permissi…
dante01yoon Jun 13, 2026
d8774b7
refactor(workspace): address Members invite UI review feedback (FE-768)
dante01yoon Jun 13, 2026
b4ee092
fix(workspace): pass is_creator through the shared type + auth schema…
dante01yoon Jun 13, 2026
548e260
fix(billing): apply DES QA polish to the unified pricing table (FE-934)
dante01yoon Jun 13, 2026
9e7043e
feat(billing): sync DES QA polish into the integration preview (FE-991)
dante01yoon Jun 14, 2026
dc6c48c
fix(billing): route queue paywall (402) to modal, out of error panel …
dante01yoon Jun 15, 2026
f8993d2
Merge branch 'main' into jaewon/fe-878-bug-subscription-required-erro…
dante01yoon Jun 15, 2026
af110fc
fix(billing): set free tier max runtime to 10 min per DES 3253-16079 …
dante01yoon Jun 15, 2026
1c97eb0
fix(billing): DES QA polish on the unified pricing table (FE-934)
dante01yoon Jun 17, 2026
d9f5442
fix(billing): complete the storybook BillingContext mock (FE-934)
dante01yoon Jun 17, 2026
4fd8acc
fix(billing): DES QA polish on the unified pricing table (FE-934)
dante01yoon Jun 17, 2026
76422f6
fix(billing): address DES pricing-table link feedback (FE-934)
dante01yoon Jun 17, 2026
a7c8f3a
fix(billing): drop underline on the pricing footnote "see details" li…
dante01yoon Jun 17, 2026
9ef8266
fix(billing): address DES pricing-table link feedback (FE-934)
dante01yoon Jun 17, 2026
5261bb3
fix(billing): drop underline on the pricing footnote "see details" li…
dante01yoon Jun 17, 2026
75131c2
refactor(billing): drop unused precedence helper, reuse RuntimeErrorI…
dante01yoon Jun 17, 2026
c0f3f6f
fix(billing): inactive plan-scope tab = active tab at 50% opacity (FE…
dante01yoon Jun 17, 2026
1231e8d
fix(billing): inactive plan-scope tab = active tab at 50% opacity (FE…
dante01yoon Jun 17, 2026
e2b67ec
fix(billing-mock): include created_at/joined_at in mock workspaces
dante01yoon Jun 17, 2026
19fb019
fix(billing): credits tile DES QA polish (FE-964)
dante01yoon Jun 17, 2026
1473639
fix(billing): workspace plan panel DES QA (FE-768)
dante01yoon Jun 17, 2026
564255f
fix(billing): truncate long workspace names in the switcher (FE-769)
dante01yoon Jun 17, 2026
6f2ed14
fix(billing): pricing dialog opens on the matching plan tab (FE-934)
dante01yoon Jun 17, 2026
785f1bb
fix(billing): keep default padding on the view-more link (FE-768)
dante01yoon Jun 17, 2026
071780c
fix(billing): update promote-to-owner dialog to DES design (FE-770)
dante01yoon Jun 17, 2026
33495bd
fix(workspace): unify the workspace menu onto the shared DropdownMenu…
dante01yoon Jun 17, 2026
65f5c02
fix(billing): pricing dialog opens on the matching plan tab (FE-934)
dante01yoon Jun 17, 2026
766c6de
fix(billing): workspace plan panel DES QA (FE-768)
dante01yoon Jun 17, 2026
1bc10fa
docs(workspace): mark is_creator shape confirmed by BE (FE-770)
dante01yoon Jun 17, 2026
341c846
fix(billing): also shrink the switcher row button so the name truncat…
dante01yoon Jun 17, 2026
881cf3a
fix(billing): size the members more-options button to match Invite (F…
dante01yoon Jun 17, 2026
e30d35e
fix(billing): size the members more-options button to match Invite (F…
dante01yoon Jun 17, 2026
8c098ee
docs(workspace): note generated ingest-types swap once is_creator shi…
dante01yoon Jun 17, 2026
98e558c
Merge remote-tracking branch 'origin/main' into jaewon/fe-934-unified…
dante01yoon Jun 17, 2026
a0b254b
[automated] Apply ESLint and Oxfmt fixes
actions-user Jun 17, 2026
2f3a827
Merge FE-770 promote-dialog DES update into fe-991 integration
dante01yoon Jun 17, 2026
9a3bad3
Merge FE-768 menu-unify + more-options button size into fe-991 integr…
dante01yoon Jun 17, 2026
0c8a8af
fix(billing): gate members panel on team-plan subscription, not tier …
dante01yoon Jun 17, 2026
c4871bf
fix(billing): gate members panel on team-plan subscription, not tier …
dante01yoon Jun 17, 2026
3727085
fix(billing): let members and non-creator owners leave from Plan & Cr…
dante01yoon Jun 17, 2026
96ac29b
docs(workspace): reword ingest-types TODO without PR-scoped phrasing …
dante01yoon Jun 18, 2026
93bb2a0
fix(workspace): block changing the workspace creator's role (FE-770)
dante01yoon Jun 18, 2026
81e0bd0
fix(workspace): let non-creator owners leave; show creator's Leave di…
dante01yoon Jun 18, 2026
55c0090
fix(billing): show the creator's Leave option disabled, not hidden (F…
dante01yoon Jun 18, 2026
0f64551
Merge branch 'jaewon/fe-768-members-invite-ui' into jaewon/fe-770-pro…
dante01yoon Jun 18, 2026
a51183a
fix(workspace): gate creator lifecycle on members-list original owner…
dante01yoon Jun 18, 2026
66d0b77
feat(billing): route personal subscription-required through preview c…
dante01yoon Jun 18, 2026
e1f2514
feat(workspace): back row-lock with Member.is_original_owner (FE-770)
dante01yoon Jun 18, 2026
ec3dcf1
feat(billing): gate cancel/reactivate to the original owner (FE-978)
dante01yoon Jun 13, 2026
6711b3d
feat(workspace): protect only original owner on downgrade to personal…
dante01yoon Jun 18, 2026
c31774b
fix(billing): set workspace name heading to font-weight 600 (FE-768)
dante01yoon Jun 18, 2026
917f1e8
Merge remote-tracking branch 'origin/jaewon/fe-770-promote-demote-wor…
dante01yoon Jun 18, 2026
3a480d1
Merge remote-tracking branch 'origin/jaewon/fe-978-owner-lifecycle-ga…
dante01yoon Jun 18, 2026
0913c88
Merge remote-tracking branch 'origin/jaewon/fe-977-team-plan-downgrad…
dante01yoon Jun 18, 2026
0dea348
test(billing): reflect is_original_owner repoint into FE-991 integrat…
dante01yoon Jun 18, 2026
2fb9313
fix(workspace): fail-closed creator guard + optional is_original_owne…
dante01yoon Jun 18, 2026
0092a45
fix(workspace): type is_original_owner as optional to match the BE co…
dante01yoon Jun 18, 2026
53b77ad
fix(billing): fail-closed downgrade member-removal + optional is_orig…
dante01yoon Jun 18, 2026
83e269a
feat(billing): gate cancel/reactivate to the original owner (FE-978)
dante01yoon Jun 13, 2026
5e17feb
Merge remote-tracking branch 'origin/jaewon/fe-770-promote-demote-wor…
dante01yoon Jun 18, 2026
2a05922
Merge remote-tracking branch 'origin/jaewon/fe-978-owner-lifecycle-ga…
dante01yoon Jun 18, 2026
1984d57
Merge remote-tracking branch 'origin/jaewon/fe-977-team-plan-downgrad…
dante01yoon Jun 18, 2026
e8e5333
fix(billing): keep successful personal subscribe when refresh fails
dante01yoon Jun 18, 2026
675d04a
test(workspace): fix stale promote-dialog copy assertions (FE-770)
dante01yoon Jun 18, 2026
ba72b5c
fix(billing): keep successful team subscribe when post-write refresh …
dante01yoon Jun 18, 2026
68de563
Merge remote-tracking branch 'origin/main' into jaewon/fe-991-e2e-int…
dante01yoon Jun 18, 2026
9968380
Merge remote-tracking branch 'origin/jaewon/fe-770-promote-demote-wor…
dante01yoon Jun 18, 2026
ffc7643
test(billing): replace double type-cast with typed preview fixture
dante01yoon Jun 18, 2026
bd95849
[automated] Apply ESLint and Oxfmt fixes
actions-user Jun 18, 2026
83f3ee6
feat(billing): collapse billing dispatch to flag-only single path (B1…
dante01yoon Jun 18, 2026
56e5e29
fix(billing): gate personal billing cutover on a backend-readiness fl…
dante01yoon Jun 18, 2026
1200108
merge: stack FE-967 on FE-966 single billing path
dante01yoon Jun 18, 2026
7ce3276
refactor(billing): drop personal legacy->workspace delegation, supers…
dante01yoon Jun 18, 2026
08f4b0f
fix(billing): validate topup amount in the integration preview (FE-991)
dante01yoon Jun 18, 2026
eced564
merge: team subscribe allSettled (#12951) into FE-991 integration
dante01yoon Jun 18, 2026
0234944
merge: FE-967 personal dialog UX + FE-966 single billing path into FE…
dante01yoon Jun 18, 2026
666f2a3
merge: re-sync FE-934 unified pricing table tip (#12666) into FE-991
dante01yoon Jun 18, 2026
145ffd4
merge: re-sync FE-878 precondition routing tip (#12785) into FE-991
dante01yoon Jun 18, 2026
195d244
feat: source usage history from /api/billing/events behind teamWorksp…
dante01yoon Jun 18, 2026
759e3e2
merge: FE-969 billing-history /api/billing/events (#12955) into FE-991
dante01yoon Jun 18, 2026
6183bc5
merge: FE-768 plan-credits tip into FE-991 (creator-only cancel recon…
dante01yoon Jun 18, 2026
54b869d
fix(billing): drop member count from enterprise upsell copy (FE-934)
dante01yoon Jun 19, 2026
18eced3
fix(billing): open team pricing tab from Upgrade to Team CTAs (FE-934)
dante01yoon Jun 19, 2026
e804967
feat(billing): wire team-plan subscribe to BE-1254 credit-stop contract
dante01yoon Jun 19, 2026
c1b42b2
fix(billing): invite dialog sizing/copy, cancel-sub copy, members Con…
dante01yoon Jun 19, 2026
739b873
fix(billing): show the cycle-discounted team price in the confirm step
dante01yoon Jun 19, 2026
3b07b5e
Merge branch 'main' into jaewon/fe-966-b1-single-billing-path-drop-is…
dante01yoon Jun 19, 2026
a5781c4
Merge remote-tracking branch 'origin/jaewon/fe-934-unified-pricing-ta…
dante01yoon Jun 19, 2026
a4e53bd
test(billing): reinitialize billing when resolved type flips at runtime
dante01yoon Jun 19, 2026
9fe12cf
fix(billing): reinitialize billing context when billing type flips at…
dante01yoon Jun 19, 2026
0073063
fix(billing): drop unused exports and mock subscription dialog in mem…
dante01yoon Jun 19, 2026
2b642e7
Merge branch 'main' into jaewon/fe-966-b1-single-billing-path-drop-is…
dante01yoon Jun 19, 2026
74799d2
test(billing): assert reinit from a settled legacy init
dante01yoon Jun 19, 2026
88133b0
merge: team-subscribe credit-stop wire (#12975) into FE-991 integration
dante01yoon Jun 19, 2026
f528e6b
merge: FE-966 latest (#12953) into FE-991 integration
dante01yoon Jun 19, 2026
b2b1fe8
fix(ui): stack DropdownMenu popover above modal dialogs (FE-768)
dante01yoon Jun 19, 2026
757156b
fix(billing): keep pricing dialog size constant across plan toggle (F…
dante01yoon Jun 19, 2026
75da921
chore(billing): remove preview billing mock harness
dante01yoon Jun 19, 2026
b86f24b
merge: FE-768 members-invite-ui latest (#12759) into FE-991 integration
dante01yoon Jun 19, 2026
2bbbf65
fix(billing): align yearly checkout confirm to updated Figma (FE-934)
dante01yoon Jun 19, 2026
6389549
fix(billing): preserve pricing-table selection on back, add Backspace…
dante01yoon Jun 19, 2026
17bea9d
merge: FE-934 yearly confirm + back-nav/Backspace fixes into FE-991 i…
dante01yoon Jun 19, 2026
912320b
feat(workspace): reactivate-vs-upgrade copy for lapsed team plans (FE…
dante01yoon Jun 19, 2026
47ec1de
fix(test): use namespace type import for vi.mock importOriginal
Jun 19, 2026
a3858b3
feat(billing): single-plan plan-change confirm + monthly billed note …
dante01yoon Jun 19, 2026
e3c3473
fix(billing): tertiary CTA surface + correct success check color (FE-…
dante01yoon Jun 19, 2026
6ec0f33
[automated] Apply ESLint and Oxfmt fixes
actions-user Jun 19, 2026
78dcc16
fix(billing): repoint FE-965 team-success story to renamed creator fi…
dante01yoon Jun 19, 2026
a0c7127
refactor(workspace): move members preload into store ensureMembersLoaded
dante01yoon Jun 19, 2026
2b9dd72
fix(workspace): only preload members for team workspaces
dante01yoon Jun 19, 2026
6c3856d
feat(billing): deep link to open the pricing table (FE-1104)
dante01yoon Jun 19, 2026
ab082bf
test(billing): add @cloud e2e for the pricing deep link (FE-1104)
dante01yoon Jun 19, 2026
fd79281
fix(billing): await members fetch before the deep-link gate (FE-1104)
dante01yoon Jun 19, 2026
0574c29
feat(billing): inline "Invite your team" block on team-upgrade succes…
dante01yoon Jun 19, 2026
b6909e3
chore(preview): pin backend to pr-4393 ephemeral env [do not merge]
dante01yoon Jun 19, 2026
0ebf361
chore(preview): repoint backend pin to pr-4378 ephemeral env [do not …
dante01yoon Jun 20, 2026
67ea86e
fix(billing): reopen team pricing tab from Members Upgrade to Team (F…
dante01yoon Jun 20, 2026
29df154
feat(billing): remove Next month invoice card from Plan & Credits pan…
dante01yoon Jun 20, 2026
de466b7
Merge FE-768 plan-credits tip (remove Next month invoice card) into F…
dante01yoon Jun 20, 2026
9a0becf
test(billing): drop invoice-card assertions after card removal (FE-768)
dante01yoon Jun 20, 2026
eef3d73
Merge FE-768 test fix (invoice-card assertions) into FE-991 integration
dante01yoon Jun 20, 2026
dafcf20
feat(billing): surface team_credit_stops + drive CreditsTile monthly …
dante01yoon Jun 20, 2026
fc18ae7
feat(billing): price team Plan & Credits header from subscribed credi…
dante01yoon Jun 20, 2026
2d12005
feat(billing): disable the active team stop in the pricing slider; ca…
dante01yoon Jun 20, 2026
2985298
fix(billing): gate team CTA on current stop (Current plan/Change plan…
dante01yoon Jun 20, 2026
456cf72
fix(billing): keep both credits-row buttons inside the user popover
dante01yoon Jun 20, 2026
3d228e3
fix(billing): cancelled team sub on a different stop reads Change pla…
dante01yoon Jun 20, 2026
13ca482
fix(billing): show the checkout success page after team/async subscri…
dante01yoon Jun 20, 2026
d29a0b4
fix(billing): match team-upgrade invite block to Figma (FE-965)
dante01yoon Jun 20, 2026
09dd1f4
feat(billing): role-gate Plan & Credits menu and action buttons (FE-768)
dante01yoon Jun 21, 2026
d526bcd
feat(billing): route personal-workspace team-plan pick to workspace c…
dante01yoon Jun 21, 2026
4e60999
test(billing): harden personalβ†’team gate test against cold-run emit r…
dante01yoon Jun 21, 2026
7e779de
feat(billing): lock team credit-stop change once subscribed (FE-934)
dante01yoon Jun 22, 2026
fe46beb
feat(billing): keep legacy team subscribers on the per-member team pr…
dante01yoon Jun 22, 2026
f746534
feat(billing): add planType + subscriptionLock to the billing facade …
dante01yoon Jun 22, 2026
9745e4d
feat(billing): lock cross-plan transitions in the unified pricing tab…
dante01yoon Jun 22, 2026
93c6d26
fix(billing): lock team billing-cycle change at the current stop (FE-…
dante01yoon Jun 22, 2026
e904ba9
feat(billing): allow all plan transitions + drop personal->team rerou…
dante01yoon Jun 23, 2026
23ffc89
chore(billing): sync pricing deep-link loader to FE-1104 latest
dante01yoon Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ const config: StorybookConfig = {
find: '@/composables/queue/useJobActions',
replacement: process.cwd() + '/src/storybook/mocks/useJobActions.ts'
},
{
find: '@/composables/billing/useBillingContext',
replacement:
process.cwd() + '/src/storybook/mocks/useBillingContext.ts'
},
{
find: '@/composables/useFeatureFlags',
replacement:
process.cwd() + '/src/storybook/mocks/useFeatureFlags.ts'
},
{
find: '@/platform/workspace/stores/teamWorkspaceStore',
replacement:
process.cwd() + '/src/storybook/mocks/teamWorkspaceStore.ts'
},
{
find: '@/utils/formatUtil',
replacement:
Expand Down
8 changes: 4 additions & 4 deletions apps/website/src/components/blocks/FAQSplit01.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ function toggle(index: number) {
<div class="flex flex-col gap-6 md:flex-row md:gap-16">
<!-- Left heading -->
<div
class="bg-primary-comfy-ink sticky top-20 z-10 w-full shrink-0 self-start py-4 md:top-28 md:w-80 md:py-0"
class="sticky top-20 z-10 w-full shrink-0 self-start bg-primary-comfy-ink py-4 md:top-28 md:w-80 md:py-0"
>
<h2 class="text-primary-comfy-canvas text-4xl font-light md:text-5xl">
<h2 class="text-4xl font-light text-primary-comfy-canvas md:text-5xl">
{{ heading }}
</h2>
</div>
Expand All @@ -42,7 +42,7 @@ function toggle(index: number) {
<div
v-for="(faq, index) in faqs"
:key="faq.id"
class="border-primary-comfy-canvas/20 border-b"
class="border-b border-primary-comfy-canvas/20"
>
<button
:id="`faq-trigger-${faq.id}`"
Expand Down Expand Up @@ -83,7 +83,7 @@ function toggle(index: number) {
:aria-labelledby="`faq-trigger-${faq.id}`"
class="pb-6"
>
<p class="text-primary-comfy-canvas/70 text-sm whitespace-pre-line">
<p class="text-sm whitespace-pre-line text-primary-comfy-canvas/70">
{{ faq.answer }}
</p>
</section>
Expand Down
2 changes: 1 addition & 1 deletion apps/website/src/components/common/CallToActionSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const {
<section class="max-w-9xl mx-auto px-6 py-20 lg:py-32">
<div class="flex flex-col items-center text-center">
<h2
class="text-primary-comfy-canvas max-w-5xl text-3xl font-light tracking-tight lg:text-5xl"
class="max-w-5xl text-3xl font-light tracking-tight text-primary-comfy-canvas lg:text-5xl"
>
{{ t(headingKey, locale) }}
</h2>
Expand Down
8 changes: 4 additions & 4 deletions apps/website/src/components/common/EventsSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ const {
<div class="grid grid-cols-1 gap-12 lg:grid-cols-2 lg:gap-16">
<div class="flex flex-col gap-8">
<h2
class="text-primary-comfy-canvas text-4xl font-light tracking-tight lg:text-6xl"
class="text-4xl font-light tracking-tight text-primary-comfy-canvas lg:text-6xl"
>
{{ t(headingKey, locale) }}
</h2>
<p
class="text-primary-comfy-canvas max-w-sm text-sm/relaxed lg:text-base"
class="max-w-sm text-sm/relaxed text-primary-comfy-canvas lg:text-base"
>
{{ t(descriptionKey, locale) }}
</p>
Expand All @@ -66,10 +66,10 @@ const {
v-for="(event, i) in events"
:key="i"
:href="event.href"
class="group border-primary-comfy-canvas/15 flex items-center gap-4 border-b py-6 lg:gap-8"
class="group flex items-center gap-4 border-b border-primary-comfy-canvas/15 py-6 lg:gap-8"
>
<span
class="text-primary-comfy-canvas shrink-0 text-sm font-medium"
class="shrink-0 text-sm font-medium text-primary-comfy-canvas"
>
{{ event.label[locale] }}
</span>
Expand Down
2 changes: 1 addition & 1 deletion apps/website/src/components/common/SiteFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const contactColumn: { title: string; links: FooterLink[] } = {
<template>
<footer
ref="footerRef"
class="bg-primary-comfy-ink text-primary-comfy-canvas px-6 py-8 lg:px-20"
class="bg-primary-comfy-ink px-6 py-8 text-primary-comfy-canvas lg:px-20"
>
<div
class="border-primary-warm-gray grid gap-12 border-t pt-16 lg:grid-cols-2 lg:gap-4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const maskRevealButtonBadgeVariants = cva({
base: 'absolute z-10 flex items-center justify-center rounded-lg transition-all duration-500',
variants: {
variant: {
solid: 'bg-primary-comfy-ink text-primary-comfy-yellow',
solid: 'text-primary-comfy-yellow bg-primary-comfy-ink',
ghost: 'bg-primary-comfy-yellow text-primary-comfy-ink'
},
size: {
Expand Down
2 changes: 1 addition & 1 deletion apps/website/src/components/common/pillButton.variants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const pillButtonBadgeVariants = cva({
base: 'absolute z-10 flex items-center justify-center rounded-lg transition-all duration-500',
variants: {
variant: {
solid: 'bg-primary-comfy-ink text-primary-comfy-yellow',
solid: 'text-primary-comfy-yellow bg-primary-comfy-ink',
ghost: 'bg-primary-comfy-yellow text-primary-comfy-ink'
},
size: {
Expand Down
4 changes: 2 additions & 2 deletions apps/website/src/components/gallery/GalleryCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ defineEmits<{ click: [] }>()
<div class="flex w-full items-end justify-between p-4">
<div class="gap-2">
<p class="text-sm font-bold text-white">{{ item.title }}</p>
<p class="text-primary-comfy-canvas text-xs">
<p class="text-xs text-primary-comfy-canvas">
<GalleryItemAttribution :item :locale />
</p>
</div>
Expand Down Expand Up @@ -82,7 +82,7 @@ defineEmits<{ click: [] }>()
<!-- Mobile metadata -->
<div v-if="mobile" class="mt-2 gap-2">
<p class="text-sm font-bold text-white">{{ item.title }}</p>
<p class="text-primary-comfy-canvas text-xs">
<p class="text-xs text-primary-comfy-canvas">
<GalleryItemAttribution :item :locale />
</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/website/src/components/learning/HeroSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const { locale = 'en' } = defineProps<{ locale?: Locale }>()
class="max-w-9xl mx-auto flex flex-col items-center px-6 pt-24 pb-12 text-center"
>
<h1
class="text-primary-comfy-canvas max-w-4xl text-3xl leading-[110%] font-light tracking-tight lg:text-5xl"
class="max-w-4xl text-3xl leading-[110%] font-light tracking-tight text-primary-comfy-canvas lg:text-5xl"
>
{{ t('learning.heroTitle.before', locale) }}
<span class="text-primary-comfy-yellow">ComfyUI</span
Expand Down
161 changes: 161 additions & 0 deletions browser_tests/tests/billingFacadeConsumers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { expect } from '@playwright/test'
import type { Page } from '@playwright/test'

import type { CloudSubscriptionStatusResponse } from '@/platform/cloud/subscription/composables/useSubscription'
import type { RemoteConfig } from '@/platform/remoteConfig/types'

import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
import { mockSystemStats } from '@e2e/fixtures/data/systemStats'
import { CloudAuthHelper } from '@e2e/fixtures/helpers/CloudAuthHelper'

/**
* Billing facade consumers β€” FE-933 (B3) regression.
*
* The repointed surfaces (avatar popover tier badge / balance, free-tier
* dialog renewal date) must keep rendering from `useBillingContext`, which in
* a personal workspace routes through the legacy `/customers/*` endpoints
* (mocked here). Drives a raw `page` (not the `comfyPage` fixture) so the
* cloud app boots against fully mocked endpoints β€” same pattern as
* creditsTile.spec.ts. `team_workspaces_enabled: false` keeps the topbar on
* the legacy popover variant that FE-933 repointed.
*/
const APP_URL = process.env.PLAYWRIGHT_TEST_URL || 'http://localhost:8188'

const jsonRoute = (body: unknown) => ({
status: 200,
contentType: 'application/json',
body: JSON.stringify(body)
})

async function mockCloudBoot(
page: Page,
subscriptionStatus: CloudSubscriptionStatusResponse,
remoteConfig: RemoteConfig = { team_workspaces_enabled: false }
) {
await page.route('**/api/features', (r) => r.fulfill(jsonRoute(remoteConfig)))
await page.route('**/api/system_stats', (r) =>
r.fulfill(jsonRoute(mockSystemStats))
)
await page.route('**/api/users', (r) =>
r.fulfill(
jsonRoute({
storage: 'server',
migrated: true,
users: { 'test-user-e2e': 'E2E Test User' }
})
)
)
await page.route('**/api/settings', (r) => r.fulfill(jsonRoute({})))
await page.route('**/api/userdata**', (r) => r.fulfill(jsonRoute([])))
await page.route('**/api/extensions', (r) => r.fulfill(jsonRoute([])))
await page.route('**/api/object_info', (r) => r.fulfill(jsonRoute({})))
await page.route('**/api/global_subgraphs', (r) => r.fulfill(jsonRoute({})))
await page.route('**/api/i18n', (r) => r.fulfill(jsonRoute({})))
await page.route('**/api/auth/session', (r) =>
r.fulfill(jsonRoute({ token: 'mock-workspace-token' }))
)
await page.route('**/releases**', (r) => r.fulfill(jsonRoute([])))

// Single personal workspace: keeps the billing facade on the legacy
// `/customers/*` path when team workspaces are enabled.
await page.route('**/api/workspaces', (r) =>
r.fulfill(
jsonRoute({
workspaces: [
{
id: 'ws-personal',
name: 'Personal Workspace',
type: 'personal',
role: 'owner'
}
]
})
)
)

await page.route('**/customers/cloud-subscription-status', (r) =>
r.fulfill(jsonRoute(subscriptionStatus))
)
await page.route('**/customers/balance', (r) =>
r.fulfill(
jsonRoute({
amount_micros: 6000, // -> 12,660 credits
currency: 'usd',
effective_balance_micros: 6000
})
)
)
}

async function bootApp(page: Page) {
const auth = new CloudAuthHelper(page)
await auth.mockAuth()

await page.addInitScript(() => {
localStorage.setItem('Comfy.userId', 'test-user-e2e')
})

await page.goto(APP_URL)
await page.waitForFunction(() => !!window.app?.extensionManager, null, {
timeout: 45_000
})
}

test.describe('Billing facade consumers (FE-933)', { tag: '@cloud' }, () => {
test('avatar popover renders tier badge and balance from the facade', async ({
page
}) => {
test.setTimeout(60_000)

await mockCloudBoot(page, {
is_active: true,
subscription_tier: 'PRO',
subscription_duration: 'MONTHLY',
renewal_date: '2099-02-20T10:00:00Z',
end_date: null
})
await bootApp(page)

await page.getByRole('button', { name: 'Current user' }).click()
const popover = page.locator('.current-user-popover')
await expect(popover).toBeVisible()

await expect(popover.getByText('Pro', { exact: true })).toBeVisible()
await expect(popover.getByText('12,660')).toBeVisible()
await expect(popover.getByTestId('add-credits-button')).toBeVisible()
})

test('free-tier dialog shows the renewal date from the facade', async ({
page
}) => {
test.setTimeout(60_000)

// Subscription gating is config-driven: with subscription_required on,
// the cloud subscription extension calls requireActiveSubscription() at
// boot, which opens the free-tier dialog for an inactive FREE user.
// (refreshRemoteConfig overwrites window.__CONFIG__ from /api/features,
// so the flag must come from the features mock, not an init script.)
// The free-tier dialog branch additionally requires an active personal
// workspace, so this boots with team workspaces enabled (production
// shape) β€” the facade still routes personal through `/customers/*`.
await mockCloudBoot(
page,
{
is_active: false,
subscription_tier: 'FREE',
subscription_duration: 'MONTHLY',
// 10:00Z keeps the en-US calendar date stable across CI timezones.
renewal_date: '2099-02-20T10:00:00Z',
end_date: null
},
{ team_workspaces_enabled: true, subscription_required: true }
)
await bootApp(page)

// T5: the dialog must source the date from facade renewalDate β€” when this
// line read the legacy store it silently vanished for team users.
await expect(
page.getByText('Your credits refresh on Feb 20, 2099.')
).toBeVisible()
})
})
Loading
Loading