project service

This commit is contained in:
2026-02-03 01:39:48 -06:00
parent 31ab977f97
commit 5529739749
2 changed files with 38 additions and 5 deletions

View File

@@ -14,7 +14,7 @@ import { getAuditLogs, type AuditLog } from "../api/audit";
import { fetchNotifications, type Notification } from "../api/notifications"; import { fetchNotifications, type Notification } from "../api/notifications";
import { getAllUsers, type User } from "../api/users"; import { getAllUsers, type User } from "../api/users";
import { fetchProjects, type Project } from "../api/projects"; import { fetchProjects, type Project } from "../api/projects";
import { getCurrentUserRole } from "../api/auth"; import { getCurrentUserRole, getCurrentUserProjectId } from "../api/auth";
import type { Page } from "../App"; import type { Page } from "../App";
import grhWatermark from "../assets/images/grhWatermark.png"; import grhWatermark from "../assets/images/grhWatermark.png";
@@ -55,6 +55,7 @@ export default function Home({
}) { }) {
const userRole = useMemo(() => getCurrentUserRole(), []); const userRole = useMemo(() => getCurrentUserRole(), []);
const userProjectId = useMemo(() => getCurrentUserProjectId(), []);
const isOperator = userRole?.toUpperCase() === 'OPERATOR'; const isOperator = userRole?.toUpperCase() === 'OPERATOR';
const isAdmin = userRole?.toUpperCase() === 'ADMIN'; const isAdmin = userRole?.toUpperCase() === 'ADMIN';
@@ -166,6 +167,12 @@ export default function Home({
}, []); }, []);
const filteredMeters = useMemo(() => { const filteredMeters = useMemo(() => {
// If user is OPERATOR, always filter by their assigned project
if (isOperator && userProjectId) {
return meters.filter((m) => m.projectId === userProjectId);
}
// For ADMIN users with organism selector
if (selectedOrganism === "Todos") { if (selectedOrganism === "Todos") {
return meters; return meters;
} }
@@ -176,7 +183,7 @@ export default function Home({
} }
return meters.filter((m) => m.projectId === selectedUser.project_id); return meters.filter((m) => m.projectId === selectedUser.project_id);
}, [meters, selectedOrganism, users]); }, [meters, selectedOrganism, users, isOperator, userProjectId]);
const filteredProjects = useMemo( const filteredProjects = useMemo(
() => [...new Set(filteredMeters.map((m) => m.projectName))].filter(Boolean) as string[], () => [...new Set(filteredMeters.map((m) => m.projectName))].filter(Boolean) as string[],
@@ -184,6 +191,13 @@ export default function Home({
); );
const selectedUserProjectName = useMemo(() => { const selectedUserProjectName = useMemo(() => {
// If user is OPERATOR, get their project name
if (isOperator && userProjectId) {
const project = projects.find(p => p.id === userProjectId);
return project?.name || null;
}
// For ADMIN users with organism selector
if (selectedOrganism === "Todos") return null; if (selectedOrganism === "Todos") return null;
const selectedUser = users.find(u => u.id === selectedOrganism); const selectedUser = users.find(u => u.id === selectedOrganism);
@@ -191,9 +205,18 @@ export default function Home({
const project = projects.find(p => p.id === selectedUser.project_id); const project = projects.find(p => p.id === selectedUser.project_id);
return project?.name || null; return project?.name || null;
}, [selectedOrganism, users, projects]); }, [selectedOrganism, users, projects, isOperator, userProjectId]);
const chartData = useMemo(() => { const chartData = useMemo(() => {
// If user is OPERATOR, show only their project
if (isOperator && selectedUserProjectName) {
return [{
name: selectedUserProjectName,
meterCount: filteredMeters.length,
}];
}
// For ADMIN users
if (selectedOrganism === "Todos") { if (selectedOrganism === "Todos") {
return filteredProjects.map((projectName) => ({ return filteredProjects.map((projectName) => ({
name: projectName, name: projectName,
@@ -211,7 +234,7 @@ export default function Home({
} }
return []; return [];
}, [selectedOrganism, filteredProjects, filteredMeters, selectedUserProjectName]); }, [selectedOrganism, filteredProjects, filteredMeters, selectedUserProjectName, isOperator]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleBarClick = (data: any) => { const handleBarClick = (data: any) => {

View File

@@ -236,11 +236,21 @@ export async function update(id: string, data: UpdateProjectInput): Promise<Proj
/** /**
* Delete a project by ID * Delete a project by ID
* Checks for dependent meters/concentrators before deletion * Checks for dependent meters/concentrators/users before deletion
* @param id - Project UUID * @param id - Project UUID
* @returns True if deleted, throws error if has dependencies * @returns True if deleted, throws error if has dependencies
*/ */
export async function deleteProject(id: string): Promise<boolean> { export async function deleteProject(id: string): Promise<boolean> {
const userCheck = await query<{ count: string }>(
'SELECT COUNT(*) as count FROM users WHERE project_id = $1',
[id]
);
const userCount = parseInt(userCheck.rows[0]?.count || '0', 10);
if (userCount > 0) {
throw new Error(`Cannot delete project: ${userCount} user(s) are assigned to this project`);
}
// Check for dependent meters // Check for dependent meters
const meterCheck = await query<{ count: string }>( const meterCheck = await query<{ count: string }>(
'SELECT COUNT(*) as count FROM meters WHERE project_id = $1', 'SELECT COUNT(*) as count FROM meters WHERE project_id = $1',