Examples
Real-world examples demonstrating common use cases and patterns with Midnight Auth.
Sign a Message
Use the signData function to cryptographically sign messages with the connected wallet.
import { useMidnightWallet } from '@uppzen/midnight-auth'
import { useState } from 'react'
export default function SignMessage() {
const { address, signData } = useMidnightWallet()
const [signature, setSignature] = useState<string>('')
const [error, setError] = useState<string>('')
const handleSign = async () => {
if (!address || !signData) return
try {
setError('')
const result = await signData(address, 'Hello Midnight Network!')
setSignature(result.signature)
console.log('Signature:', result.signature)
console.log('Key:', result.key)
} catch (err) {
setError('Failed to sign message')
console.error('Failed to sign:', err)
}
}
return (
<div>
<button onClick={handleSign} disabled={!address}>
Sign Message
</button>
{signature && (
<div>
<p>Signature:</p>
<code>{signature}</code>
</div>
)}
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
)
}
Submit a Transaction
Submit transactions to the Midnight Network using the submitTransaction function.
import { useMidnightWallet } from '@uppzen/midnight-auth'
import { useState } from 'react'
export default function SendTransaction() {
const { submitTransaction, isConnected } = useMidnightWallet()
const [txHash, setTxHash] = useState<string>('')
const [loading, setLoading] = useState(false)
const handleSend = async () => {
if (!isConnected || !submitTransaction) return
setLoading(true)
try {
const tx = {
// Your transaction object
to: '0x...',
value: '1000000000000000000'
}
const result = await submitTransaction(tx)
if (result.success) {
setTxHash(result.txHash)
console.log('Transaction hash:', result.txHash)
}
} catch (error) {
console.error('Failed to submit:', error)
} finally {
setLoading(false)
}
}
return (
<div>
<button
onClick={handleSend}
disabled={!isConnected || loading}
>
{loading ? 'Sending...' : 'Send Transaction'}
</button>
{txHash && (
<div>
<p>Transaction Hash:</p>
<code>{txHash}</code>
</div>
)}
</div>
)
}
Protected Dashboard
Create protected pages that require wallet connection before rendering content.
import { ProtectedRoute, useMidnightWallet } from '@uppzen/midnight-auth'
export default function Dashboard() {
return (
<ProtectedRoute
fallback={
<div className="text-center p-8">
<h2>Please connect your wallet</h2>
<p>You need to connect your Midnight wallet to access this page.</p>
</div>
}
>
<DashboardContent />
</ProtectedRoute>
)
}
function DashboardContent() {
const { address, balances } = useMidnightWallet()
return (
<div>
<h1>Welcome {address}!</h1>
{balances && (
<div>
<h2>Your Balances</h2>
<p>Shielded: {balances.shielded}</p>
<p>Unshielded: {balances.unshielded}</p>
<p>Total: {balances.total}</p>
</div>
)}
</div>
)
}
Session Management
Track and manage user sessions with automatic expiration handling.
import { useMidnightSession } from '@uppzen/midnight-auth'
import { useEffect, useState } from 'react'
export default function SessionInfo() {
const { session, isExpired, timeRemaining, refreshSession } = useMidnightSession()
const [formattedTime, setFormattedTime] = useState('')
useEffect(() => {
const formatTime = (ms: number) => {
const hours = Math.floor(ms / (1000 * 60 * 60))
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60))
return `${hours}h ${minutes}m`
}
if (timeRemaining > 0) {
setFormattedTime(formatTime(timeRemaining))
}
}, [timeRemaining])
if (!session) {
return <p>No active session</p>
}
return (
<div>
<p>Connected: {new Date(session.connectedAt).toLocaleString()}</p>
{isExpired ? (
<div>
<p className="text-red-500">Session expired</p>
<button onClick={refreshSession}>Reconnect</button>
</div>
) : (
<p>Time remaining: {formattedTime}</p>
)}
<button onClick={refreshSession}>Refresh Session</button>
</div>
)
}
Custom Connect Button
Create a custom connect button with your own styling.
import { useMidnightAuth } from '@uppzen/midnight-auth'
export default function CustomConnectButton() {
const { isConnected, isConnecting, connect, disconnect, walletState } = useMidnightAuth()
if (isConnecting) {
return (
<button disabled className="custom-button">
Connecting...
</button>
)
}
if (isConnected && walletState) {
return (
<div className="wallet-dropdown">
<button className="custom-button">
{walletState.address?.slice(0, 6)}...{walletState.address?.slice(-4)}
</button>
<div className="dropdown-menu">
<p>Balance: {walletState.balance}</p>
<button onClick={disconnect}>Disconnect</button>
</div>
</div>
)
}
return (
<button onClick={connect} className="custom-button">
Connect Wallet
</button>
)
}
Wallet Balance Display
Display wallet balance with automatic refresh.
import { useMidnightWallet } from '@uppzen/midnight-auth'
import { useEffect } from 'react'
export default function BalanceDisplay() {
const { balances, refreshBalance, isConnected } = useMidnightWallet()
useEffect(() => {
if (isConnected) {
// Refresh balance every 30 seconds
const interval = setInterval(() => {
refreshBalance()
}, 30000)
return () => clearInterval(interval)
}
}, [isConnected, refreshBalance])
if (!isConnected) {
return <p>Connect wallet to view balance</p>
}
if (!balances) {
return <p>Loading balance...</p>
}
return (
<div className="balance-card">
<h3>Wallet Balance</h3>
<div className="balance-item">
<span>Shielded:</span>
<span>{balances.shielded}</span>
</div>
<div className="balance-item">
<span>Unshielded:</span>
<span>{balances.unshielded}</span>
</div>
<div className="balance-total">
<span>Total:</span>
<span>{balances.total}</span>
</div>
<button onClick={refreshBalance}>Refresh</button>
</div>
)
}
Multi-Step Transaction Flow
Handle complex transaction flows with multiple steps.
import { useMidnightWallet } from '@uppzen/midnight-auth'
import { useState } from 'react'
type Step = 'idle' | 'signing' | 'submitting' | 'complete' | 'error'
export default function MultiStepTransaction() {
const { address, signData, submitTransaction } = useMidnightWallet()
const [step, setStep] = useState<Step>('idle')
const [txHash, setTxHash] = useState('')
const handleTransaction = async () => {
if (!address || !signData || !submitTransaction) return
try {
// Step 1: Sign the message
setStep('signing')
const signature = await signData(address, 'Transaction authorization')
// Step 2: Submit transaction
setStep('submitting')
const tx = {
signature: signature.signature,
// ... other tx data
}
const result = await submitTransaction(tx)
if (result.success) {
setTxHash(result.txHash)
setStep('complete')
} else {
setStep('error')
}
} catch (error) {
console.error(error)
setStep('error')
}
}
return (
<div>
<h2>Multi-Step Transaction</h2>
{step === 'idle' && (
<button onClick={handleTransaction}>Start Transaction</button>
)}
{step === 'signing' && <p>Step 1/2: Signing message...</p>}
{step === 'submitting' && <p>Step 2/2: Submitting transaction...</p>}
{step === 'complete' && (
<div>
<p>✅ Transaction complete!</p>
<p>Hash: {txHash}</p>
</div>
)}
{step === 'error' && (
<div>
<p>❌ Transaction failed</p>
<button onClick={() => setStep('idle')}>Try Again</button>
</div>
)}
</div>
)
}
Error Boundary with Wallet
Wrap wallet components in an error boundary for better error handling.
import { Component, ReactNode } from 'react'
import { useMidnightAuth } from '@uppzen/midnight-auth'
class WalletErrorBoundary extends Component<
{ children: ReactNode },
{ hasError: boolean; error: Error | null }
> {
constructor(props: { children: ReactNode }) {
super(props)
this.state = { hasError: false, error: null }
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong with the wallet connection</h2>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
Try Again
</button>
</div>
)
}
return this.props.children
}
}
export default function App() {
return (
<WalletErrorBoundary>
<WalletFeatures />
</WalletErrorBoundary>
)
}
function WalletFeatures() {
const { isConnected } = useMidnightAuth()
return <div>{isConnected ? 'Connected' : 'Not connected'}</div>
}
Next Steps
- Check the API Reference for detailed documentation
- Learn about Hooks for more programmatic control
- Explore Components for pre-built UI elements