From 966547a9b62ddd6b5bb82647fa2682a003cbf1b0 Mon Sep 17 00:00:00 2001 From: Damian Date: Thu, 22 Aug 2024 18:27:09 -0300 Subject: [PATCH] Add eligible / not eligible to submissions --- .../app/admin/_components/SubmissionCard.tsx | 85 ++++++ .../[submissionId]/eligible/route.ts | 36 +++ .../nextjs/services/database/config/schema.ts | 5 +- .../migrations/0001_young_jamie_braddock.sql | 3 + .../migrations/meta/0001_snapshot.json | 273 ++++++++++++++++++ .../database/migrations/meta/_journal.json | 10 +- .../database/repositories/submissions.ts | 21 +- 7 files changed, 428 insertions(+), 5 deletions(-) create mode 100644 packages/nextjs/app/api/submissions/[submissionId]/eligible/route.ts create mode 100644 packages/nextjs/services/database/migrations/0001_young_jamie_braddock.sql create mode 100644 packages/nextjs/services/database/migrations/meta/0001_snapshot.json diff --git a/packages/nextjs/app/admin/_components/SubmissionCard.tsx b/packages/nextjs/app/admin/_components/SubmissionCard.tsx index eaca930..eaa2b22 100644 --- a/packages/nextjs/app/admin/_components/SubmissionCard.tsx +++ b/packages/nextjs/app/admin/_components/SubmissionCard.tsx @@ -31,6 +31,10 @@ export const SubmissionCard = ({ submission }: { submission: Submission }) => { mutationFn: (newVote: { score: number }) => postMutationFetcher(`/api/submissions/${submission.id}/votes`, { body: newVote }), }); + const { mutateAsync: postNewEligible } = useMutation({ + mutationFn: (newEligible: { eligible: boolean; clear: boolean }) => + postMutationFetcher(`/api/submissions/${submission.id}/eligible`, { body: newEligible }), + }); const { refresh } = useRouter(); const clientFormAction = async (formData: FormData) => { @@ -80,6 +84,36 @@ export const SubmissionCard = ({ submission }: { submission: Submission }) => { } }; + const setEligible = async (newEligible: boolean) => { + try { + const result = await postNewEligible({ eligible: newEligible, clear: false }); + + notification.success(result.message); + refresh(); + } catch (error: any) { + if (error instanceof Error) { + notification.error(error.message); + return; + } + notification.error("Something went wrong"); + } + }; + + const clearEligible = async () => { + try { + const result = await postNewEligible({ eligible: false, clear: true }); + + notification.success(result.message); + refresh(); + } catch (error: any) { + if (error instanceof Error) { + notification.error(error.message); + return; + } + notification.error("Something went wrong"); + } + }; + const scoreAvg = submission.votes.length > 0 ? (submission.votes.map(vote => vote.score).reduce((a, b) => a + b, 0) / submission.votes.length).toFixed(2) @@ -95,6 +129,57 @@ export const SubmissionCard = ({ submission }: { submission: Submission }) => {
+
+ setEligible(false)} + /> + {submission.eligible === false ? ( +
+ +
+ ) : ( + + )} + setEligible(true)} + /> + {submission.eligible === true ? ( +
+ +
+ ) : ( + + )} + {submission.eligible !== undefined && ( + + )} +
builders.id) .notNull(), + eligible: boolean("eligible"), + eligibleTimestamp: timestamp("eligible_timestamp"), + eligibleAdmin: varchar("eligible_admin", { length: 256 }), }); export const comments = pgTable("comments", { diff --git a/packages/nextjs/services/database/migrations/0001_young_jamie_braddock.sql b/packages/nextjs/services/database/migrations/0001_young_jamie_braddock.sql new file mode 100644 index 0000000..ab29669 --- /dev/null +++ b/packages/nextjs/services/database/migrations/0001_young_jamie_braddock.sql @@ -0,0 +1,3 @@ +ALTER TABLE "submissions" ADD COLUMN "eligible" boolean;--> statement-breakpoint +ALTER TABLE "submissions" ADD COLUMN "eligible_timestamp" timestamp;--> statement-breakpoint +ALTER TABLE "submissions" ADD COLUMN "eligible_admin" varchar(256); \ No newline at end of file diff --git a/packages/nextjs/services/database/migrations/meta/0001_snapshot.json b/packages/nextjs/services/database/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..dc5fe3e --- /dev/null +++ b/packages/nextjs/services/database/migrations/meta/0001_snapshot.json @@ -0,0 +1,273 @@ +{ + "id": "e27f3c3d-878d-4b2a-b845-9df8ba748fba", + "prevId": "80443e7a-1d64-4aaa-b15a-c72ed19ef3b2", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.builders": { + "name": "builders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(256)", + "primaryKey": true, + "notNull": true + }, + "role": { + "name": "role", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "submission_id": { + "name": "submission_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "builder_id": { + "name": "builder_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_submission_id_submissions_id_fk": { + "name": "comments_submission_id_submissions_id_fk", + "tableFrom": "comments", + "tableTo": "submissions", + "columnsFrom": [ + "submission_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_builder_id_builders_id_fk": { + "name": "comments_builder_id_builders_id_fk", + "tableFrom": "comments", + "tableTo": "builders", + "columnsFrom": [ + "builder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.submissions": { + "name": "submissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "link_to_repository": { + "name": "link_to_repository", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "link_to_video": { + "name": "link_to_video", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "feedback": { + "name": "feedback", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "submission_timestamp": { + "name": "submission_timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "builder_id": { + "name": "builder_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "eligible": { + "name": "eligible", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "eligible_timestamp": { + "name": "eligible_timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "eligible_admin": { + "name": "eligible_admin", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "submissions_builder_id_builders_id_fk": { + "name": "submissions_builder_id_builders_id_fk", + "tableFrom": "submissions", + "tableTo": "builders", + "columnsFrom": [ + "builder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.votes": { + "name": "votes", + "schema": "", + "columns": { + "submission_id": { + "name": "submission_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "builder_id": { + "name": "builder_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_submission_id_submissions_id_fk": { + "name": "votes_submission_id_submissions_id_fk", + "tableFrom": "votes", + "tableTo": "submissions", + "columnsFrom": [ + "submission_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_builder_id_builders_id_fk": { + "name": "votes_builder_id_builders_id_fk", + "tableFrom": "votes", + "tableTo": "builders", + "columnsFrom": [ + "builder_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "votes_submission_id_builder_id_pk": { + "name": "votes_submission_id_builder_id_pk", + "columns": [ + "submission_id", + "builder_id" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/nextjs/services/database/migrations/meta/_journal.json b/packages/nextjs/services/database/migrations/meta/_journal.json index 494ac7c..3146761 100644 --- a/packages/nextjs/services/database/migrations/meta/_journal.json +++ b/packages/nextjs/services/database/migrations/meta/_journal.json @@ -8,7 +8,13 @@ "when": 1724237255094, "tag": "0000_easy_the_initiative", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1724361890196, + "tag": "0001_young_jamie_braddock", + "breakpoints": true } ] -} - +} \ No newline at end of file diff --git a/packages/nextjs/services/database/repositories/submissions.ts b/packages/nextjs/services/database/repositories/submissions.ts index 21d1396..bef8308 100644 --- a/packages/nextjs/services/database/repositories/submissions.ts +++ b/packages/nextjs/services/database/repositories/submissions.ts @@ -1,4 +1,4 @@ -import { InferInsertModel, InferSelectModel } from "drizzle-orm"; +import { InferInsertModel, InferSelectModel, desc, eq } from "drizzle-orm"; import { db } from "~~/services/database/config/postgresClient"; import { comments, submissions, votes } from "~~/services/database/config/schema"; @@ -8,9 +8,26 @@ type Vote = InferInsertModel; export type Submission = InferSelectModel & { comments: Comment[]; votes: Vote[] }; export async function getAllSubmissions() { - return await db.query.submissions.findMany({ with: { comments: true, votes: true } }); + return await db.query.submissions.findMany({ + with: { comments: true, votes: true }, + orderBy: [desc(submissions.id)], + }); } export async function createSubmission(submission: SubmissionInsert) { return await db.insert(submissions).values(submission); } + +export async function setEligible(submissionId: number, eligible: boolean, builderId: string) { + return await db + .update(submissions) + .set({ eligible, eligibleAdmin: builderId, eligibleTimestamp: new Date() }) + .where(eq(submissions.id, submissionId)); +} + +export async function clearEligible(submissionId: number) { + return await db + .update(submissions) + .set({ eligible: null, eligibleAdmin: null, eligibleTimestamp: null }) + .where(eq(submissions.id, submissionId)); +}