Internal Tools

Documentation for Finnance internal development tools, shared components, and engineering best practices.


Loading System

Finnance uses a unified loading system for creating snappy, consistent loading states across all applications.

Overview

The loading system provides:

  • Simple, snappy loading states with optimized animations
  • Consistent design patterns following the Finnance design system
  • Flexible components for different use cases
  • Performance optimizations with minimum loading times

Main Loading Components

Full-screen Loading

import { Loading } from '@app-launch-kit/components/common';

// Used for initial app loading
<Loading />

Page-level Loading

import { PageLoading } from '@app-launch-kit/components/common';

<PageLoading 
  title="Loading accounts..." 
  subtitle="Please wait while we fetch your data"
/>

Section-level Loading

import { ContentLoading } from '@app-launch-kit/components/common';

<ContentLoading text="Loading transactions..." />

Spinner Components

Centered Spinner

import { CenteredSpinner } from '@app-launch-kit/components/common';

<CenteredSpinner 
  text="Loading..." 
  size="md" // sm, md, lg
/>

Inline Spinner

import { InlineSpinner } from '@app-launch-kit/components/common';

<InlineSpinner size="sm" /> // xs, sm, md

Button Loading

import { ButtonLoading } from '@app-launch-kit/components/common';

<ButtonLoading text="Saving..." size="sm" />

Skeleton Components

Card Skeleton

import { SkeletonCard } from '@app-launch-kit/components/common';

<SkeletonCard showAvatar={true} showActions={true} />

List Skeleton

import { SkeletonList } from '@app-launch-kit/components/common';

<SkeletonList 
  count={3} 
  showAvatar={true} 
  showActions={true} 
/>

Table Skeleton

import { SkeletonTable } from '@app-launch-kit/components/common';

<SkeletonTable rows={5} columns={4} />

Form Skeleton

import { SkeletonForm } from '@app-launch-kit/components/common';

<SkeletonForm fields={4} showSubmit={true} />

Loading Hooks

Single Loading State

import { useLoadingState } from '@app-launch-kit/hooks';

const { isLoading, withLoading, startLoading, stopLoading } = useLoadingState({
  initialLoading: false,
  delay: 300 // Minimum loading time to prevent flash
});

// Wrap async operations
const loadData = async () => {
  const result = await withLoading(async () => {
    return await fetchData();
  });
};

// Manual control
const handleSubmit = async () => {
  startLoading();
  try {
    await submitData();
  } finally {
    stopLoading();
  }
};

Multiple Loading States

import { useMultipleLoadingStates } from '@app-launch-kit/hooks';

const { 
  isLoading, 
  isAnyLoading, 
  withLoading 
} = useMultipleLoadingStates(['accounts', 'transactions']);

// Use specific loading state
const loadAccounts = async () => {
  await withLoading('accounts', async () => {
    return await fetchAccounts();
  });
};

// Check if any operation is loading
if (isAnyLoading) {
  return <ContentLoading />;
}

Best Practices

Use PageLayout for Page Loading

<PageLayout
  title="Accounts"
  subtitle="Manage your bank accounts"
  isLoading={isLoading}
>
  {/* Content */}
</PageLayout>

Prevent Loading Flash

const { isLoading, withLoading } = useLoadingState({
  delay: 300 // Minimum 300ms loading time
});

Use Skeleton States for Lists

if (isLoading) {
  return <SkeletonList count={5} />;
}

Use Button Loading for Actions

const { isLoading, withLoading } = useLoadingState();

<Button onPress={() => withLoading(handleSubmit)}>
  {isLoading ? (
    <ButtonLoading text="Saving..." />
  ) : (
    <ButtonText>Save</ButtonText>
  )}
</Button>

Admin App Development

The admin dashboard is built with Mantine and follows specific patterns for consistency.

Client Components

Always add "use client" at the top of components that:

  1. Use React Hooks (useState, useEffect, etc.)
  2. Handle Browser Events (onClick, onSubmit, etc.)
  3. Access Browser APIs (window, document, etc.)
  4. Use third-party libraries requiring client-side execution
'use client';

import { useState } from 'react';
import { Button } from '@mantine/core';

export function MyComponent() {
  const [count, setCount] = useState(0);
  
  return (
    <Button onClick={() => setCount(count + 1)}>
      Count: {count}
    </Button>
  );
}

Component Compatibility

Working Components

  • Text, Title, Button
  • Card, Badge, Group
  • Container, Box
  • Tooltip, UnstyledButton

Problematic Components

  • Grid.Col - Use CSS Grid instead
  • Stack - Use div with flexbox instead

CSS Grid Alternative

// ❌ Don't use this (causes build errors)
<Grid>
  <Grid.Col span={3}>Content</Grid.Col>
</Grid>

// ✅ Use this instead
<div style={{ 
  display: 'grid', 
  gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', 
  gap: '1rem' 
}}>
  <div>Content</div>
</div>

Design System Compliance

All loading components use the Finnance design system colors:

TokenUsage
border-primary-mainActive spinners
border-surface-2Background spinners
text-typography-secondaryLoading text
animate-spinSpinner animations
animate-pulseSkeleton animations

Performance Tips

  1. Use delay option to prevent loading flash for fast operations
  2. Prefer skeleton states over spinners for content loading
  3. Use withLoading to automatically handle loading state lifecycle
  4. Combine loading states to reduce component re-renders
  5. Use isAnyLoading for multiple operations

Migration Guide

Before (Old Pattern)

const [isLoading, setIsLoading] = useState(false);

const loadData = async () => {
  setIsLoading(true);
  try {
    await fetchData();
  } finally {
    setIsLoading(false);
  }
};

if (isLoading) {
  return <div className="loading-spinner">Loading...</div>;
}

After (New Pattern)

const { isLoading, withLoading } = useLoadingState({ delay: 300 });

const loadData = async () => {
  await withLoading(async () => {
    return await fetchData();
  });
};

if (isLoading) {
  return <ContentLoading text="Loading data..." />;
}

Available Admin Pages

PageRouteDescription
Overview/overviewCompany health metrics dashboard
Households/householdsUser account management
Analytics/analyticsSaaS health metrics and KPIs

Chart Library (Recharts)

The admin dashboard uses Recharts for data visualization:

import {
  LineChart,
  AreaChart,
  BarChart,
  PieChart,
  ResponsiveContainer,
} from 'recharts';

Chart Best Practices

  1. Always wrap charts in ResponsiveContainer
  2. Use consistent color schemes
  3. Include proper tooltips and labels
  4. Test charts with different data sets

Resources

Was this page helpful?