Added order for submodels in ranges/meats

This commit is contained in:
Noah Lancien 2024-04-16 10:32:26 +02:00
parent ed3e7636b8
commit 9abc118780
34 changed files with 623 additions and 106 deletions

View file

@ -5,7 +5,9 @@ namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Meats\StoreMeatRequest;
use App\Http\Requests\Bo\Meats\UpdateMeatRequest;
use App\Http\Requests\Bo\Meats\UpdateSubmodelsOrderRequest;
use App\Models\Meat;
use App\Models\Submeat;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
@ -33,7 +35,7 @@ class MeatController extends Controller
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $meatModels */
$meatModels = Meat::query();
$meatModels = Meat::query()->with('submeats:id,meat_id');
/** @var string $search Search field */
$search = $request->search;
@ -185,4 +187,47 @@ class MeatController extends Controller
{
return $this->create($meat->replicate());
}
public function editSubmeatsOrder(Meat $meat)
{
$submeats = $meat->submeats()->orderBy('order')->get(['id', 'label', 'meat_id']);
$meats = Meat::query()->get(['id', 'label']);
return view('bo.pages.submodels_order.edit', [
'modelName' => 'meat',
'model' => $meat,
'models' => $meats,
'submodels' => $submeats
]);
}
/**
* Updated the order of submeats related to a given range.
*
* @param \App\Http\Requests\Bo\Meats\UpdateSubmodelsOrderRequest $request
* @param \App\Models\Meat $meat
*
* @return \Illuminate\Http\RedirectResponse
*/
public function updateSubmeatsOrder(UpdateSubmodelsOrderRequest $request, Meat $meat): \Illuminate\Http\RedirectResponse
{
$oldList = $meat->submeats()->orderBy('order')->get();
$newList = (json_decode($request->get('jsonValue'), true));
return DB::transaction(function () use ($request, $meat, $oldList, $newList) {
$i = 0;
foreach ($newList as $newElement) {
$submeatModel = Submeat::find($newElement['id']);
$submeatModel->order = $oldList[$i]['order'];
$submeatModel->saveOrFail();
$i++;
}
return redirect()->route('bo.meats.edit-submeats-order', $request->meat)
->with('success', __('crud.messages.submodels_have_been_reordered', [
'submodelName' => str(trans('models.classes.submeat'))->plural(),
'modelLabel' => $meat->label,
]));
});
}
}

View file

@ -5,7 +5,9 @@ namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Ranges\StoreRangeRequest;
use App\Http\Requests\Bo\Ranges\UpdateRangeRequest;
use App\Http\Requests\Bo\Ranges\UpdateSubmodelsOrderRequest;
use App\Models\Range;
use App\Models\Subrange;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
@ -33,7 +35,7 @@ class RangeController extends Controller
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $rangeModels */
$rangeModels = Range::query();
$rangeModels = Range::query()->with('subranges:id,range_id');
/** @var string $search Search field */
$search = $request->search;
@ -185,4 +187,46 @@ class RangeController extends Controller
{
return $this->create($range->replicate());
}
public function editSubrangesOrder(Range $range)
{
$subranges = $range->subranges()->orderBy('order')->get();
$ranges = Range::query()->get(['id', 'label']);
return view('bo.pages.submodels_order.edit', [
'modelName' => 'range',
'model' => $range,
'models' => $ranges,
'submodels' => $subranges
]);
}
/**
* Updated the order of subranges related to a given range.
*
* @param \App\Http\Requests\Bo\Ranges\UpdateSubmodelsOrderRequest $request
* @param \App\Models\Meat $range
*
* @return \Illuminate\Http\RedirectResponse
*/
public function updateSubrangesOrder(UpdateSubmodelsOrderRequest $request, Range $range): \Illuminate\Http\RedirectResponse
{
$oldList = $range->subranges()->orderBy('order')->get();
$newList = (json_decode($request->get('jsonValue'), true));
return DB::transaction(function () use ($request, $range, $oldList, $newList) {
$i = 0;
foreach ($newList as $newElement) {
$subrangeModel = Subrange::find($newElement['id']);
$subrangeModel->order = $oldList[$i]['order'];
$subrangeModel->saveOrFail();
$i++;
}
return redirect()->route('bo.ranges.edit-subranges-order', $request->range)
->with('success', __('crud.messages.submodels_have_been_reordered', [
'submodelName' => str(trans('models.classes.subrange'))->plural(),
'modelLabel' => $range->label,
]));
});
}
}

