diff --git a/app/Enums/Sections/PageSectionEnum.php b/app/Enums/Sections/PageSectionEnum.php index 15197e3..5dec1af 100644 --- a/app/Enums/Sections/PageSectionEnum.php +++ b/app/Enums/Sections/PageSectionEnum.php @@ -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 } } diff --git a/app/Http/Controllers/Bo/AisleController.php b/app/Http/Controllers/Bo/AisleController.php new file mode 100644 index 0000000..21d7193 --- /dev/null +++ b/app/Http/Controllers/Bo/AisleController.php @@ -0,0 +1,177 @@ +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()); + } +} diff --git a/app/Http/Controllers/Bo/BrandController.php b/app/Http/Controllers/Bo/BrandController.php new file mode 100644 index 0000000..f36df49 --- /dev/null +++ b/app/Http/Controllers/Bo/BrandController.php @@ -0,0 +1,177 @@ +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()); + } +} diff --git a/app/Http/Controllers/Bo/NetworkController.php b/app/Http/Controllers/Bo/NetworkController.php new file mode 100644 index 0000000..1349780 --- /dev/null +++ b/app/Http/Controllers/Bo/NetworkController.php @@ -0,0 +1,171 @@ +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()); + } +} diff --git a/app/Http/Controllers/Fo/NetworkController.php b/app/Http/Controllers/Fo/NetworkController.php new file mode 100644 index 0000000..b703b00 --- /dev/null +++ b/app/Http/Controllers/Fo/NetworkController.php @@ -0,0 +1,27 @@ +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, + ]); + } +} diff --git a/app/Http/Controllers/Fo/StaticPageController.php b/app/Http/Controllers/Fo/StaticPageController.php index d3552e4..37bbcd0 100644 --- a/app/Http/Controllers/Fo/StaticPageController.php +++ b/app/Http/Controllers/Fo/StaticPageController.php @@ -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', )); } diff --git a/app/Http/Requests/Bo/Aisles/StoreAisleRequest.php b/app/Http/Requests/Bo/Aisles/StoreAisleRequest.php new file mode 100644 index 0000000..257763c --- /dev/null +++ b/app/Http/Requests/Bo/Aisles/StoreAisleRequest.php @@ -0,0 +1,61 @@ +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> + */ + 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), + ); + } +} diff --git a/app/Http/Requests/Bo/Aisles/UpdateAisleRequest.php b/app/Http/Requests/Bo/Aisles/UpdateAisleRequest.php new file mode 100644 index 0000000..35af4ff --- /dev/null +++ b/app/Http/Requests/Bo/Aisles/UpdateAisleRequest.php @@ -0,0 +1,8 @@ +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> + */ + 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), + ); + } +} diff --git a/app/Http/Requests/Bo/Brands/UpdateBrandRequest.php b/app/Http/Requests/Bo/Brands/UpdateBrandRequest.php new file mode 100644 index 0000000..2acae2d --- /dev/null +++ b/app/Http/Requests/Bo/Brands/UpdateBrandRequest.php @@ -0,0 +1,8 @@ +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> + */ + 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), + ); + } +} diff --git a/app/Http/Requests/Bo/Networks/UpdateNetworkRequest.php b/app/Http/Requests/Bo/Networks/UpdateNetworkRequest.php new file mode 100644 index 0000000..5e0705a --- /dev/null +++ b/app/Http/Requests/Bo/Networks/UpdateNetworkRequest.php @@ -0,0 +1,8 @@ + + */ + protected $fillable = [ + 'name', + 'title', + 'text', + 'picture', + 'picture_alt', + 'picture_title', + 'published', + 'network_id', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + 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); + } +} diff --git a/app/Models/Brand.php b/app/Models/Brand.php new file mode 100644 index 0000000..5b8d03d --- /dev/null +++ b/app/Models/Brand.php @@ -0,0 +1,115 @@ + + */ + protected $fillable = [ + 'name', + 'text', + 'picture', + 'picture_alt', + 'picture_title', + 'link', + 'published', + 'aisle_id' + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + 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); + } +} diff --git a/app/Models/Network.php b/app/Models/Network.php new file mode 100644 index 0000000..3fd0c6e --- /dev/null +++ b/app/Models/Network.php @@ -0,0 +1,161 @@ + + */ + 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 + */ + 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); + } +} diff --git a/app/Policies/AislePolicy.php b/app/Policies/AislePolicy.php new file mode 100644 index 0000000..0efd808 --- /dev/null +++ b/app/Policies/AislePolicy.php @@ -0,0 +1,120 @@ +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(); + }); } /** diff --git a/database/factories/assets/1400x450.png b/database/factories/assets/1400x450.png new file mode 100644 index 0000000..b93bfac Binary files /dev/null and b/database/factories/assets/1400x450.png differ diff --git a/database/factories/assets/1920x1080.png b/database/factories/assets/1920x1080.png new file mode 100644 index 0000000..ae3045a Binary files /dev/null and b/database/factories/assets/1920x1080.png differ diff --git a/database/factories/assets/250x250.png b/database/factories/assets/250x250.png new file mode 100644 index 0000000..744ada5 Binary files /dev/null and b/database/factories/assets/250x250.png differ diff --git a/database/migrations/2026_01_19_171504_create_networks_table.php b/database/migrations/2026_01_19_171504_create_networks_table.php new file mode 100644 index 0000000..55193e3 --- /dev/null +++ b/database/migrations/2026_01_19_171504_create_networks_table.php @@ -0,0 +1,70 @@ +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(); + } +}; diff --git a/database/migrations/2026_01_20_094642_insert_networks_section.php b/database/migrations/2026_01_20_094642_insert_networks_section.php new file mode 100644 index 0000000..8319413 --- /dev/null +++ b/database/migrations/2026_01_20_094642_insert_networks_section.php @@ -0,0 +1,39 @@ +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(); + } +}; diff --git a/database/migrations/2026_01_20_114502_create_aisles_table.php b/database/migrations/2026_01_20_114502_create_aisles_table.php new file mode 100644 index 0000000..af2dd17 --- /dev/null +++ b/database/migrations/2026_01_20_114502_create_aisles_table.php @@ -0,0 +1,56 @@ +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'); + } +}; diff --git a/database/migrations/2026_01_20_154059_create_brands_table.php b/database/migrations/2026_01_20_154059_create_brands_table.php new file mode 100644 index 0000000..a2e67cd --- /dev/null +++ b/database/migrations/2026_01_20_154059_create_brands_table.php @@ -0,0 +1,70 @@ +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(); + } +}; diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php index 84209d7..b7ec1b0 100644 --- a/resources/lang/fr/models.php +++ b/resources/lang/fr/models.php @@ -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', ] ]; diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php index 6c7f2d1..d8d8285 100644 --- a/resources/lang/fr/validation.php +++ b/resources/lang/fr/validation.php @@ -295,5 +295,6 @@ return [ 'object' => 'objet', 'message' => 'message', 'banner' => 'bannière', + 'subtitle' => 'sous-titre', ], ]; diff --git a/resources/ts/fo/base/common.ts b/resources/ts/fo/base/common.ts index fba862e..4d26a9a 100644 --- a/resources/ts/fo/base/common.ts +++ b/resources/ts/fo/base/common.ts @@ -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 ""; + }, + }, + navigation: { + nextEl: ".swiper-networks-button-next", + prevEl: ".swiper-networks-button-prev", + }, + breakpoints: { + 576: { + slidesPerView: 1.3, + }, + }, + }, }; const swiperVol = document.getElementsByClassName("swiper") as HTMLCollectionOf; diff --git a/resources/views/bo/layouts/nav-list.blade.php b/resources/views/bo/layouts/nav-list.blade.php index 8645367..f89335e 100644 --- a/resources/views/bo/layouts/nav-list.blade.php +++ b/resources/views/bo/layouts/nav-list.blade.php @@ -248,7 +248,15 @@ {{-- WE PRODUCE --}} @endforeach @endcan + @can('viewAny', \App\Models\Network::class) + + @endcan + @can('viewAny', \App\Models\Aisle::class) + + @endcan + @can('viewAny', \App\Models\Brand::class) + + @endcan diff --git a/resources/views/bo/pages/aisles/create.blade.php b/resources/views/bo/pages/aisles/create.blade.php new file mode 100644 index 0000000..d318d25 --- /dev/null +++ b/resources/views/bo/pages/aisles/create.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $aisleModel]) +
+
+ +
+
+
+ @csrf + @include('bo.pages.aisles.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/aisles/edit.blade.php b/resources/views/bo/pages/aisles/edit.blade.php new file mode 100644 index 0000000..1788831 --- /dev/null +++ b/resources/views/bo/pages/aisles/edit.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $aisleModel]) +
+
+
+ @can('duplicate', $aisleModel) + + + + @endcan + + @can('delete', $aisleModel) + @csrf + @method('DELETE') + + @endcan +
+
+
+
+ @csrf + @method('PUT') + @include('bo.pages.aisles.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/aisles/form.blade.php b/resources/views/bo/pages/aisles/form.blade.php new file mode 100644 index 0000000..4fa31a8 --- /dev/null +++ b/resources/views/bo/pages/aisles/form.blade.php @@ -0,0 +1,208 @@ +
+ {{-- NAME --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.name')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- TITLE --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.title')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- NETWORK_ID --}} +
+
+ {{ Str::ucfirst(trans_choice('models.classes.network', 1)) }} +
+
+ @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'), + ]), + ]) +
+
+
+
+ {{-- PUBLISHED --}} +
+
+ {{ Str::ucfirst(__('crud.minicrud.visibility_label')) }} +
+
+ @include('bo.partials.inputs.tinyint-boolean', [ + 'id' => 'aislePublished', + 'name' => 'published', + 'model' => $aisleModel ?? null, + 'label' => __('crud.minicrud.visibility_label'), + 'helper' => __('crud.minicrud.visibility_helper'), + ]) +
+
+
+
+ {{-- TEXT --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.content')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- PICTURE --}} +
+
+ {{ Str::ucfirst(__('validation.custom.picture')) }} +
+ {{-- PICTURE_ALT --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE_TITLE --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE --}} +
+ @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, + ]) +
+
+
+
+
+

{{ __('validation.custom.required_fields') }}

+
+
diff --git a/resources/views/bo/pages/aisles/index-list.blade.php b/resources/views/bo/pages/aisles/index-list.blade.php new file mode 100644 index 0000000..64500fa --- /dev/null +++ b/resources/views/bo/pages/aisles/index-list.blade.php @@ -0,0 +1,66 @@ + + @if (count($aisleModels) > 0) + + @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')), + ], + ]) + + + @foreach ($aisleModels as $aisleModel) + + + + @include('bo.modules.change-published-status', [ + 'routeName' => 'aisles', + 'model' => $aisleModel, + ]) + + + + @endforeach + + @else + + + + @endif +
{{ $aisleModel->name }}{{ $aisleModel->network->name }} + {{ $aisleModel->updated_at->isoFormat('LLLL') }} + + @canAny(['delete', 'duplicate', 'update'], $aisleModel) +
+ @can('duplicate', $aisleModel) + + + + @endcan + @can('update', $aisleModel) + + + + @endcan + @can('delete', $aisleModel) + @csrf + @method('DELETE') + + @endcan +
+ @else + + + + @endcan +
{{ trans_choice('crud.other.no_model_found', 1, ['model' => trans_choice('models.classes.aisle', 1)]) }} +
diff --git a/resources/views/bo/pages/aisles/index.blade.php b/resources/views/bo/pages/aisles/index.blade.php new file mode 100644 index 0000000..986b46b --- /dev/null +++ b/resources/views/bo/pages/aisles/index.blade.php @@ -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') +
+ @include('modules.breadcrumbs.breadcrumb-body') + @can('create', \App\Models\Aisle::class) + + + + @endcan +
+ @include('bo.modules.search-bar') +
+ @include('bo.pages.aisles.index-list') +
+ {{ $aisleModels->links() }} +@endsection diff --git a/resources/views/bo/pages/brands/create.blade.php b/resources/views/bo/pages/brands/create.blade.php new file mode 100644 index 0000000..cdd0261 --- /dev/null +++ b/resources/views/bo/pages/brands/create.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $brandModel]) +
+
+ +
+
+
+ @csrf + @include('bo.pages.brands.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/brands/edit.blade.php b/resources/views/bo/pages/brands/edit.blade.php new file mode 100644 index 0000000..1bd17f6 --- /dev/null +++ b/resources/views/bo/pages/brands/edit.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $brandModel]) +
+
+
+ @can('duplicate', $brandModel) + + + + @endcan + + @can('delete', $brandModel) + @csrf + @method('DELETE') + + @endcan +
+
+
+
+ @csrf + @method('PUT') + @include('bo.pages.brands.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/brands/form.blade.php b/resources/views/bo/pages/brands/form.blade.php new file mode 100644 index 0000000..ed73c4c --- /dev/null +++ b/resources/views/bo/pages/brands/form.blade.php @@ -0,0 +1,207 @@ +
+ {{-- NAME --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.name')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- LINK --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.link')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- NETWORK_ID --}} +
+
+ {{ Str::ucfirst(trans_choice('models.classes.aisle', 1)) }} +
+
+ @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'), + ]), + ]) +
+
+
+
+ {{-- PUBLISHED --}} +
+
+ {{ Str::ucfirst(__('crud.minicrud.visibility_label')) }} +
+
+ @include('bo.partials.inputs.tinyint-boolean', [ + 'id' => 'brandPublished', + 'name' => 'published', + 'model' => $brandModel ?? null, + 'label' => __('crud.minicrud.visibility_label'), + 'helper' => __('crud.minicrud.visibility_helper'), + ]) +
+
+
+
+ {{-- TEXT --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.content')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- PICTURE --}} +
+
+ {{ Str::ucfirst(__('validation.custom.picture')) }} +
+ {{-- PICTURE_ALT --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE_TITLE --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE --}} +
+ @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, + ]) +
+
+
+
+
+

{{ __('validation.custom.required_fields') }}

+
+
diff --git a/resources/views/bo/pages/brands/index-list.blade.php b/resources/views/bo/pages/brands/index-list.blade.php new file mode 100644 index 0000000..038f99e --- /dev/null +++ b/resources/views/bo/pages/brands/index-list.blade.php @@ -0,0 +1,66 @@ + + @if (count($brandModels) > 0) + + @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')), + ], + ]) + + + @foreach ($brandModels as $brandModel) + + + + @include('bo.modules.change-published-status', [ + 'routeName' => 'brands', + 'model' => $brandModel, + ]) + + + + @endforeach + + @else + + + + @endif +
{{ $brandModel->name }}{{ $brandModel->aisle->name }} + {{ $brandModel->updated_at->isoFormat('LLLL') }} + + @canAny(['delete', 'duplicate', 'update'], $brandModel) +
+ @can('duplicate', $brandModel) + + + + @endcan + @can('update', $brandModel) + + + + @endcan + @can('delete', $brandModel) + @csrf + @method('DELETE') + + @endcan +
+ @else + + + + @endcan +
{{ trans_choice('crud.other.no_model_found', 1, ['model' => trans_choice('models.classes.brand', 1)]) }} +
diff --git a/resources/views/bo/pages/brands/index.blade.php b/resources/views/bo/pages/brands/index.blade.php new file mode 100644 index 0000000..6f14745 --- /dev/null +++ b/resources/views/bo/pages/brands/index.blade.php @@ -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') +
+ @include('modules.breadcrumbs.breadcrumb-body') + @can('create', \App\Models\Brand::class) + + + + @endcan +
+ @include('bo.modules.search-bar') +
+ @include('bo.pages.brands.index-list') +
+ {{ $brandModels->links() }} +@endsection diff --git a/resources/views/bo/pages/networks/create.blade.php b/resources/views/bo/pages/networks/create.blade.php new file mode 100644 index 0000000..c92d27d --- /dev/null +++ b/resources/views/bo/pages/networks/create.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $networkModel]) +
+
+ +
+
+
+ @csrf + @include('bo.pages.networks.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/networks/edit.blade.php b/resources/views/bo/pages/networks/edit.blade.php new file mode 100644 index 0000000..b37fd2a --- /dev/null +++ b/resources/views/bo/pages/networks/edit.blade.php @@ -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') +
+
+ + + + @include('modules.breadcrumbs.breadcrumb-body', ['brParam' => $networkModel]) +
+
+
+ @can('duplicate', $networkModel) + + + + @endcan + + @can('delete', $networkModel) + @csrf + @method('DELETE') + + @endcan +
+
+
+
+ @csrf + @method('PUT') + @include('bo.pages.networks.form') + @include('bo.partials.script-button-clone') +
+
+ +
+
+
+@endsection diff --git a/resources/views/bo/pages/networks/form.blade.php b/resources/views/bo/pages/networks/form.blade.php new file mode 100644 index 0000000..9877f3f --- /dev/null +++ b/resources/views/bo/pages/networks/form.blade.php @@ -0,0 +1,258 @@ +
+ {{-- SEO --}} +
+
+ {{ Str::ucfirst(__('validation.custom.seo')) }} +
+ {{-- SEO_TITLE --}} +
+ @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), + ]), + ]) +
+ {{-- SEO_DESCRIPTION --}} +
+ @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), + ]), + ]) +
+
+
+
+ {{-- NAME --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.name')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- PUBLISHED --}} +
+
+ {{ Str::ucfirst(__('crud.minicrud.visibility_label')) }} +
+
+ @include('bo.partials.inputs.tinyint-boolean', [ + 'id' => 'networkPublished', + 'name' => 'published', + 'model' => $networkModel ?? null, + 'label' => __('crud.minicrud.visibility_label'), + 'helper' => __('crud.minicrud.visibility_helper'), + ]) +
+
+
+
+ {{-- TITLE --}} +
+
+ {{ Str::ucfirst(__('validation.attributes.title')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- SUBTITLE --}} +
+
+ {{ Str::ucfirst(__('validation.custom.subtitle')) }} +
+
+ @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'), + ]) +
+
+
+
+ {{-- PICTURE --}} +
+
+ {{ Str::ucfirst(__('validation.custom.picture')) }} +
+ {{-- PICTURE_ALT --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE_TITLE --}} +
+ @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), + ]), + ]) +
+ {{-- PICTURE --}} +
+ @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, + ]) +
+
+
+
+
+

{{ __('validation.custom.required_fields') }}

+
+
diff --git a/resources/views/bo/pages/networks/index-list.blade.php b/resources/views/bo/pages/networks/index-list.blade.php new file mode 100644 index 0000000..dc21dd9 --- /dev/null +++ b/resources/views/bo/pages/networks/index-list.blade.php @@ -0,0 +1,75 @@ + + @if (count($networkModels) > 0) + + @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')), + ], + ]) + + + @foreach ($networkModels as $networkModel) + + + @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, + ]) + + + + @endforeach + + @else + + + + @endif +
{{ $networkModel->name }} + {{ $networkModel->updated_at->isoFormat('LLLL') }} + + @canAny(['delete', 'duplicate', 'update'], $networkModel) +
+ @can('duplicate', $networkModel) + + + + @endcan + @can('update', $networkModel) + + + + @endcan + @can('delete', $networkModel) + @csrf + @method('DELETE') + + @endcan +
+ @else + + + + @endcan +
{{ trans_choice('crud.other.no_model_found', 1, ['model' => trans_choice('models.classes.network', 1)]) }} +
diff --git a/resources/views/bo/pages/networks/index.blade.php b/resources/views/bo/pages/networks/index.blade.php new file mode 100644 index 0000000..d50af54 --- /dev/null +++ b/resources/views/bo/pages/networks/index.blade.php @@ -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') +
+ @include('modules.breadcrumbs.breadcrumb-body') + @can('create', \App\Models\Network::class) + + + + @endcan +
+ @include('bo.modules.search-bar') +
+ @include('bo.pages.networks.index-list') +
+ {{ $networkModels->links() }} +@endsection diff --git a/resources/views/bo/pages/sections/form.blade.php b/resources/views/bo/pages/sections/form.blade.php index 4b57bea..dfd4de8 100644 --- a/resources/views/bo/pages/sections/form.blade.php +++ b/resources/views/bo/pages/sections/form.blade.php @@ -76,7 +76,12 @@ - @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 --}}
diff --git a/resources/views/fo/pages/networks/show.blade.php b/resources/views/fo/pages/networks/show.blade.php new file mode 100644 index 0000000..3731769 --- /dev/null +++ b/resources/views/fo/pages/networks/show.blade.php @@ -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') +
+
+
+

