refactor: products.index and recipes.index pages on Bo
This commit is contained in:
parent
a7992f96c8
commit
43c3d55b72
36 changed files with 1900 additions and 384 deletions
13
app/Exceptions/AuthServiceException.php
Normal file
13
app/Exceptions/AuthServiceException.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
class AuthServiceException extends \RuntimeException
|
||||
{
|
||||
public static function of(?string $message = null, ?\Throwable $cause = null): self
|
||||
{
|
||||
return new self($message ?? 'An authentication error occurred.', previous: $cause);
|
||||
}
|
||||
}
|
||||
87
app/Http/Controllers/Back/BackendController.php
Normal file
87
app/Http/Controllers/Back/BackendController.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Back;
|
||||
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\LaravelBackend\Controllers\BackendController as UwilBackendController;
|
||||
use Uwil\LaravelBackend\Enums\ItemsPerPaginationEnum;
|
||||
use Uwil\LaravelCommon\Helpers\ToolboxHelper;
|
||||
|
||||
class BackendController extends UwilBackendController
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
use ValidatesRequests;
|
||||
|
||||
public function __construct(
|
||||
protected readonly Request $request,
|
||||
protected readonly Session $session,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize pagination with cache or config (default).
|
||||
*
|
||||
* @template T of \Illuminate\Database\Eloquent\Model
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder<T> $query
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator<array-key,T>
|
||||
*/
|
||||
protected function paginate(
|
||||
Builder $query,
|
||||
?ItemsPerPaginationEnum $pagination = null
|
||||
): LengthAwarePaginator {
|
||||
$route = $this->request->route();
|
||||
|
||||
throw_if(
|
||||
$route === null,
|
||||
\UnexpectedValueException::class,
|
||||
'Route is required in order to paginate'
|
||||
);
|
||||
|
||||
$cacheKey = $this->getCacheKey($route);
|
||||
$perPage = $this->getPerPage($cacheKey);
|
||||
|
||||
$this->persistPerPage($cacheKey, $perPage);
|
||||
|
||||
return $query->paginate(perPage: $perPage)->withQueryString();
|
||||
}
|
||||
|
||||
private function persistPerPage(string $cacheKey, int $perPage): void
|
||||
{
|
||||
if ($this->session->get($cacheKey) !== $perPage) {
|
||||
$this->session->put($cacheKey, $perPage);
|
||||
}
|
||||
}
|
||||
|
||||
private function getPerPage(string $cacheKey): int
|
||||
{
|
||||
$perPage = $this->session->get($cacheKey);
|
||||
$perPage = $perPage ?? ItemsPerPaginationEnum::twelve->value();
|
||||
|
||||
if (! is_scalar($perPage)) {
|
||||
throw new \UnexpectedValueException('perPage shall be a scalar valuye');
|
||||
}
|
||||
|
||||
return ToolboxHelper::getValidatedEnum(
|
||||
intval($perPage),
|
||||
'pagination',
|
||||
'\Uwil\LaravelBackend\Enums\ItemsPerPaginationEnum',
|
||||
);
|
||||
}
|
||||
|
||||
private function getCacheKey(Route $route): string
|
||||
{
|
||||
$currentRoutePath = Str::slug($route->getName() ?? 'unknown');
|
||||
|
||||
return "pagination.{$currentRoutePath}";
|
||||
}
|
||||
}
|
||||
241
app/Http/Controllers/Back/ProductController.php
Normal file
241
app/Http/Controllers/Back/ProductController.php
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Back;
|
||||
|
||||
use App\Http\Requests\Back\Products\IndexProductRequest;
|
||||
use App\Http\Requests\Back\Products\StoreProductRequest;
|
||||
use App\Http\Requests\Back\Products\UpdateProductRequest;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Response;
|
||||
use Uwil\LaravelBackend\Resources\CommonResource;
|
||||
|
||||
/**
|
||||
* Handles CRUD operations for Product in the backend.
|
||||
*/
|
||||
class ProductController extends BackendController
|
||||
{
|
||||
public function __construct(
|
||||
Request $request,
|
||||
Session $session,
|
||||
) {
|
||||
parent::__construct(
|
||||
$request,
|
||||
$session
|
||||
);
|
||||
|
||||
$this->authorizeResource(Product::class);
|
||||
$this->modelName = Product::modelName();
|
||||
$this->modelPage = Product::modelPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(IndexProductRequest $request): Response
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Product> $query */
|
||||
$query = Product::query();
|
||||
|
||||
if ($request->routeIs("back.{$this->modelName}.trash")) {
|
||||
$query = $query->onlyTrashed();
|
||||
}
|
||||
|
||||
$searchValue = $request->getSearchValue();
|
||||
if ($searchValue) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
$searchValue,
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
}
|
||||
$searchFields = \implode(', ', [
|
||||
trans('validation.attributes.name'),
|
||||
]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
/** Custom pagination */
|
||||
$paginatedModels = $this->paginate($query);
|
||||
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Index", [
|
||||
'paginatedModels' => CommonResource::collection($paginatedModels),
|
||||
'search' => $searchValue,
|
||||
'searchFields' => $searchFields,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(Product $product): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Create", [
|
||||
'data' => CommonResource::make($product),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a specific resource.
|
||||
*/
|
||||
public function show(Product $product): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Show", [
|
||||
'data' => CommonResource::make($product),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource.
|
||||
*/
|
||||
public function store(StoreProductRequest $request): RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$product = new Product();
|
||||
$product->inertiaFill($request->validated());
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
return redirect()->route("back.{$this->modelName}.edit", $product)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_created', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_created', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Product $product): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Edit", [
|
||||
'data' => CommonResource::make($product),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*/
|
||||
public function update(
|
||||
UpdateProductRequest $request,
|
||||
Product $product
|
||||
): RedirectResponse {
|
||||
return DB::transaction(function () use ($request, $product) {
|
||||
$product->inertiaFill($request->validated());
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
return redirect()->route("back.{$this->modelName}.edit", $product)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_updated', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->route("back.{$this->modelName}.edit", $product)
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_updated', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*/
|
||||
public function duplicate(Product $product): Response
|
||||
{
|
||||
return $this->create($product->replicate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified resource.
|
||||
*/
|
||||
public function restore(int $product): RedirectResponse
|
||||
{
|
||||
$product = Product::withTrashed()->findOrFail($product);
|
||||
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($product->restore()) {
|
||||
return redirect()->route("back.{$this->modelName}.trash", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_restored', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_restored', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the specified resource.
|
||||
*/
|
||||
public function destroy(Product $product): RedirectResponse
|
||||
{
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($product->delete()) {
|
||||
return redirect()->route("back.{$this->modelName}.index", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the specified resource.
|
||||
*/
|
||||
public function forceDestroy(Product | int $product): RedirectResponse
|
||||
{
|
||||
if (is_int($product)) {
|
||||
$product = Product::withTrashed()->findOrFail($product);
|
||||
}
|
||||
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($product->forceDelete()) {
|
||||
return redirect()->route("back.{$this->modelName}.trash", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/** @return array<array-key,string|array<mixed>> */
|
||||
private function getPreviousQueries(): array
|
||||
{
|
||||
$previousQueries = [];
|
||||
$previousQueryString = \parse_url($this->getPreviousUrl(), \PHP_URL_QUERY) ?? '' ?: '';
|
||||
\parse_str($previousQueryString, $previousQueries);
|
||||
|
||||
return $previousQueries;
|
||||
}
|
||||
|
||||
private function getPreviousUrl(): string
|
||||
{
|
||||
return url()->previous(route('back.dashboard.index'));
|
||||
}
|
||||
}
|
||||
241
app/Http/Controllers/Back/RecipeController.php
Normal file
241
app/Http/Controllers/Back/RecipeController.php
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Back;
|
||||
|
||||
use App\Http\Requests\Back\Recipes\IndexRecipeRequest;
|
||||
use App\Http\Requests\Back\Recipes\StoreRecipeRequest;
|
||||
use App\Http\Requests\Back\Recipes\UpdateRecipeRequest;
|
||||
use App\Models\Recipe;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Response;
|
||||
use Uwil\LaravelBackend\Resources\CommonResource;
|
||||
|
||||
/**
|
||||
* Handles CRUD operations for Recipe in the backend.
|
||||
*/
|
||||
class RecipeController extends BackendController
|
||||
{
|
||||
public function __construct(
|
||||
Request $request,
|
||||
Session $session,
|
||||
) {
|
||||
parent::__construct(
|
||||
$request,
|
||||
$session
|
||||
);
|
||||
|
||||
$this->authorizeResource(Recipe::class);
|
||||
$this->modelName = Recipe::modelName();
|
||||
$this->modelPage = Recipe::modelPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(IndexRecipeRequest $request): Response
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder<\App\Models\Recipe> $query */
|
||||
$query = Recipe::query();
|
||||
|
||||
if ($request->routeIs("back.{$this->modelName}.trash")) {
|
||||
$query = $query->onlyTrashed();
|
||||
}
|
||||
|
||||
$searchValue = $request->getSearchValue();
|
||||
if ($searchValue) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
$searchValue,
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
}
|
||||
$searchFields = \implode(', ', [
|
||||
trans('validation.attributes.name'),
|
||||
]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
/** Custom pagination */
|
||||
$paginatedModels = $this->paginate($query);
|
||||
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Index", [
|
||||
'paginatedModels' => CommonResource::collection($paginatedModels),
|
||||
'search' => $searchValue,
|
||||
'searchFields' => $searchFields,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(Recipe $recipe): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Create", [
|
||||
'data' => CommonResource::make($recipe),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a specific resource.
|
||||
*/
|
||||
public function show(Recipe $recipe): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Show", [
|
||||
'data' => CommonResource::make($recipe),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource.
|
||||
*/
|
||||
public function store(StoreRecipeRequest $request): RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$recipe = new Recipe();
|
||||
$recipe->inertiaFill($request->validated());
|
||||
|
||||
if ($recipe->saveOrFail()) {
|
||||
return redirect()->route("back.{$this->modelName}.edit", $recipe)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_created', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_created', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Recipe $recipe): Response
|
||||
{
|
||||
return $this->inertiaRender("back/Pages/{$this->modelPage}/Edit", [
|
||||
'data' => CommonResource::make($recipe),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*/
|
||||
public function update(
|
||||
UpdateRecipeRequest $request,
|
||||
Recipe $recipe
|
||||
): RedirectResponse {
|
||||
return DB::transaction(function () use ($request, $recipe) {
|
||||
$recipe->inertiaFill($request->validated());
|
||||
|
||||
if ($recipe->saveOrFail()) {
|
||||
return redirect()->route("back.{$this->modelName}.edit", $recipe)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_updated', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->route("back.{$this->modelName}.edit", $recipe)
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_updated', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*/
|
||||
public function duplicate(Recipe $recipe): Response
|
||||
{
|
||||
return $this->create($recipe->replicate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified resource.
|
||||
*/
|
||||
public function restore(int $recipe): RedirectResponse
|
||||
{
|
||||
$recipe = Recipe::withTrashed()->findOrFail($recipe);
|
||||
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($recipe->restore()) {
|
||||
return redirect()->route("back.{$this->modelName}.trash", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_restored', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_restored', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the specified resource.
|
||||
*/
|
||||
public function destroy(Recipe $recipe): RedirectResponse
|
||||
{
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($recipe->delete()) {
|
||||
return redirect()->route("back.{$this->modelName}.index", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the specified resource.
|
||||
*/
|
||||
public function forceDestroy(Recipe | int $recipe): RedirectResponse
|
||||
{
|
||||
if (is_int($recipe)) {
|
||||
$recipe = Recipe::withTrashed()->findOrFail($recipe);
|
||||
}
|
||||
|
||||
$previousQueries = $this->getPreviousQueries();
|
||||
|
||||
if ($recipe->forceDelete()) {
|
||||
return redirect()->route("back.{$this->modelName}.trash", $previousQueries)
|
||||
->with('success', trans('uwil-backend::crud.messages.has_been_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', trans('uwil-backend::crud.messages.cannot_be_deleted', [
|
||||
'model' => Str::ucfirst(trans_choice("models.classes.{$this->modelName}", 1)),
|
||||
]));
|
||||
}
|
||||
|
||||
/** @return array<array-key,string|array<mixed>> */
|
||||
private function getPreviousQueries(): array
|
||||
{
|
||||
$previousQueries = [];
|
||||
$previousQueryString = \parse_url($this->getPreviousUrl(), \PHP_URL_QUERY) ?? '' ?: '';
|
||||
\parse_str($previousQueryString, $previousQueries);
|
||||
|
||||
return $previousQueries;
|
||||
}
|
||||
|
||||
private function getPreviousUrl(): string
|
||||
{
|
||||
return url()->previous(route('back.dashboard.index'));
|
||||
}
|
||||
}
|
||||
17
app/Http/Controllers/Controller.php
Normal file
17
app/Http/Controllers/Controller.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
use DispatchesJobs;
|
||||
use ValidatesRequests;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ namespace App\Http\Middlewares;
|
|||
use App\Enums\Contact\ActivitySectorEnum;
|
||||
use App\Enums\Contact\ObjectEnum;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Inertia\Middleware;
|
||||
use Uwil\LaravelCommon\Helpers\InertiaHelper;
|
||||
use Uwil\LaravelCommon\Support\InertiaSharedRegistry;
|
||||
|
|
@ -17,7 +18,7 @@ class HandleInertiaRequests extends Middleware
|
|||
* Define the props that are shared by default.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array<string, mixed>
|
||||
* @return array<array-key,mixed>
|
||||
*/
|
||||
public function share(Request $request): array
|
||||
{
|
||||
|
|
@ -30,18 +31,13 @@ class HandleInertiaRequests extends Middleware
|
|||
|
||||
foreach ($dynamicPageModels as $dynamicPageModel) {
|
||||
$pascalCase =
|
||||
str_replace(' ', '', ucwords(str_replace('-', ' ', $dynamicPageModel->id_key)));
|
||||
str_replace(' ', '', ucwords(str_replace('-', ' ', $dynamicPageModel->id_key)));
|
||||
$dynamicPages["page{$pascalCase}"] = $dynamicPageModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$props = [
|
||||
...InertiaHelper::errorProps(parent::share($request)),
|
||||
'recaptchaKey' => config('services.google.recaptcha.public'),
|
||||
'dynamicPages' => $dynamicPages,
|
||||
'activitySectorEnum' => ActivitySectorEnum::toArray(),
|
||||
'objectEnum' => ObjectEnum::toArray()
|
||||
// More props here.
|
||||
];
|
||||
|
||||
|
|
@ -50,4 +46,13 @@ class HandleInertiaRequests extends Middleware
|
|||
InertiaSharedRegistry::resolve($request)
|
||||
);
|
||||
}
|
||||
|
||||
public function shareOnce(Request $request): array
|
||||
{
|
||||
return array_merge(parent::shareOnce($request), [
|
||||
'recaptchaKey' => fn() => Config::string('services.google.recaptcha.public'),
|
||||
'activitySectorEnum' => fn() => ActivitySectorEnum::toArray(),
|
||||
'objectEnum' => fn() => ObjectEnum::toArray()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
167
app/Http/Middlewares/SecureHeaders.php
Normal file
167
app/Http/Middlewares/SecureHeaders.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Middlewares;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Vite;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class SecureHeaders
|
||||
{
|
||||
/**
|
||||
* Enumerate headers which you do not want in your application's responses.
|
||||
* Great starting point would be to go check out @Scott_Helme's:
|
||||
* https://securityheaders.com/
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $unwantedHeaderList = [
|
||||
'X-Powered-By',
|
||||
'Server',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly Container $container
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request):(\Illuminate\Http\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$appUrl = Config::string('app.url');
|
||||
$appDebug = Config::boolean('app.debug');
|
||||
$telescopeEnabled = Config::boolean('telescope.enabled', false);
|
||||
|
||||
// * For Vite DEV
|
||||
$host = \parse_url($appUrl, \PHP_URL_HOST);
|
||||
$viteDevOrigin = $appDebug && \is_string($host) && $host !== ''
|
||||
? "https://{$host}:4443"
|
||||
: '';
|
||||
$viteDevSocket = $appDebug && \is_string($host) && $host !== ''
|
||||
? "wss://{$host}:4443"
|
||||
: '';
|
||||
|
||||
$nonce = Vite::cspNonce();
|
||||
$jsBo = $request->routeIs('bo*') ? "'unsafe-eval'" : '';
|
||||
$jsdelivrUrl = 'https://cdn.jsdelivr.net';
|
||||
$openStreetMapTiles = 'https://*.tile.openstreetmap.org';
|
||||
|
||||
$this->declareNonce($nonce);
|
||||
$this->removeUnwantedHeaders($this->unwantedHeaderList);
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
$response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
|
||||
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
||||
$response->headers->set('X-XSS-Protection', '1; mode=block');
|
||||
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
|
||||
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
|
||||
|
||||
// * Ignore CSP on some conditions.
|
||||
if (
|
||||
$appDebug && (
|
||||
$response->isClientError() || // Ignition
|
||||
$response->isServerError() || // Ignition
|
||||
Vite::isRunningHot() || // Vite
|
||||
($telescopeEnabled && str_starts_with($request->path(), 'telescope')) // Telescope
|
||||
)
|
||||
) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$cspPolicies = [
|
||||
"default-src 'none';",
|
||||
"base-uri 'self';",
|
||||
"manifest-src 'self';",
|
||||
"media-src 'self' blob: {$appUrl};",
|
||||
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
|
||||
"connect-src 'self' blob: " . implode(' ', [
|
||||
'https://yl.s-web.fr/',
|
||||
// * BAN address autocomplete (api-adresse.data.gouv.fr)
|
||||
'https://api-adresse.data.gouv.fr',
|
||||
'https://maps.googleapis.com',
|
||||
// * VITE DEV
|
||||
$viteDevSocket,
|
||||
$viteDevOrigin,
|
||||
]) . ';',
|
||||
"img-src 'self' data: blob: " . implode(' ', [
|
||||
'https://maps.googleapis.com',
|
||||
'https://maps.gstatic.com',
|
||||
$viteDevOrigin,
|
||||
$openStreetMapTiles,
|
||||
]) . ' data:;',
|
||||
'child-src ' . implode(' ', []) . ';',
|
||||
"frame-src 'self' " . implode(' ', [
|
||||
'https://www.google.com/recaptcha/',
|
||||
'https://recaptcha.google.com/recaptcha/',
|
||||
'https://www.google.com/maps/',
|
||||
'https://www.youtube.com/embed/',
|
||||
'https://player.vimeo.com/',
|
||||
'https://e.issuu.com/embed.html?',
|
||||
]) . ';',
|
||||
"object-src 'none';",
|
||||
"font-src 'self' data: " . \implode(' ', [
|
||||
'https://fonts.gstatic.com',
|
||||
// * VITE DEV
|
||||
$viteDevOrigin,
|
||||
]) . ';',
|
||||
// ! Using CKEditor will must have unsafe-inline style
|
||||
"style-src 'self' 'unsafe-inline' " . \implode(' ', [
|
||||
$jsdelivrUrl,
|
||||
'https://cdnjs.cloudflare.com',
|
||||
'https://fonts.googleapis.com',
|
||||
'https://use.fontawesome.com',
|
||||
// * File Manager
|
||||
// * VITE DEV
|
||||
$viteDevOrigin,
|
||||
]) . ';',
|
||||
|
||||
// ! If you dont use ckeditor use this
|
||||
// "style-src 'self' 'nonce-$nonce';",
|
||||
"script-src 'self' 'nonce-$nonce' 'strict-dynamic' " . \implode(' ', [
|
||||
'https: blob:',
|
||||
$jsBo,
|
||||
'https://www.googletagmanager.com',
|
||||
'https://cdnjs.cloudflare.com',
|
||||
'https://www.google-analytics.com',
|
||||
// * VITE DEV
|
||||
$viteDevOrigin,
|
||||
]) . ';',
|
||||
];
|
||||
|
||||
$response->headers->set(
|
||||
'Content-Security-Policy',
|
||||
implode(' ', $cspPolicies)
|
||||
);
|
||||
$response->headers->set('Feature-Policy', 'fullscreen \'self\'; geolocation \'self\';');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unwanted headers
|
||||
*
|
||||
* @param string[] $headerList List of headers to remove from the response
|
||||
* @return void
|
||||
*/
|
||||
private function removeUnwantedHeaders(array $headerList)
|
||||
{
|
||||
foreach ($headerList as $header) {
|
||||
header_remove($header);
|
||||
}
|
||||
}
|
||||
|
||||
private function declareNonce(string $value): void
|
||||
{
|
||||
Vite::useCspNonce($value);
|
||||
$this->container->singleton('csp_nonce', $value);
|
||||
}
|
||||
}
|
||||
40
app/Http/Requests/Back/Products/IndexProductRequest.php
Normal file
40
app/Http/Requests/Back/Products/IndexProductRequest.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Products;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class IndexProductRequest extends FormRequest
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AdminAuthService $authService
|
||||
) {
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->authService->check();
|
||||
}
|
||||
|
||||
public function getSearchValue(): ?string
|
||||
{
|
||||
return $this->has('search') ?
|
||||
$this->string('search')->value() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['sometimes', 'string'],
|
||||
];
|
||||
}
|
||||
}
|
||||
36
app/Http/Requests/Back/Products/StoreProductRequest.php
Normal file
36
app/Http/Requests/Back/Products/StoreProductRequest.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Products;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreProductRequest extends FormRequest
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AdminAuthService $authService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->authService->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
22
app/Http/Requests/Back/Products/UpdateProductRequest.php
Normal file
22
app/Http/Requests/Back/Products/UpdateProductRequest.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Products;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class UpdateProductRequest extends StoreProductRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
43
app/Http/Requests/Back/Recipes/IndexRecipeRequest.php
Normal file
43
app/Http/Requests/Back/Recipes/IndexRecipeRequest.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Recipes;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class IndexRecipeRequest extends FormRequest
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AdminAuthService $authService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->authService->check();
|
||||
}
|
||||
|
||||
public function getSearchValue(): ?string
|
||||
{
|
||||
return $this->has('search') ?
|
||||
$this->string('search')->value() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['sometimes', 'string'],
|
||||
];
|
||||
}
|
||||
}
|
||||
36
app/Http/Requests/Back/Recipes/StoreRecipeRequest.php
Normal file
36
app/Http/Requests/Back/Recipes/StoreRecipeRequest.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Recipes;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreRecipeRequest extends FormRequest
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AdminAuthService $authService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->authService->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
36
app/Http/Requests/Back/Recipes/UpdateRecipeRequest.php
Normal file
36
app/Http/Requests/Back/Recipes/UpdateRecipeRequest.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Back\Recipes;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateRecipeRequest extends FormRequest
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AdminAuthService $authService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return $this->authService->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,14 @@ use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
use Uwil\LaravelActivityLogs\Traits\HasActivityLog;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasCache;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasModelNaming;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasUwilImages;
|
||||
use Uwil\LaravelI18n\Interfaces\TranslatableModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
|
@ -48,11 +55,19 @@ use Illuminate\Support\Str;
|
|||
*
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Product extends Model
|
||||
class Product extends Model implements TranslatableModel
|
||||
{
|
||||
use HasActivityLog;
|
||||
use HasCache;
|
||||
|
||||
/** @use HasFactory<\Database\Factories\ProductFactory> */
|
||||
use HasFactory;
|
||||
|
||||
use HasModelNaming;
|
||||
use HasTranslations;
|
||||
use HasUwilImages;
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
|
|
|
|||
|
|
@ -6,14 +6,21 @@ namespace App\Models;
|
|||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Domain\Models\ValueObjects\Recipes\Inspiration;
|
||||
use Domain\Models\ValueObjects\Recipes\Season;
|
||||
use Domain\Models\ValueObjects\Products\ProductRange;
|
||||
use Domain\Models\ValueObjects\Recipes\ConsumptionTime;
|
||||
use Domain\Models\ValueObjects\Recipes\Inspiration;
|
||||
use Domain\Models\ValueObjects\Recipes\Season;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
use Uwil\LaravelActivityLogs\Traits\HasActivityLog;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasCache;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasModelNaming;
|
||||
use Uwil\LaravelBackend\Traits\Models\HasUwilImages;
|
||||
use Uwil\LaravelI18n\Interfaces\TranslatableModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
|
@ -36,14 +43,24 @@ use Illuminate\Support\Str;
|
|||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Product> $products
|
||||
*
|
||||
* @method static \Database\Factories\RecipeFactory factory($count = null, $state = [])
|
||||
*
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Recipe extends Model
|
||||
class Recipe extends Model implements TranslatableModel
|
||||
{
|
||||
use HasActivityLog;
|
||||
use HasCache;
|
||||
|
||||
/** @use HasFactory<\Database\Factories\RecipeFactory> */
|
||||
use HasFactory;
|
||||
|
||||
use HasModelNaming;
|
||||
use HasTranslations;
|
||||
use HasUwilImages;
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
|
|
@ -59,7 +76,7 @@ class Recipe extends Model
|
|||
'details',
|
||||
'ingredients_list',
|
||||
'preparation_steps',
|
||||
'tips_and_advices'
|
||||
'tips_and_advices',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
|
|
|||
31
app/Policies/ProductPolicy.php
Normal file
31
app/Policies/ProductPolicy.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Product;
|
||||
use Uwil\LaravelBackend\Models\User;
|
||||
|
||||
class ProductPolicy
|
||||
{
|
||||
public function viewAny(User $_): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function create(User $_): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update(User $_, Product $__): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete(User $_, Product $__): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
31
app/Policies/RecipePolicy.php
Normal file
31
app/Policies/RecipePolicy.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Recipe;
|
||||
use Uwil\LaravelBackend\Models\User;
|
||||
|
||||
class RecipePolicy
|
||||
{
|
||||
public function viewAny(User $_): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function create(User $_): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update(User $_, Recipe $__): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete(User $_, Recipe $__): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
24
app/Providers/AppServiceProvider.php
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Services\AdminAuthService;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->singleton(
|
||||
AdminAuthService::class,
|
||||
function () {
|
||||
$guard = Auth::guard('backend');
|
||||
return new AdminAuthService($guard);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
58
app/Services/AdminAuthService.php
Normal file
58
app/Services/AdminAuthService.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\AuthServiceException;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Uwil\LaravelBackend\Models\User;
|
||||
|
||||
class AdminAuthService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly StatefulGuard $guard
|
||||
) {}
|
||||
|
||||
public function canWithUser(\UnitEnum | string $abilities, mixed $arguments = []): bool
|
||||
{
|
||||
return $this->getUser()?->can($abilities, $arguments) ?? false;
|
||||
}
|
||||
|
||||
public function check(): bool
|
||||
{
|
||||
return $this->guard->check();
|
||||
}
|
||||
|
||||
public function guest(): bool
|
||||
{
|
||||
return ! $this->check();
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
$user = $this->guard->user();
|
||||
|
||||
if ($user && ! ($user instanceof User)) {
|
||||
throw new \InvalidArgumentException('Auth service needs a backend guard');
|
||||
}
|
||||
|
||||
return $user ? clone $user : null;
|
||||
}
|
||||
|
||||
public function getUserAsMandatory(): User
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($user === null) {
|
||||
throw new AuthServiceException('Authenticated user is required from here');
|
||||
}
|
||||
|
||||
return clone $user;
|
||||
}
|
||||
|
||||
public function getMandatoryUserId(): string
|
||||
{
|
||||
return (string) $this->getUserAsMandatory()->id;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,12 +12,15 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||
->withRouting(
|
||||
health: '/up',
|
||||
)
|
||||
->withProviders([
|
||||
\App\Providers\AppServiceProvider::class
|
||||
])
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->web(append: [
|
||||
\Uwil\LaravelI18n\Middlewares\ForceLocale::class,
|
||||
\App\Http\Middlewares\HandleInertiaRequests::class,
|
||||
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
|
||||
\Uwil\LaravelCommon\Middlewares\SecureHeaders::class,
|
||||
\App\Http\Middlewares\SecureHeaders::class,
|
||||
\Uwil\LaravelCommon\Middlewares\TrimStrings::class,
|
||||
\Uwil\LaravelCommon\Middlewares\TrustHosts::class,
|
||||
\Uwil\LaravelCommon\Middlewares\TrustProxies::class,
|
||||
|
|
|
|||
105
bun.lock
105
bun.lock
|
|
@ -58,6 +58,7 @@
|
|||
"slugify": "^1.6.9",
|
||||
"swiper": "^12.2.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"typescript": "^6.0.3",
|
||||
"vaul": "^1.1.2",
|
||||
"ziggy-js": "^2.6.3",
|
||||
"zod": "^4.4.3",
|
||||
|
|
@ -86,6 +87,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@uwil/husky-config": "^1.0.1",
|
||||
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"autoprefixer": "^10.5.2",
|
||||
"concurrently": "^9.2.3",
|
||||
|
|
@ -113,6 +115,7 @@
|
|||
"stylelint-scss": "^6.14.0",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript-eslint": "^8.62.1",
|
||||
"vite": "^8.1.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-stylelint": "^6.3.0",
|
||||
|
|
@ -608,46 +611,6 @@
|
|||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.0", "", { "dependencies": { "@typescript-eslint/types": "8.62.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ=="],
|
||||
|
||||
"@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.1-rc", "", { "os": "aix", "cpu": "ppc64" }, "sha512-oqq2ZfEJ7BQuufcC3QBQndZLPNyamYNHLao8lKRBeeSkZKypBqxPSgkzrcFZtbYcIaBvpiyUnQP9MT7DEYHWbw=="],
|
||||
|
||||
"@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.1-rc", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Slc0yTftT2F/uGDmtPst8ijydneL6uZaLEyr2UjahxZpbhTjHFBJ5agXtVz/TL4A+ldxzjzj+E8QtLZlh/5mXw=="],
|
||||
|
||||
"@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.1-rc", "", { "os": "darwin", "cpu": "x64" }, "sha512-h68iFW/LbA1/BsGgSRGFw981/3s1f/rY27YrmeZNuN+ly7dI+fiDduwT9ZT9866x2onoKNRq7PTyxSKyKDzfAQ=="],
|
||||
|
||||
"@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.1-rc", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-DE+ppd8Ix2c6OMuRkKY4PJ4hngMGJ9M95OQUP17p9xL/1IKXof7npIeuusMN/bgL5o5JzMfSGh+N+5scTYRg0Q=="],
|
||||
|
||||
"@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.1-rc", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ST1ozHMw0u+CLOnWkcTyWDMV4Qn9osZ6fd1V1lnKDM1t0hZIp81mdGpdHxyHJjd7jdGrb6Gb/QXcZ1uqZ0t5zw=="],
|
||||
|
||||
"@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.1-rc", "", { "os": "linux", "cpu": "arm" }, "sha512-gHmHwT5Naq5CKM8g9bbaGeEpnwQEvWCLn3fwP4K2m61VQdDKkPk0Dhab/OoZ4LV2SrMddmclYXTzpyg23YGt5g=="],
|
||||
|
||||
"@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.1-rc", "", { "os": "linux", "cpu": "arm64" }, "sha512-N46pRihK3t5zD5MUtTQcdmQUqr1WI4U2nxno1gLwOtRSsB4krFkRjPHcQNG7h2DtRkX64rQiReX6WKwg2wprMA=="],
|
||||
|
||||
"@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.1-rc", "", { "os": "linux", "cpu": "none" }, "sha512-G17Sao312rgiPBTh2F4nOpLpa3CcnBSaNhqNghZk2LNhnsp1RaMO5HMq2me21gqu9xLpc6CIgHtOzU6JBgNlfg=="],
|
||||
|
||||
"@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.1-rc", "", { "os": "linux", "cpu": "none" }, "sha512-0FQspOb5UsQ4tQKvWgUO3pS9OIWkP7/8dPRWq+CRazJUeQZ4LBjtYK52jg5iIOrvItrVl2CwvRtrU3/9OihwJg=="],
|
||||
|
||||
"@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.1-rc", "", { "os": "linux", "cpu": "ppc64" }, "sha512-SUmwfVBEv6A2Ld0eWfcvW0FqrgemfQL8jFGOmV1qYxsDqumjE5DekHXqbstgmbE4SHr4rrjHjvmuGCY+kTH/vw=="],
|
||||
|
||||
"@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.1-rc", "", { "os": "linux", "cpu": "none" }, "sha512-rxeqnNnGiYzv/LlPHi/3+4p0ooR1cNJLjRIHXKovtiVmxXGJq6gtw8VSpbHuWPekyFMXgIAoLCZN0SQ51rAALQ=="],
|
||||
|
||||
"@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.1-rc", "", { "os": "linux", "cpu": "s390x" }, "sha512-RYWCHCiPypxajdRHM2CNK/eM22e4Ex5TTjV2pXf7PTtBowGr0xX8i8kIMknyZS0LX2QfleYHouaoMVsFDSle3g=="],
|
||||
|
||||
"@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.1-rc", "", { "os": "linux", "cpu": "x64" }, "sha512-PfLJSu0JzroDkqw2m4nqflPEcn8yev0m/vHFQlY9EzHorzjR6QG0wL8AJHvnD1e6h1s76AZngJ5u+z1K/D/HKw=="],
|
||||
|
||||
"@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.1-rc", "", { "os": "none", "cpu": "arm64" }, "sha512-FfbPxH3dTfp8yVIaNM7bdWTixXuyxpzoemluqcqMROSIz+ImpCG3Q9HO9Ptzp9/giv+P9YYEnCMSXh61migj2w=="],
|
||||
|
||||
"@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.1-rc", "", { "os": "none", "cpu": "x64" }, "sha512-FzdTfSzhRYb6hlav6K3cI5RVgcvCTvNAu/vc+t7B6AmZkThQ+t/1ntnvT5fnHmY1Az2RIBw7/b+qtCEG61HJTQ=="],
|
||||
|
||||
"@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.1-rc", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-PQGhlxfNig+0YQ9Wwzd0USPBkt6w/ZqkBQWsU7G/0JkTzunJel+jSWwhKw4947pak/m7hGSeYiI04xReDLGZww=="],
|
||||
|
||||
"@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.1-rc", "", { "os": "openbsd", "cpu": "x64" }, "sha512-WJ7NYgO2mHmLUkI/tZ+hl8lFd26QPJqO8ONOHNuYbdsybLvSB6B6sep222JIVrOfPRDGvFinbGGB+l3m1FWRWA=="],
|
||||
|
||||
"@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.1-rc", "", { "os": "sunos", "cpu": "x64" }, "sha512-UYjDeUxd765V9qcwlUPk4pEXyL0i3G76CJm9baK4i99u1pGO1psf3nXDw4MMmElVOPvGbZag99ZR/O59E2OX6w=="],
|
||||
|
||||
"@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.1-rc", "", { "os": "win32", "cpu": "arm64" }, "sha512-KzXzFSXZOm7zvEt2Aw0MsB2LbTL88znAiVqTDNAOHdlEb7brgmUQh/X2wM/8Be+N0fjEqWKl65cBKNwpWEbJiw=="],
|
||||
|
||||
"@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.1-rc", "", { "os": "win32", "cpu": "x64" }, "sha512-98R3+OqDr/r0/PLWEoXu88AE0lGVLNd335Ew8ONgzK1JWkNs4ou/5BGt3Or1ij4iXjH+c7PRL+jFjCbtWze+EA=="],
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.2", "", {}, "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA=="],
|
||||
|
||||
"@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.12.2", "", { "os": "android", "cpu": "arm" }, "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w=="],
|
||||
|
|
@ -696,6 +659,8 @@
|
|||
|
||||
"@uwil/husky-config": ["@uwil/husky-config@1.0.1", "https://lab.s-web.fr/api/v4/projects/259/packages/npm/@uwil/husky-config/-/@uwil/husky-config-1.0.1.tgz", { "dependencies": { "@commitlint/cli": "^20.5.0", "@commitlint/config-conventional": "^20.5.0", "husky": "^9.1.7" } }, "sha1-VGchal1LcEFXNFsQZxh5pn4495Q="],
|
||||
|
||||
"@vitejs/plugin-basic-ssl": ["@vitejs/plugin-basic-ssl@2.3.0", "", { "peerDependencies": { "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.3", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg=="],
|
||||
|
||||
"acorn": ["acorn@8.17.0", "", { "bin": "bin/acorn" }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="],
|
||||
|
|
@ -1672,7 +1637,9 @@
|
|||
|
||||
"typed-array-length": ["typed-array-length@1.0.8", "", { "dependencies": { "call-bind": "^1.0.9", "for-each": "^0.3.5", "gopd": "^1.2.0", "is-typed-array": "^1.1.15", "possible-typed-array-names": "^1.1.0", "reflect.getprototypeof": "^1.0.10" } }, "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g=="],
|
||||
|
||||
"typescript": ["typescript@7.0.1-rc", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.1-rc", "@typescript/typescript-darwin-arm64": "7.0.1-rc", "@typescript/typescript-darwin-x64": "7.0.1-rc", "@typescript/typescript-freebsd-arm64": "7.0.1-rc", "@typescript/typescript-freebsd-x64": "7.0.1-rc", "@typescript/typescript-linux-arm": "7.0.1-rc", "@typescript/typescript-linux-arm64": "7.0.1-rc", "@typescript/typescript-linux-loong64": "7.0.1-rc", "@typescript/typescript-linux-mips64el": "7.0.1-rc", "@typescript/typescript-linux-ppc64": "7.0.1-rc", "@typescript/typescript-linux-riscv64": "7.0.1-rc", "@typescript/typescript-linux-s390x": "7.0.1-rc", "@typescript/typescript-linux-x64": "7.0.1-rc", "@typescript/typescript-netbsd-arm64": "7.0.1-rc", "@typescript/typescript-netbsd-x64": "7.0.1-rc", "@typescript/typescript-openbsd-arm64": "7.0.1-rc", "@typescript/typescript-openbsd-x64": "7.0.1-rc", "@typescript/typescript-sunos-x64": "7.0.1-rc", "@typescript/typescript-win32-arm64": "7.0.1-rc", "@typescript/typescript-win32-x64": "7.0.1-rc" }, "bin": { "tsc": "bin/tsc" } }, "sha512-drEP77wK7CCDlPfXZH4e008UUQOsw1DFmHmZOZjuNA+yoDLLnSNMZRXi90NbV/1LVo7SbNLq1bs3jjvk49TEqQ=="],
|
||||
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
||||
|
||||
"typescript-eslint": ["typescript-eslint@8.62.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.62.1", "@typescript-eslint/parser": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1", "@typescript-eslint/utils": "8.62.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw=="],
|
||||
|
||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||
|
||||
|
|
@ -1846,6 +1813,14 @@
|
|||
|
||||
"tailwindcss/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.62.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/type-utils": "8.62.1", "@typescript-eslint/utils": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.62.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.62.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.62.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.62.1", "@typescript-eslint/tsconfig-utils": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.62.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g=="],
|
||||
|
||||
"vite-plugin-full-reload/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
|
||||
|
||||
"vite-plugin-stylelint/@rollup/pluginutils": ["@rollup/pluginutils@5.4.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg=="],
|
||||
|
|
@ -1864,6 +1839,54 @@
|
|||
|
||||
"table/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1" } }, "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/typescript-estree": "8.62.1", "@typescript-eslint/utils": "8.62.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1" } }, "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.62.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.62.1", "@typescript-eslint/types": "^8.62.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.62.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/semver": ["semver@7.8.5", "", { "bin": "bin/semver.js" }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "@typescript-eslint/visitor-keys": "8.62.1" } }, "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.62.1", "", {}, "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.62.1", "", { "dependencies": { "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\Migration;
|
|||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration
|
||||
return new class () extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
|
|
@ -42,6 +42,8 @@ return new class() extends Migration
|
|||
|
||||
$table->string('pdf')->nullable();
|
||||
|
||||
$table->softDeletes();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\Migration;
|
|||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration
|
||||
return new class () extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
|
|
@ -35,6 +35,8 @@ return new class() extends Migration
|
|||
$table->text('preparation_steps');
|
||||
$table->text('tips_and_advices')->nullable();
|
||||
|
||||
$table->softDeletes();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
"classes" => [
|
||||
// "users" => "utilisateur|utilisateurs",
|
||||
'classes' => [
|
||||
'product' => 'product|products',
|
||||
'recipe' => 'recipe|recipes',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
"classes" => [
|
||||
// "users" => "utilisateur|utilisateurs",
|
||||
'classes' => [
|
||||
'product' => 'produit|produits',
|
||||
'recipe' => 'recette|recettes',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -168,12 +168,14 @@ return [
|
|||
'available' => 'disponible',
|
||||
'birthday' => 'anniversaire',
|
||||
'body' => 'corps',
|
||||
'category' => 'catégorie',
|
||||
'city' => 'ville',
|
||||
'color' => 'color',
|
||||
'company' => 'entreprise',
|
||||
'compilation' => 'compilation',
|
||||
'concept' => 'concept',
|
||||
'conditions' => 'conditions',
|
||||
'consomption_time' => 'moment de consommation',
|
||||
'content' => 'contenu',
|
||||
'contest' => 'contest',
|
||||
'country' => 'pays',
|
||||
|
|
@ -206,7 +208,9 @@ return [
|
|||
'image_main' => 'image principale',
|
||||
'image_mobile' => 'image mobile',
|
||||
'images' => 'images',
|
||||
'inspiration' => 'inspiration',
|
||||
'is_audience_winner' => 'est le gagnant du public',
|
||||
'is_egalim' => 'EGalim',
|
||||
'is_hidden' => 'est caché',
|
||||
'is_subscribed' => 'est abonné',
|
||||
'is_visible' => 'est visible',
|
||||
|
|
@ -235,6 +239,7 @@ return [
|
|||
'preview' => 'aperçu',
|
||||
'price' => 'prix',
|
||||
'product_id' => 'identifiant du produit',
|
||||
'product_range' => 'gamme',
|
||||
'product_uid' => 'UID du produit',
|
||||
'product_uuid' => 'UUID du produit',
|
||||
'promo_code' => 'code promo',
|
||||
|
|
@ -252,6 +257,7 @@ return [
|
|||
'role' => 'rôle',
|
||||
'rule' => 'règle',
|
||||
'rules' => 'règles',
|
||||
'season' => 'saison',
|
||||
'second' => 'seconde',
|
||||
'sex' => 'sexe',
|
||||
'shipment' => 'expédition',
|
||||
|
|
@ -269,6 +275,7 @@ return [
|
|||
'tag' => 'mot clé',
|
||||
'tags' => 'mots clés',
|
||||
'teacher' => 'professeur',
|
||||
'technology' => 'technologie',
|
||||
'terms' => 'conditions',
|
||||
'test_description' => 'description du test',
|
||||
'test_locale' => 'localisation du test',
|
||||
|
|
|
|||
486
package-lock.json
generated
486
package-lock.json
generated
|
|
@ -60,6 +60,7 @@
|
|||
"slugify": "^1.6.9",
|
||||
"swiper": "^12.2.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"typescript": "^6.0.3",
|
||||
"vaul": "^1.1.2",
|
||||
"ziggy-js": "^2.6.3",
|
||||
"zod": "^4.4.3",
|
||||
|
|
@ -88,6 +89,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@uwil/husky-config": "^1.0.1",
|
||||
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"autoprefixer": "^10.5.2",
|
||||
"concurrently": "^9.2.3",
|
||||
|
|
@ -115,6 +117,7 @@
|
|||
"stylelint-scss": "^6.14.0",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript-eslint": "^8.62.1",
|
||||
"vite": "^8.1.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-stylelint": "^6.3.0"
|
||||
|
|
@ -4343,17 +4346,17 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz",
|
||||
"integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==",
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz",
|
||||
"integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.62.0",
|
||||
"@typescript-eslint/type-utils": "8.62.0",
|
||||
"@typescript-eslint/utils": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0",
|
||||
"@typescript-eslint/scope-manager": "8.62.1",
|
||||
"@typescript-eslint/type-utils": "8.62.1",
|
||||
"@typescript-eslint/utils": "8.62.1",
|
||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
|
|
@ -4366,21 +4369,103 @@
|
|||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz",
|
||||
"integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==",
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz",
|
||||
"integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/typescript-estree": "8.62.0",
|
||||
"@typescript-eslint/utils": "8.62.0",
|
||||
"@typescript-eslint/scope-manager": "8.62.1",
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz",
|
||||
"integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.62.1",
|
||||
"@typescript-eslint/types": "^8.62.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz",
|
||||
"integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"@typescript-eslint/visitor-keys": "8.62.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz",
|
||||
"integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz",
|
||||
"integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
||||
"@typescript-eslint/utils": "8.62.1",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
|
|
@ -4396,17 +4481,31 @@
|
|||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz",
|
||||
"integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==",
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz",
|
||||
"integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz",
|
||||
"integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.62.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0",
|
||||
"@typescript-eslint/project-service": "8.62.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.62.1",
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
|
|
@ -4424,56 +4523,17 @@
|
|||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz",
|
||||
"integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.62.0",
|
||||
"@typescript-eslint/types": "^8.62.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz",
|
||||
"integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz",
|
||||
"integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==",
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz",
|
||||
"integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/typescript-estree": "8.62.0"
|
||||
"@typescript-eslint/scope-manager": "8.62.1",
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"@typescript-eslint/typescript-estree": "8.62.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
|
@ -4487,231 +4547,14 @@
|
|||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz",
|
||||
"integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.62.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz",
|
||||
"integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.62.0",
|
||||
"@typescript-eslint/types": "^8.62.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz",
|
||||
"integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
|
||||
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz",
|
||||
"integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/typescript-estree": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz",
|
||||
"integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.62.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz",
|
||||
"integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.62.0",
|
||||
"@typescript-eslint/types": "^8.62.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz",
|
||||
"integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
|
||||
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz",
|
||||
"integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/visitor-keys": "8.62.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz",
|
||||
"integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.62.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz",
|
||||
"integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==",
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz",
|
||||
"integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.62.0",
|
||||
"@typescript-eslint/types": "8.62.1",
|
||||
"eslint-visitor-keys": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -5070,6 +4913,19 @@
|
|||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-basic-ssl": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz",
|
||||
"integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz",
|
||||
|
|
@ -12753,6 +12609,19 @@
|
|||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
|
||||
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-interface-checker": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||
|
|
@ -12883,6 +12752,43 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.62.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz",
|
||||
"integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.62.1",
|
||||
"@typescript-eslint/parser": "8.62.1",
|
||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
||||
"@typescript-eslint/utils": "8.62.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@uwil/husky-config": "^1.0.1",
|
||||
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"autoprefixer": "^10.5.2",
|
||||
"concurrently": "^9.2.3",
|
||||
|
|
@ -65,6 +66,7 @@
|
|||
"stylelint-scss": "^6.14.0",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript-eslint": "^8.62.1",
|
||||
"vite": "^8.1.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-stylelint": "^6.3.0"
|
||||
|
|
@ -124,6 +126,7 @@
|
|||
"slugify": "^1.6.9",
|
||||
"swiper": "^12.2.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"typescript": "^6.0.3",
|
||||
"vaul": "^1.1.2",
|
||||
"ziggy-js": "^2.6.3",
|
||||
"zod": "^4.4.3",
|
||||
|
|
|
|||
|
|
@ -1,28 +1,23 @@
|
|||
// * Packages
|
||||
import { Link, usePage } from "@inertiajs/react";
|
||||
import { ElementType, ReactNode, useEffect, useRef } from "react";
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
MoreHorizontalIcon,
|
||||
CookingPotIcon,
|
||||
EggIcon,
|
||||
HomeIcon,
|
||||
MoreHorizontalIcon,
|
||||
SquareArrowOutUpRightIcon,
|
||||
TelescopeIcon,
|
||||
TelescopeIcon
|
||||
} from "lucide-react";
|
||||
import { ElementType, ReactNode, useEffect, useRef } from "react";
|
||||
import { route } from "ziggy-js";
|
||||
// * Components shadcn
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarHeader,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuAction,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
|
@ -30,25 +25,32 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleTrigger,
|
||||
CollapsibleContent,
|
||||
} from "@/components/ui/collapsible";
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarMenu,
|
||||
SidebarMenuAction,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
// * Other
|
||||
import ApplicationLogo from "@/back/Components/ApplicationLogo";
|
||||
import { SidebarRegistry } from "@/back/Components/Layout/Sidebar/SidebarRegistry";
|
||||
import Views from "@/back/lib/actions";
|
||||
import { AuthProp } from "@/back/types/global";
|
||||
import str from "@/hooks/use-string";
|
||||
import useTrans from "@/hooks/use-translations";
|
||||
import { AppEnv, LaravelEnum } from "@/types/global";
|
||||
import { AuthProp } from "@/back/types/global";
|
||||
import { GetTranslation } from "@/lib/utils";
|
||||
import { AppEnv, LaravelEnum } from "@/types/global";
|
||||
|
||||
export type NavListLinksProps = {
|
||||
/** Title of the button. */
|
||||
|
|
@ -137,6 +139,8 @@ export default function AppSidebar() {
|
|||
const transModules = useTrans("uwil-backend::back.modules");
|
||||
const transAdmin = useTrans("uwil-backend::enums.user-role.admin");
|
||||
const transTelescope = useTrans("uwil-backend::back.telescope");
|
||||
const transProducts = useTrans("models.classes.product", { choice: Infinity });
|
||||
const transRecipes = useTrans("models.classes.recipe", { choice: Infinity });
|
||||
|
||||
const navList: NavListProps = [
|
||||
{
|
||||
|
|
@ -156,6 +160,18 @@ export default function AppSidebar() {
|
|||
icon: SquareArrowOutUpRightIcon,
|
||||
},
|
||||
...SidebarRegistry.getAll(auth, "pages"),
|
||||
{
|
||||
title: str(transProducts).ucFirst().value(),
|
||||
model: "products",
|
||||
show: true,
|
||||
icon: EggIcon,
|
||||
},
|
||||
{
|
||||
title: str(transRecipes).ucFirst().value(),
|
||||
model: "recipes",
|
||||
show: true,
|
||||
icon: CookingPotIcon,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
// * Packages
|
||||
import { AlertCircleIcon, SquareArrowOutUpRightIcon } from "lucide-react";
|
||||
import { usePage } from "@inertiajs/react";
|
||||
import { AlertCircleIcon, SquareArrowOutUpRightIcon } from "lucide-react";
|
||||
// * Components shadcn
|
||||
import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
} from "@/components/ui/card";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
// * Other
|
||||
import logoUwilReportDark from "&/images/logos/uwil-report-dark.svg";
|
||||
import logoUwilReportLight from "&/images/logos/uwil-report-light.svg";
|
||||
import logoUwilSupportDark from "&/images/logos/uwil-support-dark.svg";
|
||||
import logoUwilSupportLight from "&/images/logos/uwil-support-light.svg";
|
||||
import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip";
|
||||
import useTrans from "@/hooks/use-translations";
|
||||
import { AppEnv } from "@/types/global";
|
||||
import logoUwilReportLight from "&/images/logos/uwil-report-light.svg";
|
||||
import logoUwilReportDark from "&/images/logos/uwil-report-dark.svg";
|
||||
import logoUwilSupportLight from "&/images/logos/uwil-support-light.svg";
|
||||
import logoUwilSupportDark from "&/images/logos/uwil-support-dark.svg";
|
||||
|
||||
export default function Dashboard() {
|
||||
const appEnv = usePage().props.appEnv as AppEnv;
|
||||
|
|
|
|||
190
resources/ts/back/Pages/Products/Index.tsx
Normal file
190
resources/ts/back/Pages/Products/Index.tsx
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// * Packages
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import { CheckIcon, PlusIcon, XIcon } from "lucide-react";
|
||||
import { route } from "ziggy-js";
|
||||
// * Components shadcn
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { usePage } from "@inertiajs/react";
|
||||
// * Other
|
||||
import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip";
|
||||
import DataTable from "@/back/Components/Table/DataTable";
|
||||
import DataTableFilterButton from "@/back/Components/Table/DataTableFilterButton";
|
||||
import DataTableSearch from "@/back/Components/Table/DataTableSearch";
|
||||
import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout";
|
||||
import Views from "@/back/lib/actions";
|
||||
import { AuthProp, DefaultModel, Resource } from "@/back/types/global";
|
||||
import str from "@/hooks/use-string";
|
||||
import useTrans from "@/hooks/use-translations";
|
||||
import { GetFormatedDate, GetTranslation } from "@/lib/utils";
|
||||
|
||||
const getColumns = () => {
|
||||
return [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "category",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
// Handle enum object or string
|
||||
const val = row.getValue("category") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "technology",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
// Handle enum object or string
|
||||
const val = row.getValue("technology") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "is_egalim",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`border-0 ${
|
||||
row.getValue("is_egalim")
|
||||
? "bg-green-200 dark:bg-green-900"
|
||||
: "bg-red-200 dark:bg-red-900"
|
||||
}`}
|
||||
>
|
||||
{row.getValue("is_egalim") ? (
|
||||
<CheckIcon size={15} className="mr-1" />
|
||||
) : (
|
||||
<XIcon size={15} className="mr-1" />
|
||||
)}
|
||||
{str(
|
||||
GetTranslation(
|
||||
row.getValue("is_egalim")
|
||||
? "uwil-backend::back.yes"
|
||||
: "uwil-backend::back.no",
|
||||
),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "updated_at",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => (
|
||||
<Badge variant="secondary">
|
||||
{GetFormatedDate(row.getValue("updated_at"))}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export default function Index({
|
||||
paginatedModels,
|
||||
searchFields,
|
||||
}: Readonly<{
|
||||
paginatedModels: Resource;
|
||||
searchFields: string;
|
||||
}>) {
|
||||
const { auth } = usePage().props as unknown as {
|
||||
auth: AuthProp;
|
||||
};
|
||||
const { create } = auth.policies.products || { create: true };
|
||||
const actionModels = [
|
||||
Views.VISUALIZATION,
|
||||
Views.EDITION,
|
||||
Views.DUPLICATION,
|
||||
Views.DELETION,
|
||||
];
|
||||
|
||||
const columns = getColumns();
|
||||
const transCrudAddEntry = useTrans("uwil-backend::back.crud_add_entry");
|
||||
const afterNode = () => {
|
||||
return (
|
||||
create && (
|
||||
<BtnOptionnalLinkWithTooltip
|
||||
link={route('back.products.create')}
|
||||
content={<PlusIcon />}
|
||||
tooltipContent={<p>{transCrudAddEntry}</p>}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
title={str(
|
||||
useTrans('models.classes.product', { choice: Infinity }),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
afterNode={afterNode()}
|
||||
>
|
||||
<DataTableSearch modelRoute='products' searchFields={searchFields} />
|
||||
<DataTable
|
||||
columns={columns}
|
||||
modelRoute='products'
|
||||
modelsPaginate={paginatedModels}
|
||||
actions={actionModels}
|
||||
/>
|
||||
</AuthenticatedLayout>
|
||||
);
|
||||
}
|
||||
194
resources/ts/back/Pages/Recipes/Index.tsx
Normal file
194
resources/ts/back/Pages/Recipes/Index.tsx
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
// * Packages
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import { CheckIcon, PlusIcon, XIcon } from "lucide-react";
|
||||
import { route } from "ziggy-js";
|
||||
// * Components shadcn
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { usePage } from "@inertiajs/react";
|
||||
// * Other
|
||||
import BtnOptionnalLinkWithTooltip from "@/back/Components/BtnOptionnalLinkWithTooltip";
|
||||
import DataTable from "@/back/Components/Table/DataTable";
|
||||
import DataTableFilterButton from "@/back/Components/Table/DataTableFilterButton";
|
||||
import DataTableSearch from "@/back/Components/Table/DataTableSearch";
|
||||
import AuthenticatedLayout from "@/back/Layouts/AuthenticatedLayout";
|
||||
import Views from "@/back/lib/actions";
|
||||
import { AuthProp, DefaultModel, Resource } from "@/back/types/global";
|
||||
import str from "@/hooks/use-string";
|
||||
import useTrans from "@/hooks/use-translations";
|
||||
import { GetFormatedDate, GetTranslation } from "@/lib/utils";
|
||||
|
||||
const getColumns = () => {
|
||||
return [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "product_range",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
const val = row.getValue("product_range") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "consomption_time",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
const val = row.getValue("consomption_time") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "inspiration",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
const val = row.getValue("inspiration") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "season",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => {
|
||||
const val = row.getValue("season") as any;
|
||||
const label = typeof val === 'object' && val !== null ? val.label : val;
|
||||
return (
|
||||
<Badge variant="outline">
|
||||
{str(String(label)).ucFirst().value()}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "updated_at",
|
||||
header: ({ column }: { column: { id: string } }) => (
|
||||
<DataTableFilterButton
|
||||
label={str(
|
||||
GetTranslation(`validation.attributes.${column.id}`),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
field={column.id}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }: { row: Row<DefaultModel & Record<string, any>> }) => (
|
||||
<Badge variant="secondary">
|
||||
{GetFormatedDate(row.getValue("updated_at"))}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export default function Index({
|
||||
paginatedModels,
|
||||
searchFields,
|
||||
}: Readonly<{
|
||||
paginatedModels: Resource;
|
||||
searchFields: string;
|
||||
}>) {
|
||||
const { auth } = usePage().props as unknown as {
|
||||
auth: AuthProp;
|
||||
};
|
||||
const { create } = auth.policies.recipes || { create: true };
|
||||
const actionModels = [
|
||||
Views.VISUALIZATION,
|
||||
Views.EDITION,
|
||||
Views.DUPLICATION,
|
||||
Views.DELETION,
|
||||
];
|
||||
|
||||
const columns = getColumns();
|
||||
const transCrudAddEntry = useTrans("uwil-backend::back.crud_add_entry");
|
||||
const afterNode = () => {
|
||||
return (
|
||||
create && (
|
||||
<BtnOptionnalLinkWithTooltip
|
||||
link={route('back.recipes.create')}
|
||||
content={<PlusIcon />}
|
||||
tooltipContent={<p>{transCrudAddEntry}</p>}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
title={str(
|
||||
useTrans('models.classes.recipe', { choice: Infinity }),
|
||||
)
|
||||
.ucFirst()
|
||||
.value()}
|
||||
afterNode={afterNode()}
|
||||
>
|
||||
<DataTableSearch modelRoute='recipes' searchFields={searchFields} />
|
||||
<DataTable
|
||||
columns={columns}
|
||||
modelRoute='recipes'
|
||||
modelsPaginate={paginatedModels}
|
||||
actions={actionModels}
|
||||
/>
|
||||
</AuthenticatedLayout>
|
||||
);
|
||||
}
|
||||
|
|
@ -13,12 +13,12 @@
|
|||
<x-uwil-common::head.og />
|
||||
<x-uwil-common::head.favicon mask-icon-color="#0150a8" tile-color="#0150a8" theme-color="#0150a8" />
|
||||
|
||||
<!-- Scripts -->
|
||||
{{-- Scripts --}}
|
||||
@routes(nonce: $nonce ?? '')
|
||||
@if (app()->hasDebugModeEnabled())
|
||||
@viteReactRefresh
|
||||
@endif
|
||||
@vite(["resources/ts/{$page['component']}.tsx", 'resources/sass/back/app.scss'])
|
||||
@vite(['resources/ts/app.tsx', "resources/ts/{$page['component']}.tsx", 'resources/sass/back/app.scss'])
|
||||
@inertiaHead
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
<x-uwil-common::head.hreflang />
|
||||
<x-uwil-common::head.favicon mask-icon-color="#ff0000" tile-color="#ff0000" theme-color="#ff0000" />
|
||||
|
||||
<!-- Scripts -->
|
||||
{{-- Scripts --}}
|
||||
@routes(nonce: $nonce ?? '')
|
||||
@if (app()->hasDebugModeEnabled())
|
||||
@viteReactRefresh
|
||||
@endif
|
||||
@vite(["resources/ts/{$page['component']}.tsx", 'resources/sass/front/app.scss'])
|
||||
@vite(['resources/ts/app.tsx', "resources/ts/{$page['component']}.tsx", 'resources/sass/front/app.scss'])
|
||||
@inertiaHead
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
<?php
|
||||
|
||||
// Set specific back routes here.
|
||||
// ex: Route::resource('stories', OriginalStoryController::class);.
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Http\Controllers\Back\ProductController;
|
||||
use App\Http\Controllers\Back\RecipeController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::resource('products', ProductController::class);
|
||||
Route::resource('recipes', RecipeController::class);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import laravel from "laravel-vite-plugin";
|
||||
import path from "node:path";
|
||||
|
|
@ -104,6 +105,7 @@ export default defineConfig({
|
|||
},
|
||||
},
|
||||
plugins: [
|
||||
basicSsl(),
|
||||
laravel({
|
||||
input: [
|
||||
"resources/ts/app.tsx",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue