Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ DATABASE_URL="postgresql://username:password@ep-your-endpoint-pooler.region.aws.
# Direct connection (for migrations) - without -pooler
DIRECT_URL="postgresql://username:password@ep-your-endpoint.region.aws.neon.tech/dbname?sslmode=require&channel_binding=require&connect_timeout=15"

# Next.js Application URL
NEXT_PUBLIC_APP_URL=http://localhost:3000

# Clerk Authentication - User Management & Authentication
# Get these keys from: https://dashboard.clerk.com/
# 1. Create a Clerk application
Expand All @@ -29,4 +32,5 @@ CLERK_WEBHOOK_SECRET=whsec_your_webhook_secret_here
# Paddle Payment Integration - Subscription Management
# Get these keys from: https://vendors.paddle.com/authentication-v2
PADDLE_API_KEY=
PADDLE_WEBHOOK_SECRET=
NEXT_PUBLIC_PADDLE_CLIENT_SIDE_TOKEN=
4 changes: 4 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ DATABASE_URL="postgresql://username:password@ep-your-endpoint-pooler.region.aws.
# Direct connection (for migrations) - without -pooler
DIRECT_URL="postgresql://username:password@ep-your-endpoint.region.aws.neon.tech/dbname?sslmode=require&channel_binding=require&connect_timeout=15"

# Next.js Application URL
NEXT_PUBLIC_APP_URL=http://localhost:3000

# Clerk Authentication - User Management & Authentication
# Get these keys from: https://dashboard.clerk.com/
# 1. Create a Clerk application
Expand All @@ -29,4 +32,5 @@ CLERK_WEBHOOK_SECRET=whsec_your_webhook_secret_here
# Paddle Payment Integration - Subscription Management
# Get these keys from: https://vendors.paddle.com/authentication-v2
PADDLE_API_KEY=
PADDLE_WEBHOOK_SECRET=
NEXT_PUBLIC_PADDLE_CLIENT_SIDE_TOKEN=
76 changes: 76 additions & 0 deletions app/(dashboard)/billing/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { auth } from '@clerk/nextjs/server';
import { db } from '@/server/db/client';
import { BillingDashboard } from '@/components/billing/billing-dashboard';
import { SignInPage } from '@/components/auth/sign-in-button';

export default async function BillingPage() {
const { userId } = await auth();

if (!userId) {
// Show sign-in page instead of redirecting
return (
<div className="container mx-auto py-8 px-4">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold mb-4">Billing & Subscription</h1>
<p className="text-gray-600 mb-8">
Sign in to view your billing dashboard and test Paddle checkout
</p>
</div>
<SignInPage />
</div>
);
}

// Get user's organization
const userWithMembership = await db.user.findUnique({
where: { clerkId: userId },
include: {
memberships: {
include: {
organization: true,
},
take: 1, // Get primary organization
},
},
});

if (!userWithMembership?.memberships[0]) {
return (
<div className="container mx-auto py-8 px-4">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Setup Required</h1>
<p className="text-gray-600">
Please complete your organization setup to access billing features.
</p>
</div>
</div>
);
}

const organization = userWithMembership.memberships[0].organization;

// Mock usage data - replace with actual usage tracking
const currentUsage = {
credits: 250,
projects: 5,
apiCalls: 120,
};

return (
<div className="container mx-auto py-8 px-4">
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold">Billing & Usage</h1>
<p className="text-gray-600">
Manage your subscription and monitor your usage
</p>
</div>

<BillingDashboard
organization={organization}
currentUsage={currentUsage}
/>
</div>
</div>
);
}
68 changes: 68 additions & 0 deletions app/(dashboard)/dashboard-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Image from "next/image";
import Link from "next/link";

export default function Home() {
return (
<div className="min-h-screen p-8">
{/* Simple Navigation */}
<nav className="bg-white border-b border-gray-200 mb-8">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<div className="flex items-center space-x-8">
<h1 className="text-xl font-bold">ThinkTapFast</h1>
<div className="flex space-x-4">
<Link
href="/"
className="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium"
>
Dashboard
</Link>
<Link
href="/billing"
className="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium"
>
Billing
</Link>
</div>
</div>
</div>
</div>
</nav>

{/* Main Content */}
<div className="container mx-auto px-4">
<div className="grid min-h-[60vh] grid-rows-[1fr_auto] items-center justify-items-center gap-16">
<main className="flex flex-col items-center gap-[32px] sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<div className="text-center sm:text-left space-y-4">
<h2 className="text-2xl font-bold">Welcome to ThinkTapFast Dashboard</h2>
<p className="text-gray-600">Manage your content generation and billing from here.</p>
</div>

<div className="flex flex-col items-center gap-4 sm:flex-row">
<Link
className="bg-blue-600 text-white flex h-10 items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium transition-colors hover:bg-blue-700"
href="/billing"
>
View Billing Dashboard
</Link>
<Link
className="border border-gray-300 text-gray-700 flex h-10 items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium transition-colors hover:bg-gray-50"
href="/content/generate"
>
Generate Content
</Link>
</div>
</main>
</div>
</div>
</div>
);
}
143 changes: 72 additions & 71 deletions app/(dashboard)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,84 @@
import Image from "next/image";
import Link from "next/link";
import { AuthButton } from "@/components/auth/sign-in-button";

export default function Home() {
return (
<div className="grid min-h-screen grid-rows-[20px_1fr_20px] items-center justify-items-center gap-16 p-8 pb-20 font-sans sm:p-20">
<main className="row-start-2 flex flex-col items-center gap-[32px] sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-center font-mono text-sm/6 sm:text-left">
<li className="mb-2 tracking-[-.01em]">
Get started by editing{" "}
<code className="rounded bg-black/[.05] px-1 py-0.5 font-mono font-semibold dark:bg-white/[.06]">
app/page.tsx
</code>
.
</li>
<li className="tracking-[-.01em]">Save and see your changes instantly.</li>
</ol>
<div className="min-h-screen p-8">
{/* Simple Navigation */}
<nav className="bg-white border-b border-gray-200 mb-8">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<div className="flex items-center space-x-8">
<h1 className="text-xl font-bold">ThinkTapFast</h1>
<div className="flex space-x-4">
<Link
href="/"
className="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium"
>
Dashboard
</Link>
<Link
href="/billing"
className="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium"
>
Billing
</Link>
<Link
href="/test-paddle"
className="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium"
>
Test Paddle
</Link>
</div>
</div>

{/* Auth Button */}
<AuthButton />
</div>
</div>
</nav>

<div className="flex flex-col items-center gap-4 sm:flex-row">
<a
className="bg-foreground text-background flex h-10 items-center justify-center gap-2 rounded-full border border-solid border-transparent px-4 text-sm font-medium transition-colors hover:bg-[#383838] sm:h-12 sm:w-auto sm:px-5 sm:text-base dark:hover:bg-[#ccc]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
{/* Main Content */}
<div className="container mx-auto px-4">
<div className="grid min-h-[60vh] grid-rows-[1fr_auto] items-center justify-items-center gap-16">
<main className="flex flex-col items-center gap-[32px] sm:items-start">
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
Deploy now
</a>
<a
className="flex h-10 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-4 text-sm font-medium transition-colors hover:border-transparent hover:bg-[#f2f2f2] sm:h-12 sm:w-auto sm:px-5 sm:text-base md:w-[158px] dark:border-white/[.145] dark:hover:bg-[#1a1a1a]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
<div className="text-center sm:text-left space-y-4">
<h2 className="text-2xl font-bold">Welcome to ThinkTapFast Dashboard</h2>
<p className="text-gray-600">Manage your content generation and test the Paddle billing integration.</p>
</div>

<div className="flex flex-col items-center gap-4 sm:flex-row">
<Link
className="bg-blue-600 text-white flex h-10 items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium transition-colors hover:bg-blue-700"
href="/test-paddle"
>
🚀 Test Paddle Checkout
</Link>
<Link
className="bg-green-600 text-white flex h-10 items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium transition-colors hover:bg-green-700"
href="/billing"
>
💳 View Billing Dashboard
</Link>
<Link
className="border border-gray-300 text-gray-700 flex h-10 items-center justify-center gap-2 rounded-lg px-6 text-sm font-medium transition-colors hover:bg-gray-50"
href="/content/generate"
>
✨ Generate Content
</Link>
</div>
</main>
</div>
</main>
<footer className="row-start-3 flex flex-wrap items-center justify-center gap-[24px]">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image aria-hidden src="/file.svg" alt="File icon" width={16} height={16} />
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image aria-hidden src="/window.svg" alt="Window icon" width={16} height={16} />
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
Go to nextjs.org →
</a>
</footer>
</div>
</div>
);
}
Loading