DEV Community

Daniel Ioni
Daniel Ioni

Posted on

🎨 How I Built the MyZubster NFT Dashboard – A React + TypeScript Journey

🎨 How I Built the MyZubster NFT Dashboard – A React + TypeScript Journey

After building the backend Rust template for Tari NFTs and dockerizing it, the next challenge was to create a user-friendly interface. I wanted a dashboard that anyone could use, even without blockchain experience.

The result is MyZubster NFT Dashboard – a complete React + TypeScript frontend for managing NFT collections on Tari.

In this article, I'll walk you through the architecture, design decisions, and key components that make the dashboard work.


🧠 Why React + TypeScript?

I chose React 19 with TypeScript for several reasons:

  • Type Safety: TypeScript catches errors at compile time, reducing runtime bugs
  • Component Reusability: React's component model makes it easy to build and maintain complex UIs
  • Rich Ecosystem: Vite, ESLint, and a huge library of community packages
  • Performance: Vite's fast HMR makes development a joy

📁 Architecture Overview

The dashboard follows a clean component-based architecture:
src/
├── components/
│ ├── ConnectWallet.tsx # Wallet connection UI
│ ├── CreateCollection.tsx # Create new NFT collection
│ ├── MintNFT.tsx # Mint NFTs
│ └── NFTGallery.tsx # Display NFT gallery
├── hooks/
│ └── useTariWallet.ts # Wallet connection logic
├── App.tsx # Main dashboard
└── App.css # Global styles
text


🔐 ConnectWallet – The Gateway

The wallet connection component is the first thing users see:


tsx
const ConnectWallet: React.FC = () => {
  const { isConnected, isLoading, connectWallet, disconnectWallet } = useTariWallet();

  return (
    <div className="card">
      <h3>🔐 Connessione Wallet</h3>
      {!isConnected ? (
        <button onClick={connectWallet} disabled={isLoading}>
          {isLoading ? '⏳ Connessione in corso...' : '🔗 Connetti Wallet Tari'}
        </button>
      ) : (
        <div>
          <p className="status-connected">✅ Wallet connesso con successo!</p>
          <button className="danger" onClick={disconnectWallet}>
            🔌 Disconnetti
          </button>
        </div>
      )}
    </div>
  );
};

Key Features:

    Loading state to prevent double-clicks

    Disabled state when wallet is not connected

    Clear visual feedback for connection status

🏗️ CreateCollection – Building NFT Collections

This component calls the new() function on the Tari template:
tsx

const handleCreateCollection = async () => {
  if (!isConnected) {
    alert('⚠️ Devi connettere il wallet prima di creare una collezione!');
    return;
  }

  // TODO: Replace with real wallet integration
  await new Promise(resolve => setTimeout(resolve, 2000));
  setResult({
    success: true,
    message: `✅ Collezione "${name}" (${symbol}) creata con successo!`,
  });
};
UX Flow:

    User enters collection name and symbol

    Validates that the wallet is connected

    Simulates the transaction (ready for real integration)

    Shows success/error feedback

🎨 MintNFT – Creating Digital Assets

Minting NFTs is the core feature. Users need:

    Collection address (where to mint)

    NFT ID (unique identifier)

    Immutable data (e.g., image URL)

    Mutable data (e.g., status)

tsx

const handleMintNFT = async () => {
  if (!componentAddress || !nftId || !immutableData) {
    alert('⚠️ Compila tutti i campi obbligatori!');
    return;
  }

  // Simulate minting
  await new Promise(resolve => setTimeout(resolve, 2000));
  setResult({ success: true, message: `✅ NFT "${nftId}" mintato con successo!` });
};

🖼️ NFTGallery – Showcasing NFTs

The gallery fetches and displays NFTs from a collection:
tsx

const NFTGallery: React.FC = () => {
  const [nfts, setNfts] = useState<NFT[]>([]);
  const [componentAddress, setComponentAddress] = useState('');

  const fetchNFTs = async () => {
    // TODO: Replace with real blockchain data
    const mockNFTs: NFT[] = [
      { id: 'nft-001', immutableData: 'https://example.com/nft1.png', mutableData: 'Disponibile' },
      { id: 'nft-002', immutableData: 'https://example.com/nft2.png', mutableData: 'In vendita' },
    ];
    setNfts(mockNFTs);
  };

  return (
    <div className="card">
      <h3>🖼️ Galleria NFT</h3>
      <input
        placeholder="Indirizzo della collezione"
        value={componentAddress}
        onChange={(e) => setComponentAddress(e.target.value)}
      />
      <button onClick={fetchNFTs}>🔍 Cerca NFT</button>
      <div className="grid">
        {nfts.map((nft) => (
          <NFTCard key={nft.id} nft={nft} />
        ))}
      </div>
    </div>
  );
};

🎨 Design System – Dark Mode GitHub Style

I opted for a dark theme inspired by GitHub:

    Background: #0d1117

    Cards: #161b22 with #30363d borders

    Accent: #58a6ff (blue) and #3fb950 (green)

    Typography: System font stack

css

body {
  background: #0d1117;
  color: #e6edf3;
}

.card {
  background: #161b22;
  border: 1px solid #30363d;
  border-radius: 12px;
  padding: 1.5rem;
}

button {
  background: #238636;
  color: white;
  border: none;
  padding: 0.6rem 1.2rem;
  border-radius: 8px;
}

🔗 The Missing Piece: Real Wallet Integration

Currently, the dashboard uses simulated data. The next step is integrating tari.js for real wallet connection:
typescript

import { WalletDaemonTariSigner } from '@tari-project/tarijs';

const connectWallet = async () => {
  const walletSigner = await WalletDaemonTariSigner.buildFetchSigner({
    serverUrl: 'http://localhost:18103',
  });
  // ... handle connection
};Running the Dashboard
bash

git clone https://github.com/DanielIoni-creator/MyZubster.git
cd MyZubster/myzubster-frontend
npm install
npm run dev

The dashboard will be available at http://localhost:5173.
🚀 What's Next?

    Real Wallet Integration – Connect to Tari wallet via tari.js

    Deploy on VPS – Make the dashboard publicly accessible

    Advanced Features – Royalty, whitelist, limited minting

    Mobile App – React Native for iOS and Android

🔗 Resources

    GitHub: https://github.com/DanielIoni-creator/MyZubster

    Docker Hub: https://hub.docker.com/repository/docker/myzubster/tari-nft-template

    Backend Template: https://dev.to/danielioni/i-built-an-nft-template-for-tari-monero-sidechain-heres-how-33k

    VPS Deployment Guide: https://dev.to/danielioni/how-i-deployed-myzubster-on-a-vps-a-complete-guide-51ok

📬 Connect with Me

    📖 Dev.to: https://dev.to/danielioni

    🐦 Twitter: https://x.com/myzubster

    💼 LinkedIn: https://linkedin.com/in/daniel-ioni-62b2b9423/

    🐙 GitHub: https://github.com/DanielIoni-creator

Built with ❤️ for the Monero and Tari community
If you're a React or blockchain developer, I'd love to hear your feedback!
Enter fullscreen mode Exit fullscreen mode

Top comments (0)