From c4a9da0fab22bc4e757d53d3321a1c29756226e5 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Wed, 23 Oct 2024 16:47:21 -0500 Subject: [PATCH 01/10] Removed title from users -> club relation; Added officers table for listed club officers -- is_president flag for officers that can't be removed --- src/server/db/schema/officers.ts | 24 ++++++++++++++++++++++++ src/server/db/schema/users.ts | 1 - 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/server/db/schema/officers.ts diff --git a/src/server/db/schema/officers.ts b/src/server/db/schema/officers.ts new file mode 100644 index 00000000..dc9ad607 --- /dev/null +++ b/src/server/db/schema/officers.ts @@ -0,0 +1,24 @@ +import { relations } from 'drizzle-orm'; +import { pgTable, text, boolean, primaryKey } from 'drizzle-orm/pg-core'; +import { club } from './club'; + +export const officers = pgTable( + 'officers', + { + id: text('id').notNull(), + clubId: text('club_id') + .notNull() + .references(() => club.id), + name: text('name').notNull(), + position: text('position').notNull(), + image: text('image').default('/nebula-logo.png').notNull(), + isPresident: boolean('is_president').default(false).notNull(), + }, + (table) => ({ + pk: primaryKey(table.clubId, table.id), + }) +); + +export const officersToClubs = relations(officers, ({ one }) => ({ + club: one(club, { fields: [officers.clubId], references: [club.id] }), +})); \ No newline at end of file diff --git a/src/server/db/schema/users.ts b/src/server/db/schema/users.ts index 1da47684..c1c7e1f9 100644 --- a/src/server/db/schema/users.ts +++ b/src/server/db/schema/users.ts @@ -117,7 +117,6 @@ export const userMetadataToClubs = pgTable( memberType: clubRoleEnum('member_type') .$default(() => 'Member') .notNull(), - title: text('title'), }, (t) => ({ pk: primaryKey(t.userId, t.clubId), From 5529a6e1ac425d10918c12045d395e993a8cc4eb Mon Sep 17 00:00:00 2001 From: BK2004 Date: Wed, 23 Oct 2024 17:04:50 -0500 Subject: [PATCH 02/10] Removed userMetadataToClubs title dependencies; added db migration --- .../manage/[clubId]/edit/officers/page.tsx | 2 +- .../club/listing/ClubInfoSegment.tsx | 2 +- src/server/api/routers/clubEdit.ts | 33 +- .../db/migrations/0008_military_mole_man.sql | 16 + .../db/migrations/meta/0008_snapshot.json | 828 ++++++++++++++++++ src/server/db/migrations/meta/_journal.json | 7 + src/server/db/schema/club.ts | 2 + 7 files changed, 872 insertions(+), 18 deletions(-) create mode 100644 src/server/db/migrations/0008_military_mole_man.sql create mode 100644 src/server/db/migrations/meta/0008_snapshot.json diff --git a/src/app/manage/[clubId]/edit/officers/page.tsx b/src/app/manage/[clubId]/edit/officers/page.tsx index df7955dd..6b7817aa 100644 --- a/src/app/manage/[clubId]/edit/officers/page.tsx +++ b/src/app/manage/[clubId]/edit/officers/page.tsx @@ -21,7 +21,7 @@ export default async function Page({ name: officer.userMetadata.firstName + ' ' + officer.userMetadata.lastName, locked: officer.memberType == 'President' || role == 'Officer', position: officer.memberType as 'President' | 'Officer', - title: officer.title as string, + title: "", // TODO: link from officers table })); return ( diff --git a/src/components/club/listing/ClubInfoSegment.tsx b/src/components/club/listing/ClubInfoSegment.tsx index d1fe1fc7..1654ea64 100644 --- a/src/components/club/listing/ClubInfoSegment.tsx +++ b/src/components/club/listing/ClubInfoSegment.tsx @@ -73,7 +73,7 @@ const ClubInfoSegment: FC<{ officer.userMetadata.lastName}

- {officer.title ?? 'Officer'} + Officer {/* TODO: link to officers table */}

