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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
fca75df3e2
commit
27b88426e2
@@ -9,7 +9,9 @@ import { DestructiveConfirmDialog, useDestructiveConfirm } from '@/components/ui
|
||||
import { AlertTriangle, Loader2, Upload } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { createClient } from '@/lib/supabase/client'
|
||||
import { useCompany } from '@/contexts/CompanyContext'
|
||||
import { useCompany, useCapability } from '@/contexts/CompanyContext'
|
||||
import { CAPABILITY } from '@/lib/entitlements/keys'
|
||||
import { UpgradeNote } from '@/components/billing/UpgradeNote'
|
||||
import { BankSelector, type Bank } from './BankSelector'
|
||||
import { BankConnectionStatus } from './BankConnectionStatus'
|
||||
import { AccountPickerDialog } from './AccountPickerDialog'
|
||||
@@ -26,6 +28,7 @@ export default function BankingSettingsPanel() {
|
||||
|
||||
const { dialogProps, confirm } = useDestructiveConfirm()
|
||||
const { company } = useCompany()
|
||||
const hasBankSync = useCapability(CAPABILITY.bank_sync)
|
||||
|
||||
const [bankConnections, setBankConnections] = useState<BankConnection[]>([])
|
||||
const [syncingConnectionId, setSyncingConnectionId] = useState<string | null>(null)
|
||||
@@ -464,7 +467,9 @@ export default function BankingSettingsPanel() {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Connect new bank */}
|
||||
{/* Connect new bank. Non-payers keep seeing the card (conversion
|
||||
surface) but the bank list is replaced by an upgrade note: the
|
||||
server gate would 403 the connect anyway. */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Anslut ny bank</CardTitle>
|
||||
@@ -472,6 +477,14 @@ export default function BankingSettingsPanel() {
|
||||
Välj din bank nedan för att koppla ditt konto via PSD2.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
{!hasBankSync ? (
|
||||
<CardContent>
|
||||
<UpgradeNote>
|
||||
Automatisk banksynk kräver ett abonnemang. Du kan fortfarande importera
|
||||
transaktioner manuellt via bankfiler på importsidan.
|
||||
</UpgradeNote>
|
||||
</CardContent>
|
||||
) : (
|
||||
<CardContent className="space-y-4">
|
||||
{/* Account type selector */}
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -515,6 +528,7 @@ export default function BankingSettingsPanel() {
|
||||
connectingBankName={connectingBankName}
|
||||
/>
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* Info about PSD2 */}
|
||||
|
||||
Reference in New Issue
Block a user