{Object.keys(errors || {}).length > 0 && (
diff --git a/Modules/TimelineScheduling/app/Http/Controllers/MilestoneController.php b/Modules/TimelineScheduling/app/Http/Controllers/MilestoneController.php
index 066f2f6..a770fb4 100644
--- a/Modules/TimelineScheduling/app/Http/Controllers/MilestoneController.php
+++ b/Modules/TimelineScheduling/app/Http/Controllers/MilestoneController.php
@@ -78,6 +78,11 @@ class MilestoneController extends Controller
: 0.0;
return array_merge($m->toArray(), [
+ 'tasks' => $tasks->map(fn ($task) => [
+ 'ulid' => $task->ulid,
+ 'name' => $task->name,
+ 'completion_percentage' => (float) $task->completion_percentage,
+ ])->values(),
'is_completed' => $m->is_completed,
'is_overdue' => $m->is_overdue,
'status' => $m->status,
diff --git a/Modules/TimelineScheduling/resources/js/Pages/Timeline/Index.tsx b/Modules/TimelineScheduling/resources/js/Pages/Timeline/Index.tsx
index f193b88..1c76d27 100644
--- a/Modules/TimelineScheduling/resources/js/Pages/Timeline/Index.tsx
+++ b/Modules/TimelineScheduling/resources/js/Pages/Timeline/Index.tsx
@@ -388,6 +388,18 @@ export default function Timeline({ project, milestones, milestoneStats, weatherC
)}
+ {m.tasks?.length > 0 && (
+
+ )}
+
{/* Materials Breakdown Accordion Toggle */}
{m.materials_detail && m.materials_detail.length > 0 && (
diff --git a/Modules/UserManagement/resources/js/Pages/Users/Create.tsx b/Modules/UserManagement/resources/js/Pages/Users/Create.tsx
index 87ed91d..259b3d3 100644
--- a/Modules/UserManagement/resources/js/Pages/Users/Create.tsx
+++ b/Modules/UserManagement/resources/js/Pages/Users/Create.tsx
@@ -133,12 +133,7 @@ export default function Create({ contractors, isSuperAdmin, nextEmployeeCode, ro
}
const selected = contractors.find(c => String(c.id) === String(data.contractor_id));
return selected ? (
-
- {selected.company_name}
-
- {selected.type}
-
-
+
{selected.company_name}
) :
— No contractor (platform user) —;
})()}
@@ -147,12 +142,7 @@ export default function Create({ contractors, isSuperAdmin, nextEmployeeCode, ro
— No contractor (platform user) —
{contractors.map((c) => (
-
- {c.company_name}
-
- {c.type}
-
-
+ {c.company_name}
))}
diff --git a/resources/js/Components/Dashboard/ContractorDashboardView.tsx b/resources/js/Components/Dashboard/ContractorDashboardView.tsx
index f23bb97..051379e 100644
--- a/resources/js/Components/Dashboard/ContractorDashboardView.tsx
+++ b/resources/js/Components/Dashboard/ContractorDashboardView.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/Components/ui/card';
import { Link } from '@inertiajs/react';
import { FileText, DollarSign, Layers, ArrowRight, CheckCircle2 } from 'lucide-react';
+import { formatCurrency } from '@/lib/utils';
interface ContractorDashboardViewProps {
analytics: any;
@@ -9,9 +10,6 @@ interface ContractorDashboardViewProps {
}
export default function ContractorDashboardView({ analytics, activities }: ContractorDashboardViewProps) {
- const formatCurrency = (val: number) =>
- new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(val || 0);
-
return (
{/* Subcontractor Financial & Bidding Summary */}
diff --git a/resources/js/Components/Dashboard/ExecutiveDashboardView.tsx b/resources/js/Components/Dashboard/ExecutiveDashboardView.tsx
index 2389d84..7f78235 100644
--- a/resources/js/Components/Dashboard/ExecutiveDashboardView.tsx
+++ b/resources/js/Components/Dashboard/ExecutiveDashboardView.tsx
@@ -7,6 +7,7 @@ import {
ShieldCheck, PieChart, AlertCircle, Building2, TrendingUp,
Users, Briefcase, ExternalLink, CheckCircle
} from 'lucide-react';
+import { formatCurrency } from '@/lib/utils';
interface ExecutiveDashboardViewProps {
analytics: any;
@@ -15,9 +16,6 @@ interface ExecutiveDashboardViewProps {
}
export default function ExecutiveDashboardView({ analytics, activities, blockers }: ExecutiveDashboardViewProps) {
- const formatCurrency = (val: number) =>
- new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(val || 0);
-
const getTargetHref = (blocker: any) => {
if (blocker.project_ulid) {
if (blocker.daily_report_id) {
diff --git a/resources/js/Components/Dashboard/PMDashboardView.tsx b/resources/js/Components/Dashboard/PMDashboardView.tsx
index 3c95c80..f0ffbb7 100644
--- a/resources/js/Components/Dashboard/PMDashboardView.tsx
+++ b/resources/js/Components/Dashboard/PMDashboardView.tsx
@@ -4,6 +4,7 @@ import ActivityFeed from '@/Components/Dashboard/ActivityFeed';
import BlockerList from '@/Components/Dashboard/BlockerList';
import ResourceSummary from '@/Components/Dashboard/ResourceSummary';
import { CheckCircle2, Clock, Layers, DollarSign } from 'lucide-react';
+import { formatCurrency } from '@/lib/utils';
interface PMDashboardViewProps {
analytics: any;
@@ -13,9 +14,6 @@ interface PMDashboardViewProps {
}
export default function PMDashboardView({ analytics, activities, blockers, resources }: PMDashboardViewProps) {
- const formatCurrency = (val: number) =>
- new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(val || 0);
-
return (
{/* PM Milestone & Financial Progress Row */}
diff --git a/resources/js/Components/Dashboard/RoleAnalyticsBanner.tsx b/resources/js/Components/Dashboard/RoleAnalyticsBanner.tsx
index 498732a..e3bde32 100644
--- a/resources/js/Components/Dashboard/RoleAnalyticsBanner.tsx
+++ b/resources/js/Components/Dashboard/RoleAnalyticsBanner.tsx
@@ -12,6 +12,7 @@ import {
Layers,
TrendingUp
} from 'lucide-react';
+import { formatCurrency } from '@/lib/utils';
interface RoleAnalyticsProps {
analytics: {
@@ -56,14 +57,6 @@ export default function RoleAnalyticsBanner({ analytics }: RoleAnalyticsProps) {
const isContractor = role.includes('contractor');
const isSupervisor = role.includes('supervisor');
- const formatCurrency = (amount: number) => {
- return new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: 'USD',
- maximumFractionDigits: 0,
- }).format(amount || 0);
- };
-
return (
{/* 1. Super Admin / Executive KPIs */}
diff --git a/resources/js/hooks/usePermission.ts b/resources/js/hooks/usePermission.ts
index fbe1a76..7e708a9 100644
--- a/resources/js/hooks/usePermission.ts
+++ b/resources/js/hooks/usePermission.ts
@@ -57,6 +57,11 @@ export function usePermission() {
if (normalizedModule === 'projects' || normalizedModule === 'project') {
if (normalizedAction === 'create') {
+ const isSiteOperationsUser = auth.roles.some(role => [
+ 'Site Technical', 'Construction Supervisor', 'Site Operations', 'Site Engineer', 'Site Supervisor',
+ 'Main Contractor Admin',
+ ].includes(role));
+ if (isSiteOperationsUser) return false;
directPermissions = ['create projects', 'projects.create', 'projects.access'];
if (auth.roles.includes('Project Manager') || auth.roles.includes('Admin')) {
return true;
diff --git a/resources/js/lib/utils.ts b/resources/js/lib/utils.ts
index bd0c391..eef52b4 100644
--- a/resources/js/lib/utils.ts
+++ b/resources/js/lib/utils.ts
@@ -4,3 +4,7 @@ import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
+
+export function formatCurrency(value: number | string | null | undefined): string {
+ return new Intl.NumberFormat('en-PH', { style: 'currency', currency: 'PHP' }).format(Number(value) || 0)
+}