Files
accounted/components/billing/UpgradeNote.tsx
T
Jakob Wennberg 27b88426e2 fix(entitlements): show paid features as gated upsells instead of dead ends (#913)
* fix(entitlements): show paid features as gated upsells instead of dead ends

Post-cutover, non-payers still saw fully interactive UI for paid features
(bank picker, agent-build hero, SKV VAT submission) that silently failed or
403'd on the server gate. Every surface now stays visible as a conversion
surface but is explicitly gated:

- new shared components/billing/UpgradeNote (lock icon + billing link)
- agent-build hero (dashboard + new-user checklist): routes to
  /settings/billing with upgrade copy when the ai capability is missing
- bank connect: BankingSettingsPanel and the import-page PSD2 wizard swap
  the bank list for an upgrade note; the import selection card swaps the
  "Rekommenderat" chip for "Kräver abonnemang"
- VAT report SkatteverketPanel: gated state renders before the
  connection check, so trial-connected companies see the upsell instead
  of action buttons that would 403; manual-filing framing kept
- SkatteverketConnectPanel: skahmst consent note hidden while gated
  (irrelevant until the consent page is reachable)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(ne-bilaga): fix time-of-day flake in SRU field-code assertion

The bare substrings '7310'/'7350' also match the #SKAPAD HHMMSS timestamp
when CI runs at 07:31/07:35, so the assertion now requires the full
'#UPPGIFT <code>' prefix.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-07 10:01:44 +02:00

29 lines
996 B
TypeScript

import Link from 'next/link'
import { Lock } from 'lucide-react'
import { cn } from '@/lib/utils'
/**
* Inline paywall note for a feature that is visible but not entitled.
* The feature stays on screen (conversion surface: never hide, disable
* with an upsell), this note explains why it's disabled and links to
* /settings/billing. Copy mirrors CAPABILITY_BLOCKED_MESSAGE_SV.
*/
export function UpgradeNote({ children, className }: { children?: React.ReactNode; className?: string }) {
return (
<div
className={cn(
'flex items-start gap-2.5 rounded-lg border border-border bg-secondary/40 px-3 py-2.5 text-sm text-muted-foreground',
className,
)}
>
<Lock className="h-4 w-4 mt-0.5 shrink-0" />
<span>
{children ?? 'Den här funktionen kräver ett abonnemang.'}{' '}
<Link href="/settings/billing" className="underline underline-offset-2 text-foreground">
Uppgradera
</Link>
</span>
</div>
)
}