Growth Tracking and Measurements - Developer Guide

Comprehensive technical documentation for implementing and extending growth tracking features in CrittrHavens.

Architecture Overview

The measurement system follows a multi-layered architecture with clear separation between data models, business logic, and presentation components.

Core Components

Data Layer:

  • src/config/measurements.ts - Measurement type definitions and configuration
  • src/integrations/supabase/types.ts - Database schema types for measurement logs
  • src/lib/measurement-utils.ts - Data formatting and aggregation utilities
  • src/lib/unit-utils.ts - Unit conversion and display logic

Business Logic:

  • src/hooks/useLogForm.ts - Form state management for measurement entry
  • src/lib/csv-export.ts - Data export functionality
  • src/services/logService.ts - Measurement persistence and retrieval

Presentation Layer:

  • src/components/charts/MeasurementChart.tsx - Interactive line charts
  • src/components/charts/MeasurementTimeline.tsx - Timeline visualization
  • src/components/reports/VetReport.tsx - PDF report generation
  • src/components/ui/log-modal.tsx - Measurement entry interface

Measurement Configuration

Measurement Types

// src/config/measurements.ts
export interface MeasurementType {
  id: string;
  label: string;
  unit: string;
  defaultUnit: string;
  availableFor: string[];
  isPaid?: boolean;
}

export const MEASUREMENT_TYPES: MeasurementType[] = [
  // Free measurements for crittrs
  {
    id: "weight",
    label: "Weight", 
    unit: "grams",
    defaultUnit: "grams",
    availableFor: ["crittr"],
    isPaid: false
  },
  {
    id: "length",
    label: "Length",
    unit: "millimeters",
    defaultUnit: "millimeters", 
    availableFor: ["crittr"],
    isPaid: false
  },
  // Paid measurements for habitats
  {
    id: "temperature",
    label: "Temperature",
    unit: "°C",
    defaultUnit: "°C",
    availableFor: ["habitat"],
    isPaid: true
  }
  // ... additional habitat measurements
];

Subscription-Based Feature Gates

export function getMeasurementTypesFor(itemType: string, isPaidUser: boolean = false): MeasurementType[] {
  return MEASUREMENT_TYPES.filter(type => 
    type.availableFor.includes(itemType) && 
    (!type.isPaid || isPaidUser)
  );
}

Data Flow Architecture

Measurement Entry Workflow

  1. Log Modal Interaction (src/components/ui/log-modal.tsx:270-284)

    • User selects "measurement" log type
    • Dynamic measurement type selection based on item type and subscription
    • Form validation with Zod schemas
  2. Form State Management (src/hooks/useLogForm.ts)

    • addMeasurement(type, value, unit) - Add measurement to current log
    • removeMeasurement(index) - Remove measurement from log
    • updateMeasurement(index, updates) - Modify existing measurement
  3. Data Persistence

    • Measurements stored as JSON array in log records
    • Each measurement contains: {type, value, unit, timestamp}
    • Automatic unit standardization during storage

Chart Data Generation

Chart data filtering and processing is handled within the MeasurementChart component. The component filters measurement logs to show data matching the selected measurement type and sorts chronologically for display. The actual data transformation logic is embedded within the component's data processing flow.

Chart Implementation

Interactive Time Range Filtering

The MeasurementChart component supports multiple time range options with external control capability:

type TimeRange = '3_months' | '6_months' | '1_year' | '2_years' | 'all' | 'custom';

interface MeasurementChartProps {
  title: string;
  data: MeasurementData[];
  unit: string;
  color?: string;
  onViewLogs?: () => void;
  // External control for reports
  controlledRange?: { type: TimeRange; from?: Date; to?: Date };
}

Responsive Design Patterns

Charts adapt to different screen sizes and data densities:

// src/components/charts/MeasurementChart.tsx (around line 135)
const getTickInterval = () => {
  if (isMobile) {
    // On mobile, show max 4 labels regardless of data points
    if (sortedData.length <= 4) return 0;
    return Math.ceil(sortedData.length / 4) - 1;
  }
  
  // Desktop: show more labels but still limit for readability
  if (sortedData.length <= 8) return 0;
  return Math.ceil(sortedData.length / 8) - 1;
};

Unit Display Logic

// src/lib/unit-utils.ts
const getShorthandUnit = (unit: string) => {
  const unitMap: Record<string, string> = {
    'grams': 'g',
    'millimeters': 'mm',
    'centimeters': 'cm',
    // ... additional mappings
  };
  return unitMap[unit.toLowerCase()] || unit;
};

Export Functionality

CSV Export Implementation

// src/lib/csv-export.ts:13-30
export function exportMeasurementsToCSV(logs: any[], crittrName: string) {
  // Extract all measurements from logs
  const allMeasurements = logs
    .filter(log => log.log_type === "measurement" && log.measurements)
    .flatMap(log => 
      (Array.isArray(log.measurements) ? log.measurements : []).map(m => ({
        date: log.log_date || log.created_at,
        type: m.type,
        value: m.value,
        unit: m.unit || '',
        logId: log.id,
        createdAt: log.created_at,
        content: log.content || ''
      }))
    )
    .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
  
  // Group by date and merge measurements from same day
  // ... data aggregation logic
}

PDF Report Generation

The VetReport component generates comprehensive PDF reports including:

  • Measurement history tables
  • Interactive charts (rendered as images in PDF)
  • Time range filtering
  • Professional formatting for veterinary use
// src/components/reports/VetReport.tsx (around line 244)
const generatePDF = async () => {
  if (!html2pdf) {
    html2pdf = (await import('html2pdf.js')).default;
  }
  
  const element = document.getElementById('vet-report-content');
  // SVG to PNG conversion for PDF compatibility
  // Chart rendering optimization
  // Professional PDF formatting
};

Database Schema

Log Storage Structure

Measurements are stored as JSON within log records:

-- Simplified schema representation
logs: {
  id: uuid,
  log_type: 'measurement',
  log_date: date,
  measurements: json[], -- Array of measurement objects
  content: text, -- Optional notes
  crittr_id: uuid,
  habitat_id: uuid (optional),
  created_at: timestamp
}

-- Measurement object structure within JSON:
{
  type: 'weight' | 'length' | 'temperature' | ...,
  value: number,
  unit: string,
  timestamp?: string
}

Testing Patterns

Chart Component Testing

// Example test patterns for measurement components
describe('MeasurementChart', () => {
  it('renders chart with minimum 2 data points', () => {
    const data = [
      { date: '2024-01-01', value: 100, log_id: '1' },
      { date: '2024-01-15', value: 110, log_id: '2' }
    ];
    
    render(<MeasurementChart title="Weight" data={data} unit="grams" />);
    expect(screen.getByRole('img')).toBeInTheDocument();
  });
  
  it('filters data by time range correctly', () => {
    // Time range filtering tests
  });
});

Data Export Testing

describe('CSV Export', () => {
  it('exports measurements with correct headers', () => {
    const mockLogs = [/* measurement logs */];
    exportMeasurementsToCSV(mockLogs, 'Test Crittr');
    
    // Verify CSV structure and content
  });
});

Performance Considerations

Chart Optimization

  • Lazy loading for chart components in reports
  • Data point limiting for large datasets
  • Responsive rendering based on screen size
  • Memoized calculations for chart domains

Data Loading Strategies

  • Infinite scroll pagination for measurement history
  • Time-based filtering at query level
  • Subscription-based feature loading
  • Optimistic updates for measurement entry

Extension Points

Adding New Measurement Types

  1. Update Configuration (src/config/measurements.ts)

    {
      id: "new_measurement",
      label: "New Measurement",
      unit: "custom_unit", 
      defaultUnit: "custom_unit",
      availableFor: ["crittr", "habitat"],
      isPaid: false
    }
    
  2. Add Unit Conversion (src/lib/unit-utils.ts)

  3. Update Form Validation (src/lib/validations.ts)

  4. Extend Export Logic (src/lib/csv-export.ts)

Custom Chart Types

The chart system supports extension through:

  • Custom chart components following the MeasurementChart interface
  • Pluggable data transformation functions
  • Configurable time range controls
  • Theme-aware color schemes

Advanced Analytics

Framework for adding measurement analytics:

  • Trend calculation utilities
  • Statistical analysis functions
  • Health threshold monitoring
  • Predictive growth modeling

Integration Points

Third-Party Services

  • Veterinary API integrations for health assessments
  • IoT device data import (smart scales, environmental sensors)
  • Research data sharing platforms
  • Backup and sync services

Notification System

  • Measurement reminder scheduling
  • Growth milestone alerts
  • Health threshold notifications
  • Veterinary appointment triggers

See Also

Build comprehensive growth tracking that scales with your user's needs.