-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Partner application sheet updates #2858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@steven-tey has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 20 minutes and 45 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughRefactors partner pages to centralize UI into new shared components (PartnerAbout, PartnerComments, PartnerInfoCards). Adds tabbed “About/Comments” panel and prev/next navigation to PartnerApplicationSheet, plus keyboard shortcuts for confirm modal. Updates styling for Sheet container. Page clients now delegate to shared components; some hooks/components are removed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Page as Applications Page
participant Sheet as PartnerApplicationSheet
participant Tabs as PartnerApplicationTabs
participant About as PartnerAbout
participant Comments as PartnerComments
User->>Page: Open Applications
Page->>Sheet: Render with partner + {onPrevious,onNext}
Sheet->>Tabs: set currentTabId ("about" default)
Tabs->>About: Render (when "about")
User->>Tabs: Click "Comments"
Tabs->>Comments: Render PartnerComments(partnerId)
User->>Sheet: Click ‹ / ›
Sheet->>Page: onPrevious/onNext()
Page->>Page: Update ?partnerId in URL
Page->>Sheet: Re-render with new partner
sequenceDiagram
autonumber
actor User
participant PC as PartnerComments
participant API as Actions (create/update/delete)
participant Cache as SWR Cache
User->>PC: Submit new comment
PC->>PC: Optimistic add (temp ID)
PC->>API: createPartnerCommentAction
API-->>PC: Success with server ID
PC->>Cache: mutatePrefix(...) to refresh
User->>PC: Edit comment
PC->>API: updatePartnerCommentAction
API-->>PC: Success
PC->>Cache: mutatePrefix(...)
User->>PC: Delete comment
PC->>API: deletePartnerCommentAction
API-->>PC: Success
PC->>Cache: mutatePrefix(...)
sequenceDiagram
autonumber
actor User
participant Modal as ConfirmModal
participant Hook as useKeyboardShortcut
participant Handler as onConfirm
User->>Modal: Open confirm modal
Modal->>Hook: Bind confirmShortcut
User->>Modal: Press shortcut / Click Confirm
Modal->>Handler: handleConfirm()
Handler-->>Modal: Resolve -> Close
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (1)
apps/web/ui/partners/partner-application-sheet.tsx (1)
262-267: Pass groupId to approval action to avoid wrong group assignmentApprove is gated on
partner.groupId, butexecuteAsyncomits it. If the action defaults toprogram.defaultGroupIdwhengroupIdis absent, approvals will land in the wrong group. Add a guard and passgroupIdexplicitly.- onConfirm: async () => { - if (!program || !workspaceId) return; - - await executeAsync({ - workspaceId: workspaceId, - partnerId: partner.id, - }); - }, + onConfirm: async () => { + if (!program || !workspaceId) { + toast.error("Missing program or workspace. Please refresh and try again."); + return; + } + if (!partner.groupId) { + toast.error("Select a group before approving."); + return; + } + await executeAsync({ + workspaceId, + partnerId: partner.id, + groupId: partner.groupId, + }); + },Run to confirm current server logic:
#!/bin/bash rg -nP -C3 'approvePartnerAction|approve-partner-enrollment|groupId\s*:\s*groupId\s*\|\|\s*program\.defaultGroupId'
🧹 Nitpick comments (12)
apps/web/ui/partners/partner-about.tsx (1)
19-25: Preserve author formatting in descriptionAllow line breaks and long words to wrap.
- <p className="text-content-default text-xs"> + <p className="text-content-default text-xs whitespace-pre-wrap break-words">apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx (1)
379-382: Loading state simplification is fineUsing only
isLoadingmatches the removed current-partner side fetch.Since the details sheet was removed, consider deleting the unused
useCurrentPartnerhelper at the bottom to reduce dead code.apps/web/ui/partners/partner-application-tabs.tsx (2)
49-86: Add ARIA roles for tabs for better accessibility.Declare a tablist and mark buttons as tabs with aria-selected.
- <div className="scrollbar-hide relative z-0 flex items-center justify-between gap-1 overflow-x-auto p-2"> + <div + className="scrollbar-hide relative z-0 flex items-center justify-between gap-1 overflow-x-auto p-2" + role="tablist" + aria-label="Partner application" + > @@ - <button + <button key={id} type="button" onClick={() => setCurrentTabId(id)} - data-selected={isSelected} + role="tab" + aria-selected={isSelected} + data-selected={isSelected} className={cn(
70-72: Prefer design tokens over hard-coded color.Replace bg-blue-600/text-white with your design system tokens (e.g., bg-accent text-accent-foreground) for theme consistency.
apps/web/ui/partners/partner-comments.tsx (3)
86-93: Also invalidate the comments count; avoid double revalidation.Update mutations to refresh both list and count; avoid SWR’s extra revalidate since you’re explicitly invalidating.
mutate( async (data) => { @@ }, { optimisticData: (data) => data ? [optimisticComment, ...data] : [optimisticComment], rollbackOnError: true, + revalidate: false, }, ) - .then(() => mutatePrefix(`/api/partners/${partnerId}/comments`)) + .then(() => + mutatePrefix([ + `/api/partners/${partnerId}/comments`, + `/api/partners/${partnerId}/comments/count`, + ]), + )- onSuccess: () => { + onSuccess: () => { toast.success("Comment edited successfully"); - mutatePrefix(`/api/partners/${partnerId}/comments`); + mutatePrefix(`/api/partners/${partnerId}/comments`); },- onSuccess: () => { + onSuccess: () => { toast.success("Comment deleted successfully"); - mutatePrefix(`/api/partners/${partnerId}/comments`); + mutatePrefix([ + `/api/partners/${partnerId}/comments`, + `/api/partners/${partnerId}/comments/count`, + ]); },Also applies to: 146-147, 156-157
239-247: Use the app’s confirm modal for consistency.Replace window.confirm with your ConfirmModal for unified UX and keyboard handling.
193-206: Locale handling nit.toLocaleTimeString("en-US") hardcodes locale. Consider using formatDate/timeAgo utilities for consistency with the rest of the UI.
apps/web/ui/partners/partner-application-sheet.tsx (5)
279-286: Prevent double-submits on ApproveAlso disable the button while the action is pending.
- disabled={!partner.groupId} + disabled={!partner.groupId || isPending}
53-64: Add rel to target=_blank linkOpen-in-new-tab links should use
rel="noopener noreferrer"to preventwindow.openerleaks.- <Link - href={`/${workspaceSlug}/program/messages/${partner.id}`} - target="_blank" - > + <Link + href={`/${workspaceSlug}/program/messages/${partner.id}`} + target="_blank" + rel="noopener noreferrer" + >
57-63: Keep URL state consistent when opening MessagesConsider also clearing
partnerIdfrom the URL when closing via the Message button to avoid stale state.- <Button + <Button variant="secondary" text="Message" icon={<Msgs className="size-4 shrink-0" />} - onClick={() => setIsOpen(false)} + onClick={() => { + setIsOpen(false); + // keep URL in sync with closed sheet + queryParams({ del: "partnerId", scroll: false }); + }} className="hidden h-9 rounded-lg px-4 sm:flex" />Add the hook near the other hooks in this component:
- const { slug: workspaceSlug } = useWorkspace(); + const { slug: workspaceSlug } = useWorkspace(); + const { queryParams } = useRouterStuff();
66-81: Add accessible labels to navigation buttonsIcon-only buttons need an accessible name.
<Button type="button" disabled={!onPrevious} onClick={onPrevious} variant="secondary" className="size-9 rounded-l-lg rounded-r-none p-0" icon={<ChevronLeft className="size-3.5" />} + aria-label="Previous partner" /> <Button type="button" disabled={!onNext} onClick={onNext} variant="secondary" className="-ml-px size-9 rounded-l-none rounded-r-lg p-0" icon={<ChevronRight className="size-3.5" />} + aria-label="Next partner" />
83-89: Add aria-label to Close buttonImprove accessibility for the icon-only close control.
- <Button + <Button variant="outline" icon={<X className="size-5" />} className="h-auto w-fit p-1" + aria-label="Close" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/about/page-client.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/comments/page-client.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/layout.tsx(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/page-client.tsx(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/rejected/page-client.tsx(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx(2 hunks)apps/web/ui/partners/partner-about.tsx(1 hunks)apps/web/ui/partners/partner-application-sheet.tsx(7 hunks)apps/web/ui/partners/partner-application-tabs.tsx(1 hunks)apps/web/ui/partners/partner-comments.tsx(1 hunks)apps/web/ui/partners/partner-info-cards.tsx(4 hunks)packages/ui/src/sheet.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
apps/web/ui/partners/partner-about.tsx (2)
apps/web/lib/types.ts (1)
EnrolledPartnerProps(434-434)apps/web/ui/partners/online-presence-summary.tsx (1)
OnlinePresenceSummary(89-138)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/about/page-client.tsx (2)
apps/web/lib/swr/use-partner.ts (1)
usePartner(6-29)apps/web/ui/partners/partner-about.tsx (1)
PartnerAbout(6-53)
apps/web/ui/partners/partner-comments.tsx (8)
apps/web/lib/swr/use-partner-comments.ts (1)
usePartnerComments(6-34)apps/web/lib/actions/partners/create-partner-comment.ts (1)
createPartnerCommentAction(13-42)apps/web/ui/shared/message-input.tsx (1)
MessageInput(8-109)apps/web/lib/types.ts (1)
PartnerCommentProps(553-553)apps/web/lib/actions/partners/update-partner-comment.ts (1)
updatePartnerCommentAction(12-37)apps/web/lib/actions/partners/delete-partner-comment.ts (1)
deletePartnerCommentAction(9-23)packages/utils/src/constants/misc.ts (1)
OG_AVATAR_URL(29-29)packages/ui/src/popover.tsx (1)
Popover(25-102)
apps/web/ui/partners/partner-application-tabs.tsx (2)
apps/web/lib/swr/use-partner-comments-count.ts (1)
usePartnerCommentsCount(5-31)packages/ui/src/icons/nucleo/msg.tsx (1)
Msg(3-24)
apps/web/ui/partners/partner-info-cards.tsx (4)
apps/web/lib/types.ts (1)
EnrolledPartnerProps(434-434)apps/web/ui/analytics/events/events-table.tsx (1)
EventDatum(125-125)packages/ui/src/icons/nucleo/trophy.tsx (1)
Trophy(3-48)packages/ui/src/icons/nucleo/heart.tsx (1)
Heart(3-24)
apps/web/ui/partners/partner-application-sheet.tsx (6)
apps/web/lib/types.ts (1)
EnrolledPartnerProps(434-434)packages/ui/src/sheet.tsx (1)
Sheet(74-78)apps/web/ui/partners/partner-info-cards.tsx (1)
PartnerInfoCards(33-254)apps/web/ui/partners/partner-application-tabs.tsx (1)
PartnerApplicationTabs(7-90)apps/web/ui/partners/partner-about.tsx (1)
PartnerAbout(6-53)apps/web/ui/partners/partner-comments.tsx (1)
PartnerComments(30-124)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/layout.tsx (1)
apps/web/ui/partners/partner-info-cards.tsx (1)
PartnerInfoCards(33-254)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/comments/page-client.tsx (1)
apps/web/ui/partners/partner-comments.tsx (1)
PartnerComments(30-124)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: api-tests
- GitHub Check: Vade Review
🔇 Additional comments (10)
apps/web/ui/partners/partner-about.tsx (1)
41-43: Tighten error copyThis page shows both description and links. Message should reflect that.
[ suggest_nitpick_refactor ]
- Failed to load partner links + Failed to load partner detailsapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/about/page-client.tsx (1)
11-11: LGTM – nice consolidationDelegating to
PartnerAboutsimplifies the page and unifies loading/error states.apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx (1)
58-58: LGTMImport cleanup aligns with removed details‑sheet logic.
apps/web/ui/partners/partner-info-cards.tsx (2)
44-51: Confirm /api/events returns newest-first (or make ordering explicit)Repo search returned no /api/events handler, so I couldn't verify the default ordering. With limit=1 the client will show the oldest event if the API is oldest-first — verify the endpoint returns newest-first, or include an explicit ordering parameter in the request (or update the server) so "Last event" always shows the newest.
212-251: No change required — rel="noopener noreferrer" not necessary for this internal linkhref is an internal path (starts with '/{workspaceSlug}/...'); per team guidance internal target="_blank" links don't require rel="noopener noreferrer". Optional: guard workspaceSlug to avoid generating /undefined.
Likely an incorrect or invalid review comment.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/layout.tsx (1)
10-10: Swap to PartnerInfoCards looks correct; verify deprecation/cleanup.Import/source change and usage align with PartnerInfoCards’ API ({ partner?: EnrolledPartnerProps }). Please confirm the old local PartnerInfo component and related styles are removed or unused to avoid dead code.
Also applies to: 74-75
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/comments/page-client.tsx (1)
3-3: LGTM: centralizing to PartnerComments.This simplifies the page and reuses the shared component correctly.
Also applies to: 9-9
apps/web/ui/partners/partner-application-sheet.tsx (3)
32-33: LGTM: new navigation handlersOptional
onPrevious/onNextprops are a clean extension for keyboard/UX navigation.
93-113: LGTM: layout restructureThe two-column grid with cards + tabbed content reads well and keeps the approval bar out of the scrollable area.
224-227: LGTM: sheet width constraintThe responsive clamp keeps the sheet legible across breakpoints.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/page-client.tsx
Show resolved
Hide resolved
...pp/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/applications/rejected/page-client.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/ui/partners/partner-application-sheet.tsx (1)
323-329: Same double‑binding risk for “R” (reject).Mirror the approval fix: scope the reject confirm shortcut to the modal only.
- confirmShortcut: "r", - confirmShortcutOptions: { sheet: true, modal: true }, + confirmShortcut: "r", + confirmShortcutOptions: { modal: true },Also applies to: 337-338
♻️ Duplicate comments (1)
apps/web/ui/partners/partner-application-sheet.tsx (1)
267-270: Approval call omits groupId (verify backend expectation).You disable Approve unless
partner.groupIdexists, but don’t pass it to the action. If the action defaults toprogram.defaultGroupIdwhengroupIdis absent, approved partners may land in the wrong group.If the action expects/uses
groupId, pass it:await executeAsync({ workspaceId: workspaceId, partnerId: partner.id, + groupId: partner.groupId, });Run to verify server semantics:
#!/bin/bash # Inspect approve-partner action usage of groupId/defaultGroupId fd -a 'approve-partner' | xargs -I{} rg -n -C3 -e '\bgroupId\b|\bdefaultGroupId\b' {} # Also check for an "approve-partner-enrollment" path if present rg -n -C3 -e 'approve[-_]?partner.*(groupId|defaultGroupId)' apps lib packages
🧹 Nitpick comments (5)
apps/web/ui/partners/partner-application-sheet.tsx (4)
54-66: Add rel for target=_blank and guard undefined slug.Security/a11y nit: include
rel="noopener noreferrer". Also consider hiding the button untilworkspaceSlugis ready to avoid"/undefined/..."links.- <Link - href={`/${workspaceSlug}/program/messages/${partner.id}`} - target="_blank" - > + {workspaceSlug && ( + <Link + href={`/${workspaceSlug}/program/messages/${partner.id}`} + target="_blank" + rel="noopener noreferrer" + > <Button ... /> - </Link> + </Link> + )}
67-83: Icon‑only nav buttons need accessible labels.Add
aria-labelso screen readers announce their purpose.<Button type="button" disabled={!onPrevious} onClick={onPrevious} variant="secondary" className="size-9 rounded-l-lg rounded-r-none p-0" + aria-label="Previous application" icon={<ChevronLeft className="size-3.5" />} /> <Button type="button" disabled={!onNext} onClick={onNext} variant="secondary" className="-ml-px size-9 rounded-l-none rounded-r-lg p-0" + aria-label="Next application" icon={<ChevronRight className="size-3.5" />} />
158-166: Avoid “undefined” program name during initial render.When
programhasn’t loaded, the title renders “promote undefined?”. Gate the fields onprogramor provide a neutral fallback.- const fields = [ + const fields = program ? [ { - title: `How do you plan to promote ${program?.name}?`, + title: `How do you plan to promote ${program.name}?`, value: application?.proposal, }, { title: "Any additional questions or comments?", value: application?.comments, }, - ]; + ] : [];And render a lightweight placeholder when
!program:- return ( - <div className="grid grid-cols-1 gap-6 text-xs"> - {fields.map((field) => ( + return ( + <div className="grid grid-cols-1 gap-6 text-xs"> + {program ? fields.map((field) => ( ... - ))} + )) : ( + <div className="h-4 w-28 min-w-0 animate-pulse rounded-md bg-neutral-200" /> + )}Also applies to: 170-197
330-333: Non‑null assertion on workspaceId.
workspaceId!can throw if context isn’t ready. Mirror the approve path’s guard or disable the button until available.- await rejectPartner({ - workspaceId: workspaceId!, - partnerId: partner.id, - }); + if (!workspaceId) return; + await rejectPartner({ workspaceId, partnerId: partner.id });apps/web/ui/modals/confirm-modal.tsx (1)
89-101: Minor: type name typo (Model → Modal).Rename for clarity; no behavior change.
-type PromptModelProps = { +type PromptModalProps = { ... -}; +}; ... -function ConfirmModal({ +function ConfirmModal({ ... -}: { ... } & PromptModelProps) { +}: { ... } & PromptModalProps) { ... -export function useConfirmModal(props: PromptModelProps) { +export function useConfirmModal(props: PromptModalProps) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/ui/modals/confirm-modal.tsx(4 hunks)apps/web/ui/partners/partner-application-sheet.tsx(10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/ui/partners/partner-application-sheet.tsx (5)
apps/web/lib/types.ts (1)
EnrolledPartnerProps(434-434)apps/web/ui/partners/partner-info-cards.tsx (1)
PartnerInfoCards(33-254)apps/web/ui/partners/partner-application-tabs.tsx (1)
PartnerApplicationTabs(7-90)apps/web/ui/partners/partner-about.tsx (1)
PartnerAbout(6-53)apps/web/ui/partners/partner-comments.tsx (1)
PartnerComments(29-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Vade Review
- GitHub Check: build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
apps/web/ui/partners/partner-application-sheet.tsx (6)
54-57: Add rel for security when using target="_blank".Include rel="noopener noreferrer" to prevent tab‑nabbing.
- <Link + <Link href={`/${workspaceSlug}/program/messages/${partner.id}`} target="_blank" + rel="noopener noreferrer" >
67-83: Provide accessible labels for icon‑only navigation buttons.Screen readers won’t announce intent without an accessible name.
<Button type="button" disabled={!onPrevious} onClick={onPrevious} variant="secondary" className="size-9 rounded-l-lg rounded-r-none p-0" + aria-label="Previous application" icon={<ChevronLeft className="size-3.5" />} /> <Button type="button" disabled={!onNext} onClick={onNext} variant="secondary" className="-ml-px size-9 rounded-l-none rounded-r-lg p-0" + aria-label="Next application" icon={<ChevronRight className="size-3.5" />} />
170-193: Avoid wrapping fallback text in Linkify.Simplifies markup and prevents link styles on “No response provided”.
- <div className="mt-2"> - {field.value || field.value === "" ? ( - <Linkify - as="p" - options={{ - target: "_blank", - rel: "noopener noreferrer nofollow", - className: - "underline underline-offset-4 text-neutral-400 hover:text-neutral-700", - }} - > - {field.value || ( - <span className="text-content-muted italic"> - No response provided - </span> - )} - </Linkify> - ) : ( - <div className="h-4 w-28 min-w-0 animate-pulse rounded-md bg-neutral-200" /> - )} - </div> + <div className="mt-2"> + {field.value === undefined ? ( + <div className="h-4 w-28 min-w-0 animate-pulse rounded-md bg-neutral-200" /> + ) : field.value ? ( + <Linkify + as="p" + options={{ + target: "_blank", + rel: "noopener noreferrer nofollow", + className: + "underline underline-offset-4 text-neutral-400 hover:text-neutral-700", + }} + > + {field.value} + </Linkify> + ) : ( + <p className="text-content-muted italic">No response provided</p> + )} + </div>
283-291: Disable Approve until required data is loaded.Prevents a no‑op confirm when program/workspaceId aren’t ready.
<Button type="button" variant="primary" text="Approve" shortcut="A" loading={isPending} onClick={() => setShowConfirmModal(true)} + disabled={!program || !workspaceId} className="w-fit shrink-0" />
304-315: Also clear partnerId from URL on reject (parity with approve).Prevents the sheet from reopening due to a lingering query param.
const { id: workspaceId } = useWorkspace(); + const { queryParams } = useRouterStuff();onSuccess: async () => { await mutatePrefix("/api/partners"); toast.success( "Application rejected. No email sent, and they can reapply in 30 days.", ); + queryParams({ del: "partnerId" }); setIsOpen(false); },
33-35: Optional: Arrow‑key navigation between applications.Small UX boost: allow ArrowLeft/Right to trigger previous/next when available.
const [currentTabId, setCurrentTabId] = useState<string>("about"); + useKeyboardShortcut("ArrowLeft", () => onPrevious?.(), { sheet: true }); + useKeyboardShortcut("ArrowRight", () => onNext?.(), { sheet: true });Also applies to: 44-46
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/ui/partners/partner-application-sheet.tsx(10 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-18T17:03:06.183Z
Learnt from: TWilson023
PR: dubinc/dub#2858
File: apps/web/ui/partners/partner-application-sheet.tsx:262-266
Timestamp: 2025-09-18T17:03:06.183Z
Learning: The useKeyboardShortcut hook with context options like {sheet: true, modal: true} requires ALL specified contexts to be present simultaneously. The shortcut will only trigger when both existingSheetBackdrop and existingModalBackdrop are present, using strict equality matching in the implementation.
Applied to files:
apps/web/ui/partners/partner-application-sheet.tsx
🧬 Code graph analysis (1)
apps/web/ui/partners/partner-application-sheet.tsx (6)
apps/web/lib/types.ts (1)
EnrolledPartnerProps(434-434)packages/ui/src/sheet.tsx (1)
Sheet(74-78)apps/web/ui/partners/partner-info-cards.tsx (1)
PartnerInfoCards(33-254)apps/web/ui/partners/partner-application-tabs.tsx (1)
PartnerApplicationTabs(7-90)apps/web/ui/partners/partner-about.tsx (1)
PartnerAbout(6-53)apps/web/ui/partners/partner-comments.tsx (1)
PartnerComments(29-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Vade Review
- GitHub Check: build
🔇 Additional comments (4)
apps/web/ui/partners/partner-application-sheet.tsx (4)
94-114: Nice compositional split and responsive grid.The two‑pane layout with tabs is clean and aligns with the container‑query variants.
262-266: Confirm shortcuts while typing in inputs.Please verify that useKeyboardShortcut suppresses triggers when focus is in inputs/textareas/contentEditable (Comments tab has a MessageInput). If not, guard to avoid surprising modal opens while typing “a”/“r”.
Option (guard locally if needed):
- useKeyboardShortcut("a", () => setShowConfirmModal(true), { sheet: true }); + useKeyboardShortcut( + "a", + () => { + const el = document.activeElement as HTMLElement | null; + if (el && (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable)) return; + setShowConfirmModal(true); + }, + { sheet: true }, + );- useKeyboardShortcut("r", () => setShowConfirmModal(true), { sheet: true }); + useKeyboardShortcut( + "r", + () => { + const el = document.activeElement as HTMLElement | null; + if (el && (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable)) return; + setShowConfirmModal(true); + }, + { sheet: true }, + );Also applies to: 274-275, 326-337
225-228: Width constraint looks good.The responsive clamp keeps the sheet within sensible bounds.
201-208: Comments wrapper LGTM.Clear heading + reuse of PartnerComments.
Summary by CodeRabbit
New Features
Refactor
Style