View file

@ -7,7 +7,6 @@ use App\Http\Requests\Bo\Submeats\StoreSubmeatRequest;
use App\Http\Requests\Bo\Submeats\UpdateSubmeatRequest;
use App\Models\Meat;
use App\Models\Submeat;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -15,7 +14,6 @@ use Illuminate\Support\Facades\DB;
class SubmeatController extends Controller
{
use UpdateModelPublished;
use ChangesModelOrder;
/**
* Create the controller instance.

View file

@ -7,7 +7,6 @@ use App\Http\Requests\Bo\Subranges\StoreSubrangeRequest;
use App\Http\Requests\Bo\Subranges\UpdateSubrangeRequest;
use App\Models\Range;
use App\Models\Subrange;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -15,7 +14,6 @@ use Illuminate\Support\Facades\DB;
class SubrangeController extends Controller
{
use UpdateModelPublished;
use ChangesModelOrder;
/**
* Create the controller instance.

View file

@ -64,14 +64,20 @@ class StoreMeatRequest extends FormRequest
public function attributes(): array
{
return [
'title' => trans('validation.attributes.title'),
'sustitle' => trans('validation.custom.sustitle'),
'picto' => trans('validation.custom.picto'),
'picto_alt' => trans('validation.custom.alt_attribute'),
'picto_title' => trans('validation.custom.title_attribute'),
'text' => trans('validation.attributes.text'),
'is_large' => trans('validation.custom.is_large'),
'published' => trans('validation.custom.publication')
'label' => trans('validation.custom.label'),
'description' => trans('validation.attributes.description'),
'banner_alt' => trans(':field :inter:field2', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner'),
]),
'banner_title' => trans(':field :inter:field2', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner'),
]),
'color' => trans('validation.custom.color'),
'published' => trans('validation.custom.publication')
];
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Http\Requests\Bo\Meats;
use App\Models\Meat;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use LVR\Colour\Hex;
class UpdateSubmodelsOrderRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return Gate::check('reorderSubmodels', Meat::class);
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'newValues' => json_decode($this->input('jsonValue'), true),
]);
// dd($this->all());
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
$currentMeat = request('meat');
return [
'jsonValue' => 'json',
'newValues' => 'required|array',
'newValues.*' => 'required|array',
'newValues.*.id' => 'required|exists:submeats,id',
'newValues.*.meat_id' => function (string $attribute, mixed $value, \Closure $fail) use ($currentMeat) {
if ($value !== $currentMeat->id) {
$fail("The {$attribute} is invalid.");
}
},
];
}
}

View file

@ -68,14 +68,30 @@ class StoreRangeRequest extends FormRequest
public function attributes(): array
{
return [
'title' => trans('validation.attributes.title'),
'sustitle' => trans('validation.custom.sustitle'),
'picto' => trans('validation.custom.picto'),
'picto_alt' => trans('validation.custom.alt_attribute'),
'picto_title' => trans('validation.custom.title_attribute'),
'text' => trans('validation.attributes.text'),
'is_large' => trans('validation.custom.is_large'),
'published' => trans('validation.custom.publication')
'label' => trans('validation.custom.label'),
'description' => trans('validation.attributes.description'),
'banner_alt' => trans(':field :inter:field2', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner'),
]),
'banner_title' => trans(':field :inter:field2', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner'),
]),
'banner_ambiance_alt' => trans(':field :inter:field2', [
'field' => __('validation.custom.alt_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner_ambiance'),
]),
'banner_ambiance_title' => trans(':field :inter:field2', [
'field' => __('validation.custom.title_attribute'),
'inter' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.banner_ambiance'),
]),
'color' => trans('validation.custom.color'),
'published' => trans('validation.custom.publication')
];
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Http\Requests\Bo\Ranges;
use App\Models\Range;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use LVR\Colour\Hex;
class UpdateSubmodelsOrderRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return Gate::check('reorderSubmodels', Range::class);
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'newValues' => json_decode($this->input('jsonValue'), true),
]);
// dd($this->all());
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
$currentRange = request('range');
return [
'jsonValue' => 'json',
'newValues' => 'required|array',
'newValues.*' => 'required|array',
'newValues.*.id' => 'required|exists:subranges,id',
'newValues.*.range_id' => function (string $attribute, mixed $value, \Closure $fail) use ($currentRange) {
if ($value !== $currentRange->id) {
$fail("The {$attribute} is invalid.");
}
},
];
}
}

View file

@ -57,13 +57,9 @@ class StoreSubmeatRequest extends FormRequest
public function attributes(): array
{
return [
'title' => trans('validation.attributes.title'),
'sustitle' => trans('validation.custom.sustitle'),
'picto' => trans('validation.custom.picto'),
'picto_alt' => trans('validation.custom.alt_attribute'),
'picto_title' => trans('validation.custom.title_attribute'),
'text' => trans('validation.attributes.text'),
'is_large' => trans('validation.custom.is_large'),
'label' => trans('validation.custom.label'),
'description' => trans('validation.attributes.description'),
'meat_id' => trans('models.classes.meat'),
'published' => trans('validation.custom.publication')
];
}

View file

@ -57,13 +57,9 @@ class StoreSubrangeRequest extends FormRequest
public function attributes(): array
{
return [
'title' => trans('validation.attributes.title'),
'sustitle' => trans('validation.custom.sustitle'),
'picto' => trans('validation.custom.picto'),
'picto_alt' => trans('validation.custom.alt_attribute'),
'picto_title' => trans('validation.custom.title_attribute'),
'text' => trans('validation.attributes.text'),
'is_large' => trans('validation.custom.is_large'),
'label' => trans('validation.custom.label'),
'description' => trans('validation.attributes.description'),
'range_id' => trans('models.classes.range'),
'published' => trans('validation.custom.publication')
];
}

View file

@ -117,4 +117,15 @@ class MeatPolicy
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can change the order of the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function reorderSubmodels(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -117,4 +117,15 @@ class RangePolicy
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can change the order of the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function reorderSubmodels(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -2,6 +2,8 @@
namespace App\Providers;
use App\Models\Meat;
use App\Models\Range;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
@ -50,6 +52,24 @@ class ViewServiceProvider extends ServiceProvider
}
return $mainMenu->value;
})());
// * Inject first meat and range : needed for the bo menu.
View::share('firstMeat', (function () {
/** @var \App\Models\Meat|null */
$firstMeat = Meat::query()->first();
if (!$firstMeat) {
return null;
}
return $firstMeat;
})());
View::share('firstRange', (function () {
/** @var \App\Models\Range|null */
$firstRange = Range::query()->first();
if (!$firstRange) {
return null;
}
return $firstRange;
})());
} //end if
}
}

