Conversation
📝 WalkthroughWalkthroughRemoves the PR-specific pr-checks job from CI, adds an allowed remote image host, refactors form validation and error surfacing, enhances form-to-response field matching, changes event/member points handling, adds React keys, sorts filter options, and updates several UI texts and type/const definitions across packages. Changes
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 6 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/blade/src/app/_components/admin/hackathon/events/update-event.tsx (1)
164-169:⚠️ Potential issue | 🟠 MajorBug: useEffect doesn't react to tag changes.
The effect reads
form.getValues("tag")but the dependency array only includesform. Sinceformis a stable reference, this effect only runs once on mount. The points field won't auto-update when the user changes the tag dropdown.To fix, use
form.watch()to subscribe to tag changes:🐛 Proposed fix
+ const watchedTag = form.watch("tag"); + // Auto-update points when tag changes useEffect(() => { - const currentTag = form.getValues("tag"); - const points = EVENTS.EVENT_POINTS[currentTag] || 0; + const points = EVENTS.EVENT_POINTS[watchedTag] || 0; form.setValue("points", points); - }, [form]); + }, [form, watchedTag]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/admin/hackathon/events/update-event.tsx` around lines 164 - 169, The effect that auto-updates points uses form.getValues("tag") but only depends on [form], so it runs once; change the effect to subscribe to tag changes via form.watch("tag") (or store the watched value in a variable returned by form.watch and use that in the dependency array) and then compute points = EVENTS.EVENT_POINTS[tag] || 0 and call form.setValue("points", points); update the useEffect to depend on the watched tag value instead of the stable form reference so points update whenever the tag changes.
🧹 Nitpick comments (1)
apps/blade/src/app/_components/admin/roles/roleassign.tsx (1)
171-178: Use the state setters instead of mutating the backing objects.These handlers mutate
filterRoles,checkedUsers, andcheckedRolesin place, then rely onsUpd(!upd)to force a rerender. That pattern is brittle under React batching and makes the UI depend on a manual escape hatch instead of state changes.♻️ Suggested cleanup
- onCheckedChange={(c) => { - filterRoles[v.id] = c == true; - sUpd(!upd); - }} + onCheckedChange={(c) => + _setFilterRoles((prev) => ({ ...prev, [v.id]: c === true })) + } - onCheckedChange={(c) => { - checkedUsers[v.id] = c == true; - sUpd(!upd); - }} + onCheckedChange={(c) => + setCheckedUsers((prev) => ({ ...prev, [v.id]: c === true })) + } - onCheckedChange={(c) => { - checkedRoles[v.id] = c == true; - sUpd(!upd); - }} + onCheckedChange={(c) => + _setCheckedRoles((prev) => ({ ...prev, [v.id]: c === true })) + }Once these updates go through the setters, the
updstate can be removed as well.Also applies to: 216-227, 326-333
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/admin/roles/roleassign.tsx` around lines 171 - 178, The handlers currently mutate the backing objects (filterRoles, checkedUsers, checkedRoles) and call sUpd(!upd) to force a rerender; replace those in-place mutations with proper state updates via their setters (e.g., setFilterRoles(prev => ({ ...prev, [v.id]: Boolean(c) })), setCheckedUsers(prev => ({ ...prev, [userId]: Boolean(checked) })), setCheckedRoles(...)) using the functional form to avoid stale closures, and remove the upd/sUpd forced-rerender pattern and the upd state entirely; update all Checkbox onCheckedChange handlers (and any similar click handlers referenced around the same areas) to use these setters so changes are immutable and React batching-safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/blade/next.config.js`:
- Around line 29-32: Replace the hardcoded sslip.io hostname
("minio-y44gsgsskc4ko4kkwsg0csoc.135.237.97.107.sslip.io") in the Next.js
external image host entry with the stable MinIO hostname defined in your
constants (use the exported MinIO host constant from
packages/consts/src/minio.ts) or remove the sslip.io entry if it was only for
temporary local testing; if you intentionally need both hostnames, add a short
comment explaining why and move the sslip.io value into an environment-based
config so next.config.js does not hardcode an IP-derived alias.
In `@apps/blade/src/app/_components/admin/club/check-in/manual-entry-form.tsx`:
- Around line 41-42: The controlled search input (searchValue / setSearchValue)
is not cleared when the member-selection popover closes or when a member is
chosen, leaving stale queries that incorrectly filter the list; fix this by
calling setSearchValue("") in both the popover close handler and immediately
after a member is selected (where member selection logic runs), and also apply
the same clear when the alternate popover instance referenced around the other
block (lines ~183-188) closes or completes selection; locate the popover onClose
prop and the member-selection handler in manual-entry-form.tsx and add
setSearchValue("") there so the input resets on close/selection.
In
`@apps/blade/src/app/_components/admin/hackathon/check-in/manual-entry-form.tsx`:
- Around line 45-46: The controlled search state (searchValue) persists across
hackathon switches causing the popover to remain filtered; add a useEffect that
watches the hackathon context/ID prop and calls setSearchValue("") (and
optionally clears commandListRef.current if you want to reset focus/scroll) so
the search is reset whenever the hackathon changes; update the logic around
searchValue/setSearchValue and commandListRef referenced in
manual-entry-form.tsx (also apply the same reset where search state is used
around lines ~288-293).
In `@packages/utils/src/forms.client.ts`:
- Around line 93-115: The format-specific error branches inside the
isMissingField block are unreachable because isMissingField is true only when
rawMessage.includes("received undefined"), so the nested condition
!rawMessage.includes("received undefined") will never be true; remove the inner
isFormatSpecific/... question.type branches from the isMissingField handling in
forms.client.ts (the block that checks isMissingField and rawMessage.includes)
and keep a single "Answer required" return there, since format-specific messages
are already handled by the invalid_format/invalid_type logic elsewhere.
---
Outside diff comments:
In `@apps/blade/src/app/_components/admin/hackathon/events/update-event.tsx`:
- Around line 164-169: The effect that auto-updates points uses
form.getValues("tag") but only depends on [form], so it runs once; change the
effect to subscribe to tag changes via form.watch("tag") (or store the watched
value in a variable returned by form.watch and use that in the dependency array)
and then compute points = EVENTS.EVENT_POINTS[tag] || 0 and call
form.setValue("points", points); update the useEffect to depend on the watched
tag value instead of the stable form reference so points update whenever the tag
changes.
---
Nitpick comments:
In `@apps/blade/src/app/_components/admin/roles/roleassign.tsx`:
- Around line 171-178: The handlers currently mutate the backing objects
(filterRoles, checkedUsers, checkedRoles) and call sUpd(!upd) to force a
rerender; replace those in-place mutations with proper state updates via their
setters (e.g., setFilterRoles(prev => ({ ...prev, [v.id]: Boolean(c) })),
setCheckedUsers(prev => ({ ...prev, [userId]: Boolean(checked) })),
setCheckedRoles(...)) using the functional form to avoid stale closures, and
remove the upd/sUpd forced-rerender pattern and the upd state entirely; update
all Checkbox onCheckedChange handlers (and any similar click handlers referenced
around the same areas) to use these setters so changes are immutable and React
batching-safe.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: ac2bcf8f-22e7-471a-a656-18f4a5f4317c
📒 Files selected for processing (15)
.github/workflows/ci.ymlapps/blade/next.config.jsapps/blade/src/app/_components/admin/club/check-in/manual-entry-form.tsxapps/blade/src/app/_components/admin/club/events/update-event.tsxapps/blade/src/app/_components/admin/club/members/update-member.tsxapps/blade/src/app/_components/admin/hackathon/check-in/manual-entry-form.tsxapps/blade/src/app/_components/admin/hackathon/events/update-event.tsxapps/blade/src/app/_components/admin/roles/roleassign.tsxapps/blade/src/app/_components/admin/roles/roletable.tsxapps/blade/src/app/_components/forms/connection-handler.tsapps/blade/src/app/_components/forms/form-runner.tsxapps/blade/src/app/_components/shared/filter-options.tsapps/blade/src/app/admin/club/check-in/page.tsxpackages/api/src/routers/event.tspackages/utils/src/forms.client.ts
💤 Files with no reviewable changes (1)
- .github/workflows/ci.yml
apps/blade/src/app/_components/admin/club/check-in/manual-entry-form.tsx
Show resolved
Hide resolved
apps/blade/src/app/_components/admin/hackathon/check-in/manual-entry-form.tsx
Show resolved
Hide resolved
DGoel1602
left a comment
There was a problem hiding this comment.
Almost everything looks perfect except I just don't wanna repeat our form question types in a million places and go hunting when we need to add one
packages/utils/src/forms.client.ts
Outdated
| }; | ||
|
|
||
| // Transform raw Zod error messages into user-friendly messages | ||
| const getUserFriendlyError = ( |
There was a problem hiding this comment.
Look into error maps in zod instead, I think it makes it cleaner and would avoid redundant repeating yourself
https://zod.dev/error-customization?id=per-parse-error-customization
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/consts/src/forms/index.ts`:
- Around line 338-343: The validator currently uses the in operator against
FORM_QUESTION_TYPE_BY_VALUE which accepts inherited keys (e.g., "toString"),
causing invalid types to pass; update the check so it only accepts own
properties by replacing the in-based test with
Object.prototype.hasOwnProperty.call(FORM_QUESTION_TYPE_BY_VALUE, value) or,
preferably, replace the ad-hoc validator with a Zod enum built from
FORM_QUESTION_TYPES (e.g., z.enum(FORM_QUESTION_TYPES.map(t => t.value))) and
use that enum wherever FORM_QUESTION_TYPE_BY_VALUE is validated so downstream
code referencing FormQuestionTypeMetadata (e.g., validationErrors) only ever
receives real keys.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 159dbacd-9aed-470f-a8fd-ca4caa7145d2
📒 Files selected for processing (2)
packages/consts/src/forms/index.tspackages/utils/src/forms.client.ts
Why
There were some weird bugs that were either really old, or really exaggerated by the recent resolution of #407
What
Closes: #407
Test Plan
Pull and test, pretty trivial changes though.
Checklist
db:pushbefore mergingSummary by CodeRabbit
New Features
Bug Fixes
UI Updates
Other