Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
2d3109a
feat(referrals): implement referral system with code gen, tracking, a…
sundayonah Nov 18, 2025
0e3de13
fix: coderabbit comments
sundayonah Nov 19, 2025
63dc412
fix: add bottom-up ReferralDashboardView modal in MobileDropdown
sundayonah Nov 19, 2025
f18e8ae
refactor(referral): simplify claim to KYC + $100 tx volume, integrate…
sundayonah Nov 21, 2025
03cea8f
fix: update referral/claim file for consistency
sundayonah Nov 24, 2025
cbbedb9
refactor(referral): update ReferralDashboard and ReferralDashboardVie…
sundayonah Nov 26, 2025
36aa221
refactor(referral): streamline referral claim process with improved w…
sundayonah Dec 1, 2025
d65dff6
refactor(referral): enhance error handling and data processing in cla…
sundayonah Dec 1, 2025
9758c41
refactor(analytics): replace Promise.resolve with after for asynchron…
sundayonah Dec 1, 2025
c7b030a
refactor(referral): consolidate referral code generation and enhance …
sundayonah Dec 1, 2025
f2b546b
fix(referral): update referral transaction threshold from $20 to $100…
sundayonah Dec 1, 2025
06dafbf
feat: complete glitchtip integration with sentry wizard (#297)
sundayonah Dec 17, 2025
4553987
feat: enhance user tracking with server-side event logging (#302)
sundayonah Dec 17, 2025
0c61121
refactor: update next.config.mjs for improved configuration management
chibie Dec 17, 2025
a628ef1
feat: add low-memory build support and disable sourcemaps in next.con…
chibie Dec 18, 2025
f448fcc
Merge branch 'main' into feat/user-referral-and-earnings-program
sundayonah Dec 18, 2025
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
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ MIXPANEL_PRIVACY_MODE=strict
MIXPANEL_INCLUDE_IP=false
MIXPANEL_INCLUDE_ERROR_STACKS=false
NEXT_PUBLIC_ENABLE_EMAIL_IN_ANALYTICS=false
NEXT_PUBLIC_FEE_RECIPIENT_ADDRESS=

# =============================================================================
# Security
Expand Down Expand Up @@ -125,3 +126,8 @@ SANITY_STUDIO_PROJECT_ID=your_project_id_here
# Next.js App (client-side)
NEXT_PUBLIC_SANITY_DATASET=production
NEXT_PUBLIC_SANITY_PROJECT_ID=your_project_id_here

# Sentry
SENTRY_DSN=https://abc123@o456.ingest.glitchtip.pycrst.xyz/789
SENTRY_URL=
SENTRY_AUTH_TOKEN=
46 changes: 46 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI

on:
push:
branches: ['stable']
pull_request:
branches: ['main', 'stable']

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install pnpm
run: npm install -g pnpm

- name: Verify pnpm installation
run: pnpm --version

- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm build
90 changes: 90 additions & 0 deletions app/api/aggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import type {
RecipientDetails,
RecipientDetailsWithId,
SavedRecipientsResponse,
ReferralData,
ApiResponse,
SubmitReferralResult,
} from "../types";
import {
trackServerEvent,
Expand Down Expand Up @@ -609,6 +612,93 @@ export const fetchTokens = async (): Promise<APIToken[]> => {
}
};

/**
* Submit a referral code for a new user
*/
export async function submitReferralCode(
code: string,
accessToken?: string,
): Promise<ApiResponse<SubmitReferralResult>> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};

if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`;
}

try {
const response = await axios.post(`/api/referral/submit`, { referral_code: code }, { headers });

if (!response.data?.success) {
return { success: false, error: response.data?.error || response.data?.message || "Failed to submit referral code", status: response.status };
}

return { success: true, data: response.data?.data || response.data } as ApiResponse<SubmitReferralResult>;
} catch (error) {
if (axios.isAxiosError(error)) {
const message = error.response?.data?.message || error.message || "Failed to submit referral code";
return { success: false, error: message, status: error.response?.status };
}
return { success: false, error: error instanceof Error ? error.message : "Unknown error" };
}
}


/**
* Get user's referral data (code, earnings, referral list)
*/
export async function getReferralData(
accessToken: string,
walletAddress?: string,
): Promise<ApiResponse<ReferralData>> {
if (!accessToken) {
return {
success: false,
error: "Authentication token is required",
};
}

const url = walletAddress
? `/api/referral/referral-data?wallet_address=${encodeURIComponent(walletAddress)}`
: `/api/referral/referral-data`;

try {
const response = await axios.get<ApiResponse<ReferralData>>(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (!response.data?.success) {
return {
success: false,
error: response.data?.error || "Failed to fetch referral data",
status: response.status,
};
}

// The endpoint auto-generates code if missing, so data.referral_code should always exist
return { success: true, data: response.data.data };
} catch (error) {
if (axios.isAxiosError(error)) {
const message =
error.response?.data?.message ||
error.message ||
"Failed to fetch referral data";
return {
success: false,
error: message,
status: error.response?.status,
};
}
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}

/**
* Fetches saved recipients for a wallet address
* @param {string} accessToken - The access token for authentication
Expand Down
Loading
Loading