Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/deploy-cf-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Deploy to Cloudflare Pages

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
pull-requests: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build for Cloudflare Pages
run: npx @cloudflare/next-on-pages

- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: trustflow-frontend
directory: .vercel/output/static
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
wranglerVersion: '3'
16 changes: 13 additions & 3 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
const { setupDevPlatform } = process.env.NODE_ENV === 'development'
? require('@cloudflare/next-on-pages/next-dev')
: { setupDevPlatform: () => {} };

/** @type {import('next').NextConfig} */
module.exports = {
const nextConfig = {
reactStrictMode: true,
// Built-in locale routing (Pages Router). Prefixes non-default locales, e.g.
// `/es/explore`, and exposes the active locale via `useRouter().locale`.
// Cloudflare Pages runs on the edge runtime which doesn't support the
// Node.js-based i18n middleware Next.js uses internally. We keep the
// locale list here for `useRouter().locale` support in the Pages Router
// and handle locale detection via a Cloudflare Pages _middleware instead.
i18n: {
locales: ['en', 'es'],
defaultLocale: 'en',
},
};

setupDevPlatform();

module.exports = nextConfig;
36 changes: 14 additions & 22 deletions pages/api/profile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export const runtime = 'edge'

export interface ProfileGig {
id: string
Expand All @@ -25,10 +28,6 @@ export interface UserProfileResponse {
source: 'backend' | 'mock'
}

interface UserProfileError {
error: string
}

interface BackendProfileResponse {
walletAddress: string
displayName: string
Expand Down Expand Up @@ -112,24 +111,19 @@ function normalizeBackendResponse(payload: BackendProfileResponse): UserProfileR
}
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<UserProfileResponse | UserProfileError>
) {
export default async function handler(req: NextRequest): Promise<NextResponse> {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' })
return NextResponse.json({ error: 'Method not allowed' }, { status: 405 })
}

res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate=120')
const { searchParams } = new URL(req.url)
const walletAddress = searchParams.get('walletAddress')?.trim() || 'unknown'

const walletAddress =
typeof req.query.walletAddress === 'string' && req.query.walletAddress.trim().length > 0
? req.query.walletAddress
: 'unknown'
const cacheHeaders = { 'Cache-Control': 's-maxage=30, stale-while-revalidate=120' }

const backendBaseUrl = process.env.PROFILE_API_BASE_URL
if (!backendBaseUrl) {
return res.status(200).json(getMockProfile(walletAddress))
return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders })
}

try {
Expand All @@ -138,18 +132,16 @@ export default async function handler(

const response = await fetch(url.toString(), {
method: 'GET',
headers: {
Accept: 'application/json',
},
headers: { Accept: 'application/json' },
})

if (!response.ok) {
return res.status(200).json(getMockProfile(walletAddress))
return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders })
}

const payload = (await response.json()) as BackendProfileResponse
return res.status(200).json(normalizeBackendResponse(payload))
return NextResponse.json(normalizeBackendResponse(payload), { headers: cacheHeaders })
} catch {
return res.status(200).json(getMockProfile(walletAddress))
return NextResponse.json(getMockProfile(walletAddress), { headers: cacheHeaders })
}
}
46 changes: 24 additions & 22 deletions pages/api/usdc-price.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export const runtime = 'edge';

export interface USDCPriceResponse {
price: number
currency: string
timestamp: number
source: string
price: number;
currency: string;
timestamp: number;
source: string;
}

export interface USDCPriceError {
error: string
error: string;
}

// Simulate a realistic USDC peg: $1.00 ± 0.05% variance
function getMockUSDCPrice(): number {
const variance = (Math.random() - 0.5) * 0.001
return parseFloat((1.0 + variance).toFixed(4))
const variance = (Math.random() - 0.5) * 0.001;
return parseFloat((1.0 + variance).toFixed(4));
}

export default function handler(
req: NextApiRequest,
res: NextApiResponse<USDCPriceResponse | USDCPriceError>
) {
export default function handler(req: NextRequest): NextResponse {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' })
return NextResponse.json({ error: 'Method not allowed' }, { status: 405 });
}

res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate=60')

return res.status(200).json({
price: getMockUSDCPrice(),
currency: 'USD',
timestamp: Date.now(),
source: 'mock',
})
return NextResponse.json(
{
price: getMockUSDCPrice(),
currency: 'USD',
timestamp: Date.now(),
source: 'mock',
},
{
headers: { 'Cache-Control': 's-maxage=30, stale-while-revalidate=60' },
}
);
}
5 changes: 5 additions & 0 deletions wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = "trustflow-frontend"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]

pages_build_output_dir = ".vercel/output/static"
Loading