wip crud keynumber, cant delete create show

This commit is contained in:
Nicolas Demangeat 2024-03-29 14:19:59 +01:00
parent 69a4927371
commit 77b5b2f941
27 changed files with 1049 additions and 3 deletions

View file

@ -0,0 +1,178 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\KeyNumbers\StoreKeyNumberRequest;
use App\Http\Requests\Bo\KeyNumbers\UpdateKeyNumberRequest;
use App\Models\KeyNumber;
use App\Traits\Controllers\UpdateModelPublished;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class KeyNumberController extends Controller
{
use UpdateModelPublished;
use ChangesModelOrder;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(KeyNumber::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $keyNumberModels */
$keyNumberModels = KeyNumber::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$keyNumberModels,
$search,
null,
'text',
);
}
$searchFields = \implode(', ', [
trans('validation.attributes.text'),
]);
/** Sort columns with a query */
$this->sortQuery($keyNumberModels);
/** Custom pagination */
$keyNumberModels = $this->paginate($keyNumberModels);
return view('bo.pages.keyNumbers.index', compact('keyNumberModels', 'search', 'searchFields'));
}
/**
* Show the specified resource.
*
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Contracts\View\View
*/
public function show(KeyNumber $keyNumber): \Illuminate\Contracts\View\View
{
return view('bo.pages.keyNumbers.show', ['keyNumberModel' => $keyNumber]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Contracts\View\View
*/
public function create(KeyNumber $keyNumber): \Illuminate\Contracts\View\View
{
return view('bo.pages.keyNumbers.create', ['keyNumberModel' => $keyNumber]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\KeyNumbers\StoreKeyNumberRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreKeyNumberRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$keyNumber = new KeyNumber();
$keyNumber->fill($request->validated());
if ($keyNumber->saveOrFail()) {
return redirect()->route('bo.keyNumbers.edit', $keyNumber)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Contracts\View\View
*/
public function edit(KeyNumber $keyNumber): \Illuminate\Contracts\View\View
{
return view('bo.pages.keyNumbers.edit', ['keyNumberModel' => $keyNumber]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\KeyNumbers\UpdateKeyNumberRequest $request
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateKeyNumberRequest $request, KeyNumber $keyNumber): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $keyNumber) {
$keyNumber->fill($request->validated());
if ($keyNumber->saveOrFail()) {
return redirect()->route('bo.keyNumbers.edit', $keyNumber)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
}
return redirect()->route('bo.keyNumbers.edit', $keyNumber)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(KeyNumber $keyNumber): \Illuminate\Http\RedirectResponse
{
/** @var array<string,string> */
$previousQueries = [];
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
if ($keyNumber->deleteOrFail()) {
return redirect()->route('bo.keyNumbers.index', $previousQueries)
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.keyNumber'))
]));
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\KeyNumber $keyNumber
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(KeyNumber $keyNumber): \Illuminate\Contracts\View\View
{
return $this->create($keyNumber->replicate());
}
}

View file

@ -125,7 +125,7 @@ class ProfessionController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param \App\Http\Requests\Bo\Professions\UpdateProfessionRequest $request * @param \App\Http\Requests\Bo\Professions\UpdateProfessionRequest $request
* @param \App\Models\Profession $profession * @param \App\Models\Profession $profession
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(UpdateProfessionRequest $request, Profession $profession): \Illuminate\Http\RedirectResponse public function update(UpdateProfessionRequest $request, Profession $profession): \Illuminate\Http\RedirectResponse

View file

@ -0,0 +1,73 @@
<?php
namespace App\Http\Requests\Bo\KeyNumbers;
use App\Models\KeyNumber;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreKeyNumberRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return Gate::check('create', KeyNumber::class);
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picto');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
$rules = [
'text' => 'required|string|min:3',
'picto_alt' => 'required_with:picto|between:3,255',
'picto_title' => 'required_with:picto|between:3,255',
'source' => 'sometimes|string|nullable|between:3,255',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picto', 155, 155, 155, 155),
);
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'text' => trans('validation.attributes.text'),
'source' => trans('validation.attributes.text'),
'picto' => trans('validation.attributes.image'),
'picto_alt' => trans('validation.attributes.alt_attribute'),
'picto_title' => trans('validation.attributes.title_attribute'),
'published' => trans('validation.attributes.published')
];
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests\Bo\KeyNumbers;
use Illuminate\Support\Facades\Gate;
class UpdateKeyNumberRequest extends StoreKeyNumberRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return Gate::check('update', $this->route('keyNumber'));
}
}

75
app/Models/KeyNumber.php Normal file
View file

@ -0,0 +1,75 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* @property string $picto Picto path.
* @property string $picto_title Picto title attribute.
* @property string $picto_alt Picto alt attribute.
* @property string $text Legend of picto.
* @property string $source The origin of the text.
* @property integer $order Change order request.
* @property boolean $published Picto publish status.
* @property-read \Illuminate\Support\Carbon $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*/
class KeyNumber extends Model
{
use ActivityLog;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'text',
'picto',
'picto_alt',
'picto_title',
'source',
'order',
'published',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $keyNumber) {
self::setOrder($keyNumber);
$keyNumber->picto = FileStorageHelper::storeFile($keyNumber, $keyNumber->picto, true);
});
static::updating(function (self $keyNumber) {
$keyNumber->picto = FileStorageHelper::storeFile($keyNumber, $keyNumber->picto, true);
});
static::updated(function (self $keyNumber) {
FileStorageHelper::removeOldFile($keyNumber, 'picto');
});
static::deleted(function (self $keyNumber) {
FileStorageHelper::removeFile($keyNumber, 'picto');
});
}
// * METHODS
/**
* Set order after the last element of the list.
*
* @param self $model
* @return void
*/
private static function setOrder(self $model): void
{
$model->order = \intval(self::query()->max('order')) + 1;
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace App\Policies;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use App\Policies\Rules\UserStaticRules;
class KeyNumberPolicy
{
/**
* Determine whether the user can view any models.
*
* @return boolean
*/
public function viewAny(): bool
{
return UserStaticRules::everyOne();
}
/**
* 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 create a new model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function create(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can update the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function update(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can delete the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function delete(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can duplicate the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function duplicate(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can publish/unpublish the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function changePublished(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -2,6 +2,7 @@
namespace App\Providers; namespace App\Providers;
use App\Models\KeyNumber;
use App\Models\Profession; use App\Models\Profession;
use App\Models\User; use App\Models\User;
use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Cache\RateLimiting\Limit;
@ -44,6 +45,7 @@ class RouteServiceProvider extends ServiceProvider
Route::model('user', User::class); Route::model('user', User::class);
Route::model('profession', Profession::class); Route::model('profession', Profession::class);
Route::model('keyNumber', KeyNumber::class);
} }
/** /**

View file

@ -0,0 +1,24 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class KeyNumberFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'text' => fake()->sentence(),
'picto_alt' => fake()->sentence(),
'picto_title' => fake()->sentence(),
'source' => fake()->sentence(),
'published' => fake()->boolean(75),
];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -8,6 +8,8 @@ return new class extends Migration
{ {
/** /**
* Run the migrations. * Run the migrations.
*
* @return void
*/ */
public function up(): void public function up(): void
{ {
@ -26,6 +28,8 @@ return new class extends Migration
/** /**
* Reverse the migrations. * Reverse the migrations.
*
* @return void
*/ */
public function down(): void public function down(): void
{ {

View file

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::create('key_numbers', function (Blueprint $table) {
$table->id();
$table->string('picto')->comment('Picto path.');
$table->string('picto_alt')->comment('Picto alt attribute.');
$table->string('picto_title')->comment('Picto title attribute.');
$table->string('text')->comment('Picto legend.');
$table->string('source')->comment('Text origin.');
$table->integer('order')->comment('Display order bo.');
$table->boolean('published')->comment('Picto publish status.');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::dropIfExists('key_numbers');
}
};

View file

@ -0,0 +1,35 @@
<?php
namespace Database\Seeders\Development;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\KeyNumber;
use Illuminate\Database\Seeder;
class KeyNumberSeeder extends Seeder
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = KeyNumber::class;
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
KeyNumber::factory(10)->make()->each(function (KeyNumber $keyNumber) {
$keyNumber->picto = FileStorageHelper::storeFile(
$keyNumber,
new \SplFileInfo(\resource_path(
'../database/factories/assets/keyNumbers/default-picture-150x150.png'
))
);
$keyNumber->save();
});
}
}

View file

@ -2,6 +2,7 @@
namespace Database\Seeders; namespace Database\Seeders;
use Database\Seeders\Development\KeyNumberSeeder;
use Database\Seeders\Development\ProfessionSeeder; use Database\Seeders\Development\ProfessionSeeder;
use Database\Seeders\Development\UserSeeder; use Database\Seeders\Development\UserSeeder;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@ -17,7 +18,8 @@ class DevelopmentSeeder extends Seeder
{ {
$this->call([ $this->call([
UserSeeder::class, UserSeeder::class,
ProfessionSeeder::class ProfessionSeeder::class,
KeyNumberSeeder::class
]); ]);
} }
} }

View file

@ -4,6 +4,7 @@ return [
'classes' => [ 'classes' => [
'user' => 'user', 'user' => 'user',
'activity_log' => 'activity log|activity logs', 'activity_log' => 'activity log|activity logs',
'static_page' => 'static page|static pages', 'static_page' => 'static page|static pages',
'keyNumber' => 'Key number'
] ]
]; ];

View file

@ -198,6 +198,7 @@ return [
'sex' => 'sex', 'sex' => 'sex',
'short_text' => 'short text', 'short_text' => 'short text',
'size' => 'size', 'size' => 'size',
'source' => 'text source',
'state' => 'state', 'state' => 'state',
'street' => 'street', 'street' => 'street',
'student' => 'student', 'student' => 'student',

View file

@ -6,5 +6,6 @@ return [
'activity_log' => 'journal d\'activité|journaux d\'activité', 'activity_log' => 'journal d\'activité|journaux d\'activité',
'static_page' => 'page statique|pages statiques', 'static_page' => 'page statique|pages statiques',
'profession' => 'profession', 'profession' => 'profession',
'keyNumber' => 'Chiffre clé'
] ]
]; ];

