Step 8- Power Up Wallet Display + Ignite Gasless Minting

At this stage, your editor might be throwing errors, that's because we’re referencing two components we haven’t summoned into existence yet: WalletDisplay and GaslessMinter. No worries, let’s bring these Magmar modules to life.


WalletDisplay: Visualize Your Digital Assets

Create a new file in your /common folder named:

WalletDisplay.tsx

Paste the following Magmar-powered logic inside:

import { useAuth } from "@common/AuthProvider";
import Loader from "@common/utils/Loader";
import { useEffect, useState } from "react";

interface Nft {
  contract: object;
  tokenId: string;
  tokenType: string;
  title: string;
  description: string;
  media: object;
}

interface Data {
  ownedNfts: Nft[];
  length: number;
}

export default function WalletDisplay() {
  const { user } = useAuth();
  const [ownedNftsArray, setOwnedNftsArray] = useState<Data | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetchUserNfts();
  }, []);

  function truncateDescription(description: string, wordCount: number) {
    const words = description.split(" ");
    if (words.length > wordCount) {
      return `${words.slice(0, wordCount).join(" ")} ...`;
    }
    return description;
  }

  async function fetchUserNfts() {
    setIsLoading(true);
    try {
      const response = await fetch("/api/get-user-nfts/", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ address: user?.scwAddress }),
      });

      const messageResponse = await response.json();
      setOwnedNftsArray(messageResponse.data.ownedNfts);
      setIsLoading(false);
    } catch (error) {
      console.error("Error fetching NFTs:", error);
    }
  }

  return (
    <div>
      {isLoading ? (
        <div className="flex items-center justify-center mt-[-350px]">
          <Loader />
        </div>
      ) : ownedNftsArray && ownedNftsArray.length >= 1 ? (
        <div className="flex flex-col items-center">
          <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 mx-12 mb-6">
            {ownedNftsArray.map((nft, index) => (
              <div
                key={index}
                className="rounded-lg shadow-xl max-w-[250px] max-h-[600px] overflow-hidden"
              >
                <figure>
                  <img
                    src={
                      nft.tokenUri.gateway
                        ? nft.tokenUri.gateway
                        : nft.tokenUri.raw
                    }
                    alt="user nft image"
                    className="w-full max-h-[300px]"
                  />
                </figure>
                <div className="p-4">
                  <h2 className="text-xl font-semibold mb-2">{nft.title}</h2>
                  <p>{truncateDescription(nft.description, 25)}</p>
                </div>
              </div>
            ))}
          </div>
        </div>
      ) : (
        <div className="flex flex-col items-center justify-center mx-8 mt-32 text-black">
          <p>Your Magmar Wallet is ready to ignite, but it holds no NFTs yet. 🔥</p>
          <div className="mt-4">
            Use the <b>&nbsp;Mint an NFT&nbsp;</b> tab to spark your first one!
          </div>
        </div>
      )}
    </div>
  );
}

This component fires a fetch call on mount to check which NFTs the user's Smart Contract Wallet (SCW) owns. If there’s any fire in the vault, you’ll see the blaze of your assets. If not, the minting forge awaits.


GaslessMinter: Mint with No Friction

Time to integrate Magmar’s gasless minting magic. Install the celebratory react-confetti package first:

npm install react-confetti

Then, create the component:

GaslessMinter.tsx

Paste the following:

import { useAuth } from "@common/AuthProvider";
import { useState } from "react";
import Confetti from "react-confetti";

export default function GaslessMinter() {
  const { user } = useAuth();
  const [isLoading, setIsLoading] = useState(false);
  const [hasMinted, setHasMinted] = useState(false);

  async function handleMint() {
    setIsLoading(true);
    const data = {
      userId: user?.userId,
      userScwAddress: user?.scwAddress,
      nameOfFunction: "mint",
    };

    await fetch("/api/mint-nft-user-op/", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });

    setTimeout(() => {}, 10000); // Simulate minting delay
    setIsLoading(false);
    setHasMinted(true);
  }

  return (
    <div className="flex items-center justify-center mt-12">
      {hasMinted && <Confetti />}
      <div className="card lg:card-side shadow-xl w-[70%] mb-16">
        <figure>
          <img
            src="https://github-production-user-asset-6210df.s3.amazonaws.com/83442423/267730896-dd9791c9-00b9-47ff-816d-0d626177909c.png"
            alt="sample nft"
          />
        </figure>
        <div className="card-body text-black">
          <h2 className="card-title text-2xl">🔥 Magmar Test NFT</h2>
          <p className="text-sm">
            You’re minting a test NFT on Sepolia. No gas. No friction. Just fire.  
            This NFT lands directly into your Smart Contract Wallet.
          </p>
          <div className="flex items-center justify-end">
            <div
              className={`alert w-[75%] mr-4 ${
                hasMinted ? "visible" : "hidden"
              }`}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="stroke-current shrink-0 h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth="2"
                  d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
                />
              </svg>
              <div className="flex justify-end text-right">
                <span className="text-white">🔥 NFT minted successfully!</span>
              </div>
            </div>
            <button className="btn btn-primary text-white" onClick={handleMint}>
              <span
                className={`${
                  isLoading ? "loading loading-spinner" : "hidden"
                }`}
              ></span>
              {isLoading ? "Minting..." : hasMinted ? "Mint Again" : "Mint"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

This component handles your minting flow and throws confetti when a user successfully mints their NFT — all on Sepolia and completely gasless.

Last updated