Implemented rbac

This commit is contained in:
2026-10-11 11:16:08 +02:00
parent 45a6c0aca0
commit 1142cfd94e
24 changed files with 3033 additions and 432 deletions
@@ -33,6 +33,7 @@ import { HelpTooltip } from '../components/ui/HelpTooltip';
import { ExportButton } from '../components/ui/ExportButton';
import { ExportColumn } from '../utils/exportUtils';
import { useTableSort, SortableTh } from '../utils/tableSort';
import { useRbac } from '../auth/rbac';
import { ApprovalStatusBadge } from '../components/ui/StatusBadge';
import { SiteVisit, ApprovalStatus } from '../types';
import {
@@ -53,6 +54,7 @@ type SiteVisitFormValues = z.infer<typeof siteVisitSchema>;
export const SiteVisitsPage: React.FC = () => {
const queryClient = useQueryClient();
const { success, error: toastError } = useToast();
const { canAdd, canApprove, canExport } = useRbac();
const [selectedProjectId, setSelectedProjectId] = useState<string>('all');
const [searchTerm, setSearchTerm] = useState('');
@@ -349,28 +351,31 @@ export const SiteVisitsPage: React.FC = () => {
</button>
<ExportButton
claim="site_visits"
data={sortedVisits}
columns={visitExportCols}
filename={`site_visits_${new Date().toISOString().split('T')[0]}`}
title="Site Visits Register"
/>
<button
onClick={() => {
setEditingVisit(null);
visitForm.reset({
inspectorName: '',
visitedAt: new Date().toISOString().split('T')[0],
findings: '',
status: ApprovalStatus.Pending,
});
setIsVisitModalOpen(true);
}}
className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-xl text-xs font-semibold bg-gradient-to-r from-emerald-600 to-teal-600 text-white hover:from-emerald-500 hover:to-teal-500 shadow-md shadow-emerald-600/25 transition cursor-pointer"
>
<Plus className="w-3.5 h-3.5" />
<span>Log Site Visit</span>
</button>
{canAdd('site_visits') && (
<button
onClick={() => {
setEditingVisit(null);
visitForm.reset({
inspectorName: '',
visitedAt: new Date().toISOString().split('T')[0],
findings: '',
status: ApprovalStatus.Pending,
});
setIsVisitModalOpen(true);
}}
className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-xl text-xs font-semibold bg-gradient-to-r from-emerald-600 to-teal-600 text-white hover:from-emerald-500 hover:to-teal-500 shadow-md shadow-emerald-600/25 transition cursor-pointer"
>
<Plus className="w-3.5 h-3.5" />
<span>Log Site Visit</span>
</button>
)}
</div>
</div>
@@ -505,8 +510,13 @@ export const SiteVisitsPage: React.FC = () => {
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-xs text-white focus:outline-none focus:border-emerald-500"
>
{APPROVAL_STATUS_OPTIONS.map((opt) => (
<option key={opt.value} value={opt.value}>
<option
key={opt.value}
value={opt.value}
disabled={opt.value === ApprovalStatus.Approved && !canApprove('site_visits')}
>
{opt.label}
{opt.value === ApprovalStatus.Approved && !canApprove('site_visits') ? ' (Requires Update Permission)' : ''}
</option>
))}
</select>