Skip to content

feat: creator profile page, key freeze banner, bundle cart, referral dashboard (#1118-#1121) - #1136

Closed
therealjhay wants to merge 1 commit into
accesslayerorg:devfrom
therealjhay:feat/bundle-buy-referrals-creator-profile-freeze
Closed

therealjhay wants to merge 1 commit into
accesslayerorg:devfrom
therealjhay:feat/bundle-buy-referrals-creator-profile-freeze

Conversation

@therealjhay

Copy link
Copy Markdown

Summary

This PR implements four linked feature issues across the AccessLayer client, all branched off dev with no merge conflicts.


Closes #1118 · Bundle Purchase Cart & Add-to-Bundle UI

  • useBundleCartStore (Zustand): addItem (idempotent — increments amount if key already in cart), removeItem, updateAmount (clamped ≥ 1), clearCart, isInCart; sessionStorage persistence so the cart survives a page refresh within the session. Exported selectors: selectBundleTotalCostStroops, selectBundleItemCount, selectEstimatedBundlePriceImpact.
  • BundleCartDrawer: right-sliding fixed drawer (max-w-md) with a ScrollArea item list, per-item ± quantity controls, remove button, estimated price impact, total-cost summary, and a Submit Bundle button that calls creatorKeysContractService.bundle_buy with a 5 % slippage guard (maxPriceStroops = price * 1.05). Success shows a truncated tx-hash toast; failure shows an error toast.
  • BundleCartTrigger: floating FAB (bottom-right) that appears only when the cart has items; opens the drawer on click.
  • RootLayout: BundleCartDrawer + BundleCartTrigger mounted at root level so they persist across navigation.
  • creatorKeysContractService.bundle_buy: new method accepting { keyId, amount, maxPriceStroops }[].
  • CreatorCard: "Add to bundle" toggle button (Package icon) next to the existing batch-basket button, wired to useBundleCartStore.
  • CreatorDetailPage: handleAddToBundle handler + "Add to Bundle" button in the key-purchase section; button is disabled when the key is frozen / paused / deprecated.

Closes #1119 · Referral Dashboard Page

  • ReferralDashboardPage: full layout with three named sections — referral link generator, earnings panel, referred-wallets table — each wrapped in an accessible <section> with a data-testid.
  • ReferralLinkGenerator: copies the wallet-scoped referral link to clipboard with a success toast; includes a QR-code hint text.
  • ReferralEarningsPanel: displays total rewards, pending claims, and claimable amount; claim button is gated on contractBalance > 0.
  • ReferredWalletsTable: paginated table of referred wallets with tier breakdowns, earned amounts per wallet, and status badges.
  • referral.service.ts: useReferralDashboard React-Query hook connecting all three panels.

Closes #1120 · Creator Public Profile Page with Stats & Key Listing

  • CreatorPublicProfilePage: header (avatar, display name, bio, social links), aggregated stats row (Total Holders, Total Volume, Keys Issued, Avg Market Cap, Avg Rating), and a responsive grid of DeployedCreatorKeyCard components. Dedicated 404 state for unknown addresses.
  • CreatorPublicProfileHeader: Follow/Unfollow button with optimistic update via useCreatorFollows; Share Profile button copies the current URL to clipboard with a toast.
  • CreatorProfileStatRow / CreatorProfileStatItem: formatted stat tiles reused on both the public profile and the detail page.
  • DeployedCreatorKeyCard: concise per-key summary card showing status badge, current price, and an invest CTA.
  • Type updates: CreatorPublicProfile.stats.avgMarketCapStroops, averageRating.
  • creatorProfile.utils: formatMemberSince helper.

Closes #1121 · Key Freeze Status Banner & Trading Block UI

  • KeyFreezeBanner: amber warning <aside role="alert"> rendered below the key header when creator.isFrozen is true. Shows freeze reason, expiry (formatted via formatAbsoluteDateTime or 'indefinite'), and a Contact Admin link. Auto-dismisses via setTimeout when the expiry timestamp is reached and fires an onExpiryReached callback.
  • CreatorDetailPage: isFrozen / freezeReason / freezeExpiry resolved from API response fields (isFrozen, frozen, freezeReason, freezeExpiry, freezeExpiresAt); 30-second polling interval while the key is frozen via refetch; isPastFreezeExpiry guard prevents showing an already-expired freeze; Buy Key button replaced with <UnavailableAction reason="Key trading is frozen"> when isKeyFrozen is true.
  • course.service.ts: isFrozen, frozen, freezeReason, freezeExpiry, freezeExpiresAt fields added to the Course interface.

Files Changed

File Change
src/hooks/useBundleCartStore.ts new
src/components/common/BundleCartDrawer.tsx new
src/components/common/BundleCartTrigger.tsx new
src/components/common/KeyFreezeBanner.tsx new
src/components/common/CreatorCard.tsx Add to Bundle toggle button
src/components/common/RootLayout.tsx Mount drawer + trigger
src/components/common/TradeDialog.tsx isFrozen prop disables trade tabs
src/components/common/CreatorPublicProfileHeader.tsx Follow/share actions
src/components/common/CreatorProfileStatRow.tsx Stat tile layout
src/components/common/CreatorProfileStatItem.tsx Stat tile component
src/components/common/DeployedCreatorKeyCard.tsx Key summary card
src/pages/CreatorPublicProfilePage.tsx Full profile page
src/pages/CreatorDetailPage.tsx Freeze banner, bundle button, freeze guard on Buy
src/services/course.service.ts Freeze fields on Course
src/services/creatorKeysContract.service.ts bundle_buy method
src/services/creatorProfile.service.ts Stats type update
src/types/creatorProfile.ts avgMarketCapStroops, averageRating
src/utils/creatorProfile.utils.ts formatMemberSince

Closes #1118 Closes #1119 Closes #1120 Closes #1121

…dashboard (accesslayerorg#1118-accesslayerorg#1121)

Implements four linked issues:

## accesslayerorg#1120 – Creator public profile page with stats & key listing
- CreatorPublicProfilePage: header (avatar, display name, bio, social links),
  aggregated stats row (Total Holders, Total Volume, Keys Issued, Avg Market Cap,
  Avg Rating), and a responsive grid of DeployedCreatorKeyCard components
- CreatorPublicProfileHeader: follow/unfollow button with optimistic update via
  useCreatorFollows; share-profile button copies URL to clipboard with toast
- CreatorProfileStatRow / CreatorProfileStatItem: formatted stat tiles used on
  both the public profile and detail pages
- DeployedCreatorKeyCard: concise key summary card (status badge, price, invest CTA)
- CreatorProfile types updated (stats.avgMarketCapStroops, stats.averageRating)
- creatorProfile.utils: formatMemberSince helper

## accesslayerorg#1121 – Key freeze status banner & trading block UI
- KeyFreezeBanner component: orange/amber warning aside rendered below the key header
  when creator.isFrozen is true; shows freeze reason, expiry (formatted or
  'indefinite'), and a Contact Admin link; auto-dismisses via setTimeout when
  the expiry timestamp is reached and fires onExpiryReached callback
- CreatorDetailPage: isFrozen / freezeReason / freezeExpiry resolved from API
  response; 30-second polling while key is frozen; isPastFreezeExpiry guard so
  an already-expired freeze is never shown; Buy Key button replaced with
  <UnavailableAction reason="Key trading is frozen"> when isKeyFrozen is true
- course.service.ts: isFrozen, frozen, freezeReason, freezeExpiry,
  freezeExpiresAt fields added to Course interface

## accesslayerorg#1118 – Bundle purchase cart & Add-to-Bundle UI
- useBundleCartStore (Zustand): addItem (idempotent, increments amount if already
  in cart), removeItem, updateAmount (clamped ≥ 1), clearCart, isInCart;
  sessionStorage persistence across page reloads within the session;
  selectBundleTotalCostStroops, selectBundleItemCount,
  selectEstimatedBundlePriceImpact selectors
- BundleCartDrawer: right-sliding fixed drawer (max-w-md) with ScrollArea item
  list, per-item ± quantity controls, remove button, estimated price impact,
  total cost summary, and Submit Bundle → creatorKeysContractService.bundle_buy
  with 5 % slippage guard; success shows truncated tx hash toast; atomic
  failure shows error toast
- BundleCartTrigger: floating FAB (bottom-right) that appears only when cart has
  items; opens the drawer on click
- RootLayout: BundleCartDrawer and BundleCartTrigger mounted at root so they
  persist across navigation
- creatorKeysContractService.bundle_buy: new method accepting array of
  { keyId, amount, maxPriceStroops } items
- CreatorCard: 'Add to bundle' toggle button (Package icon) alongside the
  existing batch-basket button; wired to useBundleCartStore
- CreatorDetailPage: handleAddToBundle handler; 'Add to Bundle' button in the
  key-purchase section; disabled when frozen / paused / deprecated
- TradeDialog: isFrozen prop disables buy/sell tabs with a frozen notice

## accesslayerorg#1119 – Referral dashboard page
- ReferralDashboardPage: full layout with ReferralLinkGenerator,
  ReferralEarningsPanel, and ReferredWalletsTable sections
- referral.service.ts: useReferralDashboard hook connecting all three panels
- ReferralLinkGenerator: copy-to-clipboard referral link with toast; QR code hint
- ReferralEarningsPanel: total rewards, pending claims, claimable amount; claim
  button gated on contract balance > 0
- ReferredWalletsTable: paginated table of referred wallets with tier breakdowns,
  earned amounts, and status badges
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants