add show view for CRUDs

This commit is contained in:
Alexis Gousseau 2024-03-25 16:22:57 +01:00
parent d9881c7cbf
commit af373dfdc1
16 changed files with 271 additions and 37 deletions

View file

@ -53,6 +53,17 @@ class StaticPageController extends Controller
return view('bo.pages.static_pages.index', compact('staticPageModelList', 'search', 'searchFields'));
}
/**
* Show a specific resource.
*
* @param \App\Models\StaticPage $static_page
* @return \Illuminate\Contracts\View\View
*/
public function show(StaticPage $static_page): \Illuminate\Contracts\View\View
{
return view('bo.pages.static_pages.show', ['staticPageModel' => $static_page]);
}
/**
* Show the form for editing the specified resource.
*

View file

@ -63,6 +63,17 @@ class UserController extends Controller
return view('bo.pages.users.index', compact('userModels', 'search', 'searchFields'));
}
/**
* Show a specific resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function show(User $user): \Illuminate\Contracts\View\View
{
return view('bo.pages.users.show', ['userModel' => $user]);
}
/**
* Show the form for creating a new resource.
*

View file

@ -20,6 +20,17 @@ class StaticPagePolicy
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can view the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function view(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can update the model.
*

View file

@ -3,13 +3,14 @@
return [
'actions' => [
'list' => 'list',
'view' => 'view',
'show' => 'view',
'create' => 'create',
'duplicate' => 'duplicate',
'update' => 'update',
'duplicate' => 'duplicate',
'delete' => 'delete',
'save' => 'save',
'edit' => 'edit',
'view' => 'overview',
],
'helpers' => [

View file

@ -214,27 +214,26 @@ return [
'username' => 'username',
'year' => 'year',
],
'youtube_id' => ':attribute must be a valid Youtube video ID',
'vimeo_id' => ':attribute must be a valid Vimeo video ID',
'custom' => [
'of_the' => [
'male' => 'of the ',
'female' => 'of the ',
'vowel' => 'of the '
],
'activated' => 'activated',
'event' => 'event',
'model' => 'target element',
'order' => 'order',
'publication' => 'publication',
'activated' => 'activated',
'target' => 'target',
'static_page_type' => 'static page type',
'seo_title' => 'SEO title',
'published_at' => 'published at',
'seo_description' => 'SEO description',
'seo_title' => 'SEO title',
'static_page_type' => 'static page type',
'target' => 'target',
'video_id' => 'ID of the video',
'youtube_video_id' => 'ID od the youtube video',
'vimeo_video_id' => 'ID of the vimeo video',
'youtube_video_id' => 'ID od the youtube video',
],
];

View file

@ -2,14 +2,15 @@
return [
'actions' => [
'list' => 'liste',
'view' => 'voir',
'create' => 'créer',
'list' => 'liste',
'show' => 'voir',
'create' => 'créer',
'update' => 'éditer',
'duplicate' => 'dupliquer',
'update' => 'éditer',
'delete' => 'supprimer',
'save' => 'sauvegarder',
'edit' => 'mettre à jour',
'delete' => 'supprimer',
'save' => 'sauvegarder',
'edit' => 'mettre à jour',
'view' => 'aperçu',
],
'helpers' => [

View file

@ -12,7 +12,8 @@ return [
'alpha_dash' => 'Le champ :attribute doit contenir uniquement des lettres, des chiffres et des tirets.',
'alpha_num' => 'Le champ :attribute doit contenir uniquement des chiffres et des lettres.',
'array' => 'Le champ :attribute doit être un tableau.',
'ascii' => 'Le champ :attribute ne doit contenir que des caractères alphanumériques et des symboles codés sur un octet.',
'ascii' => 'Le champ :attribute ne doit contenir que des caractères alphanumériques et des symboles
codés sur un octet.',
'before' => 'Le champ :attribute doit être une date antérieure au :date.',
'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale au :date.',
'between' => [
@ -108,7 +109,8 @@ return [
'mixed' => 'Le champ :attribute doit contenir au moins une majuscule et une minuscule.',
'numbers' => 'Le champ :attribute doit contenir au moins un chiffre.',
'symbols' => 'Le champ :attribute doit contenir au moins un symbole.',
'uncompromised' => 'La valeur du champ :attribute est apparue dans une fuite de données. Veuillez choisir une valeur différente.',
'uncompromised' => 'La valeur du champ :attribute est apparue dans une fuite de données. Veuillez choisir
une valeur différente.',
],
'present' => 'Le champ :attribute doit être présent.',
'prohibited' => 'Le champ :attribute est interdit.',
@ -152,7 +154,7 @@ return [
'city' => 'ville',
'content' => 'contenu',
'country' => 'pays',
'created_at' => 'créé à',
'created_at' => 'créé le',
'creator' => 'créateur',
'current_password' => 'mot de passe actuel',
'date' => 'Date',
@ -210,31 +212,30 @@ return [
'text' => 'texte',
'time' => 'heure',
'title' => 'titre',
'updated_at' => 'mis à jour à',
'updated_at' => 'mis à jour le',
'username' => 'nom d\'utilisateur',
'year' => 'année',
],
'youtube_id' => ':attribute doit être un ID de vidéo Youtube valide',
'vimeo_id' => ':attribute doit être un ID de vidéo Vimeo valide',
'custom' => [
'of_the' => [
'male' => 'du ',
'female' => 'de la ',
'vowel' => 'de l\''
],
'activated' => 'activé',
'event' => 'évènement',
'model' => 'élément ciblé',
'order' => 'ordre',
'publication' => 'publication',
'activated' => 'activé',
'target' => 'cible',
'static_page_type' => 'type de page',
'seo_title' => 'titre SEO',
'published_at' => 'publié le',
'seo_description' => 'description SEO',
'seo_title' => 'titre SEO',
'static_page_type' => 'type de page',
'target' => 'cible',
'video_id' => 'ID de la vidéo',
'youtube_video_id' => 'ID de la vidéo youtube',
'vimeo_video_id' => 'ID de la vidéo viméo',
'youtube_video_id' => 'ID de la vidéo youtube',
],
];

View file

@ -5,6 +5,7 @@ import {
faArrowRight,
faArrowRightFromBracket,
faArrowUp,
faArrowUpRightFromSquare,
faArrowsAltH,
faArrowsAltV,
faBackspace,
@ -69,5 +70,6 @@ library.add(faPaintRoller);
library.add(faXmark);
library.add(faChevronLeft);
library.add(faChevronRight);
library.add(faArrowUpRightFromSquare);
dom.watch();

View file

@ -2,8 +2,7 @@
@section('title', __('Édition d\'un :model', ['model' => __('models.classes.static_page')]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => __('models.classes.static_page')]))
@section('breadcrumb',
request()->route()->getName())
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap pb-3">
@ -16,6 +15,13 @@
</div>
<div class="mb-md-0 mb-2">
<div class="btn-group">
@can('view', $staticPageModel)
<a class="btn btn-warning" data-bs-toggle="tooltip"
href="{{ route('bo.static_pages.show', ['static_page' => $staticPageModel]) }}"
title="{{ str(__('crud.actions.view'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
<button class="btn btn-primary" id="formSubmitClone" data-bs-toggle="tooltip" type="submit"
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.static_page')]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}

View file

@ -18,8 +18,19 @@
<span class="badge bg-secondary">{{ $staticPageModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['update'], $staticPageModel)
@canAny(['view', 'update'], $staticPageModel)
<div class="btn-group">
<a class="btn btn-sm btn-info" data-bs-toggle="tooltip" href="#FIXME: mettre la route avec le slug"
title="{{ __('Accéder à la page') }}">
<i class="fa-solid fa-arrow-up-right-from-square"></i>
</a>
@can('view', $staticPageModel)
<a class="btn btn-sm btn-warning" data-bs-toggle="tooltip"
href="{{ route('bo.static_pages.show', ['static_page' => $staticPageModel]) }}"
title="{{ str(__('crud.actions.show'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@can('update', $staticPageModel)
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.static_pages.edit', ['static_page' => $staticPageModel]) }}"

View file

@ -0,0 +1,66 @@
@extends('bo.layout', ['brParam' => $staticPageModel])
@section('title', __('Édition d\'un :model', ['model' => __('models.classes.static_page')]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => __('models.classes.static_page')]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap pb-3">
<div class="d-flex align-items-start flex-row">
<a class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip" href="{{ route('bo.static_pages.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str()->plural(__('models.classes.static_page'))]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $staticPageModel])
</div>
<div class="btn-group mb-md-0 mb-2">
@canAny(['update'], $staticPageModel)
@can('update', $staticPageModel)
<a class="btn btn-primary" data-bs-toggle="tooltip" href="{{ route('bo.static_pages.edit', ['static_page' => $staticPageModel]) }}"
title="{{ str()->ucfirst(__('crud.actions.update')) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@endcan
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive mb-3">
<table class="table-hover m-0 table">
<tbody>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.custom.static_page_type'))->ucFirst() }}
</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->type->label() }}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.custom.seo_title'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->seo_title }}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.custom.seo_description'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->seo_description }}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.title'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->title }}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.content'))->ucFirst() }}</td>
<td class="w-50 align-middle">{!! clean($staticPageModel->content) !!}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.created_at'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->created_at->isoFormat('LLLL') }}</td>
</tr>
<tr>
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.updated_at'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">{{ $staticPageModel->updated_at->isoFormat('LLLL') }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
@endsection

View file

@ -2,8 +2,7 @@
@section('title', __('Édition d\'un :model', ['model' => __('models.classes.user')]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => __('models.classes.user')]))
@section('breadcrumb',
request()->route()->getName())
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap pb-3">
@ -16,6 +15,12 @@
</div>
<div class="mb-md-0 mb-2">
<form class="btn-group confirmDeleteTS" action="{{ route('bo.users.destroy', $userModel) }}" method="POST" novalidate>
@can('view', $userModel)
<a class="btn btn-warning" data-bs-toggle="tooltip" href="{{ route('bo.users.show', ['user' => $userModel]) }}"
title="{{ str(__('crud.actions.view'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@can('duplicate', $userModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip" href="{{ route('bo.users.duplicate', ['user' => $userModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">

View file

@ -27,9 +27,16 @@
<span class="badge bg-secondary">{{ $userModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['delete', 'duplicate', 'update'], $userModel)
@canAny(['view', 'duplicate', 'update', 'delete'], $userModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.users.destroy', $userModel) }}" method="POST"
novalidate>
@can('view', $userModel)
<a class="btn btn-sm btn-warning" data-bs-toggle="tooltip"
href="{{ route('bo.users.show', ['user' => $userModel]) }}"
title="{{ str(__('crud.actions.show'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@can('duplicate', $userModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.users.duplicate', ['user' => $userModel]) }}"

View file

@ -0,0 +1,92 @@
@extends('bo.layout', ['brParam' => $userModel])
@section('title', __('Édition d\'un :model', ['model' => __('models.classes.user')]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => __('models.classes.user')]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap pb-3">
<div class="d-flex align-items-start flex-row">
<a class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip" href="{{ route('bo.users.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.user'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $userModel])
</div>
<div class="btn-group mb-md-0 mb-2">
@canAny(['view', 'duplicate', 'update', 'delete'], $userModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.users.destroy', $userModel) }}" method="POST" novalidate>
@can('duplicate', $userModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip" href="{{ route('bo.users.duplicate', ['user' => $userModel]) }}"
title="{{ str(__('crud.actions.duplicate'))->ucfirst() }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $userModel)
<a class="btn btn-primary" data-bs-toggle="tooltip" href="{{ route('bo.users.edit', ['user' => $userModel]) }}"
title="{{ str(__('crud.actions.update'))->ucfirst() }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $userModel)
@csrf
@method('DELETE')
<button class="btn btn-danger" data-bs-toggle="tooltip" type="submit" title="{{ str(__('crud.actions.delete'))->ucfirst() }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
@endcan
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive mb-3">
<table class="table-hover m-0 table">
<tbody>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">
{{ str(sprintf('%s/%s', __('validation.attributes.first_name'), __('validation.attributes.last_name')))->ucFirst() }}
</td>
<td class="w-50 text-center align-middle">
{{ sprintf('%s %s', $userModel->first_name, $userModel->last_name) }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.email'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ $userModel->email }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.role'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ str($userModel->role->label())->ucFirst() }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">
{{ str(__('validation.custom.published_at'))->ucFirst() }}
</td>
<td class="w-50 text-center align-middle">
{{ $userModel->published ? $userModel->published_at->isoFormat('LLLL') : __('Utilisateur non publié') }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.created_at'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ $userModel->created_at->isoFormat('LLLL') }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.updated_at'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ $userModel->updated_at->isoFormat('LLLL') }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
@endsection

View file

@ -14,6 +14,10 @@ Breadcrumbs::for('bo.users.index', function (Generator $trail) {
route('bo.users.index', ['sort_col' => 'updated_at', 'sort_way' => 'desc'])
);
});
Breadcrumbs::for('bo.users.show', function (Generator $trail, User $user) {
$trail->parent('bo.users.index');
$trail->push(Str::ucfirst(trans('crud.actions.view')), route('bo.users.show', $user));
});
Breadcrumbs::for('bo.users.create', function (Generator $trail) {
$trail->parent('bo.users.index');
$trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.users.create'));
@ -46,6 +50,11 @@ Breadcrumbs::for('bo.static_pages.index', function (Generator $trail) {
route('bo.static_pages.index', ['sort_col' => 'updated_at', 'sort_way' => 'desc'])
);
});
Breadcrumbs::for('bo.static_pages.show', function (Generator $trail, StaticPage $static_page) {
$trail->parent('bo.static_pages.index');
$trail->push(Str::ucfirst(trans('crud.actions.show')), route('bo.static_pages.show', $static_page));
});
Breadcrumbs::for('bo.static_pages.edit', function (Generator $trail, StaticPage $static_page) {
$trail->parent('bo.static_pages.index');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.static_pages.edit', $static_page));

View file

@ -29,7 +29,7 @@ Route::prefix('bo')
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// * USERS.
Route::resource('users', UserController::class)->except('show');
Route::resource('users', UserController::class);
Route::patch('/users/{user}/change-published', [
UserController::class, 'changePublished'
])->name('users.change-published');
@ -40,11 +40,12 @@ Route::prefix('bo')
// * StaticPages
Route::resource('pages', StaticPageController::class)
->names([
'index' => 'static_pages.index',
'edit' => 'static_pages.edit',
'index' => 'static_pages.index',
'show' => 'static_pages.show',
'edit' => 'static_pages.edit',
'update' => 'static_pages.update',
])->parameters(['pages' => 'static_page'])
->only(['index', 'edit', 'update'])
->only(['index', 'show', 'edit', 'update'])
->withoutMiddleware('htmlsanitize')
->middleware(['htmlsanitize:content']);