From b365c57671a84f2e115f126cfa51901af26c5605 Mon Sep 17 00:00:00 2001 From: jere-mie Date: Fri, 6 Feb 2026 17:32:46 -0500 Subject: [PATCH 1/8] working code --- .gitignore | 3 + actions/index.ts | 25 + app/globals.css | 77 ++ app/layout.tsx | 4 +- app/page.tsx | 37 +- components/DeleteButton.tsx | 9 + components/RatingForm.tsx | 30 + db/index.ts | 11 + db/schema.ts | 8 + drizzle.config.ts | 13 + example.env | 1 + package-lock.json | 1570 ++++++++++++++++++++++++++++++++++- package.json | 4 + 13 files changed, 1757 insertions(+), 35 deletions(-) create mode 100644 actions/index.ts create mode 100644 components/DeleteButton.tsx create mode 100644 components/RatingForm.tsx create mode 100644 db/index.ts create mode 100644 db/schema.ts create mode 100644 drizzle.config.ts create mode 100644 example.env diff --git a/.gitignore b/.gitignore index 5ef6a52..f2bf1be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# added by me +*.db + # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies diff --git a/actions/index.ts b/actions/index.ts new file mode 100644 index 0000000..5c10dd4 --- /dev/null +++ b/actions/index.ts @@ -0,0 +1,25 @@ +"use server"; + +import { db } from "@/db"; +import { ratings } from "@/db/schema"; +import { eq } from "drizzle-orm"; +import { revalidatePath } from "next/cache"; + +export async function addRating(formData: FormData) { + const name = formData.get("name") as string; + const rating = Number(formData.get("rating")); + const comment = formData.get("comment") as string; + + await db.insert(ratings).values({ + name, + rating, + comment, + }); + + revalidatePath("/"); +} + +export async function deleteRating(id: number) { + await db.delete(ratings).where(eq(ratings.id, id)); + revalidatePath("/"); +} \ No newline at end of file diff --git a/app/globals.css b/app/globals.css index f1d8c73..f0c918f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1 +1,78 @@ @import "tailwindcss"; + +@layer base { + body { + @apply bg-gradient-to-b from-orange-50 to-amber-50 text-gray-800; + } + + main { + @apply max-w-2xl mx-auto p-6 sm:p-8; + } + + h1 { + @apply text-4xl sm:text-5xl font-bold text-orange-600 mb-8 text-center; + } + + h2 { + @apply text-2xl font-semibold text-orange-700 mb-6 mt-0; + } + + h3 { + @apply text-xl font-semibold text-gray-900 mb-2; + } + + form { + @apply bg-white rounded-xl shadow-md p-6 mb-12 border border-orange-100; + } + + form div { + @apply mb-4; + } + + label { + @apply block text-sm font-semibold text-gray-700 mb-2; + } + + input, + select, + textarea { + @apply w-full px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:border-transparent bg-white text-gray-900 transition-all; + } + + textarea { + @apply resize min-h-24; + } + + button { + @apply px-6 py-2 rounded-lg font-semibold transition-all; + } + + form button { + @apply w-full bg-gradient-to-r from-orange-500 to-amber-500 text-white hover:from-orange-600 hover:to-amber-600 active:scale-95 shadow-md; + } + + button:not(form button) { + @apply bg-red-500 text-white hover:bg-red-600 active:scale-95 text-sm; + } + + /* Rating cards container */ + main > div:last-child { + @apply bg-white rounded-xl shadow-md p-6 border border-orange-100; + } + + main > div:last-child > div { + @apply mb-6 p-4 border-l-4 border-orange-400 bg-orange-50 rounded hover:shadow-md transition-shadow; + } + + main > div:last-child > div:last-child { + @apply mb-0; + } + + main > div:last-child p { + @apply text-gray-600 mb-4 italic; + } + + main > div:last-child button { + @apply mt-2; + } +} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 756fcce..8840b67 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,8 +2,8 @@ import type { Metadata } from "next"; import "./globals.css"; export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Campus Cravings", + description: "Rate your favorite meals on campus!", }; export default function RootLayout({ diff --git a/app/page.tsx b/app/page.tsx index b95c3ed..e0cc644 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,7 +1,30 @@ -export default function Home() { - return ( -
-
Hello world!
-
- ); -} +import { db } from "@/db"; +import { ratings } from "@/db/schema"; +import { desc } from "drizzle-orm"; +import RatingForm from "@/components/RatingForm"; +import DeleteButton from "@/components/DeleteButton"; + +export default async function Home() { + const allRatings = await db.select().from(ratings).orderBy(desc(ratings.id)); + + return ( +
+

Campus Cravings 🍔

+ +
+

Recent Reviews

+ + {allRatings.length === 0 &&

No ratings yet. Be the first!

} + + {allRatings.map((rating) => ( +
+

{rating.name}

+
{rating.rating}/5
+

{rating.comment}

+ +
+ ))} +
+
+ ); +} \ No newline at end of file diff --git a/components/DeleteButton.tsx b/components/DeleteButton.tsx new file mode 100644 index 0000000..045ae06 --- /dev/null +++ b/components/DeleteButton.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { deleteRating } from "@/actions"; + +export default function DeleteButton({ id }: { id: number }) { + return ( + + ); +} \ No newline at end of file diff --git a/components/RatingForm.tsx b/components/RatingForm.tsx new file mode 100644 index 0000000..a37d0dc --- /dev/null +++ b/components/RatingForm.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { addRating } from "@/actions"; + +export default function RatingForm() { + return ( +
+

Rate a Meal

+
+ + +
+
+ + +
+
+ +