Skip to main content

Overview

Sample management actions handle oil sample CRUD operations, analysis group analytics, and sample history tracking. All functions are located in src/app/actions/samples.ts.

Sample Operations

getSamplesService

Retrieves a paginated list of oil samples with optional filtering.
params
object
Query parameters for filtering and pagination
page
number
Page number (default: 1)
limit
number
Items per page (default: 10)
Search term for filtering samples
site_id
string
Filter by site ID
asset_id
string
Filter by asset ID
sampling_point_id
string
Filter by sampling point ID
lab_name
string
Filter by laboratory name
data
Sample[]
Array of sample objects
meta
SamplesMeta
Pagination metadata
page
number
Current page number
limit
number
Items per page
total
number
Total number of samples
total_pages
number
Total number of pages
has_next
boolean
Whether there is a next page
has_prev
boolean
Whether there is a previous page
"use server";
import { getSamplesService } from "@/app/actions";

export default async function SamplesPage({ searchParams }) {
  const params = await searchParams;
  const page = parseInt(String(params?.page ?? 1), 10);
  const limit = parseInt(String(params?.limit ?? 10), 10);

  const { data: samples, meta } = await getSamplesService({ 
    page, 
    limit 
  });

  return <SampleTable data={samples} meta={meta} />;
}
This function throws on error, so wrap in try-catch when needed.

getSampleService

Retrieves a single sample by ID.
id
string
required
Unique sample identifier
data
Sample
Complete sample object with wear metals, contaminants, particle counts, and viscosity levels
import { getSampleService } from "@/app/actions";

const sample = await getSampleService("sample-123");

console.log(sample.serial_number);
console.log(sample.severity);
console.log(sample.wear_metals);
console.log(sample.contaminants);

addSampleService

Creates a new oil sample with analysis data.
payload
AddSamplePayload
required
Sample creation data
site
object
required
id
string
required
Site ID
asset
object
required
id
string
required
Asset ID
sampling_point
object
required
id
string
required
Sampling point ID
serial_number
string
required
Sample serial number
date_sampled
number
required
Sample date as Unix timestamp
lab_name
string
required
Laboratory name
service_meter_reading
string
required
Service meter reading
hrs
string
required
Operating hours
oil_in_service
string
required
Oil in service hours/days
filter_changed
string
required
Filter change status (e.g., “Yes”, “No”)
oil_drained
string
required
Oil drained status
severity
string
required
Severity level (e.g., “Normal”, “Warning”, “Critical”)
wear_metals
Record<string, string>
Wear metal measurements (key: element, value: concentration)
contaminants
Contaminant[]
Array of contaminant measurements
type
string
required
Contaminant type
value
number
required
Measured value
unit
string
required
Unit of measurement
particle_counts
ParticleCount[]
Particle count measurements
size_range
string
required
Particle size range (e.g., “>4μm”, “>6μm”)
count
number
required
Particle count
unit
string
required
Unit (e.g., “particles/mL”)
viscosity_levels
ViscosityLevel[]
Viscosity measurements at different temperatures
temperature
number
required
Temperature in Celsius
viscosity
number
required
Viscosity value
unit
string
required
Unit (e.g., “cSt”, “mm²/s”)
additives
Record<string, string> | Additive[]
Additive measurements
collection_date
string
Collection date (ISO string)
document_url
string
URL to lab report document
response
ApiResponse
Standard API response object
success
boolean
Whether the operation succeeded
message
string
Response message
data
object
Created sample data
"use client";
import { addSampleService } from "@/app/actions";
import { AddSamplePayload } from "@/schema";
import { toast } from "sonner";

export function AddSampleForm() {
  const handleSubmit = async (data: AddSamplePayload) => {
    const payload: AddSamplePayload = {
      site: { id: data.site.id },
      asset: { id: data.asset.id },
      sampling_point: { id: data.sampling_point.id },
      serial_number: data.serial_number,
      date_sampled: new Date(data.date_sampled).getTime(),
      lab_name: data.lab_name,
      service_meter_reading: data.service_meter_reading,
      hrs: data.hrs,
      oil_in_service: data.oil_in_service,
      filter_changed: data.filter_changed,
      oil_drained: data.oil_drained,
      severity: data.severity,
      wear_metals: {
        Iron: "25",
        Copper: "12",
        Chrome: "5",
      },
      contaminants: [
        { type: "Water", value: 150, unit: "ppm" },
        { type: "Fuel", value: 2.5, unit: "%" },
      ],
      particle_counts: [
        { size_range: ">4μm", count: 5000, unit: "particles/mL" },
        { size_range: ">6μm", count: 2500, unit: "particles/mL" },
      ],
    };

    const response = await addSampleService(payload);
    
    if (response.success) {
      toast.success("Sample added successfully");
      router.push("/samples");
    } else {
      toast.error(response.message || "Failed to add sample");
    }
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

editSampleService

Updates an existing sample.
id
string
required
Sample ID to update
payload
EditSamplePayload
required
Updated sample data (same structure as AddSamplePayload)
response
ApiResponse
Standard API response object
import { editSampleService } from "@/app/actions";
import { toast } from "sonner";

const handleUpdate = async (sampleId: string, data: EditSamplePayload) => {
  const response = await editSampleService(sampleId, data);
  
  if (response.success) {
    toast.success("Sample updated successfully");
  } else {
    toast.error(response.message);
  }
};

deleteSampleService

Deletes a sample.
id
string
required
Sample ID to delete
response
ApiResponse
Standard API response object
import { deleteSampleService } from "@/app/actions";
import { toast } from "sonner";

const handleDelete = async (sampleId: string) => {
  const response = await deleteSampleService(sampleId);
  
  if (response.success) {
    toast.success("Sample deleted successfully");
  } else {
    toast.error(response.message);
  }
};

Analytics Operations

getSampleAnalysisGroupsAnalyticsService

Retrieves analytics for sample analysis groups (wear metals, contaminants, etc.).
category
string
required
Analysis category (e.g., “wear_metals”, “contaminants”, “particle_counts”)
period
number
Time period in days for trend analysis
response
ApiResponse
Response with analytics data
success
boolean
Whether the operation succeeded
data
object
Analytics data for the specified category
import { getSampleAnalysisGroupsAnalyticsService } from "@/app/actions";

const response = await getSampleAnalysisGroupsAnalyticsService(
  "wear_metals",
  30
);

if (response.success) {
  console.log("Wear metals trends:", response.data);
}

Sample History Operations

getSamplingPointSampleHistoryService

Retrieves sample history for a specific sampling point with filtering and pagination.
samplingPointId
string
required
Sampling point ID
params
object
Query parameters for filtering
page
number
Page number
org_id
string
Organization ID filter
site_id
string
Site ID filter
asset_id
string
Asset ID filter
limit
number
Items per page
start_date
string
Start date for date range filter
end_date
string
End date for date range filter
response
SampleHistoryResponse
Sample history response
success
boolean
Whether the operation succeeded
data
Sample[]
Array of sample objects
meta
SampleHistoryMeta
Pagination metadata
message
string
Error message if applicable
import { getSamplingPointSampleHistoryService } from "@/app/actions";

const { success, data: samples, meta } = 
  await getSamplingPointSampleHistoryService("sampling-point-123", {
    page: 1,
    limit: 20,
  });

if (success) {
  console.log(`Found ${meta.total} historical samples`);
}
This function returns a success flag instead of throwing, making it safe to use without try-catch.

Type Definitions

Import types from @/types and schemas from @/schema:
import { 
  Sample, 
  WearMetal, 
  Contaminant, 
  ParticleCount, 
  ViscosityLevel 
} from "@/types";
import { 
  AddSamplePayload, 
  EditSamplePayload, 
  ADD_SAMPLE_SCHEMA 
} from "@/schema";
import { ApiResponse } from "@/app/actions";
import { 
  SampleHistoryResponse, 
  SampleHistoryMeta 
} from "@/app/actions/samples";

Build docs developers (and LLMs) love