# Frontend

The QuickDapp frontend is a modern React application built with cutting-edge technologies for an optimal developer experience and user interface. It provides seamless Web3 integration, real-time updates, and a responsive design system.

# Technology Stack

  • React 19 - Latest React with concurrent features and modern hooks
  • Vite - Lightning-fast build tool and development server
  • TypeScript - Full type safety across the application
  • TailwindCSS - Utility-first CSS framework
  • Radix UI - Unstyled, accessible UI components
  • RainbowKit - Beautiful wallet connection UI
  • Wagmi - React hooks for Ethereum
  • Viem - TypeScript Ethereum library
  • React Query - Powerful data synchronization
  • React Router - Client-side routing

# Key Features

# Web3 Integration

Complete Web3 functionality with wallet connections, transaction handling, and blockchain interactions:

import { useAccount, useConnect, useDisconnect } from 'wagmi'
import { ConnectButton } from '@rainbow-me/rainbowkit'

export function WalletConnection() {
  return (
    <ConnectButton.Custom>
      {({ account, chain, openConnectModal, mounted }) => (
        <div>
          {!account ? (
            <button onClick={openConnectModal}>Connect Wallet</button>
          ) : (
            <div>Connected: {account.displayName}</div>
          )}
        </div>
      )}
    </ConnectButton.Custom>
  )
}

# Real-time Data

React Query integration for efficient data fetching and caching:

import { useQuery } from '@tanstack/react-query'
import { graphqlClient } from '../lib/graphql'

export function useTokens() {
  return useQuery({
    queryKey: ['tokens'],
    queryFn: async () => {
      const data = await graphqlClient.request(`
        query GetTokens {
          tokens {
            id
            address
            name
            symbol
            createdAt
          }
        }
      `)
      return data.tokens
    }
  })
}

# Responsive Design

TailwindCSS with mobile-first design principles:

export function TokenCard({ token }: { token: Token }) {
  return (
    <div className="bg-white rounded-lg shadow-md p-4 sm:p-6 
                    border border-gray-200 hover:shadow-lg 
                    transition-shadow duration-200">
      <div className="flex items-center justify-between mb-4">
        <h3 className="text-lg font-semibold text-gray-900">
          {token.name}
        </h3>
        <span className="text-sm text-gray-500 font-mono">
          {token.symbol}
        </span>
      </div>
      <p className="text-sm text-gray-600 font-mono break-all">
        {token.address}
      </p>
    </div>
  )
}

# Component System

Reusable components built on Radix UI primitives:

import * as Dialog from '@radix-ui/react-dialog'
import { Button } from './Button'

export function Modal({ 
  isOpen, 
  onClose, 
  title, 
  children 
}: ModalProps) {
  return (
    <Dialog.Root open={isOpen} onOpenChange={onClose}>
      <Dialog.Portal>
        <Dialog.Overlay className="fixed inset-0 bg-black/50" />
        <Dialog.Content className="fixed top-1/2 left-1/2 transform 
                                   -translate-x-1/2 -translate-y-1/2
                                   bg-white rounded-lg p-6 shadow-xl
                                   max-w-md w-full">
          <Dialog.Title className="text-lg font-semibold mb-4">
            {title}
          </Dialog.Title>
          {children}
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  )
}

# Project Structure

src/client/
├── components/         # Reusable UI components
│   ├── ui/            # Base UI components (Button, Input, etc.)
│   ├── forms/         # Form components
│   └── layout/        # Layout components
├── pages/             # Application pages/routes
├── hooks/             # Custom React hooks
│   ├── useAuth.ts     # Authentication hook
│   ├── useTokens.ts   # Token data hooks
│   └── useWebSocket.ts # WebSocket connection
├── lib/               # Client-side utilities
│   ├── graphql.ts     # GraphQL client setup
│   ├── wagmi.ts       # Wagmi configuration
│   └── utils.ts       # General utilities
├── styles/            # Global styles
└── types/             # TypeScript type definitions

# Documentation Sections

  • Components - UI component library and usage
  • Forms - Form handling and validation
  • Global - Global state management and context
  • GraphQL - GraphQL client integration
  • Web3 - Blockchain interactions and wallet integration

# Quick Examples

# Custom Hook for Contract Interaction

