> ## Documentation Index
> Fetch the complete documentation index at: https://web3docs.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Components

> Create the UI components for the NFT minting dApp

# Build Components

Now let's build the UI components that use our hooks.

## 1. USDC Section

Create `src/components/usdc-section.tsx`:

```typescript theme={null}
import { useCurrentAccount } from "@mysten/dapp-kit-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { useUsdcBalance } from "@/hooks/use-usdc-balance";
import { useMintUsdc } from "@/hooks/use-mint-usdc";
import { formatUSDC, USDC_MINT_AMOUNT } from "@/lib/contracts";
import { Loader2, Plus } from "lucide-react";

export function UsdcSection() {
  const account = useCurrentAccount();
  const { data } = useUsdcBalance();
  const { mint, isPending } = useMintUsdc();

  if (!account) return null;

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <img
            src="https://cryptologos.cc/logos/usd-coin-usdc-logo.png"
            alt="USDC"
            className="w-5 h-5"
          />
          USDC
        </CardTitle>
      </CardHeader>
      <CardContent className="space-y-3">
        <div className="flex justify-between items-center p-3 bg-muted rounded-lg">
          <span className="text-sm text-muted-foreground">Balance</span>
          <span className="text-lg font-bold">
            {formatUSDC(data?.balance ?? 0n)}
          </span>
        </div>

        <Button onClick={mint} disabled={isPending} className="w-full">
          {isPending ? (
            <Loader2 className="w-4 h-4 animate-spin" />
          ) : (
            <>
              <Plus className="w-4 h-4 mr-1" />
              Mint {USDC_MINT_AMOUNT}
            </>
          )}
        </Button>
      </CardContent>
    </Card>
  );
}
```

## 2. NFT Mint Section

Create `src/components/nft-mint-section.tsx`:

```typescript theme={null}
import { useCurrentAccount } from "@mysten/dapp-kit-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { useUsdcBalance } from "@/hooks/use-usdc-balance";
import { useMintNft } from "@/hooks/use-mint-nft";
import { formatUSDC, NFT_MINT_PRICE } from "@/lib/contracts";
import { Sparkles, Loader2 } from "lucide-react";

export function NftMintSection() {
  const account = useCurrentAccount();
  const { data: usdcData } = useUsdcBalance();
  const { mint, isPending } = useMintNft();

  if (!account) return null;

  const hasEnoughBalance = (usdcData?.balance ?? 0n) >= NFT_MINT_PRICE;

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <Sparkles className="w-4 h-4" />
          Mint NFT
        </CardTitle>
      </CardHeader>
      <CardContent className="space-y-3">
        <div className="relative rounded-lg overflow-hidden">
          <img
            src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh1cpBR8d2D2P55Z2kQzlr6uGuhRfWzEnoVQ&s"
            alt="PSIL NFT"
            className="w-full aspect-square object-cover"
          />
          <div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
          <div className="absolute bottom-0 p-3 text-white">
            <p className="font-bold">Pria Solo Itu Lagi</p>
            <p className="text-xs opacity-80">SAYA AKAN PULANG KE SOLO</p>
          </div>
        </div>

        <div className="flex justify-between items-center p-3 bg-muted rounded-lg">
          <span className="text-sm text-muted-foreground">Price</span>
          <span className="font-bold">{formatUSDC(NFT_MINT_PRICE)} USDC</span>
        </div>

        {!hasEnoughBalance && (
          <p className="text-sm text-destructive">Insufficient USDC balance</p>
        )}

        <Button
          onClick={mint}
          disabled={isPending || !hasEnoughBalance}
          className="w-full"
        >
          {isPending ? (
            <>
              <Loader2 className="w-4 h-4 mr-1 animate-spin" />
              Minting...
            </>
          ) : (
            <>
              <Sparkles className="w-4 h-4 mr-1" />
              Mint
            </>
          )}
        </Button>
      </CardContent>
    </Card>
  );
}
```

## 3. NFT Gallery

Create `src/components/nft-gallery.tsx`:

```typescript theme={null}
import { useCurrentAccount } from "@mysten/dapp-kit-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { useOwnedNfts } from "@/hooks/use-owned-nfts";
import { ImageIcon } from "lucide-react";

export function NftGallery() {
  const account = useCurrentAccount();
  const { data: nfts } = useOwnedNfts();

  if (!account) return null;

  const count = nfts?.length ?? 0;

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <ImageIcon className="w-4 h-4" />
          Your NFTs
          {count > 0 && (
            <span className="ml-auto text-sm font-normal text-muted-foreground">
              {count}
            </span>
          )}
        </CardTitle>
      </CardHeader>
      <CardContent>
        {count > 0 ? (
          <div className="grid grid-cols-2 gap-2">
            {nfts!.map((nft) => (
              <div
                key={nft.id}
                className="relative rounded-lg overflow-hidden border"
              >
                <img
                  src={nft.url}
                  alt={nft.name}
                  className="w-full aspect-square object-cover"
                />
                <span className="absolute top-1 right-1 bg-black/60 text-white text-xs px-1.5 py-0.5 rounded">
                  #{nft.edition}
                </span>
              </div>
            ))}
          </div>
        ) : (
          <p className="text-center py-6 text-sm text-muted-foreground">
            No NFTs yet
          </p>
        )}
      </CardContent>
    </Card>
  );
}
```

## 4. Update App

Update `src/app.tsx` to use all components:

```typescript theme={null}
import { ConnectButton, useCurrentAccount } from "@mysten/dapp-kit-react";
import { UsdcSection } from "./components/usdc-section";
import { NftMintSection } from "./components/nft-mint-section";
import { NftGallery } from "./components/nft-gallery";

export function App() {
  const account = useCurrentAccount();

  return (
    <div className="min-h-screen bg-background bg-grid">
      <header className="sticky top-0 z-50 border-b bg-background/80 backdrop-blur">
        <div className="max-w-4xl mx-auto px-4 py-3 flex items-center justify-between">
          <h1 className="font-bold">Sui Workshop</h1>
          <ConnectButton />
        </div>
      </header>

      <main className="max-w-4xl mx-auto px-4 py-6">
        {account ? (
          <div className="grid gap-4 md:grid-cols-2">
            <div className="space-y-4">
              <UsdcSection />
              <NftGallery />
            </div>
            <NftMintSection />
          </div>
        ) : (
          <div className="text-center py-20">
            <h2 className="text-xl font-bold mb-2">Welcome</h2>
            <p className="text-muted-foreground mb-4">Connect wallet to start</p>
            <ConnectButton />
          </div>
        )}
      </main>
    </div>
  );
}
```

## Install Lucide Icons

```bash theme={null}
npm install lucide-react
```

## Final Project Structure

```
src/
├── app.tsx
├── main.tsx
├── index.css
├── components/
│   ├── providers.tsx
│   ├── usdc-section.tsx
│   ├── nft-mint-section.tsx
│   ├── nft-gallery.tsx
│   └── ui/
├── hooks/
│   ├── use-usdc-balance.ts
│   ├── use-mint-usdc.ts
│   ├── use-owned-nfts.ts
│   └── use-mint-nft.ts
└── lib/
    ├── contracts.ts
    ├── dapp-kit.ts
    └── utils.ts
```

## Test the App

1. Run `npm run dev`
2. Connect your wallet
3. Mint some USDC tokens
4. Mint an NFT with USDC
5. See your NFT in the gallery

Congratulations! You've built a complete NFT minting dApp on Sui!
