Overview
Recommendation actions manage maintenance recommendations with severity levels, attachments, and analytics. All functions are located in src/app/actions/recommendations.ts.
Recommendation Operations
getRecommendationsService
Retrieves a list of recommendations with optional filtering.
Query parameters for filtering (at least one parameter required) Filter parameters (e.g., site_id, severity, status)
Array of recommendation objects (returns empty array on error)
Server Component
Filter by Site
Filter by Severity
Multiple Filters
Client Component
"use server" ;
import { getRecommendationsService } from "@/app/actions" ;
export default async function RecommendationsPage () {
const recommendations = await getRecommendationsService ({});
return < RecommendationTable data ={ recommendations } />;
}
This function returns an empty array on permission errors (403) or network issues instead of throwing. No try-catch needed.
getRecommendationService
Retrieves a single recommendation by ID.
Unique recommendation identifier
Complete recommendation object with attachments and relationships
Basic Usage
With Error Handling
import { getRecommendationService } from "@/app/actions" ;
const recommendation = await getRecommendationService ( "rec-123" );
console . log ( recommendation . title );
console . log ( recommendation . severity );
console . log ( recommendation . attachments );
console . log ( recommendation . site . name );
addRecommendationService
Creates a new maintenance recommendation.
payload
AddRecommendationPayload
required
Recommendation creation data severity
'low' | 'medium' | 'high' | 'critical'
required
Severity level
Detailed description of the recommendation
attachments
RecommendationAttachment[]
Array of file attachments Attachment type (e.g., “document”, “image”)
Standard API response object Whether the operation succeeded
Created recommendation data
Client Component
With Attachments
With Severity Levels
"use client" ;
import { addRecommendationService } from "@/app/actions" ;
import { AddRecommendationPayload } from "@/schema" ;
import { toast } from "sonner" ;
export function AddRecommendationForm () {
const handleSubmit = async ( data : AddRecommendationPayload ) => {
const payload : AddRecommendationPayload = {
title: data . title ,
severity: data . severity ,
description: data . description ,
site: { id: data . site . id },
asset: { id: data . asset . id },
sampling_point: { id: data . sampling_point . id },
recommender: { id: data . recommender . id },
attachments: [],
};
const response = await addRecommendationService ( payload );
if ( response . success ) {
toast . success ( "Recommendation created successfully" );
router . push ( "/recommendations" );
} else {
toast . error ( response . message || "Failed to create recommendation" );
}
};
return < form onSubmit ={ handleSubmit }> ...</ form > ;
}
The payload is wrapped in a { recommendation: payload } object before being sent to the API. This is handled automatically by the service.
editRecommendationService
Updates an existing recommendation.
Recommendation ID to update
payload
EditRecommendationPayload
required
Updated recommendation data (same structure as AddRecommendationPayload)
Standard API response object
Basic Usage
Update Severity
Add Attachment
import { editRecommendationService } from "@/app/actions" ;
import { EditRecommendationPayload } from "@/schema" ;
import { toast } from "sonner" ;
const handleUpdate = async (
recId : string ,
data : EditRecommendationPayload
) => {
const response = await editRecommendationService ( recId , data );
if ( response . success ) {
toast . success ( "Recommendation updated successfully" );
} else {
toast . error ( response . message );
}
};
deleteRecommendationService
Deletes a recommendation.
Recommendation ID to delete
Standard API response object
Basic Usage
With Confirmation
import { deleteRecommendationService } from "@/app/actions" ;
import { toast } from "sonner" ;
const handleDelete = async ( recId : string ) => {
const response = await deleteRecommendationService ( recId );
if ( response . success ) {
toast . success ( "Recommendation deleted successfully" );
} else {
toast . error ( response . message );
}
};
Analytics Operations
getRecommendationAnalyticsService
Retrieves recommendation analytics for dashboard metrics and trend analysis.
data
RecommendationAnalytics[]
Array of monthly recommendation analytics (returns empty array on error) Month identifier (e.g., “2024-01”)
Total recommendations for the month
Percentage change from previous month
Number of overdue recommendations
Number of open and overdue recommendations
open_overdue_trend_percentage
Open/overdue trend percentage
Server Component
Trend Chart
Client Component
import { getRecommendationAnalyticsService } from "@/app/actions" ;
export default async function RecommendationsDashboard () {
const analytics = await getRecommendationAnalyticsService ();
if ( analytics . length === 0 ) {
return < div > No analytics data available </ div > ;
}
const currentMonth = analytics [ analytics . length - 1 ];
return (
< div >
< MetricCard
title = "Total Recommendations"
value = {currentMonth. total_count }
trend = {currentMonth. total_trend_percentage }
/>
< MetricCard
title = "Overdue"
value = {currentMonth. overdue_count }
trend = {currentMonth. overdue_trend_percentage }
/>
< MetricCard
title = "Open & Overdue"
value = {currentMonth. open_overdue_count }
trend = {currentMonth. open_overdue_trend_percentage }
/>
</ div >
);
}
Returns an empty array on permission errors (403), non-JSON responses, or network issues instead of throwing. Check array length before accessing data.
Common Workflows
Create Recommendation from Sample Analysis
import {
getSampleService ,
addRecommendationService ,
getAssetService
} from "@/app/actions" ;
import { toast } from "sonner" ;
// 1. Get sample data
const sample = await getSampleService ( sampleId );
// 2. Analyze severity
let severity : "low" | "medium" | "high" | "critical" = "low" ;
let title = "" ;
let description = "" ;
if ( sample . severity === "Critical" ) {
severity = "critical" ;
title = "Immediate action required - Critical sample results" ;
description = `Critical wear metals detected in sample ${ sample . serial_number } .` ;
} else if ( sample . severity === "Warning" ) {
severity = "high" ;
title = "Warning - Elevated wear metals" ;
description = `Warning levels detected in sample ${ sample . serial_number } .` ;
}
// 3. Create recommendation
const response = await addRecommendationService ({
title ,
severity ,
description ,
site: { id: sample . site . id },
asset: { id: sample . asset . id },
sampling_point: { id: sample . sampling_point . id },
recommender: { id: currentUser . id },
});
if ( response . success ) {
toast . success ( "Recommendation created from sample analysis" );
}
Link Recommendation to Alarm
import {
getAlarmService ,
editAlarmService ,
addRecommendationService
} from "@/app/actions" ;
// 1. Get alarm
const alarm = await getAlarmService ( alarmId );
// 2. Create recommendation
const recResponse = await addRecommendationService ({
title: `Address alarm: ${ alarm . parameter } ` ,
severity: "high" ,
description: `Recommendation for alarm detected on ${ alarm . first_detected } ` ,
site: { id: alarm . site . id },
asset: { id: assetId },
sampling_point: { id: samplingPointId },
recommender: { id: currentUser . id },
});
if ( ! recResponse . success ) {
toast . error ( "Failed to create recommendation" );
return ;
}
// 3. Link to alarm
const recId = recResponse . data ?. data ?. id ;
if ( recId ) {
const linkResponse = await editAlarmService ( alarmId , {
... alarm ,
linked_recommendations: [
... alarm . linked_recommendations ,
{ id: recId },
],
});
if ( linkResponse . success ) {
toast . success ( "Recommendation created and linked to alarm" );
}
}
Severity-based Filtering
import { getRecommendationsService } from "@/app/actions" ;
// Get critical and high severity recommendations
const [ critical , high ] = await Promise . all ([
getRecommendationsService ({ severity: "critical" }),
getRecommendationsService ({ severity: "high" }),
]);
const urgentRecommendations = [ ... critical , ... high ];
console . log ( ` ${ urgentRecommendations . length } urgent recommendations` );
Type Definitions
Import types from @/types and schemas from @/schema:
import {
Recommendation ,
RecommendationAttachment ,
RecommendationAnalytics
} from "@/types" ;
import {
AddRecommendationPayload ,
EditRecommendationPayload ,
ADD_RECOMMENDATION_SCHEMA
} from "@/schema" ;
import { ApiResponse } from "@/app/actions" ;