Contoh Autentikasi Dasar

Alur autentikasi sederhana dengan penanganan kesalahan dan status pemuatan.
import { 
  B3Provider, 
  SignInWithB3, 
  useB3 
} from "@b3dotfun/sdk/global-account/react";

function AuthExample() {
  return (
    <B3Provider environment="production">
      <AuthComponent />
    </B3Provider>
  );
}

function AuthComponent() {
  const { account, isAuthenticated, isLoading, signOut } = useB3();
  const [authError, setAuthError] = useState<string | null>(null);

  if (isLoading) {
    return (
      <div className="loading-container">
        <div className="spinner" />
        <p>Memuat akun Anda...</p>
      </div>
    );
  }

  return (
    <div className="auth-container">
      {isAuthenticated ? (
        <div className="user-profile">
          <img 
            src={account?.avatarUrl} 
            alt="Profil" 
            className="avatar"
          />
          <h2>Selamat datang, {account?.displayName}!</h2>
          <p>Email: {account?.email}</p>
          <button onClick={signOut} className="sign-out-btn">
            Keluar
          </button>
        </div>
      ) : (
        <div className="sign-in-container">
          <h2>Masuk ke B3</h2>
          
          <SignInWithB3
            provider={{ strategy: "google" }}
            partnerId="your-partner-id"
            onLoginSuccess={(globalAccount) => {
              setAuthError(null);
              console.log("Autentikasi berhasil:", globalAccount);
            }}
            onLoginError={(error) => {
              setAuthError(error.message);
              console.error("Autentikasi gagal:", error);
            }}
          />

          <SignInWithB3
            provider={{ strategy: "discord" }}
            partnerId="your-partner-id"
            onLoginSuccess={(globalAccount) => {
              setAuthError(null);
              console.log("Autentikasi Discord berhasil:", globalAccount);
            }}
            onLoginError={(error) => {
              setAuthError(error.message);
            }}
          />

          {authError && (
            <div className="error-message">
              <p>Autentikasi gagal: {authError}</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export default AuthExample;

Contoh Aplikasi Game

Contoh lengkap untuk aplikasi game dengan kunci sesi dan izin.
import {
  B3Provider,
  SignInWithB3,
  RequestPermissionsButton,
  useB3,
  usePermissions,
  useAccountWallet
} from "@b3dotfun/sdk/global-account/react";

const b3Chain = {
  id: 8333,
  name: "B3",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpc: "https://mainnet-rpc.b3.fun",
};

const gameContracts = [
  "0x9c275ff1634519E9B5449ec79cd939B5F900564d", // Kontrak game
  "0x...", // Pasar NFT
  "0x...", // Kontrak token
];

function GameApp() {
  return (
    <B3Provider environment="production">
      <GameContainer />
    </B3Provider>
  );
}

function GameContainer() {
  const { account, isAuthenticated } = useB3();
  const { hasPermissions, isExpired } = usePermissions();
  const { wallet, isConnected } = useAccountWallet();

  const isGameReady = isAuthenticated && hasPermissions && !isExpired && isConnected;

  return (
    <div className="game-container">
      <header className="game-header">
        <h1>🎮 Game B3 Epik</h1>
        {isAuthenticated && (
          <div className="user-info">
            <img src={account?.avatarUrl} alt="Avatar" className="small-avatar" />
            <span>{account?.displayName}</span>
          </div>
        )}
      </header>

      <main className="game-content">
        {!isAuthenticated ? (
          <AuthenticationStep />
        ) : !isConnected ? (
          <WalletConnectionStep />
        ) : !hasPermissions || isExpired ? (
          <PermissionStep />
        ) : (
          <GameReadyState />
        )}
      </main>
    </div>
  );
}

function AuthenticationStep() {
  return (
    <div className="setup-step">
      <h2>🔐 Masuk</h2>
      <p>Hubungkan Akun Global B3 Anda untuk mulai bermain</p>
      
      <div className="auth-options">
        <SignInWithB3
          provider={{ strategy: "google" }}
          partnerId="epic-game-studio"
          onLoginSuccess={(account) => {
            console.log("Selamat datang di game:", account.displayName);
          }}
        />
        
        <SignInWithB3
          provider={{ strategy: "discord" }}
          partnerId="epic-game-studio"
          onLoginSuccess={(account) => {
            console.log("Pemain Discord bergabung:", account.displayName);
          }}
        />
      </div>
    </div>
  );
}

function WalletConnectionStep() {
  const { connect } = useAccountWallet();

  return (
    <div className="setup-step">
      <h2>👛 Hubungkan Dompet</h2>
      <p>Hubungkan dompet Anda untuk berinteraksi dengan game</p>
      <button onClick={connect} className="connect-wallet-btn">
        Hubungkan Dompet
      </button>
    </div>
  );
}

function PermissionStep() {
  const gamePermissions = {
    approvedTargets: gameContracts,
    startDate: new Date(),
    endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 hari
    nativeTokenLimitPerTransaction: 0.001, // Batas ETH kecil untuk gas
  };

  return (
    <div className="setup-step">
      <h2>🛡️ Berikan Izin Game</h2>
      <p>Izinkan game untuk melakukan aksi atas nama Anda</p>
      
      <div className="permission-details">
        <h3>Ini akan mengizinkan game untuk:</h3>
        <ul>
          <li>✅ Berinteraksi dengan kontrak game</li>
          <li>✅ Berdagang NFT atas nama Anda</li>
          <li>✅ Menghabiskan hingga 0.001 ETH per transaksi</li>
          <li>✅ Berlaku selama 7 hari</li>
        </ul>
      </div>

      <RequestPermissionsButton
        chain={b3Chain}
        sessionKeyAddress="0x..." // Alamat kunci sesi Anda
        permissions={gamePermissions}
        onSuccess={() => {
          console.log("Izin game diberikan! Memulai game...");
        }}
        onError={(error) => {
          console.error("Pemberian izin gagal:", error);
        }}
      />
    </div>
  );
}

function GameReadyState() {
  const { account } = useB3();
  const { wallet } = useAccountWallet();
  
  return (
    <div className="game-ready">
      <h2>🎯 Game Siap!</h2>
      <div className="player-stats">
        <div className="stat">
          <label>Pemain:</label>
          <span>{account?.displayName}</span>
        </div>
        <div className="stat">
          <label>Dompet:</label>
          <span>{wallet?.address?.substring(0, 6)}...{wallet?.address?.substring(-4)}</span>
        </div>
        <div className="stat">
          <label>Saldo:</label>
          <span>{wallet?.balance} ETH</span>
        </div>
      </div>
      
      <div className="game-actions">
        <button className="play-btn">Mulai Bermain</button>
        <button className="inventory-btn">Lihat Inventaris</button>
        <button className="marketplace-btn">Pasar</button>
      </div>
    </div>
  );
}

export default GameApp;

Contoh Aplikasi E-commerce

Contoh yang menunjukkan integrasi Akun Global B3 dalam konteks e-commerce.
import {
  B3Provider,
  SignInWithB3,
  useB3,
  useAccountAssets
} from "@b3dotfun/sdk/global-account/react";

function EcommerceApp() {
  return (
    <B3Provider environment="production">
      <ShopContainer />
    </B3Provider>
  );
}

function ShopContainer() {
  const { isAuthenticated } = useB3();

  return (
    <div className="shop-container">
      <header className="shop-header">
        <h1>🛍️ Pasar NFT B3</h1>
        <UserSection />
      </header>

      <main>
        {isAuthenticated ? (
          <AuthenticatedShop />
        ) : (
          <GuestShop />
        )}
      </main>
    </div>
  );
}

function UserSection() {
  const { account, isAuthenticated, signOut } = useB3();

  return (
    <div className="user-section">
      {isAuthenticated ? (
        <div className="user-menu">
          <img src={account?.avatarUrl} alt="Profil" className="avatar" />
          <div className="dropdown">
            <span>{account?.displayName}</span>
            <div className="dropdown-content">
              <button>Koleksi Saya</button>
              <button>Riwayat Pembelian</button>
              <button onClick={signOut}>Keluar</button>
            </div>
          </div>
        </div>
      ) : (
        <div className="auth-buttons">
          <SignInWithB3
            provider={{ strategy: "google" }}
            partnerId="nft-marketplace"
            onLoginSuccess={(account) => {
              console.log("Selamat datang di pasar:", account.displayName);
            }}
          />
        </div>
      )}
    </div>
  );
}

function AuthenticatedShop() {
  const { assets } = useAccountAssets();

  return (
    <div className="authenticated-shop">
      <section className="user-collection">
        <h2>Koleksi Anda</h2>
        <div className="asset-grid">
          {assets?.map((asset) => (
            <div key={asset.id} className="asset-card">
              <img src={asset.imageUrl} alt={asset.name} />
              <h3>{asset.name}</h3>
              <p className="price">{asset.value} {asset.currency}</p>
            </div>
          ))}
        </div>
      </section>

      <section className="marketplace">
        <h2>Pasar</h2>
        <MarketplaceGrid />
      </section>
    </div>
  );
}

function GuestShop() {
  return (
    <div className="guest-shop">
      <section className="hero">
        <h2>Temukan NFT Luar Biasa</h2>
        <p>Masuk untuk mulai mengumpulkan dan berdagang</p>
        
        <SignInWithB3
          provider={{ strategy: "google" }}
          partnerId="nft-marketplace"
          onLoginSuccess={() => {
            console.log("Pengguna bergabung dengan pasar!");
          }}
        />
      </section>

      <section className="featured">
        <h2>Koleksi Unggulan</h2>
        <MarketplaceGrid />
      </section>
    </div>
  );
}

function MarketplaceGrid() {
  // Barang pasar tiruan
  const items = [
    { id: 1, name: "NFT Keren #1", price: "0.1 ETH", image: "/nft1.jpg" },
    { id: 2, name: "Barang Langka #42", price: "0.5 ETH", image: "/nft2.jpg" },
    // ... lebih banyak item
  ];

  return (
    <div className="marketplace-grid">
      {items.map((item) => (
        <div key={item.id} className="marketplace-item">
          <img src={item.image} alt={item.name} />
          <h3>{item.name}</h3>
          <p className="price">{item.price}</p>
          <button className="buy-btn">Beli Sekarang</button>
        </div>
      ))}
    </div>
  );
}

export default EcommerceApp;

Contoh React Native

Contoh untuk aplikasi React Native.
// App.tsx (React Native)
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { B3Provider, useB3 } from '@b3dotfun/sdk/global-account/react';

function App() {
  return (
    <B3Provider environment="production">
      <MainScreen />
    </B3Provider>
  );
}

function MainScreen() {
  const { account, isAuthenticated, isLoading } = useB3();

  if (isLoading) {
    return (
      <View style={styles.container}>
        <Text>Memuat...</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      {isAuthenticated ? (
        <AuthenticatedView account={account} />
      ) : (
        <SignInView />
      )}
    </View>
  );
}

function SignInView() {
  return (
    <View style={styles.signInContainer}>
      <Text style={styles.title}>Selamat Datang di B3 Mobile</Text>
      
      {/* Implementasi React Native akan menggunakan alur otentikasi asli */}
      <TouchableOpacity style={styles.signInButton}>
        <Text style={styles.buttonText}>Masuk dengan Google</Text>
      </TouchableOpacity>
      
      <TouchableOpacity style={styles.signInButton}>
        <Text style={styles.buttonText}>Masuk dengan Discord</Text>
      </TouchableOpacity>
    </View>
  );
}

function AuthenticatedView({ account }) {
  const { signOut } = useB3();

  return (
    <View style={styles.authenticatedContainer}>
      <Text style={styles.welcomeText}>
        Selamat datang, {account?.displayName}!
      </Text>
      
      <TouchableOpacity 
        style={styles.signOutButton}
        onPress={signOut}
      >
        <Text style={styles.buttonText}>Keluar</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
  },
  signInContainer: {
    padding: 20,
    alignItems: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 30,
  },
  signInButton: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 10,
    marginVertical: 10,
    minWidth: 200,
  },
  signOutButton: {
    backgroundColor: '#FF3B30',
    padding: 15,
    borderRadius: 10,
    marginTop: 20,
  },
  buttonText: {
    color: 'white',
    textAlign: 'center',
    fontSize: 16,
    fontWeight: '600',
  },
  authenticatedContainer: {
    alignItems: 'center',
  },
  welcomeText: {
    fontSize: 20,
    marginBottom: 20,
  },
});

export default App;

Contoh Router Aplikasi Next.js

Contoh untuk Router Aplikasi Next.js 13+.
// app/layout.tsx
import { B3Provider } from '@b3dotfun/sdk/global-account/react';
import '@b3dotfun/sdk/index.css';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <B3Provider environment="production">
          {children}
        </B3Provider>
      </body>
    </html>
  );
}

// app/page.tsx
'use client';

import { useB3 } from '@b3dotfun/sdk/global-account/react';
import AuthComponent from './components/AuthComponent';
import Dashboard from './components/Dashboard';

export default function HomePage() {
  const { isAuthenticated, isLoading } = useB3();

  if (isLoading) {
    return <div>Memuat...</div>;
  }

  return (
    <main>
      {isAuthenticated ? <Dashboard /> : <AuthComponent />}
    </main>
  );
}

// app/components/AuthComponent.tsx
'use client';

import { SignInWithB3 } from '@b3dotfun/sdk/global-account/react';

export default function AuthComponent() {
  return (
    <div className="auth-container">
      <h1>Selamat Datang di Aplikasi B3</h1>
      
      <SignInWithB3
        provider={{ strategy: "google" }}
        partnerId="nextjs-app"
        onLoginSuccess={(account) => {
          console.log("Sukses autentikasi Next.js:", account);
        }}
      />
    </div>
  );
}

Contoh Hook Kustom Lanjutan

Hook kustom yang menggabungkan beberapa fitur B3:
import { 
  useB3, 
  usePermissions, 
  useAccountWallet,
  useAccountAssets 
} from "@b3dotfun/sdk/global-account/react";

function useB3GameState() {
  const { account, isAuthenticated } = useB3();
  const { hasPermissions, isExpired, permissions } = usePermissions();
  const { wallet, isConnected } = useAccountWallet();
  const { assets } = useAccountAssets();

  // Hitung kesiapan game
  const isGameReady = isAuthenticated && hasPermissions && !isExpired && isConnected;
  
  // Dapatkan aset khusus game (NFT, token)
  const gameAssets = assets?.filter(asset => 
    asset.contractAddress && 
    permissions?.approvedTargets.includes(asset.contractAddress)
  ) || [];

  // Hitung total nilai game
  const totalGameValue = gameAssets.reduce((sum, asset) => sum + asset.value, 0);

  // Objek status game
  const gameState = {
    player: {
      id: account?.id,
      name: account?.displayName,
      avatar: account?.avatarUrl,
      email: account?.email,
    },
    wallet: {
      address: wallet?.address,
      balance: wallet?.balance,
      chainId: wallet?.chainId,
    },
    permissions: {
      active: hasPermissions && !isExpired,
      expires: permissions?.endDate,
      contracts: permissions?.approvedTargets || [],