diff --git a/.env.example b/.env.example index 93fda00..71715ab 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,14 @@ # Node environment (development, production, test) NODE_ENV=development + +# App base path +NEXT_PUBLIC_APP_URL=http://localhost:3000 +NEXT_PUBLIC_BASE_PATH=/bills + # NextAuth Configuration # Required for authentication -NEXTAUTH_URL=http://localhost:3000 +NEXTAUTH_URL=http://localhost:3000/bills/api/auth NEXTAUTH_SECRET=your-nextauth-secret-here # Alternative: AUTH_SECRET can be used instead of NEXTAUTH_SECRET # AUTH_SECRET=your-auth-secret-here @@ -18,7 +23,7 @@ GOOGLE_CLIENT_SECRET=your-google-client-secret # MongoDB Configuration # Required for database connection -MONGO_URI=mongodb://localhost:27017/billstracker +MONGO_URI=mongodb://localhost:27017 # Production DB connection used with local development PROD_MONGO_URI= diff --git a/next.config.ts b/next.config.ts index ed83a10..cbf43d9 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,11 +1,28 @@ import type { NextConfig } from "next"; +const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || "/bills"; + const nextConfig: NextConfig = { - basePath: "/bills", + basePath: BASE_PATH, + assetPrefix: BASE_PATH, /* config options here */ output: "standalone", + // Ensure incoming requests scoped under BASE_PATH resolve to root routes + async rewrites() { + return [ + { + source: `${BASE_PATH}`, + destination: "/", + }, + { + source: `${BASE_PATH}/:path*`, + destination: "/:path*", + }, + ]; + }, + // Performance optimizations experimental: { optimizePackageImports: ["lucide-react", "react-markdown"], diff --git a/src/app/[id]/edit/page.tsx b/src/app/[id]/edit/page.tsx index 97dbb8e..7408c14 100644 --- a/src/app/[id]/edit/page.tsx +++ b/src/app/[id]/edit/page.tsx @@ -1,9 +1,8 @@ import { redirect } from "next/navigation"; import { getBillByIdFromDB } from "@/server/get-bill-by-id-from-db"; -import { getServerSession } from "next-auth"; -import { authOptions } from "@/lib/auth"; -import { connectToDatabase } from "@/lib/mongoose"; -import { User } from "@/models/User"; +import { requireAuthenticatedUser } from "@/lib/auth-guards"; +import { BASE_PATH } from "@/utils/basePath"; +import { Button } from "@/components/ui/button"; interface Params { params: Promise<{ id: string }>; @@ -12,19 +11,8 @@ interface Params { export default async function EditBillPage({ params }: Params) { const { id } = await params; - const session = await getServerSession(authOptions); - if (!session?.user?.email) { - redirect(`/unauthorized`); - } - - // Verify the signed-in user exists in DB; do not create - await connectToDatabase(); - const dbUser = await User.findOne({ - emailLower: session.user.email.toLowerCase(), - }); - if (!dbUser) { - redirect(`/unauthorized`); - } + // Use reusable auth guard for consistent authentication + await requireAuthenticatedUser(); const bill = await getBillByIdFromDB(id); if (!bill) { @@ -37,7 +25,11 @@ export default async function EditBillPage({ params }: Params) { return (

Edit Bill

-
+
- +
); diff --git a/src/app/api/[id]/route.ts b/src/app/api/[id]/route.ts index c3f6353..e953709 100644 --- a/src/app/api/[id]/route.ts +++ b/src/app/api/[id]/route.ts @@ -4,6 +4,7 @@ import { connectToDatabase } from "@/lib/mongoose"; import { Bill } from "@/models/Bill"; import { User } from "@/models/User"; import { authOptions } from "@/lib/auth"; +import { BASE_PATH } from "@/utils/basePath"; export async function POST( request: Request, @@ -306,5 +307,8 @@ export async function POST( await Bill.updateOne({ billId: id }, { $set: update }, { upsert: false }); - return NextResponse.redirect(new URL(`/bills/${id}`, request.url)); + // API routes need to manually include basePath in redirects + const url = new URL(request.url); + const redirectUrl = new URL(`${BASE_PATH}/${id}`, url.origin); + return NextResponse.redirect(redirectUrl); } diff --git a/src/app/bills/[id]/edit/page.tsx b/src/app/bills/[id]/edit/page.tsx deleted file mode 100644 index cf04961..0000000 --- a/src/app/bills/[id]/edit/page.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import { redirect } from "next/navigation"; -import { getServerSession } from "next-auth"; -import { authOptions } from "@/auth"; -import { getBillByIdFromDB } from "@/server/get-bill-by-id-from-db"; - -interface Params { - params: Promise<{ id: string }>; -} - -export default async function EditBillPage({ params }: Params) { - const { id } = await params; - const session = await getServerSession(authOptions); - if (!session?.user) { - redirect("/"); - } - - const bill = await getBillByIdFromDB(id); - if (!bill) { - redirect(`/bills/${id}`); - } - - const questionPeriodQuestions = bill.question_period_questions || []; - const questionFields = [...questionPeriodQuestions, { question: "" }]; - - return ( -
-

Edit Bill

-
-
- -