Skip to content

Latest commit

 

History

History
226 lines (184 loc) · 7.54 KB

File metadata and controls

226 lines (184 loc) · 7.54 KB

MyListingsDashboard Implementation - Complete

Task Completion Summary

Successfully implemented a complete seller dashboard for viewing registered IP listings and managing pending swaps. Implementation follows senior development practices with proper error handling, accessibility, and consistent design patterns.

Files Created

1. /frontend/src/hooks/useMyListings.js

Purpose: React hook for fetching seller listings and cross-referencing with pending swaps

Key Features:

  • Fetches all listing IDs owned by seller via ip_registry.list_by_owner()
  • Parallel fetches full listing details for each ID
  • Fetches all swaps for seller via atomic_swap.get_swaps_by_seller()
  • Enriches listings with active_swap property (Pending swaps only)
  • 15-second polling interval with cleanup
  • Proper error handling and loading states

Exports:

export function useMyListings(sellerAddress)
// Returns: { listings, loading, error, refresh }

2. /frontend/src/components/MyListingsDashboard.jsx

Purpose: Dashboard component showing all seller listings with pending swaps

Key Features:

  • Wallet Guard: Displays connection prompt when wallet not connected
  • Two sections:
    1. "Pending Confirmations" - Listings with active pending swaps (highest priority)
    2. "All Listings" - Other listings without active swaps
  • ListingCard Subcomponent:
    • Shows listing ID, IPFS hash (truncated), price
    • Shows active swap details (buyer, amount)
    • Integrates ConfirmSwapForm for swap confirmation
    • "No pending swaps" message for passive listings
  • Loading States:
    • Skeleton screens while fetching
    • Loading spinner on refresh button
    • Error banner for failures
  • Empty State: Message when seller has no listings
  • Accessibility: Full aria-labels and semantic HTML

3. /frontend/src/components/MyListingsDashboard.css

Purpose: Professional styling for dashboard and cards

Styling Includes:

  • Header with refresh button
  • Card-based layout for listings
  • Pending swap badge (orange/warning color)
  • Swap information highlight box
  • Loading skeleton animation
  • Empty state styling
  • Responsive flex layout
  • Hover effects

4. /frontend/src/lib/contractClient.js (Extended) ✅

New Additions:

Constants

const IP_REGISTRY_CONTRACT_ID = import.meta.env.VITE_CONTRACT_IP_REGISTRY;

Helper Functions

// Generic simulator for any contract
async function simulateViewOnContract(contractId, functionName, args)

// Decode Listing struct from ScVal
function decodeListingScVal(scVal, listingId)

Exported Functions

export async function getListingsByOwner(ownerAddress)
// Calls: ip_registry.list_by_owner(address) -> Vec<u64>

export async function getListing(listingId)
// Reads persistent storage for Listing struct
// Returns: { id, owner, ipfs_hash, merkle_root, royalty_bps, royalty_recipient, price_usdc }

export async function getSwapsBySeller(sellerAddress)
// Calls: atomic_swap.get_swaps_by_seller(address) -> Vec<u64>

5. /frontend/index.html (Modified) ✅

Change: Added new React portal container

<div id="listings-dashboard-root"></div>

6. /frontend/src/main.jsx (Modified) ✅

Changes:

  • Imported MyListingsDashboard component
  • Added portal rendering for listings dashboard
  • Maintains shared WalletProvider context

Data Flow Architecture

Flow:
1. User connects wallet
   ↓
2. MyListingsDashboard receives address via useWallet()
   ↓
3. useMyListings hook executes:
   a) getListingsByOwner(address) → listing IDs
   b) getListing(id) for each ID in parallel → full Listing objects
   c) getSwapsBySeller(address) → swap IDs
   d) getSwap(id) for each swap ID in parallel → full Swap objects
   e) Build activeSwapsByListing map (only Pending status)
   f) Enrich listings with active_swap property
   ↓
4. Component renders:
   - Listings with active_swap in "Pending Confirmations" section
   - Other listings in "All Listings" section
   - Each ListingCard shows ConfirmSwapForm for pending swaps
   ↓
5. Seller confirms swap:
   - ConfirmSwapForm submits decryption key
   - confirmSwap() executes transaction
   - onSwapUpdated callback → refresh() called
   - Data refetches automatically

Smart Contract Integration

IP Registry Calls

// Get all listing IDs for owner
ip_registry.list_by_owner(owner: Address) -> Vec<u64>

// Get full listing details
ip_registry.get_listing(listing_id: u64) -> Option<Listing>
  // Returns: { owner, ipfs_hash, merkle_root, royalty_bps, royalty_recipient, price_usdc }

Atomic Swap Calls

// Get all swaps where user is seller
atomic_swap.get_swaps_by_seller(seller: Address) -> Vec<u64>

// Get full swap details
atomic_swap.get_swap(swap_id: u64) -> Option<Swap>
  // Returns: { listing_id, buyer, seller, status, usdc_amount, expires_at, created_at, decryption_key, ... }

Configuration Required

Environment Variables

Add to .env file:

VITE_CONTRACT_IP_REGISTRY=<ip_registry_contract_address>
VITE_CONTRACT_ATOMIC_SWAP=<atomic_swap_contract_address>
VITE_STELLAR_RPC_URL=https://soroban-testnet.stellar.org
VITE_STELLAR_NETWORK=testnet

Error Handling

Contract ID validation - throws meaningful error if env variable missing ✅ Network failures - caught and displayed to user ✅ Empty contract responses - properly handled null returns ✅ Parallel fetch robustness - Promise.allSettled filters failures ✅ User feedback - error banners and loading states

Accessibility Features

✅ Semantic HTML (<section>, <h2>, <h3>) ✅ ARIA labels (aria-label, aria-busy) ✅ Role attributes (role="alert") ✅ Keyboard accessible buttons ✅ Color contrast compliant styling ✅ Hidden decorative elements (aria-hidden="true")

Best Practices Applied

Consistency - Matches MySwapsDashboard patterns exactly ✅ Separation of Concerns - Hook/Component/CSS properly separated ✅ Error Boundaries - User-facing error messages ✅ Loading States - Skeletal loading, spinner, empty states ✅ Performance - Parallel data fetching, 15s polling ✅ Type Safety - JSDoc comments for function signatures ✅ Memory Management - Proper cleanup (clearInterval in useEffect) ✅ Data Normalization - Consistent object structure from decoders ✅ DRY Principle - Reused ConfirmSwapForm component ✅ Portal Rendering - Proper DOM injection for React

Testing Recommendations

  1. Unit Tests

    • Test useMyListings with mock contract calls
    • Test ListingCard rendering with various states
  2. Integration Tests

    • Test wallet connection flow
    • Test listing fetch and display
    • Test pending swap highlighting
    • Test confirm swap integration
  3. Manual Testing

    • Register test listings via ip_registry
    • Create pending swaps via atomic_swap
    • Connect wallet and verify listings display
    • Confirm swap and verify refresh

Future Enhancements

  • Pagination for sellers with many listings
  • Search/filter functionality
  • Sort by price, recent, etc.
  • Listing deregistration UI
  • Swap dispute resolution UI
  • Bulk operations

Notes

  • IPFS hash displayed truncated to 16 chars (show full on hover via title attribute)
  • Pending swaps shown with orange badge for visibility
  • Active swap section appears first to prioritize seller attention
  • All swaps filtered to only show Pending status (Completed/Cancelled excluded)
  • Price shows "No minimum" when price_usdc is 0
  • Wallet address truncated to 10 chars in swap details for readability