feat(billing): make the expired-trial state visible with a clear upgrade path (#1725)
getCompanyEntitlements now derives an entitlementState (trial / trial_expired / lapsed_subscription / paid / none) plus trialExpiredAt from the grants it already fetches, reading company_subscriptions.status inside the existing Promise.all so churned payers get 'abonnemang' copy instead of 'provperiod'. The state threads through CompanyContext and the dashboard layout. Two new surfaces, both hidden in sandbox: - SubscriptionTouchpoint replaces the sidebar trial pill: countdown while the trial runs, a persistent muted upgrade link to /settings/billing once it lapses (visible even collapsed, icon-only with aria-label), and the first mobile bottom-sheet touchpoint. - TrialExpiredDialog: one-time on-entry notice with 'Se abonnemang' and a ghost dismiss; acknowledgement persists per user+company in user_preferences.ui_state.trial_expired_ack (read server-side, no flash), set on dismiss and click-through alike. Narrows the 2026-07-11 'no trial-expired nag' decision at the founder's direction after a user could not find the upgrade path at all; see DECISIONS.md. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
834cc4d0e8
commit
c402421908
@@ -144,8 +144,19 @@
|
||||
"expand_nav": "Expand menu",
|
||||
"members_roles": "Members and roles",
|
||||
"subscription": "Subscription",
|
||||
"trial_expired_cta": "Trial ended · Upgrade",
|
||||
"subscription_lapsed_cta": "Subscription ended · Reactivate",
|
||||
"discord_community": "Discord community"
|
||||
},
|
||||
"trial_expired_dialog": {
|
||||
"title": "Your trial has expired",
|
||||
"title_dated": "Your trial expired {date}",
|
||||
"title_lapsed": "Your subscription has ended",
|
||||
"body_paused": "External connections are paused: the AI assistant, bank sync, Skatteverket and email sending.",
|
||||
"body_free": "Your bookkeeping, invoices and reports are still here and cost nothing.",
|
||||
"cta_primary": "View subscription",
|
||||
"cta_secondary": "Continue without"
|
||||
},
|
||||
"agentKnowledge": {
|
||||
"load_error_title": "Couldn't load the knowledge profile",
|
||||
"load_error_description": "Something went wrong loading what your agent knows. Try reopening this tab.",
|
||||
|
||||
@@ -144,8 +144,19 @@
|
||||
"expand_nav": "Expandera menyn",
|
||||
"members_roles": "Medlemmar och roller",
|
||||
"subscription": "Abonnemang",
|
||||
"trial_expired_cta": "Provperioden är slut · Uppgradera",
|
||||
"subscription_lapsed_cta": "Abonnemanget har avslutats · Aktivera",
|
||||
"discord_community": "Discord-community"
|
||||
},
|
||||
"trial_expired_dialog": {
|
||||
"title": "Din provperiod har löpt ut",
|
||||
"title_dated": "Din provperiod löpte ut {date}",
|
||||
"title_lapsed": "Ditt abonnemang har avslutats",
|
||||
"body_paused": "De externa kopplingarna är pausade: AI-assistenten, bankkopplingen, Skatteverket och e-postutskick.",
|
||||
"body_free": "Bokföringen, fakturorna och rapporterna finns kvar och kostar ingenting.",
|
||||
"cta_primary": "Se abonnemang",
|
||||
"cta_secondary": "Fortsätt utan"
|
||||
},
|
||||
"agentKnowledge": {
|
||||
"load_error_title": "Kunde inte läsa in kunskapsprofilen",
|
||||
"load_error_description": "Något gick fel när det din agent vet skulle läsas in. Försök öppna fliken igen.",
|
||||
|
||||
Reference in New Issue
Block a user