Skip to content

Commit 85e50a1

Browse files
author
Yaroslav Pohil
committed
- Implement task management features: add endpoints for retrieving trashed, completed, and pending tasks;
- Update Task model to use soft deletes; - Modify API request validation; enhance frontend with task management UI; - Update tests for new functionality.
1 parent ddef213 commit 85e50a1

File tree

26 files changed

+845
-179
lines changed

26 files changed

+845
-179
lines changed

app/Http/Controllers/API/TasksController.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,92 @@ public function destroy(Request $request, Task $task): JsonResponse
7676
'message' => 'Task deleted successfully'
7777
]);
7878
}
79+
80+
/**
81+
* Get all trashed tasks for the authenticated user.
82+
*
83+
* @param Request $request
84+
* @return JsonResponse
85+
*/
86+
public function trashed(Request $request): JsonResponse
87+
{
88+
if ($request->user()?->cannot('view', Task::class)) {
89+
abort(403, 'Forbidden');
90+
}
91+
92+
$tasks = Task::onlyTrashed()
93+
->where('user_id', $request->user()->id)
94+
->latest()
95+
->get();
96+
97+
return response()->json([
98+
'data' => $tasks
99+
]);
100+
}
101+
102+
/**
103+
* Get all completed tasks for the authenticated user.
104+
*
105+
* @param Request $request
106+
* @return JsonResponse
107+
*/
108+
public function completed(Request $request): JsonResponse
109+
{
110+
if ($request->user()?->cannot('view', Task::class)) {
111+
abort(403, 'Forbidden');
112+
}
113+
114+
$tasks = Task::where('user_id', $request->user()->id)
115+
->whereNotNull('completed_at')
116+
->orderBy('completed_at', 'desc')
117+
->get();
118+
119+
return response()->json([
120+
'data' => $tasks
121+
]);
122+
}
123+
124+
/**
125+
* Get all pending tasks for the authenticated user.
126+
*
127+
* @param Request $request
128+
* @return JsonResponse
129+
*/
130+
public function pending(Request $request): JsonResponse
131+
{
132+
if ($request->user()?->cannot('view', Task::class)) {
133+
abort(403, 'Forbidden');
134+
}
135+
136+
$tasks = Task::where('user_id', $request->user()->id)
137+
->whereNull('completed_at')
138+
->orderBy('created_at', 'desc')
139+
->get();
140+
141+
return response()->json([
142+
'data' => $tasks
143+
]);
144+
}
145+
146+
/**
147+
* Mark a task as completed.
148+
*
149+
* @param Request $request
150+
* @param Task $task
151+
* @return JsonResponse
152+
*/
153+
public function complete(Request $request, Task $task): JsonResponse
154+
{
155+
if ($request->user()?->cannot('update', $task)) {
156+
abort(403, 'Forbidden');
157+
}
158+
159+
$task->completed_at = now();
160+
$task->save();
161+
162+
return response()->json([
163+
'message' => 'Task completed successfully',
164+
'data' => $task
165+
]);
166+
}
79167
}

app/Http/Requests/TaskFormRequest.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,7 @@ public function rules(): array
2525
return [
2626
'title' => 'required|string|max:255',
2727
'description' => 'required|string',
28-
'status' => [
29-
'sometimes',
30-
'string',
31-
'in:' . implode(',', [
32-
Task::STATUS_PENDING,
33-
Task::STATUS_IN_PROGRESS,
34-
Task::STATUS_COMPLETED
35-
])
36-
],
28+
'completed_at' => 'nullable|datetime',
3729
];
3830
}
3931
}

app/Models/Task.php

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,27 @@
77
use Illuminate\Database\Eloquent\Relations\BelongsTo;
88
use Illuminate\Support\Carbon;
99
use Database\Factories\TaskFactory;
10+
use Illuminate\Database\Eloquent\SoftDeletes;
1011

1112
/**
1213
* Task model representing a task in the system.
1314
*
1415
* @property int $id
1516
* @property string $title
1617
* @property string|null $description
17-
* @property string $status One of pending, in_progress, completed
1818
* @property int $user_id
1919
* @property Carbon|null $completed_at
2020
* @property Carbon $created_at
2121
* @property Carbon $updated_at
22-
*
22+
*
2323
* @property-read User $user
24-
*
24+
*
2525
* @method static TaskFactory factory($count = null, $state = [])
2626
*/
2727
class Task extends Model
2828
{
2929
use HasFactory;
30-
31-
/**
32-
* Task status constants
33-
*/
34-
public const STATUS_PENDING = 'pending';
35-
public const STATUS_IN_PROGRESS = 'in_progress';
36-
public const STATUS_COMPLETED = 'completed';
30+
use SoftDeletes;
3731

3832
/**
3933
* The attributes that are mass assignable.
@@ -43,7 +37,6 @@ class Task extends Model
4337
protected $fillable = [
4438
'title',
4539
'description',
46-
'status',
4740
'user_id',
4841
'completed_at',
4942
];
@@ -59,15 +52,4 @@ public function user(): BelongsTo
5952
{
6053
return $this->belongsTo(User::class);
6154
}
62-
63-
public static function boot()
64-
{
65-
parent::boot();
66-
67-
static::updating(function ($task) {
68-
if ($task->isDirty('status') && $task->status === self::STATUS_COMPLETED) {
69-
$task->completed_at = now();
70-
}
71-
});
72-
}
7355
}

database/factories/TaskFactory.php

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,48 +21,16 @@ public function definition(): array
2121
return [
2222
'title' => fake()->sentence(4),
2323
'description' => fake()->paragraph(),
24-
'status' => fake()->randomElement([
25-
Task::STATUS_PENDING,
26-
Task::STATUS_IN_PROGRESS,
27-
Task::STATUS_COMPLETED
28-
]),
2924
'user_id' => User::factory(),
30-
'completed_at' => function (array $attributes) {
31-
return $attributes['status'] === Task::STATUS_COMPLETED ? now() : null;
32-
},
33-
];
34-
}
35-
36-
/**
37-
* Indicate that the task is pending.
38-
*/
39-
public function pending(): static
40-
{
41-
return $this->state(fn (array $attributes) => [
42-
'status' => Task::STATUS_PENDING,
43-
'completed_at' => null,
44-
]);
45-
}
46-
47-
/**
48-
* Indicate that the task is in progress.
49-
*/
50-
public function inProgress(): static
51-
{
52-
return $this->state(fn (array $attributes) => [
53-
'status' => Task::STATUS_IN_PROGRESS,
5425
'completed_at' => null,
55-
]);
26+
];
5627
}
57-
58-
/**
59-
* Indicate that the task is completed.
60-
*/
28+
6129
public function completed(): static
6230
{
6331
return $this->state(fn (array $attributes) => [
64-
'status' => Task::STATUS_COMPLETED,
6532
'completed_at' => now(),
6633
]);
6734
}
35+
6836
}

database/migrations/2025_05_05_074028_create_tasks_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ public function up(): void
1414
$table->id();
1515
$table->string('title');
1616
$table->text('description')->nullable();
17-
$table->enum('status', ['pending', 'in_progress', 'completed'])->default('pending');
1817
$table->foreignId('user_id')->constrained()->onDelete('cascade');
1918
$table->timestamp('completed_at')->nullable();
19+
$table->softDeletes();
2020
$table->timestamps();
2121
});
2222
}

0 commit comments

Comments
 (0)