Add password change page for user profiles
- New ProfileController with editPassword/updatePassword actions that verify the current password and require a confirmed new password of at least 8 chars - Adds /profile/password GET/PUT routes behind auth middleware - Adds profile.password blade view with form validation error display - Links "Change Password" in the app layout sidebar
This commit is contained in:
parent
7eb2751cd4
commit
17da8d9c3c
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function editPassword(): View
|
||||||
|
{
|
||||||
|
return view('profile.password');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatePassword(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'current_password' => ['required', 'current_password'],
|
||||||
|
'password' => ['required', 'string', 'confirmed', Password::min(8)],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$request->user()->update(['password' => $data['password']]);
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('profile.password.edit')
|
||||||
|
->with('status', 'Your password has been updated.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
<a href="{{ route('teams.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Teams</a>
|
<a href="{{ route('teams.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Teams</a>
|
||||||
<a href="{{ route('categories.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Categories</a>
|
<a href="{{ route('categories.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Categories</a>
|
||||||
<a href="{{ route('api-keys.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">API Keys</a>
|
<a href="{{ route('api-keys.index') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">API Keys</a>
|
||||||
|
<a href="{{ route('profile.password.edit') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Change Password</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('title', 'Change Password — ' . config('app.name'))
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="mx-auto max-w-md rounded-lg border border-gray-200 bg-white p-8">
|
||||||
|
<h1 class="mb-2 text-2xl font-bold">Change password</h1>
|
||||||
|
<p class="mb-6 text-gray-600">Update the password for your account.</p>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('profile.password.update') }}">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="current_password" class="mb-1 block font-semibold">Current password</label>
|
||||||
|
<input id="current_password" type="password" name="current_password" required autofocus autocomplete="current-password"
|
||||||
|
class="w-full rounded-md border border-gray-300 px-3 py-2 focus:border-secondary focus:outline-none focus:ring-2 focus:ring-secondary/40">
|
||||||
|
@error('current_password')
|
||||||
|
<p class="mt-1 text-sm text-red-700">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="password" class="mb-1 block font-semibold">New password</label>
|
||||||
|
<input id="password" type="password" name="password" required autocomplete="new-password"
|
||||||
|
class="w-full rounded-md border border-gray-300 px-3 py-2 focus:border-secondary focus:outline-none focus:ring-2 focus:ring-secondary/40">
|
||||||
|
@error('password')
|
||||||
|
<p class="mt-1 text-sm text-red-700">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="password_confirmation" class="mb-1 block font-semibold">Confirm new password</label>
|
||||||
|
<input id="password_confirmation" type="password" name="password_confirmation" required autocomplete="new-password"
|
||||||
|
class="w-full rounded-md border border-gray-300 px-3 py-2 focus:border-secondary focus:outline-none focus:ring-2 focus:ring-secondary/40">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button type="submit" class="cursor-pointer rounded-md bg-primary px-4 py-2 font-medium text-white hover:bg-primary-hover">Update password</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
@ -7,6 +7,7 @@ use App\Http\Controllers\CategoryController;
|
||||||
use App\Http\Controllers\GroupAdminController;
|
use App\Http\Controllers\GroupAdminController;
|
||||||
use App\Http\Controllers\KpiController;
|
use App\Http\Controllers\KpiController;
|
||||||
use App\Http\Controllers\KpiEntryController;
|
use App\Http\Controllers\KpiEntryController;
|
||||||
|
use App\Http\Controllers\ProfileController;
|
||||||
use App\Http\Controllers\ProjectController;
|
use App\Http\Controllers\ProjectController;
|
||||||
use App\Http\Controllers\ProjectEntryController;
|
use App\Http\Controllers\ProjectEntryController;
|
||||||
use App\Http\Controllers\TeamController;
|
use App\Http\Controllers\TeamController;
|
||||||
|
|
@ -81,6 +82,10 @@ Route::middleware('auth')->group(function () {
|
||||||
Route::put('/categories/{category}', [CategoryController::class, 'update'])->name('categories.update');
|
Route::put('/categories/{category}', [CategoryController::class, 'update'])->name('categories.update');
|
||||||
Route::delete('/categories/{category}', [CategoryController::class, 'destroy'])->name('categories.destroy');
|
Route::delete('/categories/{category}', [CategoryController::class, 'destroy'])->name('categories.destroy');
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
Route::get('/profile/password', [ProfileController::class, 'editPassword'])->name('profile.password.edit');
|
||||||
|
Route::put('/profile/password', [ProfileController::class, 'updatePassword'])->name('profile.password.update');
|
||||||
|
|
||||||
// API keys
|
// API keys
|
||||||
Route::get('/api-keys', [ApiKeyController::class, 'index'])->name('api-keys.index');
|
Route::get('/api-keys', [ApiKeyController::class, 'index'])->name('api-keys.index');
|
||||||
Route::post('/api-keys', [ApiKeyController::class, 'store'])->name('api-keys.store');
|
Route::post('/api-keys', [ApiKeyController::class, 'store'])->name('api-keys.store');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue