fix: Hide upsell banner if billing is not configured

This commit is contained in:
Dries Augustyns
2025-12-09 08:45:53 +01:00
parent 77089fcdd6
commit 433e796c04
+97 -87
View File
@@ -7,7 +7,7 @@ import {
CardContent, CardContent,
CardDescription, CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle
} from '@plunk/ui'; } from '@plunk/ui';
import {AlertCircle, Mail, Send, TrendingUp, Users} from 'lucide-react'; import {AlertCircle, Mail, Send, TrendingUp, Users} from 'lucide-react';
import {NextSeo} from 'next-seo'; import {NextSeo} from 'next-seo';
@@ -18,11 +18,13 @@ import {QuickStart} from '../components/QuickStart';
import {useActiveProject} from '../lib/contexts/ActiveProjectProvider'; import {useActiveProject} from '../lib/contexts/ActiveProjectProvider';
import {useDashboardStats} from '../lib/hooks/useDashboardStats'; import {useDashboardStats} from '../lib/hooks/useDashboardStats';
import {useProjectSetupState} from '../lib/hooks/useProjectSetupState'; import {useProjectSetupState} from '../lib/hooks/useProjectSetupState';
import {useConfig} from '../lib/hooks/useConfig';
export default function Index() { export default function Index() {
const {activeProject} = useActiveProject(); const {activeProject} = useActiveProject();
const {totalContacts, totalEmailsSent, totalCampaigns, openRate, isLoading} = useDashboardStats(); const {totalContacts, totalEmailsSent, totalCampaigns, openRate, isLoading} = useDashboardStats();
const {setupState, isLoading: isLoadingSetupState} = useProjectSetupState(activeProject?.id); const {setupState, isLoading: isLoadingSetupState} = useProjectSetupState(activeProject?.id);
const {data: config} = useConfig();
const stats = [ const stats = [
{ {
@@ -52,95 +54,103 @@ export default function Index() {
<NextSeo title="Dashboard" /> <NextSeo title="Dashboard" />
<DashboardLayout> <DashboardLayout>
<div className="space-y-8"> <div className="space-y-8">
{/* Project Disabled Banner */} {/* Project Disabled Banner */}
{activeProject && activeProject.disabled && ( {activeProject && activeProject.disabled && (
<Alert variant="destructive"> <Alert variant="destructive">
<AlertCircle className="h-4 w-4" /> <AlertCircle className="h-4 w-4" />
<AlertTitle>Project Disabled - Read-Only Mode</AlertTitle> <AlertTitle>Project Disabled - Read-Only Mode</AlertTitle>
<AlertDescription> <AlertDescription>
This project has been disabled due to security violations (high bounce or complaint rates). All scheduled This project has been disabled due to security violations (high bounce or complaint rates). All
campaigns and workflows have been cancelled. The project is now in read-only mode - you can view your data scheduled campaigns and workflows have been cancelled. The project is now in read-only mode - you can
but cannot create, update, or delete anything. Please contact support to resolve this issue. view your data but cannot create, update, or delete anything. Please contact support to resolve this
</AlertDescription> issue.
</Alert> </AlertDescription>
)} </Alert>
)}
{/* Subscription Warning Banner */} {/* Subscription Warning Banner */}
{activeProject && !activeProject.disabled && !activeProject.subscription && ( {activeProject &&
<Alert variant="warning"> !activeProject.disabled &&
<AlertCircle className="h-4 w-4" /> !activeProject.subscription &&
<AlertTitle>Upgrade to remove Plunk branding</AlertTitle> config?.features.billing.enabled && (
<AlertDescription className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3"> <Alert variant="warning">
<span className="text-sm">Your emails currently include Plunk branding. Upgrade to a subscription to remove it.</span> <AlertCircle className="h-4 w-4" />
<Link href="/settings?tab=billing"> <AlertTitle>Upgrade to remove Plunk branding</AlertTitle>
<Button size="sm" className="w-full sm:w-auto">Upgrade Now</Button> <AlertDescription className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
</Link> <span className="text-sm">
</AlertDescription> Your emails currently include Plunk branding. Upgrade to a subscription to remove it.
</Alert> </span>
)} <Link href="/settings?tab=billing">
<Button size="sm" className="w-full sm:w-auto">
Upgrade Now
</Button>
</Link>
</AlertDescription>
</Alert>
)}
{/* Header */} {/* Header */}
<div> <div>
<h1 className="text-2xl sm:text-3xl font-bold text-neutral-900">Dashboard</h1> <h1 className="text-2xl sm:text-3xl font-bold text-neutral-900">Dashboard</h1>
<p className="text-neutral-500 mt-2 text-sm sm:text-base"> <p className="text-neutral-500 mt-2 text-sm sm:text-base">
Welcome back to {activeProject?.name || 'Plunk'}. Here&apos;s what&apos;s happening with your emails. Welcome back to {activeProject?.name || 'Plunk'}. Here&apos;s what&apos;s happening with your emails.
</p> </p>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{stats.map(stat => {
const Icon = stat.icon;
return (
<Card key={stat.name}>
<CardHeader>
<div className="flex items-center justify-between">
<CardDescription>{stat.name}</CardDescription>
<Icon className="h-4 w-4 text-neutral-500" />
</div>
<CardTitle className="text-2xl">{stat.value}</CardTitle>
</CardHeader>
</Card>
);
})}
</div>
{/* Quick Actions & API Keys */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Quick Start */}
<QuickStart setupState={setupState} isLoading={isLoadingSetupState} />
{/* API Keys */}
<Card>
<CardHeader>
<CardTitle>API Keys</CardTitle>
<CardDescription>Use these keys to integrate with Plunk</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{activeProject ? (
<>
<ApiKeyDisplay
label="Public Key"
value={activeProject.public}
description="Use this key for client-side integrations"
/>
<ApiKeyDisplay
label="Secret Key"
value={activeProject.secret}
description="Keep this key secure and never expose it publicly"
isSecret
/>
</>
) : (
<p className="text-sm text-neutral-500">No project selected</p>
)}
</div>
</CardContent>
</Card>
</div>
</div> </div>
</DashboardLayout>
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{stats.map(stat => {
const Icon = stat.icon;
return (
<Card key={stat.name}>
<CardHeader>
<div className="flex items-center justify-between">
<CardDescription>{stat.name}</CardDescription>
<Icon className="h-4 w-4 text-neutral-500" />
</div>
<CardTitle className="text-2xl">{stat.value}</CardTitle>
</CardHeader>
</Card>
);
})}
</div>
{/* Quick Actions & API Keys */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Quick Start */}
<QuickStart setupState={setupState} isLoading={isLoadingSetupState} />
{/* API Keys */}
<Card>
<CardHeader>
<CardTitle>API Keys</CardTitle>
<CardDescription>Use these keys to integrate with Plunk</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{activeProject ? (
<>
<ApiKeyDisplay
label="Public Key"
value={activeProject.public}
description="Use this key for client-side integrations"
/>
<ApiKeyDisplay
label="Secret Key"
value={activeProject.secret}
description="Keep this key secure and never expose it publicly"
isSecret
/>
</>
) : (
<p className="text-sm text-neutral-500">No project selected</p>
)}
</div>
</CardContent>
</Card>
</div>
</div>
</DashboardLayout>
</> </>
); );
} }