project = $project; $this->loadProjectUsers(); $this->loadIssues(); } public function loadIssues() { $this->issues = Issue::where('project_id', $this->project->id) ->with(['feature', 'reporter', 'assignee']) ->orderBy('created_at', 'desc') ->get(); } public function loadProjectUsers() { $this->projectUsers = $this->project->users()->orderBy('name')->get(); } protected function rules(): array { return [ 'title' => 'required|string|max:255', 'description' => 'nullable|string', 'status' => 'required|in:' . implode(',', Issue::STATUSES), 'priority' => 'required|in:' . implode(',', Issue::PRIORITIES), 'assignedTo' => 'nullable|exists:users,id', 'resolutionNotes' => 'nullable|string', ]; } public function openForm($issueId = null) { $this->resetForm(); if ($issueId) { $issue = Issue::where('project_id', $this->project->id)->findOrFail($issueId); $this->editingIssue = $issue->id; $this->title = $issue->title; $this->description = $issue->description ?? ''; $this->status = $issue->status; $this->priority = $issue->priority; $this->assignedTo = $issue->assigned_to ?? ''; $this->resolutionNotes = $issue->resolution_notes ?? ''; $this->featureId = $issue->feature_id; $this->inspectionId = $issue->inspection_id; } $this->showForm = true; } public function closeForm() { $this->showForm = false; $this->resetForm(); } private function resetForm(): void { $this->reset([ 'title', 'description', 'assignedTo', 'resolutionNotes', 'featureId', 'inspectionId', 'editingIssue', ]); $this->status = 'open'; $this->priority = 'medium'; $this->resetErrorBag(); } public function save() { $this->validate(); $payload = [ 'title' => $this->title, 'description' => $this->description, 'status' => $this->status, 'priority' => $this->priority, 'feature_id' => $this->featureId, 'inspection_id' => $this->inspectionId, 'assigned_to' => $this->assignedTo ?: null, 'resolution_notes' => $this->resolutionNotes ?: null, ]; // Keep resolved_at in sync with the status if (in_array($this->status, ['resolved', 'closed'])) { $payload['resolved_at'] = now(); } else { $payload['resolved_at'] = null; } if ($this->editingIssue) { $issue = Issue::where('project_id', $this->project->id)->findOrFail($this->editingIssue); // Don't overwrite an existing resolved date if it was already resolved if ($issue->resolved_at && in_array($this->status, ['resolved', 'closed'])) { unset($payload['resolved_at']); } $issue->update($payload); } else { $issue = Issue::create(array_merge($payload, [ 'project_id' => $this->project->id, 'reported_by' => Auth::id(), ])); if ($issue->wasRecentlyCreated) { $issue->load(['feature', 'assignee']); $creator = $this->project->creator; if ($creator && $creator->id !== Auth::id()) { $creator->notify(new IssueReportedNotification($issue)); } if ($issue->assignee && $issue->assignee->id !== Auth::id()) { $issue->assignee->notify(new IssueReportedNotification($issue)); } } } $this->closeForm(); $this->loadIssues(); $this->dispatch('notify', 'Issue guardado correctamente'); } public function resolve($issueId) { $issue = Issue::where('project_id', $this->project->id)->findOrFail($issueId); $issue->update([ 'status' => 'resolved', 'resolved_at' => $issue->resolved_at ?? now(), ]); $this->loadIssues(); $this->dispatch('notify', 'Issue marcado como resuelto'); } public function close($issueId) { $issue = Issue::where('project_id', $this->project->id)->findOrFail($issueId); $issue->update([ 'status' => 'closed', 'resolved_at' => $issue->resolved_at ?? now(), ]); $this->loadIssues(); $this->dispatch('notify', 'Issue cerrado'); } public function delete($issueId) { $issue = Issue::where('project_id', $this->project->id)->findOrFail($issueId); $issue->delete(); $this->loadIssues(); $this->dispatch('notify', 'Issue eliminado'); } public function render() { return view('livewire.issues.issue-manager'); } }