Account Management
User account pages with profile, subscription, and billing management.
Profile
- • Profile information
- • Avatar from OAuth
- • Email verification status
- • Account creation date
Billing
- • Subscription details
- • Usage tracking
- • Stripe billing portal
- • Plan upgrade/downgrade
Account Page
src/app/account/page.tsx
1// src/app/account/page.tsx2import { auth } from "~/auth";3import { db } from "~/server/db";4import { redirect } from "next/navigation";56export default async function AccountPage() {7 const session = await auth();8 if (!session?.user) redirect("/auth/signin");910 const [subscription, user] = await Promise.all([11 db.subscription.findUnique({ where: { userId: session.user.id } }),12 db.user.findUnique({13 where: { id: session.user.id },14 select: { name: true, email: true, image: true, createdAt: true },15 }),16 ]);1718 return (19 <div className="container max-w-3xl py-8">20 {/* Profile Section */}21 {/* Subscription Section */}22 </div>23 );24}
Account Messages
Display messages after Stripe redirects:
src/components/AccountMessages.tsx
1"use client";23import { useSearchParams } from "next/navigation";45export function AccountMessages() {6 const searchParams = useSearchParams();7 const sessionId = searchParams.get("session_id");8 const message = searchParams.get("message");910 if (sessionId) {11 return (12 <div className="rounded-xl bg-green-500/10 p-4 text-green-700">13 Welcome to Pro! Your subscription is now active.14 </div>15 );16 }1718 if (message === "subscription_canceled") {19 return (20 <div className="rounded-xl bg-amber-500/10 p-4 text-amber-700">21 Your subscription has been canceled.22 </div>23 );24 }2526 return null;27}
Subscription Management
1"use client";23import { useState } from "react";4import { createBillingPortalSession } from "~/server/actions/stripe";56export function SubscriptionManagement({ subscription }) {7 const [loading, setLoading] = useState(false);89 const handleBillingPortal = async () => {10 setLoading(true);11 const result = await createBillingPortalSession();12 if (result.url) window.open(result.url, "_blank");13 setLoading(false);14 };1516 return (17 <button onClick={handleBillingPortal} disabled={loading}>18 {loading ? "Loading..." : "Manage Billing"}19 </button>20 );21}
Billing Portal
src/server/actions/stripe.ts
1"use server";23import { auth } from "~/auth";4import { stripe } from "~/server/lib/stripe";5import { db } from "~/server/db";67export async function createBillingPortalSession() {8 const session = await auth();9 if (!session?.user?.id) return { error: "Not authenticated" };1011 const subscription = await db.subscription.findUnique({12 where: { userId: session.user.id },13 select: { stripeCustomerId: true },14 });1516 if (!subscription?.stripeCustomerId) {17 return { error: "No billing information found" };18 }1920 const portalSession = await stripe.billingPortal.sessions.create({21 customer: subscription.stripeCustomerId,22 return_url: `${process.env.NEXTAUTH_URL}/account`,23 });2425 return { url: portalSession.url };26}
Users can update payment methods, view invoices, and cancel subscriptions through Stripe's hosted portal.
Best Practices
UX
- • Clear status indicators
- • Easy billing portal access
- • Transparent usage tracking
- • Confirmation for destructive actions
Technical
- • Validate server-side
- • Handle loading states
- • Secure session management
- • Proper error handling
Next: Admin Dashboard
Analytics and user management components