UPDATE
This commit is contained in:
@@ -23,6 +23,7 @@ import StyledVerticalNavExpandIcon from "@menu/styles/vertical/StyledVerticalNav
|
||||
// Style Imports
|
||||
import menuItemStyles from "@core/styles/vertical/menuItemStyles";
|
||||
import menuSectionStyles from "@core/styles/vertical/menuSectionStyles";
|
||||
import { navigationLabels } from "@/constants/navigation";
|
||||
|
||||
// Menu Data Imports
|
||||
// import menuData from '@/data/navigation/verticalMenuData'
|
||||
@@ -53,6 +54,9 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
|
||||
const theme = useTheme();
|
||||
const verticalNavOptions = useVerticalNav();
|
||||
|
||||
const translateNav = (key: keyof typeof navigationLabels) =>
|
||||
t.has(key) ? t(key) : navigationLabels[key];
|
||||
|
||||
// Vars
|
||||
const { isBreakpointReached, transitionDuration } = verticalNavOptions;
|
||||
|
||||
@@ -92,102 +96,102 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
|
||||
href={`/dashboard`}
|
||||
icon={<i className="tabler-smart-home" />}
|
||||
>
|
||||
{t("dashboards")}
|
||||
{translateNav("dashboards")}
|
||||
</MenuItem>
|
||||
|
||||
|
||||
<MenuSection label={t("farmManagement")}>
|
||||
<MenuSection label={translateNav("farmManagement")}>
|
||||
<MenuItem
|
||||
href="/yield-harvest"
|
||||
icon={<i className="tabler-chart-line" />}
|
||||
>
|
||||
{t("yieldHarvest")}
|
||||
{translateNav("yieldHarvest")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/farmer-todos"
|
||||
icon={<i className="tabler-checklist" />}
|
||||
>
|
||||
{t("farmerTodos")}
|
||||
{translateNav("farmerTodos")}
|
||||
</MenuItem>
|
||||
<MenuItem href="/wallet" icon={<i className="tabler-wallet" />}>
|
||||
{t("farmWallet")}
|
||||
{translateNav("farmWallet")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/farmer-calendar"
|
||||
icon={<i className="tabler-calendar-event" />}
|
||||
>
|
||||
{t("farmCalendar")}
|
||||
{translateNav("farmCalendar")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/economy"
|
||||
icon={<i className="tabler-cash-banknote" />}
|
||||
>
|
||||
{t("economicOverview")}
|
||||
{translateNav("economicOverview")}
|
||||
</MenuItem>
|
||||
</MenuSection>
|
||||
|
||||
<MenuSection label={t("riskAlerts")}>
|
||||
<MenuSection label={translateNav("riskAlerts")}>
|
||||
|
||||
<MenuItem
|
||||
href="/farm-alerts"
|
||||
icon={<i className="tabler-alert-triangle" />}
|
||||
>
|
||||
{t("farmAlerts")}
|
||||
{translateNav("farmAlerts")}
|
||||
</MenuItem>
|
||||
<MenuItem href="/pest-risk" icon={<i className="tabler-bug" />}>
|
||||
{t("pestDiseaseRisk")}
|
||||
{translateNav("pestDiseaseRisk")}
|
||||
</MenuItem>
|
||||
|
||||
</MenuSection>
|
||||
<MenuSection label={t("monitoring")}>
|
||||
<MenuSection label={translateNav("monitoring")}>
|
||||
<MenuItem href="/water-data" icon={<i className="tabler-droplet" />}>
|
||||
{t("waterData")}
|
||||
{translateNav("waterData")}
|
||||
</MenuItem>
|
||||
<MenuItem href="/soil-data" icon={<i className="tabler-seedling" />}>
|
||||
{t("soilData")}
|
||||
{translateNav("soilData")}
|
||||
</MenuItem>
|
||||
<MenuItem href="/crop-zoning" icon={<i className="tabler-map-2" />}>
|
||||
{t("cropZoning")}
|
||||
{translateNav("cropZoning")}
|
||||
</MenuItem>
|
||||
<SubMenu label={t("sensors")} icon={<i className="tabler-device-analytics" />}>
|
||||
<SubMenu label={translateNav("sensors")} icon={<i className="tabler-device-analytics" />}>
|
||||
<MenuItem href="/solid-sensor" icon={<i className="tabler-device-analytics" />}>
|
||||
{t("sensor7In1")}
|
||||
{translateNav("sensor7In1")}
|
||||
</MenuItem>
|
||||
</SubMenu>
|
||||
</MenuSection>
|
||||
|
||||
<MenuSection label={t("recommendation")}>
|
||||
<MenuSection label={translateNav("recommendation")}>
|
||||
<MenuItem
|
||||
href="/irrigation-plan"
|
||||
icon={<i className="tabler-droplet-half-2" />}
|
||||
>
|
||||
{t("irrigationPlanParser")}
|
||||
{translateNav("irrigationPlanParser")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/irrigation-recommendation"
|
||||
icon={<i className="tabler-droplet-half-2" />}
|
||||
>
|
||||
{t("irrigationRecommendation")}
|
||||
{translateNav("irrigationRecommendation")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/fertilization-recommendation"
|
||||
icon={<i className="tabler-atom-2" />}
|
||||
>
|
||||
{t("fertilizationRecommendation")}
|
||||
{translateNav("fertilizationRecommendation")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
href="/fertilization-plan"
|
||||
icon={<i className="tabler-sparkles" />}
|
||||
>
|
||||
{t("fertilizationPlanParser")}
|
||||
{translateNav("fertilizationPlanParser")}
|
||||
</MenuItem>
|
||||
</MenuSection>
|
||||
<MenuSection label={t("aiAssistant")}>
|
||||
<MenuSection label={translateNav("aiAssistant")}>
|
||||
<MenuItem
|
||||
href="/farm-ai-assistant"
|
||||
icon={<i className="tabler-robot" />}
|
||||
>
|
||||
{t("farmAiAssistant")}
|
||||
{translateNav("farmAiAssistant")}
|
||||
</MenuItem>
|
||||
</MenuSection>
|
||||
</Menu>
|
||||
|
||||
@@ -36,6 +36,5 @@ export * from "./services/rolesPermissionsService";
|
||||
export * from "./services/farmHubService";
|
||||
export {
|
||||
type FarmDashboardConfigResponse,
|
||||
type FarmDashboardCardsResponse,
|
||||
farmDashboardService,
|
||||
} from "./services/farmDashboardService";
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* Farm Dashboard Service
|
||||
* Handles API calls for dashboard config and card data.
|
||||
* Handles API calls for dashboard config only.
|
||||
* - Config: disabled cards, row order, drag reorder
|
||||
* - Cards: all 15 card payloads from /api/farm-dashboard/
|
||||
*/
|
||||
|
||||
import { apiClient } from "../client";
|
||||
@@ -29,36 +28,6 @@ export interface FarmDashboardConfigResponse {
|
||||
enable_drag_reorder?: boolean;
|
||||
}
|
||||
|
||||
/** 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>;
|
||||
}
|
||||
|
||||
interface FarmDashboardCardsTaskResult {
|
||||
farm_uuid?: string;
|
||||
all_cards?: FarmDashboardCardsResponse;
|
||||
}
|
||||
|
||||
interface FarmDashboardCardsTaskData {
|
||||
task_id?: string;
|
||||
status?: string;
|
||||
result?: FarmDashboardCardsTaskResult;
|
||||
}
|
||||
|
||||
const STORAGE_KEY_PREFIX = "farm_dashboard_config";
|
||||
|
||||
function getStorageKey(farmUuid: string): string {
|
||||
@@ -101,28 +70,6 @@ function normalizeRowOrder(rowOrder: string[] = []): string[] {
|
||||
: [...ROW_IDS];
|
||||
}
|
||||
|
||||
function extractCardsPayload(
|
||||
response:
|
||||
| ApiResponse<FarmDashboardCardsResponse>
|
||||
| ApiResponse<FarmDashboardCardsTaskData>
|
||||
| FarmDashboardCardsResponse
|
||||
| FarmDashboardCardsTaskData,
|
||||
): Partial<Record<CardId, Record<string, unknown>>> {
|
||||
const raw = response && "data" in response ? response.data : response;
|
||||
|
||||
if (!raw || typeof raw !== "object") {
|
||||
return {};
|
||||
}
|
||||
|
||||
if ("result" in raw && raw.result && typeof raw.result === "object") {
|
||||
return (raw.result.all_cards ?? {}) as Partial<
|
||||
Record<CardId, Record<string, unknown>>
|
||||
>;
|
||||
}
|
||||
|
||||
return raw as Partial<Record<CardId, Record<string, unknown>>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform API response to frontend config format
|
||||
*/
|
||||
@@ -242,26 +189,4 @@ export const farmDashboardService = {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all dashboard card data from API
|
||||
* Response: { code: 200, msg: "OK", data: { farmOverviewKpis, farmWeatherCard, ... } }
|
||||
*/
|
||||
async getAllCards(
|
||||
farmUuid: string,
|
||||
): Promise<
|
||||
Partial<Record<CardId, Record<string, unknown>>>
|
||||
> {
|
||||
try {
|
||||
const response = await apiClient.get<
|
||||
| ApiResponse<FarmDashboardCardsResponse>
|
||||
| ApiResponse<FarmDashboardCardsTaskData>
|
||||
| FarmDashboardCardsResponse
|
||||
| FarmDashboardCardsTaskData
|
||||
>(`/api/farm-dashboard/?${buildFarmQuery(farmUuid)}`);
|
||||
return extractCardsPayload(response);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
// React Imports
|
||||
import type { RefObject } from "react";
|
||||
import type { ComponentType, RefObject } from "react";
|
||||
import { useEffect, useMemo, useState, useCallback, useContext } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useFarmHub } from "@/hooks/useFarmHub";
|
||||
import { format } from "date-fns";
|
||||
|
||||
// Context Imports
|
||||
import NavbarSlotContext from "@/contexts/navbarSlotContext";
|
||||
@@ -47,6 +48,18 @@ import {
|
||||
type FarmDashboardConfig,
|
||||
} from "@views/dashboards/farm/farmDashboardConfig";
|
||||
import { farmDashboardService } from "@/libs/api/services/farmDashboardService";
|
||||
import {
|
||||
farmAlertsService,
|
||||
type FarmAlertsTrackerResponse,
|
||||
type FarmAlertNotificationItem,
|
||||
type FarmAlertTrackerItem,
|
||||
} from "@/libs/api/services/farmAlertsService";
|
||||
import { waterService } from "@/libs/api/services/waterService";
|
||||
import { sensor7Service } from "@/libs/api/services/sensor7Service";
|
||||
import { soilService } from "@/libs/api/services/soilService";
|
||||
import { cropHealthService } from "@/libs/api/services/cropHealthService";
|
||||
import { economicOverviewService } from "@/libs/api/services/economicOverviewService";
|
||||
import { yieldHarvestService } from "@/libs/api/services/yieldHarvestService";
|
||||
import FarmDashboardSettingsDropdown from "@views/dashboards/farm/FarmDashboardSettingsDropdown";
|
||||
|
||||
const cardRowSx = {
|
||||
@@ -57,7 +70,7 @@ const cardRowSx = {
|
||||
|
||||
const CARD_COMPONENTS: Record<
|
||||
CardId,
|
||||
React.ComponentType<{ data?: Record<string, unknown> }>
|
||||
ComponentType<{ data?: Record<string, unknown> }>
|
||||
> = {
|
||||
farmOverviewKpis: FarmOverviewKPIs,
|
||||
farmWeatherCard: FarmWeatherCard,
|
||||
@@ -96,6 +109,264 @@ function areStringArraysEqual(left: string[], right: string[]): boolean {
|
||||
return left.every((value, index) => value === right[index]);
|
||||
}
|
||||
|
||||
function getSeverityColor(
|
||||
value?: string,
|
||||
): "primary" | "warning" | "error" | "info" | "success" {
|
||||
switch (value?.toLowerCase()) {
|
||||
case "critical":
|
||||
case "danger":
|
||||
case "error":
|
||||
case "high":
|
||||
return "error";
|
||||
case "warning":
|
||||
case "medium":
|
||||
return "warning";
|
||||
case "success":
|
||||
return "success";
|
||||
case "low":
|
||||
case "info":
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
}
|
||||
|
||||
function buildTrackerCardData(
|
||||
result: FarmAlertsTrackerResponse,
|
||||
): Record<string, unknown> {
|
||||
const tracker = result.tracker ?? {};
|
||||
const totalAlerts = tracker.totalAlerts ?? 0;
|
||||
const alertStats = Array.isArray(tracker.alertStats) ? tracker.alertStats : [];
|
||||
const safeTotal = Math.max(totalAlerts, 1);
|
||||
const criticalCount = (
|
||||
alertStats as Array<Record<string, unknown>>
|
||||
).reduce((sum, item) => {
|
||||
const severity = String(item.severity ?? "").toLowerCase();
|
||||
|
||||
return severity === "high" ||
|
||||
severity === "critical" ||
|
||||
severity === "danger"
|
||||
? sum + Number(item.count ?? 0)
|
||||
: sum;
|
||||
}, 0);
|
||||
|
||||
return {
|
||||
totalAlerts,
|
||||
alertStats: alertStats.map((item, index) => ({
|
||||
title: String(item.title ?? `Alert ${index + 1}`),
|
||||
count: String(item.count ?? "0"),
|
||||
avatarIcon: String(item.avatarIcon ?? "tabler-alert-triangle"),
|
||||
avatarColor: getSeverityColor(
|
||||
String(item.severity ?? item.avatarColor ?? result.status_level),
|
||||
),
|
||||
})),
|
||||
radialBarValue: Math.min(Math.round((criticalCount / safeTotal) * 100), 100),
|
||||
};
|
||||
}
|
||||
|
||||
function buildTimelineData(
|
||||
result: FarmAlertsTrackerResponse,
|
||||
notifications: FarmAlertNotificationItem[],
|
||||
): Record<string, unknown> {
|
||||
const trackerAlerts = Array.isArray(result.tracker?.alerts)
|
||||
? result.tracker.alerts
|
||||
: [];
|
||||
|
||||
if (notifications.length > 0) {
|
||||
return {
|
||||
alerts: notifications.map((item) => ({
|
||||
title: item.title,
|
||||
description: item.suggested_action || item.message,
|
||||
time: format(new Date(item.created_at), "yyyy-MM-dd HH:mm"),
|
||||
color: getSeverityColor(item.level),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
alerts: trackerAlerts.map((item: FarmAlertTrackerItem, index: number) => ({
|
||||
title: item.title || `Alert ${index + 1}`,
|
||||
description:
|
||||
item.explanation || item.summary || item.recommended_action || "",
|
||||
time:
|
||||
item.duration ||
|
||||
(item.timestamp
|
||||
? format(new Date(item.timestamp), "yyyy-MM-dd HH:mm")
|
||||
: "-"),
|
||||
color: getSeverityColor(item.severity || result.status_level),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function buildRecommendationsData(
|
||||
result: FarmAlertsTrackerResponse,
|
||||
): Record<string, unknown> {
|
||||
const tracker = result.tracker ?? {};
|
||||
const actions = Array.isArray(tracker.recommendedOperationalActions)
|
||||
? tracker.recommendedOperationalActions
|
||||
: [];
|
||||
const explanations = Array.isArray(tracker.humanReadableExplanations)
|
||||
? tracker.humanReadableExplanations
|
||||
: [];
|
||||
|
||||
return {
|
||||
recommendations: actions.map((action, index) => ({
|
||||
title: `اقدام پیشنهادی ${index + 1}`,
|
||||
subtitle: explanations[index] || action,
|
||||
avatarIcon: "tabler-arrow-up-right",
|
||||
avatarColor: getSeverityColor(result.status_level),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async function loadDashboardCardData(
|
||||
cardId: CardId,
|
||||
farmUuid: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
switch (cardId) {
|
||||
case "farmOverviewKpis": {
|
||||
const summary = await yieldHarvestService.getSummary(farmUuid);
|
||||
return (summary.yield_prediction as Record<string, unknown>) ?? {};
|
||||
}
|
||||
case "farmWeatherCard":
|
||||
return await waterService.getWeatherFarmCard(farmUuid);
|
||||
case "farmAlertsTracker": {
|
||||
const result = await farmAlertsService.analyzeTracker({ farmUuid });
|
||||
return buildTrackerCardData(result);
|
||||
}
|
||||
case "sensorValuesList":
|
||||
return (await sensor7Service.getValuesList({ farmUuid })) as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
case "sensorRadarChart":
|
||||
return (await sensor7Service.getRadarChart({ farmUuid })) as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
case "sensorComparisonChart":
|
||||
return (await sensor7Service.getComparisonChart({
|
||||
farmUuid,
|
||||
})) as unknown as Record<string, unknown>;
|
||||
case "anomalyDetectionCard":
|
||||
return await soilService.getAnomalies(farmUuid);
|
||||
case "farmAlertsTimeline": {
|
||||
const result = await farmAlertsService.analyzeTracker({ farmUuid });
|
||||
const notifications = Array.isArray(result.notifications)
|
||||
? result.notifications
|
||||
: [];
|
||||
return buildTimelineData(result, notifications);
|
||||
}
|
||||
case "waterNeedPrediction":
|
||||
return await waterService.getNeedPrediction(farmUuid);
|
||||
case "harvestPredictionCard":
|
||||
return (await yieldHarvestService.getHarvestPrediction(
|
||||
farmUuid,
|
||||
)) as unknown as Record<string, unknown>;
|
||||
case "yieldPredictionChart": {
|
||||
const summary = await yieldHarvestService.getSummary(farmUuid);
|
||||
return (summary.yieldPredictionChart as Record<string, unknown>) ?? {};
|
||||
}
|
||||
case "soilMoistureHeatmap":
|
||||
return await soilService.getMoistureHeatmap(farmUuid);
|
||||
case "ndviHealthCard": {
|
||||
const summary = await cropHealthService.getSummary(farmUuid);
|
||||
return (summary.ndviHealthCard as Record<string, unknown>) ?? {};
|
||||
}
|
||||
case "recommendationsList": {
|
||||
const result = await farmAlertsService.analyzeTracker({ farmUuid });
|
||||
return buildRecommendationsData(result);
|
||||
}
|
||||
case "economicOverview": {
|
||||
const summary = await economicOverviewService.getSummary(farmUuid);
|
||||
return (summary.economicOverview as Record<string, unknown>) ?? {};
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
type FarmDashboardCardProps = {
|
||||
cardId: CardId;
|
||||
farmUuid?: string;
|
||||
overview?: boolean;
|
||||
};
|
||||
|
||||
const FarmDashboardCard = ({
|
||||
cardId,
|
||||
farmUuid,
|
||||
overview = false,
|
||||
}: FarmDashboardCardProps) => {
|
||||
const [data, setData] = useState<Record<string, unknown> | null>(null);
|
||||
const [loading, setLoading] = useState(Boolean(farmUuid));
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
if (!farmUuid) {
|
||||
setData(null);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
loadDashboardCardData(cardId, farmUuid)
|
||||
.then((nextData) => {
|
||||
if (active) {
|
||||
setData(nextData);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (active) {
|
||||
setData(null);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (active) {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [cardId, farmUuid]);
|
||||
|
||||
if (loading) {
|
||||
if (overview) {
|
||||
return (
|
||||
<Grid size={12}>
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
minHeight={180}
|
||||
>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
minHeight={200}
|
||||
>
|
||||
<CircularProgress size={28} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
const Component = CARD_COMPONENTS[cardId];
|
||||
|
||||
return Component ? <Component data={data} /> : null;
|
||||
};
|
||||
|
||||
const FarmDashboardWrapper = () => {
|
||||
const t = useTranslations("farmDashboard");
|
||||
const { farmHub } = useFarmHub();
|
||||
@@ -151,9 +422,6 @@ const FarmDashboardWrapper = () => {
|
||||
[t],
|
||||
);
|
||||
|
||||
const [cardsData, setCardsData] = useState<
|
||||
Partial<Record<CardId, Record<string, unknown>>>
|
||||
>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
@@ -168,7 +436,7 @@ const FarmDashboardWrapper = () => {
|
||||
if (!Array.isArray(cards)) return false;
|
||||
return cards.some((cardId) => !disabledSet.has(cardId));
|
||||
},
|
||||
[config.disabledCardIds],
|
||||
[disabledSet],
|
||||
);
|
||||
|
||||
const visibleRowOrder = useMemo(
|
||||
@@ -193,18 +461,15 @@ const FarmDashboardWrapper = () => {
|
||||
useEffect(() => {
|
||||
if (!farmUuid) {
|
||||
setConfig(DEFAULT_FARM_DASHBOARD_CONFIG);
|
||||
setCardsData({});
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
Promise.all([
|
||||
farmDashboardService.getConfig(farmUuid),
|
||||
farmDashboardService.getAllCards(farmUuid),
|
||||
])
|
||||
.then(([configData, cards]) => {
|
||||
farmDashboardService
|
||||
.getConfig(farmUuid)
|
||||
.then((configData) => {
|
||||
const validRowOrder = (configData.rowOrder ?? []).filter(
|
||||
(id): id is RowId => id in ROW_CARDS,
|
||||
);
|
||||
@@ -214,7 +479,6 @@ const FarmDashboardWrapper = () => {
|
||||
enableDragReorder: configData.enableDragReorder ?? true,
|
||||
};
|
||||
setConfig(merged);
|
||||
setCardsData(cards ?? {});
|
||||
})
|
||||
.catch(() => setConfig(DEFAULT_FARM_DASHBOARD_CONFIG))
|
||||
.finally(() => setLoading(false));
|
||||
@@ -356,16 +620,18 @@ const FarmDashboardWrapper = () => {
|
||||
)}
|
||||
<Grid container spacing={6} sx={{ flex: 1, minWidth: 0 }}>
|
||||
{isOverviewRow && cards.includes("farmOverviewKpis") && (
|
||||
<FarmOverviewKPIs data={cardsData?.farmOverviewKpis} />
|
||||
<FarmDashboardCard
|
||||
cardId="farmOverviewKpis"
|
||||
farmUuid={farmUuid}
|
||||
overview
|
||||
/>
|
||||
)}
|
||||
{!isOverviewRow &&
|
||||
cards.map((cardId: CardId) => {
|
||||
const size = CARD_GRID_SIZE[cardId];
|
||||
const Component = CARD_COMPONENTS[cardId];
|
||||
if (!Component) return null;
|
||||
return (
|
||||
<Grid key={cardId} size={size} sx={cardRowSx}>
|
||||
<Component data={cardsData?.[cardId]} />
|
||||
<FarmDashboardCard cardId={cardId} farmUuid={farmUuid} />
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user