diff --git a/frontend/src/pages/accounts/AccountsPage.tsx b/frontend/src/pages/accounts/AccountsPage.tsx index f2861a7..dd614e4 100644 --- a/frontend/src/pages/accounts/AccountsPage.tsx +++ b/frontend/src/pages/accounts/AccountsPage.tsx @@ -587,7 +587,7 @@ export function AccountsPage() { {investments.filter(i => i.is_active).length > 0 && ( <> - i.is_active)} onEdit={handleEditInvestment} /> + i.is_active)} onEdit={handleEditInvestment} isReadOnly={isReadOnly} /> )} @@ -605,7 +605,7 @@ export function AccountsPage() { {operatingInvestments.length > 0 && ( <> - + )} @@ -623,7 +623,7 @@ export function AccountsPage() { {reserveInvestments.length > 0 && ( <> - + )} @@ -1087,9 +1087,11 @@ function AccountTable({ function InvestmentMiniTable({ investments, onEdit, + isReadOnly = false, }: { investments: Investment[]; onEdit: (inv: Investment) => void; + isReadOnly?: boolean; }) { const totalPrincipal = investments.reduce((s, i) => s + parseFloat(i.principal || '0'), 0); const totalValue = investments.reduce( @@ -1132,7 +1134,7 @@ function InvestmentMiniTable({ Maturity Value Maturity Date Days Remaining - + {!isReadOnly && } @@ -1182,13 +1184,15 @@ function InvestmentMiniTable({ '-' )} - - - onEdit(inv)}> - - - - + {!isReadOnly && ( + + + onEdit(inv)}> + + + + + )} ))} diff --git a/frontend/src/pages/capital-projects/CapitalProjectsPage.tsx b/frontend/src/pages/capital-projects/CapitalProjectsPage.tsx index 302b867..04c4baa 100644 --- a/frontend/src/pages/capital-projects/CapitalProjectsPage.tsx +++ b/frontend/src/pages/capital-projects/CapitalProjectsPage.tsx @@ -72,9 +72,10 @@ interface KanbanCardProps { project: Project; onEdit: (p: Project) => void; onDragStart: (e: DragEvent, project: Project) => void; + isReadOnly?: boolean; } -function KanbanCard({ project, onEdit, onDragStart }: KanbanCardProps) { +function KanbanCard({ project, onEdit, onDragStart, isReadOnly }: KanbanCardProps) { const plannedLabel = formatPlannedDate(project.planned_date); // For projects in the Future bucket with a specific year, show the year const currentYear = new Date().getFullYear(); @@ -86,21 +87,23 @@ function KanbanCard({ project, onEdit, onDragStart }: KanbanCardProps) { padding="sm" radius="md" withBorder - draggable - onDragStart={(e) => onDragStart(e, project)} - style={{ cursor: 'grab', userSelect: 'none' }} + draggable={!isReadOnly} + onDragStart={!isReadOnly ? (e) => onDragStart(e, project) : undefined} + style={{ cursor: isReadOnly ? 'default' : 'grab', userSelect: 'none' }} mb="xs" > - + {!isReadOnly && } {project.name} - onEdit(project)}> - - + {!isReadOnly && ( + onEdit(project)}> + + + )} @@ -148,11 +151,12 @@ interface KanbanColumnProps { isDragOver: boolean; onDragOverHandler: (e: DragEvent, year: number) => void; onDragLeave: () => void; + isReadOnly?: boolean; } function KanbanColumn({ year, projects, onEdit, onDragStart, onDrop, - isDragOver, onDragOverHandler, onDragLeave, + isDragOver, onDragOverHandler, onDragLeave, isReadOnly, }: KanbanColumnProps) { const totalEst = projects.reduce((s, p) => s + parseFloat(p.estimated_cost || '0'), 0); const isFuture = year === FUTURE_YEAR; @@ -178,9 +182,9 @@ function KanbanColumn({ border: isDragOver ? '2px dashed var(--mantine-color-blue-4)' : undefined, transition: 'background-color 150ms ease, border 150ms ease', }} - onDragOver={(e) => onDragOverHandler(e, year)} - onDragLeave={onDragLeave} - onDrop={(e) => onDrop(e, year)} + onDragOver={!isReadOnly ? (e) => onDragOverHandler(e, year) : undefined} + onDragLeave={!isReadOnly ? onDragLeave : undefined} + onDrop={!isReadOnly ? (e) => onDrop(e, year) : undefined} > {yearLabel(year)} @@ -199,7 +203,7 @@ function KanbanColumn({ {projects.length === 0 ? ( - Drop projects here + {isReadOnly ? 'No projects' : 'Drop projects here'} ) : useWideLayout ? (
{projects.map((p) => ( - + ))}
) : ( projects.map((p) => ( - + )) )}
@@ -595,6 +599,7 @@ export function CapitalProjectsPage() { isDragOver={dragOverYear === year} onDragOverHandler={handleDragOver} onDragLeave={handleDragLeave} + isReadOnly={isReadOnly} /> ); })} diff --git a/frontend/src/pages/dashboard/DashboardPage.tsx b/frontend/src/pages/dashboard/DashboardPage.tsx index c5546a2..21c20e4 100644 --- a/frontend/src/pages/dashboard/DashboardPage.tsx +++ b/frontend/src/pages/dashboard/DashboardPage.tsx @@ -18,7 +18,7 @@ import { } from '@tabler/icons-react'; import { useState, useCallback } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { useAuthStore } from '../../stores/authStore'; +import { useAuthStore, useIsReadOnly } from '../../stores/authStore'; import api from '../../services/api'; interface HealthScore { @@ -311,6 +311,7 @@ interface DashboardData { export function DashboardPage() { const currentOrg = useAuthStore((s) => s.currentOrg); + const isReadOnly = useIsReadOnly(); const queryClient = useQueryClient(); // Track whether a refresh is in progress (per score type) for async polling @@ -424,7 +425,7 @@ export function DashboardPage() { } isRefreshing={operatingRefreshing} - onRefresh={handleRefreshOperating} + onRefresh={!isReadOnly ? handleRefreshOperating : undefined} lastFailed={!!healthScores?.operating_last_failed} /> } isRefreshing={reserveRefreshing} - onRefresh={handleRefreshReserve} + onRefresh={!isReadOnly ? handleRefreshReserve : undefined} lastFailed={!!healthScores?.reserve_last_failed} /> diff --git a/frontend/src/pages/investment-planning/InvestmentPlanningPage.tsx b/frontend/src/pages/investment-planning/InvestmentPlanningPage.tsx index 1dfb4ab..7440d08 100644 --- a/frontend/src/pages/investment-planning/InvestmentPlanningPage.tsx +++ b/frontend/src/pages/investment-planning/InvestmentPlanningPage.tsx @@ -36,6 +36,7 @@ import { import { useQuery } from '@tanstack/react-query'; import { notifications } from '@mantine/notifications'; import api from '../../services/api'; +import { useIsReadOnly } from '../../stores/authStore'; // ── Types ── @@ -347,6 +348,7 @@ function RecommendationsDisplay({ export function InvestmentPlanningPage() { const [ratesExpanded, setRatesExpanded] = useState(true); const [isTriggering, setIsTriggering] = useState(false); + const isReadOnly = useIsReadOnly(); // Load financial snapshot on mount const { data: snapshot, isLoading: snapshotLoading } = useQuery({ @@ -696,15 +698,17 @@ export function InvestmentPlanningPage() {
- + {!isReadOnly && ( + + )}
{/* Processing State */} diff --git a/frontend/src/pages/invoices/InvoicesPage.tsx b/frontend/src/pages/invoices/InvoicesPage.tsx index cab1e40..f6e1f83 100644 --- a/frontend/src/pages/invoices/InvoicesPage.tsx +++ b/frontend/src/pages/invoices/InvoicesPage.tsx @@ -9,6 +9,7 @@ import { notifications } from '@mantine/notifications'; import { IconSend, IconInfoCircle, IconCheck, IconX } from '@tabler/icons-react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import api from '../../services/api'; +import { useIsReadOnly } from '../../stores/authStore'; interface Invoice { id: string; invoice_number: string; unit_number: string; unit_id: string; @@ -64,6 +65,7 @@ export function InvoicesPage() { const [preview, setPreview] = useState(null); const [previewLoading, setPreviewLoading] = useState(false); const queryClient = useQueryClient(); + const isReadOnly = useIsReadOnly(); const { data: invoices = [], isLoading } = useQuery({ queryKey: ['invoices'], @@ -124,10 +126,12 @@ export function InvoicesPage() { Invoices - - - - + {!isReadOnly && ( + + + + + )} Total Invoices{invoices.length}