View file

@ -198,6 +198,7 @@ return [
'sex' => 'sexe', 'sex' => 'sexe',
'short_text' => 'texte court', 'short_text' => 'texte court',
'size' => 'taille', 'size' => 'taille',
'source' => 'source du text',
'state' => 'état', 'state' => 'état',
'street' => 'rue', 'street' => 'rue',
'student' => 'étudiant', 'student' => 'étudiant',

View file

@ -29,6 +29,7 @@ import {
faFile, faFile,
faFolderOpen, faFolderOpen,
faHouse, faHouse,
faKey,
faListUl, faListUl,
faPaintRoller, faPaintRoller,
faPencil, faPencil,
@ -48,6 +49,7 @@ import {
config.autoReplaceSvg = false; config.autoReplaceSvg = false;
library.add(faEraser); library.add(faEraser);
library.add(faKey);
library.add(faArrowLeftLong); library.add(faArrowLeftLong);
library.add(faPlus); library.add(faPlus);
library.add(faTrash); library.add(faTrash);

View file

@ -27,6 +27,15 @@
])> ])>
<i class="fa-solid fa-user-tie"></i>&nbsp;{{ str(__('models.classes.profession'))->title() }} <i class="fa-solid fa-user-tie"></i>&nbsp;{{ str(__('models.classes.profession'))->title() }}
</a> </a>
{{-- KEYNUMBERS --}}
<a data-bs-toggle="tooltip" href="{{ route('bo.keyNumbers.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.keyNumber')]) }}" role="button"
@class([
'btn btn-primary w-100 mt-1',
'fw-bold active' => request()->routeIs('bo.keyNumbers.*'),
])>
<i class="fa-solid fa-key"></i>&nbsp;{{ str(__('models.classes.keyNumber'))->title() }}
</a>
</div> </div>
</nav> </nav>
@endauth @endauth

