Repository navigation
feat: creator profile page, key freeze banner, bundle cart, referral dashboard (#1118-#1121) - #1136
Closed
therealjhay wants to merge 1 commit into
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements four linked feature issues across the AccessLayer client, all branched off
devwith 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;sessionStoragepersistence so the cart survives a page refresh within the session. Exported selectors:selectBundleTotalCostStroops,selectBundleItemCount,selectEstimatedBundlePriceImpact.BundleCartDrawer: right-sliding fixed drawer (max-w-md) with aScrollAreaitem list, per-item ± quantity controls, remove button, estimated price impact, total-cost summary, and a Submit Bundle button that callscreatorKeysContractService.bundle_buywith 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+BundleCartTriggermounted 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 touseBundleCartStore.CreatorDetailPage:handleAddToBundlehandler + "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 adata-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 oncontractBalance > 0.ReferredWalletsTable: paginated table of referred wallets with tier breakdowns, earned amounts per wallet, and status badges.referral.service.ts:useReferralDashboardReact-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 ofDeployedCreatorKeyCardcomponents. Dedicated 404 state for unknown addresses.CreatorPublicProfileHeader: Follow/Unfollow button with optimistic update viauseCreatorFollows; 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.CreatorPublicProfile.stats.avgMarketCapStroops,averageRating.creatorProfile.utils:formatMemberSincehelper.Closes #1121 · Key Freeze Status Banner & Trading Block UI
KeyFreezeBanner: amber warning<aside role="alert">rendered below the key header whencreator.isFrozenis true. Shows freeze reason, expiry (formatted viaformatAbsoluteDateTimeor'indefinite'), and a Contact Admin link. Auto-dismisses viasetTimeoutwhen the expiry timestamp is reached and fires anonExpiryReachedcallback.CreatorDetailPage:isFrozen/freezeReason/freezeExpiryresolved from API response fields (isFrozen,frozen,freezeReason,freezeExpiry,freezeExpiresAt); 30-second polling interval while the key is frozen viarefetch;isPastFreezeExpiryguard prevents showing an already-expired freeze; Buy Key button replaced with<UnavailableAction reason="Key trading is frozen">whenisKeyFrozenis true.course.service.ts:isFrozen,frozen,freezeReason,freezeExpiry,freezeExpiresAtfields added to theCourseinterface.Files Changed
src/hooks/useBundleCartStore.tssrc/components/common/BundleCartDrawer.tsxsrc/components/common/BundleCartTrigger.tsxsrc/components/common/KeyFreezeBanner.tsxsrc/components/common/CreatorCard.tsxsrc/components/common/RootLayout.tsxsrc/components/common/TradeDialog.tsxisFrozenprop disables trade tabssrc/components/common/CreatorPublicProfileHeader.tsxsrc/components/common/CreatorProfileStatRow.tsxsrc/components/common/CreatorProfileStatItem.tsxsrc/components/common/DeployedCreatorKeyCard.tsxsrc/pages/CreatorPublicProfilePage.tsxsrc/pages/CreatorDetailPage.tsxsrc/services/course.service.tssrc/services/creatorKeysContract.service.tsbundle_buymethodsrc/services/creatorProfile.service.tssrc/types/creatorProfile.tsavgMarketCapStroops,averageRatingsrc/utils/creatorProfile.utils.tsformatMemberSinceCloses #1118 Closes #1119 Closes #1120 Closes #1121