Conversation
📝 WalkthroughWalkthroughThe PR refactors BoostedDropCardHome with variant and rank props, introduces wave selections support across API endpoints and utilities, and updates DropsList to render the new chat-variant boosted cards with boost interaction buttons. Multiple utility functions now include selection data structures. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
openapi.yaml (1)
8380-8475:⚠️ Potential issue | 🟠 MajorDon't mark
selectionsas required without backend confirmation that all endpoints always serialize it.Making
selectionsrequired inApiDrop,ApiDropWithoutWave,ApiWave, andApiWaveMinis a breaking schema change. Local builders incomponents/waves/memes/submission/utils/buildPreviewDrop.ts,components/waves/utils/getOptimisticDrop.ts, andhooks/useWaveDropsSearch.tsalready had to initialize this field explicitly—indicating it wasn't previously guaranteed to exist. Unless every backend endpoint and code path that returns these schemas now serializesselections(even as empty arrays), clients will encounter validation failures or undefined errors at runtime.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 8380 - 8475, The OpenAPI change made the selections property required on ApiDrop, ApiDropWithoutWave, ApiWave, and ApiWaveMin causing a breaking change; revert that by removing selections from the required arrays (or make it nullable/optional) so clients that don't receive selections (or that initialize it locally in buildPreviewDrop.ts, getOptimisticDrop, and useWaveDropsSearch.ts) won't fail validation—update the schemas for ApiDrop, ApiDropWithoutWave, ApiWave, and ApiWaveMin to treat selections as optional (or allow an empty/nullable array) instead of required.
🧹 Nitpick comments (4)
components/home/boosted/BoostedDropCardHome.tsx (1)
192-205: Consider improving the author link fallback when handle is missing.When
author.handleis falsy, the link navigates to"#"which isn't ideal UX. Consider either not rendering the link as clickable or using the primary address as a fallback route.💡 Optional: Render as non-clickable span when handle is missing
- <Link - href={author.handle ? `/${author.handle}` : "#"} - onClick={(event) => event.stopPropagation()} - className={AUTHOR_LINK_CLASSES} - > + {author.handle ? ( + <Link + href={`/${author.handle}`} + onClick={(event) => event.stopPropagation()} + className={AUTHOR_LINK_CLASSES} + > + <ProfileAvatar + pfpUrl={author.pfp} + alt={author.handle} + size={ProfileBadgeSize.SMALL} + /> + <span className="tw-break-words tw-text-sm tw-font-medium tw-text-iron-50"> + {author.handle} + </span> + </Link> + ) : ( + <div className={AUTHOR_LINK_CLASSES}> + <ProfileAvatar + pfpUrl={author.pfp} + alt="Anonymous" + size={ProfileBadgeSize.SMALL} + /> + <span className="tw-break-words tw-text-sm tw-font-medium tw-text-iron-50"> + Anonymous + </span> + </div> + )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/home/boosted/BoostedDropCardHome.tsx` around lines 192 - 205, The author link currently renders an anchor to "#" when author.handle is falsy; update the JSX in BoostedDropCardHome so that if author.handle exists you render the Link component with href={`/${author.handle}`} (keeping onClick={event => event.stopPropagation()} and AUTHOR_LINK_CLASSES), but if author.handle is missing render a non-clickable span (same classes/contents: ProfileAvatar and handle display) or alternatively use author.address as the fallback route (href={`/${author.address}`} when present); ensure only the Link variant has the onClick stopPropagation handler and the non-clickable span is used for better UX when there's no handle.components/home/boosted/BoostedDropCardHomeContent.tsx (1)
318-345: Retry interval continues after successful measurement.The
useOverflowMeasurementRetryhook continues running the interval even afterhasMeasuredOverflowbecomes true. While it stops after 12 attempts, stopping early when measurement succeeds would be more efficient.💡 Optional: Stop retry interval once measurement succeeds
const useOverflowMeasurementRetry = ({ enabled, measureOverflow, + hasMeasuredOverflow, }: { readonly enabled: boolean; readonly measureOverflow: () => void; + readonly hasMeasuredOverflow: boolean; }) => { useEffect(() => { - if (!enabled) { + if (!enabled || hasMeasuredOverflow) { return; } let attempts = 0; const intervalId = globalThis.setInterval(() => { measureOverflow(); attempts += 1; if (attempts >= MAX_OVERFLOW_MEASUREMENT_ATTEMPTS) { globalThis.clearInterval(intervalId); } }, OVERFLOW_MEASUREMENT_INTERVAL_MS); return () => { if (typeof intervalId === "number") { globalThis.clearInterval(intervalId); } }; - }, [enabled, measureOverflow]); + }, [enabled, measureOverflow, hasMeasuredOverflow]); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/home/boosted/BoostedDropCardHomeContent.tsx` around lines 318 - 345, The retry interval in useOverflowMeasurementRetry should stop as soon as overflow measurement succeeds; modify the hook so measureOverflow indicates success (e.g., change its contract to return a boolean or have an accessible hasMeasuredOverflow getter) and after calling measureOverflow() inside the interval, check the result and call globalThis.clearInterval(intervalId) immediately when it returns true (in addition to the existing attempts cap), ensuring the cleanup return still clears the interval; keep the effect dependencies ([enabled, measureOverflow]) unchanged.openapi.yaml (2)
1012-1017: Clarify whetherselection_idis globally unique.
GET /dropscan now filter byselection_idalone, but selections are managed under/waves/{id}/selections/{selectionId}. If those IDs are only wave-scoped, this filter is ambiguous; if they are global, say that in the description. Otherwise requirewave_idtogether withselection_id.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 1012 - 1017, The OpenAPI param `selection_id` used by GET /drops is ambiguous about scope; clarify whether `selection_id` values are globally unique or require a `wave_id`. Update the `selection_id` parameter description (the param named selection_id in the GET /drops operation) to state explicitly that selection IDs are global if they are unique across waves, or change the schema/requirements so that `wave_id` must be provided alongside `selection_id` (or vice versa) and document that requirement; reference the existing selection resource path `/waves/{id}/selections/{selectionId}` in the description to explain scoping.
5905-6020: Document the common 4xxs on selection mutations.These endpoints only advertise success responses. Please add the expected failure cases too—at least forbidden and not-found—so generated clients can distinguish permission errors from missing wave, selection, or drop IDs.
📄 Example contract tweak
/waves/{id}/selections/{selectionId}: delete: tags: - Waves summary: Delete selection from wave operationId: deleteWaveSelection parameters: - name: id in: path required: true schema: type: string - name: selectionId in: path required: true schema: type: string responses: "200": description: successful operation + "403": + description: Only wave creators or admins can manage selections + "404": + description: Wave or selection not found🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 5905 - 6020, For each selection mutation operation (operationId createWaveSelection, deleteWaveSelection, addDropToWaveSelection, removeDropFromWaveSelection) add explicit 4xx responses: at minimum 403 (forbidden) and 404 (not found) alongside the existing success codes; include a descriptive "description" and reference the project's standard error schema (e.g., ApiError or the common error response component) so generated clients can distinguish permission errors from missing wave/selection/drop IDs—apply this change to the POST /waves/{id}/selections, DELETE /waves/{id}/selections/{selectionId}, POST /waves/{id}/selections/{selectionId}/drops, and DELETE /waves/{id}/selections/{selectionId}/drops/{dropId} entries (keep existing success schemas like ApiWaveSelection, ApiWaveSelectionRequest, ApiWaveSelectionDropRequest as-is).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@openapi.yaml`:
- Around line 8380-8475: The OpenAPI change made the selections property
required on ApiDrop, ApiDropWithoutWave, ApiWave, and ApiWaveMin causing a
breaking change; revert that by removing selections from the required arrays (or
make it nullable/optional) so clients that don't receive selections (or that
initialize it locally in buildPreviewDrop.ts, getOptimisticDrop, and
useWaveDropsSearch.ts) won't fail validation—update the schemas for ApiDrop,
ApiDropWithoutWave, ApiWave, and ApiWaveMin to treat selections as optional (or
allow an empty/nullable array) instead of required.
---
Nitpick comments:
In `@components/home/boosted/BoostedDropCardHome.tsx`:
- Around line 192-205: The author link currently renders an anchor to "#" when
author.handle is falsy; update the JSX in BoostedDropCardHome so that if
author.handle exists you render the Link component with
href={`/${author.handle}`} (keeping onClick={event => event.stopPropagation()}
and AUTHOR_LINK_CLASSES), but if author.handle is missing render a non-clickable
span (same classes/contents: ProfileAvatar and handle display) or alternatively
use author.address as the fallback route (href={`/${author.address}`} when
present); ensure only the Link variant has the onClick stopPropagation handler
and the non-clickable span is used for better UX when there's no handle.
In `@components/home/boosted/BoostedDropCardHomeContent.tsx`:
- Around line 318-345: The retry interval in useOverflowMeasurementRetry should
stop as soon as overflow measurement succeeds; modify the hook so
measureOverflow indicates success (e.g., change its contract to return a boolean
or have an accessible hasMeasuredOverflow getter) and after calling
measureOverflow() inside the interval, check the result and call
globalThis.clearInterval(intervalId) immediately when it returns true (in
addition to the existing attempts cap), ensuring the cleanup return still clears
the interval; keep the effect dependencies ([enabled, measureOverflow])
unchanged.
In `@openapi.yaml`:
- Around line 1012-1017: The OpenAPI param `selection_id` used by GET /drops is
ambiguous about scope; clarify whether `selection_id` values are globally unique
or require a `wave_id`. Update the `selection_id` parameter description (the
param named selection_id in the GET /drops operation) to state explicitly that
selection IDs are global if they are unique across waves, or change the
schema/requirements so that `wave_id` must be provided alongside `selection_id`
(or vice versa) and document that requirement; reference the existing selection
resource path `/waves/{id}/selections/{selectionId}` in the description to
explain scoping.
- Around line 5905-6020: For each selection mutation operation (operationId
createWaveSelection, deleteWaveSelection, addDropToWaveSelection,
removeDropFromWaveSelection) add explicit 4xx responses: at minimum 403
(forbidden) and 404 (not found) alongside the existing success codes; include a
descriptive "description" and reference the project's standard error schema
(e.g., ApiError or the common error response component) so generated clients can
distinguish permission errors from missing wave/selection/drop IDs—apply this
change to the POST /waves/{id}/selections, DELETE
/waves/{id}/selections/{selectionId}, POST
/waves/{id}/selections/{selectionId}/drops, and DELETE
/waves/{id}/selections/{selectionId}/drops/{dropId} entries (keep existing
success schemas like ApiWaveSelection, ApiWaveSelectionRequest,
ApiWaveSelectionDropRequest as-is).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ab952f77-6813-430e-848a-dc099e919a1f
⛔ Files ignored due to path filters (9)
generated/models/ApiDrop.tsis excluded by!**/generated/**generated/models/ApiDropWithoutWave.tsis excluded by!**/generated/**generated/models/ApiWave.tsis excluded by!**/generated/**generated/models/ApiWaveMin.tsis excluded by!**/generated/**generated/models/ApiWaveSelection.tsis excluded by!**/generated/**generated/models/ApiWaveSelectionDropRequest.tsis excluded by!**/generated/**generated/models/ApiWaveSelectionRequest.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (11)
__tests__/components/drops/view/DropsList.test.tsx__tests__/components/home/boosted/BoostedDropCardHome.test.tsxcomponents/drops/view/DropsList.tsxcomponents/home/boosted/BoostedDropCardHome.tsxcomponents/home/boosted/BoostedDropCardHomeContent.tsxcomponents/home/boosted/BoostedDropLinkPreview.tsxcomponents/user/layout/userPageVisibility.tscomponents/waves/memes/submission/utils/buildPreviewDrop.tscomponents/waves/utils/getOptimisticDrop.tshooks/useWaveDropsSearch.tsopenapi.yaml
|



Summary by CodeRabbit
New Features
Tests