dummybot/app/Http/Controllers/TaskController.php

157 lines
6.3 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class TaskController extends Controller {
public function index(Request $r) {
$tasks = $r->user()->tasks()
->with(['project:id,name,color', 'tags:id,name,color'])
->orderBy('done')
->orderByRaw("FIELD(priority,'high','med','low')")
->orderBy('created_at')
->get();
return response()->json($tasks);
}
public function pending(Request $r): JsonResponse {
$tasks = $r->user()->tasks()
->active()
->with('project:id,name,color')
->orderByRaw("FIELD(priority,'high','med','low')")
->orderBy('created_at')
->limit(20)
->get();
return response()->json($tasks->map(fn ($t) => [
'id' => $t->id,
'title' => $t->title,
'priority' => $t->priority,
'project' => $t->project?->name,
'next_due_in' => $t->next_due_in,
'estimate_min' => $t->estimate_min,
]));
}
public function store(Request $r): JsonResponse {
$data = $r->validate([
'title' => 'required|string|max:120',
'description' => 'nullable|string',
'priority' => 'nullable|in:low,med,high',
'estimate_min' => 'nullable|integer|min:1|max:9999',
'deadline' => 'nullable|date',
'project_id' => 'nullable|integer|exists:projects,id',
'recurrence' => 'nullable|in:daily,weekly,monthly',
'tags' => 'nullable|array',
'tags.*' => 'string|max:30',
]);
$task = $r->user()->tasks()->create([
'title' => $data['title'],
'description' => $data['description'] ?? null,
'priority' => $data['priority'] ?? 'med',
'estimate_min' => $data['estimate_min'] ?? null,
'deadline' => $data['deadline'] ?? null,
'project_id' => $data['project_id'] ?? null,
'recurrence' => $data['recurrence'] ?? null,
]);
if (! empty($data['tags'])) {
$this->syncTags($task, $data['tags']);
}
return response()->json($task->load('project', 'tags'), 201);
}
public function update(Request $r, Task $task): JsonResponse {
abort_unless($task->user_id === $r->user()->id, 403);
$data = $r->validate([
'title' => 'sometimes|required|string|max:120',
'description' => 'nullable|string',
'priority' => 'nullable|in:low,med,high',
'estimate_min' => 'nullable|integer|min:1|max:9999',
'deadline' => 'nullable|date',
'project_id' => 'nullable|integer|exists:projects,id',
'recurrence' => 'nullable|in:daily,weekly,monthly',
'tags' => 'nullable|array',
]);
$task->update(array_intersect_key($data, array_flip([
'title', 'description', 'priority', 'estimate_min',
'deadline', 'project_id', 'recurrence',
])));
if (array_key_exists('tags', $data)) {
$this->syncTags($task, $data['tags']);
}
return response()->json($task->load('project', 'tags'));
}
public function done(Request $r, Task $task): JsonResponse {
abort_unless($task->user_id === $r->user()->id, 403);
$task->update(['done' => true, 'done_at' => now()]);
// Si la tarea es recurrente, generamos la siguiente
if ($task->recurrence) {
$next = $task->replicate(['done', 'done_at', 'snooze_until']);
$next->done = false;
$next->done_at = null;
$next->snooze_until = null;
$next->deadline = match ($task->recurrence) {
'daily' => $task->deadline?->addDay() ?? now()->addDay(),
'weekly' => $task->deadline?->addWeek() ?? now()->addWeek(),
'monthly' => $task->deadline?->addMonth() ?? now()->addMonth(),
default => null,
};
$next->save();
}
return response()->json(['ok' => true, 'id' => $task->id]);
}
public function snooze(Request $r, Task $task): JsonResponse {
abort_unless($task->user_id === $r->user()->id, 403);
$minutes = (int) $r->input('minutes', 5);
$minutes = max(1, min(720, $minutes));
$task->update(['snooze_until' => now()->addMinutes($minutes)]);
return response()->json(['ok' => true, 'id' => $task->id, 'minutes' => $minutes]);
}
public function destroy(Request $r, Task $task): JsonResponse {
abort_unless($task->user_id === $r->user()->id, 403);
$task->delete();
return response()->json(['ok' => true]);
}
public function restore(Request $r, Task $task): JsonResponse {
abort_unless($task->user_id === $r->user()->id, 403);
$task->update(['done' => false, 'done_at' => null, 'snooze_until' => null]);
return response()->json($task);
}
/** Estadísticas rápidas para el dashboard */
public function stats(Request $r): JsonResponse {
$userId = $r->user()->id;
$today = now()->startOfDay();
return response()->json([
'pending' => Task::forUser($userId)->active()->count(),
'today' => Task::forUser($userId)->active()
->where('created_at', '>=', $today)->count(),
'done_today'=> Task::forUser($userId)->where('done', true)
->where('done_at', '>=', $today)->count(),
'overdue' => Task::forUser($userId)->active()
->where('deadline', '<', now())->count(),
'total_done'=> Task::forUser($userId)->where('done', true)->count(),
]);
}
private function syncTags(Task $task, array $tagNames): void {
$userId = $task->user_id;
$ids = [];
foreach ($tagNames as $name) {
$tag = \App\Models\Tag::firstOrCreate(
['user_id' => $userId, 'name' => $name],
['color' => '#a3a3a3']
);
$ids[] = $tag->id;
}
$task->tags()->sync($ids);
}
}