B2C/B2B split: DEFAULT_USER_TIER, ALLOWED_DOMAINS, zero-price filter, InboxRescue branding & pricing page

Agent-Logs-Url: https://github.com/christianlouis/pop_puller_to_gmail/sessions/98c1f90b-0287-4908-a0be-ad066c453cc5

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-26 16:10:39 +00:00
parent 53334402aa
commit d4aa353383
8 changed files with 237 additions and 70 deletions
+2 -2
View File
@@ -14,8 +14,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "POP3 Forwarder - Automatic Email Forwarding to Gmail",
description: "Forward your POP3 emails to Gmail automatically with our secure and reliable service",
title: "InboxRescue — your old inboxes, delivered to Gmail",
description: "Poll your legacy POP3 and IMAP mailboxes and have everything land quietly in Gmail. Set it once, forget it exists.",
};
export default function RootLayout({
+124 -39
View File
@@ -4,8 +4,61 @@ import { useEffect } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { useAuthStore } from '@/store/authStore';
import { userApi } from '@/lib/api';
import { Mail, ArrowRight, Shield, Zap, Clock } from 'lucide-react';
import { userApi, SubscriptionPlan } from '@/lib/api';
import { useQuery } from '@tanstack/react-query';
import api from '@/lib/api';
import { Mail, ArrowRight, Shield, Zap, Clock, Check } from 'lucide-react';
async function fetchPublicPlans(): Promise<SubscriptionPlan[]> {
const res = await api.get<SubscriptionPlan[]>('/subscriptions/plans');
return res.data;
}
function PricingCard({ plan }: { plan: SubscriptionPlan }) {
const yearlyMonthly = plan.price_yearly
? (plan.price_yearly / 12).toFixed(2)
: null;
return (
<div className="bg-white rounded-xl shadow-md p-8 flex flex-col border border-gray-100 hover:shadow-lg transition-shadow">
<h3 className="text-xl font-bold text-gray-900">{plan.name}</h3>
<p className="mt-2 text-sm text-gray-500 flex-1">{plan.description}</p>
<div className="mt-6">
<span className="text-4xl font-extrabold text-gray-900">
{plan.price_monthly.toFixed(2)}
</span>
<span className="text-gray-500">/month</span>
{yearlyMonthly && (
<p className="text-xs text-green-600 mt-1">
or {yearlyMonthly}/mo billed yearly ({plan.price_yearly?.toFixed(2)})
</p>
)}
</div>
<ul className="mt-6 space-y-2 text-sm text-gray-600">
<li className="flex items-center gap-2">
<Check className="h-4 w-4 text-green-500 shrink-0" />
{plan.max_mail_accounts === 1
? '1 mailbox'
: `Up to ${plan.max_mail_accounts} mailboxes`}
</li>
<li className="flex items-center gap-2">
<Check className="h-4 w-4 text-green-500 shrink-0" />
Checked every {plan.check_interval_minutes} minute{plan.check_interval_minutes > 1 ? 's' : ''}
</li>
<li className="flex items-center gap-2">
<Check className="h-4 w-4 text-green-500 shrink-0" />
Up to {plan.max_emails_per_day.toLocaleString()} emails/day
</li>
</ul>
<Link
href="/register"
className="mt-8 block text-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium"
>
Get started
</Link>
</div>
);
}
export default function Home() {
const router = useRouter();
@@ -29,6 +82,12 @@ export default function Home() {
});
}, [router, setUser, setLoading]);
const { data: plans } = useQuery({
queryKey: ['public-plans'],
queryFn: fetchPublicPlans,
staleTime: 5 * 60 * 1000,
});
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
@@ -37,6 +96,8 @@ export default function Home() {
);
}
const hasPaidPlans = plans && plans.length > 0;
return (
<div className="min-h-screen bg-gradient-to-b from-blue-50 to-white">
{/* Header */}
@@ -45,7 +106,7 @@ export default function Home() {
<div className="flex justify-between items-center py-4">
<div className="flex items-center">
<Mail className="h-8 w-8 text-blue-600 mr-2" />
<h1 className="text-2xl font-bold text-gray-900">POP3 Forwarder</h1>
<h1 className="text-2xl font-bold text-gray-900">InboxRescue</h1>
</div>
<div className="flex items-center gap-4">
<Link
@@ -58,31 +119,37 @@ export default function Home() {
href="/register"
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
>
Sign Up
Sign Up Free
</Link>
</div>
</div>
</div>
</header>
{/* Hero Section */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
{/* Hero */}
<div className="text-center">
<h2 className="text-4xl sm:text-5xl font-bold text-gray-900 mb-6">
Forward Your POP3 Emails to Gmail
<br />
<span className="text-blue-600">Automatically</span>
Your old inboxes,{' '}
<span className="text-blue-600">delivered to Gmail.</span>
</h2>
<p className="text-xl text-gray-600 mb-8 max-w-2xl mx-auto">
Connect your POP3 email accounts and automatically forward all messages to Gmail.
Simple, secure, and reliable email forwarding service.
<p className="text-xl text-gray-600 mb-4 max-w-2xl mx-auto">
You know the ones that GMX account from 2009, the old ISP address your
bank still sends to, the Hotmail you gave out in school. InboxRescue
quietly polls them all and drops everything into your Gmail. Set it once,
forget it exists.
</p>
<div className="flex items-center justify-center gap-4">
<p className="text-base text-gray-500 mb-8 max-w-xl mx-auto">
No forwarding rules to configure. No email clients to keep open.
Just your mail, where you actually read it.
</p>
<div className="flex items-center justify-center gap-4 flex-wrap">
<Link
href="/register"
className="flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-lg font-medium"
>
Get Started Free
Get Started it&apos;s free
<ArrowRight className="ml-2 h-5 w-5" />
</Link>
<Link
@@ -101,11 +168,11 @@ export default function Home() {
<Zap className="h-6 w-6" />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2">
Auto-Detection
Auto-detects everything
</h3>
<p className="text-gray-600">
Automatically detect POP3 server settings from your email address.
Quick and easy setup in minutes.
Type your old email address and InboxRescue figures out the server
settings. No Googling port numbers required.
</p>
</div>
@@ -114,11 +181,11 @@ export default function Home() {
<Clock className="h-6 w-6" />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2">
Scheduled Checks
Runs in the background
</h3>
<p className="text-gray-600">
Set custom check intervals for each account. From every minute to once a day,
you control the frequency.
Checks your old inboxes on a schedule you choose from every minute
to once a day. New mail appears in Gmail as if it was always there.
</p>
</div>
@@ -127,11 +194,11 @@ export default function Home() {
<Shield className="h-6 w-6" />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2">
Secure & Private
Your passwords stay yours
</h3>
<p className="text-gray-600">
Your credentials are encrypted and secure. We use SSL/TLS for all connections
and OAuth2 for Gmail.
Credentials are encrypted at rest and never shared. All connections
use SSL/TLS and Gmail delivery uses OAuth2 no app passwords needed.
</p>
</div>
</div>
@@ -139,53 +206,71 @@ export default function Home() {
{/* How It Works */}
<div className="mt-20">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-12">
How It Works
Three steps and you&apos;re done
</h3>
<div className="grid md:grid-cols-3 gap-8">
<div className="text-center">
<div className="flex items-center justify-center h-16 w-16 rounded-full bg-blue-100 text-blue-600 text-2xl font-bold mx-auto mb-4">
1
</div>
<h4 className="text-xl font-semibold text-gray-900 mb-2">
Connect Accounts
</h4>
<h4 className="text-xl font-semibold text-gray-900 mb-2">Add your old inbox</h4>
<p className="text-gray-600">
Add your POP3 email accounts with auto-detected settings
Paste the email address InboxRescue auto-detects the POP3/IMAP
settings in seconds.
</p>
</div>
<div className="text-center">
<div className="flex items-center justify-center h-16 w-16 rounded-full bg-blue-100 text-blue-600 text-2xl font-bold mx-auto mb-4">
2
</div>
<h4 className="text-xl font-semibold text-gray-900 mb-2">
Authorize Gmail
</h4>
<h4 className="text-xl font-semibold text-gray-900 mb-2">Connect Gmail</h4>
<p className="text-gray-600">
Sign in with Google to allow forwarding to your Gmail
Sign in with Google once. InboxRescue delivers mail directly into
your inbox using the Gmail API no SMTP relay needed.
</p>
</div>
<div className="text-center">
<div className="flex items-center justify-center h-16 w-16 rounded-full bg-blue-100 text-blue-600 text-2xl font-bold mx-auto mb-4">
3
</div>
<h4 className="text-xl font-semibold text-gray-900 mb-2">
Relax & Enjoy
</h4>
<h4 className="text-xl font-semibold text-gray-900 mb-2">Close the tab</h4>
<p className="text-gray-600">
Emails are automatically forwarded. Monitor activity from your dashboard
Seriously, that&apos;s it. Your mail arrives automatically from now on.
Check the dashboard whenever you like, but you won&apos;t need to.
</p>
</div>
</div>
</div>
{/* Pricing — only rendered when paid plans exist (hidden in enterprise/all-free mode) */}
{hasPaidPlans && (
<div className="mt-24">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-4">
Pricing
</h3>
<p className="text-center text-gray-500 mb-12 max-w-xl mx-auto">
Start free. Upgrade if you need more inboxes or faster checks.
Cancel any time no questions, no fuss.
</p>
<div className={`grid gap-8 ${plans.length === 1 ? 'max-w-sm mx-auto' : plans.length === 2 ? 'md:grid-cols-2 max-w-2xl mx-auto' : 'md:grid-cols-3'}`}>
{plans.map((plan) => (
<PricingCard key={plan.id} plan={plan} />
))}
</div>
<p className="mt-8 text-center text-sm text-gray-500">
All paid plans include a{' '}
<span className="font-medium">free tier</span> when you first sign up
no credit card required.
</p>
</div>
)}
</main>
{/* Footer */}
<footer className="mt-20 border-t border-gray-200 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<p className="text-center text-gray-600">
© 2024 POP3 Forwarder. Secure email forwarding service.
<p className="text-center text-gray-600 text-sm">
© {new Date().getFullYear()} InboxRescue made for people, not enterprises.
</p>
</div>
</footer>
+2 -2
View File
@@ -54,7 +54,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
<div className="hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col">
<div className="flex flex-col flex-grow bg-white border-r border-gray-200">
<div className="flex items-center h-16 flex-shrink-0 px-4 border-b border-gray-200">
<h1 className="text-xl font-bold text-gray-900">POP3 Forwarder</h1>
<h1 className="text-xl font-bold text-gray-900">InboxRescue</h1>
</div>
<nav className="flex-1 px-2 py-4 space-y-1">
{navigation.map((item) => {
@@ -117,7 +117,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
<div className="fixed inset-0 bg-gray-600/75" onClick={() => setSidebarOpen(false)} />
<div className="fixed inset-y-0 left-0 flex w-64 flex-col bg-white">
<div className="flex items-center justify-between h-16 px-4 border-b border-gray-200">
<h1 className="text-xl font-bold text-gray-900">POP3 Forwarder</h1>
<h1 className="text-xl font-bold text-gray-900">InboxRescue</h1>
<button onClick={() => setSidebarOpen(false)} className="text-gray-500 hover:text-gray-700">
<X className="h-6 w-6" />
</button>