diff --git a/src/server/api/routers/clubEdit.ts b/src/server/api/routers/clubEdit.ts index 03a5fb20..67b21e47 100644 --- a/src/server/api/routers/clubEdit.ts +++ b/src/server/api/routers/clubEdit.ts @@ -1,6 +1,6 @@ import { db } from '@src/server/db'; import { createTRPCRouter, protectedProcedure } from '../trpc'; -import { and, eq, inArray, sql } from 'drizzle-orm'; +import { and, eq, inArray } from 'drizzle-orm'; import { editClubSchema } from '@src/utils/formSchemas'; import { TRPCError } from '@trpc/server'; import { z } from 'zod'; @@ -136,20 +136,21 @@ export const clubEditRouter = createTRPCRouter({ ), ); } - const promises: Promise[] = []; - for (const modded of input.modified) { - const prom = ctx.db - .update(userMetadataToClubs) - .set({ title: modded.title }) - .where( - and( - eq(userMetadataToClubs.userId, modded.userId), - eq(userMetadataToClubs.clubId, input.clubId), - ), - ); - promises.push(prom); - } - await Promise.allSettled(promises); + // TODO: link to officers table + // const promises: Promise[] = []; + // for (const modded of input.modified) { + // const prom = ctx.db + // .update(userMetadataToClubs) + // .set({ title: modded.title }) + // .where( + // and( + // eq(userMetadataToClubs.userId, modded.userId), + // eq(userMetadataToClubs.clubId, input.clubId), + // ), + // ); + // promises.push(prom); + // } + // await Promise.allSettled(promises); if (input.created.length === 0) return; await ctx.db @@ -164,7 +165,7 @@ export const clubEditRouter = createTRPCRouter({ ) .onConflictDoUpdate({ target: [userMetadataToClubs.userId, userMetadataToClubs.clubId], - set: { memberType: 'Officer' as const, title: sql`excluded.title` }, + set: { memberType: 'Officer' as const}, where: eq(userMetadataToClubs.memberType, 'Member'), }); }), diff --git a/src/server/db/migrations/0008_military_mole_man.sql b/src/server/db/migrations/0008_military_mole_man.sql new file mode 100644 index 00000000..f2751de0 --- /dev/null +++ b/src/server/db/migrations/0008_military_mole_man.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS "officers" ( + "id" text NOT NULL, + "club_id" text NOT NULL, + "name" text NOT NULL, + "position" text NOT NULL, + "image" text DEFAULT '/nebula-logo.png' NOT NULL, + "is_president" boolean DEFAULT false NOT NULL, + CONSTRAINT officers_club_id_id PRIMARY KEY("club_id","id") +); +--> statement-breakpoint +ALTER TABLE "user_metadata_to_clubs" DROP COLUMN IF EXISTS "title";--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "officers" ADD CONSTRAINT "officers_club_id_club_id_fk" FOREIGN KEY ("club_id") REFERENCES "club"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/src/server/db/migrations/meta/0008_snapshot.json b/src/server/db/migrations/meta/0008_snapshot.json new file mode 100644 index 00000000..2c2337b6 --- /dev/null +++ b/src/server/db/migrations/meta/0008_snapshot.json @@ -0,0 +1,828 @@ +{ + "version": "5", + "dialect": "pg", + "id": "48d235dc-83ee-48ae-bad8-dc3e7093cdd1", + "prevId": "429d44fa-511e-4cb4-89bb-aae0f8d67bdb", + "tables": { + "admin": { + "name": "admin", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "admin_userId_user_metadata_id_fk": { + "name": "admin_userId_user_metadata_id_fk", + "tableFrom": "admin", + "tableTo": "user_metadata", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "carousel": { + "name": "carousel", + "schema": "", + "columns": { + "orgId": { + "name": "orgId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "startTime": { + "name": "startTime", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "endTime": { + "name": "endTime", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "carousel_orgId_club_id_fk": { + "name": "carousel_orgId_club_id_fk", + "tableFrom": "carousel", + "tableTo": "club", + "columnsFrom": [ + "orgId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "club": { + "name": "club", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/nebula-logo.png'" + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "approved": { + "name": "approved", + "type": "approved_enum", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "profile_image": { + "name": "profile_image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "soc": { + "name": "soc", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contacts": { + "name": "contacts", + "schema": "", + "columns": { + "platform": { + "name": "platform", + "type": "platform", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "contacts_club_id_club_id_fk": { + "name": "contacts_club_id_club_id_fk", + "tableFrom": "contacts", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contacts_platform_club_id": { + "name": "contacts_platform_club_id", + "columns": [ + "platform", + "club_id" + ] + } + }, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "events_club_id_club_id_fk": { + "name": "events_club_id_club_id_fk", + "tableFrom": "events", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "feedback_form": { + "name": "feedback_form", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "rating": { + "name": "rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "likes": { + "name": "likes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "dislikes": { + "name": "dislikes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "features": { + "name": "features", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "submit_on": { + "name": "submit_on", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "officers": { + "name": "officers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/nebula-logo.png'" + }, + "is_president": { + "name": "is_president", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "officers_club_id_club_id_fk": { + "name": "officers_club_id_club_id_fk", + "tableFrom": "officers", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "officers_club_id_id": { + "name": "officers_club_id_id", + "columns": [ + "club_id", + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_metadata": { + "name": "user_metadata", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "major": { + "name": "major", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "minor": { + "name": "minor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "year": { + "name": "year", + "type": "year", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "primaryKey": false, + "notNull": true + }, + "career": { + "name": "career", + "type": "career", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_metadata_to_clubs": { + "name": "user_metadata_to_clubs", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "member_type": { + "name": "member_type", + "type": "member_type", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_metadata_to_clubs_user_id_user_metadata_id_fk": { + "name": "user_metadata_to_clubs_user_id_user_metadata_id_fk", + "tableFrom": "user_metadata_to_clubs", + "tableTo": "user_metadata", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_metadata_to_clubs_club_id_club_id_fk": { + "name": "user_metadata_to_clubs_club_id_club_id_fk", + "tableFrom": "user_metadata_to_clubs", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_metadata_to_clubs_user_id_club_id": { + "name": "user_metadata_to_clubs_user_id_club_id", + "columns": [ + "user_id", + "club_id" + ] + } + }, + "uniqueConstraints": {} + }, + "user_metadata_to_events": { + "name": "user_metadata_to_events", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_metadata_to_events_user_id_user_id_fk": { + "name": "user_metadata_to_events_user_id_user_id_fk", + "tableFrom": "user_metadata_to_events", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_metadata_to_events_event_id_events_id_fk": { + "name": "user_metadata_to_events_event_id_events_id_fk", + "tableFrom": "user_metadata_to_events", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_metadata_to_events_user_id_event_id": { + "name": "user_metadata_to_events_user_id_event_id", + "columns": [ + "user_id", + "event_id" + ] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": { + "approved_enum": { + "name": "approved_enum", + "values": { + "approved": "approved", + "rejected": "rejected", + "pending": "pending" + } + }, + "career": { + "name": "career", + "values": { + "Healthcare": "Healthcare", + "Art and Music": "Art and Music", + "Engineering": "Engineering", + "Business": "Business", + "Sciences": "Sciences", + "Public Service": "Public Service" + } + }, + "member_type": { + "name": "member_type", + "values": { + "President": "President", + "Officer": "Officer", + "Member": "Member" + } + }, + "role": { + "name": "role", + "values": { + "Student": "Student", + "Student Organizer": "Student Organizer", + "Administrator": "Administrator" + } + }, + "year": { + "name": "year", + "values": { + "Freshman": "Freshman", + "Sophomore": "Sophomore", + "Junior": "Junior", + "Senior": "Senior", + "Grad Student": "Grad Student" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index 322fc626..b66dc73f 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1712936415961, "tag": "0007_cool_stature", "breakpoints": true + }, + { + "idx": 8, + "version": "5", + "when": 1729719886854, + "tag": "0008_military_mole_man", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/db/schema/club.ts b/src/server/db/schema/club.ts index 52f632c4..87ca99e0 100644 --- a/src/server/db/schema/club.ts +++ b/src/server/db/schema/club.ts @@ -11,6 +11,7 @@ import { events } from './events'; import { userMetadataToClubs } from './users'; import { contacts } from './contacts'; import { carousel } from './admin'; +import { officers } from './officers'; export const approvedEnum = pgEnum('approved_enum', [ 'approved', @@ -39,6 +40,7 @@ export const club = pgTable('club', { export const clubRelations = relations(club, ({ many }) => ({ contacts: many(contacts), events: many(events), + officers: many(officers), userMetadataToClubs: many(userMetadataToClubs), carousel: many(carousel), })); From 19b91879931c7c8295372fd57122303163bc14c8 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Wed, 23 Oct 2024 17:30:08 -0500 Subject: [PATCH 03/10] prettier formatting --- .../manage/[clubId]/edit/officers/page.tsx | 2 +- src/server/api/routers/clubEdit.ts | 2 +- src/server/db/schema/officers.ts | 32 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/app/manage/[clubId]/edit/officers/page.tsx b/src/app/manage/[clubId]/edit/officers/page.tsx index 6b7817aa..984253d3 100644 --- a/src/app/manage/[clubId]/edit/officers/page.tsx +++ b/src/app/manage/[clubId]/edit/officers/page.tsx @@ -21,7 +21,7 @@ export default async function Page({ name: officer.userMetadata.firstName + ' ' + officer.userMetadata.lastName, locked: officer.memberType == 'President' || role == 'Officer', position: officer.memberType as 'President' | 'Officer', - title: "", // TODO: link from officers table + title: '', // TODO: link from officers table })); return ( diff --git a/src/server/api/routers/clubEdit.ts b/src/server/api/routers/clubEdit.ts index 67b21e47..30ca549c 100644 --- a/src/server/api/routers/clubEdit.ts +++ b/src/server/api/routers/clubEdit.ts @@ -165,7 +165,7 @@ export const clubEditRouter = createTRPCRouter({ ) .onConflictDoUpdate({ target: [userMetadataToClubs.userId, userMetadataToClubs.clubId], - set: { memberType: 'Officer' as const}, + set: { memberType: 'Officer' as const }, where: eq(userMetadataToClubs.memberType, 'Member'), }); }), diff --git a/src/server/db/schema/officers.ts b/src/server/db/schema/officers.ts index dc9ad607..413ded84 100644 --- a/src/server/db/schema/officers.ts +++ b/src/server/db/schema/officers.ts @@ -3,22 +3,22 @@ import { pgTable, text, boolean, primaryKey } from 'drizzle-orm/pg-core'; import { club } from './club'; export const officers = pgTable( - 'officers', - { - id: text('id').notNull(), - clubId: text('club_id') - .notNull() - .references(() => club.id), - name: text('name').notNull(), - position: text('position').notNull(), - image: text('image').default('/nebula-logo.png').notNull(), - isPresident: boolean('is_president').default(false).notNull(), - }, - (table) => ({ - pk: primaryKey(table.clubId, table.id), - }) + 'officers', + { + id: text('id').notNull(), + clubId: text('club_id') + .notNull() + .references(() => club.id), + name: text('name').notNull(), + position: text('position').notNull(), + image: text('image').default('/nebula-logo.png').notNull(), + isPresident: boolean('is_president').default(false).notNull(), + }, + (table) => ({ + pk: primaryKey(table.clubId, table.id), + }), ); export const officersToClubs = relations(officers, ({ one }) => ({ - club: one(club, { fields: [officers.clubId], references: [club.id] }), -})); \ No newline at end of file + club: one(club, { fields: [officers.clubId], references: [club.id] }), +})); From 24903aa6c908f3fa8a514fafbe585dbd4546338c Mon Sep 17 00:00:00 2001 From: BK2004 Date: Tue, 29 Oct 2024 19:01:42 -0500 Subject: [PATCH 04/10] Removed composite key for officers id and clubId; gave officer id a default as uuid --- .../db/migrations/0009_unknown_mastermind.sql | 4 + .../db/migrations/meta/0009_snapshot.json | 821 ++++++++++++++++++ src/server/db/migrations/meta/_journal.json | 7 + src/server/db/schema/officers.ts | 28 +- 4 files changed, 843 insertions(+), 17 deletions(-) create mode 100644 src/server/db/migrations/0009_unknown_mastermind.sql create mode 100644 src/server/db/migrations/meta/0009_snapshot.json diff --git a/src/server/db/migrations/0009_unknown_mastermind.sql b/src/server/db/migrations/0009_unknown_mastermind.sql new file mode 100644 index 00000000..6fd8d0e8 --- /dev/null +++ b/src/server/db/migrations/0009_unknown_mastermind.sql @@ -0,0 +1,4 @@ +ALTER TABLE "officers" DROP CONSTRAINT "officers_club_id_id";--> statement-breakpoint +ALTER TABLE "officers" ADD PRIMARY KEY ("id");--> statement-breakpoint +ALTER TABLE "officers" ALTER COLUMN "id" SET DATA TYPE uuid;--> statement-breakpoint +ALTER TABLE "officers" ALTER COLUMN "id" SET DEFAULT gen_random_uuid(); \ No newline at end of file diff --git a/src/server/db/migrations/meta/0009_snapshot.json b/src/server/db/migrations/meta/0009_snapshot.json new file mode 100644 index 00000000..8337f20e --- /dev/null +++ b/src/server/db/migrations/meta/0009_snapshot.json @@ -0,0 +1,821 @@ +{ + "version": "5", + "dialect": "pg", + "id": "cc00cb68-4c57-4578-9141-b7fb0fcf8710", + "prevId": "48d235dc-83ee-48ae-bad8-dc3e7093cdd1", + "tables": { + "admin": { + "name": "admin", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "admin_userId_user_metadata_id_fk": { + "name": "admin_userId_user_metadata_id_fk", + "tableFrom": "admin", + "tableTo": "user_metadata", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "carousel": { + "name": "carousel", + "schema": "", + "columns": { + "orgId": { + "name": "orgId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "startTime": { + "name": "startTime", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "endTime": { + "name": "endTime", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "carousel_orgId_club_id_fk": { + "name": "carousel_orgId_club_id_fk", + "tableFrom": "carousel", + "tableTo": "club", + "columnsFrom": [ + "orgId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "club": { + "name": "club", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/nebula-logo.png'" + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "approved": { + "name": "approved", + "type": "approved_enum", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "profile_image": { + "name": "profile_image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "soc": { + "name": "soc", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contacts": { + "name": "contacts", + "schema": "", + "columns": { + "platform": { + "name": "platform", + "type": "platform", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "contacts_club_id_club_id_fk": { + "name": "contacts_club_id_club_id_fk", + "tableFrom": "contacts", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contacts_platform_club_id": { + "name": "contacts_platform_club_id", + "columns": [ + "platform", + "club_id" + ] + } + }, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "events_club_id_club_id_fk": { + "name": "events_club_id_club_id_fk", + "tableFrom": "events", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "feedback_form": { + "name": "feedback_form", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "nanoid(20)" + }, + "rating": { + "name": "rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "likes": { + "name": "likes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "dislikes": { + "name": "dislikes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "features": { + "name": "features", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "submit_on": { + "name": "submit_on", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "officers": { + "name": "officers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'/nebula-logo.png'" + }, + "is_president": { + "name": "is_president", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "officers_club_id_club_id_fk": { + "name": "officers_club_id_club_id_fk", + "tableFrom": "officers", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_metadata": { + "name": "user_metadata", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "major": { + "name": "major", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "minor": { + "name": "minor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "year": { + "name": "year", + "type": "year", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "primaryKey": false, + "notNull": true + }, + "career": { + "name": "career", + "type": "career", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_metadata_to_clubs": { + "name": "user_metadata_to_clubs", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "club_id": { + "name": "club_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "member_type": { + "name": "member_type", + "type": "member_type", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_metadata_to_clubs_user_id_user_metadata_id_fk": { + "name": "user_metadata_to_clubs_user_id_user_metadata_id_fk", + "tableFrom": "user_metadata_to_clubs", + "tableTo": "user_metadata", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_metadata_to_clubs_club_id_club_id_fk": { + "name": "user_metadata_to_clubs_club_id_club_id_fk", + "tableFrom": "user_metadata_to_clubs", + "tableTo": "club", + "columnsFrom": [ + "club_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_metadata_to_clubs_user_id_club_id": { + "name": "user_metadata_to_clubs_user_id_club_id", + "columns": [ + "user_id", + "club_id" + ] + } + }, + "uniqueConstraints": {} + }, + "user_metadata_to_events": { + "name": "user_metadata_to_events", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_metadata_to_events_user_id_user_id_fk": { + "name": "user_metadata_to_events_user_id_user_id_fk", + "tableFrom": "user_metadata_to_events", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_metadata_to_events_event_id_events_id_fk": { + "name": "user_metadata_to_events_event_id_events_id_fk", + "tableFrom": "user_metadata_to_events", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_metadata_to_events_user_id_event_id": { + "name": "user_metadata_to_events_user_id_event_id", + "columns": [ + "user_id", + "event_id" + ] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": { + "approved_enum": { + "name": "approved_enum", + "values": { + "approved": "approved", + "rejected": "rejected", + "pending": "pending" + } + }, + "career": { + "name": "career", + "values": { + "Healthcare": "Healthcare", + "Art and Music": "Art and Music", + "Engineering": "Engineering", + "Business": "Business", + "Sciences": "Sciences", + "Public Service": "Public Service" + } + }, + "member_type": { + "name": "member_type", + "values": { + "President": "President", + "Officer": "Officer", + "Member": "Member" + } + }, + "role": { + "name": "role", + "values": { + "Student": "Student", + "Student Organizer": "Student Organizer", + "Administrator": "Administrator" + } + }, + "year": { + "name": "year", + "values": { + "Freshman": "Freshman", + "Sophomore": "Sophomore", + "Junior": "Junior", + "Senior": "Senior", + "Grad Student": "Grad Student" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index b66dc73f..ec8f3e03 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -64,6 +64,13 @@ "when": 1729719886854, "tag": "0008_military_mole_man", "breakpoints": true + }, + { + "idx": 9, + "version": "5", + "when": 1730246133518, + "tag": "0009_unknown_mastermind", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/db/schema/officers.ts b/src/server/db/schema/officers.ts index 413ded84..9fab352a 100644 --- a/src/server/db/schema/officers.ts +++ b/src/server/db/schema/officers.ts @@ -1,23 +1,17 @@ import { relations } from 'drizzle-orm'; -import { pgTable, text, boolean, primaryKey } from 'drizzle-orm/pg-core'; +import { pgTable, text, boolean, uuid } from 'drizzle-orm/pg-core'; import { club } from './club'; -export const officers = pgTable( - 'officers', - { - id: text('id').notNull(), - clubId: text('club_id') - .notNull() - .references(() => club.id), - name: text('name').notNull(), - position: text('position').notNull(), - image: text('image').default('/nebula-logo.png').notNull(), - isPresident: boolean('is_president').default(false).notNull(), - }, - (table) => ({ - pk: primaryKey(table.clubId, table.id), - }), -); +export const officers = pgTable('officers', { + id: uuid('id').defaultRandom().notNull().primaryKey(), + clubId: text('club_id') + .notNull() + .references(() => club.id), + name: text('name').notNull(), + position: text('position').notNull(), + image: text('image').default('/nebula-logo.png').notNull(), + isPresident: boolean('is_president').default(false).notNull(), +}); export const officersToClubs = relations(officers, ({ one }) => ({ club: one(club, { fields: [officers.clubId], references: [club.id] }), From a9d523c20e11dfb4e4c50f9dad091e154cb40c54 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Wed, 30 Oct 2024 16:09:18 -0500 Subject: [PATCH 05/10] removed unnecessary notNull --- ..._unknown_mastermind.sql => 0009_colossal_omega_flight.sql} | 0 src/server/db/migrations/meta/0009_snapshot.json | 2 +- src/server/db/migrations/meta/_journal.json | 4 ++-- src/server/db/schema/officers.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/server/db/migrations/{0009_unknown_mastermind.sql => 0009_colossal_omega_flight.sql} (100%) diff --git a/src/server/db/migrations/0009_unknown_mastermind.sql b/src/server/db/migrations/0009_colossal_omega_flight.sql similarity index 100% rename from src/server/db/migrations/0009_unknown_mastermind.sql rename to src/server/db/migrations/0009_colossal_omega_flight.sql diff --git a/src/server/db/migrations/meta/0009_snapshot.json b/src/server/db/migrations/meta/0009_snapshot.json index 8337f20e..cd81cbe6 100644 --- a/src/server/db/migrations/meta/0009_snapshot.json +++ b/src/server/db/migrations/meta/0009_snapshot.json @@ -1,7 +1,7 @@ { "version": "5", "dialect": "pg", - "id": "cc00cb68-4c57-4578-9141-b7fb0fcf8710", + "id": "47b2b0b5-487f-408b-9e3e-1847604c807e", "prevId": "48d235dc-83ee-48ae-bad8-dc3e7093cdd1", "tables": { "admin": { diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index ec8f3e03..371700fd 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -68,8 +68,8 @@ { "idx": 9, "version": "5", - "when": 1730246133518, - "tag": "0009_unknown_mastermind", + "when": 1730322465532, + "tag": "0009_colossal_omega_flight", "breakpoints": true } ] diff --git a/src/server/db/schema/officers.ts b/src/server/db/schema/officers.ts index 9fab352a..594dfb49 100644 --- a/src/server/db/schema/officers.ts +++ b/src/server/db/schema/officers.ts @@ -3,7 +3,7 @@ import { pgTable, text, boolean, uuid } from 'drizzle-orm/pg-core'; import { club } from './club'; export const officers = pgTable('officers', { - id: uuid('id').defaultRandom().notNull().primaryKey(), + id: uuid('id').defaultRandom().primaryKey(), clubId: text('club_id') .notNull() .references(() => club.id), From aa29f209472acf9ea981d060db01cf97ac0560b4 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 5 Nov 2024 14:44:28 -0600 Subject: [PATCH 06/10] switch to neon for db provider --- package-lock.json | 117 ++++++++++++++++++++++++++++++++++++++++- package.json | 1 + src/server/db/index.ts | 8 +-- 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index c9037fd4..59a600ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@auth/drizzle-adapter": "^0.3.2", "@hookform/resolvers": "^3.3.2", + "@neondatabase/serverless": "^0.10.2", "@next/third-parties": "^14.2.15", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5", @@ -1808,6 +1809,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@neondatabase/serverless": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-0.10.2.tgz", + "integrity": "sha512-XaIMQ9fXDPWLiShfsg+YJQvmMMIyVQB7J3jnirckyoDxN7YIATyzXBThpUeFJqBUkbFJQ0e5PCxXTpK2rG4WbQ==", + "license": "MIT", + "dependencies": { + "@types/pg": "8.11.6" + } + }, "node_modules/@next/env": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz", @@ -3072,8 +3082,7 @@ "node_modules/@types/node": { "version": "18.18.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.5.tgz", - "integrity": "sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A==", - "dev": true + "integrity": "sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -3081,6 +3090,17 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, + "node_modules/@types/pg": { + "version": "8.11.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.6.tgz", + "integrity": "sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, "node_modules/@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -9397,6 +9417,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, "node_modules/oidc-token-hash": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", @@ -9668,6 +9694,48 @@ "node": ">=8" } }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -9940,6 +10008,51 @@ "url": "https://github.com/sponsors/porsager" } }, + "node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "license": "MIT" + }, "node_modules/preact": { "version": "10.11.3", "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", diff --git a/package.json b/package.json index 1c4b94b2..5df0bec5 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@auth/drizzle-adapter": "^0.3.2", "@hookform/resolvers": "^3.3.2", + "@neondatabase/serverless": "^0.10.2", "@next/third-parties": "^14.2.15", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5", diff --git a/src/server/db/index.ts b/src/server/db/index.ts index 8f3bb80e..cc1185ab 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -1,6 +1,4 @@ -import postgres from 'postgres'; -import { drizzle } from 'drizzle-orm/postgres-js'; - +import { drizzle } from 'drizzle-orm/neon-http'; import { env } from '@src/env.mjs'; import * as club from './schema/club'; @@ -9,6 +7,7 @@ import * as events from './schema/events'; import * as users from './schema/users'; import * as forms from './schema/forms'; import * as admin from './schema/admin'; +import { neon } from '@neondatabase/serverless'; const schema = { ...club, @@ -19,6 +18,7 @@ const schema = { ...admin, }; -export const db = drizzle(postgres(env.DATABASE_URL, { prepare: false }), { +const neon_client = neon(env.DATABASE_URL); +export const db = drizzle(neon_client, { schema, }); From ffd85c5623b7f71a6e67e5b64a5dae286cb49ecf Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 5 Nov 2024 15:29:51 -0600 Subject: [PATCH 07/10] fix searchBar props error --- src/components/searchBar/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/searchBar/index.tsx b/src/components/searchBar/index.tsx index 228aeb96..531df19a 100644 --- a/src/components/searchBar/index.tsx +++ b/src/components/searchBar/index.tsx @@ -9,13 +9,18 @@ type SearchBarProps = Omit, 'type'> & { export const SearchBar = (props: SearchBarProps) => { const submitButton = props.submitButton; const submitLogic = props.submitLogic; + const goodProps = { + ...props, + submitButton: undefined, + submitLogic: undefined, + }; return (
{ From 625d38d8df758f4308be4fb26d200e87384c66c8 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 5 Nov 2024 17:11:45 -0600 Subject: [PATCH 08/10] add editing club listed officers and display them --- .../edit/officers/EditListedOfficerForm.tsx | 217 ++++++++++++++++++ .../edit/officers/EditOfficerForm.tsx | 38 +-- .../manage/[clubId]/edit/officers/page.tsx | 9 +- .../club/listing/ClubInfoSegment.tsx | 14 +- src/server/api/routers/club.ts | 32 +-- src/server/api/routers/clubEdit.ts | 64 +++++- src/server/db/index.ts | 2 + src/utils/formSchemas.ts | 9 + 8 files changed, 316 insertions(+), 69 deletions(-) create mode 100644 src/app/manage/[clubId]/edit/officers/EditListedOfficerForm.tsx diff --git a/src/app/manage/[clubId]/edit/officers/EditListedOfficerForm.tsx b/src/app/manage/[clubId]/edit/officers/EditListedOfficerForm.tsx new file mode 100644 index 00000000..3f8e99cd --- /dev/null +++ b/src/app/manage/[clubId]/edit/officers/EditListedOfficerForm.tsx @@ -0,0 +1,217 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { api } from '@src/trpc/react'; +import { editListedOfficerSchema } from '@src/utils/formSchemas'; +import { useRouter } from 'next/navigation'; +import { useReducer } from 'react'; +import { + type FieldErrors, + type UseFormRegister, + useFieldArray, + useForm, +} from 'react-hook-form'; +import { type z } from 'zod'; + +type x = { + id?: boolean; + name?: boolean; + position?: boolean; +}[]; +const modifiedFields = ( + dirtyFields: x, + data: z.infer, + officers: { + id?: string; + name: string; + position: string; + }[], +) => { + const modded = data.officers.filter( + (value, index) => + !!officers.find((off) => off.id === value.id) && + dirtyFields[index]?.position, + ); + const created = data.officers.filter( + (value) => typeof value.id === 'undefined', + ); + return { + modified: modded as { id: string; name: string; position: string }[], + created: created as { name: string; position: string }[], + }; +}; + +type modifyDeletedAction = + | { + type: 'add'; + target: string; + } + | { type: 'reset' }; +const deletedReducer = (state: Array, action: modifyDeletedAction) => { + switch (action.type) { + case 'add': + return [...state, action.target]; + case 'reset': + return []; + } +}; + +type EditOfficerFormProps = { + clubId: string; + officers: { + id: string; + name: string; + position: string; + }[]; +}; +const EditOfficerForm = ({ clubId, officers }: EditOfficerFormProps) => { + const { + control, + register, + handleSubmit, + reset, + formState: { errors, dirtyFields, isDirty }, + } = useForm>({ + resolver: zodResolver(editListedOfficerSchema), + defaultValues: { officers: officers }, + }); + const { fields, append, remove } = useFieldArray({ + control, + name: 'officers', + }); + const [deleted, modifyDeleted] = useReducer(deletedReducer, []); + const removeItem = (index: number) => { + const off = officers.find((officer) => officer.id == fields[index]?.id); + if (off) modifyDeleted({ type: 'add', target: off.id }); + remove(index); + }; + const router = useRouter(); + const editOfficers = api.club.edit.listedOfficers.useMutation({ + onSuccess: () => { + router.push(`/directory/${clubId}`); + }, + }); + const submitForm = handleSubmit((data) => { + if (dirtyFields.officers !== undefined) { + const { modified, created } = modifiedFields( + dirtyFields.officers, + data, + officers, + ); + if (!editOfficers.isPending) { + editOfficers.mutate({ + clubId: clubId, + deleted: deleted, + modified: modified, + created: created, + }); + } + } + }); + return ( +
+
+
+
+ +
+
+ {errors.officers && ( +

{errors.officers.message}

+ )} +
+
+ {fields.map((field, index) => ( + + ))} +
+
+
+ + +
+
+
+ ); +}; +export default EditOfficerForm; +type OfficerItemProps = { + register: UseFormRegister>; + remove: (index: number) => void; + index: number; + errors: FieldErrors>; +}; +const OfficerItem = ({ register, index, remove, errors }: OfficerItemProps) => { + return ( +
+
+
+ + {errors.officers && errors.officers[index]?.position && ( +

+ {errors.officers[index]?.position?.message} +

+ )} +
+
+ + {errors.officers && errors.officers[index]?.position && ( +

+ {errors.officers[index]?.position?.message} +

+ )} +
+
+ +
+ ); +}; diff --git a/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx b/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx index f0f027d7..aacdb39b 100644 --- a/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx +++ b/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx @@ -6,12 +6,7 @@ import { api } from '@src/trpc/react'; import { editOfficerSchema } from '@src/utils/formSchemas'; import { useRouter } from 'next/navigation'; import { useReducer } from 'react'; -import { - type FieldErrors, - type UseFormRegister, - useFieldArray, - useForm, -} from 'react-hook-form'; +import { useFieldArray, useForm } from 'react-hook-form'; import { type z } from 'zod'; type x = { @@ -69,14 +64,12 @@ type EditOfficerFormProps = { userId: string; name: string; locked: boolean; - title: string; position: 'President' | 'Officer'; }[]; }; const EditOfficerForm = ({ clubId, officers }: EditOfficerFormProps) => { const { control, - register, handleSubmit, reset, formState: { errors, dirtyFields, isDirty }, @@ -143,11 +136,9 @@ const EditOfficerForm = ({ clubId, officers }: EditOfficerFormProps) => { {fields.map((field, index) => ( @@ -181,23 +172,13 @@ const EditOfficerForm = ({ clubId, officers }: EditOfficerFormProps) => { }; export default EditOfficerForm; type OfficerItemProps = { - register: UseFormRegister>; remove: (index: number, userId: string) => void; id: string; index: number; name: string; locked: boolean; - errors: FieldErrors>; }; -const OfficerItem = ({ - register, - index, - id, - name, - remove, - errors, - locked, -}: OfficerItemProps) => { +const OfficerItem = ({ index, id, name, remove, locked }: OfficerItemProps) => { return (
@@ -206,21 +187,6 @@ const OfficerItem = ({ {name}
-
- - {errors.officers && errors.officers[index]?.title && ( -

- {errors.officers[index]?.title?.message} -

- )} -
- {club.userMetadataToClubs.length != 0 && ( + {club.officers.length != 0 && (
<>

Leadership

- {club.userMetadataToClubs.map((officer) => ( -
+ {club.officers.map((officer) => ( +
Picture of the author

- {officer.userMetadata.firstName + - ' ' + - officer.userMetadata.lastName} + {officer.name}

- Officer {/* TODO: link to officers table */} + {officer.position}

diff --git a/src/server/api/routers/club.ts b/src/server/api/routers/club.ts index 07cd3887..36f6dafc 100644 --- a/src/server/api/routers/club.ts +++ b/src/server/api/routers/club.ts @@ -1,14 +1,4 @@ -import { - eq, - ilike, - sql, - and, - notInArray, - inArray, - or, - lt, - gt, -} from 'drizzle-orm'; +import { eq, ilike, sql, and, notInArray, inArray, lt, gt } from 'drizzle-orm'; import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc'; import { z } from 'zod'; import { clubEditRouter } from './clubEdit'; @@ -16,6 +6,7 @@ import { userMetadataToClubs } from '@src/server/db/schema/users'; import { club, usedTags } from '@src/server/db/schema/club'; import { contacts } from '@src/server/db/schema/contacts'; import { carousel } from '@src/server/db/schema/admin'; +import { officers as officersTable } from '@src/server/db/schema/officers'; import { createClubSchema as baseClubSchema } from '@src/utils/formSchemas'; const byNameSchema = z.object({ name: z.string().default(''), @@ -252,6 +243,14 @@ export const clubRouter = createTRPCRouter({ }); return officers; }), + getListedOfficers: protectedProcedure + .input(byIdSchema) + .query(async ({ input, ctx }) => { + const officers = await ctx.db.query.officers.findMany({ + where: eq(officersTable.clubId, input.id), + }); + return officers; + }), isActive: publicProcedure.input(byIdSchema).query(async ({ input, ctx }) => { const hasPresident = await ctx.db.query.userMetadataToClubs.findFirst({ where: and( @@ -278,16 +277,7 @@ export const clubRouter = createTRPCRouter({ where: (club) => eq(club.id, id), with: { contacts: true, - userMetadataToClubs: { - where: (row) => - or( - eq(row.memberType, 'President'), - eq(row.memberType, 'Officer'), - ), - with: { - userMetadata: { columns: { firstName: true, lastName: true } }, - }, - }, + officers: true, }, }); return byId; diff --git a/src/server/api/routers/clubEdit.ts b/src/server/api/routers/clubEdit.ts index 30ca549c..3dfbe4de 100644 --- a/src/server/api/routers/clubEdit.ts +++ b/src/server/api/routers/clubEdit.ts @@ -8,6 +8,7 @@ import { selectContact } from '@src/server/db/models'; import { club } from '@src/server/db/schema/club'; import { contacts } from '@src/server/db/schema/contacts'; import { userMetadataToClubs } from '@src/server/db/schema/users'; +import { officers } from '@src/server/db/schema/officers'; async function isUserOfficer(userId: string, clubId: string) { const officer = await db.query.userMetadataToClubs.findFirst({ @@ -36,7 +37,7 @@ const editContactSchema = z.object({ modified: selectContact.array(), created: selectContact.omit({ clubId: true }).array(), }); -const editOfficerSchema = z.object({ +const editCollaboratorSchema = z.object({ clubId: z.string(), deleted: z.string().array(), modified: z @@ -53,6 +54,24 @@ const editOfficerSchema = z.object({ }) .array(), }); + +const editOfficerSchema = z.object({ + clubId: z.string(), + deleted: z.string().array(), + modified: z + .object({ + id: z.string(), + name: z.string(), + position: z.string(), + }) + .array(), + created: z + .object({ + name: z.string(), + position: z.string(), + }) + .array(), +}); const deleteSchema = z.object({ clubId: z.string() }); export const clubEditRouter = createTRPCRouter({ @@ -117,7 +136,7 @@ export const clubEditRouter = createTRPCRouter({ .onConflictDoNothing(); }), officers: protectedProcedure - .input(editOfficerSchema) + .input(editCollaboratorSchema) .mutation(async ({ input, ctx }) => { const isOfficer = await isUserOfficer(ctx.session.user.id, input.clubId); if (!isOfficer) { @@ -169,6 +188,47 @@ export const clubEditRouter = createTRPCRouter({ where: eq(userMetadataToClubs.memberType, 'Member'), }); }), + listedOfficers: protectedProcedure + .input(editOfficerSchema) + .mutation(async ({ input, ctx }) => { + const isOfficer = await isUserOfficer(ctx.session.user.id, input.clubId); + if (!isOfficer) { + throw new TRPCError({ + message: 'must be an officer to modify this club', + code: 'UNAUTHORIZED', + }); + } + if (input.deleted.length > 0) { + await ctx.db + .delete(userMetadataToClubs) + .where( + and( + eq(userMetadataToClubs.clubId, input.clubId), + inArray(userMetadataToClubs.userId, input.deleted), + ), + ); + } + const promises: Promise[] = []; + for (const modded of input.modified) { + const prom = ctx.db + .update(officers) + .set({ position: modded.position }) + .where( + and(eq(officers.id, modded.id), eq(officers.clubId, input.clubId)), + ); + promises.push(prom); + } + await Promise.allSettled(promises); + if (input.created.length === 0) return; + + await ctx.db.insert(officers).values( + input.created.map((officer) => ({ + clubId: input.clubId, + name: officer.name, + position: officer.position, + })), + ); + }), delete: protectedProcedure .input(deleteSchema) .mutation(async ({ input, ctx }) => { diff --git a/src/server/db/index.ts b/src/server/db/index.ts index cc1185ab..59295784 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -7,6 +7,7 @@ import * as events from './schema/events'; import * as users from './schema/users'; import * as forms from './schema/forms'; import * as admin from './schema/admin'; +import * as officers from './schema/officers'; import { neon } from '@neondatabase/serverless'; const schema = { @@ -16,6 +17,7 @@ const schema = { ...users, ...forms, ...admin, + ...officers, }; const neon_client = neon(env.DATABASE_URL); diff --git a/src/utils/formSchemas.ts b/src/utils/formSchemas.ts index 2cc635bb..77dc0bf7 100644 --- a/src/utils/formSchemas.ts +++ b/src/utils/formSchemas.ts @@ -36,6 +36,15 @@ export const editOfficerSchema = z.object({ }) .array(), }); +export const editListedOfficerSchema = z.object({ + officers: z + .object({ + id: z.string().optional(), + name: z.string(), + position: z.string().min(1), + }) + .array(), +}); export const createEventSchema = z.object({ clubId: z.string(), From 59ba703c66a8e9327763cf600c78e11e362f02e5 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 5 Nov 2024 17:33:05 -0600 Subject: [PATCH 09/10] fix redirect --- src/components/admin/ClubTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/admin/ClubTable.tsx b/src/components/admin/ClubTable.tsx index 8123e162..51eeb228 100644 --- a/src/components/admin/ClubTable.tsx +++ b/src/components/admin/ClubTable.tsx @@ -32,7 +32,7 @@ export default function ClubTable({ clubs }: { clubs: Club[] }) { id: 'view', cell: ({ row }) => ( From 439237b82e3c20a10c7fa2c5ea0c4bfede287715 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 5 Nov 2024 19:06:44 -0600 Subject: [PATCH 10/10] private -> public --- src/server/api/routers/club.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/api/routers/club.ts b/src/server/api/routers/club.ts index 36f6dafc..20b693bd 100644 --- a/src/server/api/routers/club.ts +++ b/src/server/api/routers/club.ts @@ -243,7 +243,7 @@ export const clubRouter = createTRPCRouter({ }); return officers; }), - getListedOfficers: protectedProcedure + getListedOfficers: publicProcedure .input(byIdSchema) .query(async ({ input, ctx }) => { const officers = await ctx.db.query.officers.findMany({