Skip to content

Show latest drop subscription status + balance#2231

Merged
prxt6529 merged 7 commits intomainfrom
latest-drop-sub-balance
Apr 8, 2026
Merged

Show latest drop subscription status + balance#2231
prxt6529 merged 7 commits intomainfrom
latest-drop-sub-balance

Conversation

@prxt6529
Copy link
Copy Markdown
Collaborator

@prxt6529 prxt6529 commented Apr 8, 2026

Summary by CodeRabbit

  • New Features

    • Now displays a subscription section in Now Minting Details with a formatted balance label.
    • Compact/read-only subscription view shows "Subscribed" state and subscription counts instead of controls; section can be hidden when the user is not subscribed.
  • Tests

    • Expanded test coverage for subscription UI states, balance display, and conditional rendering.

Signed-off-by: prxt6529 <prxt@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

LatestDropNextMintSubscribe gained optional props (showOnlyWhenSubscribed, readonly), now conditionally hides when unsubscribed, computes a formatted balanceLabel, and passes it to MemeSubscriptionRow. MemeSubscriptionRow supports balanceLabel and a subscribedView (compact subscribed rendering). NowMintingDetails includes the subscription component; tests updated/added accordingly.

Changes

Cohort / File(s) Summary
LatestDropNextMintSubscribe
components/home/now-minting/LatestDropNextMintSubscribe.tsx
Added optional showOnlyWhenSubscribed and readonly props; returns null when gating hides unsubscribed users; computes balanceLabel (finite check + Intl.NumberFormat) and forwards it to MemeSubscriptionRow.
MemeSubscriptionRow
components/user/subscriptions/MemeSubscriptionRow.tsx
Added optional balanceLabel and subscribedView props. Compact variant now switches header between "Subscribed"/"Subscribe", shows count ratio when subscribed, and optionally renders an inline balance with an EthereumIcon. Minor markup/class ordering changes.
Integration into NowMintingDetails
components/home/now-minting/NowMintingDetails.tsx
Inserted LatestDropNextMintSubscribe between stats grid and accordion; invoked with showOnlyWhenSubscribed and readonly.
Tests — LatestDropNextMintSubscribe
__tests__/components/home/LatestDropNextMintSubscribe.test.tsx
Added CookieConsentContext mock, updated MemeSubscriptionRow mock text, extended assertions to expect formatted balance:0 and added test for showOnlyWhenSubscribed+readonly hiding when unsubscribed.
Tests — NowMintingDetails
__tests__/components/home/NowMintingDetails.test.tsx
Mocked LatestDropNextMintSubscribe to render a data-testid="subscribe-section" placeholder and updated an existing test to assert its presence.
Tests — MemeSubscriptionRow
__tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx
New test suite that mocks useQuery and API calls; verifies compact subscribedView rendering (header, count ratio), balance label presence, and behavior when consolidation data is absent.

Sequence Diagram(s)

sequenceDiagram
    participant NMD as NowMintingDetails
    participant LDNMS as LatestDropNextMintSubscribe
    participant API as Subscription API / useQuery
    participant MSR as MemeSubscriptionRow

    NMD->>LDNMS: Render (showOnlyWhenSubscribed=true, readonly=true)
    LDNMS->>API: Query subscription status & details
    API-->>LDNMS: { subscribed, balance, ... }

    alt subscribed === false
        LDNMS-->>NMD: Return null (no render)
    else subscribed === true
        LDNMS->>LDNMS: Compute balanceLabel (finite → Intl.NumberFormat)
        LDNMS->>MSR: Render with balanceLabel, subscribedView=true, readonly=true
        MSR-->>LDNMS: Render compact subscribed UI (header, count ratio, balance)
        LDNMS-->>NMD: Subscription section displayed
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Subscribe Next Mint #2203: Introduced foundational LatestDropNextMintSubscribe and MemeSubscriptionRow components that this PR extends with props and subscribed/balance behaviors.
  • Subscriptions visibility gating #2206: Also modifies LatestDropNextMintSubscribe.tsx gating/visibility logic; overlap in conditional rendering changes.

Suggested reviewers

  • GelatoGenesis
  • ragnep
  • simo6529

Poem

🐰 I nibble code and hop with glee,

