From 4ad19577f684935e759f26ecab4aeb514d902a1d Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Mon, 10 Jun 2024 16:47:07 +0200 Subject: [PATCH] feat: :sparkles: add CRUD claims --- app/Http/Controllers/Bo/ClaimController.php | 182 ++++++++++++++++++ .../Requests/Bo/Claims/StoreClaimRequest.php | 61 ++++++ .../Requests/Bo/Claims/UpdateClaimRequest.php | 18 ++ app/Models/Claim.php | 52 +++++ app/Policies/ClaimPolicy.php | 86 +++++++++ app/Providers/RouteServiceProvider.php | 2 + database/factories/ClaimFactory.php | 21 ++ ...4_06_10_122602_create_claims_table.php.php | 40 ++++ database/seeders/Development/ClaimSeeder.php | 21 ++ resources/lang/en/models.php | 1 + resources/lang/fr/models.php | 1 + resources/views/bo/layouts/sidemenu.blade.php | 16 ++ .../views/bo/pages/claims/create.blade.php | 36 ++++ .../views/bo/pages/claims/edit.blade.php | 60 ++++++ .../views/bo/pages/claims/form.blade.php | 58 ++++++ .../bo/pages/claims/index-list.blade.php | 73 +++++++ .../views/bo/pages/claims/index.blade.php | 21 ++ .../views/bo/pages/claims/show.blade.php | 83 ++++++++ .../pages/consumption_moments/show.blade.php | 2 +- .../bo/pages/demarche_slides/show.blade.php | 2 +- .../views/bo/pages/key_numbers/show.blade.php | 2 +- .../views/bo/pages/main_slides/show.blade.php | 2 +- .../bo/pages/product_types/show.blade.php | 2 +- .../views/bo/pages/professions/show.blade.php | 2 +- .../views/bo/pages/recipes/show.blade.php | 2 +- routes/breadcrumbs-bo.php | 25 +++ routes/web-bo.php | 10 + 27 files changed, 874 insertions(+), 7 deletions(-) create mode 100644 app/Http/Controllers/Bo/ClaimController.php create mode 100644 app/Http/Requests/Bo/Claims/StoreClaimRequest.php create mode 100644 app/Http/Requests/Bo/Claims/UpdateClaimRequest.php create mode 100644 app/Models/Claim.php create mode 100644 app/Policies/ClaimPolicy.php create mode 100644 database/factories/ClaimFactory.php create mode 100644 database/migrations/2024_06_10_122602_create_claims_table.php.php create mode 100644 database/seeders/Development/ClaimSeeder.php create mode 100644 resources/views/bo/pages/claims/create.blade.php create mode 100644 resources/views/bo/pages/claims/edit.blade.php create mode 100644 resources/views/bo/pages/claims/form.blade.php create mode 100644 resources/views/bo/pages/claims/index-list.blade.php create mode 100644 resources/views/bo/pages/claims/index.blade.php create mode 100644 resources/views/bo/pages/claims/show.blade.php diff --git a/app/Http/Controllers/Bo/ClaimController.php b/app/Http/Controllers/Bo/ClaimController.php new file mode 100644 index 00000000..6e989f71 --- /dev/null +++ b/app/Http/Controllers/Bo/ClaimController.php @@ -0,0 +1,182 @@ +authorizeResource(Claim::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 $claimModels */ + $claimModels = Claim::query(); + + /** @var string $search Search field */ + $search = $request->search; + if ($search) { + $this->searchQuery( + $claimModels, + $search, + null, + 'first_name', + 'last_name', + 'email', + 'role', + ); + } + $searchFields = \implode(', ', [ + trans('validation.attributes.first_name'), + trans('validation.attributes.last_name'), + trans('validation.attributes.email'), + trans('validation.attributes.role'), + ]); + + /** Sort columns with a query */ + $this->sortQuery($claimModels); + + /** Custom pagination */ + $claimModels = $this->paginate($claimModels); + + return view('bo.pages.claims.index', compact('claimModels', 'search', 'searchFields')); + } + + /** + * Show the specified resource. + * + * @param \App\Models\Claim $claim + * @return \Illuminate\Contracts\View\View + */ + public function show(Claim $claim): \Illuminate\Contracts\View\View + { + return view('bo.pages.claims.show', ['claimModel' => $claim]); + } + + /** + * Show the form for creating a new resource. + * + * @param \App\Models\Claim $claim + * @return \Illuminate\Contracts\View\View + */ + public function create(Claim $claim): \Illuminate\Contracts\View\View + { + return view('bo.pages.claims.create', ['claimModel' => $claim]); + } + + /** + * Store a newly created resource in storage. + * + * @param \App\Http\Requests\Bo\Claims\StoreClaimRequest $request + * @return \Illuminate\Http\RedirectResponse + */ + public function store(StoreClaimRequest $request): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request) { + $claim = new Claim(); + $claim->fill($request->validated()); + + if ($claim->saveOrFail()) { + return redirect()->route('bo.claims.edit', $claim) + ->with('success', trans('crud.messages.has_been_created', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + } + return redirect()->back() + ->with('error', trans('crud.messages.cannot_be_created', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + }); + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\Claim $claim + * @return \Illuminate\Contracts\View\View + */ + public function edit(Claim $claim): \Illuminate\Contracts\View\View + { + return view('bo.pages.claims.edit', ['claimModel' => $claim]); + } + + /** + * Update the specified resource in storage. + * + * @param \App\Http\Requests\Bo\Claims\UpdateClaimRequest $request + * @param \App\Models\Claim $claim + * @return \Illuminate\Http\RedirectResponse + */ + public function update(UpdateClaimRequest $request, Claim $claim): \Illuminate\Http\RedirectResponse + { + return DB::transaction(function () use ($request, $claim) { + $claim->fill($request->validated()); + + if ($claim->saveOrFail()) { + return redirect()->route('bo.claims.edit', $claim) + ->with('success', trans('crud.messages.has_been_updated', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + } + return redirect()->route('bo.claims.edit', $claim) + ->with('error', trans('crud.messages.cannot_be_updated', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + }); + } + + /** + * Remove the specified resource from storage. + * + * @param \App\Models\Claim $claim + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Claim $claim): \Illuminate\Http\RedirectResponse + { + /** @var array */ + $previousQueries = []; + \parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries); + if ($claim->deleteOrFail()) { + return redirect()->route('bo.claims.index', $previousQueries) + ->with('success', trans('crud.messages.has_been_deleted', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + } + return redirect()->back() + ->with('error', trans('crud.messages.cannot_be_deleted', [ + 'model' => Str::ucfirst(trans('models.classes.claim')) + ])); + } + + /** + * Duplicate the specified resource. + * + * @param \App\Models\Claim $claim + * @return \Illuminate\Contracts\View\View + */ + public function duplicate(Claim $claim): \Illuminate\Contracts\View\View + { + return $this->create($claim->replicate()); + } +} diff --git a/app/Http/Requests/Bo/Claims/StoreClaimRequest.php b/app/Http/Requests/Bo/Claims/StoreClaimRequest.php new file mode 100644 index 00000000..675580f6 --- /dev/null +++ b/app/Http/Requests/Bo/Claims/StoreClaimRequest.php @@ -0,0 +1,61 @@ +merge([ + 'published' => $this->boolean('published') + ]); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules(): array + { + return [ + 'label' => 'required|string|between:3,255', + 'published' => 'required|boolean', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes(): array + { + return [ + 'label' => trans('validation.custom.label'), + 'published' => trans('validation.attributes.published') + ]; + } +} diff --git a/app/Http/Requests/Bo/Claims/UpdateClaimRequest.php b/app/Http/Requests/Bo/Claims/UpdateClaimRequest.php new file mode 100644 index 00000000..692adea5 --- /dev/null +++ b/app/Http/Requests/Bo/Claims/UpdateClaimRequest.php @@ -0,0 +1,18 @@ +route('claim')); + } +} diff --git a/app/Models/Claim.php b/app/Models/Claim.php new file mode 100644 index 00000000..595fb524 --- /dev/null +++ b/app/Models/Claim.php @@ -0,0 +1,52 @@ + + */ + protected $fillable = [ + 'label', + 'published', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'published' => 'boolean', + ]; + + // * RELATIONSHIPS + + /** + * Get all of the products for the product type. + * + * @return \Illuminate\Database\Eloquent\Relations\MorphToMany + */ + public function products(): \Illuminate\Database\Eloquent\Relations\MorphToMany + { + return $this->morphToMany(Product::class, 'productable'); + } +} diff --git a/app/Policies/ClaimPolicy.php b/app/Policies/ClaimPolicy.php new file mode 100644 index 00000000..c20a1ea6 --- /dev/null +++ b/app/Policies/ClaimPolicy.php @@ -0,0 +1,86 @@ + + */ + public function definition() + { + return [ + 'label' => fake()->words(rand(1, 2), true), + 'published' => fake()->boolean(75), + ]; + } +} diff --git a/database/migrations/2024_06_10_122602_create_claims_table.php.php b/database/migrations/2024_06_10_122602_create_claims_table.php.php new file mode 100644 index 00000000..69171c23 --- /dev/null +++ b/database/migrations/2024_06_10_122602_create_claims_table.php.php @@ -0,0 +1,40 @@ +id(); + $table->string('label')->comment('Claim label.'); + $table->boolean('published')->comment('Claim publish status.'); + $table->timestamps(); + }); + + // Call seeder. + Artisan::call('db:seed', [ + '--class' => ClaimSeeder::class, + ]); + } + + /** + * Run the migrations. + * + * @return void + */ + public function down(): void + { + Schema::dropIfExists('claims'); + } +}; diff --git a/database/seeders/Development/ClaimSeeder.php b/database/seeders/Development/ClaimSeeder.php new file mode 100644 index 00000000..0ca17c1f --- /dev/null +++ b/database/seeders/Development/ClaimSeeder.php @@ -0,0 +1,21 @@ +create(); + } +} diff --git a/resources/lang/en/models.php b/resources/lang/en/models.php index c60c80e4..ff1087bd 100644 --- a/resources/lang/en/models.php +++ b/resources/lang/en/models.php @@ -24,5 +24,6 @@ return [ 'product' => 'product', 'recipe' => 'recipe', 'product_type' => 'product type|product types', + 'claim' => 'claim', ] ]; diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php index 008bb0e4..8b609f41 100644 --- a/resources/lang/fr/models.php +++ b/resources/lang/fr/models.php @@ -24,5 +24,6 @@ return [ 'product' => 'produit', 'recipe' => 'recette', 'product_type' => 'type de produit|types de produit', + 'claim' => 'allégations', ] ]; diff --git a/resources/views/bo/layouts/sidemenu.blade.php b/resources/views/bo/layouts/sidemenu.blade.php index 537c5592..d954ce5b 100644 --- a/resources/views/bo/layouts/sidemenu.blade.php +++ b/resources/views/bo/layouts/sidemenu.blade.php @@ -391,6 +391,22 @@
  • + {{-- CLAIMS --}} +
  • + request()->routeIs('bo.claims.*') + ]) data-bs-toggle="tooltip" + href="{{ route('bo.claims.index') }}" + title="{{ __('crud.helpers.update_model', ['model' => __('models.classes.claim')]) }}"> + request()->routeIs('bo.claims.*') + ])> + {{ str(__('models.classes.claim'))->ucFirst() }} + +
  • +
  • {{-- MEATS --}}
  • $claimModel]) + +@section('title', __('Création d\'une :model', ['model' => __('models.classes.claim')])) +@section('description', __('Création d\'une tout nouveau :model', ['model' => __('models.classes.claim')])) +@section('breadcrumb', request()->route()->getName()) + +@section('content') +
    +
    + + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $claimModel]) +
    +
    + +
    +
    +
    + @csrf + @include('bo.pages.claims.form') + @include('bo.partials.script-button-clone') +
    +
    + +
    +
    +
    +@endsection diff --git a/resources/views/bo/pages/claims/edit.blade.php b/resources/views/bo/pages/claims/edit.blade.php new file mode 100644 index 00000000..0ad2bae1 --- /dev/null +++ b/resources/views/bo/pages/claims/edit.blade.php @@ -0,0 +1,60 @@ +@extends('bo.layout', ['brParam' => $claimModel]) + +@section('title', __('Édition d\'une :model', ['model' => __('models.classes.claim')])) +@section('description', __('Édition d\'une :model déjà existant', ['model' => __('models.classes.claim')])) +@section('breadcrumb', request()->route()->getName()) + +@section('content') +
    +
    + + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $claimModel]) +
    +
    +
    + @can('view', $claimModel) + + + + @endcan + @can('duplicate', $claimModel) + + + + @endcan + + @can('delete', $claimModel) + @csrf + @method('DELETE') + + @endcan +
    +
    +
    +
    + @csrf + @method('PUT') + @include('bo.pages.claims.form') + @include('bo.partials.script-button-clone') +
    +
    + +
    +
    +
    +@endsection diff --git a/resources/views/bo/pages/claims/form.blade.php b/resources/views/bo/pages/claims/form.blade.php new file mode 100644 index 00000000..45deefb0 --- /dev/null +++ b/resources/views/bo/pages/claims/form.blade.php @@ -0,0 +1,58 @@ +
    + {{-- LABEL --}} +
    +
    + {{ str(__('validation.custom.label'))->ucFirst() }} +
    +
    + @include('bo.partials.inputs.varchar', [ + 'id' => 'claimLabel', + 'label' => __(':field :inter:model', [ + 'field' => str(__('validation.custom.label'))->ucFirst(), + 'inter' => __('validation.custom.of_the.female'), + 'model' => __('models.classes.claim'), + ]), + 'hasWordCounter' => true, + 'name' => 'label', + 'required' => true, + 'model' => $claimModel ?? null, + 'helper' => __('validation.between.string', [ + 'attribute' => __(':field :inter:model', [ + 'field' => __('validation.custom.label'), + 'inter' => __('validation.custom.of_the.female'), + 'model' => __('models.classes.claim'), + ]), + 'min' => 3, + 'max' => 255, + ]), + 'placeholder' => __(':field :inter:model', [ + 'field' => str(__('validation.custom.label'))->ucFirst(), + 'inter' => __('validation.custom.of_the.female'), + 'model' => __('models.classes.claim'), + ]), + ]) +
    +
    +
    +
    + {{-- PUBLISHED --}} +
    +
    + {{ __('crud.minicrud.visibility_label') }} +
    +
    + @include('bo.partials.inputs.tinyint-boolean', [ + 'id' => 'claimPublished', + 'name' => 'published', + 'model' => $claimModel ?? null, + 'label' => __('crud.minicrud.visibility_label'), + 'helper' => __('crud.minicrud.visibility_helper'), + ]) +
    +
    +
    +
    +
    +

    {{ __('* Champs obligatoires') }}

    +
    +
    diff --git a/resources/views/bo/pages/claims/index-list.blade.php b/resources/views/bo/pages/claims/index-list.blade.php new file mode 100644 index 00000000..35fb64d2 --- /dev/null +++ b/resources/views/bo/pages/claims/index-list.blade.php @@ -0,0 +1,73 @@ + + @if (count($claimModels) > 0) + + @include('bo.modules.table-col-sorter', [ + 'cols' => [ + 'label' => str(__('validation.custom.label'))->ucfirst(), + 'published' => str(__('validation.custom.publication'))->ucfirst(), + 'updated_at' => str(__('validation.attributes.updated_at'))->ucfirst(), + ], + ]) + + + @foreach ($claimModels as $claimModel) + + + @include('bo.modules.change-published-status', [ + 'routeName' => 'claims', + 'model' => $claimModel, + ]) + + + + @endforeach + + @else + + + + @endif +
    {{ $claimModel->label }} + {{ $claimModel->updated_at->isoFormat('LLLL') }} + + @canAny(['show', 'duplicate', 'update', 'delete'], $claimModel) +
    + @can('view', $claimModel) + + + + @endcan + @can('duplicate', $claimModel) + + + + @endcan + @can('update', $claimModel) + + + + @endcan + @can('delete', $claimModel) + @csrf + @method('DELETE') + + @endcan +
    + @else + + + + @endcan +
    + {{ trans_choice('crud.other.no_model_found', 1, ['model' => __('models.classes.claim')]) }} +
    diff --git a/resources/views/bo/pages/claims/index.blade.php b/resources/views/bo/pages/claims/index.blade.php new file mode 100644 index 00000000..a8f5f4ec --- /dev/null +++ b/resources/views/bo/pages/claims/index.blade.php @@ -0,0 +1,21 @@ +@extends('bo.layout') + +@section('title', str(__('models.classes.claim'))->ucfirst()->plural()) +@section('description', __('Liste de tous les :model', ['model' => str(__('models.classes.claim'))->plural()])) + +@section('content') +
    + @include('modules.breadcrumbs.breadcrumb-body') + @can('create', \App\Models\Claim::class) + + + + @endcan +
    + @include('bo.modules.search-bar') +
    + @include('bo.pages.claims.index-list') +
    + {{ $claimModels->links() }} +@endsection diff --git a/resources/views/bo/pages/claims/show.blade.php b/resources/views/bo/pages/claims/show.blade.php new file mode 100644 index 00000000..42e79f19 --- /dev/null +++ b/resources/views/bo/pages/claims/show.blade.php @@ -0,0 +1,83 @@ +@extends('bo.layout', ['brParam' => $claimModel]) + +@section('title', __('Aperçu d\'une :model', ['model' => __('models.classes.claim')])) +@section('description', __('Aperçu d\'une :model déjà existante', ['model' => __('models.classes.claim')])) +@section('breadcrumb', request()->route()->getName()) + +@section('content') +
    +
    + + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $claimModel]) +
    + @canAny(['duplicate', 'update', 'delete'], $claimModel) +
    + @can('duplicate', $claimModel) + + + + @endcan + @can('update', $claimModel) + + + + @endcan + @can('delete', $claimModel) + @csrf + @method('DELETE') + + @endcan +
    + @endcan +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    {{ str(__('validation.custom.label'))->ucFirst() }} + {{ $claimModel->label }} +
    + {{ str(__('validation.custom.publication'))->ucFirst() }} + + {{ $claimModel->published + ? __('Oui') + : __('Non') }} +
    {{ str(__('validation.attributes.created_at'))->ucFirst() }} + {{ str($claimModel->created_at->isoFormat('LLLL'))->ucFirst() }} +
    {{ str(__('validation.attributes.updated_at'))->ucFirst() }} + {{ str($claimModel->updated_at->isoFormat('LLLL'))->ucFirst() }} +
    +
    +
    +
    +@endsection diff --git a/resources/views/bo/pages/consumption_moments/show.blade.php b/resources/views/bo/pages/consumption_moments/show.blade.php index b1d96005..55b55a9a 100644 --- a/resources/views/bo/pages/consumption_moments/show.blade.php +++ b/resources/views/bo/pages/consumption_moments/show.blade.php @@ -15,7 +15,7 @@ @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $consumptionMomentModel]) @canAny(['duplicate', 'update', 'delete'], $consumptionMomentModel) -
    @can('duplicate', $consumptionMomentModel) $demarcheSlideModel]) @canAny(['duplicate', 'update', 'delete'], $demarcheSlideModel) - @can('duplicate', $demarcheSlideModel) $keyNumberModel]) @canAny(['duplicate', 'update', 'delete'], $keyNumberModel) - @can('duplicate', $keyNumberModel) $mainSlideModel]) @canAny(['duplicate', 'update', 'delete'], $mainSlideModel) - @can('duplicate', $mainSlideModel) $productTypeModel]) @canAny(['duplicate', 'update', 'delete'], $productTypeModel) - @can('duplicate', $productTypeModel) $professionModel]) @canAny(['duplicate', 'update', 'delete'], $professionModel) - @can('duplicate', $professionModel) $recipeModel]) @canAny(['duplicate', 'update', 'delete'], $recipeModel) - @can('duplicate', $recipeModel) push(Str::ucfirst(trans('crud.actions.duplicate'))); }); +// * CLAIMS +Breadcrumbs::for('bo.claims.index', function (Generator $trail) { + $trail->push( + Str::of(trans('models.classes.claim'))->plural()->ucfirst(), + route('bo.claims.index') + ); +}); +Breadcrumbs::for('bo.claims.show', function (Generator $trail, Claim $claim) { + $trail->parent('bo.claims.index'); + $trail->push(Str::ucfirst(trans('crud.actions.view')), route('bo.claims.show', $claim)); +}); +Breadcrumbs::for('bo.claims.create', function (Generator $trail) { + $trail->parent('bo.claims.index'); + $trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.claims.create')); +}); +Breadcrumbs::for('bo.claims.edit', function (Generator $trail, Claim $claim) { + $trail->parent('bo.claims.index'); + $trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.claims.edit', $claim)); +}); +Breadcrumbs::for('bo.claims.duplicate', function (Generator $trail) { + $trail->parent('bo.claims.index'); + $trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); +}); + // * APPROACHES Breadcrumbs::for('bo.approaches.index', function (Generator $trail, int $approach_type) { $trail->push( diff --git a/routes/web-bo.php b/routes/web-bo.php index fcdb779f..1d43b4a2 100644 --- a/routes/web-bo.php +++ b/routes/web-bo.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Bo\ActivityLogController; use App\Http\Controllers\Bo\ApproachController; use App\Http\Controllers\Bo\DemarcheSlideController; use App\Http\Controllers\Bo\BrandAdvantageController; +use App\Http\Controllers\Bo\ClaimController; use App\Http\Controllers\Bo\ConsumptionMomentController; use App\Http\Controllers\Bo\DashboardController; use App\Http\Controllers\Bo\GeneralSettingController; @@ -217,6 +218,15 @@ Route::prefix('bo') ProductTypeController::class, 'duplicate' ])->name('product_types.duplicate'); + // * CLAIMS. + Route::resource('claims', ClaimController::class); + Route::patch('/claims/{claim}/change-published', [ + ClaimController::class, 'changePublished' + ])->name('claims.change-published'); + Route::get('/claims/{claim}/duplicate', [ + ClaimController::class, 'duplicate' + ])->name('claims.duplicate'); + // * APPROACHES. Route::get('/approaches/{approach_type}', [ ApproachController::class, 'index'