View file

@ -0,0 +1,36 @@
@extends('bo.layout', ['brParam' => $keyNumberModel])
@section('title', __('Création d\'une :model', ['model' => __('models.classes.keyNumber')]))
@section('description', __('Création d\'une tout nouveau :model', ['model' => __('models.classes.keyNumber')]))
@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.keyNumbers.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.keyNumber')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $keyNumberModel])
</div>
<div class="mb-md-0 mb-2">
<button class="btn btn-primary" id="formSubmitClone" data-bs-toggle="tooltip" type="submit"
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.keyNumber')]) }}">
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
</div>
</div>
<form action="{{ route('bo.keyNumbers.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.keyNumbers.form')
@include('bo.partials.script-button-clone')
<div class="row mt-3">
<div class="col text-center">
<button class="btn btn-primary" id="formSubmit" data-bs-toggle="tooltip" type="submit"
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.keyNumber')]) }}">
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,60 @@
@extends('bo.layout', ['brParam' => $keyNumberModel])
@section('title', __('Édition d\'une :model', ['model' => __('models.classes.keyNumber')]))
@section('description', __('Édition d\'une :model déjà existant', ['model' => __('models.classes.keyNumber')]))
@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.keyNumbers.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.keyNumber'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $keyNumberModel])
</div>
<div class="mb-md-0 mb-2">
<form class="btn-group confirmDeleteTS" action="{{ route('bo.keyNumbers.destroy', $keyNumberModel) }}" method="POST" novalidate>
@can('view', $keyNumberModel)
<a class="btn btn-warning" data-bs-toggle="tooltip"
href="{{ route('bo.keyNumbers.show', ['keyNumber' => $keyNumberModel]) }}"
title="{{ str(__('crud.actions.show'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@can('duplicate', $keyNumberModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.keyNumbers.duplicate', ['keyNumber' => $keyNumberModel]) }}"
title="{{ str(__('crud.actions.duplicate'))->ucfirst() }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
<button class="btn btn-primary" id="formSubmitClone" data-bs-toggle="tooltip" type="submit"
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.keyNumber')]) }}">
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
@can('delete', $keyNumberModel)
@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>
</div>
</div>
<form action="{{ route('bo.keyNumbers.update', $keyNumberModel) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.keyNumbers.form')
@include('bo.partials.script-button-clone')
<div class="row">
<div class="col text-center">
<button class="btn btn-primary" id="formSubmit" data-bs-toggle="tooltip" type="submit"
title="{{ __('crud.helpers.save_model', ['model' => __('models.classes.keyNumber')]) }}">
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,168 @@
<div class="row">
{{-- PICTO --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ str(__('validation.attributes.image'))->ucFirst() }}</legend>
<div class="row mb-3">
{{-- PICTO_ALT --}}
<div class="col-12 col-lg-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'keyNumberPictoAlt',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => str(__('validation.custom.attribute_alt'))->ucFirst(),
'inter1' => __('validation.custom.of_the.vowel'),
'field2' => __('validation.attributes.image'),
'inter2' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'hasWordCounter' => true,
'name' => 'picto_alt',
'required' => true,
'model' => $keyNumberModel ?? null,
'helper' => __('crud.minicrud.picture_alt_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => str(__('validation.custom.attribute_alt'))->ucFirst(),
'inter1' => __('validation.custom.of_the.vowel'),
'field2' => __('validation.attributes.image'),
'inter2' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
])
</div>
{{-- PICTO_TITLE --}}
<div class="col-12 col-lg-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'keyNumberPictoTitle',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => str(__('validation.custom.attribute_title'))->ucFirst(),
'inter1' => __('validation.custom.of_the.vowel'),
'field2' => __('validation.attributes.image'),
'inter2' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'hasWordCounter' => true,
'name' => 'picto_title',
'required' => true,
'model' => $keyNumberModel ?? null,
'helper' => __('crud.minicrud.picture_title_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => str(__('validation.custom.attribute_title'))->ucFirst(),
'inter1' => __('validation.custom.of_the.vowel'),
'field2' => __('validation.attributes.image'),
'inter2' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
])
</div>
{{-- PICTO --}}
<div class="col-12">
@include('bo.partials.inputs.varchar-picture', [
'id' => 'keyNumberPicto',
'name' => 'picto',
'width' => 155,
'height' => 155,
'model' => $keyNumberModel ?? null,
'helper' => __('crud.minicrud.dimensions_must_be', [
'widthpx' => '155px',
'heightpx' => '155px',
]),
'required' => true,
'preview' => true,
])
</div>
</div>
</fieldset>
</div>
{{-- TEXT --}}
<div class="col-12 col-lg-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ str(__('validation.attributes.result_text_under_image'))->ucFirst() }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'keyNumberText',
'label' => __(':field :inter:model', [
'field' => str(__('validation.attributes.result_text_under_image'))->ucFirst(),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'hasWordCounter' => true,
'name' => 'text',
'required' => true,
'model' => $keyNumberModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.result_text_under_image'),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __(':field :inter:model', [
'field' => str(__('validation.attributes.result_text_under_image'))->ucFirst(),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- SOURCE --}}
<div class="col-12 col-lg-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ str(__('validation.attributes.text'))->ucFirst() }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'keyNumberSource',
'label' => __(':field :inter:model', [
'field' => str(__('validation.attributes.source'))->ucFirst(),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'hasWordCounter' => true,
'name' => 'source',
'required' => true,
'model' => $keyNumberModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.source'),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __(':field :inter:model', [
'field' => str(__('validation.attributes.source'))->ucFirst(),
'inter' => __('validation.custom.of_the.male'),
'model' => __('models.classes.keyNumber'),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- PUBLISHED --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ __('crud.minicrud.visibility_label') }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.tinyint-boolean', [
'id' => 'keyNumberPublished',
'name' => 'published',
'model' => $keyNumberModel ?? null,
'label' => __('crud.minicrud.visibility_label'),
'helper' => __('crud.minicrud.visibility_helper'),
])
</div>
</div>
</fieldset>
</div>
<div class="col-12 text-center">
<p><b>{{ __('* Champs obligatoires') }}</b></p>
</div>
</div>

