diff --git a/src/pages/concentrators/ConcentratorsPage.tsx b/src/pages/concentrators/ConcentratorsPage.tsx
index e61021f..ff85954 100644
--- a/src/pages/concentrators/ConcentratorsPage.tsx
+++ b/src/pages/concentrators/ConcentratorsPage.tsx
@@ -170,6 +170,15 @@ export default function ConcentratorsPage() {
projects={c.projectsData}
onRefresh={c.loadConcentrators}
refreshDisabled={c.loadingProjects}
+ meterTypes={c.meterTypes}
+ selectedMeterTypeId={c.selectedMeterTypeId}
+ onSelectMeterTypeId={(id: string) => {
+ c.setSelectedMeterTypeId(id);
+ c.setSelectedProject("");
+ setActiveConcentrator(null);
+ setSearch("");
+ }}
+ loadingMeterTypes={c.loadingMeterTypes}
/>
@@ -181,7 +190,9 @@ export default function ConcentratorsPage() {
Concentrator Management
- {c.selectedProject
+ {c.projectsData.length === 0 && c.selectedMeterTypeId
+ ? `No hay proyectos disponibles con el filtro seleccionado`
+ : c.selectedProject
? `Proyecto: ${c.selectedProject} • Tipo: ${c.sampleViewLabel}`
: "Selecciona un proyecto desde el panel izquierdo"}
@@ -190,7 +201,7 @@ export default function ConcentratorsPage() {
Agregar
@@ -214,6 +225,7 @@ export default function ConcentratorsPage() {
Actualizar
@@ -222,11 +234,11 @@ export default function ConcentratorsPage() {
setSearch(e.target.value)}
- disabled={!c.selectedProject}
+ disabled={!c.selectedProject || c.projectsData.length === 0}
/>
@@ -236,7 +248,11 @@ export default function ConcentratorsPage() {
activeRowId={activeConcentrator?.id}
onRowClick={(row) => setActiveConcentrator(row)}
emptyMessage={
- !c.selectedProject
+ c.projectsData.length === 0 && c.selectedMeterTypeId
+ ? `No hay proyectos con el tipo de toma seleccionado (${
+ c.meterTypes.find((mt) => mt.id === c.selectedMeterTypeId)?.name ?? "desconocido"
+ }) que tengan concentradores.`
+ : !c.selectedProject
? "Selecciona un proyecto para ver los concentradores."
: c.loadingConcentrators
? "Cargando concentradores..."
diff --git a/src/pages/concentrators/ConcentratorsSidebar.tsx b/src/pages/concentrators/ConcentratorsSidebar.tsx
index 694f256..e956e2d 100644
--- a/src/pages/concentrators/ConcentratorsSidebar.tsx
+++ b/src/pages/concentrators/ConcentratorsSidebar.tsx
@@ -1,7 +1,8 @@
// src/pages/concentrators/ConcentratorsSidebar.tsx
import { useMemo } from "react";
-import { ChevronDown, Check, RefreshCcw } from "lucide-react";
+import { Check, RefreshCcw } from "lucide-react";
import type { ProjectCard, SampleView } from "./ConcentratorsPage";
+import type { MeterType } from "../../api/meterTypes";
type Props = {
loadingProjects: boolean;
@@ -23,6 +24,11 @@ type Props = {
onRefresh: () => void;
refreshDisabled: boolean;
+
+ meterTypes: MeterType[];
+ selectedMeterTypeId: string;
+ onSelectMeterTypeId: (id: string) => void;
+ loadingMeterTypes: boolean;
};
export default function ConcentratorsSidebar({
@@ -30,13 +36,16 @@ export default function ConcentratorsSidebar({
sampleView,
sampleViewLabel,
typesMenuOpen,
- setTypesMenuOpen,
onChangeSampleView,
selectedProject,
onSelectProject,
projects,
onRefresh,
refreshDisabled,
+ meterTypes,
+ selectedMeterTypeId,
+ onSelectMeterTypeId,
+ loadingMeterTypes,
}: Props) {
const options = useMemo(
() =>
@@ -76,24 +85,7 @@ export default function ConcentratorsSidebar({
- {/* Tipos de tomas (dropdown) */}
-
setTypesMenuOpen((v) => !v)}
- className="w-full inline-flex items-center justify-between rounded-xl border border-gray-200 bg-white px-3 py-2 text-sm font-semibold text-gray-700 shadow-sm hover:bg-gray-50"
- >
-
- Tipos de tomas
-
- ({sampleViewLabel})
-
-
-
-
{typesMenuOpen && (
@@ -124,15 +116,36 @@ export default function ConcentratorsSidebar({
)}
+
+
+ Filtrar por Tipo de Toma
+
+ onSelectMeterTypeId(e.target.value)}
+ disabled={loadingMeterTypes}
+ className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 disabled:opacity-60 disabled:cursor-not-allowed"
+ >
+ Todos los tipos de toma
+ {meterTypes.map((type) => (
+
+ {type.name}
+
+ ))}
+
+
+
{/* List */}
{loadingProjects ? (
Loading projects...
) : projects.length === 0 ? (
- {sampleView === "GENERAL"
- ? "No projects available. Please contact your administrator."
- : `No projects with ${sampleViewLabel} concentrators found.`
+ {selectedMeterTypeId
+ ? `No hay proyectos con el tipo de toma seleccionado y concentradores ${sampleViewLabel}.`
+ : sampleView === "GENERAL"
+ ? "No hay proyectos con concentradores disponibles."
+ : `No hay proyectos con concentradores ${sampleViewLabel}.`
}
) : (
diff --git a/src/pages/concentrators/useConcentrators.ts b/src/pages/concentrators/useConcentrators.ts
index a138c48..a6775fe 100644
--- a/src/pages/concentrators/useConcentrators.ts
+++ b/src/pages/concentrators/useConcentrators.ts
@@ -5,6 +5,7 @@ import {
type ConcentratorType,
} from "../../api/concentrators";
import { fetchProjects, type Project } from "../../api/projects";
+import { fetchMeterTypes, type MeterType } from "../../api/meterTypes";
import type { ProjectCard, SampleView } from "./ConcentratorsPage";
type User = {
@@ -17,10 +18,14 @@ export function useConcentrators(currentUser: User) {
const [loadingProjects, setLoadingProjects] = useState(true);
const [loadingConcentrators, setLoadingConcentrators] = useState(true);
+ const [loadingMeterTypes, setLoadingMeterTypes] = useState(true);
const [projects, setProjects] = useState
([]);
const [allProjects, setAllProjects] = useState([]);
const [selectedProject, setSelectedProject] = useState("");
+
+ const [meterTypes, setMeterTypes] = useState([]);
+ const [selectedMeterTypeId, setSelectedMeterTypeId] = useState("");
const [concentrators, setConcentrators] = useState([]);
const [filteredConcentrators, setFilteredConcentrators] = useState<
@@ -54,6 +59,19 @@ export function useConcentrators(currentUser: User) {
[allProjects, currentUser.role, currentUser.project]
);
+ const loadMeterTypes = async () => {
+ setLoadingMeterTypes(true);
+ try {
+ const meterTypesData = await fetchMeterTypes();
+ setMeterTypes(meterTypesData);
+ } catch (err) {
+ console.error("Error loading meter types:", err);
+ setMeterTypes([]);
+ } finally {
+ setLoadingMeterTypes(false);
+ }
+ };
+
const loadProjects = async () => {
setLoadingProjects(true);
try {
@@ -92,8 +110,8 @@ export function useConcentrators(currentUser: User) {
}
};
- // init - load projects and concentrators
useEffect(() => {
+ loadMeterTypes();
loadProjects();
loadConcentrators();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -163,7 +181,21 @@ export function useConcentrators(currentUser: User) {
const baseContact = "Operaciones";
const baseLastSync = "Hace 1 h";
- return visibleProjects.map((projectId) => ({
+ let filteredProjects = visibleProjects;
+
+ filteredProjects = filteredProjects.filter((projectId) => {
+ const count = counts[projectId] ?? 0;
+ return count > 0;
+ });
+
+ if (selectedMeterTypeId) {
+ filteredProjects = filteredProjects.filter((projectId) => {
+ const project = projects.find((p) => p.id === projectId);
+ return project?.meterTypeId === selectedMeterTypeId;
+ });
+ }
+
+ return filteredProjects.map((projectId) => ({
id: projectId,
name: projectNameMap[projectId] ?? projectId,
region: baseRegion,
@@ -174,12 +206,27 @@ export function useConcentrators(currentUser: User) {
contact: baseContact,
status: "ACTIVO" as const,
}));
- }, [concentrators, visibleProjects, projects, isGeneral, sampleView]);
+ }, [concentrators, visibleProjects, projects, isGeneral, sampleView, selectedMeterTypeId]);
const projectsData: ProjectCard[] = useMemo(() => {
return projectsDataGeneral;
}, [projectsDataGeneral]);
+ useEffect(() => {
+ if (projectsData.length > 0) {
+ const firstProject = projectsData[0];
+ const currentProjectExists = projectsData.find((p) => p.id === selectedProject);
+
+ if (!selectedProject || !currentProjectExists) {
+ setSelectedProject(firstProject.id);
+ }
+ } else {
+ if (selectedProject) {
+ setSelectedProject("");
+ }
+ }
+ }, [projectsData]);
+
return {
// view
sampleView,
@@ -190,6 +237,7 @@ export function useConcentrators(currentUser: User) {
// loading
loadingProjects,
loadingConcentrators,
+ loadingMeterTypes,
// projects
allProjects,
@@ -198,6 +246,10 @@ export function useConcentrators(currentUser: User) {
selectedProject,
setSelectedProject,
+ meterTypes,
+ selectedMeterTypeId,
+ setSelectedMeterTypeId,
+
// data
concentrators,
setConcentrators,