View file

@ -11,12 +11,10 @@ class MeatFactory extends Factory
* Define the model's default state.
*
* @return array<string, mixed>
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function definition()
{
// @phpcs:enable
$label = fake()->sentence();
$label = fake()->sentence();
return [
'label' => $label,
'slug' => Str::slug($label),

View file

@ -0,0 +1,21 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProductFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
$label = fake()->sentence();
return [
'label' => $label,
];
}
}

View file

@ -11,11 +11,9 @@ class RangeFactory extends Factory
* Define the model's default state.
*
* @return array<string, mixed>
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function definition()
{
// @phpcs:enable
$label = fake()->sentence();
return [
'label' => $label,

View file

@ -11,17 +11,15 @@ class SubmeatFactory extends Factory
* Define the model's default state.
*
* @return array<string, mixed>
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function definition()
{
// @phpcs:enable
$label = fake()->sentence();
$label = fake()->sentence();
return [
'label' => $label,
'slug' => Str::slug($label),
'description' => fake()->sentence(),
'published' => fake()->boolean(75),
'label' => $label,
'slug' => Str::slug($label),
'description' => fake()->sentence(),
'published' => fake()->boolean(75),
];
}
}

View file

@ -11,17 +11,15 @@ class SubrangeFactory extends Factory
* Define the model's default state.
*
* @return array<string, mixed>
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function definition()
{
// @phpcs:enable
$label = fake()->sentence();
$label = fake()->sentence();
return [
'label' => $label,
'slug' => Str::slug($label),
'description' => fake()->sentence(),
'published' => fake()->boolean(75),
'label' => $label,
'slug' => Str::slug($label),
'description' => fake()->sentence(),
'published' => fake()->boolean(75),
];
}
}