View file

@ -0,0 +1,78 @@
<table class="table-hover table-fix-action m-0 table">
@if (count($keyNumberModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'text' => str(__('validation.attributes.text'))->ucfirst(),
'picto' => str(__('validation.attributes.image'))->ucfirst(),
'published' => str(__('validation.custom.published'))->ucfirst(),
'updated_at' => str(__('validation.attributes.updated_at'))->ucfirst(),
],
])
</thead>
<tbody>
@foreach ($keyNumberModels as $keyNumberModel)
<tr class="border-bottom">
<td class="text-center align-middle">{{ $keyNumberModel->text }}</td>
<td class="text-center align-middle">
<img class="image-preview" src="{{ asset($keyNumberModel->picto) }}" title="{{ $keyNumberModel->picto_title }}"
alt="{{ $keyNumberModel->picto_alt }}">
</td>
@include('bo.modules.change-published-status', [
'routeName' => 'keyNumbers',
'model' => $keyNumberModel,
])
<td class="text-center align-middle">
<span class="badge bg-secondary">{{ $keyNumberModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['show', 'duplicate', 'update', 'delete'], $keyNumberModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.keyNumbers.destroy', $keyNumberModel) }}"
method="POST" novalidate>
@can('view', $keyNumberModel)
<a class="btn btn-sm btn-warning" data-bs-toggle="tooltip"
href="{{ route('bo.keyNumbers.show', ['keyNumber' => $keyNumberModel]) }}"
title="{{ str(__('crud.actions.show'))->ucfirst() }}">
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@can('duplicate', $keyNumberModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.keyNumbers.duplicate', ['keyNumber' => $keyNumberModel]) }}"
title="{{ str(__('crud.actions.duplicate'))->ucfirst() }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $keyNumberModel)
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.keyNumbers.edit', ['keyNumber' => $keyNumberModel]) }}"
title="{{ str(__('crud.actions.update'))->ucfirst() }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $keyNumberModel)
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip" type="submit"
title="{{ str(__('crud.actions.delete'))->ucfirst() }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
@else
<span class="text-danger" data-bs-toggle="tooltip" title="{{ __('list.right') }}">
<i class="fa-solid fa-ban"></i>
</span>
@endcan
</td>
</tr>
@endforeach
</tbody>
@else
<tr>
<td class="border-0">
{{ trans_choice('crud.other.no_model_found', 1, ['model' => __('models.classes.keyNumber')]) }}
</td>
</tr>
@endif
</table>

View file

@ -0,0 +1,21 @@
@extends('bo.layout')
@section('title', str(__('models.classes.keyNumber'))->ucfirst()->plural())
@section('description', __('Liste de tous les :model', ['model' => str(__('models.classes.keyNumber'))->plural()]))
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap">
@include('modules.breadcrumbs.breadcrumb-body')
@can('create', \App\Models\KeyNumber::class)
<a class="btn btn-primary float-right" data-bs-toggle="tooltip" href="{{ route('bo.keyNumbers.create') }}"
title="{{ __('crud.helpers.create_model', ['model' => __('models.classes.keyNumber')]) }}">
<i class="fa-solid fa-plus"></i>
</a>
@endcan
</div>
@include('bo.modules.search-bar')
<div class="table-responsive mb-3">
@include('bo.pages.keyNumbers.index-list')
</div>
{{ $keyNumberModels->links() }}
@endsection

View file

@ -0,0 +1,98 @@
@extends('bo.layout', ['brParam' => $keyNumberModel])
@section('title', __('Aperçu d\'un :model', ['model' => __('models.classes.keyNumber')]))
@section('description', __('Aperçu d\'un :model déjà existante', ['model' => __('models.classes.keyNumber')]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-md-nowrap align-items-center border-bottom 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-tooltip="tooltip" data-bs-placement="top"
href="{{ route('bo.keyNumbers.index', ['sort_col' => 'created_at', 'sort_way' => 'desc']) }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.keyNumber'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $keyNumberModel])
</div>
@canAny(['duplicate', 'update', 'delete'], $keyNumberModel)
<form class="btn-group confirmActionTS" data-message="{{ __('crud.sweetalert.data_lost') }}"
action="{{ route('bo.keyNumbers.destroy', $keyNumberModel) }}" method="POST" novalidate>
@can('duplicate', $keyNumberModel)
<a class="btn btn-secondary" data-bs-tooltip="tooltip" data-bs-placement="top"
href="{{ route('bo.keyNumbers.duplicate', ['keyNumber' => $keyNumberModel]) }}"
title="{{ __('crud.helpers.duplicate_model', ['model' => __('models.classes.keyNumber')]) }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $keyNumberModel)
<a class="btn btn-primary" data-bs-tooltip="tooltip" data-bs-placement="top"
href="{{ route('bo.keyNumbers.edit', ['keyNumber' => $keyNumberModel]) }}"
title="{{ __('crud.helpers.edit_model', ['model' => __('models.classes.keyNumber')]) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $keyNumberModel)
@csrf
@method('DELETE')
<button class="btn btn-danger" data-bs-tooltip="tooltip" data-bs-placement="top" type="submit"
title="{{ __('crud.helpers.delete_model', ['model' => __('models.classes.keyNumber')]) }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
@endcan
</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(__('validation.attributes.text'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ $keyNumberModel->text }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.attributes.image'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
<img class="img-fluid" src="{{ asset($keyNumberModel->picto) }}"
title="{{ $keyNumberModel->picto_title }}" alt="{{ $keyNumberModel->picto_alt }}">
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">{{ str(__('validation.custom.source'))->ucFirst() }}</td>
<td class="w-50 text-center align-middle">
{{ $keyNumberModel->source }}
</td>
</tr>
<tr class="border-bottom">
<td class="w-50 fw-bold text-center align-middle">
{{ str(__('validation.custom.published'))->ucFirst() }}
</td>
<td class="w-50 text-center align-middle">
{{ $keyNumberModel->published
? str($keyNumberModel->created_at->isoFormat('LLLL'))->ucFirst()
: __('bo_other_model_not_published', [
'model' => str(__('models.keyNumber'))->ucFirst(),
]) }}
</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">
{{ str($keyNumberModel->created_at->isoFormat('LLLL'))->ucFirst() }}
</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">
{{ str($keyNumberModel->updated_at->isoFormat('LLLL'))->ucFirst() }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
@endsection

View file

@ -1,6 +1,7 @@
<?php <?php
use App\Models\ActivityLog; use App\Models\ActivityLog;
use App\Models\KeyNumber;
use App\Models\Profession; use App\Models\Profession;
use App\Models\StaticPage; use App\Models\StaticPage;
use App\Models\User; use App\Models\User;
@ -60,6 +61,30 @@ Breadcrumbs::for('bo.professions.duplicate', function (Generator $trail) {
$trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); $trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
}); });
// * KEYNUMBERS
Breadcrumbs::for('bo.keyNumbers.index', function (Generator $trail) {
$trail->push(
Str::of(trans('models.classes.keyNumber'))->plural()->ucfirst(),
route('bo.keyNumbers.index')
);
});
Breadcrumbs::for('bo.keyNumbers.show', function (Generator $trail, KeyNumber $keyNumber) {
$trail->parent('bo.keyNumbers.index');
$trail->push(Str::ucfirst(trans('crud.actions.view')), route('bo.keyNumbers.show', $keyNumber));
});
Breadcrumbs::for('bo.keyNumbers.create', function (Generator $trail) {
$trail->parent('bo.keyNumbers.index');
$trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.keyNumbers.create'));
});
Breadcrumbs::for('bo.keyNumbers.edit', function (Generator $trail, KeyNumber $keyNumber) {
$trail->parent('bo.keyNumbers.index');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.keyNumbers.edit', $keyNumber));
});
Breadcrumbs::for('bo.keyNumbers.duplicate', function (Generator $trail) {
$trail->parent('bo.keyNumbers.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});
// * ACTIVITY_LOGS // * ACTIVITY_LOGS
Breadcrumbs::for('bo.activity_logs.index', function (Generator $trail) { Breadcrumbs::for('bo.activity_logs.index', function (Generator $trail) {
$trail->push( $trail->push(

View file

@ -2,6 +2,7 @@
use App\Http\Controllers\Bo\ActivityLogController; use App\Http\Controllers\Bo\ActivityLogController;
use App\Http\Controllers\Bo\DashboardController; use App\Http\Controllers\Bo\DashboardController;
use App\Http\Controllers\Bo\KeyNumberController;
use App\Http\Controllers\Bo\ProfessionController; use App\Http\Controllers\Bo\ProfessionController;
use App\Http\Controllers\Bo\StaticPageController; use App\Http\Controllers\Bo\StaticPageController;
use App\Http\Controllers\Bo\UserController; use App\Http\Controllers\Bo\UserController;
@ -56,6 +57,15 @@ Route::prefix('bo')
ProfessionController::class, 'duplicate' ProfessionController::class, 'duplicate'
])->name('professions.duplicate'); ])->name('professions.duplicate');
// * KEYNUMBERS.
Route::resource('keyNumbers', KeyNumberController::class);
Route::patch('/keyNumbers/{keyNumber}/change-published', [
KeyNumberController::class, 'changePublished'
])->name('keyNumbers.change-published');
Route::get('/keyNumbers/{keyNumber}/duplicate', [
KeyNumberController::class, 'duplicate'
])->name('keyNumbers.duplicate');
Route::middleware('can:isConceptor')->group(function () { Route::middleware('can:isConceptor')->group(function () {
// * ACTIVITY LOGS. // * ACTIVITY LOGS.
Route::resource('activity_logs', ActivityLogController::class)->only(['index', 'show']); Route::resource('activity_logs', ActivityLogController::class)->only(['index', 'show']);