Merge branch 'trunk'

This commit is contained in:
Noah Lancien 2025-07-16 16:29:34 +02:00
commit e649ee7004
173 changed files with 5724 additions and 6577 deletions

View file

@ -18,11 +18,11 @@ enum ColorsEnum: int
* Custom added colors definition
*/
private const COLORS = [
self::redwine->name => 'rgb(165 25 60)',
self::orange->name => 'rgb(240 165 0)',
self::blue->name => 'rgb(95 155 210)',
self::redwine->name => 'rgb(165 25 60)',
self::orange->name => 'rgb(240 165 0)',
self::blue->name => 'rgb(95 155 210)',
self::lightgreen->name => 'rgb(180 190 0)',
self::brown->name => 'rgb(95 40 45)',
self::brown->name => 'rgb(95 40 45)',
];
/**

View file

@ -21,10 +21,7 @@ enum InputType: int
case string = 11;
case text = 12;
case url = 13;
/** Vimeo only */
case videoVimeo = 14;
/** Youtube only */
case videoYoutube = 15;
/** Youtube or Vimeo. */
case video = 16;
case videoVimeo = 14;
case videoYoutube = 15;
case video = 16;
}

View file

@ -23,12 +23,12 @@ enum CertificationsEnum: int
private const IMAGES = [
self::haltungsform3->name => "haltungsform3.png",
self::haltungsform4->name => "haltungsform4.png",
self::ecc->name => "ECC-Logo-green.svg",
self::nutriscoreA->name => "nutriscore-a.png",
self::nutriscoreB->name => "nutriscore-b.png",
self::nutriscoreC->name => "nutriscore-c.png",
self::nutriscoreD->name => "nutriscore-d.png",
self::nutriscoreE->name => "nutriscore-e.png",
self::ecc->name => "ECC-Logo-green.svg",
self::nutriscoreA->name => "nutriscore-a.png",
self::nutriscoreB->name => "nutriscore-b.png",
self::nutriscoreC->name => "nutriscore-c.png",
self::nutriscoreD->name => "nutriscore-d.png",
self::nutriscoreE->name => "nutriscore-e.png",
];
/**

View file

@ -19,12 +19,12 @@ enum PictoEnum : int
* Custom added images definition
*/
private const IMAGES = [
self::chicken->name => "chicken.png",
self::duck->name => "duck.png",
self::turkey->name => "turkey.png",
self::chicken->name => "chicken.png",
self::duck->name => "duck.png",
self::turkey->name => "turkey.png",
self::soupchicken->name => "soupchicken.png",
self::guineafowl->name => "guineafowl.png",
self::goose->name => "goose.png",
self::guineafowl->name => "guineafowl.png",
self::goose->name => "goose.png",
];
/**

View file

@ -11,6 +11,15 @@ enum StaticPageType: int
case contact = 1;
case legals = 2;
case confidentiality = 3;
case home = 4;
case products = 5;
case product = 6;
case recipes = 7;
case recipe = 8;
case newsPlural = 9;
case newsSingular = 10;
case concept = 11;
case store = 12;
/**
* Optionnal labels definition.
@ -21,5 +30,27 @@ enum StaticPageType: int
self::contact->name => 'enums.static_page_type.contact',
self::legals->name => 'enums.static_page_type.legals',
self::confidentiality->name => 'enums.static_page_type.confidentiality',
self::home->name => 'enums.static_page_type.home',
self::products->name => 'enums.static_page_type.products',
self::product->name => 'enums.static_page_type.product',
self::recipes->name => 'enums.static_page_type.recipes',
self::recipe->name => 'enums.static_page_type.recipe',
self::newsPlural->name => 'enums.static_page_type.newsPlural',
self::newsSingular->name => 'enums.static_page_type.newsSingular',
self::concept->name => 'enums.static_page_type.concept',
self::store->name => 'enums.static_page_type.store',
];
/**
* Get all editable pages.
*
* @return array
*/
public static function getEditableContentPages(): array
{
return [
self::legals,
self::confidentiality,
];
}
}

View file

@ -61,7 +61,7 @@ class ConceptController extends Controller
'error',
trans(
'You already created 8 :models. Please delete or edit an existing one.',
['models' => trans('models.classes.concepts')]
['models' => Str::of(trans('models.classes.concept'))->plural()]
)
);
}
@ -90,14 +90,14 @@ class ConceptController extends Controller
->route('bo.concepts.edit', $concept)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
});
}
@ -135,14 +135,14 @@ class ConceptController extends Controller
->route('bo.concepts.edit', $concept)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
});
}
@ -160,14 +160,14 @@ class ConceptController extends Controller
->route('bo.concepts.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.concepts'))]
['model' => trans('models.classes.concept')]
));
}
}

View file

@ -7,7 +7,6 @@ use App\Http\Requests\Bo\Homes\UpdateHomeRequest;
use App\Models\Home;
use App\Models\Product;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class HomeController extends Controller
{
@ -41,12 +40,12 @@ class HomeController extends Controller
->route('bo.homes.edit', $home)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.homes'))]
['model' => trans('models.classes.home')]
));
} //end if
return back()->with('success', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.homes'))]
['model' => trans('models.classes.home')]
));
});
}

View file

@ -10,9 +10,8 @@ use App\Models\Product;
use App\Models\Range;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelStatus;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class ProductController extends Controller
{
@ -88,14 +87,14 @@ class ProductController extends Controller
->route('bo.products.edit', $product)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
});
}
@ -136,14 +135,14 @@ class ProductController extends Controller
->route('bo.products.edit', $product)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
});
}
@ -163,14 +162,14 @@ class ProductController extends Controller
->route('bo.products.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.products'))]
['model' => trans('models.classes.product')]
));
});
}

View file

@ -10,7 +10,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class RangeController extends Controller
{
@ -72,14 +71,14 @@ class RangeController extends Controller
->route('bo.ranges.edit', $range)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.ranges'))]
['model' => trans('models.classes.range')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.ranges'))]
['model' => trans('models.classes.range')]
));
});
}
@ -111,7 +110,7 @@ class RangeController extends Controller
->route('bo.ranges.edit', $range)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.ranges'))]
['model' => trans('models.classes.range')]
));
} //end if
return back();
@ -131,14 +130,14 @@ class RangeController extends Controller
->route('bo.ranges.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.ranges'))]
['model' => trans('models.classes.range')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.ranges'))]
['model' => trans('models.classes.range')]
));
}
}

View file

@ -11,7 +11,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class RecipeController extends Controller
{
@ -77,14 +76,14 @@ class RecipeController extends Controller
->route('bo.recipes.edit', $recipe)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
});
}
@ -124,14 +123,14 @@ class RecipeController extends Controller
->route('bo.recipes.edit', $recipe)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
});
}
@ -151,14 +150,14 @@ class RecipeController extends Controller
->route('bo.recipes.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.recipes'))]
['model' => trans('models.classes.recipe')]
));
});
}

View file

@ -10,7 +10,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class SliderController extends Controller
{
@ -73,14 +72,14 @@ class SliderController extends Controller
->route('bo.sliders.edit', $slider)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
});
}
@ -115,14 +114,14 @@ class SliderController extends Controller
->route('bo.sliders.edit', $slider)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
});
}
@ -140,14 +139,14 @@ class SliderController extends Controller
->route('bo.sliders.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.sliders'))]
['model' => trans('models.classes.slider')]
));
}
}

View file

@ -7,7 +7,6 @@ use App\Http\Requests\Bo\StaticPages\UpdateStaticPageRequest;
use App\Models\StaticPage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StaticPageController extends Controller
{
@ -79,12 +78,12 @@ class StaticPageController extends Controller
if ($static_page->saveOrFail()) {
return redirect()->route('bo.static_pages.edit', $static_page)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
'model' => trans('models.classes.static_page')
]));
}
return redirect()->route('bo.static_pages.edit', $static_page)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
'model' => trans('models.classes.static_page')
]));
});
}

View file

@ -12,7 +12,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StoreController extends Controller
{
@ -77,14 +76,14 @@ class StoreController extends Controller
->route('bo.stores.edit', $store)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
});
}
@ -122,14 +121,14 @@ class StoreController extends Controller
->route('bo.stores.edit', $store)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
});
}
@ -147,14 +146,14 @@ class StoreController extends Controller
->route('bo.stores.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.stores'))]
['model' => trans('models.classes.store')]
));
}
}

View file

@ -10,7 +10,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StoreGroupController extends Controller
{
@ -72,14 +71,14 @@ class StoreGroupController extends Controller
->route('bo.storegroups.edit', $storeGroup)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
});
}
@ -111,14 +110,14 @@ class StoreGroupController extends Controller
->route('bo.storegroups.edit', $storegroup)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
});
}
@ -143,14 +142,14 @@ class StoreGroupController extends Controller
->route('bo.storegroups.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.storegroups'))]
['model' => trans('models.classes.storegroup')]
));
}
}

View file

@ -11,7 +11,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StoreRegionController extends Controller
{
@ -75,14 +74,14 @@ class StoreRegionController extends Controller
->route('bo.storeregions.edit', $storeregion)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
});
}
@ -122,14 +121,14 @@ class StoreRegionController extends Controller
->route('bo.storeregions.edit', $storeregion)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
});
}
@ -150,14 +149,14 @@ class StoreRegionController extends Controller
->route('bo.storeregions.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.storeregions'))]
['model' => trans('models.classes.storeregion')]
));
}
}

View file

@ -10,7 +10,6 @@ use App\Traits\Controllers\UpdateModelStatus;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StoreTypeController extends Controller
{
@ -72,14 +71,14 @@ class StoreTypeController extends Controller
->route('bo.storetypes.edit', $storetype)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
});
}
@ -114,14 +113,14 @@ class StoreTypeController extends Controller
->route('bo.storetypes.edit', $storetype)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
});
}
@ -142,14 +141,14 @@ class StoreTypeController extends Controller
->route('bo.storetypes.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.storetypes'))]
['model' => trans('models.classes.storetype')]
));
}
}

View file

@ -2,8 +2,10 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\Concept;
use App\Models\StaticPage;
class ConceptController extends Controller
{
@ -13,8 +15,9 @@ class ConceptController extends Controller
* @param \App\Models\Concept $concept
* @return \Illuminate\Contracts\View\View
*/
public function show(Concept $concept)
public function show(Concept $concept): \Illuminate\Contracts\View\View
{
return view('fo.pages.concepts.concept', ['conceptModel' => $concept]);
$staticPageModel = StaticPage::query()->where('type', StaticPageType::concept)->firstOrFail();
return view('fo.pages.concepts.concept', ['staticPageModel' => $staticPageModel, 'conceptModel' => $concept]);
}
}

View file

@ -12,23 +12,23 @@ use Illuminate\Support\Facades\Mail;
class ContactController extends Controller
{
/**
* Show contact page
* Show contact page.
*
* @return \Illuminate\Contracts\View\View
*/
public function contactForm()
public function contactForm(): \Illuminate\Contracts\View\View
{
$contactPage = StaticPage::query()->where('type', StaticPageType::contact)->first();
return view('fo.pages.contact', \compact('contactPage'));
$staticPageModel = StaticPage::query()->where('type', StaticPageType::contact)->firstOrFail();
return view('fo.pages.contact', \compact('staticPageModel'));
}
/**
* Submit contact form
* Submit contact form.
*
* @param \App\Http\Requests\Fo\ContactRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function sendContactForm(ContactRequest $request)
public function sendContactForm(ContactRequest $request): \Illuminate\Http\RedirectResponse
{
Mail::queue(new ContactMessageReceived(
first_name: $request->first_name,

View file

@ -13,7 +13,7 @@ class GroupController extends Controller
* @param integer $id
* @return \App\Models\StoreGroup
*/
public function show(int $id)
public function show(int $id): \App\Models\StoreGroup
{
return StoreGroup::query()->find($id);
}

View file

@ -2,9 +2,11 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\Home;
use App\Models\Slider;
use App\Models\StaticPage;
class HomeController extends Controller
{
@ -13,15 +15,16 @@ class HomeController extends Controller
*
* @return \Illuminate\Contracts\View\View
*/
public function index()
public function index(): \Illuminate\Contracts\View\View
{
$currentLocale = app()->currentLocale();
$home = Home::query()->firstOrFail();
$sliders = Slider::query()
->where('status', true)
->orderBy('order')
->whereJsonContains('locales', $currentLocale)
->get();
return view('fo.pages.home', compact('home', 'sliders'));
$staticPageModel = StaticPage::query()->where('type', StaticPageType::home)->firstOrFail();
$currentLocale = app()->currentLocale();
$home = Home::query()->firstOrFail();
$sliders = Slider::query()
->where('status', true)
->orderBy('order')
->whereJsonContains('locales', $currentLocale)
->get();
return view('fo.pages.home', compact('staticPageModel', 'home', 'sliders'));
}
}

View file

@ -2,8 +2,10 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\News;
use App\Models\StaticPage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
@ -13,10 +15,11 @@ class NewsController extends Controller
* News index
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\JsonResponse
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\JsonResponse
*/
public function index(Request $request)
public function index(Request $request): \Illuminate\Contracts\View\View|\Illuminate\Http\JsonResponse
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::newsPlural)->firstOrFail();
if ($request->wantsJson()) {
$currentLocale = app()->currentLocale();
$newsList = News::query()
@ -27,7 +30,7 @@ class NewsController extends Controller
return \response()->json(\collect($newsList->items())
->map(fn ($newsModel) => str($this->renderNews($newsModel))->toBase64()));
}
return view('fo.pages.news.index');
return view('fo.pages.news.index', compact('staticPageModel'));
}
/**
@ -36,8 +39,9 @@ class NewsController extends Controller
* @param \App\Models\News $publishedNews
* @return \Illuminate\Contracts\View\View
*/
public function show(News $publishedNews)
public function show(News $publishedNews): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::newsPlural)->firstOrFail();
$currentLocale = app()->currentLocale();
$relatedNewsList = News::query()
->where('id', '!=', $publishedNews->id)
@ -46,7 +50,8 @@ class NewsController extends Controller
->orderBy('order', 'DESC')
->limit(2)->get();
return view('fo.pages.news.show', [
'newsModel' => $publishedNews,
'staticPageModel' => $staticPageModel,
'newsModel' => $publishedNews,
'relatedNewsList' => $relatedNewsList
]);
}

View file

@ -2,36 +2,43 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\Product;
use App\Models\Range;
use App\Models\StaticPage;
use Illuminate\Contracts\Database\Eloquent\Builder;
class ProductController extends Controller
{
/**
* Products index
* Products index.
*
* @return \Illuminate\Contracts\View\View
*/
public function index()
public function index(): \Illuminate\Contracts\View\View
{
$ranges = Range::query()->where('status', true)
->whereHas('products', fn (Builder $q) => $q->where('status', true))
->with('products', fn (Builder $q) => $q->where('status', true)->orderBy('order'))
$staticPageModel = StaticPage::query()->where('type', StaticPageType::products)->firstOrFail();
$rangeModels = Range::query()->where('status', true)
->whereHas('products', fn(Builder $q) => $q->where('status', true))
->with('products', fn(Builder $q) => $q->where('status', true)->orderBy('order'))
->orderBy('order')
->get();
return view('fo.pages.products.index', compact(['ranges']));
->get();
return view('fo.pages.products.index', compact('staticPageModel', 'rangeModels'));
}
/**
* Product show
* Product show.
*
* @param \App\Models\Product $publishedProduct
* @return \Illuminate\Contracts\View\View
*/
public function show(Product $publishedProduct)
public function show(Product $publishedProduct): \Illuminate\Contracts\View\View
{
return view('fo.pages.products.show', ['productModel' => $publishedProduct]);
$staticPageModel = StaticPage::query()->where('type', StaticPageType::product)->firstOrFail();
return view('fo.pages.products.show', [
'staticPageModel' => $staticPageModel,
'productModel' => $publishedProduct,
]);
}
}

View file

