> For the complete documentation index, see [llms.txt](https://crowdfunding-ugmbcc.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://crowdfunding-ugmbcc.gitbook.io/docs/how-to-run/front-end-guide.md).

# Front End Guide

This guide provides comprehensive instructions for setting up and running the CrowdFUNding frontend application, including its architecture and key components.

### Overview

The frontend is a **Next.js 16** application built with React 19 and TypeScript. It provides the user interface for the CrowdFUNding platform, handling wallet connections, campaign browsing, donations, and achievement displays.

**Key Features:**

* Server-side rendering with App Router
* Google OAuth 2.0 authentication with wallet sync
* RainbowKit for Web3 wallet connections
* Beautiful UI with TailwindCSS 4 and Framer Motion
* Farcaster Miniapp integration
* Direct blockchain interaction via wagmi/viem

### Architecture

The frontend follows a modular architecture with clear separation between pages, components, hooks, and utilities.

{% @mermaid/diagram content="flowchart TB
subgraph Pages\["Pages (App Router)"]
Landing\["/ (Landing)"]
Home\["/home"]
Campaign\["/campaign/:id"]
Donate\["/donate/:id"]
Profile\["/profile"]
Honors\["/honors"]
end

```
subgraph Components["Component Layer"]
    UI["UI Elements"]
    Layout["Layouts"]
    Forms["Form Components"]
end

subgraph Hooks["Custom Hooks"]
    useCrowdfunding["useCrowdfunding"]
    useCreateCampaign["useCreateCampaign"]
    useDonate["useDonate"]
    useWithdraw["useWithdraw"]
end

subgraph Services["Service Layer"]
    WagmiConfig["Wagmi Configuration"]
    APIClient["Backend API (Axios)"]
    GoogleAuth["Google OAuth 2.0"]
end

subgraph External["External"]
    Blockchain["Base Sepolia"]
    Backend["Backend API"]
end

Pages --> Components
Pages --> Hooks
Hooks --> Services
WagmiConfig --> Blockchain
APIClient --> Backend" %}
```

#### Key Architectural Decisions

The following table explains the major architectural choices:

<table><thead><tr><th width="249">Decision</th><th>Implementation</th><th>Benefit</th></tr></thead><tbody><tr><td><strong>App Router</strong></td><td>Next.js 16 App Directory</td><td>Server components, streaming</td></tr><tr><td><strong>Dual Auth</strong></td><td>Google OAuth + Web3 Wallets</td><td>Support both Web2 and Web3 users</td></tr><tr><td><strong>React Query</strong></td><td>TanStack Query</td><td>Smart caching, background refresh</td></tr><tr><td><strong>Type-Safe Contracts</strong></td><td>Wagmi + Viem</td><td>Compile-time error detection</td></tr><tr><td><strong>Social Integration</strong></td><td>Farcaster Miniapp SDK</td><td>Native Base App experience within Farcaster, accessing the social graph</td></tr></tbody></table>

### Prerequisites

Before setting up the frontend, ensure you have:

* **Node.js** v18 or higher
* **npm**, **yarn**, or **pnpm** (yarn recommended)

### Project Structure

The frontend uses a modular structure with the App Router pattern:

```
├── app/                          # Next.js App Router
├── app/(auth)/                   # Authentication route group
│   └── login/
├── app/(main)/                   # Main app with navigation
│   ├── campaign/
│   ├── history/
│   ├── home/
│   ├── honors/
│   └── profile/
├── app/(main-no-nav)/            # Pages without navigation
│   ├── donate/
│   └── campaign-detail/
├── page.tsx                  # Landing page
├── layout.tsx                # Root layout
├── src/
├── src/components/               # Reusable UI components
│   ├── Element/              # Buttons, cards, inputs
│   ├── Layout/               # Page layouts, navigation
│   └── Contexts/             # React context providers
├── src/hooks/                    # Custom React hooks
├── src/modules/                  # Page-specific modules
├── src/utils/
│   ├── abi/                  # Contract ABIs
│   ├── api/                  # Backend API clients
│   ├── contracts/            # Contract addresses
│   └── wagmi/                # Wagmi configuration
├── src/styles/                   # Global CSS styles
├── public/                       # Static assets
├── next.config.ts                # Next.js configuration
└── tailwind.config.ts            # TailwindCSS configuration
```

### Component Architecture

The frontend uses a layered component architecture for maximum reusability:

{% @mermaid/diagram content="flowchart TB
subgraph Atoms\["Atoms"]
Button\["Button"]
Input\["Input"]
Badge\["Badge"]
end

```
subgraph Molecules["Molecules"]
    Card["CampaignCard"]
    Form["DonationForm"]
    Progress["ProgressBar"]
end

subgraph Organisms["Organisms"]
    Header["Header"]
    CampaignList["CampaignList"]
    DonationModal["DonationModal"]
end

subgraph Templates["Templates/Pages"]
    HomePage["Home Page"]
    CampaignPage["Campaign Page"]
    DonatePage["Donate Page"]
end

Atoms --> Molecules --> Organisms --> Templates" %}
```

### Environment Setup

Create a `.env.local` file in the project root:

```env
# ============================
# Wallet Connection
# ============================
NEXT_PUBLIC_WALLET_CONNECT_ID=your_walletconnect_project_id

# ============================
# Blockchain (RPC)
# ============================
NEXT_PUBLIC_ALCHEMY_KEY=your_alchemy_api_key

# ============================
# Smart Contract Addresses
# ============================
NEXT_PUBLIC_CAMPAIGN_ADDRESS=0x44e87aa98d721Dbcf368690bF5aAb1F3dD944dA9
NEXT_PUBLIC_BADGE_ADDRESS=0xaE32Df9Fb677aE68C5A1F956761a42e269Ebdc99
NEXT_PUBLIC_MOCK_SWAP_ADDRESS=0x554366984fD2f5D82c753F91357d80c29F887F17
NEXT_PUBLIC_IDRX_ADDRESS=0x387551ac55Bb6949d44715D07880f8c6260934B6
NEXT_PUBLIC_USDC_ADDRESS=0x1b929eB40670aA4e0D757d45cA9aea2311a25a97

# ============================
# Backend API
# ============================
NEXT_PUBLIC_BACKEND_URL=http://localhost:3300

# ============================
# Farcaster (Optional)
# ============================
NEXT_PUBLIC_FARCASTER_FRAME_URL=https://frames.example.com
```

#### How to Get Environment Keys

The following table provides instructions for obtaining each required key:

| Variable                        | How to Obtain                                                           |
| ------------------------------- | ----------------------------------------------------------------------- |
| `NEXT_PUBLIC_WALLET_CONNECT_ID` | [WalletConnect Cloud](https://cloud.walletconnect.com) → Create Project |
| `NEXT_PUBLIC_ALCHEMY_KEY`       | [Alchemy Dashboard](https://alchemy.com) → Create Base Sepolia App      |
| `NEXT_PUBLIC_BACKEND_URL`       | Your backend server URL (default: `http://localhost:3300`)              |

### Installation

#### Step 1: Install Dependencies

```bash
# Using yarn (recommended)
yarn install

# Using npm
npm install
```

#### Step 2: Start Development Server

```bash
yarn dev
# or
npm run dev
```

The application will start at `http://localhost:3000`

### Page Routes

The application uses Next.js App Router with route groups for different layouts:

| Route           | Layout          | Description           |
| --------------- | --------------- | --------------------- |
| `/`             | Minimal         | Landing page          |
| `/home`         | Main (with nav) | Campaign discovery    |
| `/campaign/:id` | Main (with nav) | Campaign detail       |
| `/donate/:id`   | No nav          | Donation flow         |
| `/history`      | Main (with nav) | User donation history |
| `/profile`      | Main (with nav) | User settings         |
| `/honors`       | Main (with nav) | Achievement badges    |
| `/login`        | Auth            | Authentication page   |

### Key Hooks

The frontend provides custom hooks that abstract blockchain interactions. These hooks handle wallet connections, contract calls, and state management.

#### useCrowdfunding

This hook fetches campaign data from both the blockchain and backend API:

```tsx
import { useCrowdfunding } from "@/hooks/useCrowdfunding";

const CampaignList = () => {
  const { campaigns, isLoading, error } = useCrowdfunding();

  if (isLoading) return <Spinner />;
  if (error) return <Error message={error.message} />;

  return (
    <div className="grid grid-cols-3 gap-4">
      {campaigns.map((campaign) => (
        <CampaignCard key={campaign.id} campaign={campaign} />
      ))}
    </div>
  );
};
```

#### useCreateCampaign

This hook handles the campaign creation flow including transaction signing:

```tsx
import { useCreateCampaign } from "@/hooks/useCreateCampaign";

const CreateCampaignForm = () => {
  const { createCampaign, isLoading, error } = useCreateCampaign();

  const handleSubmit = async (data) => {
    await createCampaign({
      name: data.name,
      creatorName: data.creatorName,
      targetAmount: parseUnits(data.target, 2), // IDRX has 2 decimals
    });
  };

  return <form onSubmit={handleSubmit}>...</form>;
};
```

#### useDonate

This hook handles donations with support for multiple currencies:

```tsx
import { useDonate } from "@/hooks/useDonate";

const DonationForm = ({ campaignId }) => {
  const { donate, donateWithToken, isLoading } = useDonate();

  // Donate with BASE (native token)
  const handleNativeDonation = async (amount) => {
    await donate(campaignId, parseEther(amount));
  };

  // Donate with ERC20 (USDC or IDRX)
  const handleTokenDonation = async (amount, tokenAddress) => {
    await donateWithToken(campaignId, amount, tokenAddress);
  };
};
```

#### useWithdraw

This hook allows campaign owners to withdraw accumulated funds:

```tsx
import { useWithdraw } from "@/hooks/useWithdraw";

const WithdrawButton = ({ campaignId, amount }) => {
  const { withdraw, isLoading } = useWithdraw();

  const handleWithdraw = async () => {
    await withdraw(campaignId, amount);
  };

  return (
    <button onClick={handleWithdraw} disabled={isLoading}>
      {isLoading ? "Processing..." : "Withdraw Funds"}
    </button>
  );
};
```

### Authentication & Wallet Integration

The frontend supports dual authentication methods to accommodate different user preferences:

{% @mermaid/diagram content="flowchart LR
subgraph Auth\["Authentication Options"]
GoogleAuth\["Google OAuth 2.0\n(Server-side)"]
WalletAuth\["Web3 Wallet\n(RainbowKit)"]
end

```
subgraph Features["Features"]
    Social["Google Login"]
    WalletSync["Wallet Sync"]
    External["External Wallets\n(MetaMask, etc)"]
end

GoogleAuth --> Social
GoogleAuth --> WalletSync
WalletAuth --> External
WalletAuth --> WalletSync" %}
```

#### Google OAuth 2.0 Authentication

The application uses **Google OAuth 2.0** for social login, handled server-side via Passport.js:

```tsx
// Login with Google
const LoginButton = () => {
  const handleGoogleLogin = () => {
    // Redirect to backend OAuth endpoint
    window.location.href = `${process.env.NEXT_PUBLIC_BACKEND_URL}/auth/google`;
  };

  return (
    <button onClick={handleGoogleLogin} className="btn-google">
      <GoogleIcon />
      Continue with Google
    </button>
  );
};
```

**Authentication Flow:**

1. User clicks "Login with Google"
2. Redirects to backend `/auth/google` endpoint
3. Backend handles OAuth flow with Google
4. User authorizes application
5. Backend receives user info, creates/updates user in database
6. Backend sets JWT cookie and redirects back to frontend
7. Frontend reads cookie and displays user session

#### Web3 Wallet Connection (RainbowKit)

For crypto-native users, RainbowKit provides wallet connection:

```tsx
// Using RainbowKit for Web3 wallet connection
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { useAccount } from "wagmi";

const WalletConnectButton = () => {
  const { address, isConnected } = useAccount();

  return <ConnectButton />;
};
```

#### Wallet-Google Account Sync

Users can link their Web3 wallet to their Google account:

```tsx
// Check if wallet needs to be synced with Google account
import { checkWalletSync, syncWallet } from "@/utils/api/sync";

const SyncWalletButton = () => {
  const { address } = useAccount();
  const [needsSync, setNeedsSync] = useState(false);

  useEffect(() => {
    if (address) {
      checkWalletSync(address).then((response) => {
        setNeedsSync(response.needsSync);
      });
    }
  }, [address]);

  const handleSync = async () => {
    await syncWallet(address);
    // Show success message
  };

  if (!needsSync) return null;

  return <button onClick={handleSync}>Sync wallet with your account</button>;
};
```

### Styling

The frontend uses TailwindCSS 4 for styling with custom design tokens:

```tsx
// Example component with Tailwind
const CampaignCard = ({ campaign }) => (
  <div className="bg-gradient-to-r from-purple-600 to-blue-500 rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow">
    <h2 className="text-2xl font-bold text-white">{campaign.name}</h2>
    <p className="text-white/80 mt-2">{campaign.creatorName}</p>
    <ProgressBar value={campaign.balance} max={campaign.targetAmount} />
  </div>
);
```

#### Animations with Framer Motion

```tsx
import { motion } from "framer-motion";

const AnimatedCard = ({ children }) => (
  <motion.div
    initial={{ opacity: 0, y: 20 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{ duration: 0.5 }}
    whileHover={{ scale: 1.02 }}
  >
    {children}
  </motion.div>
);
```

### Building for Production

#### Create Production Build

```bash
yarn build
# or
npm run build
```

#### Start Production Server

```bash
yarn start
# or
npm start
```

### Deployment

#### Vercel (Recommended)

Vercel provides the best experience for Next.js applications:

1. Push your code to GitHub
2. Connect repository to [Vercel](https://vercel.com)
3. Set environment variables in the Vercel dashboard
4. Deploy!

Or use the CLI:

```bash
vercel --prod
```

#### Other Platforms

The app can be deployed to any platform supporting Next.js:

* Netlify
* Railway
* AWS Amplify
* Self-hosted with Node.js

### Troubleshooting

#### Wallet Connection Failed

**Error:** `WalletConnect failed to initialize`

**Solution:** Ensure `NEXT_PUBLIC_WALLET_CONNECT_ID` is correctly set in `.env.local`.

#### Contract Interaction Failed

**Error:** `Cannot read properties of undefined (reading 'write')`

**Solution:**

1. Verify contract addresses in `.env.local`
2. Ensure wallet is connected to Base Sepolia (chainId: 84532)

#### API Request Failed

**Error:** `Network Error`

**Solution:**

1. Ensure backend is running at `NEXT_PUBLIC_API_URL`
2. Check CORS settings on backend

#### TailwindCSS Not Working

**Solution:** Ensure PostCSS is configured correctly:

```js
// postcss.config.mjs
export default {
  plugins: {
    "@tailwindcss/postcss": {},
    autoprefixer: {},
  },
};
```

### Development Tips

#### Switch Networks Easily

Force users to switch to Base Sepolia:

```tsx
import { useSwitchChain } from "wagmi";
import { baseSepolia } from "wagmi/chains";

const NetworkSwitcher = () => {
  const { switchChain } = useSwitchChain();

  return (
    <button onClick={() => switchChain({ chainId: baseSepolia.id })}>
      Switch to Base Sepolia
    </button>
  );
};
```

#### Debug Contract Calls

Enable detailed logging for wagmi:

```tsx
import { useContractWrite } from "wagmi";

const { writeAsync, error, status } = useContractWrite({
  // config...
});

console.log("Transaction status:", status);
if (error) console.error("Contract error:", error);
```
