query('project'); $project = null; if ($projectUlid) { $project = Project::where('ulid', $projectUlid)->firstOrFail(); $project->load([ 'tasks' => fn ($q) => $q->select('id', 'project_id')->with('delays'), 'milestones', ]); } return \Inertia\Inertia::render('TimelineScheduling::Timeline/Index', [ 'project' => $project, 'projects' => Project::select('id', 'ulid', 'name')->get(), 'milestones' => $project ? $project->milestones->map(fn ($m) => array_merge($m->toArray(), [ 'is_completed' => $m->is_completed, 'is_overdue' => $m->is_overdue, 'status' => $m->status, 'status_color' => $m->status_color, 'days_delayed' => $m->days_delayed, ])) : [], 'milestoneStats' => $project ? [ 'total' => $project->milestones->count(), 'completed' => $project->milestones->where('actual_date', '!=', null)->count(), 'completion_percentage' => $project->milestone_completion, 'weather_delay_days' => $project->weather_delay_days, ] : null, 'weatherConditions' => collect(WeatherCondition::cases())->map(fn ($c) => [ 'value' => $c->value, 'label' => $c->label(), 'icon' => $c->icon(), ]), 'allowedTransitions' => $project ? collect($project->status->allowedTransitions())->map(fn ($s) => [ 'value' => $s->value, 'label' => $s->label(), ]) : [], ]); } public function store(Request $request) { $validated = $request->validate([ 'project_id' => 'required|exists:projects,id', 'name' => 'required|string|max:255', 'description' => 'nullable|string', 'planned_date' => 'nullable|date', 'weight_percentage' => 'required|numeric|min:0|max:100', ]); $project = Project::findOrFail($validated['project_id']); $validated['sort_order'] = $project->milestones()->count(); $validated['is_default'] = false; ProjectMilestone::create($validated); return back()->with('success', 'Milestone added.'); } public function update(Request $request, ProjectMilestone $milestone) { $validated = $request->validate([ 'name' => 'sometimes|required|string|max:255', 'description' => 'nullable|string', 'planned_date' => 'nullable|date', 'actual_date' => 'nullable|date', 'weight_percentage' => 'sometimes|numeric|min:0|max:100', 'weather_impacted' => 'sometimes|boolean', 'weather_condition' => 'nullable|string', 'weather_delay_days' => 'sometimes|integer|min:0', 'weather_notes' => 'nullable|string|max:2000', ]); // Clear weather fields if not impacted if (isset($validated['weather_impacted']) && !$validated['weather_impacted']) { $validated['weather_condition'] = null; $validated['weather_delay_days'] = 0; $validated['weather_notes'] = null; } $milestone->update($validated); return back()->with('success', 'Milestone updated.'); } public function destroy(ProjectMilestone $milestone) { $milestone->delete(); return back()->with('success', 'Milestone removed.'); } }