@ -2,8 +2,10 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\Recipe;
use App\Models\StaticPage;
use Illuminate\Contracts\Database\Eloquent\Builder;
class RecipeController extends Controller
@ -13,13 +15,14 @@ class RecipeController extends Controller
*
* @return \Illuminate\Contracts\View\View
*/
public function index()
public function index(): \Illuminate\Contracts\View\View
{
$recipes = Recipe::query()->where('status', true)
$staticPageModel = StaticPage::query()->where('type', StaticPageType::recipes)->firstOrFail();
$recipeModels = Recipe::query()->where('status', true)
->whereHas('range', fn (Builder $q) => $q->where('status', true))
->orderBy('order')
->get();
return view('fo.pages.recipes.index', compact('recipes'));
return view('fo.pages.recipes.index', compact('staticPageModel', 'recipeModels'));
}
/**
@ -28,8 +31,12 @@ class RecipeController extends Controller
* @param \App\Models\Recipe $publishedRecipe
* @return \Illuminate\Contracts\View\View
*/
public function show(Recipe $publishedRecipe)
public function show(Recipe $publishedRecipe): \Illuminate\Contracts\View\View
{
return view('fo.pages.recipes.show', ['recipeModel' => $publishedRecipe]);
$staticPageModel = StaticPage::query()->where('type', StaticPageType::recipe)->firstOrFail();
return view('fo.pages.recipes.show', [
'staticPageModel' => $staticPageModel,
'recipeModel' => $publishedRecipe,
]);
}
}

View file

@ -13,7 +13,7 @@ class RegionController extends Controller
* @param integer $id
* @return \App\Models\StoreRegion;
*/
public function show(int $id)
public function show(int $id): \App\Models\StoreRegion
{
return StoreRegion::find($id);
}

View file

@ -16,7 +16,7 @@ class StaticPageController extends Controller
*/
public function legals(StaticPage $legalPage)
{
$legalPage = StaticPage::query()->where('type', StaticPageType::legals)->first();
$legalPage = StaticPage::query()->where('type', StaticPageType::legals)->firstOrFail();
return view('fo.pages.legals', ['staticPageModel' => $legalPage]);
}
@ -28,7 +28,7 @@ class StaticPageController extends Controller
*/
public function policies(StaticPage $policiesPage)
{
$policiesPage = StaticPage::query()->where('type', StaticPageType::confidentiality)->first();
$policiesPage = StaticPage::query()->where('type', StaticPageType::confidentiality)->firstOrFail();
return view('fo.pages.privacy', ['staticPageModel' => $policiesPage]);
}
}

View file

@ -2,21 +2,33 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\StoreFinderRequest;
use App\Http\Resources\StoreFinderResource;
use App\Models\StaticPage;
use App\Models\Store;
use Illuminate\Http\JsonResponse;
class StoreController extends Controller
{
/**
* Store by city
* Store page.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::store)->firstOrFail();
return view('fo.pages.storefinder', compact('staticPageModel'));
}
/**
* Store by city.
*
* @param \App\Http\Requests\Api\StoreFinderRequest $request
* @return \Illuminate\Http\JsonResponse;
* @return \Illuminate\Http\JsonResponse
*/
public function city(StoreFinderRequest $request): JsonResponse
public function city(StoreFinderRequest $request): \Illuminate\Http\JsonResponse
{
return \response()->json(new StoreFinderResource(Store::query()
->where('city', 'LIKE', '%' . $request->input('city') . '%')

View file

@ -11,7 +11,7 @@ class ChangeOrderRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -21,7 +21,7 @@ class ChangeOrderRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'direction' => $this->direction === 'up' ? true : false
@ -33,7 +33,7 @@ class ChangeOrderRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
return [
'direction' => 'required|boolean',

View file

@ -25,7 +25,7 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return (auth('backend')->check() && Concept::count() < 9);
}
@ -35,7 +35,7 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug(strip_tags($this->input('name')))
@ -48,25 +48,21 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'name' => 'required|min:3|max:70',
'slug' => 'unique_translation:concepts',
'title' => 'required|min:3|max:70',
'title_background_color' => [
'required', new Enum(ColorsEnum::class)
],
'subtitle' => 'required|min:3|max:70',
'description' => 'required|string|min:15',
'data' => 'present|array',
'data.*' => 'required|array',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'name' => 'required|min:3|max:70',
'slug' => 'unique_translation:concepts',
'title' => 'required|min:3|max:70',
'title_background_color' => ['required', new Enum(ColorsEnum::class)],
'subtitle' => 'required|min:3|max:70',
'description' => 'required|string|min:15',
'data' => 'present|array',
'data.*' => 'required|array',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
];
return \array_merge(
parent::rules(),
@ -83,20 +79,18 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
public function attributes()
{
return [
'seo_title' => trans('titre') . ' seo',
'seo_title' => trans('titre') . ' seo',
'seo_description' => trans('description') . ' seo',
'name' => trans('name of the concept'),
'slug' => trans('slug of the concept'),
'title' => trans('title of the concept'),
'subtitle' => trans('subtitle of the concept'),
'description' => trans('description of the concept'),
'data' => trans('values of the data'),
'data.*.value' => trans('value of the data'),
'picture' => trans('illustration'),
'picture_alt' => trans('alt attribute of the image'),
'picture_title' => trans('title attribute of the image'),
'name' => trans('name of the concept'),
'slug' => trans('slug of the concept'),
'title' => trans('title of the concept'),
'subtitle' => trans('subtitle of the concept'),
'description' => trans('description of the concept'),
'data' => trans('values of the data'),
'data.*.value' => trans('value of the data'),
'picture' => trans('illustration'),
'picture_alt' => trans('alt attribute of the image'),
'picture_title' => trans('title attribute of the image'),
];
}
}

View file

@ -12,7 +12,7 @@ class UpdateConceptRequest extends StoreConceptRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'slug' => UniqueTranslationRule::for('concepts')->ignore($this->concept->id),

View file

@ -14,7 +14,7 @@ class UpdateHomeRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -24,7 +24,7 @@ class UpdateHomeRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->mergePicture('part3_picture');
}
@ -34,28 +34,25 @@ class UpdateHomeRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'part1_title' => 'required|min:3|max:70',
'part1_subtitle' => 'required|min:3|max:70',
'part1_text_1' => 'required|string|min:15',
'part1_text_2' => 'required|string|min:15',
'part1_text_3' => 'required|string|min:15',
'part2_title' => 'required|min:3|max:70',
'part2_subtitle' => 'required|min:3|max:70',
'part2_text' => 'required|string|min:15',
'part2_list' => 'present|array',
'part2_list.*' => 'required|array',
'part2_list.*.value' => 'required|string|min:3|max:255',
'part2_product1_id' => 'required|exists:products,id',
'part2_product2_id' => 'required|exists:products,id',
'part3_picture_alt' => 'required|min:3|max:255',
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'part1_title' => 'required|min:3|max:70',
'part1_subtitle' => 'required|min:3|max:70',
'part1_text_1' => 'required|string|min:15',
'part1_text_2' => 'required|string|min:15',
'part1_text_3' => 'required|string|min:15',
'part2_title' => 'required|min:3|max:70',
'part2_subtitle' => 'required|min:3|max:70',
'part2_text' => 'required|string|min:15',
'part2_list' => 'present|array',
'part2_list.*' => 'required|array',
'part2_list.*.value' => 'required|string|min:3|max:255',
'part2_product1_id' => 'required|exists:products,id',
'part2_product2_id' => 'required|exists:products,id',
'part3_picture_alt' => 'required|min:3|max:255',
'part3_picture_title' => 'required|min:3|max:255',
];
return \array_merge(
@ -69,28 +66,25 @@ class UpdateHomeRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'seo_title' => trans('titre') . ' seo',
'seo_description' => trans('description') . ' seo',
'part1_title' => trans('title part.1'),
'part1_subtitle' => trans('subtitle part.1'),
'part1_text_1' => trans('text 1 part.1'),
'part1_text_2' => trans('text 2 part.1'),
'part1_text_3' => trans('text 3 part.1'),
'part2_title' => trans('title part.2'),
'part2_subtitle' => trans('subtitle part.2'),
'part2_text' => trans('text part.2'),
'part2_list' => trans('values of the list part.2'),
'part2_list.*.value' => trans('value of the list part.2'),
'part2_product1_id' => trans('value of the first product part.2'),
'part2_product2_id' => trans('value of the second product part.2'),
'part3_picture' => trans('illustration'),
'part3_picture_alt' => trans('alt attribute of the image'),
'seo_title' => trans('titre') . ' seo',
'seo_description' => trans('description') . ' seo',
'part1_title' => trans('title part.1'),
'part1_subtitle' => trans('subtitle part.1'),
'part1_text_1' => trans('text 1 part.1'),
'part1_text_2' => trans('text 2 part.1'),
'part1_text_3' => trans('text 3 part.1'),
'part2_title' => trans('title part.2'),
'part2_subtitle' => trans('subtitle part.2'),
'part2_text' => trans('text part.2'),
'part2_list' => trans('values of the list part.2'),
'part2_list.*.value' => trans('value of the list part.2'),
'part2_product1_id' => trans('value of the first product part.2'),
'part2_product2_id' => trans('value of the second product part.2'),
'part3_picture' => trans('illustration'),
'part3_picture_alt' => trans('alt attribute of the image'),
'part3_picture_title' => trans('title attribute of the image'),
];
}

View file

@ -19,7 +19,7 @@ class StoreNewsRequest extends UpdateMiniCrudRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -29,14 +29,14 @@ class StoreNewsRequest extends UpdateMiniCrudRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug(strip_tags($this->input('name'))),
'status' => $this->boolean('status'),
'publish_at' => $this->date('publish_at'),
'slug' => Str::slug(strip_tags($this->input('name'))),
'status' => $this->boolean('status'),
'publish_at' => $this->date('publish_at'),
'unpublish_at' => $this->date('unpublish_at'),
'locales' => \collect($this->input('locales'))->filter()->unique()->all()
'locales' => \collect($this->input('locales'))->filter()->unique()->all()
]);
}
@ -45,25 +45,26 @@ class StoreNewsRequest extends UpdateMiniCrudRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'slug' => 'unique_translation:news',
'title' => 'required|min:3|max:70',
'subtitle' => 'required|min:3|max:70',
'content' => 'required|string|min:15',
'locales' => 'required|array',
'locales.*' => ['required', \sprintf('in:%s', \implode(',', \config('app.locales')))],
'data' => 'present|array',
'data.*' => 'required|array',
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'slug' => 'unique_translation:news',
'title' => 'required|min:3|max:70',
'subtitle' => 'required|min:3|max:70',
'content' => 'required|string|min:15',
'locales' => 'required|array',
'locales.*' => [
'required',
\sprintf('in:%s', \implode(',', \config('app.locales')))
],
'data' => 'present|array',
'data.*' => 'required|array',
'data.bloc_1_display_picture.value' => 'required|accepted',
'status' => 'required|boolean',
'publish_at' => 'required|date',
'unpublish_at' => 'sometimes|nullable|date'
'status' => 'required|boolean',
'publish_at' => 'required|date',
'unpublish_at' => 'sometimes|nullable|date'
];
return \array_merge(
parent::rules(),
@ -76,17 +77,17 @@ class StoreNewsRequest extends UpdateMiniCrudRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'seo_title' => trans('titre') . ' seo',
'seo_description' => trans('description') . ' seo',
'slug' => trans('slug of the news'),
'subtitle' => trans('subtitle of the news'),
'content' => trans('content of the news'),
'data' => trans('values of the data'),
'data.*.value' => trans('value of the data'),
'seo_title' => trans('titre') . ' seo',
'seo_description' => trans('description') . ' seo',
'slug' => trans('slug of the news'),
'title' => trans('title of the news'),
'subtitle' => trans('subtitle of the news'),
'content' => trans('content of the news'),
'data' => trans('values of the data'),
'data.*.value' => trans('value of the data'),
'data.bloc_1_display_picture.value' => trans('visibility of the first picture')
];
}

View file

@ -12,7 +12,7 @@ class UpdateNewsRequest extends StoreNewsRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'slug' => UniqueTranslationRule::for('news')->ignore($this->news->id),

View file

@ -15,7 +15,7 @@ class StoreProductRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -25,14 +25,14 @@ class StoreProductRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug(strip_tags($this->input('label'))),
'status' => $this->boolean('status'),
'list' => $this->input('list') ?? [],
'slug' => Str::slug(strip_tags($this->input('label'))),
'status' => $this->boolean('status'),
'list' => $this->input('list') ?? [],
'nutritionnal_values' => $this->input('nutritionnal_values') ?? [],
'certifications' => \collect($this->input('certifications'))->all(),
'certifications' => \collect($this->input('certifications'))->all(),
]);
$this->mergePicture('picture');
}
@ -42,22 +42,22 @@ class StoreProductRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'label' => 'required|min:3|max:255',
'slug' => 'unique_translation:products',
'description' => 'required|string|min:15',
'marinade' => 'nullable|string|min:15',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'picture_arrow_alt' => 'required_with:picture_arrow|min:3|max:255',
'picture_arrow_title' => 'required_with:picture_arrow|min:3|max:255',
'certifications' => 'present|array',
'certifications.*' => 'required|integer',
'list' => [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'label' => 'required|min:3|max:255',
'slug' => 'unique_translation:products',
'description' => 'required|string|min:15',
'marinade' => 'nullable|string|min:15',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'picture_arrow_alt' => 'required_with:picture_arrow|min:3|max:255',
'picture_arrow_title' => 'required_with:picture_arrow|min:3|max:255',
'certifications' => 'present|array',
'certifications.*' => 'required|integer',
'list' => [
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
'present', 'array', function ($attribute, array $value, $fail) {
if (1 > count($value)) {
@ -65,9 +65,9 @@ class StoreProductRequest extends FormRequest
}
}
],
'list.*' => 'required|array',
'list.*.value' => 'nullable|string|min:3|max:255',
'nutritionnal_values' => [
'list.*' => 'required|array',
'list.*.value' => 'nullable|string|min:3|max:255',
'nutritionnal_values' => [
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
'present', 'array', function ($attribute, array $value, $fail) {
if (1 > count($value)) {
@ -75,11 +75,11 @@ class StoreProductRequest extends FormRequest
}
}
],
'nutritionnal_values.*' => 'required|array',
'nutritionnal_values.*' => 'required|array',
'nutritionnal_values.*.label' => 'nullable|string|min:3|max:255',
'nutritionnal_values.*.value' => 'nullable|string|min:1|max:255',
'range_id' => 'required|exists:ranges,id',
'status' => 'required|boolean'
'range_id' => 'required|exists:ranges,id',
'status' => 'required|boolean'
];
return \array_merge(
$rules,
@ -96,25 +96,25 @@ class StoreProductRequest extends FormRequest
public function attributes(): array
{
return [
'seo_title' => trans('title') . ' seo',
'seo_description' => trans('description') . ' seo',
'label' => trans('label'),
'slug' => trans('slug'),
'description' => trans('description'),
'marinade' => trans('marinade'),
'picture_alt' => trans('picture_alt'),
'picture_title' => trans('picture_title'),
'picture_arrow' => trans('picture_arrow'),
'picture_arrow_alt' => trans('picture_arrow_alt'),
'picture_arrow_title' => trans('picture_arrow_title'),
'certifications' => trans('certifications'),
'certifications.*' => trans('value(s) of certifications'),
'list' => trans('list'),
'nutritionnal_values' => trans('nutritionnal_values'),
'seo_title' => trans('title') . ' seo',
'seo_description' => trans('description') . ' seo',
'label' => trans('label'),
'slug' => trans('slug'),
'description' => trans('description'),
'marinade' => trans('marinade'),
'picture_alt' => trans('picture_alt'),
'picture_title' => trans('picture_title'),
'picture_arrow' => trans('picture_arrow'),
'picture_arrow_alt' => trans('picture_arrow_alt'),
'picture_arrow_title' => trans('picture_arrow_title'),
'certifications' => trans('certifications'),
'certifications.*' => trans('value(s) of certifications'),
'list' => trans('list'),
'nutritionnal_values' => trans('nutritionnal_values'),
'nutritionnal_values.*.label' => trans('label(s) of nutritionnal_values'),
'nutritionnal_values.*.value' => trans('value(s) of nutritionnal_values'),
'range_id' => trans('range'),
'status' => trans('publish'),
'range_id' => trans('range'),
'status' => trans('publish'),
];
}
}

View file

@ -11,7 +11,7 @@ class UpdateProductRequest extends StoreProductRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',

View file

@ -17,7 +17,7 @@ class StoreRangeRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -27,10 +27,10 @@ class StoreRangeRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug(strip_tags($this->input('label'))),
'slug' => Str::slug(strip_tags($this->input('label'))),
'status' => $this->boolean('status'),
]);
}
@ -40,15 +40,15 @@ class StoreRangeRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
return [
'seo_title' => 'required|min:3|max:70',
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'label' => 'required|min:3|max:255',
'slug' => 'unique_translation:ranges',
'picto' => [new Enum(PictoEnum::class)],
'status' => 'required|boolean'
'label' => 'required|min:3|max:255',
'slug' => 'unique_translation:ranges',
'picto' => [new Enum(PictoEnum::class)],
'status' => 'required|boolean'
];
}
@ -60,12 +60,12 @@ class StoreRangeRequest extends FormRequest
public function attributes(): array
{
return [
'seo_title' => trans('title') . ' seo',
'seo_title' => trans('title') . ' seo',
'seo_description' => trans('description') . ' seo',
'label' => trans('label'),
'picto' => trans('picto'),
'slug' => trans('slug'),
'status' => trans('publish')
'label' => trans('label'),
'picto' => trans('picto'),
'slug' => trans('slug'),
'status' => trans('publish')
];
}
}

View file

@ -2,9 +2,7 @@
namespace App\Http\Requests\Bo\Ranges;
use App\Enums\Ranges\PictoEnum;
use CodeZero\UniqueTranslation\UniqueTranslationRule;
use Illuminate\Validation\Rules\Enum;
class UpdateRangeRequest extends StoreRangeRequest
{
@ -13,15 +11,14 @@ class UpdateRangeRequest extends StoreRangeRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
return [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'label' => 'required|min:3|max:255',
$rules = [
'slug' => UniqueTranslationRule::for('ranges')->ignore($this->range->id),
'picto' => [new Enum(PictoEnum::class)],
'status' => 'required|boolean'
];
return \array_merge(
parent::rules(),
$rules,
);
}
}

View file

@ -17,7 +17,7 @@ class StoreRecipeRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -27,10 +27,10 @@ class StoreRecipeRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug(strip_tags($this->input('name'))),
'slug' => Str::slug(strip_tags($this->input('name'))),
'status' => $this->boolean('status'),
]);
$this->mergePicture('picture');
@ -42,18 +42,18 @@ class StoreRecipeRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'name' => 'required|min:3|max:255',
'slug' => 'unique_translation:recipes',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'picture_thumbnail_alt' => 'required|min:3|max:255',
'seo_title' => 'required|min:3|max:70',
'seo_description' => 'required|min:50|max:160',
'name' => 'required|min:3|max:255',
'slug' => 'unique_translation:recipes',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'picture_thumbnail_alt' => 'required|min:3|max:255',
'picture_thumbnail_title' => 'required|min:3|max:255',
'ingredients' => [
'ingredients' => [
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
'present', 'array', function ($attribute, array $value, $fail) {
if (1 > count($value)) {
@ -61,16 +61,16 @@ class StoreRecipeRequest extends FormRequest
}
}
],
'ingredients.*' => 'nullable|array',
'ingredients.*.header' => 'nullable|string|min:2|max:255',
'ingredients.*.value' => 'string|min:2|max:255',
'teaser' => 'required|min:50|max:160',
'steps' => 'required|string|min:15',
'difficulty' => [new Enum(DifficultyEnum::class)],
'duration' => 'required|string|min:1|max:150',
'tips' => 'nullable|string|min:15',
'range_id' => 'required|exists:ranges,id',
'status' => 'required|boolean'
'ingredients.*' => 'nullable|array',
'ingredients.*.header' => 'nullable|string|min:2|max:255',
'ingredients.*.value' => 'string|min:2|max:255',
'teaser' => 'required|min:50|max:160',
'steps' => 'required|string|min:15',
'difficulty' => [new Enum(DifficultyEnum::class)],
'duration' => 'required|string|min:1|max:150',
'tips' => 'nullable|string|min:15',
'range_id' => 'required|exists:ranges,id',
'status' => 'required|boolean'
];
return \array_merge(
$rules,
@ -87,21 +87,21 @@ class StoreRecipeRequest extends FormRequest
public function attributes(): array
{
return [
'seo_title' => trans('title') . ' seo',
'seo_description' => trans('description') . ' seo',
'name' => trans('name'),
'slug' => trans('slug'),
'ingredients' => trans('ingredients'),
'seo_title' => trans('title') . ' seo',
'seo_description' => trans('description') . ' seo',
'name' => trans('name'),
'slug' => trans('slug'),
'ingredients' => trans('ingredients'),
'ingredients.*.header' => trans('header in the list of ingredients'),
'ingredients.*.label' => trans('value of ingredients'),
'ingredients.*.value' => trans('value of ingredients'),
'teaser' => trans('teaser'),
'steps' => trans('steps'),
'difficulty' => trans('difficulty'),
'duration' => trans('duration'),
'tips' => trans('tips'),
'range_id' => trans('range'),
'status' => trans('publish')
'ingredients.*.label' => trans('value of ingredients'),
'ingredients.*.value' => trans('value of ingredients'),
'teaser' => trans('teaser'),
'steps' => trans('steps'),
'difficulty' => trans('difficulty'),
'duration' => trans('duration'),
'tips' => trans('tips'),
'range_id' => trans('range'),
'status' => trans('publish')
];
}
}

View file

@ -11,7 +11,7 @@ class UpdateRecipeRequest extends StoreRecipeRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'slug' => UniqueTranslationRule::for('recipes')->ignore($this->recipe->id)
@ -19,8 +19,6 @@ class UpdateRecipeRequest extends StoreRecipeRequest
return \array_merge(
parent::rules(),
$rules,
$this->pictureRules('picture', 1600, 900, 1600, 900, true),
$this->pictureRules('picture_thumbnail', 430, 242, 430, 242, true),
);
}
}

View file

@ -23,7 +23,7 @@ class StoreSliderRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -33,16 +33,16 @@ class StoreSliderRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'link_new_tab' => $this->boolean('link_new_tab'),
'status' => $this->boolean('status'),
'publish_at' => $this->input('publish_at') ? \str_replace('T', ' ', $this->input('publish_at')) : null,
'status' => $this->boolean('status'),
'publish_at' => $this->input('publish_at') ? \str_replace('T', ' ', $this->input('publish_at')) : null,
'unpublish_at' => $this->input('unpublish_at') ?
\str_replace('T', ' ', $this->input('unpublish_at')) :
null,
'locales' => \collect($this->input('locales'))->filter()->unique()->all()
'locales' => \collect($this->input('locales'))->filter()->unique()->all()
]);
$this->mergePicture('picture');
}
@ -52,23 +52,23 @@ class StoreSliderRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'type' => [new Enum(TypeEnum::class)],
'title' => 'required|min:3|max:70',
'subtitle' => 'required|min:3|max:70',
'description' => 'required|string|min:15',
'link' => 'required|url',
'link_title' => 'required|min:3|max:255',
'link_new_tab' => 'required|boolean',
'picture_alt' => 'required|min:3|max:255',
'type' => [new Enum(TypeEnum::class)],
'title' => 'required|min:3|max:70',
'subtitle' => 'required|min:3|max:70',
'description' => 'required|string|min:15',
'link' => 'required|url',
'link_title' => 'required|min:3|max:255',
'link_new_tab' => 'required|boolean',
'picture_alt' => 'required|min:3|max:255',
'picture_title' => 'required|min:3|max:255',
'status' => 'required|boolean',
'locales' => 'required|array',
'locales.*' => ['required', \sprintf('in:%s', \implode(',', \config('app.locales')))],
'publish_at' => 'sometimes|nullable|date',
'unpublish_at' => 'sometimes|nullable|date'
'status' => 'required|boolean',
'locales' => 'required|array',
'locales.*' => ['required', \sprintf('in:%s', \implode(',', \config('app.locales')))],
'publish_at' => 'sometimes|nullable|date',
'unpublish_at' => 'sometimes|nullable|date'
];
return \array_merge(
$rules,
@ -81,20 +81,20 @@ class StoreSliderRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'type' => trans('type of slider'),
'title' => trans('title of the slide'),
'subtitle' => trans('subtitle of the slide'),
'description' => trans('description of the slide'),
'link' => trans('link of the slide'),
'link_title' => trans('title of link'),
'link_new_tab' => trans('open the link in the new tab'),
'picture' => trans('illustration'),
'picture_alt' => trans('alt attribute of the image'),
'type' => trans('type of slider'),
'title' => trans('title of the slide'),
'subtitle' => trans('subtitle of the slide'),
'description' => trans('description of the slide'),
'link' => trans('link of the slide'),
'link_title' => trans('title of link'),
'link_new_tab' => trans('open the link in the new tab'),
'picture' => trans('illustration'),
'picture_alt' => trans('alt attribute of the image'),
'picture_title' => trans('title attribute of the image'),
'status' => trans('status of the slide'),
'status' => trans('status of the slide'),
];
}
}

View file

@ -25,8 +25,12 @@ class UpdateStaticPageRequest extends FormRequest
*/
public function prepareForValidation(): void
{
/** @var \App\Models\StaticPage $staticPageModel */
$staticPageModel = request()->route()->parameter('static_page');
$this->merge([
'content' => (string)Str::of($this->input('content'))
'content' => (in_array($staticPageModel->type, \App\Enums\StaticPageType::getEditableContentPages()))
? Str::of($this->input('content'))->value()
: null
]);
}
@ -41,7 +45,7 @@ class UpdateStaticPageRequest extends FormRequest
'seo_title' => 'required|min:45|max:70',
'seo_description' => 'required|min:50|max:160',
'title' => 'required|min:3|max:255',
'content' => 'present',
'content' => 'present|string|nullable'
];
}

View file

@ -14,7 +14,7 @@ class StoreStoreGroupRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -24,7 +24,7 @@ class StoreStoreGroupRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->mergePicture('picture');
}
@ -34,7 +34,7 @@ class StoreStoreGroupRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => 'required|min:3|max:255',
@ -50,7 +50,7 @@ class StoreStoreGroupRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'name' => trans('name'),

View file

@ -12,7 +12,7 @@ class UpdateStoreGroupRequest extends StoreStoreGroupRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => [

View file

@ -14,7 +14,7 @@ class StoreStoreRegionRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -24,7 +24,7 @@ class StoreStoreRegionRequest extends FormRequest
*
* @return void
*/
protected function prepareForValidation()
protected function prepareForValidation(): void
{
$this->mergePicture('picture');
}
@ -34,10 +34,10 @@ class StoreStoreRegionRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => 'required|min:3|max:255',
'name' => 'required|min:3|max:255',
'group_id' => 'required|exists:store_groups,id',
];
return \array_merge(
@ -51,10 +51,10 @@ class StoreStoreRegionRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'name' => trans('name'),
'name' => trans('name'),
'group_id' => trans('group'),
];
}

View file