balance shown, subscribe set free.
Compact counts and toggles hide,
Subscribed view hops by my side.
Mint approaches — carrots and key!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Show latest drop subscription status + balance' accurately and concisely describes the main change: displaying subscription status and balance information in the latest drop section.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch latest-drop-sub-balance

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.

🧹 Nitpick comments (1)
components/home/now-minting/LatestDropNextMintSubscribe.tsx (1)

85-90: Consider handling non-finite balance values.

The balance field is typed as number, which could potentially be NaN or Infinity in edge cases (e.g., API errors, corrupt data). The current fallback ?? 0 only handles undefined/null, but Intl.NumberFormat will render NaN as "NaN" and Infinity as "∞", which could be confusing to users.

🛡️ Defensive fix for non-finite values
 const balanceLabel = useMemo(() => {
-  const balance = details?.balance ?? 0;
+  const rawBalance = details?.balance ?? 0;
+  const balance = Number.isFinite(rawBalance) ? rawBalance : 0;
   return new Intl.NumberFormat(undefined, {
     maximumFractionDigits: 6,
   }).format(Math.round(balance * 1_000_000) / 1_000_000);
 }, [details?.balance]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/home/now-minting/LatestDropNextMintSubscribe.tsx` around lines 85
- 90, The computed balanceLabel should guard against non-finite numbers: inside
the useMemo for balanceLabel (which reads details?.balance), validate the
numeric value with Number.isFinite (or isFinite) and fallback to 0 when the
value is NaN or Infinity before rounding/formatting; then pass that safe finite
number into the existing Math.round(...)/Intl.NumberFormat logic so
Intl.NumberFormat never receives NaN/Infinity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@components/home/now-minting/LatestDropNextMintSubscribe.tsx`:
- Around line 85-90: The computed balanceLabel should guard against non-finite
numbers: inside the useMemo for balanceLabel (which reads details?.balance),
validate the numeric value with Number.isFinite (or isFinite) and fallback to 0
when the value is NaN or Infinity before rounding/formatting; then pass that
safe finite number into the existing Math.round(...)/Intl.NumberFormat logic so
Intl.NumberFormat never receives NaN/Infinity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 870b1b61-478b-48e7-bac9-180ea4a8f504

📥 Commits

Reviewing files that changed from the base of the PR and between 262eec4 and af8dbb4.

📒 Files selected for processing (5)
  • __tests__/components/home/LatestDropNextMintSubscribe.test.tsx
  • __tests__/components/home/NowMintingDetails.test.tsx
  • components/home/now-minting/LatestDropNextMintSubscribe.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/user/subscriptions/MemeSubscriptionRow.tsx

prxt6529 added 3 commits April 8, 2026 11:46
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@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

🧹 Nitpick comments (3)
app/page.tsx (2)

107-117: Consider configuring QueryClient defaults for SSR.

Creating a bare QueryClient() in a server component means every request gets a fresh client (correct), but the default staleTime is 0. If the prefetched data is immediately considered stale on the client, React Query may refetch on mount, negating the SSR benefit.

💡 Suggested improvement
 export default async function Page() {
-  const queryClient = new QueryClient();
+  const queryClient = new QueryClient({
+    defaultOptions: {
+      queries: {
+        staleTime: 60 * 1000, // 1 minute - adjust as needed
+      },
+    },
+  });
   await prefetchHomeSubscriptionState(queryClient);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/page.tsx` around lines 107 - 117, The QueryClient created in Page() uses
default staleTime=0 causing prefetched data to be immediately stale and trigger
refetch on mount; update the QueryClient instantiation in Page (where
QueryClient is constructed before
prefetchHomeSubscriptionState/dehydrate/HydrationBoundary) to pass sensible
defaultOptions (e.g., set queries.staleTime to a nonzero value and/or cacheTime)
so SSR-prefetched queries remain fresh on the client and avoid unnecessary
refetches.

35-45: JWT decoding silently catches all errors—consider logging for observability.

While returning null on decode failure is safe, silently swallowing errors makes debugging authentication issues harder in production. Consider logging the error at a debug/warn level.

💡 Optional improvement
   try {
     return jwtDecode<WalletJwtPayload>(jwt).sub?.toLowerCase() ?? null;
   } catch {
+    // Optionally log for observability: console.warn('Failed to decode wallet JWT');
     return null;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/page.tsx` around lines 35 - 45, The getWalletAddressFromJwt function
currently swallows all thrown errors from jwtDecode; update its catch block to
capture the caught error (e.g., "err") and log it at an appropriate level (debug
or warn) before returning null so decoding failures are observable; reference
the function getWalletAddressFromJwt, the jwtDecode call, and the
WalletJwtPayload type when making the change and use the project's logger (or
console as fallback) to record the error and a brief context message.
__tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx (1)

20-81: Consider adding edge case tests for robustness.

The current test covers the happy path well. Consider adding tests for:

  • subscribedView with balanceLabel to verify the balance UI renders
  • subscribedView when finalWithMetadata is null (no phase info displayed)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx` around
lines 20 - 81, Add two edge-case tests in MemeSubscriptionRow.test.tsx: (1) a
test that renders <MemeSubscriptionRow ... subscribedView balanceLabel="0.5"
.../> and asserts the balance UI renders (e.g., text containing the
balanceLabel) while keeping other props similar to the existing happy-path test;
(2) a test that simulates no final metadata by making useQueryMock return {
data: null } for the "consolidation-final-subscription" queryKey and rendering
<MemeSubscriptionRow subscribedView .../> then asserting that the phase line
(the text matched by /Phase:/ or the element rendered by MemeSubscriptionRow
when finalWithMetadata exists) is not present; locate usage of useQueryMock in
beforeEach and the component props
token_id/contract/subscribed/subscribed_count, subscribedView, balanceLabel and
finalWithMetadata to implement these assertions.
🤖 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/home/LatestDropNextMintSubscribe.test.tsx`:
- Around line 94-96: The test currently only checks for the prefix with
expect(screen.getByTestId("meme-subscription-row")).toHaveTextContent(/balance:/)
— update this to assert the exact rendered fallback value given the default mock
(details.balance is undefined). Inspect the mock that supplies details.balance
and change the assertion on getByTestId("meme-subscription-row") to match the
actual expected output (for example toHaveTextContent(/balance:\s*0/),
toHaveTextContent(/balance:\s*N\/A/), or toHaveTextContent(/balance:\s*$/)
depending on the component's fallback behavior) so the test verifies the full
balance string rather than just the prefix.

In `@components/user/subscriptions/MemeSubscriptionRow.tsx`:
- Around line 289-292: The read-only view shows subscribedCount derived from
props.subscription.subscribed_count using nullish coalescing which doesn't treat
explicit 0 as a fallback; update the calculation in MemeSubscriptionRow (where
subscribedCount is computed) to treat 0 like null/undefined (e.g., use a falsy
check or explicit === 0 handling so subscribedCount becomes 1 when
props.subscription.subscribed_count is 0/undefined/null), and leave
LatestDropNextMintSubscribe as-is since it already uses ?? 1; ensure
UserPageSubscriptionsUpcoming-supplied subscriptions are normalized similarly or
handled in the same subscribedCount logic.

---

Nitpick comments:
In `@__tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx`:
- Around line 20-81: Add two edge-case tests in MemeSubscriptionRow.test.tsx:
(1) a test that renders <MemeSubscriptionRow ... subscribedView
balanceLabel="0.5" .../> and asserts the balance UI renders (e.g., text
containing the balanceLabel) while keeping other props similar to the existing
happy-path test; (2) a test that simulates no final metadata by making
useQueryMock return { data: null } for the "consolidation-final-subscription"
queryKey and rendering <MemeSubscriptionRow subscribedView .../> then asserting
that the phase line (the text matched by /Phase:/ or the element rendered by
MemeSubscriptionRow when finalWithMetadata exists) is not present; locate usage
of useQueryMock in beforeEach and the component props
token_id/contract/subscribed/subscribed_count, subscribedView, balanceLabel and
finalWithMetadata to implement these assertions.

In `@app/page.tsx`:
- Around line 107-117: The QueryClient created in Page() uses default
staleTime=0 causing prefetched data to be immediately stale and trigger refetch
on mount; update the QueryClient instantiation in Page (where QueryClient is
constructed before prefetchHomeSubscriptionState/dehydrate/HydrationBoundary) to
pass sensible defaultOptions (e.g., set queries.staleTime to a nonzero value
and/or cacheTime) so SSR-prefetched queries remain fresh on the client and avoid
unnecessary refetches.
- Around line 35-45: The getWalletAddressFromJwt function currently swallows all
thrown errors from jwtDecode; update its catch block to capture the caught error
(e.g., "err") and log it at an appropriate level (debug or warn) before
returning null so decoding failures are observable; reference the function
getWalletAddressFromJwt, the jwtDecode call, and the WalletJwtPayload type when
making the change and use the project's logger (or console as fallback) to
record the error and a brief context message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aa758cd8-6ad5-44bf-86f3-f83c5b8f0a7e

📥 Commits

Reviewing files that changed from the base of the PR and between af8dbb4 and 9ea462a.

📒 Files selected for processing (5)
  • __tests__/components/home/LatestDropNextMintSubscribe.test.tsx
  • __tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx
  • app/page.tsx
  • components/home/now-minting/LatestDropNextMintSubscribe.tsx
  • components/user/subscriptions/MemeSubscriptionRow.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/home/now-minting/LatestDropNextMintSubscribe.tsx

Comment thread __tests__/components/home/LatestDropNextMintSubscribe.test.tsx
Comment thread components/user/subscriptions/MemeSubscriptionRow.tsx
prxt6529 added 2 commits April 8, 2026 13:09
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@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.

🧹 Nitpick comments (1)
components/user/subscriptions/MemeSubscriptionRow.tsx (1)

277-287: Balance label lacks accessibility context.

The balance label displays a value with an EthereumIcon but screen readers won't understand that the icon represents Ethereum/ETH currency. Consider adding an aria-label or visually hidden text for accessibility.

♿ Proposed accessibility improvement
             {props.balanceLabel && (
               <span className="tw-flex tw-items-center tw-gap-1 tw-text-sm tw-leading-none tw-text-iron-400">
                 <span className="tw-leading-none">Balance</span>
                 <span className="tw-leading-none tw-text-iron-300">
                   {props.balanceLabel}
                 </span>
-                <span className="tw-flex tw-size-3.5 tw-items-center tw-justify-center tw-self-center tw-text-iron-400">
+                <span 
+                  className="tw-flex tw-size-3.5 tw-items-center tw-justify-center tw-self-center tw-text-iron-400"
+                  aria-label="ETH"
+                  role="img"
+                >
                   <EthereumIcon />
                 </span>
               </span>
             )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/user/subscriptions/MemeSubscriptionRow.tsx` around lines 277 -
287, The balance label (props.balanceLabel) renders an EthereumIcon with no
accessible text, so screen readers can't identify the currency; update the
MemeSubscriptionRow rendering to provide accessibility by either adding an
aria-label (e.g., aria-label="Ethereum" or aria-hidden="true" on the decorative
part plus a visually hidden text node saying "ETH") to the EthereumIcon span, or
include a visually-hidden span (screen-reader-only) adjacent to the icon that
reads "Ethereum" or "ETH" so assistive tech correctly announces the currency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@components/user/subscriptions/MemeSubscriptionRow.tsx`:
- Around line 277-287: The balance label (props.balanceLabel) renders an
EthereumIcon with no accessible text, so screen readers can't identify the
currency; update the MemeSubscriptionRow rendering to provide accessibility by
either adding an aria-label (e.g., aria-label="Ethereum" or aria-hidden="true"
on the decorative part plus a visually hidden text node saying "ETH") to the
EthereumIcon span, or include a visually-hidden span (screen-reader-only)
adjacent to the icon that reads "Ethereum" or "ETH" so assistive tech correctly
announces the currency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fcc6d690-321d-473a-95ff-7afb0942ff2a

📥 Commits

Reviewing files that changed from the base of the PR and between 951ece3 and 6f6ee0b.

📒 Files selected for processing (1)
  • components/user/subscriptions/MemeSubscriptionRow.tsx

Signed-off-by: prxt6529 <prxt@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 8, 2026

@prxt6529 prxt6529 merged commit d6ac792 into main Apr 8, 2026
8 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 21, 2026
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