2026-02-19 15:48:32 +03:30
|
|
|
/**
|
2026-02-19 16:58:30 +03:30
|
|
|
* Farm Dashboard Service
|
|
|
|
|
* Handles API calls for dashboard config and card data.
|
|
|
|
|
* - Config: disabled cards, row order, drag reorder
|
|
|
|
|
* - Cards: all 15 card payloads from /api/farm-dashboard/
|
2026-02-19 15:48:32 +03:30
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { apiClient } from '../client'
|
|
|
|
|
import type { FarmDashboardConfig } from '@/views/dashboards/farm/farmDashboardConfig'
|
2026-02-19 16:58:30 +03:30
|
|
|
import type { CardId } from '@/views/dashboards/farm/farmDashboardConfig'
|
2026-02-19 15:48:32 +03:30
|
|
|
|
|
|
|
|
export interface ApiResponse<T> {
|
|
|
|
|
code: number
|
|
|
|
|
msg: string
|
|
|
|
|
data: T
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface FarmDashboardConfigResponse {
|
|
|
|
|
disabled_card_ids: string[]
|
|
|
|
|
row_order: string[]
|
|
|
|
|
enable_drag_reorder?: boolean
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 16:58:30 +03:30
|
|
|
/** API response shape for /api/farm-dashboard/ - each key matches CardId */
|
|
|
|
|
export interface FarmDashboardCardsResponse {
|
|
|
|
|
farmOverviewKpis?: Record<string, unknown>
|
|
|
|
|
farmWeatherCard?: Record<string, unknown>
|
|
|
|
|
farmAlertsTracker?: Record<string, unknown>
|
|
|
|
|
sensorValuesList?: Record<string, unknown>
|
|
|
|
|
sensorRadarChart?: Record<string, unknown>
|
|
|
|
|
sensorComparisonChart?: Record<string, unknown>
|
|
|
|
|
anomalyDetectionCard?: Record<string, unknown>
|
|
|
|
|
farmAlertsTimeline?: Record<string, unknown>
|
|
|
|
|
waterNeedPrediction?: Record<string, unknown>
|
|
|
|
|
harvestPredictionCard?: Record<string, unknown>
|
|
|
|
|
yieldPredictionChart?: Record<string, unknown>
|
|
|
|
|
soilMoistureHeatmap?: Record<string, unknown>
|
|
|
|
|
ndviHealthCard?: Record<string, unknown>
|
|
|
|
|
recommendationsList?: Record<string, unknown>
|
|
|
|
|
economicOverview?: Record<string, unknown>
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 15:48:32 +03:30
|
|
|
const STORAGE_KEY = 'farm_dashboard_config'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transform API response to frontend config format
|
|
|
|
|
*/
|
|
|
|
|
function fromApiResponse(data: FarmDashboardConfigResponse): FarmDashboardConfig {
|
|
|
|
|
return {
|
|
|
|
|
disabledCardIds: data.disabled_card_ids ?? [],
|
|
|
|
|
rowOrder: data.row_order ?? [],
|
|
|
|
|
enableDragReorder: data.enable_drag_reorder ?? true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transform frontend config to API request format
|
|
|
|
|
*/
|
|
|
|
|
function toApiRequest(config: Partial<FarmDashboardConfig>): Partial<FarmDashboardConfigResponse> {
|
|
|
|
|
const req: Partial<FarmDashboardConfigResponse> = {}
|
|
|
|
|
if (config.disabledCardIds !== undefined) req.disabled_card_ids = config.disabledCardIds
|
|
|
|
|
if (config.rowOrder !== undefined) req.row_order = config.rowOrder
|
|
|
|
|
if (config.enableDragReorder !== undefined) req.enable_drag_reorder = config.enableDragReorder
|
|
|
|
|
return req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* localStorage fallback when backend is not ready
|
|
|
|
|
*/
|
|
|
|
|
function getLocalConfig(): FarmDashboardConfig | null {
|
|
|
|
|
if (typeof window === 'undefined') return null
|
|
|
|
|
try {
|
|
|
|
|
const stored = localStorage.getItem(STORAGE_KEY)
|
|
|
|
|
return stored ? (JSON.parse(stored) as FarmDashboardConfig) : null
|
|
|
|
|
} catch {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setLocalConfig(config: FarmDashboardConfig): void {
|
|
|
|
|
if (typeof window === 'undefined') return
|
|
|
|
|
try {
|
|
|
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(config))
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Failed to save farm dashboard config to localStorage', e)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const farmDashboardService = {
|
|
|
|
|
/**
|
|
|
|
|
* Get farm dashboard config for current user
|
|
|
|
|
*/
|
|
|
|
|
async getConfig(): Promise<FarmDashboardConfig> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await apiClient.get<
|
|
|
|
|
ApiResponse<FarmDashboardConfigResponse> | FarmDashboardConfigResponse
|
|
|
|
|
>('/api/farm-dashboard-config')
|
|
|
|
|
const raw = response && 'data' in response ? response.data : response
|
|
|
|
|
if (raw && typeof raw === 'object' && ('disabled_card_ids' in raw || 'row_order' in raw)) {
|
|
|
|
|
return fromApiResponse(raw as FarmDashboardConfigResponse)
|
|
|
|
|
}
|
|
|
|
|
throw new Error('Invalid response')
|
|
|
|
|
} catch {
|
|
|
|
|
const local = getLocalConfig()
|
|
|
|
|
if (local) return local
|
|
|
|
|
return { disabledCardIds: [], rowOrder: [], enableDragReorder: true }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update farm dashboard config
|
|
|
|
|
*/
|
|
|
|
|
async updateConfig(data: Partial<FarmDashboardConfig>): Promise<FarmDashboardConfig> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await apiClient.patch<
|
|
|
|
|
ApiResponse<FarmDashboardConfigResponse> | FarmDashboardConfigResponse
|
|
|
|
|
>('/api/farm-dashboard-config', toApiRequest(data))
|
|
|
|
|
const raw = response && 'data' in response ? response.data : response
|
|
|
|
|
if (raw && typeof raw === 'object' && ('disabled_card_ids' in raw || 'row_order' in raw)) {
|
|
|
|
|
const config = fromApiResponse(raw as FarmDashboardConfigResponse)
|
|
|
|
|
setLocalConfig(config)
|
|
|
|
|
return config
|
|
|
|
|
}
|
|
|
|
|
throw new Error('Update failed')
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const local = getLocalConfig()
|
|
|
|
|
if (local) {
|
|
|
|
|
const merged: FarmDashboardConfig = {
|
|
|
|
|
disabledCardIds: data.disabledCardIds ?? local.disabledCardIds,
|
|
|
|
|
rowOrder: data.rowOrder ?? local.rowOrder,
|
|
|
|
|
enableDragReorder: data.enableDragReorder ?? local.enableDragReorder ?? true
|
|
|
|
|
}
|
|
|
|
|
setLocalConfig(merged)
|
|
|
|
|
return merged
|
|
|
|
|
}
|
|
|
|
|
throw err
|
|
|
|
|
}
|
2026-02-19 16:58:30 +03:30
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get all dashboard card data from API
|
|
|
|
|
* Response: { code: 200, msg: "OK", data: { farmOverviewKpis, farmWeatherCard, ... } }
|
|
|
|
|
*/
|
|
|
|
|
async getAllCards(): Promise<Partial<Record<CardId, Record<string, unknown>>>> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await apiClient.get<ApiResponse<FarmDashboardCardsResponse>>('/api/farm-dashboard/')
|
|
|
|
|
const raw = response?.data ?? response
|
|
|
|
|
if (raw && typeof raw === 'object') {
|
|
|
|
|
return raw as Partial<Record<CardId, Record<string, unknown>>>
|
|
|
|
|
}
|
|
|
|
|
return {}
|
|
|
|
|
} catch {
|
|
|
|
|
return {}
|
|
|
|
|
}
|
2026-02-19 15:48:32 +03:30
|
|
|
}
|
|
|
|
|
}
|