{{ $networkModel->title }}

+
+
+ + {{-- AISLES --}} + @foreach ($networkModel->aisles as $aisleModel) +
+
+
+

{{ $aisleModel->title }}

+ {{ $aisleModel->picture_alt }} +
+
+
{!! clean($aisleModel->text) !!}
+
+
+
+
+ @foreach($aisleModel->brands as $brandModel) +
+
$loop->even + ])> + + {{ $brandModel->picture_alt }} + +
+
$loop->even + ])> +

{{ $brandModel->name }} :

+

{!! clean($brandModel->text) !!}

+
+
+ @endforeach +
+
+
+ @endforeach +
+ {{-- SLIDER --}} +
+
+
+
+

{{ __('Découvrez d\'autres réseaux') }}

+
+
+
+
+
+ @foreach ($networkModels as $networkModel) +
+ @include('fo.partials.networks.slider-card', [ + 'networkModel' => $networkModel + ]) +
+ @endforeach +
+
+ + +
+
+
+
+ +
+@endsection diff --git a/resources/views/fo/pages/produce/show.blade.php b/resources/views/fo/pages/produce/show.blade.php index 81b23a5..e505b67 100644 --- a/resources/views/fo/pages/produce/show.blade.php +++ b/resources/views/fo/pages/produce/show.blade.php @@ -132,6 +132,39 @@ --}} + {{-- NETWORKS --}} +
+
+
+
+