View file

@ -14,6 +14,7 @@ return new class extends Migration
Schema::create('products', function (Blueprint $table) {
// FIXME: la table a juste été créée pour permettre la relation avec gammes/viandes/...
$table->id();
$table->string('label')->comment('Product label.');
$table->timestamps();
});
}

View file

@ -0,0 +1,66 @@
<?php
namespace Database\Seeders\Development;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Meat;
use App\Models\Product;
use App\Models\Range;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ProductSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Product::factory(25)->create();
$productModels = Product::all();
foreach ($productModels as $productModel) {
$rangeModel = Range::inRandomOrder()->first();
// Morph relationships (Range/Subrange)
DB::table('productables')->insert(
[
'product_id' => $productModel->id,
'productable_id' => $rangeModel->id,
'productable_type' => 'App\Models\Range'
]
);
if (\fake()->boolean(75)) {
DB::table('productables')->insert(
[
'product_id' => $productModel->id,
'productable_id' => $rangeModel->subranges->random()->id,
'productable_type' => 'App\Models\Subrange'
]
);
}
if (\fake()->boolean(75)) {
$meatModel = Meat::inRandomOrder()->first();
// Morph relationships (Meat/Submeat)
DB::table('productables')->insert(
[
'product_id' => $productModel->id,
'productable_id' => $meatModel->id,
'productable_type' => 'App\Models\Meat'
]
);
if (\fake()->boolean(75)) {
DB::table('productables')->insert(
[
'product_id' => $productModel->id,
'productable_id' => $meatModel->submeats->random()->id,
'productable_type' => 'App\Models\Submeat'
]
);
}
}
}
}
}

View file

@ -8,6 +8,7 @@ use Database\Seeders\Development\ProfessionSeeder;
use Database\Seeders\Development\BrandAdvantageSeeder;
use Database\Seeders\Development\MainSlideSeeder;
use Database\Seeders\Development\MeatSeeder;
use Database\Seeders\Development\ProductSeeder;
use Database\Seeders\Development\RangeSeeder;
use Database\Seeders\Development\SubmeatSeeder;
use Database\Seeders\Development\SubrangeSeeder;
@ -34,6 +35,7 @@ class DevelopmentSeeder extends Seeder
SubrangeSeeder::class,
MeatSeeder::class,
SubmeatSeeder::class,
ProductSeeder::class,
]);
}
}

View file

