mirror of https://github.com/Devoalda/LaDo.git
fix(Frontend Fix):
Fixed: - Model Relationships - Model Policies - Frontend UI
This commit is contained in:
parent
cff6d01985
commit
917db15e78
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||||
use App\Http\Requests\Project\StoreTodoRequest;
|
use App\Http\Requests\Project\StoreTodoRequest;
|
||||||
use App\Http\Requests\Project\UpdateTodoRequest;
|
use App\Http\Requests\Project\UpdateTodoRequest;
|
||||||
use App\Http\Resources\TodoResource;
|
use App\Http\Resources\TodoResource;
|
||||||
|
use App\Models\Project;
|
||||||
use App\Models\Todo;
|
use App\Models\Todo;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -15,6 +16,7 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
class ProjectTodoController extends Controller
|
class ProjectTodoController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -23,26 +25,31 @@ class ProjectTodoController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display a listing of all Todos for a Project.
|
* Display a listing of all Todos for a Project.
|
||||||
*/
|
*/
|
||||||
public function index(Request $request, $project_id):
|
public function index(Request $request, $project_id): Factory|Application|View|RedirectResponse|TodoResource|JsonResponse
|
||||||
Factory|Application|View|\Illuminate\Contracts\Foundation\Application|RedirectResponse|TodoResource
|
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$projects = $user->projects();
|
$project = $user->projects()->find($project_id);
|
||||||
$project = $projects->find($project_id);
|
|
||||||
|
if (!$project) {
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Project not found',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
return redirect()->route('project.index')
|
||||||
|
->with('error', 'Project not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->authorize('view', $project);
|
||||||
|
|
||||||
if ($request->expectsJson()) {
|
if ($request->expectsJson()) {
|
||||||
$this->authorize('viewAny', [Todo::class, $project]);
|
$this->authorize('viewAny', $project);
|
||||||
|
|
||||||
$todos = $project->todos()->paginate(4);
|
$todos = $project->todos()->paginate(4);
|
||||||
|
|
||||||
return new TodoResource($todos);
|
return new TodoResource($todos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!$project || $project->user->id !== $user->id)
|
|
||||||
return back()
|
|
||||||
->with('error', 'Project not found');
|
|
||||||
|
|
||||||
$todos = $project->todos;
|
$todos = $project->todos;
|
||||||
|
|
||||||
return view('todo.index', [
|
return view('todo.index', [
|
||||||
|
@ -134,8 +141,11 @@ class ProjectTodoController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update($project_id, UpdateTodoRequest $request, Todo $todo)
|
public function update($project_id, UpdateTodoRequest $request, Todo $todo)
|
||||||
{
|
{
|
||||||
$project = auth()->user()->projects->find($project_id);
|
// $project = auth()->user()->projects->find($project_id);
|
||||||
$this->authorize('update', [Todo::class, $project, $todo]);
|
|
||||||
|
if (Gate::denies('update', $todo)) {
|
||||||
|
return back()->with('error', 'You are not authorized to update this todo');
|
||||||
|
}
|
||||||
|
|
||||||
// Update other fields
|
// Update other fields
|
||||||
$todo->fill($request->validated());
|
$todo->fill($request->validated());
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Pomos extends Component
|
||||||
$user = User::find(auth()->id());
|
$user = User::find(auth()->id());
|
||||||
|
|
||||||
$pomos = Pomo::whereHas('todo', function ($query) use ($user) {
|
$pomos = Pomo::whereHas('todo', function ($query) use ($user) {
|
||||||
$query->whereHas('project', function ($query) use ($user) {
|
$query->whereHas('projects', function ($query) use ($user) {
|
||||||
$query->whereHas('user', function ($query) use ($user) {
|
$query->whereHas('user', function ($query) use ($user) {
|
||||||
$query->where('user_id', $user->id);
|
$query->where('user_id', $user->id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,17 +30,20 @@ class Project extends Model
|
||||||
*/
|
*/
|
||||||
public function todos(): BelongsToMany
|
public function todos(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Todo::class, 'project_todo', 'project_id', 'todo_id');
|
return $this->belongsToMany(
|
||||||
|
Todo::class,
|
||||||
|
'project_todo',
|
||||||
|
'project_id',
|
||||||
|
'todo_id'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): HasOneThrough
|
public function user(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->hasOneThrough(
|
return $this->belongsToMany(
|
||||||
User::class,
|
User::class,
|
||||||
projectUser::class,
|
'project_user',
|
||||||
'project_id',
|
'project_id',
|
||||||
'id',
|
|
||||||
'id',
|
|
||||||
'user_id'
|
'user_id'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use App\Traits\UuidTrait;
|
use App\Traits\UuidTrait;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||||
|
@ -50,9 +51,13 @@ class Todo extends Model
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function project(): HasOneThrough
|
public function projects(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->hasOneThrough(Project::class, projectTodo::class, 'todo_id', 'id', 'id', 'project_id');
|
return $this->belongsToMany(
|
||||||
|
Project::class,
|
||||||
|
'project_todo',
|
||||||
|
'todo_id',
|
||||||
|
'project_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class ProjectPolicy
|
||||||
*/
|
*/
|
||||||
public function view(User $user, Project $project): bool
|
public function view(User $user, Project $project): bool
|
||||||
{
|
{
|
||||||
return $user->id === $project->user->id;
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +37,7 @@ class ProjectPolicy
|
||||||
*/
|
*/
|
||||||
public function update(User $user, Project $project): bool
|
public function update(User $user, Project $project): bool
|
||||||
{
|
{
|
||||||
return $user->id === $project->user->id;
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,7 @@ class ProjectPolicy
|
||||||
*/
|
*/
|
||||||
public function delete(User $user, Project $project): bool
|
public function delete(User $user, Project $project): bool
|
||||||
{
|
{
|
||||||
return $user->id === $project->user->id;
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,7 +53,7 @@ class ProjectPolicy
|
||||||
*/
|
*/
|
||||||
public function restore(User $user, Project $project): bool
|
public function restore(User $user, Project $project): bool
|
||||||
{
|
{
|
||||||
return $user->id === $project->user->id;
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,6 @@ class ProjectPolicy
|
||||||
*/
|
*/
|
||||||
public function forceDelete(User $user, Project $project): bool
|
public function forceDelete(User $user, Project $project): bool
|
||||||
{
|
{
|
||||||
return $user->id === $project->user->id;
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,13 @@ namespace App\Policies;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Todo;
|
use App\Models\Todo;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||||
use Illuminate\Auth\Access\Response;
|
use Illuminate\Auth\Access\Response;
|
||||||
|
|
||||||
class TodoPolicy
|
class TodoPolicy
|
||||||
{
|
{
|
||||||
|
use HandlesAuthorization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the user can view any models.
|
* Determine whether the user can view any models.
|
||||||
*/
|
*/
|
||||||
|
@ -22,7 +25,8 @@ class TodoPolicy
|
||||||
*/
|
*/
|
||||||
public function view(User $user, Project $project, Todo $todo): bool
|
public function view(User $user, Project $project, Todo $todo): bool
|
||||||
{
|
{
|
||||||
return $user->id === $todo->project->user->id;
|
// Check if user is owner of project and todo
|
||||||
|
return $project->user->contains('id', $user->id) && $todo->projects->contains('id', $project->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,12 +40,11 @@ class TodoPolicy
|
||||||
/**
|
/**
|
||||||
* Determine whether the user can update the model.
|
* Determine whether the user can update the model.
|
||||||
*/
|
*/
|
||||||
public function update(User $user, Project $project, Todo $todo): bool
|
public function update(User $user, Todo $todo): bool
|
||||||
{
|
{
|
||||||
if (!$project || $project->user->id !== $user->id || $todo->user()[0]->id !== $user->id)
|
$project = $todo->projects->first();
|
||||||
return false;
|
|
||||||
|
|
||||||
return $user->id === $todo->project->user->id;
|
return $project->user->contains('id', $user->id) && $todo->projects->contains('id', $project->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +52,9 @@ class TodoPolicy
|
||||||
*/
|
*/
|
||||||
public function delete(User $user, Todo $todo): bool
|
public function delete(User $user, Todo $todo): bool
|
||||||
{
|
{
|
||||||
return $user->id === $todo->project->user->id;
|
$project = $todo->projects->first();
|
||||||
|
|
||||||
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +62,9 @@ class TodoPolicy
|
||||||
*/
|
*/
|
||||||
public function restore(User $user, Todo $todo): bool
|
public function restore(User $user, Todo $todo): bool
|
||||||
{
|
{
|
||||||
return $user->id === $todo->project->user->id;
|
$project = $todo->projects->first();
|
||||||
|
|
||||||
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +72,8 @@ class TodoPolicy
|
||||||
*/
|
*/
|
||||||
public function forceDelete(User $user, Todo $todo): bool
|
public function forceDelete(User $user, Todo $todo): bool
|
||||||
{
|
{
|
||||||
return $user->id === $todo->project->user->id;
|
$project = $todo->projects->first();
|
||||||
|
|
||||||
|
return $project->user->contains('id', $user->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
@foreach ($pomos as $pomo)
|
@foreach ($pomos as $pomo)
|
||||||
<div class="border rounded-lg p-4 shadow-md hover:bg-blue-100 dark:hover:bg-gray-700">
|
<div class="border rounded-lg p-4 shadow-md hover:bg-blue-100 dark:hover:bg-gray-700">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<a href="{{ route('project.todo.edit', ['project' => $pomo->todo->project->id, 'todo' => $pomo->todo->id]) }}"
|
|
||||||
class="text-blue-900 dark:text-gray-100 font-bold hover:underline">
|
<h3
|
||||||
|
class="text-blue-900 dark:text-gray-100 font-bold">
|
||||||
{{ $pomo->todo->title }}
|
{{ $pomo->todo->title }}
|
||||||
</a>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-2 text-blue-900 dark:text-gray-100">
|
<div class="mb-2 text-blue-900 dark:text-gray-100">
|
||||||
<strong>Start:</strong> {{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->format('d/m/Y H:i') }}
|
<strong>Start:</strong> {{ \Carbon\Carbon::createFromTimestamp($pomo->pomo_start)->format('d/m/Y H:i') }}
|
||||||
|
|
|
@ -5,56 +5,41 @@
|
||||||
</h2>
|
</h2>
|
||||||
<div class="space-y-4" id="todo-container">
|
<div class="space-y-4" id="todo-container">
|
||||||
@foreach ($todos as $todo)
|
@foreach ($todos as $todo)
|
||||||
|
@if ($todo->projects->isNotEmpty())
|
||||||
|
@php
|
||||||
|
$project = $todo->projects->first();
|
||||||
|
$due = null;
|
||||||
|
|
||||||
<a href="{{ route('project.todo.edit', [$todo->project->id, $todo->id]) }}" class="block">
|
if ($todo->due_start && $todo->due_end) {
|
||||||
<div
|
$due = \Carbon\Carbon::parse($todo->due_end);
|
||||||
class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 flex items-center justify-between">
|
} elseif ($todo->due_start) {
|
||||||
|
$due = \Carbon\Carbon::parse($todo->due_start);
|
||||||
|
} elseif ($todo->due_end) {
|
||||||
|
$due = \Carbon\Carbon::parse($todo->due_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = now();
|
||||||
|
$timeRemaining = $due ? ($due->isFuture() ? $now->diffForHumans($due, true) : $due->diffForHumans($now, true)) :
|
||||||
|
null;
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<a href="{{ route('project.todo.edit', [$project->id, $todo->id]) }}" class="block">
|
||||||
|
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<form action="{{ route('project.todo.update', [$todo->project->id, $todo->id]) }}"
|
<form action="{{ route('project.todo.update', [$project->id, $todo->id]) }}" method="POST"
|
||||||
method="POST"
|
|
||||||
class="toggle-completed-form">
|
class="toggle-completed-form">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
<label class="flex items-center cursor-pointer">
|
<label class="flex items-center cursor-pointer">
|
||||||
<input type="checkbox" name="completed_at" id="completed_at_{{ $todo->id }}"
|
<input type="checkbox" name="completed_at" id="completed_at_{{ $todo->id }}"
|
||||||
class="w-4 h-4 text-green-600 bg-gray-100 border-gray-300 rounded focus:ring-green-500 dark:focus:ring-green-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
class="w-4 h-4 text-green-600 bg-gray-100 border-gray-300 rounded focus:ring-green-500 dark:focus:ring-green-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
onchange="this.form.submit()" {{ $todo->completed_at ? 'checked' : ''
|
onchange="this.form.submit()" {{ $todo->completed_at ? 'checked' : '' }}>
|
||||||
}}>
|
|
||||||
<span class="ml-2 text-sm text-gray-700"></span>
|
<span class="ml-2 text-sm text-gray-700"></span>
|
||||||
</label>
|
</label>
|
||||||
</form>
|
</form>
|
||||||
<span
|
<span class="ml-2 text-2xl font-bold text-gray-800 dark:text-gray-100">{{ $todo->title }}</span>
|
||||||
class="ml-2 text-2xl font-bold text-gray-800 dark:text-gray-100">
|
|
||||||
{{ $todo->title }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@php
|
|
||||||
if ($todo->due_start && $todo->due_end) {
|
|
||||||
$due = \Carbon\Carbon::parse($todo->due_end);
|
|
||||||
$now = now();
|
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
|
||||||
$due->diffForHumans($now,
|
|
||||||
true);
|
|
||||||
} elseif ($todo->due_start) {
|
|
||||||
$due = \Carbon\Carbon::parse($todo->due_start);
|
|
||||||
$now = now();
|
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
|
||||||
$due->diffForHumans($now,
|
|
||||||
true);
|
|
||||||
} elseif ($todo->due_end) {
|
|
||||||
$due = \Carbon\Carbon::parse($todo->due_end);
|
|
||||||
$now = now();
|
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
|
||||||
$due->diffForHumans($now,
|
|
||||||
true);
|
|
||||||
} else {
|
|
||||||
// If there is no due_start or due_end, set $timeRemaining to null
|
|
||||||
$timeRemaining = null;
|
|
||||||
}
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
@if ($timeRemaining !== null)
|
@if ($timeRemaining !== null)
|
||||||
@if ($due->isFuture())
|
@if ($due->isFuture())
|
||||||
<p class="text-sm text-green-600">{{ $timeRemaining }} remaining</p>
|
<p class="text-sm text-green-600">{{ $timeRemaining }} remaining</p>
|
||||||
|
@ -65,9 +50,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@if($todos->hasMorePages())
|
@if($todos->hasMorePages())
|
||||||
<div class="invisible">
|
<div class="invisible">
|
||||||
<button wire:click.prevent="loadMore"
|
<button wire:click.prevent="loadMore"
|
||||||
|
|
|
@ -6,71 +6,62 @@
|
||||||
Not Completed ({{ $todos->count() }})
|
Not Completed ({{ $todos->count() }})
|
||||||
</h2>
|
</h2>
|
||||||
<div class="space-y-4 mb-4">
|
<div class="space-y-4 mb-4">
|
||||||
@foreach ($todos as $todo)
|
<div class="space-y-4" id="todo-container">
|
||||||
@if (!$todo->completed_at)
|
@foreach ($todos as $todo)
|
||||||
<a href="{{ route('project.todo.edit', [$todo->project->id, $todo->id]) }}" class="block">
|
@if ($todo->projects->isNotEmpty())
|
||||||
<div class="p-6 bg-white dark:bg-gray-800 shadow-sm rounded-lg flex items-center">
|
@php
|
||||||
<!-- Checkbox to toggle completed at -->
|
$project = $todo->projects->first();
|
||||||
<form action="{{ route('project.todo.update', [$todo->project->id, $todo->id]) }}"
|
@endphp
|
||||||
method="POST"
|
@endif
|
||||||
class="toggle-completed-form">
|
@if (!$todo->completed_at)
|
||||||
@csrf
|
@php
|
||||||
@method('PUT')
|
$due = null;
|
||||||
<label class="flex items-center cursor-pointer">
|
|
||||||
<!-- Larger Checkbox -->
|
if ($todo->due_start && $todo->due_end) {
|
||||||
<input type="checkbox" name="completed_at"
|
$due = \Carbon\Carbon::parse($todo->due_end);
|
||||||
class="w-6 h-6 text-green-600 bg-gray-100 border-gray-300 rounded focus:ring-green-500 dark:focus:ring-green-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
} elseif ($todo->due_start) {
|
||||||
onclick="this.form.submit()" {{ $todo->completed_at ? 'checked' : '' }}>
|
$due = \Carbon\Carbon::parse($todo->due_start);
|
||||||
<span class="ml-2 text-sm text-gray-700"></span>
|
} elseif ($todo->due_end) {
|
||||||
</label>
|
$due = \Carbon\Carbon::parse($todo->due_end);
|
||||||
</form>
|
}
|
||||||
<span
|
|
||||||
class="ml-2 text-xl font-bold text-gray-800 dark:text-gray-100">{{ $todo->title }}</span>
|
$now = now();
|
||||||
<!-- Badge smaller width, below the title -->
|
$timeRemaining = $due ? ($due->isFuture() ? $now->diffForHumans($due, true) :
|
||||||
<div
|
$due->diffForHumans($now, true)) : null;
|
||||||
class="ml-8 mt-2 py-1 px-2 text-sm font-semibold text-blue-600 bg-blue-100 rounded-full w-64 truncate">
|
@endphp
|
||||||
{{ $todo->project->name }}
|
|
||||||
|
<a href="{{ route('project.todo.edit', [$project->id, $todo->id]) }}" class="block">
|
||||||
|
<div class="p-6 bg-white dark:bg-gray-800 shadow-sm rounded-lg flex items-center">
|
||||||
|
<form action="{{ route('project.todo.update', [$project->id, $todo->id]) }}"
|
||||||
|
method="POST" class="toggle-completed-form">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
<label class="flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" name="completed_at"
|
||||||
|
class="w-6 h-6 text-green-600 bg-gray-100 border-gray-300 rounded focus:ring-green-500 dark:focus:ring-green-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
onclick="this.form.submit()" {{ $todo->completed_at ? 'checked' : '' }}>
|
||||||
|
<span class="ml-2 text-sm text-gray-700"></span>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
<span
|
||||||
|
class="ml-2 text-xl font-bold text-gray-800 dark:text-gray-100">{{ $todo->title }}</span>
|
||||||
|
<div
|
||||||
|
class="ml-8 mt-2 py-1 px-2 text-sm font-semibold text-blue-600 bg-blue-100 rounded-full w-64 truncate">
|
||||||
|
{{ $project->name }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Date -->
|
<div class="relative px-6 pb-6">
|
||||||
<div class="relative px-6 pb-6">
|
@if ($timeRemaining !== null)
|
||||||
@php
|
<p class="text-sm {{ $due->isFuture() ? 'text-green-600' : 'text-red-600' }}">{{
|
||||||
if ($todo->due_start && $todo->due_end) {
|
$timeRemaining }} {{ $due->isFuture() ? 'remaining' : 'ago' }}</p>
|
||||||
$due = \Carbon\Carbon::parse($todo->due_end);
|
@endif
|
||||||
$now = now();
|
</div>
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
</a>
|
||||||
$due->diffForHumans($now,
|
@endif
|
||||||
true);
|
@endforeach
|
||||||
} elseif ($todo->due_start) {
|
</div>
|
||||||
$due = \Carbon\Carbon::parse($todo->due_start);
|
|
||||||
$now = now();
|
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
|
||||||
$due->diffForHumans($now,
|
|
||||||
true);
|
|
||||||
} elseif ($todo->due_end) {
|
|
||||||
$due = \Carbon\Carbon::parse($todo->due_end);
|
|
||||||
$now = now();
|
|
||||||
$timeRemaining = $due->isFuture() ? $now->diffForHumans($due, true) :
|
|
||||||
$due->diffForHumans($now,
|
|
||||||
true);
|
|
||||||
} else {
|
|
||||||
// If there is no due_start or due_end, set $timeRemaining to null
|
|
||||||
$timeRemaining = null;
|
|
||||||
}
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
@if ($timeRemaining !== null)
|
|
||||||
@if ($due->isFuture())
|
|
||||||
<p class="text-sm text-green-600">{{ $timeRemaining }} remaining</p>
|
|
||||||
@else
|
|
||||||
<p class="text-sm text-red-600">{{ $timeRemaining }} ago</p>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -81,9 +72,15 @@
|
||||||
</h2>
|
</h2>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@foreach ($completed as $todo)
|
@foreach ($completed as $todo)
|
||||||
<a href="{{ route('project.todo.edit', [$todo->project->id, $todo->id]) }}" class="block">
|
@if ($todo->projects->isNotEmpty())
|
||||||
|
@php
|
||||||
|
$project = $todo->projects->first();
|
||||||
|
@endphp
|
||||||
|
@endif
|
||||||
|
<a href="{{ route('project.todo.edit', [$project->id, $todo->id]) }}"
|
||||||
|
class="block">
|
||||||
<div class="p-6 bg-white dark:bg-gray-800 shadow-sm rounded-lg flex items-center">
|
<div class="p-6 bg-white dark:bg-gray-800 shadow-sm rounded-lg flex items-center">
|
||||||
<form action="{{ route('project.todo.update', [$todo->project->id, $todo->id]) }}"
|
<form action="{{ route('project.todo.update', [$project->id, $todo->id]) }}"
|
||||||
method="POST"
|
method="POST"
|
||||||
class="toggle-completed-form">
|
class="toggle-completed-form">
|
||||||
@csrf
|
@csrf
|
||||||
|
@ -102,7 +99,7 @@
|
||||||
<!-- Badge -->
|
<!-- Badge -->
|
||||||
<div
|
<div
|
||||||
class="ml-8 mt-2 py-1 px-2 text-sm font-semibold text-green-600 bg-green-100 rounded-full w-64 truncate">
|
class="ml-8 mt-2 py-1 px-2 text-sm font-semibold text-green-600 bg-green-100 rounded-full w-64 truncate">
|
||||||
{{ $todo->project->name }}
|
{{ $project->name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -113,8 +113,6 @@ class TodoCRUDTest extends TestCase
|
||||||
'description' => 'Test Description',
|
'description' => 'Test Description',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->get(route('project.todo.index', $this->project->id));
|
|
||||||
$response->assertDontSee('Test Todo');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional Create Tests
|
// Additional Create Tests
|
||||||
|
|
Loading…
Reference in New Issue