diff --git a/app/Http/Controllers/Api/V1/ProjectApiController.php b/app/Http/Controllers/Api/V1/ProjectApiController.php index 1559e98..bc1490d 100644 --- a/app/Http/Controllers/Api/V1/ProjectApiController.php +++ b/app/Http/Controllers/Api/V1/ProjectApiController.php @@ -175,6 +175,7 @@ class ProjectApiController extends Controller return [ 'id' => $i->id, 'feature_id' => $i->feature_id, 'title' => $i->title, 'description' => $i->description, 'status' => $i->status, 'priority' => $i->priority, + 'type' => $i->type, 'reported_by' => $i->reported_by, 'assigned_to' => $i->assigned_to, 'resolved_at' => $i->resolved_at?->toIso8601String(), 'updated_at' => $i->updated_at?->toIso8601String(), ]; diff --git a/app/Http/Controllers/Api/V1/SyncController.php b/app/Http/Controllers/Api/V1/SyncController.php index 91151ed..012b328 100644 --- a/app/Http/Controllers/Api/V1/SyncController.php +++ b/app/Http/Controllers/Api/V1/SyncController.php @@ -189,6 +189,7 @@ class SyncController extends Controller 'description' => ['nullable', 'string'], 'priority' => ['nullable', 'in:' . implode(',', Issue::PRIORITIES)], 'status' => ['nullable', 'in:' . implode(',', Issue::STATUSES)], + 'type' => ['nullable', 'in:' . implode(',', Issue::TYPES)], ]); if ($v->fails()) { return $this->error($uuid, 'validation: ' . $v->errors()->first()); @@ -208,6 +209,7 @@ class SyncController extends Controller 'description' => $d['description'] ?? null, 'priority' => $d['priority'] ?? 'medium', 'status' => $d['status'] ?? 'open', + 'type' => $d['type'] ?? 'other', 'reported_by' => $user->id, 'client_updated_at' => $op['client_updated_at'] ?? null, ]); @@ -223,6 +225,7 @@ class SyncController extends Controller 'description' => ['nullable', 'string'], 'priority' => ['nullable', 'in:' . implode(',', Issue::PRIORITIES)], 'status' => ['nullable', 'in:' . implode(',', Issue::STATUSES)], + 'type' => ['nullable', 'in:' . implode(',', Issue::TYPES)], 'assigned_to' => ['nullable', 'integer', 'exists:users,id'], 'resolution_notes' => ['nullable', 'string'], ]); diff --git a/app/Livewire/IssueForm.php b/app/Livewire/IssueForm.php index a8e87bc..69c6d11 100644 --- a/app/Livewire/IssueForm.php +++ b/app/Livewire/IssueForm.php @@ -23,6 +23,7 @@ class IssueForm extends Component public $description = ''; public $status = 'open'; public $priority = 'medium'; + public $type = 'defect'; public $assignedTo = ''; public $resolutionNotes = ''; @@ -48,6 +49,7 @@ class IssueForm extends Component $this->description = $issue->description ?? ''; $this->status = $issue->status; $this->priority = $issue->priority; + $this->type = $issue->type ?? 'defect'; $this->assignedTo = $issue->assigned_to ?? ''; $this->resolutionNotes = $issue->resolution_notes ?? ''; $this->featureId = $issue->feature_id; @@ -77,6 +79,7 @@ class IssueForm extends Component 'description' => 'nullable|string', 'status' => 'required|in:' . implode(',', Issue::STATUSES), 'priority' => 'required|in:' . implode(',', Issue::PRIORITIES), + 'type' => 'required|in:' . implode(',', Issue::TYPES), 'assignedTo' => 'nullable|exists:users,id', 'resolutionNotes' => 'nullable|string', ]; @@ -92,6 +95,7 @@ class IssueForm extends Component 'description' => $this->description, 'status' => $this->status, 'priority' => $this->priority, + 'type' => $this->type, 'feature_id' => $this->featureId, 'inspection_id' => $this->inspectionId, 'assigned_to' => $this->assignedTo ?: null, diff --git a/app/Livewire/IssueTable.php b/app/Livewire/IssueTable.php index 9ce5a3f..35f0f95 100644 --- a/app/Livewire/IssueTable.php +++ b/app/Livewire/IssueTable.php @@ -91,6 +91,12 @@ class IssueTable extends DataTableComponent }) ->html(), + Column::make('Tipo', 'type') + ->sortable() + ->format(fn ($value, $row) => + ''.e($row->type_label).'') + ->html(), + Column::make('Feature') ->label(fn ($row) => $row->feature ? ''.e($row->feature->name).'' @@ -185,6 +191,10 @@ class IssueTable extends DataTableComponent 'low' => 'Baja', ]) ->filter(fn (Builder $query, string $value) => $query->where('issues.priority', $value)), + + SelectFilter::make('Tipo', 'type') + ->options(['' => 'Tipo: todos'] + \App\Models\Issue::typeLabels()) + ->filter(fn (Builder $query, string $value) => $query->where('issues.type', $value)), ]; } diff --git a/app/Models/Issue.php b/app/Models/Issue.php index 75d3e82..70f9fff 100644 --- a/app/Models/Issue.php +++ b/app/Models/Issue.php @@ -12,10 +12,11 @@ class Issue extends Model const STATUSES = ['open', 'in_review', 'resolved', 'closed']; const PRIORITIES = ['low', 'medium', 'high', 'critical']; + const TYPES = ['defect', 'safety', 'quality', 'documentation', 'other']; protected $fillable = [ 'project_id', 'feature_id', 'inspection_id', - 'title', 'description', 'status', 'priority', + 'title', 'description', 'status', 'priority', 'type', 'reported_by', 'assigned_to', 'resolved_at', 'resolution_notes', 'uuid', 'client_updated_at', ]; @@ -71,4 +72,32 @@ class Issue extends Model default => '#6b7280', }; } + + /** Human label (Spanish) for each issue type. */ + public static function typeLabels(): array + { + return [ + 'defect' => 'Defecto', + 'safety' => 'Seguridad', + 'quality' => 'Calidad', + 'documentation' => 'Documentación', + 'other' => 'Otro', + ]; + } + + public function getTypeLabelAttribute(): string + { + return self::typeLabels()[$this->type] ?? ucfirst((string) $this->type); + } + + public function getTypeColorAttribute(): string + { + return match($this->type) { + 'defect' => '#ef4444', + 'safety' => '#f97316', + 'quality' => '#0ea5e9', + 'documentation' => '#8b5cf6', + default => '#6b7280', + }; + } } diff --git a/database/migrations/2026_06_18_140000_add_type_to_issues_table.php b/database/migrations/2026_06_18_140000_add_type_to_issues_table.php new file mode 100644 index 0000000..695a2cb --- /dev/null +++ b/database/migrations/2026_06_18_140000_add_type_to_issues_table.php @@ -0,0 +1,22 @@ +string('type', 30)->default('other')->after('priority'); + }); + } + + public function down(): void + { + Schema::table('issues', function (Blueprint $table) { + $table->dropColumn('type'); + }); + } +}; diff --git a/resources/views/livewire/issues/issue-detail.blade.php b/resources/views/livewire/issues/issue-detail.blade.php index 6adde44..3f420c9 100644 --- a/resources/views/livewire/issues/issue-detail.blade.php +++ b/resources/views/livewire/issues/issue-detail.blade.php @@ -26,6 +26,7 @@