diff --git a/app/Livewire/IssueManager.php b/app/Livewire/IssueManager.php index 8a03f03..5359224 100644 --- a/app/Livewire/IssueManager.php +++ b/app/Livewire/IssueManager.php @@ -14,22 +14,29 @@ class IssueManager extends Component { public Project $project; - public $editing = false; - public $editingId = null; + public $issues = []; + public $projectUsers = []; + // Form / modal state + public $showForm = false; + public $editingIssue = null; // issue id when editing, null when creating + + // Form fields public $title = ''; public $description = ''; public $status = 'open'; public $priority = 'medium'; + public $assignedTo = ''; + public $resolutionNotes = ''; + + // Optional context (e.g. when reporting from a map feature) public $featureId = null; public $inspectionId = null; - public $assignedTo = null; - - public $issues = []; public function mount(Project $project) { $this->project = $project; + $this->loadProjectUsers(); $this->loadIssues(); } @@ -41,79 +48,134 @@ class IssueManager extends Component ->get(); } - public function create() + public function loadProjectUsers() { - $this->reset(['title', 'description', 'status', 'priority', 'featureId', 'inspectionId', 'assignedTo', 'editingId']); - $this->status = 'open'; - $this->priority = 'medium'; - $this->editing = true; + $this->projectUsers = $this->project->users()->orderBy('name')->get(); } - public function edit($issueId) + protected function rules(): array { - $issue = Issue::findOrFail($issueId); - $this->editingId = $issue->id; - $this->title = $issue->title; - $this->description = $issue->description ?? ''; - $this->status = $issue->status; - $this->priority = $issue->priority; - $this->featureId = $issue->feature_id; - $this->inspectionId = $issue->inspection_id; - $this->assignedTo = $issue->assigned_to; - $this->editing = true; + 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([ - 'title' => 'required|string|max:255', - 'status' => 'required|in:' . implode(',', Issue::STATUSES), - 'priority' => 'required|in:' . implode(',', Issue::PRIORITIES), - ]); + $this->validate(); - if ($this->editingId) { - $issue = Issue::findOrFail($this->editingId); - $issue->update([ - 'title' => $this->title, - 'description' => $this->description, - 'status' => $this->status, - 'priority' => $this->priority, - 'feature_id' => $this->featureId, - 'inspection_id' => $this->inspectionId, - 'assigned_to' => $this->assignedTo, - ]); + $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 { - $issue = Issue::create([ - 'project_id' => $this->project->id, - 'title' => $this->title, - 'description' => $this->description, - 'status' => $this->status, - 'priority' => $this->priority, - 'feature_id' => $this->featureId, - 'inspection_id' => $this->inspectionId, - 'reported_by' => Auth::id(), - 'assigned_to' => $this->assignedTo, - ]); + $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->editing = false; + $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); @@ -122,14 +184,8 @@ class IssueManager extends Component $this->dispatch('notify', 'Issue eliminado'); } - public function cancel() - { - $this->editing = false; - $this->reset(['title', 'description', 'status', 'priority', 'featureId', 'inspectionId', 'assignedTo', 'editingId']); - } - public function render() { - return view('livewire.issue-manager'); + return view('livewire.issues.issue-manager'); } } diff --git a/resources/views/livewire/issue-manager.blade.php b/resources/views/livewire/issue-manager.blade.php deleted file mode 100644 index 0800aa4..0000000 --- a/resources/views/livewire/issue-manager.blade.php +++ /dev/null @@ -1,89 +0,0 @@ -
{{ $issue->title }}
- @if($issue->description) -{{ $issue->description }}
- @endif -No hay issues registrados
- @endforelse -