@ -12,7 +12,7 @@ class UpdateStoreRegionRequest extends StoreStoreRegionRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => [

View file

@ -11,7 +11,7 @@ class StoreStoreTypeRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -21,7 +21,7 @@ class StoreStoreTypeRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => 'required|min:3|max:255',
@ -36,7 +36,7 @@ class StoreStoreTypeRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'name' => trans('name'),

View file

@ -12,7 +12,7 @@ class UpdateStoreTypeRequest extends StoreStoreTypeRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'name' => [

View file

@ -14,7 +14,7 @@ class StoreStoreRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -24,15 +24,15 @@ class StoreStoreRequest extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$rules = [
'state' => 'required|min:3|max:255',
'type_id' => 'required|exists:store_types,id',
'street' => 'required|min:3|max:255',
'zipcode' => 'required|min:0|max:5',
'city' => 'required|min:3|max:255',
'latitude' => 'required|between:-90,90|decimal:0,8',
'state' => 'required|min:3|max:255',
'type_id' => 'required|exists:store_types,id',
'street' => 'required|min:3|max:255',
'zipcode' => 'required|min:0|max:5',
'city' => 'required|min:3|max:255',
'latitude' => 'required|between:-90,90|decimal:0,8',
'longitude' => 'required|between:-180,180|decimal:0,8',
'region_id' => 'required|exists:store_regions,id',
];
@ -46,15 +46,15 @@ class StoreStoreRequest extends FormRequest
*
* @return array
*/
public function attributes()
public function attributes(): array
{
return [
'state' => trans('State'),
'type_id' => trans('Type'),
'street' => trans('Street'),
'zipcode' => trans('Zipcode'),
'city' => trans('City'),
'latitude' => trans('Latitude'),
'state' => trans('State'),
'type_id' => trans('Type'),
'street' => trans('Street'),
'zipcode' => trans('Zipcode'),
'city' => trans('City'),
'latitude' => trans('Latitude'),
'longitude' => trans('Longitude'),
'region_id' => trans('Region'),
];

View file

@ -23,7 +23,7 @@ abstract class UpdateMiniCrudRequest extends FormRequest
*
* @return boolean
*/
public function authorize()
public function authorize(): bool
{
return auth('backend')->check();
}
@ -36,7 +36,7 @@ abstract class UpdateMiniCrudRequest extends FormRequest
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
*/
public function rules()
public function rules(): array
{
// phpcs:enable
$rules = [];
@ -112,11 +112,11 @@ abstract class UpdateMiniCrudRequest extends FormRequest
}) : $input['dimensions'];
// * Adapt dimensions
$sizes = (object)[
$sizes = (object) [
'minHeight' => $dim['height'],
'maxHeight' => $dim['height'],
'minWith' => $dim['width'],
'maxWith' => $dim['width'],
'minWith' => $dim['width'],
'maxWith' => $dim['width'],
];
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate(

View file

@ -26,10 +26,10 @@ class ContactRequest extends FormRequest
public function rules(): array
{
return [
'first_name' => 'required|min:1',
'last_name' => 'required|min:1',
'email' => 'required|email:rfc,spoof,dns,strict',
'message' => 'required|string|min:10',
'first_name' => 'required|min:1',
'last_name' => 'required|min:1',
'email' => 'required|email:rfc,spoof,dns,strict',
'message' => 'required|string|min:10',
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
'g-recaptcha-response' => function (string $attribute, mixed $value, \Closure $fail) {
try {

View file

@ -19,14 +19,14 @@ class StoreFinderResource extends ResourceCollection
{
// phpcs:enable
return $this->collection->map(fn (Store $store) => [
'name' => $store->storeRegion->storeGroup->name,
'type' => $store->storeType->name,
'street' => $store->street,
'zipcode' => $store->zipcode,
'city' => $store->city,
'latitude' => $store->latitude,
'name' => $store->storeRegion->storeGroup->name,
'type' => $store->storeType->name,
'street' => $store->street,
'zipcode' => $store->zipcode,
'city' => $store->city,
'latitude' => $store->latitude,
'longitude' => $store->longitude,
'picture' => $store->storeRegion->storeGroup->picture,
'picture' => $store->storeRegion->storeGroup->picture,
])->all();
}
}

View file

@ -4,10 +4,48 @@ namespace App\Interfaces\Models;
interface Publishable
{
/**
* Get status attribute.
*
* @return boolean
*/
public function getStatus(): bool;
/**
* Set status attribute.
*
* @param boolean $status
* @return void
*/
public function setStatus(bool $status): void;
/**
* Get publish_at attribute.
*
* @return \Carbon\Carbon|null
*/
public function getPublishAt(): ?\Carbon\Carbon;
/**
* Set publish_at attribute.
*
* @param \Carbon\Carbon|null $date
* @return void
*/
public function setPublishAt(?\Carbon\Carbon $date): void;
/**
* Get unpublish_at attribute.
*
* @return \Carbon\Carbon|null
*/
public function getUnpublishAt(): ?\Carbon\Carbon;
/**
* Set unpublish_at attribute.
*
* @param \Carbon\Carbon|null $date
* @return void
*/
public function setUnpublishAt(?\Carbon\Carbon $date): void;
}

View file

@ -24,7 +24,7 @@ class NewsStatusUpdate
->where('status', false)->get();
Log::debug(__CLASS__ . " news to publish " . $newsListToPublish->count());
foreach ($newsListToPublish as $news) {
$news->status = true;
$news->status = true;
$news->saveOrFail();
}
/** @var \Illuminate\Database\Eloquent\Collection<array-key, \App\Models\News> */
@ -32,7 +32,7 @@ class NewsStatusUpdate
->where('status', true)->get();
Log::debug(__CLASS__ . " news to unpublish " . $newsListToPublish->count());
foreach ($newsListToUnPublish as $news) {
$news->status = false;
$news->status = false;
$news->saveOrFail();
}
}

View file

@ -402,7 +402,7 @@ class ToolboxHelper
if (!(is_object($input) or is_array($input))) {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
$ret = (array)$input;
$ret = (array) $input;
foreach ($ret as &$item) {
// Recursively process EACH element only if not scalar.
$item = (is_object($item) or is_array($item)) ?
@ -425,7 +425,7 @@ class ToolboxHelper
if (!(is_object($input) or is_array($input))) {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
$ret = (object)$input;
$ret = (object) $input;
foreach ($ret as &$item) {
// Recursively process EACH element only if not scalar.
$item = (is_object($item) or is_array($item)) ?

View file

@ -13,6 +13,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
use Uwil\Seo\Laravel\Traits\SeoTrait;
@ -32,13 +35,14 @@ use Uwil\Seo\Laravel\Traits\SeoTrait;
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class News extends Model implements SeoInterface, Publishable
class News extends Model implements SeoInterface, Publishable, SchemaOrgInterface
{
use HasFactory;
use HasTranslations;
use MiniCrudModel;
use SeoTrait;
use IsPublishable;
use SchemaOrgTrait;
/**
* The attributes that are mass assignable.
@ -63,8 +67,11 @@ class News extends Model implements SeoInterface, Publishable
* @var array<string, string>
*/
protected $casts = [
'data' => 'object',
'locales' => 'array',
'data' => 'object',
'locales' => 'array',
'status' => 'bool',
'publish_at' => 'datetime',
'unpublish_at' => 'datetime'
];
/**
@ -139,8 +146,8 @@ class News extends Model implements SeoInterface, Publishable
case InputType::text->value:
FileStorageHelper::removeModelFilesOfHtml($input['text']);
break;
} //end switch
} //end foreach
}
}
}
/**
@ -156,11 +163,11 @@ class News extends Model implements SeoInterface, Publishable
->groupBy(fn($value, $key) => \collect(\explode('_', $key))->take(2)->implode('_'))
->filter(fn(Collection $blocks) => \collect($blocks->first())->get('value'))
->map(function (Collection $blocks) {
$pictureBlock = (object)$blocks->last();
return (object)[
$pictureBlock = (object) $blocks->last();
return (object) [
'value' => $pictureBlock->value,
'title' => $pictureBlock->title,
'alt' => $pictureBlock->alt
'alt' => $pictureBlock->alt
];
})->values();
}
@ -258,21 +265,50 @@ class News extends Model implements SeoInterface, Publishable
bool $required = false,
): array {
$data["bloc_{$index}_display_picture"] = [
'label' => "Bloc {$index} - Display picture",
'label' => "Bloc {$index} - Display picture",
'inputType' => InputType::boolean->value,
'value' => $required
'value' => $required
];
$data["bloc_{$index}_image"] = [
'label' => "Bloc {$index} - Image",
'label' => "Bloc {$index} - Image",
'dimensions' => ['width' => 770, 'height' => 770],
'inputType' => InputType::image->value,
'alt' => $imgAlt,
'title' => $imgTitle,
'value' => $img,
'validate' => "required_if:data.bloc_{$index}_display_picture.value,true|nullable",
'required' => $required
'inputType' => InputType::image->value,
'alt' => $imgAlt,
'title' => $imgTitle,
'value' => $img,
'validate' => "required_if:data.bloc_{$index}_display_picture.value,true|nullable",
'required' => $required
];
return $data;
}
/**
* Create a SchemaOrg.
*
* @return \Spatie\SchemaOrg\NewsArticle
*/
public function toSchemaOrg(): \Spatie\SchemaOrg\NewsArticle
{
return Schema::NewsArticle()
->headline($this->seo_title)
->description($this->seo_description)
->name($this->title)
->inLanguage(config('schema-org.website.languages')[app()->currentLocale()])
->abstract($this->subtitle)
->dateCreated($this->created_at)
->dateModified($this->updated_at)
->datePublished($this->publish_at)
->articleBody(strip_tags($this->content))
->wordCount(str_word_count(strip_tags($this->content)))
->url(route('news.show', $this))
->author($this->getOrganizationSchema())
->creator($this->getOrganizationSchema())
->copyrightYear($this->created_at->year)
->image(
Schema::imageObject()
->url(asset($this->data['bloc_1_image']['value']))
->headline($this->data['bloc_1_image']['title'])
);
}
}

View file

@ -10,29 +10,33 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
use Uwil\Seo\Laravel\Traits\SeoTrait;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
/**
* @property integer $range_id
* @property string $seo_title
* @property string $seo_description
* @property string $label
* @property string $slug
* @property string $description
* @property string|null $marinade
* @property string $picture
* @property array $certifications
* @property array $nutritionnal_values
* @property array $list
* @property boolean $status
* @property integer $order
* @property string $created_at
* @property string $updated_at
* @property integer $range_id
* @property string $seo_title
* @property string $seo_description
* @property string $label
* @property string $slug
* @property string $description
* @property string|null $marinade
* @property string $picture
* @property array $certifications
* @property array $nutritionnal_values
* @property array $list
* @property boolean $status
* @property integer $order
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
*/
class Product extends Model implements SeoInterface
class Product extends Model implements SeoInterface, SchemaOrgInterface
{
use HasFactory;
use HasTranslations;
use SeoTrait;
use SchemaOrgTrait;
/**
* The attributes that are mass assignable.
@ -182,6 +186,37 @@ class Product extends Model implements SeoInterface
$model->order = \intval(self::query()->max('order')) + 1;
}
/**
* Create a SchemaOrg.
*
* @return \Spatie\SchemaOrg\Product
*/
public function toSchemaOrg(): \Spatie\SchemaOrg\Product
{
$model = $this->load(['range']);
// Main.
$schema = Schema::Product()
->name($model->seo_title)
->description($model->seo_description)
->url(route('product.show', $model->slug))
->keywords('produit')
->releaseDate($model->created_at)
->image([
Schema::imageObject()
->url(asset($model->picture))
->headline($model->picture_title),
])
->brand($model->getBrandSchema());
// Range associated.
if ($model->range->status) {
$schema->subjectOf($model->range->toSchemaOrg()->toArray());
}
return $schema;
}
// * RELATIONSHIPS
/**

View file

@ -8,6 +8,9 @@ use App\Traits\Models\HasTranslations;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
use Uwil\Seo\Laravel\Objects\SeoItem;
use Uwil\Seo\Laravel\Traits\SeoTrait;
@ -23,11 +26,12 @@ use Uwil\Seo\Laravel\Traits\SeoTrait;
* @property string $created_at
* @property string $updated_at
*/
class Range extends Model implements SeoInterface
class Range extends Model implements SeoInterface, SchemaOrgInterface
{
use HasFactory;
use HasTranslations;
use SeoTrait;
use SchemaOrgTrait;
/**
* The attributes that are mass assignable.
@ -136,6 +140,21 @@ class Range extends Model implements SeoInterface
$model->order = \intval(self::query()->max('order')) + 1;
}
/**
* Create a SchemaOrg.
*
* @return \Spatie\SchemaOrg\DefinedTermSet
*/
public function toSchemaOrg(): \Spatie\SchemaOrg\DefinedTermSet
{
return Schema::definedTermSet()
->hasDefinedTerm(
Schema::definedTerm()
->name($this->seo_title)
->description($this->seo_description)
);
}
// * RELATIONSHIPS
/**

View file

@ -11,31 +11,35 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
use Uwil\Seo\Laravel\Traits\SeoTrait;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
/**
* @property integer $range_id
* @property string $seo_title
* @property string $seo_description
* @property string $name
* @property string $slug
* @property string $picture
* @property string $picture_thumbnail
* @property array $ingredients
* @property string $teaser
* @property string $steps
* @property integer $range_id
* @property string $seo_title
* @property string $seo_description
* @property string $name
* @property string $slug
* @property string $picture
* @property string $picture_thumbnail
* @property array<array<string>> $ingredients
* @property string $teaser
* @property string $steps
* @property \App\Enums\Recipes\DifficultyEnum $difficulty
* @property string $duration
* @property string $tips
* @property boolean $status
* @property integer $order
* @property string $created_at
* @property string $updated_at
* @property integer $duration
* @property string $tips
* @property boolean $status
* @property integer $order
* @property-read \Illuminate\Support\Carbon $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*/
class Recipe extends Model implements SeoInterface
class Recipe extends Model implements SeoInterface, SchemaOrgInterface
{
use HasFactory;
use HasTranslations;
use SeoTrait;
use SchemaOrgTrait;
/**
* The attributes that are mass assignable.
@ -73,7 +77,7 @@ class Recipe extends Model implements SeoInterface
*/
protected $casts = [
'ingredients' => 'array',
'difficulty' => DifficultyEnum::class
'difficulty' => DifficultyEnum::class,
];
/**
@ -137,6 +141,7 @@ class Recipe extends Model implements SeoInterface
*/
private static function manageFields(self $model)
{
/** @var array<string,string> $itemIngredients */
foreach ($model->ingredients as $itemIngredients) {
if (isset($itemIngredients['header'])) {
ToolboxHelper::assertNoInternalBoUrls('ingredients', $itemIngredients['header']);
@ -186,6 +191,56 @@ class Recipe extends Model implements SeoInterface
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
}
/**
* Create and return microdata.
*
* @return \Spatie\SchemaOrg\Recipe
*/
public function toSchemaOrg(): \Spatie\SchemaOrg\Recipe
{
$model = $this->load(['range']);
$schema = Schema::Recipe()
->name($model->seo_title)
->description($model->seo_description)
->url(route('recipe.show', $this))
->inLanguage(config('schema-org.website.languages')[app()->currentLocale()])
->keywords('recette')
->recipeCategory([
$model->difficulty->label(),
])
->recipeCuisine("Française")
->recipeInstructions($model->tips)
->dateCreated($model->created_at)
->dateModified($model->updated_at)
->datePublished($model->created_at)
->totalTime(
Schema::duration()->setProperty("@value", $model->formatDurationIso($model->duration))
)
->steps($model->steps)
->author($model->getOrganizationSchema())
->creator($model->getOrganizationSchema())
->image(
Schema::imageObject()
->url(asset($model->picture))
->headline($model->picture_title)
);
// Ingredients.
$ingredientsList = [];
foreach ($this->ingredients as $ingredient) {
array_push($ingredientsList, $ingredient['value']);
};
$schema->ingredients($ingredientsList);
// Range associated.
if ($model->range->status) {
$schema->subjectOf($model->range->toSchemaOrg()->toArray());
}
return $schema;
}
// * RELATIONSHIPS
/**

View file

@ -8,6 +8,9 @@ use App\Traits\Models\HasTranslations;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
/**
* @property \App\Enums\StaticPageType $type Page type (StaticPageEnum).
@ -19,10 +22,11 @@ use Illuminate\Support\Str;
* @property-read \Illuminate\Support\Carbon $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*/
class StaticPage extends Model
class StaticPage extends Model implements SchemaOrgInterface
{
use HasFactory;
use HasTranslations;
use SchemaOrgTrait;
/**
* The attributes that are mass assignable.
@ -86,9 +90,9 @@ class StaticPage extends Model
/**
* Get the value of the model's route key.
*
* @return mixed
* @return string|integer
*/
public function getRouteKey()
public function getRouteKey(): string|int
{
/** @var \App\Enums\StaticPageType */
$enum = $this->getAttribute($this->getRouteKeyName());
@ -117,10 +121,31 @@ class StaticPage extends Model
* @return void
* @throws \Illuminate\Validation\ValidationException If an actu title already exists.
*/
private static function assertTitleIsUnique(string|null $title, ?int $id = null)
private static function assertTitleIsUnique(string|null $title, ?int $id = null): void
{
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, 'title', $title, $id);
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($title), $id);
}
/**
* Create a SchemaOrg.
*
* @return \Spatie\SchemaOrg\WebPage
*/
public function toSchemaOrg(): \Spatie\SchemaOrg\WebPage
{
return Schema::webPage()
->name($this->seo_title)
->description($this->seo_description)
->headline($this->title)
->isAccessibleForFree(true)
->keywords(['page'])
->dateCreated($this->created_at)
->dateModified($this->updated_at)
->reviewedBy($this->getOrganizationSchema())
->publisher($this->getOrganizationSchema())
->author($this->getOrganizationSchema())
->isPartOf($this->getWebsiteSchema());
}
}

View file

@ -30,6 +30,7 @@ trait UpdateModelStatus
*
* @param Model $model
* @return \Illuminate\Http\RedirectResponse
* @throws \InvalidArgumentException Model must use IsPublishable trait.
*/
public function updatePublicationDate(Model $model)
{

View file

@ -109,7 +109,7 @@ trait BaseEnum
}
$baseArray[$index] = $elements[$enum->name];
}
return [$enum->name => (object)$baseArray];
return [$enum->name => (object) $baseArray];
})->all());
}
return self::getCache('enums');

View file

@ -2,6 +2,8 @@
namespace App\Traits\Models;
use Carbon\Carbon;
/**
*
*/
@ -12,13 +14,13 @@ trait IsPublishable
*
* @return void
*/
public function initializeIsPublishable()
public function initializeIsPublishable(): void
{
/** @var \Illuminate\Database\Eloquent\Model $this */
$this->mergeCasts([
'status' => 'string',
'publish_at' => 'datetime',
'status' => 'string',
'publish_at' => 'datetime',
'unpublish_at' => 'datetime',
]);
$this->mergeFillable([
@ -72,32 +74,66 @@ trait IsPublishable
}
// * GETTERS / SETTERS (for PHPStan)
/**
* Get status attribute.
*
* @return boolean
*/
public function getStatus(): bool
{
return $this->status;
}
/**
* Set status attribute.
*
* @param boolean $status
* @return void
*/
public function setStatus(bool $status): void
{
$this->status = $status;
}
public function getPublishAt(): ?\Carbon\Carbon
/**
* Get publish_at attribute.
*
* @return \Carbon\Carbon|null
*/
public function getPublishAt(): Carbon|null
{
return $this->publish_at;
}
public function setPublishAt(?\Carbon\Carbon $date): void
/**
* Set publish_at attribute.
*
* @param \Carbon\Carbon|null $date
* @return void
*/
public function setPublishAt(Carbon|null $date): void
{
$this->publish_at = $date;
}
public function getUnpublishAt(): ?\Carbon\Carbon
/**
* Get unpublish_at attribute.
*
* @return \Carbon\Carbon|null
*/
public function getUnpublishAt(): Carbon|null
{
return $this->unpublish_at;
}
public function setUnpublishAt(?\Carbon\Carbon $date): void
/**
* Set unpublish_at attribute.
*
* @param \Carbon\Carbon|null $date
* @return void
*/
public function setUnpublishAt(Carbon|null $date): void
{
$this->unpublish_at = $date;
}

View file

@ -56,7 +56,7 @@ trait HasPicture
?int $maxHeight = null,
bool $nullable = false
): array {
$sizes = (object)[
$sizes = (object) [
'minWith' => $minWith ?? $this->minWith,
'minHeight' => $minHeight ?? $this->minHeight,
'maxWith' => $maxWith ?? $this->maxWith,
@ -89,7 +89,7 @@ trait HasPicture
?int $maxWith = null,
?int $maxHeight = null
): array {
$sizes = (object)[
$sizes = (object) [
'minWith' => $minWith ?? $this->minWith,
'minHeight' => $minHeight ?? $this->minHeight,
'maxWith' => $maxWith ?? $this->maxWith,

View file

@ -6,36 +6,36 @@
"description": "Website of Nature & Respect.",
"license": "MIT",
"require": {
"php": "^8.1",
"codezero/laravel-localized-routes": "^3.1",
"codezero/laravel-unique-translation": "^4.1",
"diglactic/laravel-breadcrumbs": "^8.0",
"php": "^8.3",
"codezero/laravel-localized-routes": "^4.0.1",
"codezero/laravel-unique-translation": "^4.3.1",
"diglactic/laravel-breadcrumbs": "^9.0.0",
"guzzlehttp/guzzle": "^7.2",
"kwaadpepper/image-resizer": "^2.1",
"kwaadpepper/refresh-sitemap": "^2.0",
"laravel/framework": "^10.0",
"kwaadpepper/image-resizer": "^3.1.0",
"laravel/framework": "^11.0",
"laravel/tinker": "^2.8",
"laravel/ui": "^4.2",
"ldc/web-admin-secure-laravel": "^2.0",
"mews/purifier": "^3.4",
"sentry/sentry-laravel": "^3.3",
"simplesoftwareio/simple-qrcode": "~4",
"sentry/sentry-laravel": "^4.15.1",
"simplesoftwareio/simple-qrcode": "^4.2.0",
"spatie/laravel-translatable": "^6.4",
"uwil/k8s-laravel": "^1.2",
"uwil/seo-laravel": "^1.0"
"uwil/admin-secure-laravel": "^4.0.0",
"uwil/k8s-laravel": "^2.0.0",
"uwil/schema-org-laravel": "^2.2.0",
"uwil/sitemap-generator": "^4.0.0",
"uwil/seo-laravel": "^4.0.0"
},
"require-dev": {
"fakerphp/faker": "^1.9.1",
"kitloong/laravel-migrations-generator": "^6.8",
"krlove/eloquent-model-generator": "dev-l10-compatibility",
"kitloong/laravel-migrations-generator": "^7.0.0",
"larastan/larastan": "^2.6",
"laravel-lang/common": "^3.1",
"laravel/pint": "^1.0",
"laravel/sail": "^1.18",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0",
"nunomaduro/collision": "^8.1",
"phpunit/phpunit": "^10.0",
"slevomat/coding-standard": "^8.10",
"slevomat/coding-standard": "^8.19",
"spatie/laravel-ignition": "^2.0",
"thedoctor0/laravel-factory-generator": "^1.2"
},
@ -72,6 +72,12 @@
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"phpcs": [
"./vendor/bin/phpcs"
],
"phpstan": [
"./vendor/bin/phpstan"
]
},
"extra": {

4589
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@ return [
|
*/
'debug' => (bool)env('APP_DEBUG', false),
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------

View file

@ -24,8 +24,7 @@ return [
* Here the cache for images is
* one hour
*/
'lifeTime' => 535680,
// 1 ans
'lifetime' => 535680,
/**
* Format can specifiy to which format save the image
@ -35,17 +34,27 @@ return [
* For WebP support GD driver must be used with PHP 5 >= 5.5.0 or PHP 7
* in order to use imagewebp(). If Imagick is used, it must be compiled
* with libwebp for WebP support.
* resize => will resize the image (boolean)
* fit => Combine cropping and resizing to format image in a smart way (boolean)
* keepRatio => will keep image ratio wile resizing (boolean)
* trim => boolean to trim the image using border color
* inCanvas => to make sure image boundarie is respected
* format => select tha wantd ouput form, yan can just convert images if you want
* example :
* 'small' => [
* 'height' => 500,
* 'width' => 250,
* 'inCanvas' => true,
* 'trim' => ['transparent', null, 10]
* ],
* 'smallWebp' => [
* 'height' => 500,
* 'width' => 250,
* 'inCanvas' => true,
* 'format' => 'webp'
* ],
* 'justconvertImage' => [
* 'format' => 'webp'
* ]
*/
'templates' => [

136
config/schema-org.php Normal file
View file

@ -0,0 +1,136 @@
<?php
return [
'brand' => [
/**
* App name.
* type: string
*/
'name' => env('APP_NAME', 'Laravel'),
/**
* Description (can be a translation key).
* type: string
*/
'description' => 'schema-org.description',
/**
* Logo path.
* type: string
* ex: 'resources/assets/images/logo.png
*/
'logo' => 'resources/assets/images/Icons/logo-nature-respect.svg',
/**
* Slogan (can be a translation key).
* type: string
*/
'slogan' => 'schema-org.slogan',
],
'organization' => [
/**
* Name.
* type: string
*/
'name' => env('APP_NAME', 'Laravel'),
/**
* Description (can be a translation key).
* type: string
*/
'description' => 'schema-org.description',
/**
* Logo path.
* type: string
*/
'logo' => 'resources/assets/images/Icons/logo-nature-respect.svg',
/**
* Slogan (can be a translation key).
* type: string
*/
'slogan' => 'schema-org.slogan',
/**
* Url associated.
* type: string|string[]
* ex: 'url' || ['url]
*/
'sameAs' => [
'https://www.instagram.com/nature_and_respect/',
'https://de.pinterest.com/natureandrespect/',
],
/**
* Place associated.
* type: <string, string>[]
* ex: [
* 'address' => '',
* 'keywords' => '' (can be a translation key),
* ]
*/
'place' => [
'address' => 'Zone Industrielle Saint-Laurent 72300 Sablé-sur-Sarthe',
'keywords' => 'schema-org.place',
],
],
'website' => [
/**
* About (can be a translation key).
* type: string
*/
'about' => 'schema-org.website',
/**
* Description (can be a translation key).
* type: string
*/
'description' => 'schema-org.website',
/**
* Genre (can be a translation key).
* type: string
*/
'genre' => 'schema-org.genre',
/**
* Created date.
* type: string
* ex: '2025-06-12'
*/
'created_at' => '2018-03-19',
/**
* Published date.
* type: string
* ex: '2025-06-12'
*/
'published_at' => '2018-03-19',
/**
* Locales codes (RFC 4647 - "Matching of Language Tags": 'language-range').
* link: https://datatracker.ietf.org/doc/html/rfc4647
* type: string[]
* ex: ['fr' => 'fr-FR']
*/
'languages' => [
'en' => 'en-US',
'de' => 'de-DE'
],
/**
* Keywords (can be a translation key).
* type: string|string[]
* ex: 'volaille' || ['volaille', 'élevage']
*/
'keywords' => 'schema-org.keywords',
/**
* Search path with parameters.
* type: string|null
* ex: '/recherche?texte={search_term_string}'
*/
'search' => null
]
];

View file

@ -55,7 +55,7 @@ return [
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate.
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_TRACES_SAMPLE_RATE'),
'before_send' => [\App\Lib\Helpers\ExceptionsHelper::class, 'sentryEventHandler'],
];

View file

@ -2,12 +2,13 @@
return [
'bo_route_prefix' => 'bo.',
'blade' => 'bo.pages.seo.index',
'middlewares' => [
'fo_route_prefix' => '',
'blade' => 'bo.pages.seo.index',
'middlewares' => [
'web',
'admin-secure',
'lang',
'auth:backend'
],
'guard' => 'backend'
'guard' => 'backend'
];

View file

@ -33,8 +33,6 @@ final class HomeFactory extends Factory
}
return [
'seo_title' => fake()->word,
'seo_description' => fake()->text(160),
'part1_title' => fake()->word,
'part1_subtitle' => fake()->word,
'part1_text_1' => fake()->text,

View file

@ -0,0 +1,79 @@
<?php
use App\Enums\StaticPageType;
use App\Models\Home;
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.
*
* @return void
*/
public function up(): void
{
// Add missed static pages.
Schema::table('static_pages', function (Blueprint $table) {
$table->string('seo_title')->comment('Static page SEO title.')->change();
$table->string('seo_description')->comment('Static page SEO description.')->change();
$table->string('title')->comment('Static page title.')->change();
$table->text('content')->nullable()->comment('Static page content.')->change();
});
foreach (StaticPageType::toArray() as $enum) {
$staticPageModel = StaticPage::query()->where('type', $enum->value)->first();
if (is_null($staticPageModel)) {
$staticPageModel = new StaticPage();
$staticPageModel->type = $enum->value;
$staticPageModel->seo_title = sprintf('Seo title pour la page %s', $enum->label);
$staticPageModel->seo_description = sprintf('Seo description pour la page %s', $enum->label);
$staticPageModel->title = $enum->label;
$staticPageModel->content = \clean(\fake()->randomHtml(6, 7));
$staticPageModel->saveOrFail();
}
}
// Home table clean.
$staticPageModel = StaticPage::query()->where('type', StaticPageType::home)->firstOrFail();
$homeModel = Home::query()->first();
$staticPageModel->seo_title = $homeModel->seo_title ?? "";
$staticPageModel->seo_description = $homeModel->seo_description ?? "";
$staticPageModel->saveOrFail();
Schema::table('homes', function (Blueprint $table) {
$table->dropColumn(['seo_title', 'seo_description']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::table('static_pages', function (Blueprint $table) {
$table->string('seo_title')->nullable(false)->comment('Seo title about 70 chars as recommended')->change();
$table->string('seo_description')->nullable(false)
->comment('Seo description about 160 chars as recommended')->change();
$table->string('title')->nullable(false)->comment('Title for the page')->change();
$table->text('content')->nullable(false)->comment('WYSIWYG text content using ckeditor')->change();
});
Schema::table('homes', function (Blueprint $table) {
$table->json('seo_title')->comment('Utilisé pour la balise title de la page')
->after('id');
$table->json('seo_description')->comment('Utilisé pour la balise méta description de la page')
->after('seo_title');
});
$staticPageModel = StaticPage::query()->where('type', StaticPageType::home)->firstOrFail();
$homeModel = Home::query()->first();
$homeModel->seo_title = $staticPageModel->seo_title;
$homeModel->seo_description = $staticPageModel->seo_description;
$homeModel->saveOrFail();
}
};

View file

@ -29,8 +29,7 @@
<rule ref="Generic.Files.LineLength"/>
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<rule ref="Generic.Formatting.MultipleStatementAlignment"/>
<rule ref="Generic.Formatting.NoSpaceAfterCast"/>
<rule ref="Generic.Functions.CallTimePassByReference"/>
<rule ref="Generic.Formatting.SpaceAfterCast"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<rule ref="Generic.Metrics.CyclomaticComplexity"/>
<rule ref="Generic.Metrics.NestingLevel"/>
@ -43,10 +42,8 @@
<rule ref="Generic.PHP.NoSilencedErrors"/>
<rule ref="Generic.Strings.UnnecessaryStringConcat"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="Generic.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Generic.WhiteSpace.ScopeIndent"/>
<rule ref="MySource.PHP.EvalObjectFactory"/>
<rule ref="MySource.PHP.GetRequestData"/>
<rule ref="MySource.PHP.AjaxNullComparison"/>
<rule ref="PEAR.Classes.ClassDeclaration"/>
<rule ref="PEAR.Commenting.InlineComment"/>
<rule ref="PSR1.Classes.ClassDeclaration"/>
@ -79,7 +76,6 @@
<rule ref="Squiz.Scope.MemberVarScope"/>
<rule ref="Squiz.Scope.MethodScope"/>
<rule ref="Squiz.Scope.StaticThisUsage"/>
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
<properties>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

View file

@ -1,14 +1,18 @@
<?php
return [
'difficulty_enum' => [
'easy' => 'leicht',
'medium' => 'mittlere',
'hard' => 'hart',
],
'static_page_type' => [
'contact' => 'Kontakt Us',
'legals' => 'Bedingungen und Konditionen',
'contact' => 'Kontakt Us',
'legals' => 'Bedingungen und Konditionen',
'confidentiality' => 'Datenschutzbestimmungen',
'home' => 'Startseite',
'products' => 'Produkte',
'product' => 'Produkt',
'recipes' => 'Rezepte',
'recipe' => 'Rezept',
'newsPlural' => 'Nachrichten',
'newsSingular' => 'Nachricht',
'concept' => 'Konzept',
'store' => 'Geschäft',
]
];

View file

@ -2,18 +2,18 @@
return [
'classes' => [
'sliders' => 'Sliders',
'homes' => 'Startseite',
'ranges' => 'Bereiche',
'news' => 'Aktuelles',
'products' => 'Produkte',
'concepts' => 'Konzepte',
'recipes' => 'Rezepte',
'stores' => 'Läden',
'storegroups' => 'Groups',
'storeregions' => 'Regions',
'storetypes' => 'Types',
'seo' => 'SEO',
'static_page' => 'statische Seite|statische Seiten',
'slider' => 'schieber',
'home' => 'startseite',
'range' => 'bereich',
'news' => 'aktualität',
'product' => 'produkt',
'concept' => 'konzept',
'recipe' => 'rezept',
'store' => 'läden',
'storegroup' => 'marktgrupp',
'storeregion' => 'marktregion',
'storetype' => 'markttyp',
'seo' => 'SEO',
'static_page' => 'statische seite',
]
];

View file

@ -0,0 +1,14 @@
<?php
return [
'description' => 'Nature & Respect bietet seine Expertise in der Freilandgeflügelzucht auf dem
internationalen Markt an. Geflügel, das mit 100 % pflanzlichem, gentechnikfreiem Futter ernährt
wird. Es wird unter Achtung des Tierwohls auf kleinen Höfen aufgezogen, die eine enge Beziehung
zwischen Züchter und Tier fördern.',
'slogan' => 'Unser Geflügel aus Freilandhaltung',
'website' => 'Website der Marke Nature & Respect mit Präsentation ihrer Produkte, Rezepte,
Neuigkeiten und mehr.',
'place' => ['anschrift', 'platz'],
'genre' => 'Präsentationswebsite',
'keywords' => ['Produkte', 'Rezepte', 'Neuigkeiten'],
];

View file

@ -1,14 +1,18 @@
<?php
return [
'difficulty_enum' => [
'easy' => 'easy',
'medium' => 'medium',
'hard' => 'hard',
],
'static_page_type' => [
'contact' => 'Contact Us',
'legals' => 'Terms & Conditions',
'contact' => 'Contact Us',
'legals' => 'Terms & Conditions',
'confidentiality' => 'Privacy policy',
'home' => 'Home',
'products' => 'Products',
'product' => 'Product',
'recipes' => 'Recipes',
'recipe' => 'Recipe',
'newsPlural' => 'News list',
'newsSingular' => 'News',
'concept' => 'Concept',
'store' => 'Store',
]
];

View file

@ -2,18 +2,18 @@
return [
'classes' => [
'sliders' => 'Sliders',
'homes' => 'Homepage',
'ranges' => 'Ranges',
'news' => 'News',
'products' => 'Products',
'concepts' => 'Concepts',
'recipes' => 'Recipes',
'stores' => 'Stores',
'storegroups' => 'Store Groups',
'storeregions' => 'Store Regions',
'storetypes' => 'Store Types',
'seo' => 'SEO',
'static_page' => 'static page|static pages',
'slider' => 'slider',
'home' => 'homepage',
'range' => 'range',
'news' => 'news',
'product' => 'product',
'concept' => 'concept',
'recipe' => 'recipe',
'store' => 'store',
'storegroup' => 'store group',
'storeregion' => 'store region',
'storetype' => 'store type',
'seo' => 'SEO',
'static_page' => 'static page',
]
];

View file

@ -0,0 +1,12 @@
<?php
return [
'description' => 'Nature & Respect offers its expertise in outdoor poultry production to the international
market. Poultry fed on 100% plant-based, GMO-free feed. They are raised with respect for the animal\'s
well-being, on small-scale farms that promote close proximity between breeder and animal.',
'slogan' => 'Our poultry raised on outdoor runs',
'website' => 'Nature & Respect brand website presenting its products, recipes, news and more.',
'place' => ['address', 'place'],
'genre' => 'showcase website',
'keywords' => ['products', 'recipes', 'news'],
];

View file

@ -39,6 +39,8 @@ import {
faHeader,
faCircleCheck,
faCog,
faGlobe,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import {
faCircleXmark,
@ -79,6 +81,8 @@ library.add(faBars);
library.add(faEllipsisVertical);
library.add(faHeader);
library.add(faAnglesRight);
library.add(faGlobe);
library.add(faUser);
// Front
library.add(faChevronLeft);

View file

@ -4,63 +4,70 @@
@section('breadcrumb', 'no')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 p-0">
<div class="card">
<div class="card-header">{{ __('Connection') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('bo.login') }}">
@csrf
<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" autocomplete="email" autofocus required>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" autocomplete="current-password" required>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label user-select-none" for="remember">
{{ __('Remember me') }}
</label>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 p-0">
<div class="card">
<div class="card-header">{{ __('Connection') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('bo.login') }}">
@csrf
<div class="row mb-3">
<label for="email"
class="col-md-4 col-form-label text-md-end">{{ __('Email address') }}</label>
<div class="col-md-6">
<input id="email" type="email"
class="form-control @error('email') is-invalid @enderror" name="email"
value="{{ old('email') }}" autocomplete="email" autofocus required>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
<span>{{ __('Connection') }}</span>
<i class="fa-solid fa-arrow-right-from-bracket"></i>
</button>
@if (Route::has('bo.password.request'))
<a class="btn btn-link" href="{{ route('bo.password.request') }}">
{{ __('Forgot password ?') }}
</a>
@endif
<div class="row mb-3">
<label for="password"
class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password"
class="form-control @error('password') is-invalid @enderror" name="password"
autocomplete="current-password" required>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
</div>
</form>
<div class="row mb-3">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember"
{{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label user-select-none" for="remember">
{{ __('Remember me') }}
</label>
</div>
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
<span>{{ __('Connection') }}</span>
<i class="fa-solid fa-arrow-right-from-bracket"></i>
</button>
@if (Route::has('bo.password.request'))
<a class="btn btn-link" href="{{ route('bo.password.request') }}">
{{ __('Forgot password ?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@endsection

View file

@ -7,4 +7,4 @@
<span class="text-reset fw-bold">UWIL</span>
© {{ $cpsr_time }}
</div>
</footer>
</footer>

View file

@ -9,16 +9,16 @@
<meta name="csrf-token" content="{{ csrf_token() }}">
@hasSection('canonical')
<link rel="canonical" href="@yield('canonical')" />
<link rel="canonical" href="@yield('canonical')" />
@else
<link rel="canonical" href="{{ url()->current() }}" />
<link rel="canonical" href="{{ url()->current() }}" />
@endif
<!-- META INDEX, FOLLOW -->
@hasSection('metaIndex')
<meta name="robots" content="@yield('metaIndex')">
<meta name="robots" content="@yield('metaIndex')">
@else
<meta name="robots" content="index, follow">
<meta name="robots" content="index, follow">
@endif
<!-- Favicon -->
@ -36,6 +36,8 @@
<!-- STYLES -->
@vite(['resources/sass/bo/bo.scss'])
@if(config('app.debug'))
<script nonce="{{ $nonce }}">window.vueDebug = true;</script>
@if (config('app.debug'))
<script nonce="{{ $nonce }}">
window.vueDebug = true;
</script>
@endif

View file

@ -3,15 +3,16 @@
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Afficher/Masquer le menu d\'utilisateur') }}">
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="{{ __('Afficher/Masquer le menu d\'utilisateur') }}">
<i class="fa-solid fa-bars"></i>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="navbarSupportedContent">
<div class="offcanvas-header border-bottom">
<h5 class="offcanvas-title">{{ __('Users menu') }}</h5>
<button type="button" class="btn-close btn-close-dark" data-bs-dismiss="offcanvas" aria-label="Close"></button>
<button type="button" class="btn-close btn-close-dark" data-bs-dismiss="offcanvas"
aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav w-100">
@ -19,29 +20,45 @@
@include('bo.layouts.nav-menu')
<!-- Authentication Links -->
@auth('backend')
<li class="nav-item dropdown m-0 ms-md-auto">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ __('Language') }} : <b>{{ strtoupper(app()->getLocale()) }}</b> - {{ auth('backend')->user()->firstname }}&nbsp;{{ auth('backend')->user()->lastname}} <span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-end p-0 m-0" aria-labelledby="navbarDropdown">
@foreach(config('app.locales') as $locale)
@if ($locale !== app()->getLocale())
<div class="dropdown-item">
<a href="{{ route('bo.lang', ['lang' => $locale]) }}" class="btn">{{ __('Change language') }} -> {{ strtoupper($locale) }}</a>
<li class="nav-item dropdown m-0 ms-md-auto">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<b>{{ strtoupper(app()->getLocale()) }}</b>
<i class="fa-solid fa-globe"></i>
</a>
<div class="dropdown-menu dropdown-menu-end p-0 m-0" aria-labelledby="navbarDropdown">
@foreach (config('app.locales') as $locale)
@if ($locale !== app()->getLocale())
<a href="{{ route('bo.lang', ['lang' => $locale]) }}" class="dropdown-item btn py-2 rounded-2">
{{ strtoupper($locale) }}
</a>
@endif
@endforeach
</div>
@endif
@endforeach
<div class="dropdown-item">
<form action="{{ route('bo.logout') }}" method="POST" class="text-center">
@csrf
<button class="btn btn-link p-0 text-decoration-none text-muted text-capitalize w-100 py-2" type="submit">{{ __('Logout') }}</button>
</form>
</li>
<li class="nav-item dropdown m-0 ms-md-auto">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@php $userModel = auth('backend')->user(); @endphp
{{ sprintf('%s %s', $userModel->firstname, $userModel->lastname) }}
<i class="fa-solid fa-user"></i>
</a>
<div class="dropdown-menu dropdown-menu-end p-0 m-0" aria-labelledby="navbarDropdown">
<div class="dropdown-item p-0">
<form action="{{ route('bo.logout') }}" method="POST" class="text-center">
@csrf
<button
class="btn btn-link p-0 text-decoration-none text-muted text-capitalize w-100 rounded-2 py-2"
type="submit">
{{ __('Logout') }}
</button>
</form>
</div>
</div>
</div>
</li>
</li>
@endguest
</ul>
</div>
</div>
</div>
</header>
</header>

View file

@ -1,107 +1,117 @@
@auth('backend')
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.dashboard')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.dashboard') }}"
title="{{ __('Show the dashboard') }}" role="button">
<a class="nav-link @if (request()->routeIs('bo.dashboard')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.dashboard') }}" title="{{ __('Show the dashboard') }}" role="button">
{{ __('Dashboard') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.seo.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.seo.index') }}"
title="{{ __('Show the SEO informations') }}" role="button">
<a class="nav-link @if (request()->routeIs('bo.seo.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.seo.index') }}" title="{{ __('Show the SEO informations') }}" role="button">
{{ __('SEO') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.sliders.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.sliders.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.sliders')]) }}" role="button">
{{ __('models.classes.sliders') }}
<a class="nav-link @if (request()->routeIs('bo.sliders.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.sliders.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.slider'))->plural()]) }}" role="button">
{{ str(__('models.classes.slider'))->ucfirst()->plural() }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.homes.*')) active @endif" data-bs-toggle="tooltip"
<a class="nav-link @if (request()->routeIs('bo.homes.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.homes.edit', $globalHome->id) }}"
title="{{ __('crud.helpers.update_model', ['model' => Str::singular(__('models.classes.homes'))]) }}" role="button">
{{ __('models.classes.homes') }}
title="{{ __('crud.helpers.update_model', ['model' => __('models.classes.home')]) }}"
role="button">
{{ str(__('models.classes.home'))->ucfirst() }}
</a>
</li>
@can('viewAny', \App\Models\StaticPage::class)
<li class="nav-item">
<a class="nav-link @if (request()->routeIs('bo.static_pages.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.static_pages.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => Str::of(trans_choice('models.classes.static_page', '*'))->title()]) }}">
{{ Str::of(trans_choice('models.classes.static_page', '*'))->title() }}
title="{{ __('crud.helpers.list_all', ['model' => str(trans('models.classes.static_page'))->plural()]) }}">
{{ str(trans('models.classes.static_page'))->ucfirst()->plural() }}
</a>
</li>
@endcan
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.news.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.news.index') }}?rst=1"
<a class="nav-link @if (request()->routeIs('bo.news.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.news.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.news')]) }}" role="button">
{{ __('models.classes.news') }}
{{ str(trans('models.classes.news'))->ucfirst() }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.concepts.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.concepts.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.concepts')]) }}" role="button">
{{ __('models.classes.concepts') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.ranges.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.ranges.index') }}?rst=1" title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.ranges')]) }}"
role="button">
{{ __('models.classes.ranges') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.products.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.products.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.products')]) }}" role="button">
{{ __('models.classes.products') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if (Route::is('bo.recipes.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.recipes.index') }}?rst=1" title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.recipes')]) }}"
role="button">
{{ __('models.classes.recipes') }}
<a class="nav-link @if (request()->routeIs('bo.concepts.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.concepts.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.concept'))->plural()]) }}" role="button">
{{ str(__('models.classes.concept'))->ucfirst()->plural() }}
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle @if (Route::is('bo.store*')) active @endif" data-bs-toggle="dropdown"
href="{{ route('bo.stores.index') }}?rst=1" role="button" aria-expanded="false">
{{ __('models.classes.stores') }}
</a>
<button class="nav-link dropdown-toggle @if (request()->routeIs('bo.products.*') || request()->routeIs('bo.ranges.*') || request()->routeIs('bo.recipes.*')) active @endif"
data-bs-toggle="dropdown" role="button" aria-expanded="false">
{{ str(__('models.classes.product'))->ucfirst()->plural() }}
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item @if (Route::is('bo.stores.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.stores.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.stores')]) }}" role="button">
{{ __('models.classes.stores') }}
<a class="dropdown-item @if (request()->routeIs('bo.products.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.products.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.product'))->plural()]) }}" role="button">
{{ str(__('models.classes.product'))->ucfirst()->plural() }}
</a>
</li>
<li>
<a class="dropdown-item @if (Route::is('bo.storegroups.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storegroups.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.storegroups')]) }}" role="button">
{{ __('models.classes.storegroups') }}
<a class="dropdown-item @if (request()->routeIs('bo.ranges.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.ranges.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.range'))->plural()]) }}" role="button">
{{ str(__('models.classes.range'))->ucfirst()->plural() }}
</a>
</li>
<li>
<a class="dropdown-item @if (Route::is('bo.storeregions.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storeregions.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.storeregions')]) }}" role="button">
{{ __('models.classes.storeregions') }}
<a class="dropdown-item @if (request()->routeIs('bo.recipes.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.recipes.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.recipe'))->plural()]) }}" role="button">
{{ str(__('models.classes.recipe'))->ucfirst()->plural() }}
</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<button class="nav-link dropdown-toggle @if (request()->routeIs('bo.store*')) active @endif" data-bs-toggle="dropdown"
role="button" aria-expanded="false">
{{ str(__('models.classes.store'))->ucfirst()->plural() }}
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item @if (request()->routeIs('bo.stores.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.stores.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.store'))->plural()]) }}" role="button">
{{ str(__('models.classes.store'))->ucfirst()->plural() }}
</a>
</li>
<li>
<a class="dropdown-item @if (Route::is('bo.storetypes.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storetypes.index') }}?rst=1"
title="{{ __('crud.helpers.list_all', ['model' => __('models.classes.storetypes')]) }}" role="button">
{{ __('models.classes.storetypes') }}
<a class="dropdown-item @if (request()->routeIs('bo.storegroups.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storegroups.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.storegroup'))->plural()]) }}"
role="button">
{{ str(__('models.classes.storegroup'))->ucfirst()->plural() }}
</a>
</li>
<li>
<a class="dropdown-item @if (request()->routeIs('bo.storeregions.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storeregions.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.storeregion'))->plural()]) }}"
role="button">
{{ str(__('models.classes.storeregion'))->ucfirst()->plural() }}
</a>
</li>
<li>
<a class="dropdown-item @if (request()->routeIs('bo.storetypes.*')) active @endif" data-bs-toggle="tooltip"
href="{{ route('bo.storetypes.index') }}"
title="{{ __('crud.helpers.list_all', ['model' => str(__('models.classes.storetype'))->plural()]) }}" role="button">
{{ str(__('models.classes.storetype'))->ucfirst()->plural() }}
</a>
</li>
</ul>

View file

@ -1,63 +1,87 @@
@php
$route = request()->route();
$routeName = $route->getName();
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
$noOrder = !empty($noOrder);
$noOrder = $noOrder || (Session::get("$routeName.sort_col") !== 'order' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way")));
$noOrder = $noOrder || !empty(request()->search);
$ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
$route = request()->route();
$routeName = $route->getName();
$rst = !is_null(request()->rst) || !session()->has("$routeName.sorted");
$noOrder = !empty($noOrder);
$noOrder =
$noOrder ||
(session()->get("$routeName.sort_col") !== 'order' and
(session()->has("$routeName.sort_col") or session()->has("$routeName.sort_way")));
$noOrder = $noOrder || !empty(request()->search);
$ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
@endphp
<tr>
@foreach($cols as $col => $colname)
@php
$iArgs = ['sort_col' => $col];
if(request()->search) {
$iArgs['search'] = request()->search;
}
@endphp
{{-- NO Sort for order column --}}
@if($col === 'order' or in_array($col, $ignore))
@if(($noOrder or in_array($col, $ignore))) @continue @endif
<th scope="col" @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) class="d-none d-md-table-cell text-center" @endif>
<span class="text-nowrap">{{ $colname }}</span>
</th>
@continue
@endif
<th scope="col" @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) class="d-none d-md-table-cell text-center" @endif>
<span class="text-nowrap">
{{ $colname }}
@if(!session("$routeName.sort_way") or session("$routeName.sort_col") !== $col or (session("$routeName.sort_way") === 'desc' and session("$routeName.sort_col") === $col))
<a class="col_sort text-info lead asc"
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'asc', 'rst' => null])) }}"
title="{{ __('Sort :name in ascending order', ['name' => Str::lower($colname)]) }}"
data-bs-toggle="tooltip">
&nbsp;&darr;&nbsp;
</a>
<tr class="table-col-sorter border-start-0 border-end-0 border-top-0 border-secondary border border-2">
@foreach ($cols as $col => $colname)
@php
$iArgs = ['sort_col' => $col];
if (request()->search) {
$iArgs['search'] = request()->search;
}
@endphp
{{-- NO Sort for order column --}}
@if ($col === 'order' or in_array($col, $ignore))
@if ($noOrder and !in_array($col, $ignore))
@continue
@endif
@if(!session("$routeName.sort_way") or session("$routeName.sort_col") !== $col or (session("$routeName.sort_way") === 'asc' and session("$routeName.sort_col") === $col))
<a class="col_sort text-info lead desc"
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'desc', 'rst' => null])) }}"
title="{{ __('Sort :name in descending order', ['name' => Str::lower($colname)]) }}"
data-bs-toggle="tooltip">
&nbsp;&uarr;&nbsp;
</a>
@endif
</span>
</th>
<th @class([
'h-100 text-center',
'd-none d-md-table-cell' =>
isset($mobileHide) and
is_array($mobileHide) and
in_array($col, $mobileHide),
]) scope="col">
<div class="d-flex justify-content-center align-items-center h-100">
<span class="text-nowrap">{{ $colname }}</span>
</div>
</th>
@continue
@endif
<th @class([
'h-100 text-center',
'd-none d-md-table-cell' =>
isset($mobileHide) and
is_array($mobileHide) and
in_array($col, $mobileHide),
]) scope="col">
<div class="d-flex justify-content-center align-items-center h-100">
<span class="text-nowrap">
{{ $colname }}
</span>
@if (
!session("$routeName.sort_way") or
session("$routeName.sort_col") !== $col or
session("$routeName.sort_way") === 'desc' and session("$routeName.sort_col") === $col)
<a class="btn btn-sm btn-outline-secondary text-decoration-none ms-1" data-bs-toggle="tooltip"
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'asc', 'rst' => null])) }}"
title="{{ __('crud.other.sort_descending', ['name' => str($colname)->lower()]) }}">
<i class="fas fa-arrow-down 2xs"></i>
</a>
@endif
@if (
!session("$routeName.sort_way") or
session("$routeName.sort_col") !== $col or
session("$routeName.sort_way") === 'asc' and session("$routeName.sort_col") === $col)
<a class="btn btn-sm btn-outline-secondary text-decoration-none ms-1"
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'desc', 'rst' => null])) }}"data-bs-toggle="tooltip"
title="{{ __('crud.other.sort_ascending', ['name' => str($colname)->lower()]) }}">
<i class="fas fa-arrow-up 2xs"></i>
</a>
@endif
</div>
</th>
@endforeach
{{-- Buttons Col --}}
<th scope="col">
@if(!$rst)
<a class="btn btn-small btn-danger"
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
data-bs-toggle="tooltip"
title="{{ __('Delete the sorting') }}">
<i class="fa fa-eraser"></i>
</a>
<th class="text-end" scope="col">
@if (!$rst)
<a class="btn btn-sm btn-danger" data-bs-toggle="tooltip"
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
title="{{ __('crud.other.sort_delete') }}">
<i class="fa fa-eraser"></i>
</a>
@else
<span data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Here, the arrows are used to sort and not to filter') }}">
<i class="fas fa-question-circle"></i>
</span>
<span data-bs-toggle="tooltip" title="{{ __('crud.other.sort_arrow') }}">
<i class="fas fa-question-circle"></i>
</span>
@endif
</th>
</tr>

