Conversation
Drewbi
commented
Feb 22, 2026
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| CLAUDE.md | ||
| .CLAUDE | ||
| .llms No newline at end of file |
There was a problem hiding this comment.
Shout out to my homies
|
|
||
| export const positionsInGeneralMeetingsRouter = createTRPCRouter({ | ||
| get: getPositions, | ||
| getWithCounts: getPositionsWithCounts, |
There was a problem hiding this comment.
I think this can probably just be calculated from the returned candidates for a position
| .select({ | ||
| ...getTableColumns(positions), | ||
| nomineeCount: count(nominations.candidateId), | ||
| }) | ||
| .from(positions) | ||
| .leftJoin(nominations, eq(nominations.positionId, positions.id)) | ||
| .where(eq(positions.meetingId, input.meetingId)) | ||
| .groupBy(positions.id) | ||
| .orderBy(asc(positions.priority)) |
There was a problem hiding this comment.
You reckon there would be a way to do this with query instead of select? Will probably delete this endpoint anyway
| if (!position) throw new TRPCError({ code: "NOT_FOUND", message: "Position not found" }) | ||
|
|
||
| const positionNominations = await ctx.db | ||
| .select() |
| questions: meetingQuestions, | ||
| candidates: candidateRows.map((candidate) => ({ | ||
| ...candidate, | ||
| answers: allAnswers.filter((a) => a.candidateId === candidate.id), |
There was a problem hiding this comment.
This is BAD. Should really just include questions and answers in candidate query
| const getNominations = publicRatedProcedure() | ||
| .input(z.object({ positionId: z.uuidv7() })) | ||
| .query(async ({ ctx, input }) => { | ||
| return ctx.db.select().from(nominations).where(eq(nominations.positionId, input.positionId)) |
| const getNominationsByCandidate = publicRatedProcedure() | ||
| .input(z.object({ candidateId: z.uuidv7() })) | ||
| .query(async ({ ctx, input }) => { | ||
| return ctx.db.select().from(nominations).where(eq(nominations.candidateId, input.candidateId)) |
| const getCandidates = publicRatedProcedure() | ||
| .input(z.object({ meetingId: z.uuidv7() })) | ||
| .query(async ({ ctx, input }) => { | ||
| return ctx.db.select().from(candidates).where(eq(candidates.meetingId, input.meetingId)) |
| const [candidate] = await ctx.db | ||
| .select() | ||
| .from(candidates) | ||
| .where(and(eq(candidates.meetingId, input.meetingId), eq(candidates.userId, ctx.session.user.id))) | ||
| return candidate ?? null |
| const sameDay = meeting.end && meeting.start.toDateString() === meeting.end.toDateString() | ||
|
|
||
| return ( | ||
| <main className="container mx-auto px-4 py-12"> |
There was a problem hiding this comment.
I think this needs extra styles to work in light mode
| <h1 className="scroll-m-20 font-mono text-4xl tracking-tight text-balance">{meeting.title}</h1> | ||
| <div className="flex flex-col gap-1.5 font-mono text-sm text-neutral-500 dark:text-neutral-400"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="material-symbols-sharp text-base! leading-none!">schedule</span> |
There was a problem hiding this comment.
Lots of important usage here, not really sure why
| </section> | ||
| )} | ||
|
|
||
| {(meeting.status === "upcoming" || meeting.status === "ongoing") && ( |
There was a problem hiding this comment.
This allows them to access nominations page even when meeting is open. I think this is desired behaviour
| </section> | ||
| )} | ||
|
|
||
| {meeting.status === "ongoing" && ( |
There was a problem hiding this comment.
Might need an else here to tell them to hang tight if the meeting hasn't opened yet
| <Header /> | ||
| {children} | ||
| <Footer /> |
There was a problem hiding this comment.
Could probably put some of the general layout styles in this top level layout
| </ul> | ||
| )} | ||
|
|
||
| <p className="text-sm text-neutral-500 dark:text-neutral-400">Voting coming soon.</p> |
There was a problem hiding this comment.
Not sure how we want to handle which position is open for voting. Might need to add a property to the positions table
| const key = `cfc-stars-${positionId}` | ||
| const [starred, setStarred] = React.useState<Set<string>>(new Set()) |
There was a problem hiding this comment.
this is a non-essential feature but is kinda useful for remembering your favs before voting has opened
| type Question = { | ||
| id: string | ||
| text: string | ||
| type: "short" | "long" | "checkbox" | null | ||
| required: boolean | null | ||
| order: number | ||
| } |
There was a problem hiding this comment.
should this stuff be coming from tRPC?
| { enabled: !!myCandidate }, | ||
| ) | ||
|
|
||
| const [isEditing, setIsEditing] = React.useState(false) |
There was a problem hiding this comment.
do we really gotta preface React. all the time?
| await Promise.all([ | ||
| ...[...selectedPositions].map((positionId) => | ||
| createNomination.mutateAsync({ meetingId: meeting.id, positionId, candidateId: candidate.id }), | ||
| ), | ||
| ...questions |
There was a problem hiding this comment.
this looks hella jank, lmk if theres a better way
| {btnText} | ||
| </motion.span> | ||
| </AnimatePresence> | ||
| {loading && <Spinner className="absolute right-4" />} |
There was a problem hiding this comment.
This loading spinner is inside the text every time, gotta fix
There was a problem hiding this comment.
This probably has huge conflicts with your changes @JeremiahPinto, m'pologies