Merge branch '70-network-pages' into 'develop'

feat: Added network part in 'produce' page + networks, aisles and brands models

See merge request ldc-web/projets/volena!50
This commit is contained in:
noah.lancien 2026-01-22 10:11:52 +00:00
commit 2e23543a0d
53 changed files with 3315 additions and 6 deletions

View file

@ -38,6 +38,7 @@ enum PageSectionEnum: int
case produce_quality = 28;
case produce_linking = 29;
case listening_study = 30;
case produce_networks = 31;
/**
* Optionnal labels definition.
@ -75,6 +76,7 @@ enum PageSectionEnum: int
self::produce_quality->name => 'Qualité',
self::produce_linking->name => 'Liens',
self::listening_study->name => 'On étudie',
self::produce_networks->name => 'Nos réseaux',
];
/**
@ -114,7 +116,8 @@ enum PageSectionEnum: int
self::produce_rhd,
self::produce_export,
self::produce_quality,
self::listening_study => false,
self::listening_study,
self::produce_networks => false,
}; //end match
}
@ -155,7 +158,8 @@ enum PageSectionEnum: int
self::produce_quality,
self::listening_study => \App\Enums\CkEditorConfigName::advanced->label(),
self::produce_linking,
self::hire_grow, => null,
self::hire_grow,
self::produce_networks => null,
}; //end match
}
}

View file

@ -0,0 +1,177 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Aisles\StoreAisleRequest;
use App\Http\Requests\Bo\Aisles\UpdateAisleRequest;
use App\Models\Logo;
use App\Models\Aisle;
use App\Models\Network;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class AisleController extends Controller
{
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Aisle::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 $aisleModels */
$aisleModels = Aisle::query()->with('network');
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$aisleModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($aisleModels);
/** Custom pagination */
$aisleModels = $this->paginate($aisleModels);
return view('bo.pages.aisles.index', compact('aisleModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function create(Aisle $aisle): \Illuminate\Contracts\View\View
{
$networkModels = Network::all();
return view('bo.pages.aisles.create', [
'aisleModel' => $aisle,
'networkModels' => $networkModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Aisles\StoreAisleRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreAisleRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$aisle = new Aisle();
$aisle->fill($request->validated());
if ($aisle->saveOrFail()) {
return redirect()->route('bo.aisles.edit', $aisle)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function edit(Aisle $aisle): \Illuminate\Contracts\View\View
{
$networkModels = Network::all();
return view('bo.pages.aisles.edit', [
'aisleModel' => $aisle,
'networkModels' => $networkModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Aisles\UpdateAisleRequest $request
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateAisleRequest $request, Aisle $aisle): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $aisle) {
$aisle->fill($request->validated());
if ($aisle->saveOrFail()) {
return redirect()->route('bo.aisles.edit', $aisle)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->route('bo.aisles.edit', $aisle)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Aisle $aisle): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($aisle) {
if ($aisle->deleteOrFail()) {
return redirect()->route('bo.aisles.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.aisle'))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Aisle $aisle
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Aisle $aisle): \Illuminate\Contracts\View\View
{
return $this->create($aisle->replicate());
}
}

View file

@ -0,0 +1,177 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
use App\Models\Aisle;
use App\Models\Brand;
use App\Models\Network;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class BrandController extends Controller
{
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Brand::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 $brandModels */
$brandModels = Brand::query()->with('aisle');
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$brandModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($brandModels);
/** Custom pagination */
$brandModels = $this->paginate($brandModels);
return view('bo.pages.brands.index', compact('brandModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function create(Brand $brand): \Illuminate\Contracts\View\View
{
$aisleModels = Aisle::all();
return view('bo.pages.brands.create', [
'brandModel' => $brand,
'aisleModels' => $aisleModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\StoreBrandRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreBrandRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$brand = new Brand();
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()->route('bo.brands.edit', $brand)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function edit(Brand $brand): \Illuminate\Contracts\View\View
{
$aisleModels = Aisle::all();
return view('bo.pages.brands.edit', [
'brandModel' => $brand,
'aisleModels' => $aisleModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\UpdateBrandRequest $request
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateBrandRequest $request, Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $brand) {
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()->route('bo.brands.edit', $brand)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->route('bo.brands.edit', $brand)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Brand $brand): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($brand) {
if ($brand->deleteOrFail()) {
return redirect()->route('bo.brands.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans('models.classes.brand'))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Brand $brand): \Illuminate\Contracts\View\View
{
return $this->create($brand->replicate());
}
}

View file

@ -0,0 +1,171 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Networks\StoreNetworkRequest;
use App\Http\Requests\Bo\Networks\UpdateNetworkRequest;
use App\Models\Network;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class NetworkController extends Controller
{
use ChangesModelOrder;
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Network::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 $networkModels */
$networkModels = Network::query();
/** @var string $search Search field */
$search = $request->input('search');
if ($search) {
$this->searchQuery(
$networkModels,
$search,
null,
'name',
);
}
$searchFields = \implode(', ', [
Str::ucfirst(trans('validation.attributes.name')),
]);
/** Sort columns with a query */
$this->sortQuery($networkModels);
/** Custom pagination */
$networkModels = $this->paginate($networkModels);
return view('bo.pages.networks.index', compact('networkModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function create(Network $network): \Illuminate\Contracts\View\View
{
return view('bo.pages.networks.create', [
'networkModel' => $network,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Networks\StoreNetworkRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreNetworkRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$network = new Network();
$network->fill($request->validated());
if ($network->saveOrFail()) {
return redirect()->route('bo.networks.edit', $network)
->with('success', trans('crud.messages.has_been_created', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function edit(Network $network): \Illuminate\Contracts\View\View
{
return view('bo.pages.networks.edit', [
'networkModel' => $network,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Networks\UpdateNetworkRequest $request
* @param \App\Models\Network $network
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateNetworkRequest $request, Network $network): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $network) {
$network->fill($request->validated());
if ($network->saveOrFail()) {
return redirect()->route('bo.networks.edit', $network)
->with('success', trans('crud.messages.has_been_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->route('bo.networks.edit', $network)
->with('error', trans('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Network $network
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Network $network): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($network) {
if ($network->deleteOrFail()) {
return redirect()->route('bo.networks.index')
->with('success', trans('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
}
return redirect()->back()
->with('error', trans('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(trans_choice('models.classes.network', 1))
]));
});
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\Network $network
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(Network $network): \Illuminate\Contracts\View\View
{
return $this->create($network->replicate());
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\Network;
class NetworkController extends Controller
{
/**
* Display the specified resource.
*/
public function show(Network $network)
{
$network->load(['aisles', 'aisles.brands']);
$networkModels = Network::query()
->whereNot('id', $network->id)
->where('published', true)
->orderBy('order')
->get();
return view('fo.pages.networks.show', [
'networkModel' => $network,
'networkModels' => $networkModels,
]);
}
}

View file

@ -13,6 +13,7 @@ use App\Mail\SendConfirmationMail;
use App\Mail\SendContactMail;
use App\Models\HistoricalMilestone;
use App\Models\JobVideo;
use App\Models\Network;
use App\Models\News;
use App\Models\Section;
use App\Models\Site;
@ -196,21 +197,28 @@ class StaticPageController extends Controller
*/
public function produce(): \Illuminate\Contracts\View\View
{
// MODELS
$staticPageModel = StaticPage::query()->where('type', StaticPageType::we_produce)->first();
$sectionModels = Section::query()->where('page_id', $staticPageModel->id)->get();
$networkModels = Network::query()->where('published', true)->orderBy('order')->get();
// SECTIONS
$localSection = $sectionModels->where('section', PageSectionEnum::produce_local)->first();
$gmsSection = $sectionModels->where('section', PageSectionEnum::produce_gms)->first();
$rhdSection = $sectionModels->where('section', PageSectionEnum::produce_rhd)->first();
$exportSection = $sectionModels->where('section', PageSectionEnum::produce_export)->first();
$qualitySection = $sectionModels->where('section', PageSectionEnum::produce_quality)->first();
$networkSection = $sectionModels->where('section', PageSectionEnum::produce_networks)->first();
return view('fo.pages.produce.show', compact(
'staticPageModel',
'networkModels',
'localSection',
'gmsSection',
'rhdSection',
'exportSection',
'qualitySection'
'qualitySection',
'networkSection',
));
}

View file

@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests\Bo\Aisles;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreAisleRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'name' => 'required|string|between:3,255',
'title' => 'required|string|between:3,255',
'text' => [
'required',
'string',
new WysiwygLength(3, 500),
],
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'network_id' => 'required|exists:networks,id',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 1400, 450, 1400, 450, false),
);
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests\Bo\Aisles;
class UpdateAisleRequest extends StoreAisleRequest
{
}

View file

@ -0,0 +1,61 @@
<?php
namespace App\Http\Requests\Bo\Brands;
use App\Rules\WysiwygLength;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreBrandRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'name' => 'required|string|between:3,255',
'text' => [
'required',
'string',
new WysiwygLength(3, 255),
],
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'link' => 'nullable|url:https',
'aisle_id' => 'required|exists:aisles,id',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 250, 250, 250, 250, false),
);
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests\Bo\Brands;
class UpdateBrandRequest extends StoreBrandRequest
{
}

View file

@ -0,0 +1,58 @@
<?php
namespace App\Http\Requests\Bo\Networks;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreNetworkRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->merge([
'published' => $this->boolean('published')
]);
$this->mergePicture('picture');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$rules = [
'seo_title' => 'required|string|between:45,70',
'seo_description' => 'required|string|between:50,160',
'name' => 'required|string|between:3,255',
'title' => 'required|string|between:3,255',
'subtitle' => 'required|string|between:3,255',
'picture_alt' => 'required|string|between:3,255',
'picture_title' => 'required|string|between:3,255',
'published' => 'required|boolean',
];
return \array_merge(
$rules,
$this->pictureRules('picture', 1920, 1080, 1920, 1080, false),
);
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests\Bo\Networks;
class UpdateNetworkRequest extends StoreNetworkRequest
{
}

123
app/Models/Aisle.php Normal file
View file

@ -0,0 +1,123 @@
<?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;
use Illuminate\Validation\ValidationException;
class Aisle extends Model
{
use ActivityLog;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'title',
'text',
'picture',
'picture_alt',
'picture_title',
'published',
'network_id',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'boolean',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
});
}
// * METHODS
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS
self::assertLimitPublishedModels($model);
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @return void
*/
private static function assertLimitPublishedModels(self $model, $isDeletion = false)
{
$count = self::query()->where('published', true)->where('network_id', $model->network_id)->count();
if (
(!$model->published && $count <= 1) ||
($model->published && $count >= 4) ||
($isDeletion && $count === 1)
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 4 éléments attachés à chaque réseau.'
]);
}
}
// * RELATIONS
/**
* The network that belongs to the logo.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function network(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Network::class);
}
/**
* Associated brands.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function brands(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Brand::class);
}
}

115
app/Models/Brand.php Normal file
View file

@ -0,0 +1,115 @@
<?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;
use Illuminate\Validation\ValidationException;
class Brand extends Model
{
use ActivityLog;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'text',
'picture',
'picture_alt',
'picture_title',
'link',
'published',
'aisle_id'
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'bool',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
});
}
// * METHODS
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS
self::assertLimitPublishedModels($model);
// * TRANSFORMATIONS
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @return void
*/
private static function assertLimitPublishedModels(self $model, $isDeletion = false)
{
$count = self::query()->where('published', true)->count();
if (
!$count === 0 &&
((!$model->published && $count <= 1) ||
($model->published && $count >= 5) ||
($isDeletion && $count === 1))
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 5 éléments publiés simultanément.'
]);
}
}
// * RELATIONS
/**
* Associated aisle.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function aisle(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Aisle::class);
}
}

161
app/Models/Network.php Normal file
View file

@ -0,0 +1,161 @@
<?php
namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class Network extends Model
{
use ActivityLog;
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'seo_title',
'seo_description',
'name',
'slug',
'title',
'subtitle',
'picture',
'picture_alt',
'picture_title',
'order',
'published',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'published' => 'bool',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::setOrder($model);
self::manageFields($model);
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
FileStorageHelper::removeOldFile($model, 'picture');
});
static::deleting(function (self $model) {
self::assertLimitPublishedModels($model, true);
});
static::deleted(function (self $model) {
FileStorageHelper::removeFile($model, 'picture');
});
}
// * METHODS
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// * ASSERTIONS
self::assertLimitPublishedModels($model);
self::assertFieldIsUnique('name', $model->name, $model->id);
self::assertFieldIsUnique('slug', Str::slug($model->name), $model->id);
// * TRANSFORMATIONS
self::setSlug($model, $model->name);
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
/**
* Set the slug.
*
* @param self $model
* @param string $original
*
* @return void
*/
private static function setSlug(self $model, string $original): void
{
$model->slug = Str::slug($original);
}
/**
* 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;
}
/**
* Asserts using validation that the field is unique.
*
* @param string $nameField
* @param string $valueField
* @param integer|null $id
* @return void
*/
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null): void
{
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
}
/**
* Check if the limit of published models is reached.
*
* @param self $model
* @param boolean $isDeletion
* @return void
*/
private static function assertLimitPublishedModels(self $model, $isDeletion = false)
{
$count = self::query()->where('published', true)->count();
if (
(!$model->published && $count <= 1) ||
($model->published && $count >= 5) ||
($isDeletion && $count === 1)
) {
throw ValidationException::withMessages([
'Il doit y avoir entre 1 et 5 éléments publiés simultanément.'
]);
}
}
// * RELATIONS
/**
* The aisles that belong to the logo.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function aisles(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Aisle::class);
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace App\Policies;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use App\Policies\Rules\UserStaticRules;
class AislePolicy
{
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function viewAny(User $authUser): bool
{
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 create models.
*
* @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 restore the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function restore(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function forceDelete(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);
}
/**
* Determine whether the user can change the order of the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function changeOrder(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace App\Policies;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use App\Policies\Rules\UserStaticRules;
class BrandPolicy
{
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function viewAny(User $authUser): bool
{
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 create models.
*
* @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 restore the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function restore(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function forceDelete(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);
}
/**
* Determine whether the user can change the order of the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function changeOrder(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace App\Policies;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use App\Policies\Rules\UserStaticRules;
class NetworkPolicy
{
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function viewAny(User $authUser): bool
{
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 create models.
*
* @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 restore the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function restore(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function forceDelete(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);
}
/**
* Determine whether the user can change the order of the model.
*
* @param \App\Models\User $authUser
* @return boolean
*/
public function changeOrder(User $authUser): bool
{
return UserStaticRules::atLeastRole($authUser, RoleEnum::admin);
}
}

View file

@ -3,6 +3,9 @@
namespace App\Providers;
use App\Http\Middleware\VerifyCsrfToken;
use App\Models\Aisle;
use App\Models\Brand;
use App\Models\Network;
use App\Models\News;
use App\Models\Strip;
use App\Models\User;
@ -47,11 +50,19 @@ class RouteServiceProvider extends ServiceProvider
Route::model('user', User::class);
Route::model('strip', Strip::class);
Route::model('news', News::class);
Route::model('network', Network::class);
Route::model('aisle', Aisle::class);
Route::model('brand', Brand::class);
Route::bind('publishedNews', function ($value) {
return News::where(function ($q) use ($value) {
$q->where('slug', $value);
})->where('published', true)->firstOrFail();
});
Route::bind('publishedNetwork', function ($value) {
return Network::where(function ($q) use ($value) {
$q->where('slug', $value);
})->where('published', true)->firstOrFail();
});
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,70 @@
<?php
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Network;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('networks', function (Blueprint $table) {
$table->id();
$table->string('seo_title')->comment('SeoTitle of the network');
$table->string('seo_description')->comment('SeoDescription of the network');
$table->string('name')->comment('Name of the network');
$table->string('slug')->comment('Slug of the network');
$table->string('title')->comment('Title of the network page');
$table->string('subtitle')->comment('Subtitle of the network page');
$table->string('picture')->comment('Picture of the network');
$table->string('picture_alt')->comment('Alt attribute of the picture');
$table->string('picture_title')->comment('Title attribute of the picture');
$table->integer('order')->unique()->comment('Position of the networks');
$table->boolean('published')->comment('Is the network published ?');
$table->timestamps();
});
$this->createNetwork('RHD');
$this->createNetwork('GMS');
$this->createNetwork('Export');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('networks');
}
/**
* Create fake network
*
* @param string $name
* @return void
*/
private function createNetwork(string $name)
{
$network = new Network();
$network->seo_title = sprintf('Notre réseau %s', $name);
$network->seo_description = sprintf('Découvrez en plus sur notre réseau %s', $name);
$network->name = $name;
$network->title = 'Lorem ipsum dolor sit amet';
$network->subtitle = sprintf('Notre réseau %s', $name);
$network->picture = FileStorageHelper::storeFile(
new Network(),
new \SplFileInfo(\resource_path(
'../database/factories/assets/1920x1080.png'
))
);
$network->picture_alt = 'Default picture';
$network->picture_title = 'Default picture';
$network->published = true;
$network->saveOrFail();
}
};

View file

@ -0,0 +1,39 @@
<?php
use App\Enums\Sections\PageSectionEnum;
use App\Enums\StaticPageType;
use App\Models\Section;
use App\Models\StaticPage;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$networkSection = Section::query()->where('section', PageSectionEnum::produce_networks)->firstOrNew(
[
'section' => PageSectionEnum::produce_networks,
],
[
'h2_title' => 'Retrouvez-nous dans nos réseaux',
'text' => '',
'data' => [],
'page_id' => StaticPage::query()->where('type', StaticPageType::we_produce)->firstOrFail()->id
]
);
$networkSection->saveQuietly();
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Section::query()->where('section', PageSectionEnum::produce_networks)->delete();
}
};

View file

@ -0,0 +1,56 @@
<?php
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Aisle;
use App\Models\Network;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('aisles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('title');
$table->text('text');
$table->string('picture');
$table->string('picture_alt');
$table->string('picture_title');
$table->foreignId('network_id')->constrained();
$table->boolean('published')->comment('Is the aisle published ?');
$table->timestamps();
});
Network::query()->each(function ($network) {
$aisle = new Aisle();
$aisle->name = 'Rayon 1';
$aisle->title = 'Nous sommes présent au rayon 1';
$aisle->text = 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis minima minus maiores delectus nesciunt eveniet voluptatum, saepe veniam beatae, tempora voluptate quidem unde odio dolores ut distinctio ea vero cumque?';
$aisle->picture = FileStorageHelper::storeFile(
new Aisle(),
new \SplFileInfo(\resource_path(
'../database/factories/assets/1400x450.png'
))
);
$aisle->picture_alt = 'Image décorative pour le rayon 1';
$aisle->picture_title = 'Image décorative pour le rayon 1';
$aisle->published = true;
$aisle->network()->associate($network);
$aisle->saveOrFail();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('aisles');
}
};

View file

@ -0,0 +1,70 @@
<?php
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Aisle;
use App\Models\Brand;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('brands', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('text');
$table->string('picture');
$table->string('picture_alt');
$table->string('picture_title');
$table->string('link')->nullable();
$table->foreignId('aisle_id')->constrained();
$table->boolean('published')->comment('Is the brand published ?');
$table->timestamps();
});
Aisle::query()->each(function ($aisle) {
for ($i = 0; $i < 5; $i++) {
$this->createBrand($aisle, $i);
}
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('brands');
}
/**
* Create fake brand
*
* @param Aisle $aisle
* @param int $number
* @return void
*/
private function createBrand(Aisle $aisle, int $number)
{
$brand = new Brand();
$brand->name = sprintf('Marque %d', $number);
$brand->text = 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis minima minus maiores delectus nesciunt eveniet voluptatum, saepe veniam beatae, tempora voluptate quidem unde odio dolores ut distinctio ea vero cumque?';
$brand->picture = FileStorageHelper::storeFile(
new Aisle(),
new \SplFileInfo(\resource_path(
'../database/factories/assets/250x250.png'
))
);
$brand->picture_alt = 'Image décorative pour la marque';
$brand->picture_title = 'Image décorative pour la marque';
$brand->link = 'https://www.example.com';
$brand->published = true;
$brand->aisle()->associate($aisle);
$brand->saveOrFail();
}
};

View file

@ -10,7 +10,7 @@ data:
APP_DEBUG: "${APP_APP_DEBUG}"
APP_URL: "https://${REDIRECT}${APP_DOMAIN}"
LOG_CHANNEL: "k8s"
DB_HOST: "mariadb.common-services"
DB_HOST: "${APP_DB_HOST}"
DB_DATABASE: "${APP_DB_DATABASE}"
DB_USERNAME: "${APP_DB_USERNAME}"
DB_PASSWORD: "${APP_DB_PASSWORD}"
@ -132,6 +132,8 @@ metadata:
name: ${CI_PROJECT_PATH_SLUG}-cronjob
spec:
schedule: "* * * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
concurrencyPolicy: Forbid
jobTemplate:
spec:

View file

@ -14,5 +14,8 @@ return [
'job_video' => 'vidéo métier|vidéos métiers',
'strip' => 'bandeau d\'information|bandeaux d\'information',
'testimonial' => 'témoignage',
'network' => 'réseau|réseaux',
'aisle' => 'rayon',
'brand' => 'marque',
]
];

View file

@ -295,5 +295,6 @@ return [
'object' => 'objet',
'message' => 'message',
'banner' => 'bannière',
'subtitle' => 'sous-titre',
],
];

View file

@ -322,6 +322,30 @@ document.addEventListener("DOMContentLoaded", function () {
},
},
},
"swiper-networks": {
modules: [Pagination, Navigation],
grabCursor: true,
slidesPerView: 1.1,
spaceBetween: 15,
centeredSlides: true,
speed: 750,
pagination: {
el: ".swiper-networks-pagination",
clickable: true,
renderBullet: function (index: number, className: string) {
return "<button class=\"btn btn-tertiary rounded-0 border-0 w-100 mx-2 p-0 " + className + "\" title=\"Aller à la slide " + (index + 1) + "\"></button>";
},
},
navigation: {
nextEl: ".swiper-networks-button-next",
prevEl: ".swiper-networks-button-prev",
},
breakpoints: {
576: {
slidesPerView: 1.3,
},
},
},
};
const swiperVol = document.getElementsByClassName("swiper") as HTMLCollectionOf<HTMLElement>;

View file

@ -248,7 +248,15 @@
{{-- WE PRODUCE --}}
<li class="nav-item">
<div class="dropdown">
<a class="nav-link @if (url()->current() === route('bo.static_pages.edit', $produceStaticPageModel->type->value()) || $isActiveProduce) active @endif dropdown-toggle" data-bs-toggle="dropdown" type="button"
<a class="nav-link @if (
url()->current() === route('bo.static_pages.edit', $produceStaticPageModel->type->value()) ||
$isActiveProduce ||
request()->routeIs('bo.networks.*') ||
request()->routeIs('bo.aisles.*') ||
request()->routeIs('bo.brands.*')
) active @endif dropdown-toggle"
data-bs-toggle="dropdown"
type="button"
aria-expanded="false">
{{ $produceStaticPageModel->type->label() }}
</a>
@ -273,6 +281,33 @@
</li>
@endforeach
@endcan
@can('viewAny', \App\Models\Network::class)
<li class="nav-item">
<a class="nav-link @if (request()->routeIs('bo.networks.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.networks.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.network', \INF)]) }}">
{{ Str::of(trans_choice('models.classes.network', \INF))->ucfirst() }}
</a>
</li>
@endcan
@can('viewAny', \App\Models\Aisle::class)
<li class="nav-item">
<a class="nav-link @if (request()->routeIs('bo.aisles.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.aisles.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.aisle'))->plural()]) }}">
{{ str(__('models.classes.aisle'))->plural()->ucfirst() }}
</a>
</li>
@endcan
@can('viewAny', \App\Models\Brand::class)
<li class="nav-item">
<a class="nav-link @if (request()->routeIs('bo.brands.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.brands.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.brand'))->plural()]) }}">
{{ str(__('models.classes.brand'))->plural()->ucfirst() }}
</a>
</li>
@endcan
</ol>
</div>
</li>

View file

@ -0,0 +1,36 @@
@extends('bo.layout', ['brParam' => $aisleModel])
@section('title', __('Création d\'un :model', ['model' => trans_choice('models.classes.aisle', 1)]))
@section('description', __('Création d\'un tout nouveau :model', ['model' => trans_choice('models.classes.aisle', 1)]))
@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.aisles.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.aisle', 1)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $aisleModel])
</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' => trans_choice('models.classes.aisle', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
<form action="{{ route('bo.aisles.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.aisles.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' => trans_choice('models.classes.aisle', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,52 @@
@extends('bo.layout', ['brParam' => $aisleModel])
@section('title', __('Édition d\'un :model', ['model' => trans_choice('models.classes.aisle', 1)]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => trans_choice('models.classes.aisle', 1)]))
@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.aisles.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.aisle', '*')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $aisleModel])
</div>
<div class="mb-md-0 mb-2">
<form class="btn-group confirmDeleteTS" action="{{ route('bo.aisles.destroy', $aisleModel) }}" method="POST" novalidate>
@can('duplicate', $aisleModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip" href="{{ route('bo.aisles.duplicate', ['aisle' => $aisleModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<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' => trans_choice('models.classes.aisle', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
@can('delete', $aisleModel)
@csrf
@method('DELETE')
<button class="btn btn-danger" data-bs-toggle="tooltip" type="submit" title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
</div>
</div>
<form action="{{ route('bo.aisles.update', $aisleModel) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.aisles.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' => trans_choice('models.classes.aisle', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,208 @@
<div class="row">
{{-- NAME --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.name')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'aisleName',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.name')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $aisleModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.name'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un nom clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- TITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.title')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'aisleTitle',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'hasWordCounter' => true,
'name' => 'title',
'required' => true,
'model' => $aisleModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.title'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un nom clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- NETWORK_ID --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(trans_choice('models.classes.network', 1)) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.bigint-foreign-id', [
'id' => 'aisleNetwork',
'label' => __(':field du :model', [
'field' => str(trans_choice('models.classes.network', '1'))->ucFirst(),
'model' => __('models.classes.aisle'),
]),
'name' => 'network_id',
'required' => true,
'model' => $aisleModel ?? null,
'associatedModels' => $networkModels ?? null,
'foreignLabel' => 'name',
'helper' => __('crud.minicrud.enum_select', [
'enum' => trans_choice('models.classes.network', '1'),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- PUBLISHED --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('crud.minicrud.visibility_label')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.tinyint-boolean', [
'id' => 'aislePublished',
'name' => 'published',
'model' => $aisleModel ?? null,
'label' => __('crud.minicrud.visibility_label'),
'helper' => __('crud.minicrud.visibility_helper'),
])
</div>
</div>
</fieldset>
</div>
{{-- TEXT --}}
<div class="col-12 mb-3">
<fieldset class="border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.content')) }}</legend>
<div class="row mb-3">
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'aisleText',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.first_content')),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'name' => 'text',
'model' => $aisleModel ?? null,
'required' => true,
// 'editorConfig' => $aisleModel->aisle->getFirstWysiwygType(),
'helper' => __('crud.minicrud.text_warning'),
])
</div>
</div>
</fieldset>
</div>
{{-- PICTURE --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.picture')) }}</legend>
<div class="row mb-3">
{{-- PICTURE_ALT --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'aislePictureAlt',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_alt',
'required' => true,
'model' => $aisleModel ?? null,
'helper' => __('crud.minicrud.picture_alt_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
])
</div>
{{-- PICTURE_TITLE --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'aislePictureTitle',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_title',
'required' => true,
'model' => $aisleModel ?? null,
'helper' => __('crud.minicrud.picture_title_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.aisle', 1),
]),
])
</div>
{{-- PICTURE --}}
<div class="col-12">
@include('bo.partials.inputs.varchar-picture', [
'id' => 'aislePicture',
'name' => 'picture',
'width' => 1400,
'height' => 450,
'model' => $aisleModel ?? null,
'helper' => __('crud.minicrud.dimensions_must_be', [
'widthpx' => '1400px',
'heightpx' => '450px',
]),
'required' => true,
'preview' => true,
])
</div>
</div>
</fieldset>
</div>
<div class="col-12 text-center">
<p><b>{{ __('validation.custom.required_fields') }}</b></p>
</div>
</div>

View file

@ -0,0 +1,66 @@
<table class="table-hover table-fix-action m-0 table">
@if (count($aisleModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'name' => Str::ucfirst(__('validation.attributes.name')),
'network_id' => Str::ucfirst(trans_choice('models.classes.network', 1)),
'published' => Str::ucfirst(__('validation.custom.activated')),
'updated_at' => Str::ucfirst(__('validation.attributes.updated_at')),
],
])
</thead>
<tbody>
@foreach ($aisleModels as $aisleModel)
<tr class="border-bottom list-item">
<td class="text-center align-middle">{{ $aisleModel->name }}</td>
<td class="text-center align-middle">{{ $aisleModel->network->name }}</td>
@include('bo.modules.change-published-status', [
'routeName' => 'aisles',
'model' => $aisleModel,
])
<td class="text-center align-middle">
<span class="badge bg-secondary">{{ $aisleModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['delete', 'duplicate', 'update'], $aisleModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.aisles.destroy', $aisleModel) }}" method="POST" novalidate>
@can('duplicate', $aisleModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.aisles.duplicate', ['aisle' => $aisleModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $aisleModel)
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.aisles.edit', ['aisle' => $aisleModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.update')) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $aisleModel)
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip" type="submit"
title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<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' => trans_choice('models.classes.aisle', 1)]) }}
</td>
</tr>
@endif
</table>

View file

@ -0,0 +1,21 @@
@extends('bo.layout')
@section('title', Str::ucfirst(trans_choice('models.classes.aisle', 1)))
@section('description', __('Liste de tous les :model', ['model' => trans_choice('models.classes.aisle', '*')]))
@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\Aisle::class)
<a class="btn btn-primary float-right" data-bs-toggle="tooltip" href="{{ route('bo.aisles.create') }}"
title="{{ __('crud.helpers.create_model', ['model' => trans_choice('models.classes.aisle', 1)]) }}">
<i class="fa-solid fa-plus"></i>
</a>
@endcan
</div>
@include('bo.modules.search-bar')
<div class="table-responsive mb-3">
@include('bo.pages.aisles.index-list')
</div>
{{ $aisleModels->links() }}
@endsection

View file

@ -0,0 +1,36 @@
@extends('bo.layout', ['brParam' => $brandModel])
@section('title', __('Création d\'un :model', ['model' => trans_choice('models.classes.brand', 1)]))
@section('description', __('Création d\'un tout nouveau :model', ['model' => trans_choice('models.classes.brand', 1)]))
@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.brands.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.brand', 1)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $brandModel])
</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' => trans_choice('models.classes.brand', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
<form action="{{ route('bo.brands.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.brands.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' => trans_choice('models.classes.brand', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,52 @@
@extends('bo.layout', ['brParam' => $brandModel])
@section('title', __('Édition d\'un :model', ['model' => trans_choice('models.classes.brand', 1)]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => trans_choice('models.classes.brand', 1)]))
@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.brands.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.brand', '*')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $brandModel])
</div>
<div class="mb-md-0 mb-2">
<form class="btn-group confirmDeleteTS" action="{{ route('bo.brands.destroy', $brandModel) }}" method="POST" novalidate>
@can('duplicate', $brandModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip" href="{{ route('bo.brands.duplicate', ['brand' => $brandModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<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' => trans_choice('models.classes.brand', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
@can('delete', $brandModel)
@csrf
@method('DELETE')
<button class="btn btn-danger" data-bs-toggle="tooltip" type="submit" title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
</div>
</div>
<form action="{{ route('bo.brands.update', $brandModel) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.brands.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' => trans_choice('models.classes.brand', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,207 @@
<div class="row">
{{-- NAME --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.name')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'brandName',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.name')),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $brandModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.name'),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un nom clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- LINK --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.link')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'brandLink',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.link')),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'hasWordCounter' => true,
'name' => 'link',
'required' => false,
'model' => $brandModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.link'),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('https://www.example.com'),
])
</div>
</div>
</fieldset>
</div>
{{-- NETWORK_ID --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(trans_choice('models.classes.aisle', 1)) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.bigint-foreign-id', [
'id' => 'brandNetwork',
'label' => __(':field du :model', [
'field' => str(trans_choice('models.classes.aisle', '1'))->ucFirst(),
'model' => __('models.classes.brand'),
]),
'name' => 'aisle_id',
'required' => true,
'model' => $brandModel ?? null,
'associatedModels' => $aisleModels ?? null,
'foreignLabel' => 'name',
'helper' => __('crud.minicrud.enum_select', [
'enum' => trans_choice('models.classes.aisle', '1'),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- PUBLISHED --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('crud.minicrud.visibility_label')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.tinyint-boolean', [
'id' => 'brandPublished',
'name' => 'published',
'model' => $brandModel ?? null,
'label' => __('crud.minicrud.visibility_label'),
'helper' => __('crud.minicrud.visibility_helper'),
])
</div>
</div>
</fieldset>
</div>
{{-- TEXT --}}
<div class="col-12 mb-3">
<fieldset class="border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.content')) }}</legend>
<div class="row mb-3">
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'brandText',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.first_content')),
'inter' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'name' => 'text',
'model' => $brandModel ?? null,
'required' => true,
'helper' => __('crud.minicrud.text_warning'),
])
</div>
</div>
</fieldset>
</div>
{{-- PICTURE --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.picture')) }}</legend>
<div class="row mb-3">
{{-- PICTURE_ALT --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'brandPictureAlt',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_alt',
'required' => true,
'model' => $brandModel ?? null,
'helper' => __('crud.minicrud.picture_alt_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
])
</div>
{{-- PICTURE_TITLE --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'brandPictureTitle',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_title',
'required' => true,
'model' => $brandModel ?? null,
'helper' => __('crud.minicrud.picture_title_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.female'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.female'),
'model' => trans_choice('models.classes.brand', 1),
]),
])
</div>
{{-- PICTURE --}}
<div class="col-12">
@include('bo.partials.inputs.varchar-picture', [
'id' => 'brandPicture',
'name' => 'picture',
'width' => 250,
'height' => 250,
'model' => $brandModel ?? null,
'helper' => __('crud.minicrud.dimensions_must_be', [
'widthpx' => '250px',
'heightpx' => '250px',
]),
'required' => true,
'preview' => true,
])
</div>
</div>
</fieldset>
</div>
<div class="col-12 text-center">
<p><b>{{ __('validation.custom.required_fields') }}</b></p>
</div>
</div>

View file

@ -0,0 +1,66 @@
<table class="table-hover table-fix-action m-0 table">
@if (count($brandModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'name' => Str::ucfirst(__('validation.attributes.name')),
'aisle_id' => Str::ucfirst(trans_choice('models.classes.aisle', 1)),
'published' => Str::ucfirst(__('validation.custom.activated')),
'updated_at' => Str::ucfirst(__('validation.attributes.updated_at')),
],
])
</thead>
<tbody>
@foreach ($brandModels as $brandModel)
<tr class="border-bottom list-item">
<td class="text-center align-middle">{{ $brandModel->name }}</td>
<td class="text-center align-middle">{{ $brandModel->aisle->name }}</td>
@include('bo.modules.change-published-status', [
'routeName' => 'brands',
'model' => $brandModel,
])
<td class="text-center align-middle">
<span class="badge bg-secondary">{{ $brandModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['delete', 'duplicate', 'update'], $brandModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.brands.destroy', $brandModel) }}" method="POST" novalidate>
@can('duplicate', $brandModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.brands.duplicate', ['brand' => $brandModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $brandModel)
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.brands.edit', ['brand' => $brandModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.update')) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $brandModel)
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip" type="submit"
title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<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' => trans_choice('models.classes.brand', 1)]) }}
</td>
</tr>
@endif
</table>

View file

@ -0,0 +1,21 @@
@extends('bo.layout')
@section('title', Str::ucfirst(trans_choice('models.classes.brand', 1)))
@section('description', __('Liste de tous les :model', ['model' => trans_choice('models.classes.brand', '*')]))
@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\Brand::class)
<a class="btn btn-primary float-right" data-bs-toggle="tooltip" href="{{ route('bo.brands.create') }}"
title="{{ __('crud.helpers.create_model', ['model' => trans_choice('models.classes.brand', 1)]) }}">
<i class="fa-solid fa-plus"></i>
</a>
@endcan
</div>
@include('bo.modules.search-bar')
<div class="table-responsive mb-3">
@include('bo.pages.brands.index-list')
</div>
{{ $brandModels->links() }}
@endsection

View file

@ -0,0 +1,36 @@
@extends('bo.layout', ['brParam' => $networkModel])
@section('title', __('Création d\'un :model', ['model' => trans_choice('models.classes.network', 1)]))
@section('description', __('Création d\'un tout nouveau :model', ['model' => trans_choice('models.classes.network', 1)]))
@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.networks.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.network', 1)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $networkModel])
</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' => trans_choice('models.classes.network', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
<form action="{{ route('bo.networks.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.networks.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' => trans_choice('models.classes.network', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,52 @@
@extends('bo.layout', ['brParam' => $networkModel])
@section('title', __('Édition d\'un :model', ['model' => trans_choice('models.classes.network', 1)]))
@section('description', __('Édition d\'un :model déjà existant', ['model' => trans_choice('models.classes.network', 1)]))
@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.networks.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.network', '*')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $networkModel])
</div>
<div class="mb-md-0 mb-2">
<form class="btn-group confirmDeleteTS" action="{{ route('bo.networks.destroy', $networkModel) }}" method="POST" novalidate>
@can('duplicate', $networkModel)
<a class="btn btn-secondary" data-bs-toggle="tooltip" href="{{ route('bo.networks.duplicate', ['network' => $networkModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<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' => trans_choice('models.classes.network', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
@can('delete', $networkModel)
@csrf
@method('DELETE')
<button class="btn btn-danger" data-bs-toggle="tooltip" type="submit" title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<i class="fa-solid fa-trash"></i>
</button>
@endcan
</form>
</div>
</div>
<form action="{{ route('bo.networks.update', $networkModel) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.networks.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' => trans_choice('models.classes.network', 1)]) }}">
{{ Str::ucfirst(__('crud.actions.save')) }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,258 @@
<div class="row">
{{-- SEO --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.seo')) }}</legend>
<div class="row mb-3">
{{-- SEO_TITLE --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'networkSeoTitle',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.seo_title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'seo_title',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.custom.seo_title'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'min' => 45,
'max' => 70,
]),
'placeholder' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.seo_title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
])
</div>
{{-- SEO_DESCRIPTION --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar-multiline', [
'id' => 'networkSeoDescription',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.seo_description')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'seo_description',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.custom.seo_description'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'min' => 50,
'max' => 160,
]),
'placeholder' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.seo_description')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- NAME --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.name')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'networkName',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.name')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.name'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un nom clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- PUBLISHED --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('crud.minicrud.visibility_label')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.tinyint-boolean', [
'id' => 'networkPublished',
'name' => 'published',
'model' => $networkModel ?? null,
'label' => __('crud.minicrud.visibility_label'),
'helper' => __('crud.minicrud.visibility_helper'),
])
</div>
</div>
</fieldset>
</div>
{{-- TITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.title')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'networkTitle',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.attributes.title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'title',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.attributes.title'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un nom clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- SUBTITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.subtitle')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'networkSubtitle',
'label' => __(':field :inter:model', [
'field' => Str::ucfirst(__('validation.custom.subtitle')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'subtitle',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.custom.subtitle'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'min' => 3,
'max' => 100,
]),
'placeholder' => __('Un sous-titre clair et concis'),
])
</div>
</div>
</fieldset>
</div>
{{-- PICTURE --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(__('validation.custom.picture')) }}</legend>
<div class="row mb-3">
{{-- PICTURE_ALT --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'networkPictureAlt',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_alt',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('crud.minicrud.picture_alt_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.alt_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
])
</div>
{{-- PICTURE_TITLE --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'networkPictureTitle',
'label' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
'hasWordCounter' => true,
'name' => 'picture_title',
'required' => true,
'model' => $networkModel ?? null,
'helper' => __('crud.minicrud.picture_title_helper'),
'placeholder' => __(':field1 :inter1:field2 :inter2:model', [
'field1' => Str::ucfirst(__('validation.custom.title_attribute')),
'inter1' => __('validation.custom.of_the.male'),
'field2' => __('validation.custom.picture'),
'inter2' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.network', 1),
]),
])
</div>
{{-- PICTURE --}}
<div class="col-12">
@include('bo.partials.inputs.varchar-picture', [
'id' => 'networkPicture',
'name' => 'picture',
'width' => 1920,
'height' => 1080,
'model' => $networkModel ?? null,
'helper' => __('crud.minicrud.dimensions_must_be', [
'widthpx' => '1920px',
'heightpx' => '1080px',
]),
'required' => true,
'preview' => true,
])
</div>
</div>
</fieldset>
</div>
<div class="col-12 text-center">
<p><b>{{ __('validation.custom.required_fields') }}</b></p>
</div>
</div>

View file

@ -0,0 +1,75 @@
<table class="table-hover table-fix-action m-0 table">
@if (count($networkModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'name' => Str::ucfirst(__('validation.attributes.name')),
'order' => Str::ucfirst(__('validation.custom.order')),
'published' => Str::ucfirst(__('validation.custom.activated')),
'updated_at' => Str::ucfirst(__('validation.attributes.updated_at')),
],
])
</thead>
<tbody>
@foreach ($networkModels as $networkModel)
<tr class="border-bottom list-item">
<td class="text-center align-middle">{{ $networkModel->name }}</td>
@php
$routeName = request()->route()->getName();
@endphp
@if (empty(request()->search) && Session::get("$routeName.sort_col") === 'order')
@include('bo.modules.change-model-order', [
'routeName' => 'networks',
'model' => $networkModel,
'models' => $networkModels,
])
@endif
@include('bo.modules.change-published-status', [
'routeName' => 'networks',
'model' => $networkModel,
])
<td class="text-center align-middle">
<span class="badge bg-secondary">{{ $networkModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="text-end align-middle">
@canAny(['delete', 'duplicate', 'update'], $networkModel)
<form class="btn-group confirmDeleteTS" action="{{ route('bo.networks.destroy', $networkModel) }}" method="POST" novalidate>
@can('duplicate', $networkModel)
<a class="btn btn-sm btn-secondary" data-bs-toggle="tooltip"
href="{{ route('bo.networks.duplicate', ['network' => $networkModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.duplicate')) }}">
<i class="fa-solid fa-copy"></i>
</a>
@endcan
@can('update', $networkModel)
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.networks.edit', ['network' => $networkModel]) }}"
title="{{ Str::ucfirst(__('crud.actions.update')) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@endcan
@can('delete', $networkModel)
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip" type="submit"
title="{{ Str::ucfirst(__('crud.actions.delete')) }}">
<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' => trans_choice('models.classes.network', 1)]) }}
</td>
</tr>
@endif
</table>

View file

@ -0,0 +1,21 @@
@extends('bo.layout')
@section('title', Str::ucfirst(trans_choice('models.classes.network', 1)))
@section('description', __('Liste de tous les :model', ['model' => trans_choice('models.classes.network', '*')]))
@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\Network::class)
<a class="btn btn-primary float-right" data-bs-toggle="tooltip" href="{{ route('bo.networks.create') }}"
title="{{ __('crud.helpers.create_model', ['model' => trans_choice('models.classes.network', 1)]) }}">
<i class="fa-solid fa-plus"></i>
</a>
@endcan
</div>
@include('bo.modules.search-bar')
<div class="table-responsive mb-3">
@include('bo.pages.networks.index-list')
</div>
{{ $networkModels->links() }}
@endsection

View file

@ -76,7 +76,12 @@
</div>
</fieldset>
</div>
@if ($sectionModel->section !== \App\Enums\Sections\PageSectionenum::hire_grow)
@if (
!in_array($sectionModel->section, [
\App\Enums\Sections\PageSectionenum::hire_grow,
\App\Enums\Sections\PageSectionenum::produce_networks,
])
)
{{-- CONTENT --}}
<div class="col-12 mb-3">
<fieldset class="border p-3">

View file

@ -0,0 +1,107 @@
@extends('fo.layout')
@section('title', __($networkModel->seo_title))
@section('description', __($networkModel->seo_description))
@section('breadcrumb', request()->route()->getName())
@section('banner')
@include('fo.layouts.banner', [
'h1' => __($networkModel->name),
'asset' => asset($networkModel->picture),
'title' => __($networkModel->picture_title),
'alt' => __($networkModel->picture_alt),
'displayArrow' => true,
'buttonLink' => '#network',
])
@endsection
@section('content')
<section class="anchor-padding container my-4" id="network">
<div class="row">
<div class="col-12 text-center">
<h2 class="fw-bold text-primary">{{ $networkModel->title }}</h2>
</div>
</div>
{{-- AISLES --}}
@foreach ($networkModel->aisles as $aisleModel)
<section class="anchor-padding my-4">
<div class="row">
<div class="col-12 text-center">
<h3 class="fw-bold text-sixt my-3">{{ $aisleModel->title }}</h3>
<img class="img-fluid my-4 rounded-3"
src="{{ asset($aisleModel->picture) }}"
alt="{{ $aisleModel->picture_alt }}"
title="{{ $aisleModel->picture_title }}">
</div>
<div class="col-12 col-md-10 offset-md-1">
<div class="ck-content my-5">{!! clean($aisleModel->text) !!}</div>
</div>
</div>
<div class="row">
<div class="col-12 col-md-8 offset-md-2">
@foreach($aisleModel->brands as $brandModel)
<div class="row my-3 align-items-center">
<div @class([
'col-3',
'order-2' => $loop->even
])>
<a href="{{ $brandModel->link }}"
target="_blank"
title="{{ __('Accéder au lien : :link', ['link' => $brandModel->link])}}"
>
<img class="img-fluid"
src="{{ asset($brandModel->picture) }}"
alt="{{ $brandModel->picture_alt }}"
title="{{ $brandModel->picture_title }}">
</a>
</div>
<div @class([
'col-9',
'order-1' => $loop->even
])>
<p class="fw-bold">{{ $brandModel->name }}&nbsp;:</p>
<p>{!! clean($brandModel->text) !!}</p>
</div>
</div>
@endforeach
</div>
</div>
</section>
@endforeach
</section>
{{-- SLIDER --}}
<div class="anchor-padding overflow-hidden">
<section class=" container my-4 text-center" id="slider">
<div class="row">
<div class="col-12">
<h2 class="fw-bold text-primary my-5">{{ __('Découvrez d\'autres réseaux') }}</h2>
</div>
<div class="row">
<div class="col-12 position-relative mb-5">
<div class="swiper swiper-networks mt-lg-0 mt-5 overflow-visible" id="swiper-networks">
<div class="swiper-wrapper">
@foreach ($networkModels as $networkModel)
<div class="swiper-slide">
@include('fo.partials.networks.slider-card', [
'networkModel' => $networkModel
])
</div>
@endforeach
</div>
</div>
<button class="swiper-button swiper-button-prev-custom swiper-networks-button-prev z-1 mx-3">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</button>
<button class="swiper-button swiper-button-next-custom swiper-networks-button-next z-1 mx-3">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</button>
</div>
</div>
</div>
</div>
</section>
</div>
@endsection

View file

@ -132,6 +132,39 @@
</div>
</div>
</section> --}}
{{-- NETWORKS --}}
<div class="anchor-padding overflow-hidden">
<section class="container my-4 text-center" id="networks">
<div class="row">
<div class="col-12">
<h2 class="fw-bold text-primary mb-3">{{ $networkSection->h2_title }}</h2>
<div class="row">
<div class="col-12 position-relative mb-5">
<div class="swiper swiper-networks mt-lg-0 mt-5 overflow-visible" id="swiper-networks">
<div class="swiper-wrapper">
@foreach ($networkModels as $networkModel)
<div class="swiper-slide">
@include('fo.partials.networks.slider-card', [
'networkModel' => $networkModel
])
</div>
@endforeach
</div>
</div>
<button class="swiper-button swiper-button-prev-custom swiper-networks-button-prev z-1 mx-3">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</button>
<button class="swiper-button swiper-button-next-custom swiper-networks-button-next z-1 mx-3">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</button>
</div>
</div>
</div>
</div>
</section>
</div>
{{-- QUALITY --}}
{{-- <section class="border-top-curved-upper-primary"> --}}
<div class="overflow-hidden bg-white pb-5">

View file

@ -0,0 +1,8 @@
<div class="card ratio ratio-21x9 position-relative">
<div class="img-wrapper w-100 h-100 overflow-hidden border">
<img class="object-fit-cover w-100 h-100" src="{{ asset($networkModel->picture) }}" title="{{ $networkModel->picture_title }}"
alt="{{ $networkModel->picture_alt }}">
</div>
<a class="btn btn-primary position-absolute top-50 start-50 translate-middle rounded-5 text-uppercase mx-auto w-fit h-auto"
href="{{ route('fo.networks.show', $networkModel) }}">{{ __('Découvrir le réseau :network', ['network' => $networkModel->name]) }}</a>
</div>

View file

@ -1,9 +1,12 @@
<?php
use App\Models\ActivityLog;
use App\Models\Aisle;
use App\Models\Brand;
use App\Models\HistoricalMilestone;
use App\Models\JobVideo;
use App\Models\Logo;
use App\Models\Network;
use App\Models\News;
use App\Models\Section;
use App\Models\Site;
@ -233,3 +236,63 @@ Breadcrumbs::for('bo.sections.edit', function (Generator $trail, Section $sectio
$trail->parent('bo.sections.index', '');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.sections.edit', $section));
});
// * NETWORKS
Breadcrumbs::for('bo.networks.index', function (Generator $trail) {
$trail->push(
Str::of(trans_choice('models.classes.network', \INF))->ucfirst(),
route('bo.networks.index', ['sort_col' => 'updated_at', 'sort_way' => 'desc'])
);
});
Breadcrumbs::for('bo.networks.create', function (Generator $trail) {
$trail->parent('bo.networks.index');
$trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.networks.create'));
});
Breadcrumbs::for('bo.networks.edit', function (Generator $trail, Network $network) {
$trail->parent('bo.networks.index');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.networks.edit', $network));
});
Breadcrumbs::for('bo.networks.duplicate', function (Generator $trail) {
$trail->parent('bo.networks.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});
// * AISLES
Breadcrumbs::for('bo.aisles.index', function (Generator $trail) {
$trail->push(
Str::of(trans('models.classes.aisle'))->plural()->ucfirst(),
route('bo.aisles.index', ['sort_col' => 'updated_at', 'sort_way' => 'desc'])
);
});
Breadcrumbs::for('bo.aisles.create', function (Generator $trail) {
$trail->parent('bo.aisles.index');
$trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.aisles.create'));
});
Breadcrumbs::for('bo.aisles.edit', function (Generator $trail, Aisle $aisle) {
$trail->parent('bo.aisles.index');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.aisles.edit', $aisle));
});
Breadcrumbs::for('bo.aisles.duplicate', function (Generator $trail) {
$trail->parent('bo.aisles.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});
// * BRANDS
Breadcrumbs::for('bo.brands.index', function (Generator $trail) {
$trail->push(
Str::of(trans('models.classes.brand'))->plural()->ucfirst(),
route('bo.brands.index', ['sort_col' => 'updated_at', 'sort_way' => 'desc'])
);
});
Breadcrumbs::for('bo.brands.create', function (Generator $trail) {
$trail->parent('bo.brands.index');
$trail->push(Str::ucfirst(trans('crud.actions.create')), route('bo.brands.create'));
});
Breadcrumbs::for('bo.brands.edit', function (Generator $trail, Brand $brand) {
$trail->parent('bo.brands.index');
$trail->push(Str::ucfirst(trans('crud.actions.edit')), route('bo.brands.edit', $brand));
});
Breadcrumbs::for('bo.brands.duplicate', function (Generator $trail) {
$trail->parent('bo.brands.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
});

View file

@ -1,10 +1,13 @@
<?php
use App\Http\Controllers\Bo\ActivityLogController;
use App\Http\Controllers\Bo\AisleController;
use App\Http\Controllers\Bo\BrandController;
use App\Http\Controllers\Bo\DashboardController;
use App\Http\Controllers\Bo\HistoricalMilestoneController;
use App\Http\Controllers\Bo\JobVideoController;
use App\Http\Controllers\Bo\LogoController;
use App\Http\Controllers\Bo\NetworkController;
use App\Http\Controllers\Bo\NewsController;
use App\Http\Controllers\Bo\SectionController;
use App\Http\Controllers\Bo\SiteController;
@ -159,6 +162,49 @@ Route::middleware(['admin-secure'])->prefix('bo')
'duplicate'
])->name('testimonials.duplicate');
// * NETWORKS
Route::resource('networks', NetworkController::class)->except('show')
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:content');
Route::get('/networks/{network}/duplicate', [
NetworkController::class,
'duplicate'
])->name('networks.duplicate');
Route::patch('/networks/{network}/change-order/{direction}', [
NetworkController::class,
'changeOrder'
])->where('direction', 'up|down')->name('networks.change-order');
Route::patch('/networks/{network}/change-published', [
NetworkController::class,
'changePublished'
])->name('networks.change-published');
// * AISLES
Route::resource('aisles', AisleController::class)->except('show')
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:content');
Route::get('/aisles/{aisle}/duplicate', [
AisleController::class,
'duplicate'
])->name('aisles.duplicate');
Route::patch('/aisles/{aisle}/change-published', [
AisleController::class,
'changePublished'
])->name('aisles.change-published');
// * BRANDS
Route::resource('brands', BrandController::class)->except('show')
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:content');
Route::get('/brands/{brand}/duplicate', [
BrandController::class,
'duplicate'
])->name('brands.duplicate');
Route::patch('/brands/{brand}/change-published', [
BrandController::class,
'changePublished'
])->name('brands.change-published');
Route::middleware('can:isConceptor')->group(function () {
// * ACTIVITY LOGS.
Route::resource('activity_logs', ActivityLogController::class)->only(['index', 'show']);

View file

@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\Fo\NetworkController;
use App\Http\Controllers\Fo\StaticPageController;
use App\Http\Controllers\Fo\NewsController;
use Illuminate\Support\Facades\Route;
@ -20,6 +21,7 @@ Route::middleware(['throttle:web'])->name('fo.')->group(function () {
Route::get('/on-bouge/{publishedNews:slug}', [NewsController::class, 'show'])->name('news.show');
Route::get('/on-embauche', [StaticPageController::class, 'hire'])->name('hire.show');
Route::get('/on-produit', [StaticPageController::class, 'produce'])->name('produce.show');
Route::get('/nos-reseaux/{publishedNetwork:slug}', [NetworkController::class, 'show'])->name('networks.show');
// * RGPD
Route::get('/mentions-legales', [StaticPageController::class, 'legals'])->name('legals');