feat: ✨ Added edition page for brands <-> users relations

This commit is contained in:
Noah Lancien 2026-05-13 16:53:56 +02:00
parent 42faaf51bb
commit 91c0aa2f9a
8 changed files with 208 additions and 1 deletions

View file

@ -0,0 +1,58 @@
<?php
namespace App\Http\Controllers;
use App\Models\Marque;
use App\Http\Requests\Bo\UpdateBrandUserRequest;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class BrandController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles(config('roles.const.ADMIN'));
$brands = Marque::all();
return view('brands.index')->with([
'brands' => $brands
]);
}
public function editUsers(Marque $brand)
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles(config('roles.const.ADMIN'));
$userModels = User::all();
return view('brands.edit-relations')->with([
'brand' => $brand,
'brands' => Marque::all(),
'userModels' => $userModels,
]);
}
public function updateUsers(UpdateBrandUserRequest $request, Marque $brand)
{
/** @var \App\Models\User */
$user = auth()->user();
$user->authorizeRoles(config('roles.const.ADMIN'));
DB::transaction(function () use ($request, $brand) {
if ($request->validated('users')) {
$brand->users()->sync($request->validated('users'));
}
return redirect()->route('brands.editUsers', ['brand' => $brand])
->with('success', __('Les utilisateurs ont bien été mis à jour'));
});
return back()->with('error', __('Une erreur est survenue. Veuillez réessayer ultérieurement.'));
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace App\Http\Requests\Bo;
use Illuminate\Foundation\Http\FormRequest;
class UpdateBrandUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth()->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'users' => !$this->users ? null : \explode(',', \strval($this->users))
]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'users' => 'nullable|array',
'users.*' => 'required|exists:users,id',
];
}
}

View file

@ -31,7 +31,8 @@ class Marque extends Model
*/
public function users()
{
return $this->belongsToMany(User::class);
// We have to define foreignPivotKey because primaryKey has been overwritten ...
return $this->belongsToMany(User::class, foreignPivotKey:'marque_id');
}
/**

View file

@ -25,6 +25,13 @@ $(document).ready(function() {
tableGlobalSearch('.datatable tr.data_row', search, [1,2,3]);
});
// ---- Gestion des utilisateurs : recherche de marque
$(".filter_brand_btn").on('click', function(event) {
event.preventDefault();
const search = $(".filter_brand_input").val();
tableGlobalSearch('.datatable tr.data_row', search, [1,2,3]);
});
// ---- Gestion des dossiers : recherche un dossier
$(".filter_dossier_btn").on('click', function(event) {
event.preventDefault();
@ -195,6 +202,7 @@ $(document).ready(function() {
initSelector(".selector_marques");
initSelector(".selector_sujets");
initSelector(".selector_users");
});

View file

@ -0,0 +1,41 @@
@extends('layouts.app')
@include('layouts.header')
@section('content')
<main class="user_index template_2col">
@include('modules.param-sideMenu')
<div class="main_content">
@include('modules.flashMessage')
<div class="heading">
<h1>{{ __('Edition des utilisateurs de la marque') }} : {{ $brand->libMarq }}</h1>
</div>
{!! Form::model($brand, ['route' => ['brands.updateUsers', $brand], 'enctype' => 'multipart/form-data', 'class' => 'dataform']) !!}
@method('PUT')
<div class="form-section">
{!! Form::label('users', 'Utilisateurs associés') !!}
</div>
<div class="form-field">
{!! Form::label("", "") !!}
<div class="selector_form selector_users">
{!! Form::text('search', null, ['class' => "selector_filter", 'placeholder' => "Rechercher...", "autocomplete" => "off"]) !!}
<div class="selector_list">
<ul class="selector_choices" >
@foreach ($userModels as $userModel)
<li data-value="{{$userModel->id}}" >{{$userModel->firstname}} {{$userModel->lastname}}</li>
@endforeach
</ul>
<ul class="selector_values" >
@foreach ($brand->users as $user)
<li data-value="{{$user->id}}" >{{$user->firstname}} {{$user->lastname}}</li>
@endforeach
</ul>
<input class="selector_dataValues" type="hidden" name="users" value="">
</div>
</div>
</div>
<div class="button-row">
{!! Form::submit('Enregistrer', [ 'class' => 'btn']) !!} <a href="{{ route('brands.index') }}" class="btn btn-black ml-10">Retour</a>
</div>
{!! Form::close() !!}
</div>
</main>
@endsection

View file

@ -0,0 +1,48 @@
@extends('layouts.app')
@include('layouts.header')
@section('content')
<main class="brand_index template_2col">
@include('modules.param-sideMenu')
<div class="main_content">
@include('modules.flashMessage')
<div class="heading">
<h1>{{ __('Gestion des marques') }}</h1>
</div>
<div class="filter_row group">
<div class="right_col">
<input type="text" value="" class="filter_brand_input">
<a href="#" class="btn btn-black filter_brand_btn">Rechercher une marque</a>
</div>
</div>
<table class="datatable">
<thead>
<tr>
<th>CODE</th>
<th>LIBELLE</th>
<th>ACTIONS</th>
</tr>
</thead>
@foreach ($brands as $brand)
<tr class="data_row">
<td>{{ $brand->codMarq }}</td>
<td>{{ $brand->libMarq }}</td>
<td>
<a href="{{ route('brands.editUsers', $brand) }}" class="btn" title="{{ __('Gérer les relations avec les utilisateurs') }}">
{{ __('Gérer les utilisateurs') }}
<i class="fas fa-users-cog"></i>
</a>
</td>
</tr>
@endforeach
<tfoot>
<tr>
<td colspan="4">
</td>
</tr>
</tfoot>
</table>
</div>
</main>
@endsection

View file

@ -3,6 +3,10 @@
<span>{{ __('Gestion des utilisateur') }}s</span>
<i class="fas fa-users-cog"></i>
</a>
<a @if(request()->routeIs('brands.*')) class="active" @endif href="{{ route('brands.index') }}">
<span>{{ __('Gestion des marques') }}</span>
<i class="fas fa-building"></i>
</a>
<a @if(request()->routeIs('dossier.*')) class="active" @endif href="{{ route('dossier.index') }}">
<span>{{ __('Gestion des dossiers') }}</span>
<i class="fa-solid fa-folder"></i>

View file

@ -2,6 +2,7 @@
use App\Http\Controllers\ArcadiaLinkController;
use App\Http\Controllers\ArticleController;
use App\Http\Controllers\BrandController;
use App\Http\Controllers\CommonController;
use App\Http\Controllers\DossierController;
use App\Http\Controllers\MediaController;
@ -57,6 +58,9 @@ Route::group(['middleware' => ['auth']], function () {
// * Back office .
Route::resource('user', UserController::class);
Route::get('/brands', [BrandController::class, 'index'])->name('brands.index');
Route::get('/brands/{brand}/edit-users', [BrandController::class, 'editUsers'])->name('brands.editUsers');
Route::put('/brands/{brand}/edit-users', [BrandController::class, 'updateUsers'])->name('brands.updateUsers');
Route::resource('arcadialinks', ArcadiaLinkController::class)->only(['index', 'destroy']);
Route::resource('dossier', DossierController::class)->except('show');
Route::get('/recovery', [RecoveryController::class, 'index'])->name('recovery.index');