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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
//
|
||||
return redirect()->route('project.index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +76,18 @@ class ProjectController extends Controller
|
|||
*/
|
||||
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);
|
||||
$project = $user->projects->find($project_id);
|
||||
// Add the Todo to the Project
|
||||
$project->todos()->save($todo);
|
||||
|
||||
return redirect()->route('project.todo.index', $project_id)
|
||||
|
@ -140,8 +141,7 @@ class ProjectTodoController extends Controller
|
|||
|
||||
$todo->update($data);
|
||||
|
||||
return redirect()->route('project.todo.index', $project_id)
|
||||
->with('success', 'Todo updated successfully');
|
||||
return back()->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\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
|
||||
class Project extends Model
|
||||
{
|
||||
|
@ -25,13 +26,13 @@ class Project extends Model
|
|||
* Relationship with Todo model (one to many)
|
||||
* @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
|
||||
{
|
||||
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 App\Traits\UuidTrait;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
|
@ -39,7 +40,7 @@ class Todo extends Model
|
|||
|
||||
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 App\Traits\UuidTrait;
|
||||
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\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
@ -45,13 +47,13 @@ class User extends Authenticatable
|
|||
'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
|
||||
{
|
||||
return $this->hasManyThrough(Todo::class, projectUser::class, 'user_id', 'id', 'id', 'project_id');
|
||||
}
|
||||
// public function todos(): HasManyThrough
|
||||
// {
|
||||
// return $this->hasManyThrough(Todo::class, projectUser::class, 'user_id', 'id', 'id', 'project_id');
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public const HOME = '/todo';
|
||||
public const HOME = '/project';
|
||||
|
||||
/**
|
||||
* 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>
|
||||
</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">
|
||||
<form method="POST" action="{{ route('project.todo.update', [$project, $todo]) }}"
|
||||
id="todo-form">
|
||||
|
|
|
@ -9,6 +9,18 @@
|
|||
</h2>
|
||||
</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="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
|
@ -83,12 +95,12 @@
|
|||
<div class="space-y-4">
|
||||
@foreach ($todos as $todo)
|
||||
@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
|
||||
class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6 flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<!-- 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"
|
||||
class="toggle-completed-form">
|
||||
@csrf
|
||||
|
|
Loading…
Reference in New Issue