Skip to content

sentry issues#2088

Merged
simo6529 merged 12 commits intomainfrom
090326-1
Mar 9, 2026
Merged

sentry issues#2088
simo6529 merged 12 commits intomainfrom
090326-1

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Mar 9, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Prevented unhandled promise rejections during initial settings load.
    • File metadata (type and dimensions) now shown only when available.
  • New Features

    • Improved media source resolution: top-level media URLs take precedence with robust fallbacks for animation and image.
  • Refactor

    • Centralized media metadata parsing with per-media helpers; components now derive file type/dimensions from unified logic.
  • Tests

    • Added broad test coverage for media helpers, source precedence, renderers/carousel interactions, and load-failure handling.
  • Chores

    • Removed a stale API schema entry from documentation.

simo6529 added 3 commits March 9, 2026 08:12
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replace ad-hoc NFT metadata access with typed helpers and resolved image/animation source utilities; update media renderers and MemeLab/NowMinting UIs to use these helpers and conditionally show file metadata; add/extend unit tests; guard SeizeSettingsContext initial load to avoid unhandled promise rejections.

Changes

Cohort / File(s) Summary
Core helpers & types
helpers/nft.helpers.ts
Introduce NFTMediaMetadata/NFTMediaDetails, add specialized getters (getAnimationFileTypeFromMetadata, getImageFileTypeFromMetadata, getAnimationDimensionsFromMetadata, getImageDimensionsFromMetadata), tighten getFileTypeFromMetadata/getDimensionsFromMetadata with null-safe trimming and validation.
Resolved source utils & tests
components/nft-image/utils/animation-source.ts, components/nft-image/utils/image-source.ts, __tests__/components/nft-image/utils/animation-source.test.ts, __tests__/components/nft-image/utils/image-source.test.ts
Add getResolvedAnimationSrc and getResolvedImageSrc to normalize/prioritize top-level vs metadata fields; include unit tests covering trimming and fallback scenarios.
Media-type & renderers
components/nft-image/utils/media-type.ts, components/nft-image/NFTModel.tsx, components/nft-image/renderers/NFTHTMLRenderer.tsx, components/nft-image/renderers/NFTModelRenderer.tsx, components/nft-image/renderers/NFTVideoRenderer.tsx
Switch animation detection to getResolvedAnimationSrc, prefer resolved/compressed variants for video src and error fallbacks, and use safe classname resolution to avoid undefined classes.
Memelab / MemePage UI
components/memelab/MemeLabPage.tsx, components/the-memes/MemePageArt.tsx
Replace ad-hoc metadata checks with helper-derived imageFormat/animationFormat/imageHref/animationHref; compute hasAnimation/isShowingAnimation; conditional rendering of file type, dimensions, links, and downloads based on resolved sources.
Now Minting UI
components/home/now-minting/NowMintingDetailsAccordion.tsx, __tests__/components/home/NowMintingDetails.test.tsx
Make fileType and dimensions optional and render corresponding rows only when present; add tests for presence/absence of file metadata.
SeizeSettingsContext init handling
contexts/SeizeSettingsContext.tsx, __tests__/contexts/SeizeSettingsContext.test.tsx
Guard initial loadSeizeSettings() with .catch(() => undefined) to prevent unhandled promise rejections; add test asserting rejection is handled and no unhandledrejection fires.
Tests: MemeLab / MemePage / NFT image / helpers
__tests__/components/memelab/MemeLabPage.test.tsx, __tests__/components/the-memes/MemePageArt.test.tsx, __tests__/components/nft-image/*, __tests__/helpers/nft.helpers.test.ts
Add/extend tests for media-source precedence, carousel-driven metadata switches, file-type/dimensions expectations, download hrefs, and video error fallbacks; update mocks (Carousel, Download, FontAwesomeIcon) and nft.helpers mocks.
OpenAPI
openapi.yaml
Remove ApiSetPinnedDropRequest schema entry and apply minor whitespace adjustments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • ragnep

Poem

🐰 I trim each string and follow the track,
I hop through metadata, bringing truth back.
Animation then image — I pick what is true,
Tests thump their feet as the fallbacks pass through.
Code chewed and tidy, I leave a small snack.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'sentry issues' is vague and does not meaningfully describe the actual changeset, which involves refactoring NFT metadata helpers, animation/image source resolution, and comprehensive test additions across multiple components. Replace with a descriptive title that captures the main change, such as 'Refactor NFT metadata helpers and implement resolved animation/image source utilities' or 'Extract animation and image source resolution logic into dedicated utilities'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 090326-1

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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)
components/memelab/MemeLabPage.tsx (1)

99-103: ⚠️ Potential issue | 🟠 Major

Change the nullish coalescing operator to a logical OR operator.

The code uses ?? which only checks the fallback if the left side is null or undefined. An empty string "" will bypass the fallback to metadata.animation, preventing the page from detecting animations that only exist in metadata. Test files throughout the codebase (MemeLab.additional.test.tsx, MemePageArt.test.tsx, etc.) include explicit test cases with animation: "", confirming this is a real scenario. MemePageArt.tsx correctly uses the logical OR operator for this exact check.

Proposed fix
-  const hasAnimation = Boolean(nft?.animation ?? nft?.metadata?.animation);
+  const hasAnimation = Boolean(nft?.animation || nft?.metadata?.animation);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/memelab/MemeLabPage.tsx` around lines 99 - 103, The hasAnimation
calculation uses the nullish coalescing operator (??) which ignores empty-string
cases; update the expression in the hasAnimation definition to use a logical OR
(||) so nft?.animation || nft?.metadata?.animation correctly treats "" as falsy
and falls back to metadata.animation; adjust the derived fullscreenElementId
logic (which relies on hasAnimation and currentSlide) will then behave as
intended without further changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/memelab/MemeLabPage.tsx`:
- Around line 982-984: The link/download URL fallbacks were narrowed to metadata
only (variables imageHref and animationHref), removing support for top-level
nft.image and nft.animation; update the logic in MemeLabPage (where imageHref
and animationHref are computed) to fall back to nft.image and nft.animation when
metadata.image / metadata.animation(_url) are missing so links/downloads match
rendered art (mirror the fallback behavior from MemePageArt).

In `@components/the-memes/MemePageArt.tsx`:
- Around line 48-50: The media URL fallbacks currently only read from
props.nft.metadata, causing top-level props.nft.image and props.nft.animation to
be ignored for downloads; update the assignments for imageHref and animationHref
(and any code referencing them) to fall back to top-level fields: set imageHref
to props.nft?.metadata?.image ?? props.nft?.image and set animationHref to
props.nft?.metadata?.animation ?? props.nft?.metadata?.animation_url ??
props.nft?.animation so components that use imageHref/animationHref for
rendering and link/download actions will work when only top-level URLs are
present.

In `@helpers/nft.helpers.ts`:
- Around line 23-27: The getMediaFormat function can call .trim() on non-string
values from details.format; update getMediaFormat to first verify details and
typeof details.format === 'string' (or use String guard) before calling .trim(),
and return null for any non-string or falsy result so it fails closed; reference
the getMediaFormat function and its use of details?.format in your change.

---

Outside diff comments:
In `@components/memelab/MemeLabPage.tsx`:
- Around line 99-103: The hasAnimation calculation uses the nullish coalescing
operator (??) which ignores empty-string cases; update the expression in the
hasAnimation definition to use a logical OR (||) so nft?.animation ||
nft?.metadata?.animation correctly treats "" as falsy and falls back to
metadata.animation; adjust the derived fullscreenElementId logic (which relies
on hasAnimation and currentSlide) will then behave as intended without further
changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32695666-bfb0-47e9-83a3-c9cd94be232f

📥 Commits

Reviewing files that changed from the base of the PR and between 8bb0347 and aac877e.

📒 Files selected for processing (9)
  • __tests__/components/home/NowMintingDetails.test.tsx
  • __tests__/components/the-memes/MemePageArt.test.tsx
  • __tests__/contexts/SeizeSettingsContext.test.tsx
  • __tests__/helpers/nft.helpers.test.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/memelab/MemeLabPage.tsx
  • components/the-memes/MemePageArt.tsx
  • contexts/SeizeSettingsContext.tsx
  • helpers/nft.helpers.ts

Comment thread components/memelab/MemeLabPage.tsx Outdated
Comment thread components/the-memes/MemePageArt.tsx Outdated
Comment thread helpers/nft.helpers.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/memelab/MemeLabPage.tsx`:
- Line 99: hasAnimation is currently derived with a nullish coalescing
expression that can be fooled by empty strings and it also ignores
metadata.animation_url; update the logic so both hasAnimation and the
animationHref use the same precedence list of possible sources (e.g.,
nft.animation, nft.metadata?.animation, nft.metadata?.animation_url) and pick
the first non-empty value (filtering falsy values) to set animationHref, then
set hasAnimation = Boolean(animationHref). Apply this change where hasAnimation
is declared and where animationHref is computed/used (references: hasAnimation,
animationHref).

In `@components/the-memes/MemePageArt.tsx`:
- Around line 37-39: The component's hasAnimation check is missing
metadata.animation_url so the art branch can render a static view while
animationHref (or download link) uses that field; update the Boolean computation
for hasAnimation (and any duplicated logic around where the art branch decides
to render animation vs static, e.g., the same logic near the code handling
animationHref) to include props.nft?.metadata?.animation_url in addition to
props.nft?.animation and props.nft?.metadata?.animation so both rendering and
link generation stay in sync.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e7a2297-1c0c-4116-aa6a-b7b733633578

📥 Commits

Reviewing files that changed from the base of the PR and between aac877e and f8588c4.

📒 Files selected for processing (6)
  • __tests__/components/memelab/MemeLabPage.test.tsx
  • __tests__/components/the-memes/MemePageArt.test.tsx
  • __tests__/helpers/nft.helpers.test.ts
  • components/memelab/MemeLabPage.tsx
  • components/the-memes/MemePageArt.tsx
  • helpers/nft.helpers.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/helpers/nft.helpers.test.ts
  • tests/components/the-memes/MemePageArt.test.tsx

Comment thread components/memelab/MemeLabPage.tsx Outdated
Comment thread components/the-memes/MemePageArt.tsx Outdated
simo6529 added 2 commits March 9, 2026 11:49
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx (2)

636-641: ⚠️ Potential issue | 🟡 Minor

Same dead code pattern repeated.

Lines 638 and 640 have the same constant condition issue.

Suggested fix
     it("handles completely empty NFT animation properties gracefully", () => {
       const nft = createMockNFT({
-        ...(undefined !== undefined ? { animation: undefined } : {}),
+        animation: undefined,
         compressed_animation: undefined,
-        ...(undefined !== undefined ? { metadata: undefined } : {}),
+        metadata: undefined,
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx` around
lines 636 - 641, The test contains dead ternary expressions using "undefined !==
undefined" when calling createMockNFT (in NFTVideoRenderer.test.tsx) which
always evaluate false; update the createMockNFT invocation to set the intended
properties directly (e.g., pass animation: undefined and metadata: undefined, or
simply omit those spread ternaries) so the test reflects the intended empty
animation/metadata setup and removes the redundant conditional spreads.

275-279: ⚠️ Potential issue | 🟡 Minor

Same dead code pattern.

The undefined !== undefined condition at line 277 is always false. The test doesn't actually set animation: undefined.

Suggested fix
     it("handles missing animation properties gracefully", () => {
       const nft = createMockNFT({
-        ...(undefined !== undefined ? { animation: undefined } : {}),
+        animation: undefined,
         compressed_animation: undefined,
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx` around
lines 275 - 279, The test "handles missing animation properties gracefully"
contains a dead conditional `undefined !== undefined` so it never sets animation
to undefined; update the test to explicitly pass animation: undefined when
calling createMockNFT (or remove the conditional and include animation:
undefined in the object), e.g. modify the createMockNFT call in the
NFTVideoRenderer.test.tsx test so the props object contains animation: undefined
and compressed_animation: undefined to correctly simulate missing animation
properties.
🧹 Nitpick comments (1)
components/nft-image/utils/animation-source.ts (1)

3-10: Simplify the conditional return.

SonarCloud flagged line 9 as an unnecessary conditional expression. Since trimmed is already a string (empty or non-empty), you can simplify:

Suggested simplification
 const normalizeNonEmptyString = (value: unknown): string | undefined => {
   if (typeof value !== "string") {
     return undefined;
   }

   const trimmed = value.trim();
-  return trimmed ? trimmed : undefined;
+  return trimmed || undefined;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/nft-image/utils/animation-source.ts` around lines 3 - 10, The
function normalizeNonEmptyString currently returns trimmed ? trimmed : undefined
which is an unnecessary conditional; replace that expression with a simpler
truthy fallback (e.g., return trimmed || undefined) inside
normalizeNonEmptyString so it returns the non-empty string or undefined without
the redundant ternary.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@__tests__/components/nft-image/NFTImage.test.tsx`:
- Around line 444-460: The test title claims props are forwarded but only
verifies the renderer mounted; update the "passes all required props to
renderers" test so it asserts that the NFTImage component actually forwards the
props to the renderer (the element queried by getByTestId("nft-image-renderer")
or the mock renderer call). Specifically, verify that height, balance,
showOwned, showUnseized, transparentBG, id, showOriginal and showThumbnail are
present on the renderer (either by checking DOM attributes/data-attributes or by
asserting the renderer mock was called with those props) using explicit expect
checks rather than only toBeInTheDocument.
- Around line 43-47: The test currently only verifies that the HTML branch was
chosen because the mock `MockNFTHTMLRenderer` renders `props.nft.animation`
(which is `""`), so update the test to assert the actual resolved animation URL:
import or compute the expected URL using the resolver in
`components/nft-image/utils/animation-source.ts` (or call the same resolution
function used by `NFTImage`), provide that expected value into the mock's
`props.nft.animation` (or compare against the resolved output), and add an
assertion that the rendered iframe (from `MockNFTHTMLRenderer`) has src equal to
the expected resolved animation URL; reference `MockNFTHTMLRenderer`,
`props.nft.animation`, and the resolver in `animation-source.ts` when making the
change.
- Around line 463-476: The test is using a bogus object cast with `as any`
instead of a real NFTLite, so update the test in NFTImage.test.tsx to construct
a proper NFTLite fixture (include the required fields `contract`, `icon`,
`scaled`, and `animation` per entities/INFT.ts) instead of using `as any`;
create a minimal valid NFTLite object (e.g., provide a contract id/object, icon
URL, scaled boolean, animation url/null) and pass that to render(<NFTImage
{...defaultProps} nft={nftLite} />), or import/create a shared NFTLite
fixture/type to ensure the NFTImage component hits the NFTLite branch and the
test type-checks without bypassing types.

In `@__tests__/components/nft-image/renderers/NFTHTMLRenderer.test.tsx`:
- Around line 314-316: The test calls createMockNFT with a spread that never
applies, so it doesn't actually set metadata to undefined; update the fixture to
explicitly pass metadata: undefined to exercise the missing-metadata case (e.g.,
change the call to createMockNFT({ metadata: undefined, ...otherProps })) or, if
missing metadata should render safely now, update the test expectation instead;
locate the call to createMockNFT in NFTHTMLRenderer.test.tsx and either provide
metadata: undefined directly or change the assertion to match the current
safe-render behavior.

In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx`:
- Around line 307-310: The test uses a tautological false condition (`undefined
!== undefined`) so the spread never sets metadata to undefined; update the test
to actually create an NFT with missing metadata by directly passing metadata:
undefined to createMockNFT (or remove the metadata key entirely) in the test
case that declares nft (the createMockNFT call in NFTVideoRenderer.test.tsx) so
the "handles missing metadata gracefully" scenario is exercised.

In `@__tests__/components/nft-image/utils/media-type.test.ts`:
- Around line 390-446: The tests rely on getMediaType being robust to malformed
metadata, but current behavior calls format.toLowerCase() unguarded and treats
padded strings incorrectly; update getMediaType to safely coerce/validate
format: check typeof animation_details.format === "string", trim() it, then
toLowerCase() (or fall back to using existing metadata helpers that normalize
formats), and for any non-string or missing formats return the safe default
"image" instead of throwing; after fixing getMediaType, update the affected
tests (the cases with padded whitespace and with non-string/boolean/array/object
formats) to expect a normalized media type (trimmed/lowercased) or "image"
rather than asserting a runtime error.
- Around line 104-106: The conditional spread using "undefined !== undefined ? {
metadata: undefined } : {}" within the createMockNFT call is a no-op and should
be removed; replace the call to createMockNFT(...) with a direct instantiation
that yields a BaseNFT without metadata (either call createMockNFT() with no
overrides or explicitly pass { metadata: undefined } if you need to be explicit)
so the test covers the metadata-absent case and removes the constant-conditional
spread that trips the linter.

In `@components/memelab/MemeLabPage.tsx`:
- Around line 980-989: The file metadata (fileType/dimensions) is currently
chosen directly from metadata helper functions
(getFileTypeFromMetadata/getDimensionsFromMetadata and
getAnimationFileTypeFromMetadata/getImageFileTypeFromMetadata) which can prefer
animation_details even when the resolved media is actually the image; change the
selection to follow the resolved media branch used for rendering (use
hasAnimation, imageHref, and currentSlide) so that when the image is the shown
asset you pick imageFormat/image dimensions and when the animation is the shown
asset you pick animationFormat/animation dimensions; update the logic around
currentFormat, fileType, and dimensions to derive from imageFormat vs
animationFormat based on hasAnimation and currentSlide (or whether imageHref is
blank) rather than from raw metadata precedence.

In `@components/nft-image/renderers/NFTVideoRenderer.tsx`:
- Around line 41-49: The equality check inside the onError handler can fail when
props.nft.compressed_animation is a relative URL because currentTarget.src is
absolute; update the comparison in the withArweaveFallback callback to normalize
compressed_animation to an absolute URL before comparing (e.g., use new
URL(props.nft.compressed_animation, window.location.href).href) and only perform
the swap if that normalized URL equals currentTarget.src and animationSrc is
present; ensure you guard for undefined compressed_animation and keep the rest
of the handler (withArweaveFallback, currentTarget.src assignment) unchanged.

In `@components/the-memes/MemePageArt.tsx`:
- Around line 44-47: The Card Details rows are computed from metadata that
prefers animation_details even when no usable animation URL exists; update the
assignments for fileType and dimensions to follow the same resolved-media logic
used for currentFormat/hasAnimation by checking getResolvedAnimationSrc (or
hasAnimation) first and only calling
getAnimationFileTypeFromMetadata/getDimensionsFromMetadata when a resolved
animation URL is present, otherwise fall back to image metadata via
getImageFileTypeFromMetadata/getDimensionsFromMetadata; apply the same change to
the other occurrence noted (the block around the currentFormat logic at the
later section) so both places derive format/dimensions from the same
resolved-media branch.

---

Outside diff comments:
In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx`:
- Around line 636-641: The test contains dead ternary expressions using
"undefined !== undefined" when calling createMockNFT (in
NFTVideoRenderer.test.tsx) which always evaluate false; update the createMockNFT
invocation to set the intended properties directly (e.g., pass animation:
undefined and metadata: undefined, or simply omit those spread ternaries) so the
test reflects the intended empty animation/metadata setup and removes the
redundant conditional spreads.
- Around line 275-279: The test "handles missing animation properties
gracefully" contains a dead conditional `undefined !== undefined` so it never
sets animation to undefined; update the test to explicitly pass animation:
undefined when calling createMockNFT (or remove the conditional and include
animation: undefined in the object), e.g. modify the createMockNFT call in the
NFTVideoRenderer.test.tsx test so the props object contains animation: undefined
and compressed_animation: undefined to correctly simulate missing animation
properties.

---

Nitpick comments:
In `@components/nft-image/utils/animation-source.ts`:
- Around line 3-10: The function normalizeNonEmptyString currently returns
trimmed ? trimmed : undefined which is an unnecessary conditional; replace that
expression with a simpler truthy fallback (e.g., return trimmed || undefined)
inside normalizeNonEmptyString so it returns the non-empty string or undefined
without the redundant ternary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59a3b14f-30bf-49b5-a39a-c093e98cb11a

📥 Commits

Reviewing files that changed from the base of the PR and between f8588c4 and 3fbb860.

📒 Files selected for processing (15)
  • __tests__/components/memelab/MemeLabPage.test.tsx
  • __tests__/components/nft-image/NFTImage.test.tsx
  • __tests__/components/nft-image/NFTModel.test.tsx
  • __tests__/components/nft-image/renderers/NFTHTMLRenderer.test.tsx
  • __tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx
  • __tests__/components/nft-image/utils/media-type.test.ts
  • __tests__/components/the-memes/MemePageArt.test.tsx
  • components/memelab/MemeLabPage.tsx
  • components/nft-image/NFTModel.tsx
  • components/nft-image/renderers/NFTHTMLRenderer.tsx
  • components/nft-image/renderers/NFTModelRenderer.tsx
  • components/nft-image/renderers/NFTVideoRenderer.tsx
  • components/nft-image/utils/animation-source.ts
  • components/nft-image/utils/media-type.ts
  • components/the-memes/MemePageArt.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/components/memelab/MemeLabPage.test.tsx

Comment thread __tests__/components/nft-image/NFTImage.test.tsx
Comment thread __tests__/components/nft-image/NFTImage.test.tsx
Comment thread __tests__/components/nft-image/NFTImage.test.tsx
Comment thread __tests__/components/nft-image/renderers/NFTHTMLRenderer.test.tsx
Comment thread __tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx
Comment thread __tests__/components/nft-image/utils/media-type.test.ts
Comment thread __tests__/components/nft-image/utils/media-type.test.ts
Comment thread components/memelab/MemeLabPage.tsx Outdated
Comment thread components/nft-image/renderers/NFTVideoRenderer.tsx
Comment thread components/the-memes/MemePageArt.tsx Outdated
simo6529 added 3 commits March 9, 2026 13:40
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx (1)

308-310: ⚠️ Potential issue | 🟡 Minor

Dead code: condition is always false.

The expression undefined !== undefined always evaluates to false, making this spread operation ineffective. The test isn't actually testing the scenario with metadata: undefined.

Suggested fix
     it("handles missing metadata gracefully", () => {
-      const nft = createMockNFT({
-        ...(undefined !== undefined ? { metadata: undefined } : {}),
-      });
+      const nft = { ...createMockNFT(), metadata: undefined };
       const props = createDefaultProps({ nft });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx` around
lines 308 - 310, The test uses a useless conditional `undefined !== undefined`
so the spread never sets metadata to undefined; update the call to createMockNFT
inside NFTVideoRenderer.test.tsx to explicitly include metadata: undefined (or
use a real flag/variable instead of the always-false expression) so the test
actually constructs an NFT with metadata === undefined; modify the expression
around createMockNFT to pass { metadata: undefined } directly (or replace the
conditional with a meaningful variable) to ensure the test covers the intended
branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/the-memes/MemePageArt.tsx`:
- Line 50: imageHref is set using props.nft?.metadata?.image ?? props.nft?.image
which treats empty or whitespace strings as valid and can override a usable
top-level image URL; update the logic to mirror getResolvedAnimationSrc by
trimming and validating that metadata.image is a non-empty string (e.g., use a
helper like getResolvedAnimationSrc or create getResolvedImageSrc) before
falling back to props.nft?.image, and apply the same normalization to the other
occurrence that handles image resolution (the block around the other image
handling you referenced).
- Around line 40-43: The carousel renders a second image slide even when
imageHref is empty, which allows currentSlide to flip the fullscreen target to
the image; change the conditional rendering so any image slide (the slide using
animation={false}) is only created when imageHref is truthy, and update the
fullscreenElementId logic to rely on isShowingAnimation (or explicitly check
imageHref) so that when !imageHref the fullscreen ID remains
"the-art-fullscreen-animation"; apply the same guard to the other slide-creation
blocks that set animation={false} (the blocks around the alternate conditional
renderings and the slide range ~50-53 and ~102-130) so no empty image slide is
rendered.

---

Duplicate comments:
In `@__tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx`:
- Around line 308-310: The test uses a useless conditional `undefined !==
undefined` so the spread never sets metadata to undefined; update the call to
createMockNFT inside NFTVideoRenderer.test.tsx to explicitly include metadata:
undefined (or use a real flag/variable instead of the always-false expression)
so the test actually constructs an NFT with metadata === undefined; modify the
expression around createMockNFT to pass { metadata: undefined } directly (or
replace the conditional with a meaningful variable) to ensure the test covers
the intended branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5b328477-1076-4a5f-87e7-9e40b505b859

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbb860 and afc2a11.

📒 Files selected for processing (11)
  • __tests__/components/memelab/MemeLabPage.test.tsx
  • __tests__/components/nft-image/renderers/NFTVideoRenderer.test.tsx
  • __tests__/components/nft-image/utils/animation-source.test.ts
  • __tests__/components/the-memes/MemePageArt.test.tsx
  • __tests__/helpers/nft.helpers.test.ts
  • components/memelab/MemeLabPage.tsx
  • components/nft-image/renderers/NFTVideoRenderer.tsx
  • components/nft-image/utils/animation-source.ts
  • components/the-memes/MemePageArt.tsx
  • helpers/nft.helpers.ts
  • openapi.yaml
✅ Files skipped from review due to trivial changes (1)
  • openapi.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/nft-image/utils/animation-source.ts
  • tests/components/the-memes/MemePageArt.test.tsx

Comment thread components/the-memes/MemePageArt.tsx Outdated
Comment thread components/the-memes/MemePageArt.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 9, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
components/memelab/MemeLabPage.tsx (2)

1067-1075: ⚠️ Potential issue | 🟡 Minor

Conditionally render the static image view based on hasImage.

In the non-animation branch, the image is rendered without checking hasImage. This matches the same pattern that was fixed in MemePageArt.tsx (lines 158-168).

🐛 Proposed fix to guard static image rendering
-                 <NFTImage
-                   nft={nft}
-                   animation={false}
-                   height={650}
-                   transparentBG={true}
-                   showOriginal={true}
-                   showBalance={false}
-                   id="the-art-fullscreen-img"
-                 />
+                 {hasImage && (
+                   <NFTImage
+                     nft={nft}
+                     animation={false}
+                     height={650}
+                     transparentBG={true}
+                     showOriginal={true}
+                     showBalance={false}
+                     id="the-art-fullscreen-img"
+                   />
+                 )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/memelab/MemeLabPage.tsx` around lines 1067 - 1075, The
non-animation branch in MemeLabPage.tsx renders the NFTImage component
unconditionally; change it to only render the static image when the meme has an
image by guarding the NFTImage JSX with the same hasImage check used in
MemePageArt.tsx (i.e., only render NFTImage with animation={false} when hasImage
is true). Locate the NFTImage usage (id="the-art-fullscreen-img",
animation={false}) and wrap it in a conditional that checks the existing
hasImage boolean so the static view is skipped when no image is present.

1035-1045: ⚠️ Potential issue | 🟡 Minor

Conditionally render the image slide based on hasImage.

Unlike MemePageArt.tsx which wraps the image slide in {hasImage && ...}, this carousel always renders the image slide. For animation-only NFTs without a valid image URL, this creates a broken slide that the user can navigate to.

🐛 Proposed fix to match MemePageArt pattern
-                   <Carousel.Item className="text-center">
-                     <NFTImage
-                       nft={nft}
-                       animation={false}
-                       height={650}
-                       transparentBG={true}
-                       showOriginal={true}
-                       showBalance={false}
-                       id="the-art-fullscreen-img"
-                     />
-                   </Carousel.Item>
+                   {hasImage && (
+                     <Carousel.Item className="text-center">
+                       <NFTImage
+                         nft={nft}
+                         animation={false}
+                         height={650}
+                         transparentBG={true}
+                         showOriginal={true}
+                         showBalance={false}
+                         id="the-art-fullscreen-img"
+                       />
+                     </Carousel.Item>
+                   )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/memelab/MemeLabPage.tsx` around lines 1035 - 1045, The Carousel
image slide is always rendered causing a broken slide for NFTs without images;
wrap the Carousel.Item that contains NFTImage in a conditional check using the
same hasImage boolean (e.g., {hasImage &&
(<Carousel.Item>...NFTImage...</Carousel.Item>)}), referencing the existing
hasImage variable and the Carousel.Item/NFTImage component block so the slide is
only rendered when an image URL exists.
🧹 Nitpick comments (2)
components/nft-image/renderers/NFTVideoRenderer.tsx (1)

19-30: Guard globalScope.window explicitly before property access.

The current code catches the error if globalScope.window is undefined, but the intent is unclear. It's better to explicitly check for the window object to avoid relying on error handling for expected undefined behavior.

♻️ Proposed fix for explicit window guard
 const normalizedCompressedAnimationSrc = (() => {
   if (compressedAnimationSrc == null || compressedAnimationSrc === "") {
     return undefined;
   }

+  if (typeof globalScope.window === "undefined") {
+    return undefined;
+  }
+
   try {
     const baseUrl = globalScope.window.location.href;
     return new URL(compressedAnimationSrc, baseUrl).href;
   } catch {
     return undefined;
   }
 })();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/nft-image/renderers/NFTVideoRenderer.tsx` around lines 19 - 30,
The self-invoking normalization for compressedAnimationSrc should explicitly
guard access to globalScope.window instead of relying on try/catch for expected
undefined behavior; update the normalizedCompressedAnimationSrc initializer to
first check that compressedAnimationSrc is non-empty and that globalScope and
globalScope.window are defined (or truthy) before constructing a baseUrl from
globalScope.window.location.href and creating new URL(compressedAnimationSrc,
baseUrl).href, and only fall back to undefined on URL construction failure (keep
the existing try/catch around new URL but move window checks outside it) — refer
to normalizedCompressedAnimationSrc, compressedAnimationSrc and
globalScope.window to locate the code to change.
components/memelab/MemeLabPage.tsx (1)

101-106: Consider aligning fullscreenElementId logic with MemePageArt.

In MemePageArt.tsx, fullscreenElementId uses isShowingAnimation and explicitly handles the no-image case. Here, the logic only checks hasAnimation && currentSlide === 0. If the image slide guard is added as suggested above, this should remain consistent, but if an animation-only NFT allows navigation to slide 1, the fullscreen ID would incorrectly point to the-art-fullscreen-img.

♻️ Proposed alignment with MemePageArt pattern
+ const isShowingAnimation = hasAnimation && (currentSlide === 0 || !hasImage);
  const fullscreenElementId =
-   hasAnimation && currentSlide === 0
+   isShowingAnimation
      ? "the-art-fullscreen-animation"
      : "the-art-fullscreen-img";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/memelab/MemeLabPage.tsx` around lines 101 - 106, The
fullscreenElementId calculation in MemeLabPage (using getResolvedAnimationSrc,
hasAnimation and currentSlide) should match MemePageArt's pattern: compute an
explicit isShowingAnimation flag (e.g., using hasAnimation && currentSlide === 0
but also considering the presence/absence of an image) and handle the no-image
case so animation-only NFTs don't fall back to "the-art-fullscreen-img"; update
the fullscreenElementId logic to select "the-art-fullscreen-animation" when
isShowingAnimation is true, otherwise choose "the-art-fullscreen-img" only if an
image exists, and ensure references to getResolvedAnimationSrc, hasAnimation,
currentSlide and the new isShowingAnimation variable are used to locate and
adjust the code.
🤖 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 `@components/memelab/MemeLabPage.tsx`:
- Around line 1067-1075: The non-animation branch in MemeLabPage.tsx renders the
NFTImage component unconditionally; change it to only render the static image
when the meme has an image by guarding the NFTImage JSX with the same hasImage
check used in MemePageArt.tsx (i.e., only render NFTImage with animation={false}
when hasImage is true). Locate the NFTImage usage (id="the-art-fullscreen-img",
animation={false}) and wrap it in a conditional that checks the existing
hasImage boolean so the static view is skipped when no image is present.
- Around line 1035-1045: The Carousel image slide is always rendered causing a
broken slide for NFTs without images; wrap the Carousel.Item that contains
NFTImage in a conditional check using the same hasImage boolean (e.g., {hasImage
&& (<Carousel.Item>...NFTImage...</Carousel.Item>)}), referencing the existing
hasImage variable and the Carousel.Item/NFTImage component block so the slide is
only rendered when an image URL exists.

---

Nitpick comments:
In `@components/memelab/MemeLabPage.tsx`:
- Around line 101-106: The fullscreenElementId calculation in MemeLabPage (using
getResolvedAnimationSrc, hasAnimation and currentSlide) should match
MemePageArt's pattern: compute an explicit isShowingAnimation flag (e.g., using
hasAnimation && currentSlide === 0 but also considering the presence/absence of
an image) and handle the no-image case so animation-only NFTs don't fall back to
"the-art-fullscreen-img"; update the fullscreenElementId logic to select
"the-art-fullscreen-animation" when isShowingAnimation is true, otherwise choose
"the-art-fullscreen-img" only if an image exists, and ensure references to
getResolvedAnimationSrc, hasAnimation, currentSlide and the new
isShowingAnimation variable are used to locate and adjust the code.

In `@components/nft-image/renderers/NFTVideoRenderer.tsx`:
- Around line 19-30: The self-invoking normalization for compressedAnimationSrc
should explicitly guard access to globalScope.window instead of relying on
try/catch for expected undefined behavior; update the
normalizedCompressedAnimationSrc initializer to first check that
compressedAnimationSrc is non-empty and that globalScope and globalScope.window
are defined (or truthy) before constructing a baseUrl from
globalScope.window.location.href and creating new URL(compressedAnimationSrc,
baseUrl).href, and only fall back to undefined on URL construction failure (keep
the existing try/catch around new URL but move window checks outside it) — refer
to normalizedCompressedAnimationSrc, compressedAnimationSrc and
globalScope.window to locate the code to change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b00473e-1802-4e29-b006-8b93ec2e2010

📥 Commits

Reviewing files that changed from the base of the PR and between afc2a11 and 2bc3fcd.

📒 Files selected for processing (7)
  • __tests__/components/memelab/MemeLabPage.test.tsx
  • __tests__/components/nft-image/utils/image-source.test.ts
  • __tests__/components/the-memes/MemePageArt.test.tsx
  • components/memelab/MemeLabPage.tsx
  • components/nft-image/renderers/NFTVideoRenderer.tsx
  • components/nft-image/utils/image-source.ts
  • components/the-memes/MemePageArt.tsx

@simo6529 simo6529 merged commit 9de746a into main Mar 9, 2026
7 checks passed
@simo6529 simo6529 deleted the 090326-1 branch March 9, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants