Skip to content

Components Documentation

This document describes the React components used in the frontend.

UI Components

The frontend uses shadcn/ui components located in frontend/src/components/ui/.

Card

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

Usage:

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>
    Content here
  </CardContent>
</Card>

Badge

import { Badge } from "@/components/ui/badge";

Usage:

<Badge variant="outline">Status</Badge>
<Badge variant="secondary">Label</Badge>
<Badge variant="destructive">Alert</Badge>

Custom Components

MapView

Interactive map component showing animal positions and paddocks.

Location: frontend/src/components/MapView.tsx

Features: - Leaflet map with OpenStreetMap tiles - Paddock polygons rendered from GeoJSON - Animal markers with custom icons - Popup details on marker click - Auto-centering on animal positions

Props: None (uses Zustand store)

AnimalHealthChart

ECharts component for visualizing temperature and activity data.

Location: frontend/src/components/AnimalHealthChart.tsx

Features: - Line chart for temperature over time - Line chart for activity level - Belt ID selector - Responsive design

Props: None

AlertTable

Table displaying geofence breach alerts.

Location: frontend/src/components/AlertTable.tsx

Features: - Sortable columns - Belt ID, location, paddock, timestamp - Responsive design

Props: None

Creating New Components

Step 1: Create Component File

// frontend/src/components/MyComponent.tsx
"use client";

import { useState } from "react";

interface MyComponentProps {
  title: string;
}

export default function MyComponent({ title }: MyComponentProps) {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>{title}</h1>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Step 2: Add to Page

// frontend/src/app/page.tsx
import MyComponent from "@/components/MyComponent";

export default function Page() {
  return (
    <main>
      <MyComponent title="My Component" />
    </main>
  );
}

State Management

Using Zustand Store

// frontend/src/lib/myStore.ts
import { create } from 'zustand';

interface MyStoreState {
  data: string[];
  setData: (data: string[]) => void;
}

export const useMyStore = create<MyStoreState>((set) => ({
  data: [],
  setData: (data) => set({ data }),
}));

Using in Components

import { useMyStore } from "@/lib/myStore";

function MyComponent() {
  const { data, setData } = useMyStore();

  return (
    <div>
      {data.map(item => <div key={item}>{item}</div>)}
    </div>
  );
}

Event Handling

WebSocket Events

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // Update store
  useTelemetryStore.getState().updatePosition(data);
};

Form Events

<form onSubmit={handleSubmit}>
  <input onChange={handleChange} />
  <button type="submit">Submit</button>
</form>

Styling

Tailwind CSS

<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow">
  <span className="text-green-700">Content</span>
</div>

Conditional Classes

<div className={`p-4 ${isActive ? 'bg-green-100' : 'bg-gray-100'}`}>