// src/client/hooks/useTokenContract.ts
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { ERC20_ABI } from '../lib/abis'

export function useTokenTransfer(tokenAddress: string) {
  const { writeContract, data: hash, isPending } = useWriteContract()
  
  const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
    hash,
  })
  
  const transfer = (to: string, amount: bigint) => {
    writeContract({
      address: tokenAddress as `0x${string}`,
      abi: ERC20_ABI,
      functionName: 'transfer',
      args: [to, amount],
    })
  }
  
  return {
    transfer,
    isPending,
    isConfirming,
    isSuccess,
    hash
  }
}

# Realtime Notifications with WebSockets

GraphQL is used for authentication and notifications querying/mutations. On-chain interactions (including token deployment) are done via viem/wagmi on the client, not via GraphQL mutations.

Use WebSockets to react to new notifications as they arrive:

// src/client/hooks/useNotificationsSocket.ts
import { useEffect } from 'react'

export function useNotificationsSocket(onNotification: (n: any) => void) {
  useEffect(() => {
    const token = localStorage.getItem('auth-token')
    if (!token) return

    const proto = location.protocol === 'https:' ? 'wss' : 'ws'
    const ws = new WebSocket(`${proto}://${location.host}/ws?token=${encodeURIComponent(token)}`)

    ws.onmessage = (evt) => {
      try {
        const msg = JSON.parse(evt.data)
        if (msg?.type === 'NotificationReceived' || msg?.type === 1) {
          onNotification(msg.data)
        }
      } catch {}
    }

    return () => ws.close()
  }, [onNotification])
}

# Form Component with Validation

// src/client/components/forms/DeployTokenForm.tsx
import { useForm } from 'react-hook-form'
import { Button } from '../ui/Button'
import { Input } from '../ui/Input'
import { useDeployToken } from '../../hooks/useDeployToken'

interface DeployTokenFormData {
  name: string
  symbol: string
  initialSupply: string
}

export function DeployTokenForm({ onSuccess }: { onSuccess?: () => void }) {
  const {
    register,
    handleSubmit,
    formState: { errors, isValid },
    reset
  } = useForm<DeployTokenFormData>()
  
  const deployToken = useDeployToken()
  
  const onSubmit = async (data: DeployTokenFormData) => {
    try {
      await deployToken.mutateAsync(data)
      reset()
      onSuccess?.()
    } catch (error) {
      console.error('Failed to deploy token:', error)
    }
  }
  
  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
      <div>
        <Input
          label="Token Name"
          {...register('name', { required: 'Token name is required' })}
          error={errors.name?.message}
          placeholder="My Token"
        />
      </div>
      
      <div>
        <Input
          label="Symbol"
          {...register('symbol', { 
            required: 'Symbol is required',
            maxLength: { value: 6, message: 'Symbol must be 6 characters or less' }
          })}
          error={errors.symbol?.message}
          placeholder="MTK"
        />
      </div>
      
      <div>
        <Input
          label="Initial Supply"
          type="number"
          {...register('initialSupply', { 
            required: 'Initial supply is required',
            min: { value: 1, message: 'Supply must be at least 1' }
          })}
          error={errors.initialSupply?.message}
          placeholder="1000000"
        />
      </div>
      
      <Button 
        type="submit"
        disabled={!isValid || deployToken.isPending}
        loading={deployToken.isPending}
      >
        Deploy Token
      </Button>
    </form>
  )
}

# Layout Component

// src/client/components/layout/AppLayout.tsx
import { ReactNode } from 'react'
import { Header } from './Header'
import { Sidebar } from './Sidebar'
import { NotificationCenter } from '../NotificationCenter'
import { useAuth } from '../../hooks/useAuth'

interface AppLayoutProps {
  children: ReactNode
}

export function AppLayout({ children }: AppLayoutProps) {
  const { user } = useAuth()
  
  return (
    <div className="min-h-screen bg-gray-50">
      <Header />
      
      <div className="flex">
        {user && <Sidebar />}
        
        <main className="flex-1 p-6">
          {children}
        </main>
      </div>
      
      <NotificationCenter />
    </div>
  )
}

The frontend architecture emphasizes modern React patterns, excellent type safety, and seamless Web3 integration while maintaining a clean, maintainable codebase.