@ -2,15 +2,16 @@
return [
'actions' => [
'list' => 'liste',
'show' => 'voir',
'create' => 'créer',
'update' => 'éditer',
'duplicate' => 'dupliquer',
'delete' => 'supprimer',
'save' => 'sauvegarder',
'edit' => 'mettre à jour',
'view' => 'aperçu',
'list' => 'liste',
'show' => 'voir',
'create' => 'créer',
'update' => 'éditer',
'duplicate' => 'dupliquer',
'delete' => 'supprimer',
'save' => 'sauvegarder',
'edit' => 'mettre à jour',
'view' => 'aperçu',
'order_submodels' => 'ordonner les sous-élements',
],
'helpers' => [
@ -23,6 +24,7 @@ return [
'delete_model' => 'Supprimer :model',
'save_model' => 'Sauvegarder :model',
'edit_model' => 'Mettre à jour :model',
'order_submodels' => 'Modifier l\'ordre des :model',
'no_results' => 'Aucun résultat pour :model',
'publish' => 'Publié',
'unpublish' => 'Dépublié',
@ -43,18 +45,19 @@ return [
],
'messages' => [
'has_been_created' => ':model a été créé',
'cannot_be_created' => ':model ne peut être créé',
'has_been_updated' => ':model a été mis à jour',
'cannot_be_updated' => ':model ne peut être mis à jour',
'has_been_deleted' => ':model a été supprimé',
'cannot_be_deleted' => ':model ne peut être supprimé',
'order_changed' => 'L\'ordre a été changé !',
'order_not_changed' => 'L\'ordre n\'a pas été changé !',
'publish_status_saved' => 'Changement de l\'état de publication réussit !',
'right' => 'Vous n\'avez pas les droits pour accéder à cette partie !',
'theme_updated' => 'Le thème a été mis à jour !',
'user_unpublished' => 'Vous ne pouvez pas désactiver votre propre compte !',
'has_been_created' => ':model a été créé',
'cannot_be_created' => ':model ne peut être créé',
'has_been_updated' => ':model a été mis à jour',
'cannot_be_updated' => ':model ne peut être mis à jour',
'has_been_deleted' => ':model a été supprimé',
'cannot_be_deleted' => ':model ne peut être supprimé',
'order_changed' => 'L\'ordre a été changé !',
'submodels_have_been_reordered' => 'L\'ordre des :submodelName appartenant à :modelLabel a été changé !',
'order_not_changed' => 'L\'ordre n\'a pas été changé !',
'publish_status_saved' => 'Changement de l\'état de publication réussi !',
'right' => 'Vous n\'avez pas les droits pour accéder à cette partie !',
'theme_updated' => 'Le thème a été mis à jour !',
'user_unpublished' => 'Vous ne pouvez pas désactiver votre propre compte !',
],
'minicrud' => [

View file

@ -101,3 +101,7 @@ body {
max-width: 6rem;
max-height: 6rem;
}
.rotate-90 {
transform: rotate(90deg);
}

View file

@ -0,0 +1,76 @@
<template>
<div class="container-fluid reorder-elements-component my-3">
<!-- ORDERABLE NODES -->
<div class="row justify-content-start">
<div class="col my-3">
<fieldset
class="border p-4"
>
<legend>
<span class="fs-5">{{ trans.methods.__('Réorganisez les éléments en les déplaçant.') }}</span>
</legend>
<div class="list-group">
<Draggable
:list="nodeList"
item-key="type"
>
<!-- LIST ITEM -->
<template #item="{ element, index } : {element: LaravelModel, index: number}">
<div class="list-group-item d-flex flux-column justify-content-between">
<span class="h6">
<FontAwesomeIcon
icon="fa-solid fa-align-justify"
class="handle text-secondary"
/>
<span>&nbsp;&nbsp;&nbsp;</span>
<strong>{{ element.label }}</strong>
</span>
</div>
</template>
</Draggable>
</div>
</fieldset>
</div>
<!-- INPUTS FOR SUBMISSION -->
<input
type="hidden"
name="jsonValue"
:value="JSON.stringify(nodeList)"
>
</div>
</div>
</template>
<script lang="ts" setup>
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { defineOptions, onMounted, ref, useAttrs } from "vue";
import Draggable from "vuedraggable";
import trans from "../../modules/trans";
defineOptions({
name: "ReorderElements",
inheritAttrs: true,
});
// * ATTRIBUTES
const attrs = useAttrs();
// * DATA
const nodeList = ref<Array<LaravelModelList>>([]);
// * LIFECYCLE
onMounted(() => {
const json = String(attrs.json ?? "{}"),
data = JSON.parse(json);
nodeList.value = data.nodeList ?? [];
});
</script>
<style lang="scss" scoped>
.reorder-elements-component {
.handle {
cursor: grab;
}
}
</style>

View file

@ -7,6 +7,7 @@ import {
faArrowLeft,
faArrowLeftLong,
faArrowRight,
faArrowRightArrowLeft,
faArrowRightFromBracket,
faArrowUp,
faArrowUpRightFromSquare,
@ -101,5 +102,6 @@ library.add(faThumbsUp);
library.add(faPanorama);
library.add(faAlignJustify);
library.add(faTag);
library.add(faArrowRightArrowLeft);
dom.watch();

View file

@ -85,6 +85,13 @@
<a class="dropdown-item"
href="{{ route('bo.subranges.index') }}">{{ str(__('models.classes.subrange'))->ucfirst()->plural() }}</a>
</li>
@if ($firstRange && $firstRange->subranges->count() >= 2)
<li>
<a class="dropdown-item" href="{{ route('bo.ranges.edit-subranges-order', $firstRange) }}">
{{ __('crud.helpers.order_submodels', ['model' => str(__('models.classes.subrange'))->plural()]) }}
</a>
</li>
@endif
<li>
<a class="dropdown-item"
href="{{ route('bo.meats.index') }}">{{ str(__('models.classes.meat'))->ucfirst()->plural() }}</a>
@ -93,6 +100,13 @@
<a class="dropdown-item"
href="{{ route('bo.submeats.index') }}">{{ str(__('models.classes.submeat'))->ucfirst()->plural() }}</a>
</li>
@if ($firstMeat && $firstMeat->submeats->count() >= 2)
<li>
<a class="dropdown-item" href="{{ route('bo.meats.edit-submeats-order', $firstMeat) }}">
{{ __('crud.helpers.order_submodels', ['model' => str(__('models.classes.submeat'))->plural()]) }}
</a>
</li>
@endif
</ul>
</div>
</div>

View file

@ -17,7 +17,7 @@
@foreach ($meatModels as $meatModel)
<tr class="border-bottom">
<td class="text-center align-middle">{{ $meatModel->label }}</td>
<td class="text-center align-middle">{{ $meatModel->description }}</td>
<td class="text-center align-middle">{{ str(strip_tags($meatModel->description))->limit(50, '...') }}</td>
<td class="text-center align-middle"><input type="color" value="{{ $meatModel->color }}" disabled></td>
@php
$routeName = request()->route()->getName();
@ -47,6 +47,15 @@
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@if ($meatModel->submeats->count() >= 2)
@can('reorderSubmodels', $meatModel)
<a class="btn btn-sm btn-info" data-bs-toggle="tooltip"
href="{{ route('bo.meats.edit-submeats-order', $meatModel) }}"
title="{{ str(__('crud.actions.order_submodels'))->ucfirst() }}">
<i class="fa-solid fa-solid fa-arrow-right-arrow-left rotate-90"></i>
</a>
@endcan
@endif
@can('duplicate', $meatModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.meats.duplicate', ['meat' => $meatModel]) }}"

View file

@ -17,7 +17,7 @@
@foreach ($rangeModels as $rangeModel)
<tr class="border-bottom">
<td class="text-center align-middle">{{ $rangeModel->label }}</td>
<td class="text-center align-middle">{{ $rangeModel->description }}</td>
<td class="text-center align-middle">{{ str(strip_tags($rangeModel->description))->limit(50, '...') }}</td>
<td class="text-center align-middle"><input type="color" value="{{ $rangeModel->color }}" disabled></td>
@php
$routeName = request()->route()->getName();
@ -47,6 +47,15 @@
<i class="fa-solid fa-eye"></i>
</a>
@endcan
@if ($rangeModel->subranges->count() >= 2)
@can('reorderSubmodels', $rangeModel)
<a class="btn btn-sm btn-info" data-bs-toggle="tooltip"
href="{{ route('bo.ranges.edit-subranges-order', $rangeModel) }}"
title="{{ str(__('crud.actions.order_submodels'))->ucfirst() }}">
<i class="fa-solid fa-solid fa-arrow-right-arrow-left rotate-90"></i>
</a>
@endcan
@endif
@can('duplicate', $rangeModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.ranges.duplicate', ['range' => $rangeModel]) }}"

View file

@ -6,7 +6,6 @@
'label' => str(__('validation.custom.label'))->ucfirst(),
'description' => str(__('validation.attributes.description'))->ucfirst(),
'meat_id' => str(__('models.classes.meat'))->ucfirst(),
'order' => str(__('validation.custom.order'))->ucfirst(),
'published' => str(__('validation.custom.activated'))->ucfirst(),
'updated_at' => str(__('validation.attributes.updated_at'))->ucfirst(),
],
@ -24,16 +23,6 @@
{{ $submeatModel->meat->label }}
</a>
</td>
@php
$routeName = request()->route()->getName();
@endphp
@if (empty(request()->search) && session()->get("$routeName.sort_col") === 'order')
@include('bo.modules.change-model-order', [
'routeName' => 'submeats',
'model' => $submeatModel,
'models' => $submeatModels,
])
@endif
@include('bo.modules.change-published-status', [
'routeName' => 'submeats',
'model' => $submeatModel,

View file

@ -0,0 +1,63 @@
@extends('bo.layout', ['brParam' => $model])
@section('title', __('crud.helpers.order_submodels', ['model' => str(__("models.classes.sub{$modelName}"))->plural()]))
@section('description', __('crud.helpers.order_submodels', ['model' => str(__("models.classes.sub{$modelName}"))->plural()]))
@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.{$modelName}s.index") }}'
title="{{ __('crud.helpers.list_all', ['model' => str(__("models.classes.{$modelName}"))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $model])
</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' => str(__("models.classes.sub{$modelName}"))->plural()]) }}">
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
</div>
</div>
<form action='{{ route("bo.{$modelName}s.update-sub{$modelName}s-order", $model) }}' method="POST" enctype="multipart/form-data">
@csrf
@method('PATCH')
<div class="container-fluid mt-3">
<div class="d-flex justify-content-between align-items-center">
<span
class="h5">{{ sprintf('%s associé(e)s à : %s',str(__("models.classes.sub{$modelName}"))->ucfirst()->plural(),$model->label) }}</span>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button" aria-expanded="false">
{{ __('Sélectionnez l\'élément parent') }}
</button>
<ul class="dropdown-menu">
@foreach ($models as $parentModel)
<li>
<a href="{{ route("bo.{$modelName}s.edit-sub{$modelName}s-order", $parentModel) }}"
title="{{ sprintf('%s de l\'élément parent : %s', __('crud.helpers.order_submodels', ['model' => __("models.classes.sub{$modelName}")]), $model->label) }}"
@class([
'dropdown-item',
'active' => request($modelName)->is($parentModel),
])>
{{ $parentModel->label }}
</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
@include('bo.pages.submodels_order.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.sub{$modelName}")]) }}'>
{{ str(__('crud.actions.save'))->ucfirst() }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,8 @@
<div class="row">
@php
$json = [
'nodeList' => $submodels,
];
@endphp
<div class="reorder-elements" data-json='@json($json)'></div>
</div>

View file

@ -6,7 +6,6 @@
'label' => str(__('validation.custom.label'))->ucfirst(),
'description' => str(__('validation.attributes.description'))->ucfirst(),
'range_id' => str(__('models.classes.range'))->ucfirst(),
'order' => str(__('validation.custom.order'))->ucfirst(),
'published' => str(__('validation.custom.activated'))->ucfirst(),
'updated_at' => str(__('validation.attributes.updated_at'))->ucfirst(),
],
@ -24,16 +23,6 @@
{{ $subrangeModel->range->label }}
</a>
</td>
@php
$routeName = request()->route()->getName();
@endphp
@if (empty(request()->search) && session()->get("$routeName.sort_col") === 'order')
@include('bo.modules.change-model-order', [
'routeName' => 'subranges',
'model' => $subrangeModel,
'models' => $subrangeModels,
])
@endif
@include('bo.modules.change-published-status', [
'routeName' => 'subranges',
'model' => $subrangeModel,

View file

@ -226,6 +226,10 @@ Breadcrumbs::for('bo.ranges.duplicate', function (Generator $trail) {
$trail->parent('bo.ranges.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});
Breadcrumbs::for('bo.ranges.edit-subranges-order', function (Generator $trail) {
$trail->parent('bo.ranges.index');
$trail->push(Str::ucfirst(trans('crud.helpers.order_submodels', ['model' => Str::plural(trans('models.classes.subrange'))])));
});
// * SUBRANGES
Breadcrumbs::for('bo.subranges.index', function (Generator $trail) {
@ -274,6 +278,10 @@ Breadcrumbs::for('bo.meats.duplicate', function (Generator $trail) {
$trail->parent('bo.meats.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});
Breadcrumbs::for('bo.meats.edit-submeats-order', function (Generator $trail) {
$trail->parent('bo.meats.index');
$trail->push(Str::ucfirst(trans('crud.helpers.order_submodels', ['model' => Str::plural(trans('models.classes.submeat'))])));
});
// * SUBMEATS
Breadcrumbs::for('bo.submeats.index', function (Generator $trail) {

View file

@ -145,14 +145,18 @@ Route::prefix('bo')
Route::get('/ranges/{range}/duplicate', [
RangeController::class, 'duplicate'
])->name('ranges.duplicate');
// Change order of ranges.
Route::get('/ranges/{range}/change-subranges-order', [
RangeController::class, 'editSubrangesOrder'
])->name('ranges.edit-subranges-order');
Route::patch('/ranges/{range}/update-subranges-order', [
RangeController::class, 'updateSubrangesOrder'
])->name('ranges.update-subranges-order');
// * SUBRANGES.
Route::resource('subranges', SubrangeController::class)
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:description');
Route::patch('/subranges/{subrange}/change-order/{direction}', [
SubrangeController::class, 'changeOrder'
])->where('direction', 'up|down')->name('subranges.change-order');
Route::patch('/subranges/{subrange}/change-published', [
SubrangeController::class, 'changePublished'
])->name('subranges.change-published');
@ -173,14 +177,18 @@ Route::prefix('bo')
Route::get('/meats/{meat}/duplicate', [
MeatController::class, 'duplicate'
])->name('meats.duplicate');
// Change order of submodels.
Route::get('/meats/{meat}/change-submeats-order', [
MeatController::class, 'editSubmeatsOrder'
])->name('meats.edit-submeats-order');
Route::patch('/meats/{meat}/update-submeats-order', [
MeatController::class, 'updateSubmeatsOrder'
])->name('meats.update-submeats-order');
// * SUBMEATS.
Route::resource('submeats', SubmeatController::class)
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:description');
Route::patch('/submeats/{submeat}/change-order/{direction}', [
SubmeatController::class, 'changeOrder'
])->where('direction', 'up|down')->name('submeats.change-order');
Route::patch('/submeats/{submeat}/change-published', [
SubmeatController::class, 'changePublished'
])->name('submeats.change-published');