210 lines
5.6 KiB
TypeScript
210 lines
5.6 KiB
TypeScript
import { useEffect, useMemo, useState } from "react";
|
|
import {
|
|
fetchConcentrators,
|
|
type Concentrator,
|
|
type ConcentratorType,
|
|
} from "../../api/concentrators";
|
|
import { fetchProjects, type Project } from "../../api/projects";
|
|
import type { ProjectCard, SampleView } from "./ConcentratorsPage";
|
|
|
|
type User = {
|
|
role: "SUPER_ADMIN" | "USER";
|
|
project?: string;
|
|
};
|
|
|
|
export function useConcentrators(currentUser: User) {
|
|
const [sampleView, setSampleView] = useState<SampleView>("GENERAL");
|
|
|
|
const [loadingProjects, setLoadingProjects] = useState(true);
|
|
const [loadingConcentrators, setLoadingConcentrators] = useState(true);
|
|
|
|
const [projects, setProjects] = useState<Project[]>([]);
|
|
const [allProjects, setAllProjects] = useState<string[]>([]);
|
|
const [selectedProject, setSelectedProject] = useState("");
|
|
|
|
const [concentrators, setConcentrators] = useState<Concentrator[]>([]);
|
|
const [filteredConcentrators, setFilteredConcentrators] = useState<
|
|
Concentrator[]
|
|
>([]);
|
|
|
|
const isGeneral = sampleView === "GENERAL";
|
|
|
|
const sampleViewLabel = useMemo(() => {
|
|
switch (sampleView) {
|
|
case "GENERAL":
|
|
return "General";
|
|
case "LORA":
|
|
return "LoRa";
|
|
case "LORAWAN":
|
|
return "LoRaWAN";
|
|
case "GRANDES":
|
|
return "Grandes consumidores";
|
|
default:
|
|
return "General";
|
|
}
|
|
}, [sampleView]);
|
|
|
|
const visibleProjects = useMemo(
|
|
() =>
|
|
currentUser.role === "SUPER_ADMIN"
|
|
? allProjects
|
|
: currentUser.project
|
|
? [currentUser.project]
|
|
: [],
|
|
[allProjects, currentUser.role, currentUser.project]
|
|
);
|
|
|
|
const loadProjects = async () => {
|
|
setLoadingProjects(true);
|
|
try {
|
|
const projectsData = await fetchProjects();
|
|
setProjects(projectsData);
|
|
const projectIds = projectsData.map((p) => p.id);
|
|
setAllProjects(projectIds);
|
|
|
|
setSelectedProject((prev) => {
|
|
if (prev) return prev;
|
|
if (currentUser.role !== "SUPER_ADMIN" && currentUser.project) {
|
|
return currentUser.project;
|
|
}
|
|
return projectIds[0] ?? "";
|
|
});
|
|
} catch (err) {
|
|
console.error("Error loading projects:", err);
|
|
setProjects([]);
|
|
setAllProjects([]);
|
|
} finally {
|
|
setLoadingProjects(false);
|
|
}
|
|
};
|
|
|
|
const loadConcentrators = async () => {
|
|
setLoadingConcentrators(true);
|
|
|
|
try {
|
|
const data = await fetchConcentrators();
|
|
setConcentrators(data);
|
|
} catch (err) {
|
|
console.error("Error loading concentrators:", err);
|
|
setConcentrators([]);
|
|
} finally {
|
|
setLoadingConcentrators(false);
|
|
}
|
|
};
|
|
|
|
// init - load projects and concentrators
|
|
useEffect(() => {
|
|
loadProjects();
|
|
loadConcentrators();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
// view changes
|
|
useEffect(() => {
|
|
loadProjects();
|
|
loadConcentrators();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [sampleView]);
|
|
|
|
// auto select single visible project
|
|
useEffect(() => {
|
|
if (!isGeneral) return;
|
|
if (!selectedProject && visibleProjects.length === 1) {
|
|
setSelectedProject(visibleProjects[0]);
|
|
}
|
|
}, [visibleProjects, selectedProject, isGeneral]);
|
|
|
|
useEffect(() => {
|
|
let filtered = concentrators;
|
|
|
|
if (selectedProject) {
|
|
filtered = filtered.filter((c) => c.projectId === selectedProject);
|
|
}
|
|
|
|
if (!isGeneral) {
|
|
const typeMap: Record<Exclude<SampleView, "GENERAL">, ConcentratorType> = {
|
|
LORA: "LORA",
|
|
LORAWAN: "LORAWAN",
|
|
GRANDES: "GRANDES",
|
|
};
|
|
const targetType = typeMap[sampleView as Exclude<SampleView, "GENERAL">];
|
|
filtered = filtered.filter((c) => c.type === targetType);
|
|
}
|
|
|
|
setFilteredConcentrators(filtered);
|
|
}, [selectedProject, concentrators, isGeneral, sampleView]);
|
|
|
|
// sidebar cards (general)
|
|
const projectsDataGeneral: ProjectCard[] = useMemo(() => {
|
|
let concentratorsToCount = concentrators;
|
|
|
|
if (!isGeneral) {
|
|
const typeMap: Record<Exclude<SampleView, "GENERAL">, ConcentratorType> = {
|
|
LORA: "LORA",
|
|
LORAWAN: "LORAWAN",
|
|
GRANDES: "GRANDES",
|
|
};
|
|
const targetType = typeMap[sampleView as Exclude<SampleView, "GENERAL">];
|
|
concentratorsToCount = concentrators.filter((c) => c.type === targetType);
|
|
}
|
|
|
|
const counts = concentratorsToCount.reduce<Record<string, number>>((acc, c) => {
|
|
const project = c.projectId ?? "SIN PROYECTO";
|
|
acc[project] = (acc[project] ?? 0) + 1;
|
|
return acc;
|
|
}, {});
|
|
|
|
const projectNameMap = projects.reduce<Record<string, string>>((acc, p) => {
|
|
acc[p.id] = p.name;
|
|
return acc;
|
|
}, {});
|
|
|
|
const baseRegion = "Baja California";
|
|
const baseContact = "Operaciones";
|
|
const baseLastSync = "Hace 1 h";
|
|
|
|
return visibleProjects.map((projectId) => ({
|
|
id: projectId,
|
|
name: projectNameMap[projectId] ?? projectId,
|
|
region: baseRegion,
|
|
projects: 1,
|
|
concentrators: counts[projectId] ?? 0,
|
|
activeAlerts: 0,
|
|
lastSync: baseLastSync,
|
|
contact: baseContact,
|
|
status: "ACTIVO" as const,
|
|
}));
|
|
}, [concentrators, visibleProjects, projects, isGeneral, sampleView]);
|
|
|
|
const projectsData: ProjectCard[] = useMemo(() => {
|
|
return projectsDataGeneral;
|
|
}, [projectsDataGeneral]);
|
|
|
|
return {
|
|
// view
|
|
sampleView,
|
|
setSampleView,
|
|
sampleViewLabel,
|
|
isGeneral,
|
|
|
|
// loading
|
|
loadingProjects,
|
|
loadingConcentrators,
|
|
|
|
// projects
|
|
allProjects,
|
|
visibleProjects,
|
|
projectsData,
|
|
selectedProject,
|
|
setSelectedProject,
|
|
|
|
// data
|
|
concentrators,
|
|
setConcentrators,
|
|
filteredConcentrators,
|
|
|
|
// actions
|
|
loadConcentrators,
|
|
};
|
|
}
|