This was already implemented, migrated, and running live, but had never been committed. Bringing it into git: Project/Task/Idea/ TaskComment models, their JSON API (CRUD + status transitions, task comments, idea<->project linking), Livewire UI pages, and the nav/route wiring for them. All 42 of its own tests pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
128 lines
3.4 KiB
PHP
128 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\StoreTaskRequest;
|
|
use App\Http\Requests\UpdateTaskRequest;
|
|
use App\Http\Resources\TaskResource;
|
|
use App\Models\Task;
|
|
use Illuminate\Http\Request;
|
|
|
|
class TaskController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$query = Task::with(['project', 'comments']);
|
|
|
|
if ($request->filled('status')) {
|
|
$query->where('status', $request->string('status'));
|
|
}
|
|
|
|
if ($request->filled('project_id')) {
|
|
$query->where('project_id', $request->integer('project_id'));
|
|
}
|
|
|
|
if ($request->filled('priority')) {
|
|
$query->where('priority', $request->integer('priority'));
|
|
}
|
|
|
|
if ($request->boolean('due_soon')) {
|
|
$query->dueSoon($request->integer('days', 3));
|
|
}
|
|
|
|
if ($request->boolean('overdue')) {
|
|
$query->overdue();
|
|
}
|
|
|
|
$tasks = $query->orderBy('priority', 'desc')->orderBy('created_at')->get();
|
|
|
|
return TaskResource::collection($tasks);
|
|
}
|
|
|
|
public function store(StoreTaskRequest $request)
|
|
{
|
|
$task = Task::create($request->validated());
|
|
|
|
return (new TaskResource($task))
|
|
->response()
|
|
->setStatusCode(201);
|
|
}
|
|
|
|
public function show(Request $request, Task $task)
|
|
{
|
|
$task->load(['project', 'comments']);
|
|
|
|
return new TaskResource($task);
|
|
}
|
|
|
|
public function update(UpdateTaskRequest $request, Task $task)
|
|
{
|
|
// Handle status transitions
|
|
$validated = $request->validated();
|
|
|
|
// Auto-set timestamps based on status
|
|
if (isset($validated['status'])) {
|
|
if ($validated['status'] === 'in_progress' && ! $task->started_at) {
|
|
$validated['started_at'] = now();
|
|
}
|
|
if (in_array($validated['status'], ['done', 'completed']) && ! $task->completed_at) {
|
|
$validated['completed_at'] = now();
|
|
}
|
|
if ($validated['status'] !== 'in_progress') {
|
|
$validated['started_at'] = null;
|
|
}
|
|
}
|
|
|
|
$task->update($validated);
|
|
|
|
return new TaskResource($task->fresh(['project', 'comments']));
|
|
}
|
|
|
|
public function destroy(Task $task)
|
|
{
|
|
$task->delete();
|
|
|
|
return response()->noContent();
|
|
}
|
|
|
|
/**
|
|
* Get comments for a task.
|
|
*/
|
|
public function comments(Request $request, Task $task)
|
|
{
|
|
$comments = $task->comments()->orderBy('created_at')->get();
|
|
|
|
return TaskCommentResource::collection($comments);
|
|
}
|
|
|
|
/**
|
|
* Change task status.
|
|
*/
|
|
public function changeStatus(Request $request, Task $task)
|
|
{
|
|
$request->validate([
|
|
'status' => ['required', 'string', 'in:' . implode(',', Task::STATUSES)],
|
|
]);
|
|
|
|
$status = $request->string('status');
|
|
|
|
$updateData = ['status' => $status];
|
|
|
|
// Auto-set timestamps
|
|
if ($status === 'in_progress' && ! $task->started_at) {
|
|
$updateData['started_at'] = now();
|
|
}
|
|
if (in_array($status, ['done', 'completed']) && ! $task->completed_at) {
|
|
$updateData['completed_at'] = now();
|
|
}
|
|
if ($status !== 'in_progress') {
|
|
$updateData['started_at'] = null;
|
|
}
|
|
|
|
$task->update($updateData);
|
|
|
|
return new TaskResource($task->fresh(['project', 'comments']));
|
|
}
|
|
}
|