mirror of
https://github.com/10h30/MoveMate.git
synced 2026-06-05 15:07:35 +09:00
Add manual authentication, create, read, update task
This commit is contained in:
@@ -8,4 +8,15 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class Task extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $attributes = [
|
||||
'completed' => false, // Set default value for completed
|
||||
];
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
public function category() {
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@ class TaskSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Task::factory(100)->create();
|
||||
Task::factory(20)->create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<x-layout>
|
||||
<x-slot:heading>Login Page</x-slot:heading>
|
||||
<div>
|
||||
<!-- Your content -->
|
||||
<div class="w-full max-w-md p-8 mt-8 space-y-4 bg-white shadow-lg rounded-lg">
|
||||
<h2 class="text-2xl font-bold text-center text-gray-700">Login</h2>
|
||||
<form action="/login" method="POST" class="space-y-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Email</label>
|
||||
<input type="email" name="email" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" value="{{ old('email') }}" required>
|
||||
<x-form-error name="email"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Password</label>
|
||||
<input type="password" name="password" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" required>
|
||||
<x-form-error name="email"></x-form-error>
|
||||
</div>
|
||||
<button type="submit" class="w-full p-2 text-white bg-blue-500 rounded-md hover:bg-blue-600">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</x-layout>
|
||||
@@ -0,0 +1,34 @@
|
||||
<x-layout>
|
||||
<x-slot:heading>Register Page</x-slot:heading>
|
||||
<div>
|
||||
<!-- Your content -->
|
||||
<div class="w-full max-w-md p-8 space-y-4 bg-white shadow-lg rounded-lg">
|
||||
|
||||
<form action="/register" method="POST" class="space-y-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Full Name</label>
|
||||
<input type="text" name="name" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" >
|
||||
<x-form-error name="name"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Email</label>
|
||||
<input type="email" name="email" class="w-full p-name2 mt-1 border rounded-md focus:ring focus:ring-blue-300" >
|
||||
<x-form-error name="email"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Password</label>
|
||||
<input type="password" name="password" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" >
|
||||
<x-form-error name="password"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Confirm Password</label>
|
||||
<input type="password" name="password_confirmation" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" >
|
||||
<x-form-error name="password_confirmation"></x-form-error>
|
||||
</div>
|
||||
<button type="submit" class="w-full p-2 text-white bg-blue-500 rounded-md hover:bg-blue-600">Register</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</x-layout>
|
||||
@@ -0,0 +1 @@
|
||||
<button type="submit" {{ $attributes->merge(['class' => 'rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600'])}}>{{ $slot }}</button>
|
||||
@@ -0,0 +1,4 @@
|
||||
@props(['name'])
|
||||
@error($name)
|
||||
<p class="text-xs text-red-500">{{ $message}}</p>
|
||||
@enderror
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Simple Tailwind Layout</title>
|
||||
<title>{{ $heading }}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="flex flex-col min-h-screen bg-gray-100">
|
||||
@@ -11,17 +11,11 @@
|
||||
<header class="bg-white shadow">
|
||||
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
|
||||
<!-- Title on left -->
|
||||
<h1 class="text-xl font-bold text-gray-800">MoveMate</h1>
|
||||
<a href="/"><h1 class="text-xl font-bold text-gray-800">MoveMate</h1></a>
|
||||
|
||||
<!-- Navigation on right -->
|
||||
<nav>
|
||||
<ul class="flex space-x-6">
|
||||
<li><a href="#" class="text-gray-600 hover:text-gray-900">Home</a></li>
|
||||
<li><a href="#" class="text-gray-600 hover:text-gray-900">About</a></li>
|
||||
<li><a href="#" class="text-gray-600 hover:text-gray-900">Services</a></li>
|
||||
<li><a href="#" class="text-gray-600 hover:text-gray-900">Contact</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<x-nav />
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<li><a {{ $attributes->merge(['class' => 'text-gray-600 hover:text-gray-900']) }}> {{ $slot }}</a></li>
|
||||
@@ -0,0 +1,16 @@
|
||||
<nav>
|
||||
<ul class="flex space-x-6 items-center ">
|
||||
@guest
|
||||
<x-nav-link href="/login">Login</x-nav-link>
|
||||
<x-nav-link href="/register">Register</x-nav-link>
|
||||
@endguest
|
||||
@auth
|
||||
<x-nav-link type="button" href="/task/create">Create new task</x-nav-link>
|
||||
<form method="POST" action="/logout">
|
||||
@csrf
|
||||
<x-form-button>Log Out</x-form-button>
|
||||
</form>
|
||||
@endauth
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -1 +1,44 @@
|
||||
Hello
|
||||
<x-layout>
|
||||
<x-slot:heading>Create New Task</x-slot:heading>
|
||||
@if (session('success'))
|
||||
<div class="bg-green-500 text-white p-3 rounded mb-4">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
<form action="/task/create" method="POST" class="space-y-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Task Name</label>
|
||||
<input type="text" name="name" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" required>
|
||||
<x-form-error name="name"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Description</label>
|
||||
<textarea name="description" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" rows="3" required></textarea>
|
||||
<x-form-error name="description"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Category</label>
|
||||
<select name="category_id" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" required>
|
||||
@foreach($categories as $category)
|
||||
<option value="{{ $category->id }}">{{ $category->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<x-form-error name="category_id"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Location</label>
|
||||
<input type="text" name="location" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300">
|
||||
<x-form-error name="location"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Estimated Time (hours)</label>
|
||||
<input type="number" name="time_estimate" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" min="0" step="0.5" required>
|
||||
<x-form-error name="time_estimate"></x-form-error>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-y-6">
|
||||
<button type="submit" class="w-full p-2 text-white bg-blue-500 rounded-md hover:bg-blue-600">Create Task</button>
|
||||
<a href="/task/" class="text-sm font-semibold text-gray-900">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</x-layout>
|
||||
@@ -0,0 +1,48 @@
|
||||
<x-layout>
|
||||
<x-slot:heading>Update Task</x-slot:heading>
|
||||
@if (session('success'))
|
||||
<div class="bg-green-500 text-white p-3 rounded mb-4">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
<form action="/task/{{ $task->id }}" method="POST" class="space-y-4">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Task Name</label>
|
||||
<input value={{ $task->name }} type="text" name="name" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" required>
|
||||
<x-form-error name="name"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Description</label>
|
||||
<textarea name="description" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" rows="3" required>{{ $task->description }}</textarea>
|
||||
<x-form-error name="description"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Category</label>
|
||||
<select name="category_id" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" required>
|
||||
@foreach($categories as $category)
|
||||
<option value="{{ $category->id }}"
|
||||
{{ $category->id == $task->category_id ? 'selected' : '' }}>
|
||||
{{ $category->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<x-form-error name="category_id"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Location</label>
|
||||
<input type="text" value="{{ $task->location }}" name="location" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300">
|
||||
<x-form-error name="location"></x-form-error>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600">Estimated Time (hours)</label>
|
||||
<input type="number" value="{{ $task->time_estimate }}" name="time_estimate" class="w-full p-2 mt-1 border rounded-md focus:ring focus:ring-blue-300" min="0" step="0.5" required>
|
||||
<x-form-error name="time_estimate"></x-form-error>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-y-6">
|
||||
<button type="submit" class="w-full p-2 text-white bg-blue-500 rounded-md hover:bg-blue-600">Update Task</button>
|
||||
<a href="/jobs/{{ $task->id }}" type="button" class="text-sm font-semibold text-gray-900">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</x-layout>
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
<x-layout>
|
||||
<x-slot:heading>{{ $task->name }}</x-slot:heading>
|
||||
|
||||
|
||||
<div>
|
||||
<div class="text-lg mb-4"> {{ $task->description }}</div>
|
||||
<div><strong>Where to go:</strong> {{ $task->location }}</div>
|
||||
<div><strong>Time Estimate:</strong> {{ $task->time_estimate }} hour</div>
|
||||
<div><strong>Category:</strong> {{ $task->category->name }}</div>
|
||||
<div><strong>Owner:</strong> {{ $task->user->name }}</div>
|
||||
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<a href="/task/{{ $task->id }}/edit" class="text-sm text-blue-600 dark:text-blue-500 hover:underline">Edit</a>
|
||||
</div>
|
||||
</x-layout>
|
||||
+120
-8
@@ -1,24 +1,136 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('task.index');
|
||||
});
|
||||
|
||||
|
||||
Route::get('/task', function () {
|
||||
$task = Task::latest()->Paginate(5);
|
||||
$task = Task::latest('updated_at')->Paginate(20);
|
||||
return view('task.index', [
|
||||
'tasks' => $task
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Route::get('/task', function () {
|
||||
$task = Task::latest('updated_at')->Paginate(20);
|
||||
return view('task.index', [
|
||||
'tasks' => $task
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
Route::get('/task/create', function () {
|
||||
return view('task.create');
|
||||
$categories = Category::all();
|
||||
return view('task.create', [
|
||||
'categories' => $categories
|
||||
]);
|
||||
});
|
||||
|
||||
Route::post('/task/create', function () {
|
||||
|
||||
//dd(Auth::id());
|
||||
$validatedAtts = request()->validate([
|
||||
'name' => ['required'],
|
||||
'description' => ['required'],
|
||||
'category_id' => ['required'],
|
||||
'location' => ['required'],
|
||||
'time_estimate' => ['required'],
|
||||
]);
|
||||
|
||||
$validatedAtts['user_id'] = Auth::id();
|
||||
|
||||
//dd($validatedAtts);
|
||||
|
||||
$task = Task::create(
|
||||
$validatedAtts
|
||||
);
|
||||
|
||||
return redirect()->route('task.create')->with('success', 'Task created successfully!');
|
||||
})->name('task.create');
|
||||
|
||||
Route::get('/task/{id}', function ($id) {
|
||||
$task = Task::find($id);
|
||||
return view('task.show', [
|
||||
'task' => $task
|
||||
]);
|
||||
});
|
||||
|
||||
Route::get('/task/{id}/edit', function ($id) {
|
||||
$task = Task::find($id);
|
||||
$categories = Category::all();
|
||||
return view('task.edit', [
|
||||
'task' => $task,
|
||||
'categories' => $categories
|
||||
]);
|
||||
});
|
||||
|
||||
Route::patch('/task/{id}', function ($id) {
|
||||
$task = Task::find($id);
|
||||
$validatedAtts = request()->validate([
|
||||
'name' => ['required'],
|
||||
'description' => ['required'],
|
||||
'category_id' => ['required'],
|
||||
'location' => ['required'],
|
||||
'time_estimate' => ['required'],
|
||||
]);
|
||||
//dd($task);
|
||||
$task->update($validatedAtts);
|
||||
|
||||
return redirect('/task/'.$task->id);
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Route::get('/login', function () {
|
||||
return view('auth.login');
|
||||
});
|
||||
|
||||
Route::post('/login', function () {
|
||||
$validatedAtts = request()->validate([
|
||||
'email' => ['required'],
|
||||
'password' => ['required']
|
||||
]);
|
||||
//dd($validatedAtts);
|
||||
// Attemp
|
||||
if (! Auth::attempt($validatedAtts)) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => 'The information does not match'
|
||||
]);
|
||||
|
||||
};
|
||||
|
||||
// regenerate the session token
|
||||
request()->session()->regenerate();
|
||||
|
||||
//redirect
|
||||
return redirect('/task');
|
||||
});
|
||||
|
||||
Route::get('/register', function () {
|
||||
return view('auth.register');
|
||||
});
|
||||
|
||||
Route::post('/register', function () {
|
||||
//validate
|
||||
$validatedAtts = request()->validate([
|
||||
'name' => ['required'],
|
||||
'email' => ['required'],
|
||||
'password' => ['required', Password::min(2), 'confirmed']
|
||||
]);
|
||||
$user = User::create($validatedAtts);
|
||||
Auth::login($user);
|
||||
|
||||
});
|
||||
|
||||
Route::post('/logout', function() {
|
||||
Auth::logout();
|
||||
return redirect('/');
|
||||
});
|
||||
Reference in New Issue
Block a user