View file

@ -1,36 +1,34 @@
@extends('bo.layout')
@section('title', sprintf('%s - %s', Str::singular(__('models.classes.concepts')), Str::ucfirst(__('create'))))
@section('title', sprintf('%s - %s', str(__('models.classes.concept'))->ucfirst(), str(__('crud.actions.create'))->ucfirst()))
@section('description', __('Creation of a new concept.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<a href="{{ route('bo.concepts.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" title="{{ __('Return to the :model list', ['model' => __('models.classes.concepts')]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.concepts')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('create')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<a href="{{ route('bo.concepts.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip"
title="{{ __('Return to the :model list', ['model' => str(__('models.classes.concept'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ str(__('models.classes.concept'))->ucfirst() }}</span>&nbsp;<small
class="text-muted">{{ str(__('crud.actions.create'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.concepts.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.concepts.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary"
title="{{ __('Save :model', ['model' => __('models.classes.concept')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.concepts.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.concepts.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.concepts'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -1,37 +1,37 @@
@extends('bo.layout', ['brParam' => $conceptModel])
@section('title', sprintf('%s - %s %s', Str::singular(__('models.classes.concepts')), Str::ucfirst(__('crud.actions.edit')), $conceptModel->seo_title))
@section('title', sprintf('%s - %s %s', str(__('models.classes.concept'))->ucfirst(), str(__('crud.actions.edit'))->ucfirst(), $conceptModel->seo_title))
@section('description', $conceptModel->seo_description)
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<a href="{{ route('bo.concepts.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" title="{{ __('Return to the :model list', ['model' => __('models.classes.concepts')]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.concepts')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('crud.actions.edit')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<a href="{{ route('bo.concepts.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip"
title="{{ __('Return to the :model list', ['model' => str(__('models.classes.concept'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ str(__('models.classes.concept'))->ucfirst() }}</span>
<small class="text-muted">{{ Str::ucfirst(__('crud.actions.edit')) }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.concepts.update', $conceptModel->id) }}" method="POST"
enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.concepts.form-inputs', ['model' => $conceptModel])
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary"
title="{{ __('Save :model', ['model' => __('models.classes.concept')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.concepts.update', $conceptModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.concepts.form-inputs', ['model' => $conceptModel])
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.concepts'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -6,18 +6,22 @@
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'conceptSeoTitle',
'label' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'hasWordCounter' => true,
'name' => 'seo_title',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'min' => 3,
'max' => 255
]),
'placeholder' => __('A beautiful title'),
'id' => 'conceptSeoTitle',
'label' => __('SEO title of the :model', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'seo_title',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('SEO title of the :model', [
'model' => __('models.classes.concept'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __('A beautiful title'),
])
</div>
</div>
@ -30,17 +34,21 @@
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar-multiline', [
'id' => 'conceptSeoDescription',
'label' => __('SEO description of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'name' => 'seo_description',
'model' => $conceptModel ?? null,
'required' => true,
'helper' => __('validation.between.string', [
'attribute' => __('SEO description of the :model', ['model' => Str::singular(__('models.classes.products'))]),
'min' => 50,
'max' => 160
]),
'placeholder' => __('A description of the content for search engines.'),
'id' => 'conceptSeoDescription',
'label' => __('SEO description of the :model', [
'model' => __('models.classes.concept'),
]),
'name' => 'seo_description',
'model' => $conceptModel ?? null,
'required' => true,
'helper' => __('validation.between.string', [
'attribute' => __('SEO description of the :model', [
'model' => __('models.classes.products'),
]),
'min' => 50,
'max' => 160,
]),
'placeholder' => __('A description of the content for search engines.'),
])
</div>
</div>
@ -55,18 +63,22 @@
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'conceptName',
'label' => __('Name of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Name of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'min' => 3,
'max' => 255
]),
'placeholder' => __('A beautiful name'),
'id' => 'conceptName',
'label' => __('Name of the :model', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Name of the :model', [
'model' => __('models.classes.concept'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __('A beautiful name'),
])
</div>
</div>
@ -81,18 +93,22 @@
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'conceptTitle',
'label' => __('Title of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'hasWordCounter' => true,
'name' => 'title',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Title of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'min' => 3,
'max' => 255
]),
'placeholder' => __('A beautiful title'),
'id' => 'conceptTitle',
'label' => __('Title of the :model', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'title',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Title of the :model', [
'model' => __('models.classes.concept'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __('A beautiful title'),
])
</div>
</div>
@ -107,19 +123,19 @@
@include('bo.partials.inputs.tinyint-enum', [
'id' => 'productTitleBackgroundColor',
'label' => __('Title background color'),
'name' => "title_background_color",
'name' => 'title_background_color',
'model' => $conceptModel ?? null,
'value' => old('title_background_color', $conceptModel->title_background_color ?? null),
'required' => true,
'associatedModels' => collect(\App\Enums\Concepts\ColorsEnum::all())
->map(fn ($enum) => (object)[
'associatedModels' => collect(\App\Enums\Concepts\ColorsEnum::all())->map(
fn($enum) => (object) [
'label' => $enum->label(),
'value' => $enum->value(),
]),
'helper' => __('Title background color'),
])
@include('modules.input-error', [
'inputName' => "title_background_color"
'inputName' => 'title_background_color',
])
</div>
</div>
@ -132,18 +148,22 @@
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'conceptSubtitle',
'label' => __('Subtitle of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'hasWordCounter' => true,
'name' => 'subtitle',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Subtitle of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'min' => 3,
'max' => 255
]),
'placeholder' => __('A beautiful subtitle'),
'id' => 'conceptSubtitle',
'label' => __('Subtitle of the :model', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'subtitle',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Subtitle of the :model', [
'model' => __('models.classes.concept'),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __('A beautiful subtitle'),
])
</div>
</div>
@ -157,12 +177,14 @@
<div class="row mb-3">
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'conceptDescription',
'label' => __('Description of the :model', ['model' => Str::singular(__('models.classes.concepts'))]),
'name' => 'description',
'model' => $conceptModel ?? null,
'required' => true,
'helper' => __('Proofread your content before publishing it (minimum 15 characters).'),
'id' => 'conceptDescription',
'label' => __('Description of the :model', [
'model' => __('models.classes.concept'),
]),
'name' => 'description',
'model' => $conceptModel ?? null,
'required' => true,
'helper' => __('Proofread your content before publishing it (minimum 15 characters).'),
])
</div>
</div>
@ -170,7 +192,8 @@
</div>
{{-- MINICRUD --}}
<div class="col-12 mb-3">
<button class="btn btn-primary col-form-label rounded-0 dropdown-toggle w-100" type="button" data-bs-toggle="collapse" data-bs-target="#minicrud" aria-expanded="false" aria-controls="minicrud">
<button class="btn btn-primary col-form-label rounded-0 dropdown-toggle w-100" type="button"
data-bs-toggle="collapse" data-bs-target="#minicrud" aria-expanded="false" aria-controls="minicrud">
<b>{{ __('ALL BLOCS') }}</b>
</button>
<div class="collapse" id="minicrud">
@ -178,7 +201,7 @@
<div class="row">
@include('bo.modules.minicrud-form-inputs', [
'data' => $conceptModel->data ?? \App\Models\Concept::getEmptyData(),
'selectedEnum' => \App\Enums\Concepts\ColorsEnum::toArray()
'selectedEnum' => \App\Enums\Concepts\ColorsEnum::toArray(),
])
</div>
</div>
@ -193,30 +216,40 @@
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'homePart3PictureAlt',
'label' => __('crud.minicrud.picture_alt_label', ['model' => Str::singular(__('models.classes.concepts'))]),
'label' => __('crud.minicrud.picture_alt_label', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'picture_alt',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('crud.minicrud.picture_alt_helper') . '. ' . __('validation.min.string', [
'attribute' => __('crud.minicrud.picture_alt_label'),
'min' => 3
]),
'helper' =>
__('crud.minicrud.picture_alt_helper') .
'. ' .
__('validation.min.string', [
'attribute' => __('crud.minicrud.picture_alt_label'),
'min' => 3,
]),
])
</div>
{{-- PICTURE_TITLE --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'homePart3PictureTitle',
'label' => __('crud.minicrud.picture_title_label', ['model' => Str::singular(__('models.classes.concepts'))]),
'label' => __('crud.minicrud.picture_title_label', [
'model' => __('models.classes.concept'),
]),
'hasWordCounter' => true,
'name' => 'picture_title',
'required' => true,
'model' => $conceptModel ?? null,
'helper' => __('crud.minicrud.picture_title_helper') . '. ' . __('validation.min.string', [
'attribute' => __('crud.minicrud.picture_title_label'),
'min' => 3
]),
'helper' =>
__('crud.minicrud.picture_title_helper') .
'. ' .
__('validation.min.string', [
'attribute' => __('crud.minicrud.picture_title_label'),
'min' => 3,
]),
])
</div>
{{-- PICTURE --}}
@ -238,62 +271,57 @@
</div>
</fieldset>
</div>
</div>
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function () {
const hasLoadedComponentsMarker = 'data[bloc_6_text][value]';
const showBloc = document.getElementById("bloc-5-display-bloc");
const displayBloc = function(index) {
const switchInput = document.querySelector(`input[name="data[bloc_${index}_use_bloc][value]"]`);
const inputList = [
`data[bloc_${index}_title][value]`,
`data[bloc_${index}_color][value]`,
`data[bloc_${index}_text][value]`,
`data[bloc_${index}_image][alt]`,
`data[bloc_${index}_image][title]`,
`data[bloc_${index}_image][value]`,
`data[bloc_${index}_video][value]`,
`data[bloc_${index}_has_video][value]`,
];
const inputs = [];
inputList.forEach((name) => {
const input = document.querySelector(`input[name="${name}"]`) ??
document.querySelector(`select[name="${name}"]`);
inputs.push(input);
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function() {
const hasLoadedComponentsMarker = 'data[bloc_6_text][value]';
const showBloc = document.getElementById("bloc-5-display-bloc");
const displayBloc = function(index) {
const switchInput = document.querySelector(`input[name="data[bloc_${index}_use_bloc][value]"]`);
const inputList = [
`data[bloc_${index}_title][value]`,
`data[bloc_${index}_color][value]`,
`data[bloc_${index}_text][value]`,
`data[bloc_${index}_image][alt]`,
`data[bloc_${index}_image][title]`,
`data[bloc_${index}_image][value]`,
`data[bloc_${index}_video][value]`,
`data[bloc_${index}_has_video][value]`,
];
const inputs = [];
inputList.forEach((name) => {
const input = document.querySelector(`input[name="${name}"]`) ??
document.querySelector(`select[name="${name}"]`);
inputs.push(input);
});
inputs.forEach((input) => {
// * hide.
if (!switchInput.checked) {
input.closest('.minicrud-input ').classList.add('d-none');
}
});
switchInput.addEventListener('change', function() {
inputs.forEach((input) => {
// * Toggle hide.
input.closest('.minicrud-input ').classList.toggle('d-none');
});
});
};
const waitForLoaded = () => {
setTimeout(() => {
if (!document.querySelector(`input[name="${hasLoadedComponentsMarker}"]`)) {
waitForLoaded();
return;
}
displayBloc(5);
displayBloc(6);
}, 300);
};
waitForLoaded();
});
inputs.forEach((input) => {
// * hide.
if(!switchInput.checked) {
input.closest('.minicrud-input ').classList.add('d-none');
}
});
switchInput.addEventListener('change', function () {
inputs.forEach((input) => {
// * Toggle hide.
input.closest('.minicrud-input ').classList.toggle('d-none');
});
});
};
const waitForLoaded = () => {
setTimeout(() => {
if(!document.querySelector(`input[name="${hasLoadedComponentsMarker}"]`)) {
waitForLoaded();
return;
}
displayBloc(5);
displayBloc(6);
}, 300);
};
waitForLoaded();
});
</script>
</script>
@endpush

View file

@ -1,16 +1,16 @@
<div class="table-responsive">
<table class="fix-action m-0 table">
<thead>
@php
$cols = [
@include('bo.modules.table-col-sorter', [
'cols' => [
'name' => __('validation.attributes.name'),
'title' => __('validation.attributes.title'),
'subtitle' => __('validation.attributes.subtitle'),
'order' => __('validation.attributes.order'),
'updated_at' => __('validation.attributes.updated_at'),
];
@endphp
@include('bo.modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => ['status']])
],
'mobileHide' => ['status']
])
</thead>
<tbody>
@if ($conceptModels->count())
@ -19,11 +19,7 @@
<td class="align-middle">{{ $conceptModel->name }}</td>
<td class="align-middle">{{ $conceptModel->title }}</td>
<td class="align-middle">{{ $conceptModel->subtitle }}</td>
@php
$routeName = request()
->route()
->getName();
@endphp
@php $routeName = request()->route()->getName(); @endphp
@if (empty(request()->search) and empty($noOrder) and Session::get("$routeName.sort_col") === 'order')
<td class="d-flex">
<form class="@if ($loop->first and $conceptModels->onFirstPage()) invisible @endif text-center"
@ -47,22 +43,24 @@
</td>
@endif
<td class="align-middle">
<span
class="badge bg-warning text-dark text-wrap">{{ $conceptModel->updated_at->formatLocalized('%d/%m/%Y à %H:%M') }}</span>
<span class="badge bg-warning text-dark text-wrap">
{{ $conceptModel->updated_at->isoFormat('LLLL') }}
</span>
</td>
<td class="align-middle">
<form class="btn-group confirmDeleteJS" action="{{ route('bo.concepts.destroy', $conceptModel->id) }}"
method="POST" novalidate>
<form class="btn-group confirmDeleteJS"
action="{{ route('bo.concepts.destroy', $conceptModel->id) }}" method="POST"
novalidate>
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.concepts.edit', $conceptModel->id) }}"
title="{{ __('crud.helpers.update_model', ['model' => Str::singular(__('models.classes.concepts'))]) }}">
title="{{ __('crud.helpers.update_model', ['model' => __('models.classes.concept')]) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@method('DELETE')
@csrf
<div class="btn-group" role="group">
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip"
title="{{ __('crud.helpers.delete_model', ['model' => Str::singular(__('models.classes.concepts'))]) }}">
title="{{ __('crud.helpers.delete_model', ['model' => __('models.classes.concept')]) }}">
<i class="fa-solid fa-trash"></i>
</button>
</div>
@ -73,7 +71,9 @@
@else
<tr>
<td class="text-center" colspan="6">
<span class="h3">{{ __('crud.helpers.no_results', ['models' => __('models.classes.concepts')]) }}</span>
<span class="h3">
{{ __('crud.helpers.no_results', ['models' => str(__('models.classes.concept'))->plural()]) }}
</span>
</td>
</tr>
@endif

View file

@ -1,48 +1,41 @@
@extends('bo.layout')
@section('title', __('crud.helpers.list_all', ['model' => __('models.classes.concepts')]))
@section('description', __('crud.helpers.list_all', ['model' => __('models.classes.concepts')]))
@section('breadcrumb', request()->route()->getName())
@section('title', __('crud.helpers.list_all', ['model' => str(__('models.classes.concept'))->plural()]))
@section('description', __('crud.helpers.list_all', ['model' => str(__('models.classes.concept'))->plural()]))
@section('content')
<div class="container">
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="h2 d-inline"><span class="fw-bold">{{ __('models.classes.concepts') }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('crud.helpers.list')) }}</small>&nbsp;&nbsp;</h1>
</div>
<div class="col-md-3 d-flex align-items-center">
<div class="input-group justify-content-end">
<a href="{{ route('bo.concepts.create') }}" class="btn btn-primary" title="{{ __('crud.helpers.create_model', ['model' => Str::singular(__('models.classes.concepts'))]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-plus"></i>
</a>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="h2 d-inline">
<span class="fw-bold">{{ str(__('models.classes.concept'))->ucfirst()->plural() }}</span>
<small class="text-muted">{{ str(__('crud.helpers.list'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $conceptModels->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
<div class="row">
<div class="col">
@include('bo.pages.concepts.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $conceptModels->withQueryString()->onEachSide(1)->links() }}
</div>
<div class="col-md-3 d-flex align-items-center">
<div class="input-group justify-content-end">
<a href="{{ route('bo.concepts.create') }}" class="btn btn-primary"
title="{{ __('crud.helpers.create_model', ['model' => __('models.classes.concept')]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-plus"></i>
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row">
<div class="col">
@include('bo.pages.concepts.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $conceptModels->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
</div>
</div>
</div>
@endsection
@endsection

View file

@ -1,33 +1,32 @@
@extends('bo.layout', ['brParam' => $homeModel])
@section('title', sprintf('%s - %s %s', __('models.classes.homes'), Str::ucfirst(__('crud.actions.edit')), $homeModel->seo_title))
@section('title', sprintf('%s - %s %s', str(__('models.classes.home'))->ucfirst(), str(__('crud.actions.edit'))->ucfirst(), $homeModel->seo_title))
@section('description', $homeModel->seo_description)
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<span class="fw-bold">{{ __('models.classes.homes') }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('crud.actions.edit')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<span class="fw-bold">{{ str(__('models.classes.home'))->ucfirst() }}</span>
<small class="text-muted">{{ str(__('crud.actions.edit'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.homes.update', $homeModel->id) }}" method="POST"
enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.homes.form-inputs', compact('homeModel'))
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary"
title="{{ __('Save :model', ['model' => __('models.classes.home')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.homes.update', $homeModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.homes.form-inputs', compact('homeModel'))
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.homes'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</form>
</div>
</div>
@endsection

View file

@ -7,13 +7,13 @@
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'homeSeoTitle',
'label' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('SEO title of the :model', ['model' => __('models.classes.home')]),
'hasWordCounter' => true,
'name' => 'seo_title',
'required' => true,
'model' => $homeModel,
'helper' => __('validation.between.string', [
'attribute' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'attribute' => __('SEO title of the :model', ['model' => __('models.classes.home')]),
'min' => 3,
'max' => 255
]),
@ -31,7 +31,7 @@
<div class="col-12">
@include('bo.partials.inputs.varchar-multiline', [
'id' => 'homeSeoDescription',
'label' => __('SEO description of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('SEO description of the :model', ['model' => __('models.classes.home')]),
'name' => 'seo_description',
'model' => $homeModel ?? null,
'required' => true,
@ -105,7 +105,7 @@
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'homePart1Text1',
'label' => __('Text 1 of the part.1 of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('Text 1 of the part.1 of the :model', ['model' => __('models.classes.home')]),
'name' => 'part1_text_1',
'model' => $homeModel,
'required' => true,
@ -123,7 +123,7 @@
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'homePart1Text2',
'label' => __('Text 2 of the part.1 of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('Text 2 of the part.1 of the :model', ['model' => __('models.classes.home')]),
'name' => 'part1_text_2',
'model' => $homeModel,
'required' => true,
@ -141,7 +141,7 @@
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'homePart1Text3',
'label' => __('Text 3 of the part.1 of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('Text 3 of the part.1 of the :model', ['model' => __('models.classes.home')]),
'name' => 'part1_text_3',
'model' => $homeModel,
'required' => true,
@ -212,7 +212,7 @@
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'homePart2Text',
'label' => __('Text of the part.2 of the :model', ['model' => Str::singular(__('models.classes.homes'))]),
'label' => __('Text of the part.2 of the :model', ['model' => __('models.classes.home')]),
'name' => 'part2_text',
'model' => $homeModel,
'required' => true,

View file

@ -1,36 +1,34 @@
@extends('bo.layout')
@section('title', sprintf('%s - %s', Str::singular(__('models.classes.news')), Str::ucfirst(__('create'))))
@section('title', sprintf('%s - %s', str(__('models.classes.news'))->ucfirst(), str(__('crud.actions.create'))->ucfirst()))
@section('description', __('Creation of a new news.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<a href="{{ route('bo.news.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" title="{{ __('Return to the :model list', ['model' => __('models.classes.news')]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.news')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('create')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<a href="{{ route('bo.news.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip"
title="{{ __('Return to the :model list', ['model' => __('models.classes.news')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ str(__('models.classes.news'))->ucfirst() }}</span>
<small class="text-muted">{{ str(__('crud.actions.create'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.news.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.news.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary"
title="{{ __('Save :model', ['model' => __('models.classes.news')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.news.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.news.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.news'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -1,37 +1,35 @@
@extends('bo.layout', ['brParam' => $newsModel])
@section('title', sprintf('%s - %s %s', Str::singular(__('models.classes.news')), Str::ucfirst(__('crud.actions.edit')), $newsModel->seo_title))
@section('title', sprintf('%s - %s %s', str(__('models.classes.news'))->ucfirst(), str(__('crud.actions.edit'))->ucfirst(), $newsModel->seo_title))
@section('description', $newsModel->seo_description)
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<a href="{{ route('bo.news.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" title="{{ __('Return to the :model list', ['model' => __('models.classes.news')]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.news')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('crud.actions.edit')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<a href="{{ route('bo.news.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip"
title="{{ __('Return to the :model list', ['model' => __('models.classes.news')]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ str(__('models.classes.news'))->ucfirst() }}</span>
<small class="text-muted">{{ str(__('crud.actions.edit'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.news.update', $newsModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.news.form-inputs', ['model' => $newsModel])
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => __('models.classes.news')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.news.update', $newsModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.news.form-inputs', ['model' => $newsModel])
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.news'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -7,13 +7,13 @@
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'newsSeoTitle',
'label' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'label' => __('SEO title of the :model', ['model' => __('models.classes.news')]),
'hasWordCounter' => true,
'name' => 'seo_title',
'required' => true,
'model' => $newsModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('SEO title of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'attribute' => __('SEO title of the :model', ['model' => __('models.classes.news')]),
'min' => 3,
'max' => 255,
]),
@ -31,13 +31,13 @@
<div class="col-12">
@include('bo.partials.inputs.varchar-multiline', [
'id' => 'newsSeoDescription',
'label' => __('SEO description of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'label' => __('SEO description of the :model', ['model' => __('models.classes.news')]),
'name' => 'seo_description',
'model' => $newsModel ?? null,
'required' => true,
'helper' => __('validation.between.string', [
'attribute' => __('SEO description of the :model', [
'model' => Str::singular(__('models.classes.products')),
'model' => __('models.classes.news'),
]),
'min' => 50,
'max' => 160,
@ -58,13 +58,13 @@
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'newsTitle',
'label' => __('Title of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'label' => __('Title of the :model', ['model' => __('models.classes.news')]),
'hasWordCounter' => true,
'name' => 'title',
'required' => true,
'model' => $newsModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Title of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'attribute' => __('Title of the :model', ['model' => __('models.classes.news')]),
'min' => 3,
'max' => 255,
]),
@ -82,13 +82,13 @@
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'newsSubtitle',
'label' => __('Subtitle of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'label' => __('Subtitle of the :model', ['model' => __('models.classes.news')]),
'hasWordCounter' => true,
'name' => 'subtitle',
'required' => true,
'model' => $newsModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __('Subtitle of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'attribute' => __('Subtitle of the :model', ['model' => __('models.classes.news')]),
'min' => 3,
'max' => 255,
]),
@ -106,7 +106,7 @@
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => 'newContent',
'label' => __('Description of the :model', ['model' => Str::singular(__('models.classes.news'))]),
'label' => __('Description of the :model', ['model' => __('models.classes.news')]),
'name' => 'content',
'model' => $newsModel ?? null,
'required' => true,
@ -232,24 +232,19 @@
document.querySelector(`select[name="${name}"]`);
inputs.push(input);
});
inputs.forEach((input) => {
// * hide.
if (!switchInput.checked) {
input.closest('.minicrud-input ').classList.add('d-none');
}
});
switchInput.addEventListener('change', function() {
inputs.forEach((input) => {
// * Toggle hide.
input.closest('.minicrud-input ').classList.toggle('d-none');
});
});
};
const waitForLoaded = () => {
setTimeout(() => {
if (!document.querySelector(`input[name="${hasLoadedComponentsMarker}"]`)) {
@ -261,9 +256,7 @@
displayBloc(3);
}, 300);
};
waitForLoaded();
});
</script>
@endpush

View file

@ -23,19 +23,11 @@
@csrf
<button class="btn btn-sm" data-bs-toggle="tooltip" type="submit"
title="{{ __($newsModel->status ? __('crud.helpers.unpublish') : __('crud.helpers.publish')) }}">
@if ($newsModel->status)
<i class="fs-6 text-success fa-solid fa-circle-check"></i>
@else
<i class="fs-6 text-danger fa-regular fa-circle-xmark"></i>
@endif
<i class="fs-6 fa-circle-{{ ($newsModel->status) ? 'check text-success fa-solid' : 'xmark text-danger fa-regular' }}"></i>
</button>
</form>
</td>
@php
$routeName = request()
->route()
->getName();
@endphp
@php $routeName = request()->route()->getName(); @endphp
@if (empty(request()->search) and empty($noOrder) and Session::get("$routeName.sort_col") === 'order')
<td class="d-flex">
<form class="@if ($loop->first and $newsListModels->onFirstPage()) invisible @endif text-center"
@ -59,22 +51,21 @@
</td>
@endif
<td class="align-middle">
<span
class="badge bg-warning text-dark text-wrap">{{ $newsModel->updated_at->formatLocalized('%d/%m/%Y à %H:%M') }}</span>
<span class="badge bg-warning text-dark text-wrap">{{ $newsModel->updated_at->isoFormat('LLLL') }}</span>
</td>
<td class="align-middle">
<form class="btn-group confirmDeleteJS" action="{{ route('bo.news.destroy', $newsModel->id) }}" method="POST"
novalidate>
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip"
href="{{ route('bo.news.edit', $newsModel->id) }}"
title="{{ __('crud.helpers.update_model', ['model' => Str::singular(__('models.classes.news'))]) }}">
title="{{ __('crud.helpers.update_model', ['model' => __('models.classes.news')]) }}">
<i class="fa-solid fa-pencil"></i>
</a>
@method('DELETE')
@csrf
<div class="btn-group" role="group">
<button class="btn btn-sm btn-danger" data-bs-toggle="tooltip"
title="{{ __('crud.helpers.delete_model', ['model' => Str::singular(__('models.classes.news'))]) }}">
title="{{ __('crud.helpers.delete_model', ['model' => __('models.classes.news')]) }}">
<i class="fa-solid fa-trash"></i>
</button>
</div>

View file

@ -2,47 +2,39 @@
@section('title', __('crud.helpers.list_all', ['model' => __('models.classes.news')]))
@section('description', __('crud.helpers.list_all', ['model' => __('models.classes.news')]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="container">
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="h2 d-inline"><span class="fw-bold">{{ __('models.classes.news') }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('crud.helpers.list')) }}</small>&nbsp;&nbsp;</h1>
</div>
<div class="col-md-3 d-flex align-items-center">
<div class="input-group justify-content-end">
<a href="{{ route('bo.news.create') }}" class="btn btn-primary" title="{{ __('crud.helpers.create_model', ['model' => Str::singular(__('models.classes.news'))]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-plus"></i>
</a>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="h2 d-inline">
<span class="fw-bold">{{ str(__('models.classes.news'))->ucfirst() }}</span>
<small class="text-muted">{{ str(__('crud.helpers.list'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $newsListModels->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
<div class="row">
<div class="col">
@include('bo.pages.news.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $newsListModels->withQueryString()->onEachSide(1)->links() }}
</div>
<div class="col-md-3 d-flex align-items-center">
<div class="input-group justify-content-end">
<a href="{{ route('bo.news.create') }}" class="btn btn-primary" data-bs-toggle="tooltip"
title="{{ __('crud.helpers.create_model', ['model' => __('models.classes.news')]) }}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row">
<div class="col">
@include('bo.pages.news.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0">
{{ $newsListModels->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
</div>
</div>
</div>
@endsection
@endsection

View file

@ -1,36 +1,34 @@
@extends('bo.layout')
@section('title', sprintf('%s - %s', Str::singular(__('models.classes.products')), Str::ucfirst(__('create'))))
@section('title', sprintf('%s - %s', str(__('models.classes.product'))->ucfirst(), str(__('crud.actions.create'))->ucfirst()))
@section('description', __('Creation of a new product.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<a href="{{ route('bo.products.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" title="{{ __('Return to the :model list', ['model' => __('models.classes.products')]) }}" data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.products')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('create')) }}</small>
</h1>
</div>
<div class="card">
<div class="card-header">
<h1 class="h2">
<a href="{{ route('bo.products.index') }}" class="btn btn-primary text-decoration-none m-0" data-bs-toggle="tooltip"
title="{{ __('Return to the :model list', ['model' => str(__('models.classes.product'))->plural()]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ str(__('models.classes.product'))->ucfirst() }}</span>&nbsp;<small
class="text-muted">{{ str(__('crud.actions.create'))->ucfirst() }}</small>
</h1>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.products.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.products.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary"
title="{{ __('Save :model', ['model' => __('models.classes.product')]) }}"
data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="card-body bg-light">
<form id="formSubmit" action="{{ route('bo.products.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.products.form-inputs')
<div class="row">
<div class="col text-center">
<button type="submit" class="btn btn-primary" title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.products'))]) }}" data-bs-toggle="tooltip">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

Some files were not shown because too many files have changed in this diff Show more