diff --git a/.gitignore b/.gitignore index a23aa6d..89921bc 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files +_.env .env*.local .env.dev .env diff --git a/src/app/(public)/courses/[courseSlug]/[lessonSlug]/page.tsx b/src/app/(public)/courses/[courseSlug]/[lessonSlug]/page.tsx index 395d194..f34f21a 100644 --- a/src/app/(public)/courses/[courseSlug]/[lessonSlug]/page.tsx +++ b/src/app/(public)/courses/[courseSlug]/[lessonSlug]/page.tsx @@ -7,6 +7,8 @@ import { dbGetUserPurchasedCourses } from "@/server/controllers/dbController"; import { redirect } from "next/navigation"; import { Suspense } from "react"; +export const dynamic = "force-dynamic"; + export default async function LessonFrontPageRoute({ params, }: { diff --git a/src/app/(public)/courses/[courseSlug]/page.tsx b/src/app/(public)/courses/[courseSlug]/page.tsx index f95d839..0430342 100644 --- a/src/app/(public)/courses/[courseSlug]/page.tsx +++ b/src/app/(public)/courses/[courseSlug]/page.tsx @@ -6,6 +6,8 @@ import FadeIn from "@/components/animations/FadeIn"; import { errorMessages } from "@/config/errorMessages"; import { redirect } from "next/navigation"; +export const dynamic = "force-dynamic"; + export default async function CourseFrontPageRoute({ params, }: { diff --git a/src/app/(public)/courses/page.tsx b/src/app/(public)/courses/page.tsx index a4bbb04..1d097f6 100644 --- a/src/app/(public)/courses/page.tsx +++ b/src/app/(public)/courses/page.tsx @@ -5,6 +5,8 @@ import { PageWrapper } from "@/components/PageWrapper"; import FadeIn from "@/components/animations/FadeIn"; import { Suspense } from "react"; +export const dynamic = "force-dynamic"; + export default async function PublishedCourses() { return ( diff --git a/src/app/(user)/billing/page.tsx b/src/app/(user)/billing/page.tsx index a159bf9..5d38b3f 100644 --- a/src/app/(user)/billing/page.tsx +++ b/src/app/(user)/billing/page.tsx @@ -6,7 +6,9 @@ import Image from "next/image"; import Link from "next/link"; import { redirect } from "next/navigation"; -export default async function Admin() { +export const dynamic = "force-dynamic"; + +export default async function Billing() { const session = await getServerAuthSession(); if (!session) { diff --git a/src/app/(user)/layout.tsx b/src/app/(user)/layout.tsx index 5737336..f3566fe 100644 --- a/src/app/(user)/layout.tsx +++ b/src/app/(user)/layout.tsx @@ -4,18 +4,13 @@ import { redirect } from "next/navigation"; export default async function UserLayout({ children, }: { - children: React.ReactNode + children: React.ReactNode; }) { const user = await getServerAuthSession(); if (!user) { - /** - * TODO fix redirect properly - */ - return redirect("/?missing=login");; + return redirect("/?missing=login"); } - return ( - <>{children} - ); -} \ No newline at end of file + return <>{children}; +} diff --git a/src/app/(user)/purchase-success/page.tsx b/src/app/(user)/purchase-success/page.tsx index 72e6c53..fab7cfc 100644 --- a/src/app/(user)/purchase-success/page.tsx +++ b/src/app/(user)/purchase-success/page.tsx @@ -4,6 +4,8 @@ import { getServerAuthSession } from "@/server/auth"; import { redirect } from "next/navigation"; import { Suspense } from "react"; +export const dynamic = "force-dynamic"; + export default async function PublishedCourses({ searchParams, }: { diff --git a/src/app/api/image-upload/route.ts b/src/app/api/image-upload/route.ts index c32bd9e..839f750 100644 --- a/src/app/api/image-upload/route.ts +++ b/src/app/api/image-upload/route.ts @@ -1,7 +1,9 @@ -import sharp from 'sharp' -import { NextRequest, NextResponse } from 'next/server' -import { requireAdminAuth } from '@/server/auth' -import { gcPipeImageUpload } from '@/server/controllers/gcController'; +import sharp from "sharp"; +import { NextRequest, NextResponse } from "next/server"; +import { requireAdminAuth } from "@/server/auth"; +import { gcPipeImageUpload } from "@/server/controllers/gcController"; + +export const dynamic = "force-dynamic"; /** * Thanks to these resources for helping me understand how to do this! @@ -12,7 +14,7 @@ export async function POST(request: NextRequest) { requireAdminAuth(); const formData = await request.formData(); - const imageFile = formData.get('image') as unknown as File | null; + const imageFile = formData.get("image") as unknown as File | null; if (!imageFile) return NextResponse.json(null, { status: 400 }); @@ -28,13 +30,13 @@ export async function POST(request: NextRequest) { fileName: `${imageFileName}`, }); - return NextResponse.json({ imageUrl }) + return NextResponse.json({ imageUrl }); } // Export types for API Routes export type UploadProfileImageResponse = ExtractGenericFromNextResponse< - Awaited> -> + Awaited> +>; type ExtractGenericFromNextResponse = Type extends NextResponse - ? X - : never \ No newline at end of file + ? X + : never; diff --git a/src/app/api/stripe-webhook/route.ts b/src/app/api/stripe-webhook/route.ts index 7cc80cd..2a54355 100644 --- a/src/app/api/stripe-webhook/route.ts +++ b/src/app/api/stripe-webhook/route.ts @@ -3,14 +3,16 @@ import { stripe } from "@/lib/stripe/stripeClient"; import { handleSessionCompleted } from "@/server/controllers/stripeWebhookController"; import { dbCreateStripeEventRecord } from "@/server/controllers/dbController"; +export const dynamic = "force-dynamic"; + const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET ?? ""; -export async function POST (req: NextRequest) { +export async function POST(req: NextRequest) { const event = await stripe.webhooks.constructEvent( await req.text(), req.headers.get("stripe-signature") as string, webhookSecret as string - ) + ); // Handle the event switch (event.type) { @@ -26,13 +28,15 @@ export async function POST (req: NextRequest) { case "payment_intent.requires_action": break; case "product.updated": - console.log("===Product updated event received") + console.log("===Product updated event received"); break; case "product.created": break; default: - console.log(`===Unhandled event type: ${event.type}`); - // Unexpected event type + if (process.env.NODE_ENV === "development") { + console.log(`===Unhandled event type: ${event.type}`); + } + // Unexpected event type } // Record the event in the database (unless development mode) diff --git a/src/app/test/[courseSlug]/[lessonSlug]/page.tsx b/src/app/test/[courseSlug]/[lessonSlug]/page.tsx index a1206d0..cd1ffd7 100644 --- a/src/app/test/[courseSlug]/[lessonSlug]/page.tsx +++ b/src/app/test/[courseSlug]/[lessonSlug]/page.tsx @@ -1,13 +1,21 @@ import LoadingBars from "@/components/LoadingBars"; import { MDXRenderer } from "@/components/MDXRenderer"; -import { DBGetCompiledMdxBySlugsProps, dbGetCompiledMdxBySlugs } from "@/server/controllers/dbController"; +import { + DBGetCompiledMdxBySlugsProps, + dbGetCompiledMdxBySlugs, +} from "@/server/controllers/dbController"; import { Suspense } from "react"; +export const dynamic = "force-dynamic"; /** * * TEST ROUTE * * /test/first-course-updated/logic-introduction */ -export default async function TestPage2({ params }: { params: { courseSlug: string, lessonSlug: string}}) { +export default async function TestPage2({ + params, +}: { + params: { courseSlug: string; lessonSlug: string }; +}) { const courseSlug = params.courseSlug; const lessonSlug = params.lessonSlug; /** @@ -18,22 +26,21 @@ export default async function TestPage2({ params }: { params: { courseSlug: stri lessonSlug: lessonSlug, lessonType: "CONTENT", access: "PUBLIC", - } - const compiledMdx = await dbGetCompiledMdxBySlugs(mdxGetArgs) + }; + const compiledMdx = await dbGetCompiledMdxBySlugs(mdxGetArgs); const mdxGetArgs2: DBGetCompiledMdxBySlugsProps = { courseSlug: courseSlug, lessonSlug: lessonSlug, lessonType: "TRANSCRIPT", access: "PUBLIC", - } - const compiledMdx2 = await dbGetCompiledMdxBySlugs(mdxGetArgs2) + }; + const compiledMdx2 = await dbGetCompiledMdxBySlugs(mdxGetArgs2); return (

Test page with 2 dynamic retrieval from db

-

Content:

}> @@ -47,8 +54,7 @@ export default async function TestPage2({ params }: { params: { courseSlug: stri
-
- ) -} \ No newline at end of file + ); +} diff --git a/src/app/test/[courseSlug]/page.tsx b/src/app/test/[courseSlug]/page.tsx index 1549e3f..9006a89 100644 --- a/src/app/test/[courseSlug]/page.tsx +++ b/src/app/test/[courseSlug]/page.tsx @@ -1,13 +1,21 @@ import LoadingBars from "@/components/LoadingBars"; import { MDXRenderer } from "@/components/MDXRenderer"; -import { DBGetCompiledMdxBySlugsProps, dbGetCompiledMdxBySlugs } from "@/server/controllers/dbController"; +import { + DBGetCompiledMdxBySlugsProps, + dbGetCompiledMdxBySlugs, +} from "@/server/controllers/dbController"; import { Suspense } from "react"; +export const dynamic = "force-dynamic"; /** * * TEST ROUTE * * /test/first-course-updated */ -export default async function TestPage1({ params }: { params: { courseSlug: string }}) { +export default async function TestPage1({ + params, +}: { + params: { courseSlug: string }; +}) { const courseSlug = params.courseSlug; /** * TODO Why must I add the Props here for TS not to yell at me!? @@ -15,7 +23,7 @@ export default async function TestPage1({ params }: { params: { courseSlug: stri const mdxGetArgs: DBGetCompiledMdxBySlugsProps = { courseSlug: courseSlug, access: "PUBLIC", - } + }; // const compiledMdx = await mdxGetCompiledSource(mdxGetArgs) const mdxCompiled = await dbGetCompiledMdxBySlugs(mdxGetArgs); @@ -32,5 +40,5 @@ export default async function TestPage1({ params }: { params: { courseSlug: stri - ) -} \ No newline at end of file + ); +} diff --git a/src/app/test/page.tsx b/src/app/test/page.tsx index 507f8cf..dcad56a 100644 --- a/src/app/test/page.tsx +++ b/src/app/test/page.tsx @@ -1,24 +1,20 @@ import Link from "next/link"; - - export default async function TestPage() { - - - return (

Test page with hardcoded retrieval from db

-

Scheduled for deletion

-

- +

Scheduled for deletion

+

+ + +

- - + + +
- -
- ) -} \ No newline at end of file + ); +} diff --git a/src/server/bucket.ts b/src/server/bucket.ts index c79fd3b..0e6dff8 100644 --- a/src/server/bucket.ts +++ b/src/server/bucket.ts @@ -2,18 +2,18 @@ import { Storage } from "@google-cloud/storage"; import { env } from "process"; const creds = { - type: 'service_account', + type: "service_account", project_id: env.GCP_PROJECT_ID, private_key_id: env.GCP_PRIVATE_KEY_ID, private_key: env.GCP_PRIVATE_KEY, client_email: env.GCP_CLIENT_EMAIL, client_id: env.GCP_CLIENT_ID, - auth_uri: 'https://accounts.google.com/o/oauth2/auth', - token_uri: 'https://oauth2.googleapis.com/token', - auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs', + auth_uri: "https://accounts.google.com/o/oauth2/auth", + token_uri: "https://oauth2.googleapis.com/token", + auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs", client_x509_cert_url: env.GCP_CLIENT_X509_CERT_URL, universe_domain: "googleapis.com", -} +}; const storage = new Storage({ projectId: env.GCP_PROJECT_ID, @@ -23,13 +23,9 @@ const storage = new Storage({ const PRIMARY_BUCKET_NAME = env.GCP_PRIMARY_BUCKET_NAME ?? "invalid"; const SECONDARY_BUCKET_NAME = env.GCP_SECONDARY_BUCKET_NAME ?? "invalid"; -if (PRIMARY_BUCKET_NAME === "invalid" || SECONDARY_BUCKET_NAME === "invalid") { - throw new Error("A GCP bucket name is not set"); -} - /** * Storage bucket reference instance. Call methods on this object to interact with the bucket. * @see https://cloud.google.com/nodejs/docs/reference/storage/latest */ export const primaryBucket = storage.bucket(PRIMARY_BUCKET_NAME); -export const secondaryBucket = storage.bucket(SECONDARY_BUCKET_NAME); \ No newline at end of file +export const secondaryBucket = storage.bucket(SECONDARY_BUCKET_NAME); diff --git a/src/server/email.ts b/src/server/email.ts index d50c3e4..a93b259 100644 --- a/src/server/email.ts +++ b/src/server/email.ts @@ -1,5 +1,5 @@ -import { Resend } from 'resend'; +import { Resend } from "resend"; -const RESEND_API_KEY = process.env.RESEND_API_KEY; +const RESEND_API_KEY = process.env.RESEND_API_KEY ?? "invalid"; -export const resend = new Resend(RESEND_API_KEY); \ No newline at end of file +export const resend = new Resend(RESEND_API_KEY);