From 78839e3eac6e1522d05f51138e800460b9ece2da Mon Sep 17 00:00:00 2001 From: Dylan Vidal Date: Sat, 17 Jan 2026 18:47:42 -0500 Subject: [PATCH 1/2] setup recruiting hook, fix form update, and add custom connection values --- .../src/app/admin/forms/[slug]/con-viewer.tsx | 8 +- .../src/app/admin/forms/[slug]/linker.tsx | 70 ++++++++++++-- .../_components/PerUserResponsesView.tsx | 51 +++++++++- .../app/admin/forms/[slug]/responses/page.tsx | 1 + apps/blade/src/app/forms/[formName]/page.tsx | 13 ++- packages/api/src/root.ts | 3 + packages/api/src/routers/forms.ts | 41 +++++++- packages/api/src/routers/misc.ts | 94 +++++++++++++++++++ packages/consts/src/knight-hacks.ts | 35 +++++++ 9 files changed, 296 insertions(+), 20 deletions(-) create mode 100644 packages/api/src/routers/misc.ts diff --git a/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx b/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx index 0765c02e..1eb1c350 100644 --- a/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx @@ -1,5 +1,5 @@ -import { useState } from "react"; import { Trash2 } from "lucide-react"; +import { useState } from "react"; import { Button } from "@forge/ui/button"; import { Card } from "@forge/ui/card"; @@ -14,8 +14,8 @@ import { } from "@forge/ui/dialog"; import { toast } from "@forge/ui/toast"; -import type { MatchingType } from "./linker"; import { api } from "~/trpc/react"; +import type { MatchingType } from "./linker"; export function ConnectionViewer({ matching, @@ -93,7 +93,9 @@ export function ConnectionViewer({ Form Field
- {conn.formField || "Not Mapped"} + {conn.customValue + ? `Custom: "${conn.customValue}"` + : conn.formField || "Not Mapped"}
diff --git a/apps/blade/src/app/admin/forms/[slug]/linker.tsx b/apps/blade/src/app/admin/forms/[slug]/linker.tsx index f14f0d00..4c25933c 100644 --- a/apps/blade/src/app/admin/forms/[slug]/linker.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/linker.tsx @@ -1,7 +1,7 @@ "use client"; -import React, { useState } from "react"; import { Loader2 } from "lucide-react"; +import { useState } from "react"; import { z } from "zod"; import { Button } from "@forge/ui/button"; @@ -26,6 +26,7 @@ const matchingSchema = z.object({ z.object({ procField: z.string(), formField: z.string().optional(), + customValue: z.string().optional(), }), ), }); @@ -44,7 +45,7 @@ export default function ListMatcher({ const [procFields, setProcFields] = useState([]); const [isLoading, setIsLoading] = useState(false); const [connections, setConnections] = useState< - { procField: string; formField: string }[] + { procField: string; formField?: string; customValue?: string }[] >([]); const formFields = form.questions; @@ -68,7 +69,7 @@ export default function ListMatcher({ const newProcFields = procs[value].inputSchema; setProcFields(newProcFields); setConnections( - newProcFields.map((item) => ({ procField: item, formField: "" })), + newProcFields.map((item) => ({ procField: item })), ); }; @@ -76,7 +77,28 @@ export default function ListMatcher({ setConnections((prev) => { const updated = [...prev]; if (!updated[index]) return updated; - updated[index] = { ...updated[index], formField: value }; + if (value === "__CUSTOM__") { + updated[index] = { + ...updated[index], + formField: undefined, + customValue: updated[index].customValue || "", + }; + } else { + updated[index] = { + ...updated[index], + formField: value, + customValue: undefined, + }; + } + return updated; + }); + }; + + const updateCustomValue = (index: number, value: string) => { + setConnections((prev) => { + const updated = [...prev]; + if (!updated[index]) return updated; + updated[index] = { ...updated[index], customValue: value }; return updated; }); }; @@ -89,13 +111,31 @@ export default function ListMatcher({ return formFields.filter((item) => !usedItems.includes(item)); }; + const isCustomValue = (index: number) => { + const conn = connections[index]; + return conn && !conn.formField && (conn.customValue !== undefined); + }; + const handleSubmit = () => { setIsLoading(true); + const cleanedConnections = connections.map((conn) => { + const cleaned: { procField: string; formField?: string; customValue?: string } = { + procField: conn.procField, + }; + if (conn.formField) { + cleaned.formField = conn.formField; + } + if (conn.customValue !== undefined && conn.customValue !== "") { + cleaned.customValue = conn.customValue; + } + return cleaned; + }); + const data = { form: form.id, proc: procSelection, - connections: connections, + connections: cleanedConnections, }; try { @@ -126,7 +166,7 @@ export default function ListMatcher({ - {procFields.length > 0 && formFields.length > 0 && ( + {procFields.length > 0 && (

Connect Items

@@ -145,7 +185,11 @@ export default function ListMatcher({
+ {isCustomValue(index) && ( + + updateCustomValue(index, e.target.value) + } + className="mt-2" + /> + )}
))} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx index 340b679b..b77066d2 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useRouter } from "next/navigation"; import Link from "next/link"; import { ChevronLeft, @@ -11,6 +12,7 @@ import { FileSpreadsheet, FileText, Loader2, + X, } from "lucide-react"; import type { FormType } from "@forge/consts/knight-hacks"; @@ -24,6 +26,7 @@ import { api } from "~/trpc/react"; interface PerUserResponsesViewProps { formData: FormType; responses: { + id: string; submittedAt: Date; responseData: Record; member: { @@ -36,6 +39,7 @@ interface PerUserResponsesViewProps { } interface GroupedResponse { + id: string; member: { firstName: string; lastName: string; @@ -58,6 +62,7 @@ export function PerUserResponsesView({ acc[anonymousKey] = []; } acc[anonymousKey].push({ + id: response.id, member: { firstName: "Anonymous", lastName: "", @@ -75,6 +80,7 @@ export function PerUserResponsesView({ acc[userId] = []; } acc[userId].push({ + id: response.id, member: response.member, submittedAt: response.submittedAt, responseData: response.responseData, @@ -191,10 +197,15 @@ export function PerUserResponsesView({ {currentUserResponses.map((response, responseIndex) => ( - Response #{responseIndex + 1} -

- Submitted: {new Date(response.submittedAt).toLocaleString()} -

+
+
+ Response #{responseIndex + 1} +

+ Submitted: {new Date(response.submittedAt).toLocaleString()} +

+
+ +
{formData.questions.map((question, questionIndex) => { @@ -241,6 +252,38 @@ export function PerUserResponsesView({ ); } +function DeleteResponseButton({ responseId }: { responseId: string }) { + const router = useRouter(); + const utils = api.useUtils(); + + const deleteResponse = api.forms.deleteResponse.useMutation({ + async onSuccess() { + toast.success("Response deleted"); + await utils.forms.getResponses.invalidate(); + router.refresh(); + }, + onError() { + toast.error("Failed to delete response"); + }, + }); + + return ( + + ); +} + function FileUploadDisplay({ objectName }: { objectName: string }) { const [isDownloading, setIsDownloading] = useState(false); diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/page.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/page.tsx index a76823e0..862a55eb 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/page.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/page.tsx @@ -65,6 +65,7 @@ export default async function FormResponsesPage({ // type assertion to the correct format const responses = apiResponses as { + id: string; submittedAt: Date; responseData: Record; member: { diff --git a/apps/blade/src/app/forms/[formName]/page.tsx b/apps/blade/src/app/forms/[formName]/page.tsx index 8d7b6022..d70d1362 100644 --- a/apps/blade/src/app/forms/[formName]/page.tsx +++ b/apps/blade/src/app/forms/[formName]/page.tsx @@ -48,10 +48,14 @@ export default async function FormResponderPage({ const data: Record = {}; for (const map of con.connections as { procField: string; - formField: string; + formField?: string; + customValue?: string; }[]) { - if (map.formField in response) + if (map.customValue !== undefined) { + data[map.procField] = map.customValue; + } else if (map.formField && map.formField in response) { data[map.procField] = response[map.formField]; + } } const route = procs[con.proc]?.route.split("."); @@ -71,10 +75,11 @@ export default async function FormResponderPage({ color: "success_green", userId: session.user.discordUserId, }); - } catch { + } catch (error) { + const errorMessage = JSON.stringify(error, null, 2); await log({ title: `Failed to automatically fire procedure`, - message: `**Failed to fire procedure**\n\`${con.proc}\`\n\nTriggered after **${form.name}** submission from **${session.user.name}**\n\n**Data:**\n\`\`\`json\n${stringify(data)}\`\`\``, + message: `**Failed to fire procedure**\n\`${con.proc}\`\n\nTriggered after **${form.name}** submission from **${session.user.name}**\n\n**Data:**\n\`\`\`json\n${stringify(data)}\`\`\`` + `\n\n**Error:**\n\`\`\`json\n${errorMessage}\`\`\``, color: "uhoh_red", userId: session.user.discordUserId, }); diff --git a/packages/api/src/root.ts b/packages/api/src/root.ts index 4b8e3dd0..35b1f091 100644 --- a/packages/api/src/root.ts +++ b/packages/api/src/root.ts @@ -13,6 +13,7 @@ import { hackathonRouter } from "./routers/hackathon"; import { hackerRouter } from "./routers/hacker"; import { judgeRouter } from "./routers/judge"; import { memberRouter } from "./routers/member"; +import { miscRouter } from "./routers/misc"; import { passkitRouter } from "./routers/passkit"; import { qrRouter } from "./routers/qr"; import { resumeRouter } from "./routers/resume"; @@ -21,6 +22,7 @@ import { userRouter } from "./routers/user"; import { createTRPCRouter } from "./trpc"; export const appRouter = createTRPCRouter<{ + misc: typeof miscRouter; auth: typeof authRouter; duesPayment: typeof duesPaymentRouter; member: typeof memberRouter; @@ -42,6 +44,7 @@ export const appRouter = createTRPCRouter<{ forms: typeof formsRouter; roles: typeof rolesRouter; }>({ + misc: miscRouter, auth: authRouter, duesPayment: duesPaymentRouter, member: memberRouter, diff --git a/packages/api/src/routers/forms.ts b/packages/api/src/routers/forms.ts index c10b68e6..f7f6f265 100644 --- a/packages/api/src/routers/forms.ts +++ b/packages/api/src/routers/forms.ts @@ -1,6 +1,6 @@ -import type { JSONSchema7 } from "json-schema"; import { TRPCError } from "@trpc/server"; import { and, count, desc, eq, inArray, lt, sql } from "drizzle-orm"; +import type { JSONSchema7 } from "json-schema"; import jsonSchemaToZod from "json-schema-to-zod"; import * as z from "zod"; @@ -118,6 +118,10 @@ export const formsRouter = { }); } + const existingForm = await db.query.FormsSchemas.findFirst({ + where: (t, { eq }) => eq(t.id, input.id ?? ""), + }); + await db .insert(FormsSchemas) .values({ @@ -125,6 +129,7 @@ export const formsRouter = { name: input.formData.name, slugName: slug_name, formValidatorJson: jsonSchema.schema, + sectionId: existingForm?.sectionId ?? null, }) .onConflictDoUpdate({ //If it already exists upsert it @@ -134,6 +139,7 @@ export const formsRouter = { name: input.formData.name, slugName: slug_name, formValidatorJson: jsonSchema.schema, + sectionId: existingForm?.sectionId ?? null, }, }); }), @@ -244,7 +250,17 @@ export const formsRouter = { }), addConnection: permProcedure - .input(TrpcFormConnectionSchema) + .input( + TrpcFormConnectionSchema.extend({ + connections: z.array( + z.object({ + procField: z.string(), + formField: z.string().optional(), + customValue: z.string().optional(), + }), + ), + }), + ) .mutation(async ({ input, ctx }) => { controlPerms.or(["EDIT_FORMS"], ctx); try { @@ -360,6 +376,7 @@ export const formsRouter = { controlPerms.or(["READ_FORMS", "EDIT_FORMS"], ctx); return await db .select({ + id: FormResponse.id, submittedAt: FormResponse.createdAt, responseData: FormResponse.responseData, member: { @@ -375,6 +392,26 @@ export const formsRouter = { .orderBy(desc(FormResponse.createdAt)); }), + deleteResponse: permProcedure + .input(z.object({ id: z.string() })) + .mutation(async ({ input, ctx }) => { + controlPerms.or(["EDIT_FORMS"], ctx); + try { + await db.delete(FormResponse).where(eq(FormResponse.id, input.id)); + await log({ + title: `Form response deleted`, + message: `**Response deleted:** ${input.id}`, + color: "uhoh_red", + userId: ctx.session.user.discordUserId, + }); + } catch { + throw new TRPCError({ + message: "Could not delete response", + code: "BAD_REQUEST", + }); + } + }), + getUserResponse: protectedProcedure .input( z.object({ diff --git a/packages/api/src/routers/misc.ts b/packages/api/src/routers/misc.ts new file mode 100644 index 00000000..a76e2b7a --- /dev/null +++ b/packages/api/src/routers/misc.ts @@ -0,0 +1,94 @@ +import { RECRUITING_CHANNEL, TEAM_MAP } from "@forge/consts/knight-hacks"; +import type { TRPCRouterRecord } from "@trpc/server"; +import { Routes } from "discord-api-types/v10"; +import { z } from "zod"; +import { protectedProcedure } from "../trpc"; +import { discord } from "../utils"; + + +// Miscellaneous routes (primarily for form integrations) +export const miscRouter = { + recruitingUpdate: protectedProcedure + .meta({ + id: "recruitingUpdate", + inputSchema: z.object({ + name: z.string().min(1), + email: z.string().email(), + major: z.string().min(1), + gradTerm: z.string().min(1), + gradYear: z.number().min(1), + team: z.string().min(1), + }), + }) + .input( + z.object({ + name: z.string().min(1), + email: z.string().email(), + major: z.string().min(1), + gradTerm: z.string().min(1), + gradYear: z.number().min(1), + team: z.string().min(1), + }), + ) + .mutation(async ({ input }) => { + + const team = TEAM_MAP.find(team => team.team === input.team); + if (!team) { + throw new Error("Team not found"); + } + + const directorRole = team.director_role; + + // Convert hex color string to integer for Discord API + const colorInt = parseInt(team.color.replace("#", ""), 16); + + await discord.post(Routes.channelMessages(RECRUITING_CHANNEL), { + body: { + content: `<@&${directorRole}> **New Applicant for ${team.team}!**`, + embeds: [ + { + title: `${input.name}'s Application`, + description: `A new applicant is interested in joining the **${team.team}** team.\n\nPlease see details below:`, + color: colorInt, + fields: [ + { + name: "Name", + value: input.name, + inline: true, + }, + { + name: "Email", + value: input.email, + inline: true, + }, + { + name: "Major", + value: input.major, + inline: true, + }, + { + name: "Grad Term", + value: input.gradTerm, + inline: true, + }, + { + name: "Grad Year", + value: input.gradYear.toString(), + inline: true, + }, + { + name: "Team", + value: team.team, + inline: true, + }, + ], + footer: { + text: `Submitted at: ${new Date().toLocaleString()}`, + }, + timestamp: new Date().toISOString(), + }, + ], + }, + }); + }), +} satisfies TRPCRouterRecord; diff --git a/packages/consts/src/knight-hacks.ts b/packages/consts/src/knight-hacks.ts index 8144a87b..347f3199 100644 --- a/packages/consts/src/knight-hacks.ts +++ b/packages/consts/src/knight-hacks.ts @@ -6821,3 +6821,38 @@ export const FORM_QUESTION_TYPES = [ { value: "BOOLEAN", label: "Boolean (Yes/No)" }, { value: "LINK", label: "Link (URL)" }, ] as const; + +export const RECRUITING_CHANNEL = IS_PROD ? "1461758896950608104" : DEV_KNIGHTHACKS_LOG_CHANNEL + +export const TEAM_MAP = [ + { + team: "Outreach", + color: "#88fea1", + director_role: "779845137822908436" + }, + { + team: "Design", + color: "#eaacff", + director_role: "874028482089349172" + }, + { + team: "Development", + color: "#93ceff", + director_role: "1082124530077683772" + }, + { + team: "Sponsorship", + color: "#f5f4af", + director_role: "626815399442513920" + }, + { + team: "Workshops", + color: "#206694", + director_role: "757002949603098837" + }, + { + team: "Projects/Mentorship", + color: "#3498db", + director_role: "1244790444626280550" + } + ] \ No newline at end of file From f8df282c7d678cf096b974b95672a1335282e418 Mon Sep 17 00:00:00 2001 From: Dylan Vidal Date: Sat, 17 Jan 2026 18:49:30 -0500 Subject: [PATCH 2/2] format --- .../src/app/admin/forms/[slug]/con-viewer.tsx | 4 +- .../src/app/admin/forms/[slug]/linker.tsx | 18 ++--- .../_components/PerUserResponsesView.tsx | 2 +- apps/blade/src/app/forms/[formName]/page.tsx | 4 +- packages/api/src/routers/forms.ts | 2 +- packages/api/src/routers/misc.ts | 32 ++++----- packages/consts/src/knight-hacks.ts | 68 ++++++++++--------- 7 files changed, 67 insertions(+), 63 deletions(-) diff --git a/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx b/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx index 1eb1c350..d0491562 100644 --- a/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/con-viewer.tsx @@ -1,5 +1,5 @@ -import { Trash2 } from "lucide-react"; import { useState } from "react"; +import { Trash2 } from "lucide-react"; import { Button } from "@forge/ui/button"; import { Card } from "@forge/ui/card"; @@ -14,8 +14,8 @@ import { } from "@forge/ui/dialog"; import { toast } from "@forge/ui/toast"; -import { api } from "~/trpc/react"; import type { MatchingType } from "./linker"; +import { api } from "~/trpc/react"; export function ConnectionViewer({ matching, diff --git a/apps/blade/src/app/admin/forms/[slug]/linker.tsx b/apps/blade/src/app/admin/forms/[slug]/linker.tsx index 4c25933c..cb6b3c59 100644 --- a/apps/blade/src/app/admin/forms/[slug]/linker.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/linker.tsx @@ -1,7 +1,7 @@ "use client"; -import { Loader2 } from "lucide-react"; import { useState } from "react"; +import { Loader2 } from "lucide-react"; import { z } from "zod"; import { Button } from "@forge/ui/button"; @@ -68,9 +68,7 @@ export default function ListMatcher({ setProcSelection(value); const newProcFields = procs[value].inputSchema; setProcFields(newProcFields); - setConnections( - newProcFields.map((item) => ({ procField: item })), - ); + setConnections(newProcFields.map((item) => ({ procField: item }))); }; const updateConnection = (index: number, value: string) => { @@ -113,14 +111,18 @@ export default function ListMatcher({ const isCustomValue = (index: number) => { const conn = connections[index]; - return conn && !conn.formField && (conn.customValue !== undefined); + return conn && !conn.formField && conn.customValue !== undefined; }; const handleSubmit = () => { setIsLoading(true); const cleanedConnections = connections.map((conn) => { - const cleaned: { procField: string; formField?: string; customValue?: string } = { + const cleaned: { + procField: string; + formField?: string; + customValue?: string; + } = { procField: conn.procField, }; if (conn.formField) { @@ -209,9 +211,7 @@ export default function ListMatcher({ id={`custom-${index}`} placeholder="Enter custom value" value={connection.customValue || ""} - onChange={(e) => - updateCustomValue(index, e.target.value) - } + onChange={(e) => updateCustomValue(index, e.target.value)} className="mt-2" /> )} diff --git a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx index b77066d2..aa7b12fa 100644 --- a/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx +++ b/apps/blade/src/app/admin/forms/[slug]/responses/_components/PerUserResponsesView.tsx @@ -1,8 +1,8 @@ "use client"; import { useState } from "react"; -import { useRouter } from "next/navigation"; import Link from "next/link"; +import { useRouter } from "next/navigation"; import { ChevronLeft, ChevronRight, diff --git a/apps/blade/src/app/forms/[formName]/page.tsx b/apps/blade/src/app/forms/[formName]/page.tsx index d70d1362..8c227d50 100644 --- a/apps/blade/src/app/forms/[formName]/page.tsx +++ b/apps/blade/src/app/forms/[formName]/page.tsx @@ -79,7 +79,9 @@ export default async function FormResponderPage({ const errorMessage = JSON.stringify(error, null, 2); await log({ title: `Failed to automatically fire procedure`, - message: `**Failed to fire procedure**\n\`${con.proc}\`\n\nTriggered after **${form.name}** submission from **${session.user.name}**\n\n**Data:**\n\`\`\`json\n${stringify(data)}\`\`\`` + `\n\n**Error:**\n\`\`\`json\n${errorMessage}\`\`\``, + message: + `**Failed to fire procedure**\n\`${con.proc}\`\n\nTriggered after **${form.name}** submission from **${session.user.name}**\n\n**Data:**\n\`\`\`json\n${stringify(data)}\`\`\`` + + `\n\n**Error:**\n\`\`\`json\n${errorMessage}\`\`\``, color: "uhoh_red", userId: session.user.discordUserId, }); diff --git a/packages/api/src/routers/forms.ts b/packages/api/src/routers/forms.ts index f7f6f265..a2c41336 100644 --- a/packages/api/src/routers/forms.ts +++ b/packages/api/src/routers/forms.ts @@ -1,6 +1,6 @@ +import type { JSONSchema7 } from "json-schema"; import { TRPCError } from "@trpc/server"; import { and, count, desc, eq, inArray, lt, sql } from "drizzle-orm"; -import type { JSONSchema7 } from "json-schema"; import jsonSchemaToZod from "json-schema-to-zod"; import * as z from "zod"; diff --git a/packages/api/src/routers/misc.ts b/packages/api/src/routers/misc.ts index a76e2b7a..15b4a8ab 100644 --- a/packages/api/src/routers/misc.ts +++ b/packages/api/src/routers/misc.ts @@ -1,25 +1,26 @@ -import { RECRUITING_CHANNEL, TEAM_MAP } from "@forge/consts/knight-hacks"; import type { TRPCRouterRecord } from "@trpc/server"; import { Routes } from "discord-api-types/v10"; import { z } from "zod"; + +import { RECRUITING_CHANNEL, TEAM_MAP } from "@forge/consts/knight-hacks"; + import { protectedProcedure } from "../trpc"; import { discord } from "../utils"; - // Miscellaneous routes (primarily for form integrations) export const miscRouter = { recruitingUpdate: protectedProcedure - .meta({ - id: "recruitingUpdate", - inputSchema: z.object({ - name: z.string().min(1), - email: z.string().email(), - major: z.string().min(1), - gradTerm: z.string().min(1), - gradYear: z.number().min(1), - team: z.string().min(1), - }), - }) + .meta({ + id: "recruitingUpdate", + inputSchema: z.object({ + name: z.string().min(1), + email: z.string().email(), + major: z.string().min(1), + gradTerm: z.string().min(1), + gradYear: z.number().min(1), + team: z.string().min(1), + }), + }) .input( z.object({ name: z.string().min(1), @@ -31,12 +32,11 @@ export const miscRouter = { }), ) .mutation(async ({ input }) => { - - const team = TEAM_MAP.find(team => team.team === input.team); + const team = TEAM_MAP.find((team) => team.team === input.team); if (!team) { throw new Error("Team not found"); } - + const directorRole = team.director_role; // Convert hex color string to integer for Discord API diff --git a/packages/consts/src/knight-hacks.ts b/packages/consts/src/knight-hacks.ts index 347f3199..e8695386 100644 --- a/packages/consts/src/knight-hacks.ts +++ b/packages/consts/src/knight-hacks.ts @@ -6822,37 +6822,39 @@ export const FORM_QUESTION_TYPES = [ { value: "LINK", label: "Link (URL)" }, ] as const; -export const RECRUITING_CHANNEL = IS_PROD ? "1461758896950608104" : DEV_KNIGHTHACKS_LOG_CHANNEL - +export const RECRUITING_CHANNEL = IS_PROD + ? "1461758896950608104" + : DEV_KNIGHTHACKS_LOG_CHANNEL; + export const TEAM_MAP = [ - { - team: "Outreach", - color: "#88fea1", - director_role: "779845137822908436" - }, - { - team: "Design", - color: "#eaacff", - director_role: "874028482089349172" - }, - { - team: "Development", - color: "#93ceff", - director_role: "1082124530077683772" - }, - { - team: "Sponsorship", - color: "#f5f4af", - director_role: "626815399442513920" - }, - { - team: "Workshops", - color: "#206694", - director_role: "757002949603098837" - }, - { - team: "Projects/Mentorship", - color: "#3498db", - director_role: "1244790444626280550" - } - ] \ No newline at end of file + { + team: "Outreach", + color: "#88fea1", + director_role: "779845137822908436", + }, + { + team: "Design", + color: "#eaacff", + director_role: "874028482089349172", + }, + { + team: "Development", + color: "#93ceff", + director_role: "1082124530077683772", + }, + { + team: "Sponsorship", + color: "#f5f4af", + director_role: "626815399442513920", + }, + { + team: "Workshops", + color: "#206694", + director_role: "757002949603098837", + }, + { + team: "Projects/Mentorship", + color: "#3498db", + director_role: "1244790444626280550", + }, +];