From 9580f78ef5c8d58b3cb48ffde41073eb1b47e13d Mon Sep 17 00:00:00 2001 From: Don Strawsburg Date: Thu, 16 Jan 2025 16:06:34 -0500 Subject: [PATCH] users page and a function to populate table headers --- src/actions/userActions.ts | 15 ++- src/app/Admin/Users/page.tsx | 26 ++++ src/app/api/auth/signup/route.tsx | 18 +-- src/app/userProfile/[uuid].tsx | 101 ++++++++++++++++ src/components/RegistrationForm/index.tsx | 1 - src/components/admin/UsersTable/index.tsx | 137 ++++++++++++++++++++++ src/components/footer/index.tsx | 16 +++ src/drizzle/schema/schema.ts | 2 - src/lib/utils.ts | 17 +++ 9 files changed, 319 insertions(+), 14 deletions(-) create mode 100644 src/app/Admin/Users/page.tsx create mode 100644 src/app/userProfile/[uuid].tsx create mode 100644 src/components/admin/UsersTable/index.tsx diff --git a/src/actions/userActions.ts b/src/actions/userActions.ts index b8eb7a9..d504a20 100644 --- a/src/actions/userActions.ts +++ b/src/actions/userActions.ts @@ -5,7 +5,7 @@ import { db } from "@db/index"; import { users } from "@schemas/schema"; export const getData = async () => { - const data = await db.select().from(users).orderBy(asc(users.email)); + const data = await db.select().from(users).orderBy(asc(users.last_name)); return data; }; @@ -16,7 +16,7 @@ export const getUserByEmail = async (email:string) => { export const addUser = async ( first_name: string, last_name: string, username: string, email: string, password_hash : string) => { await db.insert(users).values({ - first_name : first_name, last_name: last_name, username: username, email: email, password_hash : password_hash + first_name : first_name, last_name: last_name, username: email, email: email, password_hash : password_hash }); }; @@ -37,4 +37,15 @@ export const editUser = async (id: string, first_name: string, last_name: string }) .where(eq(users.id, id)); revalidatePath("/"); +}; + +export const makeAdmin = async ( email : string) => { + await db + .update(users) + .set({ + isAdmin : true + + }) + .where(eq(users.email, email)); + revalidatePath("/"); }; \ No newline at end of file diff --git a/src/app/Admin/Users/page.tsx b/src/app/Admin/Users/page.tsx new file mode 100644 index 0000000..6901184 --- /dev/null +++ b/src/app/Admin/Users/page.tsx @@ -0,0 +1,26 @@ +import { getData } from "@actions/userActions"; +import styles from '../styles.module.css'; +import PageHero from "@components/PageHero"; +import UsersTable from "@src/components/admin/UsersTable"; +import { Suspense } from "react"; +import Loading from "@src/app/components/Loading/loading"; +import { ColumnHeadings } from "@src/lib/utils"; + +export default async function UsersPage() { + const data = await getData(); + + + const columnHeadings = new ColumnHeadings(['E-mail Address', 'First Name', 'Last Name', 'Blank']); + return ( +
+ + +
+ + + +
+ +
+ ); +} \ No newline at end of file diff --git a/src/app/api/auth/signup/route.tsx b/src/app/api/auth/signup/route.tsx index ddfc274..8c90fdb 100644 --- a/src/app/api/auth/signup/route.tsx +++ b/src/app/api/auth/signup/route.tsx @@ -1,8 +1,8 @@ -import { NextResponse } from 'next/server'; -import { db } from '@db/index'; -import { users } from '@schemas/schema'; -import bcrypt from 'bcryptjs'; -import { eq } from 'drizzle-orm'; +import { NextResponse } from "next/server"; +import { db } from "@db/index"; +import { users } from "@schemas/schema"; +import bcrypt from "bcryptjs"; +import { eq } from "drizzle-orm"; export async function POST(request: Request) { try { @@ -19,14 +19,14 @@ export async function POST(request: Request) { await db.insert(users).values(newUser); return NextResponse.json( - { message: 'User created successfully', redirect: '/' }, + { message: "User created successfully", redirect: "/" }, { status: 201 } ); } catch (error) { - console.error('Signup error:', error); + console.error("Signup error:", error); return NextResponse.json( - { error: 'Failed to create user' }, + { error: "Failed to create user" }, { status: 500 } ); } -} \ No newline at end of file +} diff --git a/src/app/userProfile/[uuid].tsx b/src/app/userProfile/[uuid].tsx new file mode 100644 index 0000000..5100318 --- /dev/null +++ b/src/app/userProfile/[uuid].tsx @@ -0,0 +1,101 @@ +import { NextPage } from "next"; +import { Herr_Von_Muellerhoff } from "next/font/google"; +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; + + +export default function UserProfilePage() { + const router = useRouter(); + const { uuid } = router.query; + + + useEffect(() => { + if (uuid) { + // Fetch product data based on the id + fetch(`/api/products/${id}`) + .then((response) => response.json()) + + .catch((error) => console.error("Error fetching product data:", error)); + } + }, [uuid]); + + if (!product) { + return
Loading...
; + } + + return ( +
+
+ + {/* Product Info */} +
+

{product.name}

+ + {/* Vendor Pricing Table */} +
+

Available From

+
+ + + + + + + + + + + {product.vendors.map((vendor, index) => ( + + + + + + + ))} + +
VendorPriceStockAction
{vendor.name}{vendor.price}{vendor.stock} + +
+
+
+
+
+ + {/* Product Description */} +
+

Product Description

+

+ {product.description} +

+
+ + {/* Product Specifications */} +
+

Specifications

+
+
+ Manufacturer: {product.specifications.manufacturer} +
+
+ Model: {product.specifications.model} +
+
+ Weight: {product.specifications.weight} +
+
+ Dimensions: {product.specifications.dimensions} +
+
+ Material: {product.specifications.material} +
+
+ Warranty: {product.specifications.warranty} +
+
+
+
+ ); +} diff --git a/src/components/RegistrationForm/index.tsx b/src/components/RegistrationForm/index.tsx index e8e7898..ef89b77 100644 --- a/src/components/RegistrationForm/index.tsx +++ b/src/components/RegistrationForm/index.tsx @@ -22,7 +22,6 @@ export default function RegistrationForm() { e.preventDefault(); setError(""); - alert(formData.password + ":" + formData.confirmPassword); if (formData.password !== formData.confirmPassword) { setError("Passwords do not match"); return; diff --git a/src/components/admin/UsersTable/index.tsx b/src/components/admin/UsersTable/index.tsx new file mode 100644 index 0000000..aa04c42 --- /dev/null +++ b/src/components/admin/UsersTable/index.tsx @@ -0,0 +1,137 @@ +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { PlusCircleIcon } from "@heroicons/react/20/solid"; + +import Image from "next/image"; +import Link from "next/link"; + + +export default async function UsersTable(props: any) { + return ( +
+ +
+
+
+ + + + + + + + + + + + {props.data.map((item: any) => ( + + + + + + + + + ))} + +
+ + {props.newColumnHeadings.getHeading()} + + + + + + {props.newColumnHeadings.getHeading()} + + + + + + {props.newColumnHeadings.getHeading()} + + + + + + {props.newColumnHeadings.getHeading()} + + + + + + {props.newColumnHeadings.getHeading()} + + + +
+ + {item.email} + + {item.first_name} + + {item.last_name} + + ${item.username} + + + + +
+ +
+
+
+
+ + ); +} diff --git a/src/components/footer/index.tsx b/src/components/footer/index.tsx index cb0e534..4a3929d 100644 --- a/src/components/footer/index.tsx +++ b/src/components/footer/index.tsx @@ -8,6 +8,9 @@ const navigation = { { name: 'Optics', href: '/Products/optics' }, { name: 'Accessories', href: '/Products/accessories#' }, ], + admin: [ + { name: 'Users', href: '/Admin/Users' }, + ], account: [ { name: 'My Account', href: '/MyAccount' }, { name: 'Register', href: '/signin' }, @@ -109,6 +112,19 @@ export default function Footer() { ))} +
+

Administration

+ +
diff --git a/src/drizzle/schema/schema.ts b/src/drizzle/schema/schema.ts index fa9f898..7da29a7 100644 --- a/src/drizzle/schema/schema.ts +++ b/src/drizzle/schema/schema.ts @@ -1,8 +1,6 @@ import { pgTable, integer, varchar, text, numeric, timestamp, unique, check, bigserial, date, boolean, uuid, bigint, real, doublePrecision, primaryKey } from "drizzle-orm/pg-core" import { sql } from "drizzle-orm" - - export const products = pgTable("products", { id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "products_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), name: varchar({ length: 255 }).notNull(), diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bd0c391..c79f2d3 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,3 +4,20 @@ import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } + +export class ColumnHeadings { + headingNames: string[]; + current: number; + + constructor(headingNames: string[]) { + console.log(headingNames.length); + this.headingNames = headingNames; + this.current = 0; + } + getHeading = () => { + + const returnedHeading:string = this.headingNames[this.current]; + this.current = this.current+1; + return returnedHeading; + } +}