{{ $networkSection->h2_title }}

+
+
+
+
+ @foreach ($networkModels as $networkModel) +
+ @include('fo.partials.networks.slider-card', [ + 'networkModel' => $networkModel + ]) +
+ @endforeach +
+
+ + +
+
+
+
+
+
{{-- QUALITY --}} {{--
--}}
diff --git a/resources/views/fo/partials/networks/slider-card.blade.php b/resources/views/fo/partials/networks/slider-card.blade.php new file mode 100644 index 0000000..30b5862 --- /dev/null +++ b/resources/views/fo/partials/networks/slider-card.blade.php @@ -0,0 +1,8 @@ + diff --git a/routes/breadcrumbs-bo.php b/routes/breadcrumbs-bo.php index e95ce9b..d7e5411 100644 --- a/routes/breadcrumbs-bo.php +++ b/routes/breadcrumbs-bo.php @@ -1,9 +1,12 @@ 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'))); +}); diff --git a/routes/web-bo.php b/routes/web-bo.php index 27f01c0..eda9c71 100644 --- a/routes/web-bo.php +++ b/routes/web-bo.php @@ -1,10 +1,13 @@ 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']); diff --git a/routes/web-fo.php b/routes/web-fo.php index db425d3..59aad33 100644 --- a/routes/web-fo.php +++ b/routes/web-fo.php @@ -1,5 +1,6 @@ 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');