Skip to content

JavaScript Examples ​

Real-world JavaScript and TypeScript examples for integrating with the FundlyHub API using standard Fetch API.

Getting Started ​

API Configuration ​

Define your API base URL and helper functions.

javascript
// config.js
export const API_BASE_URL = 'https://api.fundlyhub.org/api/v1';

// Helper for authenticated requests (uses httpOnly cookies)
export const authenticatedFetch = async (endpoint, options = {}) => {
  const response = await fetch(`${API_BASE_URL}${endpoint}`, {
    ...options,
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(error.message || `Request failed with status ${response.status}`);
  }

  return response.json();
};

Fundraiser Management ​

Create a Complete Fundraiser ​

Full example including image handling and error management.

javascript
import { authenticatedFetch, API_BASE_URL } from './config';

export const createFundraiser = async (fundraiserData) => {
  try {
    // 1. Create the fundraiser
    const fundraiser = await authenticatedFetch('/fundraisers', {
      method: 'POST',
      body: JSON.stringify({
        title: fundraiserData.title,
        // Required. Lowercase letters, digits and hyphens; check it first with
        // GET /fundraisers/check-slug/:slug.
        slug: fundraiserData.slug,
        summary: fundraiserData.summary,
        story_html: fundraiserData.story_html,
        // Integer cents — the form field is dollars, so convert here.
        goal_amount_cents: Math.round(parseFloat(fundraiserData.goal_amount) * 100),
        // A category id, slug or name. There is no `category_id` field.
        category: fundraiserData.category,
        location: fundraiserData.location,
        tags: fundraiserData.tags || [],
        end_date: fundraiserData.end_date,
        // Always send a status: 'draft' saves work in progress (and is the
        // only create an unverified email may make); 'active' publishes.
        status: fundraiserData.publish ? 'active' : 'draft'
      })
    });

    // The campaign is wrapped in `data`. Read its status: asking for
    // 'active' can come back 'pending' when it is held for review.
    console.log('Fundraiser created:', fundraiser.data.id, fundraiser.data.status);
    return { success: true, data: fundraiser.data };
  } catch (error) {
    console.error('Error creating fundraiser:', error);
    return { success: false, error: error.message };
  }
};

Fundraiser Dashboard Data ​

Fetch a user's fundraisers and their live statistics.

javascript
import { authenticatedFetch } from './config';

export const getFundraiserDashboard = async (myProfileId) => {
  try {
    // 1. Get the user's own campaigns. There is no /fundraisers/me: a
    //    profile's campaigns come from /users/:id/campaigns, and signing in
    //    as that profile includes its unpublished ones too.
    const { data } = await authenticatedFetch(`/users/${myProfileId}/campaigns?limit=100`);
    // The list also carries campaigns this person endorsed; keep their own.
    const myFundraisers = data.filter(f => f.owner_user_id === myProfileId);

    // 2. Calculate dashboard totals — money is integer cents.
    const stats = {
      total_campaigns: myFundraisers.length,
      active_campaigns: myFundraisers.filter(f => f.status === 'active').length,
      total_raised_cents: myFundraisers.reduce((sum, f) => sum + (Number(f.total_raised_cents) || 0), 0),
      total_donors: myFundraisers.reduce((sum, f) => sum + (Number(f.donor_count) || 0), 0)
    };

    return {
      success: true,
      fundraisers: myFundraisers,
      stats
    };
  } catch (error) {
    console.error('Error loading dashboard:', error);
    return { success: false, error: error.message };
  }
};

User Authentication ​

Complete Auth Flow ​

Sign up, sign in, and session management using AWS Cognito with httpOnly cookies.

javascript
// auth.js
const API_BASE_URL = 'https://api.fundlyhub.org/api/v1';

export const authService = {
  // Sign up via Cognito
  async register(userData) {
    try {
      const response = await fetch(`${API_BASE_URL}/cognito/signup`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify(userData)
      });

      if (!response.ok) throw new Error('Registration failed');

      return { success: true, message: 'Confirmation code sent to email' };
    } catch (error) {
      return { success: false, error: error.message };
    }
  },

  // Confirm registration with email code
  async confirm(email, code) {
    try {
      const response = await fetch(`${API_BASE_URL}/cognito/confirm`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ email, code })
      });

      if (!response.ok) throw new Error('Confirmation failed');
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  },

  // Sign in — cookies are set automatically
  async login(email, password) {
    try {
      const response = await fetch(`${API_BASE_URL}/cognito/signin`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ email, password })
      });

      if (!response.ok) throw new Error('Invalid credentials');

      const { user } = await response.json();
      return { success: true, user };
    } catch (error) {
      return { success: false, error: error.message };
    }
  },

  // Google SSO — redirect-based flow
  loginWithGoogle() {
    window.location.href = `${API_BASE_URL}/cognito/oauth/google`;
  },

  // Sign out — clears session cookies
  async logout() {
    await fetch(`${API_BASE_URL}/cognito/logout`, {
      method: 'POST',
      credentials: 'include'
    });
    window.location.href = '/';
  },

  // Check auth status
  async isAuthenticated() {
    try {
      const response = await fetch(`${API_BASE_URL}/cognito/me`, {
        credentials: 'include'
      });
      return response.ok;
    } catch {
      return false;
    }
  }
};

Advanced Examples ​

Implement efficient pagination and search.

javascript
// useInfiniteSearch.js
const API_BASE_URL = 'https://api.fundlyhub.org/api/v1';

export const useInfiniteSearch = () => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(0);
  const LIMIT = 20;

  const loadMore = useCallback(async (query = '', reset = false) => {
    if (loading) return;
    setLoading(true);

    try {
      const currentOffset = reset ? 0 : page * LIMIT;
      const params = new URLSearchParams({
        limit: LIMIT,
        offset: currentOffset,
        status: 'active'
      });
      // `q` is the listing's free-text filter (2+ characters).
      if (query.trim().length >= 2) params.set('q', query.trim());

      const response = await fetch(`${API_BASE_URL}/fundraisers?${params}`);
      // The listing answers { data, pagination }, not a bare array.
      const { data: newItems } = await response.json();

      setItems(prev => reset ? newItems : [...prev, ...newItems]);
      setPage(prev => reset ? 1 : prev + 1);
    } finally {
      setLoading(false);
    }
  }, [page, loading]);

  return { items, loading, loadMore };
};

Built with VitePress