mirror of https://github.com/Devoalda/LaDo.git
feature(Project addition):
Added: - Functionality to add projects Fixed: - Todo Creation Functionality - Todo Update Functionality
This commit is contained in:
parent
3af59cfaba
commit
fcbd9e21ae
|
@ -37,12 +37,20 @@ class ProjectController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Complete this method
|
|
||||||
* Store a newly created project in storage.
|
* Store a newly created project in storage.
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
//
|
$user = User::find(auth()->user()->id);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'name' => 'required|unique:projects|max:255',
|
||||||
|
'description' => 'nullable|max:255',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->projects()->save(new Project($data));
|
||||||
|
|
||||||
|
return redirect()->route('project.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +59,7 @@ class ProjectController extends Controller
|
||||||
*/
|
*/
|
||||||
public function show(Project $project)
|
public function show(Project $project)
|
||||||
{
|
{
|
||||||
//
|
return redirect()->route('project.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +76,18 @@ class ProjectController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, Project $project)
|
public function update(Request $request, Project $project)
|
||||||
{
|
{
|
||||||
//
|
$user = User::find(auth()->user()->id);
|
||||||
|
$projects = $user->projects;
|
||||||
|
$project = $projects->find($project->id);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'name' => 'required|unique:projects|max:255',
|
||||||
|
'description' => 'nullable|max:255',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$project->update($data);
|
||||||
|
|
||||||
|
return back()->with('status', 'Project updated!');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -77,6 +77,7 @@ class ProjectTodoController extends Controller
|
||||||
|
|
||||||
$user = User::find(auth()->user()->id);
|
$user = User::find(auth()->user()->id);
|
||||||
$project = $user->projects->find($project_id);
|
$project = $user->projects->find($project_id);
|
||||||
|
// Add the Todo to the Project
|
||||||
$project->todos()->save($todo);
|
$project->todos()->save($todo);
|
||||||
|
|
||||||
return redirect()->route('project.todo.index', $project_id)
|
return redirect()->route('project.todo.index', $project_id)
|
||||||
|
@ -140,8 +141,7 @@ class ProjectTodoController extends Controller
|
||||||
|
|
||||||
$todo->update($data);
|
$todo->update($data);
|
||||||
|
|
||||||
return redirect()->route('project.todo.index', $project_id)
|
return back()->with('success', 'Todo updated successfully');
|
||||||
->with('success', 'Todo updated successfully');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Requests\StoreTodoRequest;
|
|
||||||
use App\Http\Requests\UpdateTodoRequest;
|
|
||||||
use App\Models\Todo;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Contracts\View\Factory;
|
|
||||||
use Illuminate\Contracts\View\View;
|
|
||||||
use Illuminate\Foundation\Application;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
|
||||||
use Illuminate\Support\Facades\Request;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
class TodoController extends Controller
|
|
||||||
{
|
|
||||||
private string $timezone = "Asia/Singapore";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*/
|
|
||||||
public function index(): View|Application
|
|
||||||
{
|
|
||||||
$user = User::find(auth()->user()->id);
|
|
||||||
|
|
||||||
$projects = $user->projects;
|
|
||||||
|
|
||||||
$todos = collect();
|
|
||||||
|
|
||||||
foreach ($projects as $project) {
|
|
||||||
$todos = $todos->merge($project->todos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return view('todo.index', [
|
|
||||||
'todos' => $todos->whereNull('completed_at')->values(),
|
|
||||||
'completed' => $todos->whereNotNull('completed_at')->values(),
|
|
||||||
'projects' => $projects,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*/
|
|
||||||
public function create(): Factory|View|Application
|
|
||||||
{
|
|
||||||
return view('todo.create');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*/
|
|
||||||
public function store(StoreTodoRequest $request): RedirectResponse
|
|
||||||
{
|
|
||||||
$validatedData = $request->validate([
|
|
||||||
'title' => 'required|max:255',
|
|
||||||
'description' => 'nullable|max:255',
|
|
||||||
'due_start' => 'nullable|date',
|
|
||||||
// due_end is not required, but if it is provided, it must be after due_start
|
|
||||||
'due_end' => 'nullable|after:due_start',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$due_end = match (true) {
|
|
||||||
isset($validatedData['due_end']) => strtotime($validatedData['due_end']),
|
|
||||||
isset($validatedData['due_start']) => strtotime($validatedData['due_start']),
|
|
||||||
default => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
$validatedData = array_merge($validatedData, [
|
|
||||||
// due_end = due_start if due_end is not provided and due_start is provided or null
|
|
||||||
'due_end' => $due_end,
|
|
||||||
'user_id' => auth()->user()->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Modify all dates to unix timestamp
|
|
||||||
if (isset($validatedData['due_start']))
|
|
||||||
$validatedData['due_start'] = strtotime($validatedData['due_start']);
|
|
||||||
if (isset($validatedData['due_end']))
|
|
||||||
$validatedData['due_end'] = strtotime($validatedData['due_end']);
|
|
||||||
|
|
||||||
$todo = new Todo($validatedData);
|
|
||||||
|
|
||||||
$user = User::find(auth()->user()->id);
|
|
||||||
$project = $user->projects->first();
|
|
||||||
$project->todos()->save($todo);
|
|
||||||
|
|
||||||
// Set flash message
|
|
||||||
session()->flash('success', 'Todo created successfully.');
|
|
||||||
|
|
||||||
return redirect()->route('todo.index');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*/
|
|
||||||
public function show(Todo $todo): Factory|View|Application
|
|
||||||
{
|
|
||||||
$user = User::find(auth()->user()->id);
|
|
||||||
$projects = $user->projects;
|
|
||||||
$todo = $projects->first()
|
|
||||||
->todos
|
|
||||||
->where('id', $todo->id)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
return view('todo.show', compact('todo'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*/
|
|
||||||
public function edit(Todo $todo): Factory|View|Application
|
|
||||||
{
|
|
||||||
$user = User::find(auth()->user()->id);
|
|
||||||
$projects = $user->projects;
|
|
||||||
$todo = $projects->first()
|
|
||||||
->todos
|
|
||||||
->where('id', $todo->id)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
return view('todo.edit', compact('todo'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
* Can either update completed_at (Checkbox) or other fields
|
|
||||||
*
|
|
||||||
* @param UpdateTodoRequest $request UpdateTodoRequest
|
|
||||||
* @param Todo $todo Todo Object
|
|
||||||
* @return RedirectResponse Redirect to todo.index
|
|
||||||
*/
|
|
||||||
public function update(UpdateTodoRequest $request, Todo $todo): RedirectResponse
|
|
||||||
{
|
|
||||||
$data = $request->only(['title', 'description', 'due_start', 'due_end', 'completed_at']);
|
|
||||||
|
|
||||||
if (Request::filled('completed_at')) {
|
|
||||||
$todo->completed_at = Request::input('completed_at') === 'on' ? strtotime(now($this->timezone)) : null;
|
|
||||||
$todo->save();
|
|
||||||
return redirect()->route('todo.index')->with('success', 'Good job! Todo completed.');
|
|
||||||
} else {
|
|
||||||
// If 'completed_at' is not provided, toggle its value (only if the request is empty)
|
|
||||||
if (empty($data))
|
|
||||||
$todo->completed_at = $todo->completed_at ? null : strtotime(now($this->timezone));
|
|
||||||
else
|
|
||||||
// Continue to update other fields
|
|
||||||
unset($data['completed_at']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Request::filled('due_start')) {
|
|
||||||
$data['due_start'] = strtotime(Request::input('due_start'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Request::filled('due_end')) {
|
|
||||||
$data['due_end'] = strtotime(Request::input('due_end'));
|
|
||||||
} elseif (isset($data['due_start'])) {
|
|
||||||
// If 'due_end' is not provided, set it to 'due_start' value
|
|
||||||
$data['due_end'] = strtotime(Request::input('due_start'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$todo->update($data);
|
|
||||||
|
|
||||||
return redirect()->route('todo.index')->with('success', 'Todo updated successfully.');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*/
|
|
||||||
public function destroy(Todo $todo): RedirectResponse
|
|
||||||
{
|
|
||||||
$todo = Todo::where('user_id', auth()->user()->id)
|
|
||||||
->where('id', $todo->id)
|
|
||||||
->firstOrFail();
|
|
||||||
$todo->delete();
|
|
||||||
|
|
||||||
// Set flash message
|
|
||||||
session()->flash('success', 'Todo deleted successfully.');
|
|
||||||
|
|
||||||
return redirect()->route('todo.index');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
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;
|
||||||
|
|
||||||
class Project extends Model
|
class Project extends Model
|
||||||
{
|
{
|
||||||
|
@ -25,13 +26,13 @@ class Project extends Model
|
||||||
* Relationship with Todo model (one to many)
|
* Relationship with Todo model (one to many)
|
||||||
* @return BelongsToMany
|
* @return BelongsToMany
|
||||||
*/
|
*/
|
||||||
public function todos(): HasManyThrough
|
public function todos(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->hasManyThrough(Todo::class, projectTodo::class, 'project_id', 'id', 'id', 'todo_id');
|
return $this->belongsToMany(Todo::class, 'project_todo', 'project_id', 'todo_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(projectUser::class, 'project_user', 'project_id', 'user_id');
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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\HasManyThrough;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ class Todo extends Model
|
||||||
|
|
||||||
public function project(): HasOneThrough
|
public function project(): HasOneThrough
|
||||||
{
|
{
|
||||||
return $this->hasOneThrough(Project::class, ProjectTodo::class, 'todo_id', 'id', 'id', 'project_id');
|
return $this->hasOneThrough(Project::class, projectTodo::class, 'todo_id', 'id', 'id', 'project_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ namespace App\Models;
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use App\Traits\UuidTrait;
|
use App\Traits\UuidTrait;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
@ -45,13 +47,13 @@ class User extends Authenticatable
|
||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function projects(): HasManyThrough
|
public function projects(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->hasManyThrough(Project::class, projectUser::class, 'user_id', 'id', 'id', 'project_id');
|
return $this->belongsToMany(Project::class, 'project_user', 'user_id', 'project_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function todos(): HasManyThrough
|
// public function todos(): HasManyThrough
|
||||||
{
|
// {
|
||||||
return $this->hasManyThrough(Todo::class, projectUser::class, 'user_id', 'id', 'id', 'project_id');
|
// return $this->hasManyThrough(Todo::class, projectUser::class, 'user_id', 'id', 'id', 'project_id');
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public const HOME = '/todo';
|
public const HOME = '/project';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define your route model bindings, pattern filters, and other route configuration.
|
* Define your route model bindings, pattern filters, and other route configuration.
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||||
|
{{ __('Create Project') }}
|
||||||
|
</h2>
|
||||||
|
</x-slot>
|
||||||
|
|
||||||
|
<!-- Create Project Form (Name, Description) -->
|
||||||
|
<div class="py-4">
|
||||||
|
<form method="POST" action="{{ route('project.store') }}" id="project-form">
|
||||||
|
@csrf
|
||||||
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
|
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6">
|
||||||
|
<div class="text-gray-800 dark:text-gray-100">
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="name" class="block mb-2 font-semibold">Name</label>
|
||||||
|
<input type="text" name="name" id="name" placeholder="Name"
|
||||||
|
class="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-700 focus:ring-2 focus:ring-blue-500 rounded-lg w-full p-4 @error('name') border-red-500 @enderror"
|
||||||
|
value="{{ old('name') }}">
|
||||||
|
@error('name')
|
||||||
|
<div class="text-red-500 mt-2 text-sm">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="description" class="block mb-2 font-semibold">Description</label>
|
||||||
|
<textarea name="description" id="description" placeholder="Description"
|
||||||
|
class="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-700 focus:ring-2 focus:ring-blue-500 rounded-lg w-full p-4 @error('description') border-red-500 @enderror">{{ old('description') }}</textarea>
|
||||||
|
@error('description')
|
||||||
|
<div class="text-red-500 mt-2 text-sm">
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="submit"
|
||||||
|
class="bg-blue-500 hover:bg-blue-600 text-white font-semibold px-4 py-2 rounded-lg">
|
||||||
|
Create Project
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</x-app-layout>
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,19 @@
|
||||||
</h2>
|
</h2>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
|
<!-- Success/Error Message in green/red session('success') or session('error') -->
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="bg-green-500 text-white p-4 rounded-lg mb-6 text-center">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="bg-red-500 text-white p-4 rounded-lg mb-6 text-center">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<form method="POST" action="{{ route('project.todo.update', [$project, $todo]) }}"
|
<form method="POST" action="{{ route('project.todo.update', [$project, $todo]) }}"
|
||||||
id="todo-form">
|
id="todo-form">
|
||||||
|
|
|
@ -9,6 +9,18 @@
|
||||||
</h2>
|
</h2>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
|
|
||||||
|
<!-- Success/Error Message in green/red session('success') or session('error') -->
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="bg-green-500 text-white p-4 rounded-lg mb-6 text-center">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="bg-red-500 text-white p-4 rounded-lg mb-6 text-center">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
|
@ -83,12 +95,12 @@
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@foreach ($todos as $todo)
|
@foreach ($todos as $todo)
|
||||||
@if (!$todo->completed_at)
|
@if (!$todo->completed_at)
|
||||||
<a href="{{ route('project.todo.edit', [$project->id, $todo->id]) }}" class="block">:
|
<a href="{{ route('project.todo.edit', [$todo->project->id, $todo->id]) }}" class="block">
|
||||||
<div
|
<div
|
||||||
class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 flex items-center justify-between">
|
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">
|
||||||
<!-- Checkbox to toggle completed at -->
|
<!-- Checkbox to toggle completed at -->
|
||||||
<form action="{{ route('project.todo.update', [$project->id, $todo->id]) }}"
|
<form action="{{ route('project.todo.update', [$todo->project->id, $todo->id]) }}"
|
||||||
method="POST"
|
method="POST"
|
||||||
class="toggle-completed-form">
|
class="toggle-completed-form">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
Loading…
Reference in New Issue