UPDATE
This commit is contained in:
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import Sensor7Page from "@/views/dashboards/farm/sensor7/Sensor7Page";
|
import Sensor7Page from "@/views/dashboards/farm/sensor7/Sensor7Page";
|
||||||
|
|
||||||
const Sensor7 = async () => {
|
const SolidSensor = async () => {
|
||||||
return <Sensor7Page />;
|
return <Sensor7Page />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Sensor7;
|
export default SolidSensor;
|
||||||
@@ -111,12 +111,17 @@ const VerticalMenu = ({ scrollMenu }: Props) => {
|
|||||||
<MenuItem href="/crop-zoning" icon={<i className="tabler-map-2" />}>
|
<MenuItem href="/crop-zoning" icon={<i className="tabler-map-2" />}>
|
||||||
{t('cropZoning')}
|
{t('cropZoning')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
</MenuSection>
|
||||||
{canShowSensor7Menu && (
|
{canShowSensor7Menu && (
|
||||||
<MenuItem href="/sensor-7" icon={<i className="tabler-sensor" />}>
|
|
||||||
|
<MenuSection label={t('sesnorSection')}>
|
||||||
|
|
||||||
|
<MenuItem href="/solid-sensor" icon={<i className="tabler-sensor" />}>
|
||||||
Sensor 7
|
Sensor 7
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
|
||||||
</MenuSection>
|
</MenuSection>
|
||||||
|
)}
|
||||||
|
|
||||||
<MenuSection label={t('simulator')}>
|
<MenuSection label={t('simulator')}>
|
||||||
<MenuItem href="/plant-simulator" icon={<i className="tabler-flower" />}>
|
<MenuItem href="/plant-simulator" icon={<i className="tabler-flower" />}>
|
||||||
{t('plantSimulator')}
|
{t('plantSimulator')}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ const PREFIX = "/api/crop-zoning";
|
|||||||
const AREA_CACHE_KEY_PREFIX = "crop-zoning:area";
|
const AREA_CACHE_KEY_PREFIX = "crop-zoning:area";
|
||||||
const AREA_CACHE_VERSION = "v1";
|
const AREA_CACHE_VERSION = "v1";
|
||||||
const AREA_CACHE_TTL_MS = 1000 * 60 * 60 * 6;
|
const AREA_CACHE_TTL_MS = 1000 * 60 * 60 * 6;
|
||||||
|
type CropZoningLayerEndpoint =
|
||||||
|
| "area"
|
||||||
|
| "water-need"
|
||||||
|
| "soil-quality"
|
||||||
|
| "cultivation-risk";
|
||||||
|
|
||||||
export interface Product {
|
export interface Product {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -217,6 +222,7 @@ function getAreaCacheUserKey(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getAreaCacheKey(
|
function getAreaCacheKey(
|
||||||
|
endpoint: CropZoningLayerEndpoint,
|
||||||
farmUuid: string,
|
farmUuid: string,
|
||||||
page: number,
|
page: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
@@ -225,6 +231,7 @@ function getAreaCacheKey(
|
|||||||
AREA_CACHE_KEY_PREFIX,
|
AREA_CACHE_KEY_PREFIX,
|
||||||
AREA_CACHE_VERSION,
|
AREA_CACHE_VERSION,
|
||||||
getAreaCacheUserKey(),
|
getAreaCacheUserKey(),
|
||||||
|
endpoint,
|
||||||
farmUuid,
|
farmUuid,
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
@@ -232,6 +239,7 @@ function getAreaCacheKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readCachedArea(
|
function readCachedArea(
|
||||||
|
endpoint: CropZoningLayerEndpoint,
|
||||||
farmUuid: string,
|
farmUuid: string,
|
||||||
page: number,
|
page: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
@@ -239,7 +247,9 @@ function readCachedArea(
|
|||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem(getAreaCacheKey(farmUuid, page, pageSize));
|
const raw = localStorage.getItem(
|
||||||
|
getAreaCacheKey(endpoint, farmUuid, page, pageSize),
|
||||||
|
);
|
||||||
|
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
return null;
|
return null;
|
||||||
@@ -248,7 +258,7 @@ function readCachedArea(
|
|||||||
const parsed = JSON.parse(raw) as CachedAreaEntry;
|
const parsed = JSON.parse(raw) as CachedAreaEntry;
|
||||||
|
|
||||||
if (!parsed?.expiresAt || parsed.expiresAt < Date.now()) {
|
if (!parsed?.expiresAt || parsed.expiresAt < Date.now()) {
|
||||||
localStorage.removeItem(getAreaCacheKey(farmUuid, page, pageSize));
|
localStorage.removeItem(getAreaCacheKey(endpoint, farmUuid, page, pageSize));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,6 +269,7 @@ function readCachedArea(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function writeCachedArea(
|
function writeCachedArea(
|
||||||
|
endpoint: CropZoningLayerEndpoint,
|
||||||
farmUuid: string,
|
farmUuid: string,
|
||||||
page: number,
|
page: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
@@ -273,7 +284,7 @@ function writeCachedArea(
|
|||||||
};
|
};
|
||||||
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
getAreaCacheKey(farmUuid, page, pageSize),
|
getAreaCacheKey(endpoint, farmUuid, page, pageSize),
|
||||||
JSON.stringify(payload),
|
JSON.stringify(payload),
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
@@ -290,6 +301,97 @@ function logAreaRequest(
|
|||||||
console.log(`[crop-zoning][area][${phase}]`, payload);
|
console.log(`[crop-zoning][area][${phase}]`, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLayerEndpointUrl(
|
||||||
|
endpoint: CropZoningLayerEndpoint,
|
||||||
|
params: URLSearchParams,
|
||||||
|
): string {
|
||||||
|
return `${PREFIX}/${endpoint}/?${params.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLayerArea(
|
||||||
|
endpoint: CropZoningLayerEndpoint,
|
||||||
|
farmUuid: string,
|
||||||
|
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
||||||
|
): Promise<CropZoningAreaResponse> {
|
||||||
|
const page = options?.page ?? 1;
|
||||||
|
const pageSize = options?.pageSize ?? 10;
|
||||||
|
const useCache = options?.useCache ?? true;
|
||||||
|
|
||||||
|
if (useCache) {
|
||||||
|
const cached = readCachedArea(endpoint, farmUuid, page, pageSize);
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
logAreaRequest("cache-hit", {
|
||||||
|
endpoint,
|
||||||
|
farmUuid,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
pagination: cached.pagination ?? null,
|
||||||
|
taskStatus: cached.task?.status ?? null,
|
||||||
|
zonesCount: cached.zones?.length ?? 0,
|
||||||
|
});
|
||||||
|
return Promise.resolve(cached);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams({ farm_uuid: farmUuid });
|
||||||
|
|
||||||
|
params.set("page", String(page));
|
||||||
|
params.set("page_size", String(pageSize));
|
||||||
|
|
||||||
|
const requestUrl = getLayerEndpointUrl(endpoint, params);
|
||||||
|
|
||||||
|
logAreaRequest("request", {
|
||||||
|
endpoint,
|
||||||
|
farmUuid,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
endpointUrl: requestUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
return unwrap(
|
||||||
|
apiClient.get<ApiResponse<CropZoningAreaResponse>>(requestUrl),
|
||||||
|
).then((response) => {
|
||||||
|
if ("task_id" in response) {
|
||||||
|
logAreaRequest("response", {
|
||||||
|
endpoint,
|
||||||
|
farmUuid,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
taskId: response.task_id,
|
||||||
|
status: response.status,
|
||||||
|
});
|
||||||
|
return normalizeTaskInitResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = normalizeAreaResult(response);
|
||||||
|
const taskStatus = normalized.task?.status?.toLowerCase();
|
||||||
|
|
||||||
|
logAreaRequest("response", {
|
||||||
|
endpoint,
|
||||||
|
farmUuid,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
taskStatus: normalized.task?.status ?? null,
|
||||||
|
pagination: normalized.pagination ?? null,
|
||||||
|
zonesCount: normalized.zones?.length ?? 0,
|
||||||
|
hasArea: Boolean(normalized.area),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
normalized.area &&
|
||||||
|
taskStatus !== "pending" &&
|
||||||
|
taskStatus !== "processing" &&
|
||||||
|
taskStatus !== "failure" &&
|
||||||
|
taskStatus !== "failed"
|
||||||
|
) {
|
||||||
|
writeCachedArea(endpoint, farmUuid, page, pageSize, normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const cropZoningService = {
|
export const cropZoningService = {
|
||||||
getProducts(): Promise<{ products: Product[] }> {
|
getProducts(): Promise<{ products: Product[] }> {
|
||||||
return unwrap(
|
return unwrap(
|
||||||
@@ -323,79 +425,28 @@ export const cropZoningService = {
|
|||||||
farmUuid: string,
|
farmUuid: string,
|
||||||
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
||||||
): Promise<CropZoningAreaResponse> {
|
): Promise<CropZoningAreaResponse> {
|
||||||
const page = options?.page ?? 1;
|
return getLayerArea("area", farmUuid, options);
|
||||||
const pageSize = options?.pageSize ?? 10;
|
},
|
||||||
const useCache = options?.useCache ?? true;
|
|
||||||
|
|
||||||
if (useCache) {
|
getWaterNeedArea(
|
||||||
const cached = readCachedArea(farmUuid, page, pageSize);
|
farmUuid: string,
|
||||||
|
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
||||||
|
): Promise<CropZoningAreaResponse> {
|
||||||
|
return getLayerArea("water-need", farmUuid, options);
|
||||||
|
},
|
||||||
|
|
||||||
if (cached) {
|
getSoilQualityArea(
|
||||||
logAreaRequest("cache-hit", {
|
farmUuid: string,
|
||||||
farmUuid,
|
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
||||||
page,
|
): Promise<CropZoningAreaResponse> {
|
||||||
pageSize,
|
return getLayerArea("soil-quality", farmUuid, options);
|
||||||
pagination: cached.pagination ?? null,
|
},
|
||||||
taskStatus: cached.task?.status ?? null,
|
|
||||||
zonesCount: cached.zones?.length ?? 0,
|
|
||||||
});
|
|
||||||
return Promise.resolve(cached);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = new URLSearchParams({ farm_uuid: farmUuid });
|
getCultivationRiskArea(
|
||||||
|
farmUuid: string,
|
||||||
params.set("page", String(page));
|
options?: { page?: number; pageSize?: number; useCache?: boolean },
|
||||||
params.set("page_size", String(pageSize));
|
): Promise<CropZoningAreaResponse> {
|
||||||
|
return getLayerArea("cultivation-risk", farmUuid, options);
|
||||||
const endpoint = `${PREFIX}/area/?${params.toString()}`;
|
|
||||||
|
|
||||||
logAreaRequest("request", {
|
|
||||||
farmUuid,
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
endpoint,
|
|
||||||
});
|
|
||||||
|
|
||||||
return unwrap(
|
|
||||||
apiClient.get<ApiResponse<CropZoningAreaResponse>>(endpoint),
|
|
||||||
).then((response) => {
|
|
||||||
if ("task_id" in response) {
|
|
||||||
logAreaRequest("response", {
|
|
||||||
farmUuid,
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
taskId: response.task_id,
|
|
||||||
status: response.status,
|
|
||||||
});
|
|
||||||
return normalizeTaskInitResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalized = normalizeAreaResult(response);
|
|
||||||
const taskStatus = normalized.task?.status?.toLowerCase();
|
|
||||||
|
|
||||||
logAreaRequest("response", {
|
|
||||||
farmUuid,
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
taskStatus: normalized.task?.status ?? null,
|
|
||||||
pagination: normalized.pagination ?? null,
|
|
||||||
zonesCount: normalized.zones?.length ?? 0,
|
|
||||||
hasArea: Boolean(normalized.area),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
normalized.area &&
|
|
||||||
taskStatus !== "pending" &&
|
|
||||||
taskStatus !== "processing" &&
|
|
||||||
taskStatus !== "failure" &&
|
|
||||||
taskStatus !== "failed"
|
|
||||||
) {
|
|
||||||
writeCachedArea(farmUuid, page, pageSize, normalized);
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getAreaStatus(
|
getAreaStatus(
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { apiClient } from "../client";
|
||||||
|
|
||||||
|
const PREFIX = "/api/sensor-external-api";
|
||||||
|
|
||||||
|
export interface SensorExternalFarmSensor {
|
||||||
|
uuid: string;
|
||||||
|
sensor_catalog_uuid: string | null;
|
||||||
|
physical_device_uuid: string;
|
||||||
|
name: string;
|
||||||
|
sensor_type: string;
|
||||||
|
is_active: boolean;
|
||||||
|
specifications?: Record<string, unknown> | null;
|
||||||
|
power_source?: Record<string, unknown> | null;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SensorExternalCatalog {
|
||||||
|
uuid: string;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
description?: string | null;
|
||||||
|
customizable_fields?: unknown[];
|
||||||
|
supported_power_sources?: unknown[];
|
||||||
|
returned_data_fields?: string[];
|
||||||
|
sample_payload?: Record<string, unknown> | null;
|
||||||
|
is_active: boolean;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SensorExternalRequestLog {
|
||||||
|
id: number;
|
||||||
|
farm_uuid: string;
|
||||||
|
sensor_catalog_uuid: string | null;
|
||||||
|
physical_device_uuid: string;
|
||||||
|
farm_sensor: SensorExternalFarmSensor | null;
|
||||||
|
sensor_catalog: SensorExternalCatalog | null;
|
||||||
|
payload: Record<string, unknown> | null;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SensorExternalRequestLogsResponse {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
count: number;
|
||||||
|
next: string | null;
|
||||||
|
previous: string | null;
|
||||||
|
data: SensorExternalRequestLog[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sensorExternalApiService = {
|
||||||
|
listRequestLogs(params: {
|
||||||
|
farmUuid: string;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
}): Promise<SensorExternalRequestLogsResponse> {
|
||||||
|
const searchParams = new URLSearchParams({ farm_uuid: params.farmUuid });
|
||||||
|
|
||||||
|
if (typeof params.page === "number") {
|
||||||
|
searchParams.set("page", String(params.page));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof params.pageSize === "number") {
|
||||||
|
searchParams.set("page_size", String(params.pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiClient.get<SensorExternalRequestLogsResponse>(
|
||||||
|
`${PREFIX}/logs/?${searchParams.toString()}`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -80,9 +80,25 @@ export default function CropZoningWrapper() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const layerLabel = t(`layers.${activeLayer}`);
|
||||||
|
const loadingMessage = `${t("loadingArea")} - ${layerLabel}`;
|
||||||
|
const getLayerArea = (() => {
|
||||||
|
switch (activeLayer) {
|
||||||
|
case "waterNeed":
|
||||||
|
return cropZoningService.getWaterNeedArea;
|
||||||
|
case "soilQuality":
|
||||||
|
return cropZoningService.getSoilQualityArea;
|
||||||
|
case "cultivationRisk":
|
||||||
|
return cropZoningService.getCultivationRiskArea;
|
||||||
|
case "crops":
|
||||||
|
default:
|
||||||
|
return cropZoningService.getArea;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setProgress({ message: t("loadingArea"), percent: 0 });
|
setProgress({ message: loadingMessage, percent: 0 });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let polls = 0;
|
let polls = 0;
|
||||||
@@ -110,7 +126,10 @@ export default function CropZoningWrapper() {
|
|||||||
|
|
||||||
setZonesData(firstPageZones as ZoneInitialData[]);
|
setZonesData(firstPageZones as ZoneInitialData[]);
|
||||||
setProgress({
|
setProgress({
|
||||||
message: totalPages > 1 ? `${t("loadingArea")} (1/${totalPages})` : completedTaskMessage || t("loadingArea"),
|
message:
|
||||||
|
totalPages > 1
|
||||||
|
? `${loadingMessage} (1/${totalPages})`
|
||||||
|
: completedTaskMessage || loadingMessage,
|
||||||
percent: totalPages > 1 ? 80 : 100,
|
percent: totalPages > 1 ? 80 : 100,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,7 +143,7 @@ export default function CropZoningWrapper() {
|
|||||||
totalPages,
|
totalPages,
|
||||||
});
|
});
|
||||||
|
|
||||||
const pageRes = await cropZoningService.getArea(farmUuid, {
|
const pageRes = await getLayerArea(farmUuid, {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
});
|
});
|
||||||
@@ -150,7 +169,7 @@ export default function CropZoningWrapper() {
|
|||||||
|
|
||||||
setZonesData(mergedZones);
|
setZonesData(mergedZones);
|
||||||
setProgress({
|
setProgress({
|
||||||
message: `${t("loadingArea")} (${pagesLoaded}/${totalPages})`,
|
message: `${loadingMessage} (${pagesLoaded}/${totalPages})`,
|
||||||
percent: Math.min(80 + pagesProgress, 100),
|
percent: Math.min(80 + pagesProgress, 100),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -158,7 +177,7 @@ export default function CropZoningWrapper() {
|
|||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setZonesData(mergeZones(zonePages));
|
setZonesData(mergeZones(zonePages));
|
||||||
setProgress({
|
setProgress({
|
||||||
message: completedTaskMessage || t("loadingArea"),
|
message: completedTaskMessage || loadingMessage,
|
||||||
percent: 100,
|
percent: 100,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -171,7 +190,7 @@ export default function CropZoningWrapper() {
|
|||||||
pageSize: ZONES_PAGE_SIZE,
|
pageSize: ZONES_PAGE_SIZE,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await cropZoningService.getArea(farmUuid, {
|
const res = await getLayerArea(farmUuid, {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: ZONES_PAGE_SIZE,
|
pageSize: ZONES_PAGE_SIZE,
|
||||||
});
|
});
|
||||||
@@ -192,7 +211,7 @@ export default function CropZoningWrapper() {
|
|||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
setProgress({
|
setProgress({
|
||||||
message: task.message || task.stage_label || t("loadingArea"),
|
message: task.message || task.stage_label || loadingMessage,
|
||||||
percent: Math.min(Math.round((task.progress_percent || 0) * 0.8), 80),
|
percent: Math.min(Math.round((task.progress_percent || 0) * 0.8), 80),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -200,13 +219,13 @@ export default function CropZoningWrapper() {
|
|||||||
if (taskStatus === "completed" || taskStatus === "success") {
|
if (taskStatus === "completed" || taskStatus === "success") {
|
||||||
await loadAllZonePages(
|
await loadAllZonePages(
|
||||||
res,
|
res,
|
||||||
task?.message || task?.stage_label || t("loadingArea"),
|
task?.message || task?.stage_label || loadingMessage,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!task && res.area) || (res.area && taskStatus !== "pending" && taskStatus !== "processing")) {
|
if ((!task && res.area) || (res.area && taskStatus !== "pending" && taskStatus !== "processing")) {
|
||||||
await loadAllZonePages(res, task?.message || task?.stage_label || t("loadingArea"));
|
await loadAllZonePages(res, task?.message || task?.stage_label || loadingMessage);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,20 +256,54 @@ export default function CropZoningWrapper() {
|
|||||||
|
|
||||||
loadArea();
|
loadArea();
|
||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, [farmUuid, isClientReady, t]);
|
}, [activeLayer, farmUuid, isClientReady, t]);
|
||||||
|
|
||||||
const mapZonesData = useMemo(() => {
|
const mapZonesData = useMemo(() => {
|
||||||
if (activeLayer === "crops" && zonesData) {
|
if (!zonesData) return null;
|
||||||
return zonesData.map(z => ({
|
|
||||||
|
return zonesData.map(z => {
|
||||||
|
if (activeLayer === "waterNeed") {
|
||||||
|
return {
|
||||||
|
zoneId: z.zoneId,
|
||||||
|
geometry: z.geometry,
|
||||||
|
color: z.waterNeedLayer?.color || "#94a3b8",
|
||||||
|
tooltipContent: `<div style="padding: 4px 8px;">${z.waterNeedLayer?.value || z.waterNeedLayer?.level || "نامشخص"}</div>`,
|
||||||
|
cultivable: false,
|
||||||
|
zoneInitialData: z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeLayer === "soilQuality") {
|
||||||
|
return {
|
||||||
|
zoneId: z.zoneId,
|
||||||
|
geometry: z.geometry,
|
||||||
|
color: z.soilQualityLayer?.color || "#94a3b8",
|
||||||
|
tooltipContent: `<div style="padding: 4px 8px;">${z.soilQualityLayer?.score ?? z.soilQualityLayer?.level ?? "نامشخص"}</div>`,
|
||||||
|
cultivable: false,
|
||||||
|
zoneInitialData: z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeLayer === "cultivationRisk") {
|
||||||
|
return {
|
||||||
|
zoneId: z.zoneId,
|
||||||
|
geometry: z.geometry,
|
||||||
|
color: z.cultivationRiskLayer?.color || "#94a3b8",
|
||||||
|
tooltipContent: `<div style="padding: 4px 8px;">${z.cultivationRiskLayer?.level || "نامشخص"}</div>`,
|
||||||
|
cultivable: false,
|
||||||
|
zoneInitialData: z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
zoneId: z.zoneId,
|
zoneId: z.zoneId,
|
||||||
geometry: z.geometry,
|
geometry: z.geometry,
|
||||||
color: z.crop ? CROP_COLORS[z.crop as CropType] || "#94a3b8" : "#94a3b8",
|
color: z.crop ? CROP_COLORS[z.crop as CropType] || "#94a3b8" : "#94a3b8",
|
||||||
tooltipContent: `<div style="padding: 4px 8px;">${z.crop || "نامشخص"}</div>`,
|
tooltipContent: `<div style="padding: 4px 8px;">${z.crop || "نامشخص"}</div>`,
|
||||||
cultivable: !!z.crop,
|
cultivable: !!z.crop,
|
||||||
zoneInitialData: z,
|
zoneInitialData: z,
|
||||||
}));
|
};
|
||||||
}
|
});
|
||||||
return null;
|
|
||||||
}, [activeLayer, zonesData]);
|
}, [activeLayer, zonesData]);
|
||||||
|
|
||||||
const handleZoneClick = useCallback((zone: ZoneInitialData) => {
|
const handleZoneClick = useCallback((zone: ZoneInitialData) => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user