Compare commits
69 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317577fb9b | ||
|
|
2a2490b302 | ||
|
|
53524b96d0 | ||
|
|
e7fe9d920b | ||
|
|
6e678b88c9 | ||
|
|
9c5cef6d99 | ||
|
|
0ab895e7ac | ||
|
|
06301a44fa | ||
|
|
4274b21eea | ||
|
|
dec444160b | ||
|
|
4dfa2d0412 | ||
|
|
a230697de0 | ||
|
|
2a9e109855 | ||
|
|
e19964fc89 | ||
|
|
edad0b4279 | ||
|
|
d70135b6af | ||
|
|
adae4da02f | ||
|
|
2f7289f531 | ||
|
|
6b85d63f5e | ||
|
|
5c5b34f33e | ||
|
|
ca47520a74 | ||
|
|
af3a63e36f | ||
|
|
21cc60457d | ||
|
|
36703bc9ac | ||
|
|
8a99cf98fc | ||
|
|
a4ed3dbb0f | ||
|
|
dae0c6271a | ||
|
|
98762d68a8 | ||
|
|
c450d71bed | ||
|
|
99f7545595 | ||
|
|
a0ddeda5a9 | ||
|
|
771978412a | ||
|
|
f43ea7c9ff | ||
|
|
c88583d727 | ||
|
|
6aab7d4eff | ||
|
|
0681bf8f0a | ||
|
|
923c3e0f6a | ||
|
|
8e48fc5ea1 | ||
|
|
615263f233 | ||
|
|
16f4af41fd | ||
|
|
d51f78a8db | ||
|
|
25b2e42f14 | ||
|
|
b9f51a1a5d | ||
|
|
e381de5e9c | ||
|
|
042e78583e | ||
|
|
e6796029ec | ||
|
|
39fc13dfe2 | ||
|
|
686bf307a2 | ||
|
|
549f874abd | ||
|
|
17ac0aaa5c | ||
|
|
f5367815e1 | ||
|
|
0d1f135616 | ||
|
|
817ffa68fc | ||
|
|
a31512216c | ||
|
|
cc24e547d2 | ||
|
|
16fe3773a9 | ||
|
|
8ce9d5734b | ||
|
|
6de828bc31 | ||
|
|
fe3eb7a955 | ||
|
|
c0bce88e75 | ||
|
|
61e900ee32 | ||
|
|
f44d9d7849 | ||
|
|
ecaec2823f | ||
|
|
22b598a11a | ||
|
|
d9c132ad25 | ||
|
|
634dbe832e | ||
|
|
f539cdd99a | ||
|
|
52dda4e346 | ||
|
|
8a3058e7bc |
92 changed files with 3974 additions and 1498 deletions
22
.vscode/settings.json
vendored
Normal file
22
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.activeBackground": "#90431a",
|
||||||
|
"activityBar.background": "#90431a",
|
||||||
|
"activityBar.foreground": "#e7e7e7",
|
||||||
|
"activityBar.inactiveForeground": "#e7e7e799",
|
||||||
|
"activityBarBadge.background": "#1da24b",
|
||||||
|
"activityBarBadge.foreground": "#e7e7e7",
|
||||||
|
"commandCenter.border": "#e7e7e799",
|
||||||
|
"sash.hoverBorder": "#90431a",
|
||||||
|
"statusBar.background": "#652f12",
|
||||||
|
"statusBar.foreground": "#e7e7e7",
|
||||||
|
"statusBarItem.hoverBackground": "#90431a",
|
||||||
|
"statusBarItem.remoteBackground": "#652f12",
|
||||||
|
"statusBarItem.remoteForeground": "#e7e7e7",
|
||||||
|
"titleBar.activeBackground": "#652f12",
|
||||||
|
"titleBar.activeForeground": "#e7e7e7",
|
||||||
|
"titleBar.inactiveBackground": "#652f1299",
|
||||||
|
"titleBar.inactiveForeground": "#e7e7e799"
|
||||||
|
},
|
||||||
|
"peacock.remoteColor": "#652f12"
|
||||||
|
}
|
||||||
|
|
@ -9,14 +9,18 @@ class Kernel extends ConsoleKernel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Define the application's command schedule.
|
* Define the application's command schedule.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
// $schedule->command('inspire')->hourly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the commands for the application.
|
* Register the commands for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function commands(): void
|
protected function commands(): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
16
app/Enums/Pagination/ItemsPerPaginationEnum.php
Normal file
16
app/Enums/Pagination/ItemsPerPaginationEnum.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Pagination;
|
||||||
|
|
||||||
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
|
enum ItemsPerPaginationEnum: int
|
||||||
|
{
|
||||||
|
use BaseEnum;
|
||||||
|
|
||||||
|
case five = 5;
|
||||||
|
case twelve = 12;
|
||||||
|
case twentyfive = 25;
|
||||||
|
case fifty = 50;
|
||||||
|
case onehundred = 100;
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum CertificationEnum : int
|
enum CertificationEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
@ -12,8 +12,8 @@ enum CertificationEnum : int
|
||||||
case labelRouge = 2;
|
case labelRouge = 2;
|
||||||
case certifiedCQ = 3;
|
case certifiedCQ = 3;
|
||||||
case standard = 4;
|
case standard = 4;
|
||||||
case freeRange = 5;
|
case freeRange = 6;
|
||||||
case others = 6;
|
case others = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom added functions definition
|
* Custom added functions definition
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum ClaimEnum : int
|
enum ClaimEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum DistributionNetworkEnum : int
|
enum DistributionNetworkEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum GeoAreaEnum : int
|
enum GeoAreaEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum OriginEnum : int
|
enum OriginEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum RangeEnum : int
|
enum RangeEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
@ -18,9 +18,9 @@ enum RangeEnum : int
|
||||||
case rawMeat = 8;
|
case rawMeat = 8;
|
||||||
case cookedMeats = 9;
|
case cookedMeats = 9;
|
||||||
case farcis = 10;
|
case farcis = 10;
|
||||||
case plant = 11;
|
case plant = 12;
|
||||||
case frozenSpecific = 12;
|
case frozenSpecific = 13;
|
||||||
case others = 13;
|
case others = 11;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom added functions definition
|
* Custom added functions definition
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum RayEnum : int
|
enum RayEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,24 @@ namespace App\Enums\Products;
|
||||||
|
|
||||||
use App\Traits\Enums\BaseEnum;
|
use App\Traits\Enums\BaseEnum;
|
||||||
|
|
||||||
enum SourceEnum : int
|
enum SourceEnum: int
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
use BaseEnum;
|
||||||
|
|
||||||
case catalogArgumentary = 1;
|
// * Catalogue argumentaire
|
||||||
case magazin = 2;
|
case catalogArgumentary = 7;
|
||||||
case press = 3;
|
// * Magasin
|
||||||
case showConsumer = 4;
|
case magazin = 1;
|
||||||
case showCustomer = 5;
|
// * Presse
|
||||||
case showTrade = 6;
|
case press = 3;
|
||||||
case web = 7;
|
// * Salon Grand Public
|
||||||
|
case showConsumer = 6;
|
||||||
|
// * Salon Clients
|
||||||
|
case showCustomer = 5;
|
||||||
|
// * Salon Professionnel
|
||||||
|
case showTrade = 4;
|
||||||
|
// * Web
|
||||||
|
case web = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom added functions definition
|
* Custom added functions definition
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,14 @@ class Handler extends ExceptionHandler
|
||||||
*
|
*
|
||||||
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
||||||
*/
|
*/
|
||||||
protected $levels = [
|
protected $levels = [];
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of the exception types that are not reported.
|
* A list of the exception types that are not reported.
|
||||||
*
|
*
|
||||||
* @var array<int, class-string<\Throwable>>
|
* @var array<int, class-string<\Throwable>>
|
||||||
*/
|
*/
|
||||||
protected $dontReport = [
|
protected $dontReport = [];
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of the inputs that are never flashed to the session on validation exceptions.
|
* A list of the inputs that are never flashed to the session on validation exceptions.
|
||||||
|
|
@ -36,6 +34,8 @@ class Handler extends ExceptionHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the exception handling callbacks for the application.
|
* Register the exception handling callbacks for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
29
app/Http/Controllers/BrandController.php
Normal file
29
app/Http/Controllers/BrandController.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Brands\StoreBrandRequest;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class BrandController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Brands\StoreBrandRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function store(StoreBrandRequest $request)
|
||||||
|
{
|
||||||
|
return DB::transaction(function () use ($request) {
|
||||||
|
$brand = new Brand();
|
||||||
|
$brand->fill($request->validated());
|
||||||
|
if ($brand->saveOrFail()) {
|
||||||
|
return \response()->json(['status' => true, 'brand' => $brand]);
|
||||||
|
}
|
||||||
|
return \response()->json(['status' => false, 'message' => __('La marque n\'a pas pu être créée')]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,13 +2,18 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||||
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Controller extends BaseController
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
|
|
@ -122,4 +127,26 @@ class Controller extends BaseController
|
||||||
}
|
}
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize pagination with cache or config (default).
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
|
||||||
|
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||||
|
*/
|
||||||
|
protected function paginate(Builder $query, ItemsPerPaginationEnum $pagination = null): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
$currentRoutePath = Str::slug(request()->route()->getName());
|
||||||
|
$cacheKey = "pagination.{$currentRoutePath}";
|
||||||
|
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve->value;
|
||||||
|
$pagination = ToolboxHelper::getValidatedPaginate(
|
||||||
|
Cache::get($cacheKey, $pagination)
|
||||||
|
);
|
||||||
|
if (Cache::get($cacheKey) !== $pagination) {
|
||||||
|
Cache::put($cacheKey, $pagination);
|
||||||
|
}
|
||||||
|
$query = $query->paginate($pagination);
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Products\IndexFilterRequest;
|
||||||
use App\Http\Requests\Products\StoreProductRequest;
|
use App\Http\Requests\Products\StoreProductRequest;
|
||||||
use App\Http\Requests\Products\UpdateProductRequest;
|
use App\Http\Requests\Products\UpdateProductRequest;
|
||||||
use App\Jobs\ExportProduct;
|
use App\Jobs\ExportProduct;
|
||||||
|
|
@ -12,6 +13,7 @@ use App\Models\Product;
|
||||||
use App\Traits\Controllers\HasDocuments;
|
use App\Traits\Controllers\HasDocuments;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
|
@ -22,99 +24,54 @@ class ProductController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \App\Http\Requests\Products\IndexFilterRequest $request
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(IndexFilterRequest $request)
|
||||||
{
|
{
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
||||||
$brands = Brand::get();
|
$brandsQuery = Brand::query();
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $products */
|
/** @var \Illuminate\Database\Eloquent\Builder $productsQuery */
|
||||||
$products = Product::query();
|
$productsQuery = Product::query()->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
$this->requestFilters($products, $request);
|
$this->requestFilters($request, $productsQuery);
|
||||||
|
|
||||||
$this->sortQuery($products);
|
$this->sortQuery($productsQuery);
|
||||||
|
|
||||||
$products = $products->paginate(10);
|
$products = $this->paginate($productsQuery);
|
||||||
|
|
||||||
/** @var array $printMultiProduct Array of id */
|
/** @var array $printMultiProduct Array of id */
|
||||||
$printMultiProduct = session('printMultiProduct') ?? [];
|
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
$brands = $brandsQuery->get();
|
||||||
$brands = Brand::get();
|
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $keyword */
|
$keywords = Keyword::query()->where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||||
$keywords = Keyword::where('keyword_cat', 'LIKE', 'product_%')->get();
|
|
||||||
|
|
||||||
return view('pages.products.index', [
|
return view('pages.products.index', [
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
'brands' => $brands,
|
'brands' => $brands,
|
||||||
'keywords' => $keywords,
|
'keywords' => $keywords,
|
||||||
'printMultiProduct' => $printMultiProduct,
|
'printMultiProduct' => $printMultiProduct
|
||||||
'queryParameters' => $request->all(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $products
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
|
|
||||||
*/
|
|
||||||
private function requestFilters(Builder $products, Request $request): \Illuminate\Database\Eloquent\Builder
|
|
||||||
{
|
|
||||||
//phpcs:enable
|
|
||||||
foreach ($request->all() as $key => $queryParameter) {
|
|
||||||
if (request()->sort_col === null && request()->sort_way === null && request()->rst === null) {
|
|
||||||
$products->when(
|
|
||||||
isset($queryParameter) && $queryParameter != 0,
|
|
||||||
function ($q) use ($queryParameter, $key) {
|
|
||||||
if ($key === "name") {
|
|
||||||
$q->where($key, 'LIKE', '%' . $queryParameter . '%');
|
|
||||||
} elseif ($key === "claims" || $key === "origins") {
|
|
||||||
foreach ($queryParameter as $item) {
|
|
||||||
$q->where($key, 'LIKE', '%{"id":"' . $item['value'] . '"}%');
|
|
||||||
}
|
|
||||||
} elseif ($key === "keywords") {
|
|
||||||
foreach ($queryParameter as $keyword) {
|
|
||||||
$q->whereHas('productKeywords', function ($q) use ($keyword, $key) {
|
|
||||||
$q->where($key . '.id', intval($keyword['value']));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} elseif ($key === "date_before" || $key === "date_after") {
|
|
||||||
if ($key === "date_before") {
|
|
||||||
$q->whereDate('created_at', '>=', $queryParameter);
|
|
||||||
} else {
|
|
||||||
$q->whereDate('created_at', '<=', $queryParameter);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$q->where($key, $queryParameter);
|
|
||||||
} //end if
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} //end if
|
|
||||||
} //end foreach
|
|
||||||
return $products;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for creating a new resource.
|
* Show the form for creating a new resource.
|
||||||
*
|
*
|
||||||
* @param App\Models\Product $productModel
|
* @param App\Models\Product $productModel
|
||||||
|
* @param Illuminate\Support\Collection $commentModel
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View
|
||||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||||
*/
|
*/
|
||||||
public function create(Product $productModel): \Illuminate\Contracts\View\View
|
public function create(Product $productModel, Collection $commentModel): \Illuminate\Contracts\View\View
|
||||||
{
|
{
|
||||||
//phpcs:enable
|
//phpcs:enable
|
||||||
$brands = Brand::get();
|
$brands = Brand::all();
|
||||||
$productsFair = Product::pluck('fair');
|
$productsFair = Product::query()->pluck('fair');
|
||||||
$productsShop = Product::pluck('shop');
|
$productsShop = Product::query()->pluck('shop');
|
||||||
$productsCatalog = Product::pluck('catalogue');
|
$productsCatalog = Product::query()->pluck('catalogue');
|
||||||
$keywords = Keyword::where('keyword_cat', 'product_pleasure')
|
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||||
->orWhere('keyword_cat', 'product_shape')
|
->orWhere('keyword_cat', 'product_shape')
|
||||||
->orWhere('keyword_cat', 'product_practicality')
|
->orWhere('keyword_cat', 'product_practicality')
|
||||||
->orWhere('keyword_cat', 'product_health')
|
->orWhere('keyword_cat', 'product_health')
|
||||||
|
|
@ -127,7 +84,8 @@ class ProductController extends Controller
|
||||||
'productsFair',
|
'productsFair',
|
||||||
'productsShop',
|
'productsShop',
|
||||||
'productsCatalog',
|
'productsCatalog',
|
||||||
'keywords'
|
'keywords',
|
||||||
|
'commentModel'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,12 +128,12 @@ class ProductController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit(Product $product)
|
public function edit(Product $product)
|
||||||
{
|
{
|
||||||
$brands = Brand::get();
|
$brands = Brand::all();
|
||||||
$productsFair = Product::pluck('fair');
|
$productsFair = Product::query()->pluck('fair');
|
||||||
$productsShop = Product::pluck('shop');
|
$productsShop = Product::query()->pluck('shop');
|
||||||
$productsCatalog = Product::pluck('catalogue');
|
$productsCatalog = Product::query()->pluck('catalogue');
|
||||||
$commentModel = $product->productComments;
|
$commentModel = $product->productComments;
|
||||||
$keywords = Keyword::where('keyword_cat', 'product_pleasure')
|
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||||
->orWhere('keyword_cat', 'product_shape')
|
->orWhere('keyword_cat', 'product_shape')
|
||||||
->orWhere('keyword_cat', 'product_practicality')
|
->orWhere('keyword_cat', 'product_practicality')
|
||||||
->orWhere('keyword_cat', 'product_health')
|
->orWhere('keyword_cat', 'product_health')
|
||||||
|
|
@ -300,7 +258,11 @@ class ProductController extends Controller
|
||||||
*/
|
*/
|
||||||
public function duplicate(Product $product)
|
public function duplicate(Product $product)
|
||||||
{
|
{
|
||||||
return $this->create($product->replicate());
|
$duplicatedProduct = $product->replicate();
|
||||||
|
foreach ($product->productComments as $comment) {
|
||||||
|
$duplicatedComments[] = $comment->replicate();
|
||||||
|
}
|
||||||
|
return $this->create($duplicatedProduct, collect($duplicatedComments ?? null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -312,20 +274,20 @@ class ProductController extends Controller
|
||||||
public function checkGencode(Request $request)
|
public function checkGencode(Request $request)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
isset($request->GENCODE) &&
|
isset($request->GENCOD) &&
|
||||||
$request->GENCODE !== null &&
|
$request->GENCOD !== null &&
|
||||||
ctype_digit($request->GENCODE) &&
|
ctype_digit($request->GENCOD) &&
|
||||||
strlen($request->GENCODE) > 0
|
strlen($request->GENCOD) > 0
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
isset($request->ID) &&
|
isset($request->ID) &&
|
||||||
$request->ID !== null &&
|
$request->ID !== null &&
|
||||||
intval($request->GENCODE) === Product::where('id', $request->ID)->firstOrFail()->gencod
|
intval($request->GENCOD) === Product::where('id', $request->ID)->firstOrFail()->gencod
|
||||||
) {
|
) {
|
||||||
$result = null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
$result = in_array(intval($request->GENCODE), Product::pluck('gencod')->toArray()) ?
|
$result = in_array(intval($request->GENCOD), Product::pluck('gencod')->toArray()) ?
|
||||||
Product::orderBy('created_at', 'desc')->where('gencod', intval($request->GENCODE))->first() : null;
|
Product::orderBy('created_at', 'desc')->where('gencod', intval($request->GENCOD))->first() : null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$result = null;
|
$result = null;
|
||||||
|
|
@ -363,6 +325,7 @@ class ProductController extends Controller
|
||||||
*/
|
*/
|
||||||
public function printMultiProductSheet()
|
public function printMultiProductSheet()
|
||||||
{
|
{
|
||||||
|
// FIXME: This should not use session.
|
||||||
/** @var array printMultiProduct */
|
/** @var array printMultiProduct */
|
||||||
$printMultiProduct = session('printMultiProduct') ?? [];
|
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||||
asort($printMultiProduct);
|
asort($printMultiProduct);
|
||||||
|
|
@ -427,4 +390,62 @@ class ProductController extends Controller
|
||||||
{
|
{
|
||||||
\dispatch(new ExportProduct($request->id))->onConnection('database');
|
\dispatch(new ExportProduct($request->id))->onConnection('database');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies filters from products.index
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Products\IndexFilterRequest $request
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $productsQuery
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
|
||||||
|
*/
|
||||||
|
private function requestFilters(
|
||||||
|
IndexFilterRequest $request,
|
||||||
|
Builder $productsQuery
|
||||||
|
): \Illuminate\Database\Eloquent\Builder {
|
||||||
|
//phpcs:enable
|
||||||
|
foreach ($request->validated() as $parameterName => $queryParameter) {
|
||||||
|
$productsQuery->when(
|
||||||
|
!empty($queryParameter),
|
||||||
|
function (Builder $q) use ($queryParameter, $parameterName) {
|
||||||
|
switch ($parameterName) {
|
||||||
|
// * String type parameters (Approx search)
|
||||||
|
case 'name':
|
||||||
|
case 'shop':
|
||||||
|
case 'fair':
|
||||||
|
case 'catalogue':
|
||||||
|
case 'specified_claim':
|
||||||
|
$q->where($parameterName, 'LIKE', "%{$queryParameter}%");
|
||||||
|
break;
|
||||||
|
// * Number type parameters (Approx search)
|
||||||
|
case 'gencode':
|
||||||
|
$q->where($parameterName, \intval($queryParameter));
|
||||||
|
break;
|
||||||
|
// * Date type parameters
|
||||||
|
case 'date_before':
|
||||||
|
$q->whereDate('created_at', '<=', $queryParameter);
|
||||||
|
break;
|
||||||
|
case 'date_after':
|
||||||
|
$q->whereDate('created_at', '>=', $queryParameter);
|
||||||
|
break;
|
||||||
|
// * Enums Array
|
||||||
|
case 'claims':
|
||||||
|
case 'origins':
|
||||||
|
$q->whereJsonContains($parameterName, \collect($queryParameter)
|
||||||
|
->map(fn ($enumValue) => \intval($enumValue)));
|
||||||
|
break;
|
||||||
|
// * RelationShips parameters
|
||||||
|
case 'keywords':
|
||||||
|
$q->whereHas('productKeywords', function (Builder $subQ) use ($queryParameter) {
|
||||||
|
$subQ->whereIn('keywords.id', $queryParameter);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$q->where($parameterName, $queryParameter);
|
||||||
|
} //end switch
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} //end foreach
|
||||||
|
return $productsQuery;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ class Kernel extends HttpKernel
|
||||||
* @var array<int, class-string|string>
|
* @var array<int, class-string|string>
|
||||||
*/
|
*/
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
// \App\Http\Middleware\TrustHosts::class,
|
\App\Http\Middleware\TrustHosts::class,
|
||||||
\App\Http\Middleware\TrustProxies::class,
|
\App\Http\Middleware\TrustProxies::class,
|
||||||
\Illuminate\Http\Middleware\HandleCors::class,
|
\Illuminate\Http\Middleware\HandleCors::class,
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ class Authenticate extends Middleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the path the user should be redirected to when they are not authenticated.
|
* Get the path the user should be redirected to when they are not authenticated.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
protected function redirectTo(Request $request): ?string
|
protected function redirectTo(Request $request): ?string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
@ -13,10 +12,15 @@ class RedirectIfAuthenticated
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure(\Illuminate\Http\Request):(\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
* @param string ...$guards
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
public function handle(Request $request, \Closure $next, string ...$guards): Response
|
||||||
{
|
{
|
||||||
|
// phpcs:enable
|
||||||
$guards = empty($guards) ? [null] : $guards;
|
$guards = empty($guards) ? [null] : $guards;
|
||||||
|
|
||||||
foreach ($guards as $guard) {
|
foreach ($guards as $guard) {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ class ValidateSignature extends Middleware
|
||||||
* The names of the query string parameters that should be ignored.
|
* The names of the query string parameters that should be ignored.
|
||||||
*
|
*
|
||||||
* @var array<int, string>
|
* @var array<int, string>
|
||||||
|
*
|
||||||
|
* 'fbclid',
|
||||||
|
* 'utm_campaign',
|
||||||
|
* 'utm_content',
|
||||||
|
* 'utm_medium',
|
||||||
|
* 'utm_source',
|
||||||
|
* 'utm_term',
|
||||||
*/
|
*/
|
||||||
protected $except = [
|
protected $except = [];
|
||||||
// 'fbclid',
|
|
||||||
// 'utm_campaign',
|
|
||||||
// 'utm_content',
|
|
||||||
// 'utm_medium',
|
|
||||||
// 'utm_source',
|
|
||||||
// 'utm_term',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
app/Http/Requests/Brands/StoreBrandRequest.php
Normal file
42
app/Http/Requests/Brands/StoreBrandRequest.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Brands;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreBrandRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|min:3|max:255',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get custom attributes for validator errors.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => trans('nom de la marque'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/Http/Requests/Products/IndexFilterRequest.php
Normal file
60
app/Http/Requests/Products/IndexFilterRequest.php
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Products;
|
||||||
|
|
||||||
|
use App\Enums\Products\CertificationEnum;
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
|
use App\Enums\Products\DistributionNetworkEnum;
|
||||||
|
use App\Enums\Products\GeoAreaEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
|
use App\Enums\Products\RangeEnum;
|
||||||
|
use App\Enums\Products\RayEnum;
|
||||||
|
use App\Enums\Products\SourceEnum;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
|
||||||
|
class IndexFilterRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'nullable|string',
|
||||||
|
'brand_id' => 'nullable|exists:brands,id',
|
||||||
|
'gencod' => 'nullable|string',
|
||||||
|
|
||||||
|
'source' => ['nullable', new Enum(SourceEnum::class)],
|
||||||
|
'shop' => 'nullable|string',
|
||||||
|
'fair' => 'nullable|string',
|
||||||
|
'catalogue' => 'nullable|string',
|
||||||
|
'claims' => 'nullable|array',
|
||||||
|
'claims.*' => ['required', new Enum(ClaimEnum::class)],
|
||||||
|
'specified_claim' => 'nullable|string',
|
||||||
|
'origins' => 'nullable|array',
|
||||||
|
'origins.*' => ['required', new Enum(OriginEnum::class)],
|
||||||
|
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
||||||
|
'distribution_network' => ['nullable', new Enum(DistributionNetworkEnum::class)],
|
||||||
|
'ray' => ['nullable', new Enum(RayEnum::class)],
|
||||||
|
'product_range' => ['nullable', new Enum(RangeEnum::class)],
|
||||||
|
'geo_area' => ['nullable', new Enum(GeoAreaEnum::class)],
|
||||||
|
'keywords' => 'nullable|array',
|
||||||
|
'keywords.*' => 'required|exists:keywords,id',
|
||||||
|
'date_before' => 'nullable|date:Y-m-d',
|
||||||
|
'date_after' => 'nullable|date:Y-m-d',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ use App\Enums\Products\RangeEnum;
|
||||||
use App\Enums\Products\RayEnum;
|
use App\Enums\Products\RayEnum;
|
||||||
use App\Enums\Products\SourceEnum;
|
use App\Enums\Products\SourceEnum;
|
||||||
use App\Lib\Helpers\ToolboxHelper;
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
use App\Traits\Requests\HasDocument;
|
use App\Traits\Requests\HasDocumentAndPictureList;
|
||||||
use App\Traits\Requests\HasPicture;
|
use App\Traits\Requests\HasPicture;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rules\Enum;
|
use Illuminate\Validation\Rules\Enum;
|
||||||
|
|
@ -20,7 +20,7 @@ use Illuminate\Validation\ValidationException;
|
||||||
class StoreProductRequest extends FormRequest
|
class StoreProductRequest extends FormRequest
|
||||||
{
|
{
|
||||||
use HasPicture;
|
use HasPicture;
|
||||||
use HasDocument;
|
use HasDocumentAndPictureList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
|
|
@ -44,6 +44,9 @@ class StoreProductRequest extends FormRequest
|
||||||
'is_tasted' => $this->is_tasted ? true : false,
|
'is_tasted' => $this->is_tasted ? true : false,
|
||||||
'origins' => $this->origins ? $this->origins : [],
|
'origins' => $this->origins ? $this->origins : [],
|
||||||
'claims' => $this->claims ? $this->claims : [],
|
'claims' => $this->claims ? $this->claims : [],
|
||||||
|
'picture_alt' => $this->name,
|
||||||
|
'picture_title' => $this->name,
|
||||||
|
'certification' => $this->certification == 0 ? null : $this->certification,
|
||||||
]);
|
]);
|
||||||
$this->mergePicture('picture');
|
$this->mergePicture('picture');
|
||||||
$this->mergeDocuments('docs');
|
$this->mergeDocuments('docs');
|
||||||
|
|
@ -60,9 +63,9 @@ class StoreProductRequest extends FormRequest
|
||||||
'name' => 'required|string|min:3|max:255',
|
'name' => 'required|string|min:3|max:255',
|
||||||
'brand_id' => 'required|exists:brands,id',
|
'brand_id' => 'required|exists:brands,id',
|
||||||
'source' => [new Enum(SourceEnum::class)],
|
'source' => [new Enum(SourceEnum::class)],
|
||||||
'fair' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::showConsumer->value . ',' . SourceEnum::showCustomer->value . ',' . SourceEnum::showTrade->value,
|
'fair' => 'nullable|string|min:3|max:255',
|
||||||
'shop' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::magazin->value,
|
'shop' => 'nullable|string|min:3|max:255',
|
||||||
'catalogue' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::catalogArgumentary->value,
|
'catalogue' => 'nullable|string|min:3|max:255',
|
||||||
'gencod' => 'nullable|numeric|min:0',
|
'gencod' => 'nullable|numeric|min:0',
|
||||||
'picture_alt' => 'required|min:3|max:255',
|
'picture_alt' => 'required|min:3|max:255',
|
||||||
'picture_title' => 'required|min:3|max:255',
|
'picture_title' => 'required|min:3|max:255',
|
||||||
|
|
@ -76,19 +79,17 @@ class StoreProductRequest extends FormRequest
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
||||||
'origins' => 'nullable|array',
|
'origins' => 'present|array',
|
||||||
'origins.*' => 'present|array',
|
'origins.*' => [new Enum(OriginEnum::class)],
|
||||||
'origins.*.id' => [new Enum(OriginEnum::class)],
|
'claims' => 'present|array',
|
||||||
'claims' => 'nullable|array',
|
'claims.*' => [new Enum(ClaimEnum::class)],
|
||||||
'claims.*' => 'present|array',
|
|
||||||
'claims.*.id' => [new Enum(ClaimEnum::class)],
|
|
||||||
'specified_claim' => 'string|min:3|max:255|required_if:claims,' . ClaimEnum::others->value,
|
'specified_claim' => 'string|min:3|max:255|required_if:claims,' . ClaimEnum::others->value,
|
||||||
'distribution_network' => ['required', new Enum(DistributionNetworkEnum::class)],
|
'distribution_network' => ['required', new Enum(DistributionNetworkEnum::class)],
|
||||||
'ray' => ['required', new Enum(RayEnum::class)],
|
'ray' => ['required', new Enum(RayEnum::class)],
|
||||||
'product_range' => ['required', new Enum(RangeEnum::class)],
|
'product_range' => ['required', new Enum(RangeEnum::class)],
|
||||||
'geo_area' => ['required', new Enum(GeoAreaEnum::class)],
|
'geo_area' => ['required', new Enum(GeoAreaEnum::class)],
|
||||||
'weight' => 'nullable|integer',
|
'weight' => 'nullable|integer',
|
||||||
'pvc' => 'nullable|integer',
|
'pvc' => 'nullable|decimal:0,2',
|
||||||
'comment' => 'nullable|string|min:15',
|
'comment' => 'nullable|string|min:15',
|
||||||
'is_tasted' => 'required|boolean',
|
'is_tasted' => 'required|boolean',
|
||||||
'tasters_number' => 'nullable|integer',
|
'tasters_number' => 'nullable|integer',
|
||||||
|
|
@ -106,7 +107,7 @@ class StoreProductRequest extends FormRequest
|
||||||
return \array_merge(
|
return \array_merge(
|
||||||
$rules,
|
$rules,
|
||||||
$this->pictureRules('picture', false, 1200, 900, 1200, 900),
|
$this->pictureRules('picture', false, 1200, 900, 1200, 900),
|
||||||
$this->documentsRules('docs', false),
|
$this->documentsRules('docs'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
use App\Enums\Products\CertificationEnum;
|
|
||||||
use App\Enums\Products\ClaimEnum;
|
use App\Enums\Products\ClaimEnum;
|
||||||
use App\Enums\Products\OriginEnum;
|
use App\Enums\Products\OriginEnum;
|
||||||
use App\Models\Brand;
|
use App\Models\Keyword;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\User;
|
use App\Models\ProductComment;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
class ProductResource extends JsonResource
|
class ProductResource extends JsonResource
|
||||||
|
|
@ -19,8 +17,8 @@ class ProductResource extends JsonResource
|
||||||
/** @var array */
|
/** @var array */
|
||||||
private static $skeleton = [
|
private static $skeleton = [
|
||||||
'id' => null,
|
'id' => null,
|
||||||
'user_id' => null,
|
'user' => null,
|
||||||
'brand_id' => null,
|
'brand' => null,
|
||||||
'name' => null,
|
'name' => null,
|
||||||
'seen_at' => null,
|
'seen_at' => null,
|
||||||
'source' => null,
|
'source' => null,
|
||||||
|
|
@ -36,6 +34,7 @@ class ProductResource extends JsonResource
|
||||||
'certification' => null,
|
'certification' => null,
|
||||||
'origins' => null,
|
'origins' => null,
|
||||||
'claims' => null,
|
'claims' => null,
|
||||||
|
'specified_claim' => null,
|
||||||
'distribution_network' => null,
|
'distribution_network' => null,
|
||||||
'ray' => null,
|
'ray' => null,
|
||||||
'product_range' => null,
|
'product_range' => null,
|
||||||
|
|
@ -65,54 +64,13 @@ class ProductResource extends JsonResource
|
||||||
*/
|
*/
|
||||||
public function toArray($request = null)
|
public function toArray($request = null)
|
||||||
{
|
{
|
||||||
foreach (CertificationEnum::toArray() as $enumValue) {
|
|
||||||
if ($this->product->certification->value === $enumValue->value) {
|
|
||||||
$certification = $enumValue->label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count($this->product->origins)) {
|
|
||||||
$origins = "";
|
|
||||||
foreach ($this->product->origins as $originValue) {
|
|
||||||
foreach (OriginEnum::toArray() as $enumValue) {
|
|
||||||
if (intval($originValue['id']) === $enumValue->value) {
|
|
||||||
$origins = $origins . $enumValue->label . ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count($this->product->claims)) {
|
|
||||||
$claims = "";
|
|
||||||
foreach ($this->product->claims as $originValue) {
|
|
||||||
foreach (ClaimEnum::toArray() as $enumValue) {
|
|
||||||
if (intval($originValue['id']) === $enumValue->value) {
|
|
||||||
if ($enumValue->value === ClaimEnum::others->value) {
|
|
||||||
$claims = $claims . $enumValue->label . ": " . $this->product->specified_claim . ", ";
|
|
||||||
} else {
|
|
||||||
$claims = $claims . $enumValue->label . ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($this->product->productComments as $productComment) {
|
|
||||||
$productComment->date = Carbon::createFromFormat(
|
|
||||||
'Y-m-d H:i:s',
|
|
||||||
$productComment->created_at
|
|
||||||
)->format('d/m/Y');
|
|
||||||
}
|
|
||||||
if (count($this->product->productKeywords)) {
|
|
||||||
$productKeywords = "";
|
|
||||||
foreach ($this->product->productKeywords as $productKeyword) {
|
|
||||||
$productKeywords = $productKeywords . $productKeyword->label . ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array_intersect_key(
|
return array_intersect_key(
|
||||||
[
|
[
|
||||||
'id' => $this->product->id,
|
'id' => $this->product->id,
|
||||||
'user_id' => User::where('id', $this->product->user_id)->firstOrFail(),
|
'user' => (object)$this->product->user->toArray(),
|
||||||
'brand_id' => Brand::where('id', $this->product->brand_id)->firstOrFail(),
|
'brand' => (object)$this->product->brand->toArray(),
|
||||||
'name' => $this->product->name,
|
'name' => $this->product->name,
|
||||||
'seen_at' => Carbon::createFromFormat('Y-m-d H:i:s', $this->product->seen_at)->format('d/m/Y'),
|
'seen_at' => $this->product->seen_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
'source' => $this->product->source->label(),
|
'source' => $this->product->source->label(),
|
||||||
'fair' => $this->product->fair,
|
'fair' => $this->product->fair,
|
||||||
'shop' => $this->product->shop,
|
'shop' => $this->product->shop,
|
||||||
|
|
@ -123,16 +81,25 @@ class ProductResource extends JsonResource
|
||||||
'picture' => $this->product->picture,
|
'picture' => $this->product->picture,
|
||||||
'picture_alt' => $this->product->picture_alt,
|
'picture_alt' => $this->product->picture_alt,
|
||||||
'picture_title' => $this->product->picture_title,
|
'picture_title' => $this->product->picture_title,
|
||||||
'certification' => $certification,
|
'certification' => \optional($this->product->certification)->label(),
|
||||||
'origins' => $origins ?? null,
|
'origins' => $this->product->origins_enum->map(fn (OriginEnum $enum) => $enum->label())->implode(', '),
|
||||||
'claims' => $claims ?? null,
|
'claims' => $this->product->claims_enum->map(fn (ClaimEnum $enum) => $enum->label())->implode(', '),
|
||||||
|
'specified_claim' => $this->product->specified_claim,
|
||||||
'distribution_network' => $this->product->distribution_network->label(),
|
'distribution_network' => $this->product->distribution_network->label(),
|
||||||
'ray' => $this->product->ray->label(),
|
'ray' => $this->product->ray->label(),
|
||||||
'product_range' => $this->product->product_range->label(),
|
'product_range' => $this->product->product_range->label(),
|
||||||
'geo_area' => $this->product->geo_area->label(),
|
'geo_area' => $this->product->geo_area->label(),
|
||||||
'freeComment' => $this->product->comment,
|
'freeComment' => $this->product->comment,
|
||||||
'productComments' => $this->product->productComments,
|
// FIXME: Use dedicaced resources for relations.
|
||||||
'productKeywords' => $productKeywords ?? null,
|
'productComments' => $this->product->productComments->map(function (ProductComment $comment) {
|
||||||
|
return (object)\array_merge($comment->toArray(), [
|
||||||
|
'created_at' => $comment->created_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
|
'updated_at' => $comment->updated_at->isoFormat('DD\/MM\/YYYY'),
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
'productKeywords' => $this->product->productKeywords
|
||||||
|
->map(fn (Keyword $keyword) => $keyword->label)
|
||||||
|
->implode(', '),
|
||||||
],
|
],
|
||||||
$this->getSkeleton()
|
$this->getSkeleton()
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class ExportProduct implements ShouldQueue
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*
|
*
|
||||||
|
* @param integer $productId
|
||||||
* @return void
|
* @return void
|
||||||
* @throws \Error If file storage config is wrong.
|
* @throws \Error If file storage config is wrong.
|
||||||
* @throws \RuntimeException If the storage disk export is not local file system.
|
* @throws \RuntimeException If the storage disk export is not local file system.
|
||||||
|
|
@ -50,7 +51,10 @@ class ExportProduct implements ShouldQueue
|
||||||
throw new \RuntimeException("The ZIP file cannot be created.");
|
throw new \RuntimeException("The ZIP file cannot be created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$dirName = Str::slug(Carbon::parse($product->updated_at)->format('y-m-d') . '-' . $product->user->lastname . '-' . $product->user->id);
|
$dirName = Str::slug(
|
||||||
|
Carbon::parse($product->updated_at)->format('y-m-d') . '-' .
|
||||||
|
$product->user->lastname . '-' . $product->user->id
|
||||||
|
);
|
||||||
|
|
||||||
if (!$zip->addEmptyDir($dirName)) {
|
if (!$zip->addEmptyDir($dirName)) {
|
||||||
throw new \RuntimeException("The folder cannot be created inside the ZIP.");
|
throw new \RuntimeException("The folder cannot be created inside the ZIP.");
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
namespace App\Lib\Helpers;
|
namespace App\Lib\Helpers;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\Rules\Enum;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
|
@ -140,75 +139,15 @@ class ToolboxHelper
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an array from a dot separated string
|
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
* @param mixed $value
|
|
||||||
* @param string $separator
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function dotStringToNestedArray(string $path, $value, string $separator = '.'): array
|
|
||||||
{
|
|
||||||
$arr = $value;
|
|
||||||
$keys = array_reverse(explode($separator, $path));
|
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$arr = [$key => $arr];
|
|
||||||
}
|
|
||||||
return $arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate url using laravel route passing our group query if present
|
|
||||||
* This is used to keep ou group tracking
|
|
||||||
* Curd-policies is only used for root users as it cannot keep track of our group
|
|
||||||
* and validate things
|
|
||||||
*
|
|
||||||
* @param array|string $name
|
|
||||||
* @param mixed $parameters
|
|
||||||
* @param boolean $absolute
|
|
||||||
* @return string
|
|
||||||
* @throws \ErrorException If an object given as parameter is not a Model.
|
|
||||||
*/
|
|
||||||
public static function routeWithGroup($name, $parameters = [], bool $absolute = true): string
|
|
||||||
{
|
|
||||||
// * Handle if parameter if is an object.
|
|
||||||
if (\is_object($parameters)) {
|
|
||||||
$parents = \class_parents($parameters);
|
|
||||||
if ($parents === false or !\in_array(Model::class, $parents)) {
|
|
||||||
throw new \ErrorException(\sprintf(
|
|
||||||
'%s only support object of type %s',
|
|
||||||
__FUNCTION__,
|
|
||||||
Model::class
|
|
||||||
));
|
|
||||||
}
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Model $model */
|
|
||||||
$model = $parameters;
|
|
||||||
$parameters = [Str::singular($model->getTable()) => $model];
|
|
||||||
}
|
|
||||||
// * Handle if parameter isnt and array like slug or else.
|
|
||||||
if (!is_array($parameters)) {
|
|
||||||
// * Best effort, result is not garantee.
|
|
||||||
$parameters = [$parameters];
|
|
||||||
}
|
|
||||||
// * Pass our group.
|
|
||||||
if ($group = Session::get('activeGroup', request()->group)) {
|
|
||||||
$parameters = array_merge($parameters, ['group' => $group]);
|
|
||||||
}
|
|
||||||
// * Call laravel route helper.
|
|
||||||
return route($name, $parameters, $absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutltibyte string replace
|
* Mutltibyte string replace
|
||||||
* @param mixed $search
|
* @param string|array $search
|
||||||
* @param mixed $replace
|
* @param string|array $replace
|
||||||
* @param mixed $subject
|
* @param mixed $subject
|
||||||
* @param integer $count
|
* @param integer $count
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function mbReplace($search, $replace, $subject, int &$count = 0)
|
public static function mbReplace(string|array $search, string|array $replace, mixed $subject, int &$count = 0)
|
||||||
{
|
{
|
||||||
if (!is_array($search) && is_array($replace)) {
|
if (!is_array($search) && is_array($replace)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -253,7 +192,7 @@ class ToolboxHelper
|
||||||
public static function assertFieldIsUnique(
|
public static function assertFieldIsUnique(
|
||||||
string $table,
|
string $table,
|
||||||
string $field,
|
string $field,
|
||||||
$value,
|
mixed $value,
|
||||||
?int $id = null,
|
?int $id = null,
|
||||||
?callable $query = null
|
?callable $query = null
|
||||||
) {
|
) {
|
||||||
|
|
@ -288,4 +227,22 @@ class ToolboxHelper
|
||||||
{
|
{
|
||||||
return (array_diff($array1, $array2) == [] && array_diff($array2, $array1) == []);
|
return (array_diff($array1, $array2) == [] && array_diff($array2, $array1) == []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get validated pagination from request
|
||||||
|
*
|
||||||
|
* @param integer $default
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public static function getValidatedPaginate(int $default): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return \intval(Validator::make(
|
||||||
|
['pagination' => \request()->get('pagination')],
|
||||||
|
['pagination' => new Enum(ItemsPerPaginationEnum::class)]
|
||||||
|
)->validated()['pagination']);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property integer $id
|
* @property integer $id
|
||||||
* @property string $brand
|
* @property string $name
|
||||||
* @property string $filter
|
* @property string $filter
|
||||||
* @property string $created_at
|
* @property string $created_at
|
||||||
* @property string $updated_at
|
* @property string $updated_at
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
* @property \App\Enums\KeywordCategoryEnum $keyword_cat
|
* @property \App\Enums\KeywordCategoryEnum $keyword_cat
|
||||||
* @property \Carbon\Carbon $created_at
|
* @property \Carbon\Carbon $created_at
|
||||||
* @property \Carbon\Carbon $updated_at
|
* @property \Carbon\Carbon $updated_at
|
||||||
* @property Keywordable[] $keywordables
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Product> $products
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Keyword> $keywordables
|
||||||
*/
|
*/
|
||||||
class Keyword extends Model
|
class Keyword extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -34,6 +37,8 @@ class Keyword extends Model
|
||||||
'keyword_cat' => KeywordCategoryEnum::class
|
'keyword_cat' => KeywordCategoryEnum::class
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\Products\CertificationEnum;
|
use App\Enums\Products\CertificationEnum;
|
||||||
|
use App\Enums\Products\ClaimEnum;
|
||||||
use App\Enums\Products\DistributionNetworkEnum;
|
use App\Enums\Products\DistributionNetworkEnum;
|
||||||
use App\Enums\Products\GeoAreaEnum;
|
use App\Enums\Products\GeoAreaEnum;
|
||||||
|
use App\Enums\Products\OriginEnum;
|
||||||
use App\Enums\Products\RangeEnum;
|
use App\Enums\Products\RangeEnum;
|
||||||
use App\Enums\Products\RayEnum;
|
use App\Enums\Products\RayEnum;
|
||||||
use App\Enums\Products\SourceEnum;
|
use App\Enums\Products\SourceEnum;
|
||||||
|
|
@ -13,43 +15,53 @@ use App\Lib\Helpers\FileStorageHelper;
|
||||||
use App\Lib\Helpers\ToolboxHelper;
|
use App\Lib\Helpers\ToolboxHelper;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property integer $id
|
* FIXME: using migration, do not set nullable props without a real need.
|
||||||
* @property integer $user_id
|
*
|
||||||
* @property integer $brand_id
|
* @property integer $id
|
||||||
* @property string $name
|
* @property integer $user_id
|
||||||
* @property string $brand
|
* @property integer $brand_id
|
||||||
* @property string $seen_at
|
* @property string $name
|
||||||
* @property enum $source
|
* @property \Carbon\Carbon $seen_at
|
||||||
* @property string $fair
|
* @property \App\Enums\Products\SourceEnum $source
|
||||||
* @property string $shop
|
* @property string|null $fair
|
||||||
* @property string $catalogue
|
* @property string|null $shop
|
||||||
* @property string $gencod
|
* @property string|null $catalogue
|
||||||
* @property string $picture
|
* @property string|null $gencod
|
||||||
* @property array $docs
|
* @property string|null $picture
|
||||||
* @property string $url
|
* @property string $picture_alt
|
||||||
* @property enum $certification
|
* @property string $picture_title
|
||||||
* @property object $origins
|
* @property array|null $docs
|
||||||
* @property object $claims
|
* @property string|null $url
|
||||||
* @property string $specified_claim
|
* @property \App\Enums\Products\CertificationEnum|null $certification
|
||||||
* @property enum $distribution_network
|
* @property array<integer>|null $origins
|
||||||
* @property enum $ray
|
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $origins_enum
|
||||||
* @property enum $product_range
|
* @property array<integer>|null $claims
|
||||||
* @property enum $geo area
|
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $claims_enum
|
||||||
* @property integer $weight
|
* @property string|null $specified_claim
|
||||||
* @property integer $pvc
|
* @property \App\Enums\Products\DistributionNetworkEnum $distribution_network
|
||||||
* @property string $comment
|
* @property \App\Enums\Products\RayEnum $ray
|
||||||
* @property boolean $is_tasted
|
* @property \App\Enums\Products\RangeEnum $product_range
|
||||||
* @property integer $tasters_number
|
* @property \App\Enums\Products\GeoAreaEnum $geo area
|
||||||
* @property string $created_at
|
* @property integer|null $weight
|
||||||
* @property string $updated_at
|
* @property integer|null $pvc
|
||||||
* @property string $deleted_at
|
* @property string|null $comment
|
||||||
* @property ProductComment[] $productComments
|
* @property boolean $is_tasted
|
||||||
* @property User $user
|
* @property integer|null $tasters_number
|
||||||
|
* @property \Carbon\Carbon|null $created_at
|
||||||
|
* @property \Carbon\Carbon|null $updated_at
|
||||||
|
* @property \Carbon\Carbon|null $deleted_at
|
||||||
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \App\Models\Brand $brand
|
||||||
|
* @property-read \App\Models\User $user
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\ProductComment> $productComments
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Keyword> $productKeywords
|
||||||
*/
|
*/
|
||||||
class Product extends Model
|
class Product extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -109,10 +121,10 @@ class Product extends Model
|
||||||
'product_range' => RangeEnum::class,
|
'product_range' => RangeEnum::class,
|
||||||
'geo_area' => GeoAreaEnum::class,
|
'geo_area' => GeoAreaEnum::class,
|
||||||
'is_tasted' => 'boolean',
|
'is_tasted' => 'boolean',
|
||||||
'seen_at' => 'datetime:Y-m-d',
|
'seen_at' => 'datetime',
|
||||||
'created_at' => 'datetime:Y-m-d',
|
'created_at' => 'datetime',
|
||||||
'updated_at' => 'datetime:Y-m-d',
|
'updated_at' => 'datetime',
|
||||||
'deleted_at' => 'datetime:Y-m-d',
|
'deleted_at' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
// * EVENTS
|
// * EVENTS
|
||||||
|
|
@ -132,7 +144,7 @@ class Product extends Model
|
||||||
$model->user_id = 1;
|
$model->user_id = 1;
|
||||||
});
|
});
|
||||||
static::updating(function (self $model) {
|
static::updating(function (self $model) {
|
||||||
self::deleteOldDocuments($model);
|
self::deleteOldDocuments($model, true);
|
||||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||||
self::updateSource($model);
|
self::updateSource($model);
|
||||||
self::updateSpecifiedClaim($model);
|
self::updateSpecifiedClaim($model);
|
||||||
|
|
@ -171,8 +183,11 @@ class Product extends Model
|
||||||
*/
|
*/
|
||||||
private static function updateSpecifiedClaim(Product $model)
|
private static function updateSpecifiedClaim(Product $model)
|
||||||
{
|
{
|
||||||
foreach ($model->claims as $claim) {
|
$check = false;
|
||||||
$check = (intval($claim['id']) === \App\Enums\Products\ClaimEnum::others->value) ? true : false;
|
foreach ($model->claims as $claimValue) {
|
||||||
|
if (!$check) {
|
||||||
|
$check = (intval($claimValue) === \App\Enums\Products\ClaimEnum::others->value) ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$model->specified_claim = ($check) ? $model->specified_claim : null;
|
$model->specified_claim = ($check) ? $model->specified_claim : null;
|
||||||
}
|
}
|
||||||
|
|
@ -208,15 +223,23 @@ class Product extends Model
|
||||||
/**
|
/**
|
||||||
* Delete old documents.
|
* Delete old documents.
|
||||||
*
|
*
|
||||||
* @param self $model
|
* @param self $model
|
||||||
|
* @param boolean $onlyIfUpdated
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function deleteOldDocuments(self $model)
|
public static function deleteOldDocuments(self $model, bool $onlyIfUpdated = false)
|
||||||
{
|
{
|
||||||
foreach ($model->getOriginal('docs') as $document) {
|
$original = \collect($model->getOriginal('docs'))->map(fn ($document) => strval($document));
|
||||||
|
$new = \collect($model->docs)->map(fn ($document) => strval($document))->flip();
|
||||||
|
foreach ($original as $document) {
|
||||||
|
// * Ignore if document is to keep.
|
||||||
|
if ($onlyIfUpdated and $new->has($document)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$originalPath = \ltrim(\urldecode($document), '/');
|
$originalPath = \ltrim(\urldecode($document), '/');
|
||||||
if (\strpos($originalPath, 'storage') !== 0) {
|
if (\strpos($originalPath, 'storage') !== 0) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
||||||
if (Storage::disk('public')->exists($originalPath)) {
|
if (Storage::disk('public')->exists($originalPath)) {
|
||||||
|
|
@ -283,26 +306,27 @@ class Product extends Model
|
||||||
/**
|
/**
|
||||||
* Generate a pdf with multiple products.
|
* Generate a pdf with multiple products.
|
||||||
*
|
*
|
||||||
* @param array $printMultiProduct
|
* @param array<integer> $printMultiProduct
|
||||||
* @param string $title
|
* @param string $title
|
||||||
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
||||||
*/
|
*/
|
||||||
public static function generateMultipleProductPdf(array $printMultiProduct, string $title)
|
public static function generateMultipleProductPdf(array $printMultiProduct, string $title)
|
||||||
{
|
{
|
||||||
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */
|
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf|null */
|
||||||
$pdf = null;
|
$pdf = null;
|
||||||
// Loop all views.
|
// * Loop all Model ids.
|
||||||
foreach ($printMultiProduct as $productId) {
|
foreach ($printMultiProduct as $productId) {
|
||||||
$product = Product::where('id', $productId)->firstOrFail();
|
/** @var \App\Models\Product */
|
||||||
// If not yet defined, set the first page.
|
$product = Product::query()->where('id', $productId)->firstOrFail();
|
||||||
|
// * If not yet defined, set the first page.
|
||||||
if (is_null($pdf)) {
|
if (is_null($pdf)) {
|
||||||
$pdf = Product::generateProductPdf($product, $title);
|
$pdf = Product::generateProductPdf($product, $title);
|
||||||
} else {
|
} else {
|
||||||
// Add another page and add HTML from view to this.
|
// * Add another page and add HTML from view to this.
|
||||||
$pdf->getMpdf()->AddPage();
|
$pdf->getMpdf()->AddPage();
|
||||||
$pdf->getMpdf()->WriteHTML((string)view(
|
$pdf->getMpdf()->WriteHTML((string)view(
|
||||||
'documents.product-body',
|
'documents.product-body',
|
||||||
['product' => \json_decode(\json_encode(new ProductResource($product)))],
|
['product' => (object)(new ProductResource($product))->toArray()],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -340,14 +364,64 @@ class Product extends Model
|
||||||
])->send();
|
])->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
// * RELATIONS
|
// * GETTERS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get origins_enum attribute
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection<\App\Enums\Ingredients\OriginEnum>
|
||||||
|
*/
|
||||||
|
public function getOriginsEnumAttribute(): Collection
|
||||||
|
{
|
||||||
|
return \collect($this->getAttribute('origins'))->filter()
|
||||||
|
->map(fn (int $originEnumValue) => OriginEnum::make($originEnumValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set origins_enum attribute
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOriginsEnumAttribute(mixed $value): void
|
||||||
|
{
|
||||||
|
$this->setAttribute('origins', \collect($value)->filter()
|
||||||
|
->map(fn ($originEnumValue) => OriginEnum::make($originEnumValue)->value())
|
||||||
|
->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get claims_enum attribute
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection<\App\Enums\Ingredients\ClaimEnum>
|
||||||
|
*/
|
||||||
|
public function getClaimsEnumAttribute(): Collection
|
||||||
|
{
|
||||||
|
return \collect($this->getAttribute('claims'))->filter()
|
||||||
|
->map(fn (int $originEnumValue) => ClaimEnum::make($originEnumValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set claims_enum attribute
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClaimsEnumAttribute(mixed $value): void
|
||||||
|
{
|
||||||
|
$this->setAttribute('claims', \collect($value)->filter()
|
||||||
|
->map(fn ($claimEnumValue) => OriginEnum::make($claimEnumValue)->value())
|
||||||
|
->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
public function productComments()
|
public function productComments()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\ProductComment');
|
return $this->hasMany(ProductComment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -355,7 +429,7 @@ class Product extends Model
|
||||||
*/
|
*/
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\User');
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -363,7 +437,7 @@ class Product extends Model
|
||||||
*/
|
*/
|
||||||
public function brand()
|
public function brand()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Brand');
|
return $this->belongsTo(Brand::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,18 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property integer $id
|
* @property integer $id
|
||||||
* @property integer $product_id
|
* @property integer $product_id
|
||||||
* @property string $evaluation
|
* @property string $evaluation
|
||||||
* @property string $aspect
|
* @property string|null $aspect
|
||||||
* @property string $taste
|
* @property string|null $taste
|
||||||
* @property string $odor
|
* @property string|null $odor
|
||||||
* @property string $texture
|
* @property string|null $texture
|
||||||
* @property string $created_at
|
* @property \Carbon\Carbon $created_at
|
||||||
* @property string $updated_at
|
* @property \Carbon\Carbon $updated_at
|
||||||
* @property Product $product
|
*
|
||||||
|
* * RELATIONSHIPS
|
||||||
|
* @property-read \App\Models\Product $product
|
||||||
*/
|
*/
|
||||||
class ProductComment extends Model
|
class ProductComment extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -35,11 +37,23 @@ class ProductComment extends Model
|
||||||
'updated_at'
|
'updated_at'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
// * RELATIONSHIPS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
*/
|
*/
|
||||||
public function product()
|
public function product()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Product');
|
return $this->belongsTo(Product::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Bootstrap any application services.
|
* Bootstrap any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +27,7 @@ class AppServiceProvider extends ServiceProvider
|
||||||
return request()->getClientIp();
|
return request()->getClientIp();
|
||||||
} else {
|
} else {
|
||||||
return request()->server('HTTP_X_FORWARDED_FOR') ??
|
return request()->server('HTTP_X_FORWARDED_FOR') ??
|
||||||
request()->getClientIp();
|
request()->getClientIp();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
// use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
class AuthServiceProvider extends ServiceProvider
|
||||||
|
|
@ -12,12 +11,12 @@ class AuthServiceProvider extends ServiceProvider
|
||||||
*
|
*
|
||||||
* @var array<class-string, class-string>
|
* @var array<class-string, class-string>
|
||||||
*/
|
*/
|
||||||
protected $policies = [
|
protected $policies = [];
|
||||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register any authentication / authorization services.
|
* Register any authentication / authorization services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class EventServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register any events for your application.
|
* Register any events for your application.
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +29,7 @@ class EventServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if events and listeners should be automatically discovered.
|
* Determine if events and listeners should be automatically discovered.
|
||||||
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function shouldDiscoverEvents(): bool
|
public function shouldDiscoverEvents(): bool
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,10 @@ trait HasDocuments
|
||||||
*/
|
*/
|
||||||
private function storeDocuments(Request $request, Model $model): void
|
private function storeDocuments(Request $request, Model $model): void
|
||||||
{
|
{
|
||||||
if (is_array($request->docs)) {
|
$model->docs = [];
|
||||||
$model->docs = [];
|
$model->docs = collect($request->docs)
|
||||||
$model->docs = collect($request->docs)
|
->map(function ($document) use ($model) {
|
||||||
->map(function ($document) use ($model) {
|
return FileStorageHelper::storeFile($model, $document);
|
||||||
return FileStorageHelper::storeFile($model, $document);
|
})->all();
|
||||||
})->all();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,43 @@ namespace App\Traits\Requests;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
trait HasDocument
|
trait HasDocumentAndPictureList
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Autorised mimtypes
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $autorisedMimTypes = [
|
||||||
|
'application/msword',
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'application/pdf',
|
||||||
|
'application/vnd.ms-powerpoint',
|
||||||
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'text/csv',
|
||||||
|
'text/plain',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Images rules
|
* Images rules
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param boolean $required
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function documentsRules(
|
public function documentsRules(
|
||||||
string $name = 'documents',
|
string $name = 'docs',
|
||||||
?bool $required = null
|
|
||||||
): array {
|
): array {
|
||||||
return [
|
return [
|
||||||
"{$name}" => ($required ? 'required' : 'nullable') . '|array',
|
"{$name}" => 'present|array',
|
||||||
"{$name}.*" => [
|
"{$name}.*" => [
|
||||||
$required ? 'required' : 'nullable',
|
'required',
|
||||||
function (string $attribute, $value, callable $fail) {
|
function (string $attribute, $value, callable $fail) {
|
||||||
return $this->validateDocument($attribute, $value, $fail);
|
return $this->validateDocument($attribute, $value, $fail);
|
||||||
}
|
}
|
||||||
|
|
@ -38,32 +57,36 @@ trait HasDocument
|
||||||
* @return void
|
* @return void
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||||
*/
|
*/
|
||||||
private function validateDocument(string $attribute, $value, callable $fail)
|
private function validateDocument(string $attribute, mixed $value, callable $fail)
|
||||||
{
|
{
|
||||||
|
// phpcs:enable
|
||||||
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||||
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (!\in_array($this->getUploadedFileMimeType($value, $useStorage), $this->autorisedMimTypes)) {
|
||||||
!\in_array($this->getUploadedFileMimeType($value, $useStorage), [
|
$fail(trans(':attribute doit être un document de type :mimetypes', [
|
||||||
'application/pdf'
|
'mimetypes' => Str::of($this->autorisedMimTypes)->implode(' ou ')
|
||||||
])
|
]));
|
||||||
) {
|
}
|
||||||
$fail(trans(":attribute doit être une image de type 'application/pdf'"));
|
$maxSize = 6 * 1024 * 1024;
|
||||||
|
if (File::size($value) > $maxSize) {
|
||||||
|
$fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges documents fields with request data.
|
* Merges docs fields with request data.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function mergeDocuments(string $name = 'documents'): void
|
protected function mergeDocuments(string $name = 'docs'): void
|
||||||
{
|
{
|
||||||
$documents = $this->{$name};
|
$documents = $this->{$name};
|
||||||
|
$this->merge([$name => $this->{$name} ?? []]);
|
||||||
|
$this->merge(["{$name}Validate" => []]);
|
||||||
if (is_array($documents)) {
|
if (is_array($documents)) {
|
||||||
$this->merge(["{$name}Validate" => []]);
|
|
||||||
foreach ($documents as $key => $documentPath) {
|
foreach ($documents as $key => $documentPath) {
|
||||||
// ! Empty document.
|
// ! Empty document.
|
||||||
if ($documentPath === 'false') {
|
if ($documentPath === 'false') {
|
||||||
|
|
@ -123,7 +123,7 @@ trait HasPicture
|
||||||
* @return void
|
* @return void
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||||
*/
|
*/
|
||||||
private function validatePicture(string $attribute, $value, callable $fail, object $sizes)
|
private function validatePicture(string $attribute, mixed $value, callable $fail, object $sizes)
|
||||||
{
|
{
|
||||||
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||||
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||||
|
|
@ -138,6 +138,11 @@ trait HasPicture
|
||||||
) {
|
) {
|
||||||
$fail(trans(":attribute doit être une image de type 'image/jpeg,image/jpg,image/png,image/gif'"));
|
$fail(trans(":attribute doit être une image de type 'image/jpeg,image/jpg,image/png,image/gif'"));
|
||||||
}
|
}
|
||||||
|
$filesize = \filesize($fileFullPath);
|
||||||
|
$maxSize = 6 * 1024 * 1024;
|
||||||
|
if ($filesize === false || $filesize > $maxSize) {
|
||||||
|
$fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)]));
|
||||||
|
}
|
||||||
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
|
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
|
||||||
$fail(trans(":attribute impossible de valider les dimensions"));
|
$fail(trans(":attribute impossible de valider les dimensions"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -239,7 +244,7 @@ trait HasPicture
|
||||||
*/
|
*/
|
||||||
private function getUploadedFileFullPath(string $value, bool $useStorage): string
|
private function getUploadedFileFullPath(string $value, bool $useStorage): string
|
||||||
{
|
{
|
||||||
return !$useStorage ? realpath($value) ?: $value : Storage::getAdapter()->applyPathPrefix($value);
|
return !$useStorage ? (realpath($value) ?: $value) : Storage::path($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"carlos-meneses/laravel-mpdf": "^2.1",
|
"carlos-meneses/laravel-mpdf": "^2.1",
|
||||||
"diglactic/laravel-breadcrumbs": "^8.0",
|
"diglactic/laravel-breadcrumbs": "^8.0",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
|
"kwaadpepper/image-resizer": "^2.1",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^10.0",
|
||||||
"laravel/tinker": "^2.8"
|
"laravel/tinker": "^2.8"
|
||||||
},
|
},
|
||||||
|
|
@ -19,6 +20,7 @@
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
"kitloong/laravel-migrations-generator": "^6.8",
|
"kitloong/laravel-migrations-generator": "^6.8",
|
||||||
"krlove/eloquent-model-generator": "dev-l10-compatibility",
|
"krlove/eloquent-model-generator": "dev-l10-compatibility",
|
||||||
|
"laravel-lang/common": "^4.0",
|
||||||
"laravel/pint": "^1.0",
|
"laravel/pint": "^1.0",
|
||||||
"laravel/sail": "^1.18",
|
"laravel/sail": "^1.18",
|
||||||
"mockery/mockery": "^1.4.4",
|
"mockery/mockery": "^1.4.4",
|
||||||
|
|
|
||||||
1145
composer.lock
generated
1145
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -140,7 +140,7 @@ return [
|
||||||
|
|
||||||
'maintenance' => [
|
'maintenance' => [
|
||||||
'driver' => 'file',
|
'driver' => 'file',
|
||||||
// 'store' => 'redis',
|
// 'store' 'redis'
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -159,6 +159,7 @@ return [
|
||||||
/*
|
/*
|
||||||
* Laravel Framework Service Providers...
|
* Laravel Framework Service Providers...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Illuminate\Auth\AuthServiceProvider::class,
|
Illuminate\Auth\AuthServiceProvider::class,
|
||||||
Illuminate\Broadcasting\BroadcastServiceProvider::class,
|
Illuminate\Broadcasting\BroadcastServiceProvider::class,
|
||||||
Illuminate\Bus\BusServiceProvider::class,
|
Illuminate\Bus\BusServiceProvider::class,
|
||||||
|
|
@ -185,11 +186,13 @@ return [
|
||||||
/*
|
/*
|
||||||
* Package Service Providers...
|
* Package Service Providers...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Krlove\EloquentModelGenerator\Provider\GeneratorServiceProvider::class,
|
Krlove\EloquentModelGenerator\Provider\GeneratorServiceProvider::class,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Application Service Providers...
|
* Application Service Providers...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\AuthServiceProvider::class,
|
App\Providers\AuthServiceProvider::class,
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,6 @@ return [
|
||||||
'driver' => 'eloquent',
|
'driver' => 'eloquent',
|
||||||
'model' => App\Models\User::class,
|
'model' => App\Models\User::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
// 'users' => [
|
|
||||||
// 'driver' => 'database',
|
|
||||||
// 'table' => 'users',
|
|
||||||
// ],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,8 @@ return [
|
||||||
'encrypted' => true,
|
'encrypted' => true,
|
||||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||||
],
|
],
|
||||||
'client_options' => [
|
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html .
|
||||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
'client_options' => [],
|
||||||
],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'ably' => [
|
'ably' => [
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,7 @@ return [
|
||||||
env('MEMCACHED_USERNAME'),
|
env('MEMCACHED_USERNAME'),
|
||||||
env('MEMCACHED_PASSWORD'),
|
env('MEMCACHED_PASSWORD'),
|
||||||
],
|
],
|
||||||
'options' => [
|
'options' => [],
|
||||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
|
||||||
],
|
|
||||||
'servers' => [
|
'servers' => [
|
||||||
[
|
[
|
||||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ return [
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
|
||||||
69
config/image-resizer.php
Normal file
69
config/image-resizer.php
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
/**
|
||||||
|
* The php image driver to use
|
||||||
|
* this can be 'imagick' or 'gd'
|
||||||
|
*/
|
||||||
|
'driver' => 'imagick',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache driver to use as defined
|
||||||
|
* in config/cache of your app
|
||||||
|
*/
|
||||||
|
'cache' => 'file',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path where to store image in cache
|
||||||
|
*/
|
||||||
|
'cachePath' => 'cache/images',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image cache life time
|
||||||
|
* This is given in minutes
|
||||||
|
* Here the cache for images is
|
||||||
|
* one hour
|
||||||
|
*/
|
||||||
|
'lifetime' => 60,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format can specifiy to which format save the image
|
||||||
|
* JPEG PNG GIF TIF BMP ICO PSD WebP
|
||||||
|
* GD ✔️ ✔️ ✔️ - - - - ✔️ *
|
||||||
|
* Imagick ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ *
|
||||||
|
* For WebP support GD driver must be used with PHP 5 >= 5.5.0 or PHP 7
|
||||||
|
* in order to use imagewebp(). If Imagick is used, it must be compiled
|
||||||
|
* with libwebp for WebP support.
|
||||||
|
* resize => will resize the image (boolean)
|
||||||
|
* fit => Combine cropping and resizing to format image in a smart way (boolean)
|
||||||
|
* keepRatio => will keep image ratio wile resizing (boolean)
|
||||||
|
* trim => boolean to trim the image using border color
|
||||||
|
* inCanvas => to make sure image boundarie is respected
|
||||||
|
* format => select tha wantd ouput form, yan can just convert images if you want
|
||||||
|
* example :
|
||||||
|
* 'small' => [
|
||||||
|
* 'height' => 500,
|
||||||
|
* 'width' => 250,
|
||||||
|
* 'inCanvas' => true,
|
||||||
|
* 'trim' => ['transparent', null, 10]
|
||||||
|
* ],
|
||||||
|
* 'smallWebp' => [
|
||||||
|
* 'height' => 500,
|
||||||
|
* 'width' => 250,
|
||||||
|
* 'inCanvas' => true,
|
||||||
|
* 'format' => 'webp'
|
||||||
|
* ],
|
||||||
|
* 'justconvertImage' => [
|
||||||
|
* 'format' => 'webp'
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
'templates' => [
|
||||||
|
'productTiny' => [
|
||||||
|
'height' => 180,
|
||||||
|
'width' => 180,
|
||||||
|
'resize' => true,
|
||||||
|
'keepRatio' => true,
|
||||||
|
'format' => 'jpg',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
@ -51,16 +51,16 @@ return [
|
||||||
|
|
||||||
'mailgun' => [
|
'mailgun' => [
|
||||||
'transport' => 'mailgun',
|
'transport' => 'mailgun',
|
||||||
// 'client' => [
|
'client' => [
|
||||||
// 'timeout' => 5,
|
'timeout' => 5,
|
||||||
// ],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'postmark' => [
|
'postmark' => [
|
||||||
'transport' => 'postmark',
|
'transport' => 'postmark',
|
||||||
// 'client' => [
|
'client' => [
|
||||||
// 'timeout' => 5,
|
'timeout' => 5,
|
||||||
// ],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'sendmail' => [
|
'sendmail' => [
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ final class BrandFactory extends Factory
|
||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => fake()->word,
|
'name' => fake()->unique()->word,
|
||||||
'filter' => fake()->word,
|
'filter' => fake()->word,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,15 @@ final class ProductFactory extends Factory
|
||||||
*/
|
*/
|
||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
$source = \collect(SourceEnum::toArray())->random()->value;
|
$source = \collect(SourceEnum::toArray())->random()->value;
|
||||||
$fair = $shop = $catalogue = null;
|
$catalogue = null;
|
||||||
if ($source === SourceEnum::showConsumer->value || $source === SourceEnum::showCustomer->value || $source === SourceEnum::showTrade->value) {
|
$fair = null;
|
||||||
|
$shop = null;
|
||||||
|
if (
|
||||||
|
$source === SourceEnum::showConsumer->value ||
|
||||||
|
$source === SourceEnum::showCustomer->value ||
|
||||||
|
$source === SourceEnum::showTrade->value
|
||||||
|
) {
|
||||||
$fair = fake()->word;
|
$fair = fake()->word;
|
||||||
} elseif ($source === SourceEnum::magazin->value) {
|
} elseif ($source === SourceEnum::magazin->value) {
|
||||||
$shop = fake()->word;
|
$shop = fake()->word;
|
||||||
|
|
@ -61,8 +67,8 @@ final class ProductFactory extends Factory
|
||||||
'docs' => [],
|
'docs' => [],
|
||||||
'url' => fake()->url,
|
'url' => fake()->url,
|
||||||
'certification' => \collect(CertificationEnum::toArray())->random()->value,
|
'certification' => \collect(CertificationEnum::toArray())->random()->value,
|
||||||
'origins' => [["id" => strval(\collect(OriginEnum::toArray())->random()->value)]],
|
'origins' => [\collect(OriginEnum::toArray())->random()->value],
|
||||||
'claims' => [["id" => strval($claim)]],
|
'claims' => [$claim],
|
||||||
'specified_claim' => ($claim == OriginEnum::others->value) ? fake()->text : null,
|
'specified_claim' => ($claim == OriginEnum::others->value) ? fake()->text : null,
|
||||||
'distribution_network' => \collect(DistributionNetworkEnum::toArray())->random()->value,
|
'distribution_network' => \collect(DistributionNetworkEnum::toArray())->random()->value,
|
||||||
'ray' => \collect(RayEnum::toArray())->random()->value,
|
'ray' => \collect(RayEnum::toArray())->random()->value,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
$table->decimal('pvc', 12, 2)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
$table->integer('pvc')->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -9,12 +9,16 @@ use App\Enums\Products\OriginEnum;
|
||||||
use App\Enums\Products\RangeEnum;
|
use App\Enums\Products\RangeEnum;
|
||||||
use App\Enums\Products\RayEnum;
|
use App\Enums\Products\RayEnum;
|
||||||
use App\Enums\Products\SourceEnum;
|
use App\Enums\Products\SourceEnum;
|
||||||
|
use App\Lib\Helpers\FileStorageHelper;
|
||||||
use App\Models\Brand;
|
use App\Models\Brand;
|
||||||
use App\Models\Keyword;
|
use App\Models\Keyword;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
|
use App\Models\ProductComment;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Console\OutputStyle;
|
||||||
use Illuminate\Contracts\Database\Query\Builder;
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Database\Migrations\Migration;
|
use Illuminate\Database\Migrations\Migration;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
@ -22,8 +26,11 @@ use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\ItemNotFoundException;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
|
|
||||||
return new class extends Migration
|
return new class extends Migration
|
||||||
|
|
@ -47,9 +54,18 @@ return new class extends Migration
|
||||||
'VEILLE_PROD', 'VEILLE_PROD_COMM',
|
'VEILLE_PROD', 'VEILLE_PROD_COMM',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var \App\Model\User */
|
/**
|
||||||
|
* Console tabulation (margin left)
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $consoleTabulation = 28;
|
||||||
|
|
||||||
|
/** @var \App\Models\User */
|
||||||
private $dummyUser;
|
private $dummyUser;
|
||||||
|
|
||||||
|
/** @var \App\Models\Brand */
|
||||||
|
private $dummyBrand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the migrations.
|
* Run the migrations.
|
||||||
*
|
*
|
||||||
|
|
@ -58,8 +74,14 @@ return new class extends Migration
|
||||||
*/
|
*/
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
$console = new ConsoleOutput();
|
$ouput = new ConsoleOutput();
|
||||||
$section = $console->section();
|
$input = new ArgvInput();
|
||||||
|
$style = new OutputStyle($input, $ouput);
|
||||||
|
$section = $ouput->section();
|
||||||
|
|
||||||
|
if (!$style->confirm('Do this migration or skip ?', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// * SEED KEYWORDS As they are needed on runtime.
|
// * SEED KEYWORDS As they are needed on runtime.
|
||||||
Schema::disableForeignKeyConstraints();
|
Schema::disableForeignKeyConstraints();
|
||||||
|
|
@ -67,6 +89,9 @@ return new class extends Migration
|
||||||
DB::table('keywordables')->truncate();
|
DB::table('keywordables')->truncate();
|
||||||
DB::table('keywords')->truncate();
|
DB::table('keywords')->truncate();
|
||||||
DB::table('products')->truncate();
|
DB::table('products')->truncate();
|
||||||
|
DB::table('product_comments')->truncate();
|
||||||
|
// * Remove previously uploaded files.
|
||||||
|
File::deleteDirectory(storage_path('app/public/modelfiles/products'));
|
||||||
Schema::enableForeignKeyConstraints();
|
Schema::enableForeignKeyConstraints();
|
||||||
if (Artisan::call('db:seed', ['--class' => 'KeywordInitSeeder']) !== 0) {
|
if (Artisan::call('db:seed', ['--class' => 'KeywordInitSeeder']) !== 0) {
|
||||||
throw new \RuntimeException('Failed to seed keywords');
|
throw new \RuntimeException('Failed to seed keywords');
|
||||||
|
|
@ -77,6 +102,11 @@ return new class extends Migration
|
||||||
'firstname' => 'Dummy',
|
'firstname' => 'Dummy',
|
||||||
'lastname' => 'User'
|
'lastname' => 'User'
|
||||||
]);
|
]);
|
||||||
|
// * Seed a dummy brand.
|
||||||
|
$this->dummyBrand = Brand::factory()->createOne([
|
||||||
|
'name' => Str::of('Sans Marque')->slug()->studly(),
|
||||||
|
'filter' => null
|
||||||
|
]);
|
||||||
|
|
||||||
// * Apply DB corrections
|
// * Apply DB corrections
|
||||||
$this->setUniqueOnBrandName();
|
$this->setUniqueOnBrandName();
|
||||||
|
|
@ -88,13 +118,13 @@ return new class extends Migration
|
||||||
$this->createAndFillTempTables();
|
$this->createAndFillTempTables();
|
||||||
|
|
||||||
// * Migrate PRODUCTS, comment all except the one you want to develop here.
|
// * Migrate PRODUCTS, comment all except the one you want to develop here.
|
||||||
$this->migrateBrands();
|
$this->migrateBrands($style);
|
||||||
$this->migrateProducts();
|
$this->migrateProducts($style);
|
||||||
|
$this->migrateProductsComments($style);
|
||||||
|
|
||||||
// ! DEV: Add a die here to develop migration and prevent droping temp tables
|
|
||||||
// dd('toto');
|
|
||||||
|
|
||||||
|
if (!$style->confirm('Continue ?')) {
|
||||||
|
throw new \RuntimeException('Migration stoped');
|
||||||
|
}
|
||||||
$this->dropTempTables();
|
$this->dropTempTables();
|
||||||
$section->clear();
|
$section->clear();
|
||||||
}
|
}
|
||||||
|
|
@ -113,21 +143,91 @@ return new class extends Migration
|
||||||
// - MIGRATION METHODS -
|
// - MIGRATION METHODS -
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate products
|
* Migrate products comments
|
||||||
*
|
|
||||||
*
|
*
|
||||||
|
* @param \Illuminate\Console\OutputStyle $style
|
||||||
* @return void
|
* @return void
|
||||||
* @throws \Error In case of failure.
|
* @throws \Error In case of failure.
|
||||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||||
*/
|
*/
|
||||||
private function migrateProducts(): void
|
private function migrateProductsComments(OutputStyle $style): void
|
||||||
|
{
|
||||||
|
// phpcs:enable
|
||||||
|
$index = "NUM_COMM";
|
||||||
|
$query = $this->getQuery("VEILLE_PROD_COMM")->orderBy($index);
|
||||||
|
$nbRowsToMigrate = (clone $query)->count();
|
||||||
|
$totalRowsToMigrate = $nbRowsToMigrate;
|
||||||
|
|
||||||
|
$console = new ConsoleOutput();
|
||||||
|
$console->writeln('');
|
||||||
|
$progress = new ProgressBar($console, $nbRowsToMigrate);
|
||||||
|
$progress->setMessage(str_pad('Migrate Products Comments', $this->consoleTabulation, ' '));
|
||||||
|
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
||||||
|
$skipped = collect();
|
||||||
|
|
||||||
|
while ($nbRowsToMigrate > 0) {
|
||||||
|
$progress->display();
|
||||||
|
$progress->advance(1);
|
||||||
|
$row = (clone $query)->skip($totalRowsToMigrate - $nbRowsToMigrate--)->limit(1)->first();
|
||||||
|
try {
|
||||||
|
|
||||||
|
/** @var \App\Models\ProductComment $comment */
|
||||||
|
$comment = ProductComment::query()->where('id', $row->{$index})->firstOrNew();
|
||||||
|
$comment->id = $row->NUM_COMM;
|
||||||
|
/** @var \App\Models\Product $product */
|
||||||
|
$product = Product::query()->where('id', $row->NUM_PROD)->firstOrFail();
|
||||||
|
$product->id = $row->NUM_PROD;
|
||||||
|
|
||||||
|
$date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null;
|
||||||
|
|
||||||
|
$fill = [
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'evaluation' => $row->APPRECIATION ?? '',
|
||||||
|
'aspect' => $row->ASPECT,
|
||||||
|
'taste' => $row->GOUT,
|
||||||
|
'odor' => $row->ODEUR,
|
||||||
|
'texture' => $row->TEXTURE,
|
||||||
|
];
|
||||||
|
if ($date_saisie) {
|
||||||
|
// ? FIXME: IS this pertinent ?
|
||||||
|
$fill['created_at'] = $date_saisie;
|
||||||
|
$fill['updated_at'] = $date_saisie;
|
||||||
|
}
|
||||||
|
$comment->fill($fill);
|
||||||
|
if (!DB::transaction(fn () => $comment->saveQuietly())) {
|
||||||
|
throw new \Error("Failed to save comment {$row->NUM_COMM}");
|
||||||
|
}
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
$model = $e->getModel();
|
||||||
|
$skipped->push("No {$model} found for '{$row->NUM_PROD}', skip comment '{$row->NUM_COMM}'");
|
||||||
|
} //end try
|
||||||
|
} //end while
|
||||||
|
$progress->finish();
|
||||||
|
if ($skipped->count() and !$console->writeln('') and $style->confirm('Show errors ?', false)) {
|
||||||
|
$console->writeln('');
|
||||||
|
$skipped->each(fn (string $error) => $console->writeln(str_repeat(' ', 8) . $error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate products
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Console\OutputStyle $style
|
||||||
|
* @return void
|
||||||
|
* @throws \Error In case of failure.
|
||||||
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||||
|
*/
|
||||||
|
private function migrateProducts(OutputStyle $style): void
|
||||||
{
|
{
|
||||||
// phpcs:enable
|
// phpcs:enable
|
||||||
$otherAllegations = Str::of(File::get(base_path('database/migrations/other_allegations.txt')))
|
$otherAllegations = Str::of(File::get(base_path('database/migrations/other_allegations.txt')))
|
||||||
->explode(PHP_EOL)->map(fn (string $other_allegation) => Str::of($other_allegation)->squish())
|
->explode(PHP_EOL)->map(fn (string $other_allegation) => Str::of($other_allegation)->squish())
|
||||||
->unique();
|
->unique();
|
||||||
|
|
||||||
$MOTKS = Keyword::all();
|
$MOTKS = Keyword::query()->where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||||
/** @var \Illuminate\Support\Collection<string,string> */
|
/** @var \Illuminate\Support\Collection<string,string> */
|
||||||
$START_SOURCES = $this->getQuery('SOURCE')->get();
|
$START_SOURCES = $this->getQuery('SOURCE')->get();
|
||||||
/** @var \Illuminate\Support\Collection<string,string> */
|
/** @var \Illuminate\Support\Collection<string,string> */
|
||||||
|
|
@ -156,7 +256,7 @@ return new class extends Migration
|
||||||
$console = new ConsoleOutput();
|
$console = new ConsoleOutput();
|
||||||
$console->writeln('');
|
$console->writeln('');
|
||||||
$progress = new ProgressBar($console, $nbRowsToMigrate);
|
$progress = new ProgressBar($console, $nbRowsToMigrate);
|
||||||
$progress->setMessage(str_pad('Migrate Products', 24, ' '));
|
$progress->setMessage(str_pad('Migrate Products', $this->consoleTabulation, ' '));
|
||||||
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
||||||
|
|
||||||
while ($nbRowsToMigrate > 0) {
|
while ($nbRowsToMigrate > 0) {
|
||||||
|
|
@ -211,22 +311,22 @@ return new class extends Migration
|
||||||
// * Uu OMG !!!
|
// * Uu OMG !!!
|
||||||
if ($motk === 'Gain de temps Nomadisme') {
|
if ($motk === 'Gain de temps Nomadisme') {
|
||||||
return $MOTKS->where('label', 'Gain de temps')
|
return $MOTKS->where('label', 'Gain de temps')
|
||||||
->where('keyword_cat', KeywordCategoryEnum::productPracticality)->firstOrFail();
|
->where('keyword_cat', KeywordCategoryEnum::productPracticality)->firstOrFail();
|
||||||
}
|
}
|
||||||
if ($motk === 'Vari??t?? des sens') {
|
if ($motk === 'Vari??t?? des sens') {
|
||||||
return $MOTKS->where('label', 'Variété des sens')
|
return $MOTKS->where('label', 'Variété des sens')
|
||||||
->where('keyword_cat', KeywordCategoryEnum::productPleasure)->firstOrFail();
|
->where('keyword_cat', KeywordCategoryEnum::productPleasure)->firstOrFail();
|
||||||
}
|
}
|
||||||
if ($motk === 'V??g??tal') {
|
if ($motk === 'V??g??tal') {
|
||||||
return $MOTKS->where('label', 'Végétal')
|
return $MOTKS->where('label', 'Végétal')
|
||||||
->where('keyword_cat', KeywordCategoryEnum::productHealth)->firstOrFail();
|
->where('keyword_cat', KeywordCategoryEnum::productHealth)->firstOrFail();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return $MOTKS->firstOrFail(
|
return $MOTKS->firstOrFail(
|
||||||
fn (Keyword $keyword) => Str::of($keyword->label)->ascii()->replace(' ', '')
|
fn (Keyword $keyword) => Str::of($keyword->label)->ascii()->replace(' ', '')
|
||||||
== Str::of($motk)->trim()->ascii()->replace(' ', '')
|
== Str::of($motk)->trim()->ascii()->replace(' ', '')
|
||||||
);
|
);
|
||||||
} catch (\Exception) {
|
} catch (ItemNotFoundException) {
|
||||||
dump(
|
dump(
|
||||||
$motk,
|
$motk,
|
||||||
$MOTKS->pluck('label')
|
$MOTKS->pluck('label')
|
||||||
|
|
@ -235,28 +335,32 @@ return new class extends Migration
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9740 .
|
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9740 .
|
||||||
if (empty($row->MARQUE)) {
|
if (is_null($row->MARQUE)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9750 .
|
if (!strlen(trim($row->MARQUE))) {
|
||||||
|
$row->MARQUE = $this->dummyBrand->name;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9750 .
|
||||||
if (empty($row->NUM_RESEAU)) {
|
if (empty($row->NUM_RESEAU)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9758 .
|
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9758 .
|
||||||
if (empty($row->NUM_SECTEUR)) {
|
if (empty($row->NUM_SECTEUR)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9760 .
|
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9760 .
|
||||||
if (empty($row->NUM_RAYON)) {
|
if (empty($row->NUM_RAYON)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9767 .
|
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9767 .
|
||||||
if (empty($row->NUM_FAMILLE)) {
|
if (empty($row->NUM_FAMILLE)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$brandName = Str::of($row->MARQUE)->slug()->studly();
|
$brandName = Str::of($row->MARQUE)->trim()->title();
|
||||||
/** name is unique on brand */
|
/** name is unique on brand */
|
||||||
$brand = null;
|
$brand = null;
|
||||||
try {
|
try {
|
||||||
|
|
@ -264,9 +368,9 @@ return new class extends Migration
|
||||||
} catch (\Exception) {
|
} catch (\Exception) {
|
||||||
throw new \Error("brand` {$brandName}` not found");
|
throw new \Error("brand` {$brandName}` not found");
|
||||||
}
|
}
|
||||||
$url = $row->URL ? Str::of(url($row->URL))->lower() : null;
|
$url = $row->URL ? Str::lower(url($row->URL)) : null;
|
||||||
$date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null;
|
$date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null;
|
||||||
$is_tasted = Str::of($row->DEGUSTER_O_N)->lower() === 'o' ? true : false;
|
$is_tasted = Str::lower($row->DEGUSTER_O_N) === 'o' ? true : false;
|
||||||
$claimList = collect([
|
$claimList = collect([
|
||||||
$row->ALLEG0, $row->ALLEG1, $row->ALLEG2
|
$row->ALLEG0, $row->ALLEG1, $row->ALLEG2
|
||||||
])->filter()->map(fn (string $alleg) => $resolveAllegation($alleg));
|
])->filter()->map(fn (string $alleg) => $resolveAllegation($alleg));
|
||||||
|
|
@ -319,7 +423,26 @@ return new class extends Migration
|
||||||
/** @var \App\Models\Product $product */
|
/** @var \App\Models\Product $product */
|
||||||
$product = Product::query()->where('id', $row->{$index})->firstOrNew();
|
$product = Product::query()->where('id', $row->{$index})->firstOrNew();
|
||||||
$product->id = $row->NUM_VEILLE_PROD;
|
$product->id = $row->NUM_VEILLE_PROD;
|
||||||
$fill = [
|
|
||||||
|
// * DOCS
|
||||||
|
$disk = $this->getMigrationStorage('Produit/' . strval($row->{$index}));
|
||||||
|
$files = $disk ? collect($disk->files())->mapWithKeys(function (string $file) use ($disk, $product) {
|
||||||
|
$filePath = FileStorageHelper::storeFile($product, new \SplFileInfo($disk->path($file)));
|
||||||
|
return [pathinfo($filePath, PATHINFO_BASENAME) => $filePath];
|
||||||
|
}) : null;
|
||||||
|
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||||
|
$pictureKey = $files ? $files->map(fn (string $filePath, string $fileName) => $fileName)
|
||||||
|
->first(function ($fileName) {
|
||||||
|
return preg_match('/(ref-?[0-9a-z]{0,}.jpg)/', $fileName) === 1;
|
||||||
|
}) : null;
|
||||||
|
$picture = $files ? $files->get($pictureKey) : null;
|
||||||
|
if ($files) {
|
||||||
|
$files->pull($pictureKey);
|
||||||
|
$files = $files->values();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fill = [
|
||||||
'brand_id' => $brand->id,
|
'brand_id' => $brand->id,
|
||||||
'catalogue' => $row->CATALOGUE,
|
'catalogue' => $row->CATALOGUE,
|
||||||
'certification' => $certificationEnum,
|
'certification' => $certificationEnum,
|
||||||
|
|
@ -341,10 +464,11 @@ return new class extends Migration
|
||||||
'specified_claim' => $claim,
|
'specified_claim' => $claim,
|
||||||
'tasters_number' => $row->NB_DEGUST,
|
'tasters_number' => $row->NB_DEGUST,
|
||||||
'origins' => $originList,
|
'origins' => $originList,
|
||||||
'docs' => 'tttt',
|
'docs' => $files,
|
||||||
'picture_alt' => 'tttt',
|
'picture_alt' => "Image de {$row->NOM}",
|
||||||
'picture_title' => 'tttt',
|
'picture_title' => "Image de {$row->NOM}",
|
||||||
'picture' => 'tttt',
|
'picture' => $picture,
|
||||||
|
// NOTE: https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_10688 .
|
||||||
'user_id' => $this->dummyUser->id
|
'user_id' => $this->dummyUser->id
|
||||||
];
|
];
|
||||||
if ($date_saisie) {
|
if ($date_saisie) {
|
||||||
|
|
@ -369,18 +493,21 @@ return new class extends Migration
|
||||||
/**
|
/**
|
||||||
* Create unique brands using veille products
|
* Create unique brands using veille products
|
||||||
*
|
*
|
||||||
|
* @param \Illuminate\Console\OutputStyle $style
|
||||||
* @return void
|
* @return void
|
||||||
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||||
*/
|
*/
|
||||||
private function migrateBrands(): void
|
private function migrateBrands(OutputStyle $style): void
|
||||||
{
|
{
|
||||||
|
// phpcs:enable
|
||||||
$query = $this->getQuery("VEILLE_PROD");
|
$query = $this->getQuery("VEILLE_PROD");
|
||||||
/** @var \Illuminate\Support\Collection<string,string> */
|
/** @var \Illuminate\Support\Collection<string,string> */
|
||||||
$brands = (clone $query)->pluck('MARQUE')->filter()
|
$brands = (clone $query)->pluck('MARQUE')->filter()
|
||||||
->map(fn (string $brandName) => Str::of($brandName)->slug()->studly())->unique();
|
->map(fn (string $brandName) => Str::of($brandName)->trim()->title())->unique();
|
||||||
$console = new ConsoleOutput();
|
$console = new ConsoleOutput();
|
||||||
$console->writeln('');
|
$console->writeln('');
|
||||||
$progress = new ProgressBar($console, $brands->count());
|
$progress = new ProgressBar($console, $brands->count());
|
||||||
$progress->setMessage(str_pad('Migrate Brands', 24, ' '));
|
$progress->setMessage(str_pad('Migrate Brands', $this->consoleTabulation, ' '));
|
||||||
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
||||||
// FIXME: Insert brand->filter and find from where it should be fetched.
|
// FIXME: Insert brand->filter and find from where it should be fetched.
|
||||||
$brands->each(function ($brandName) use ($progress) {
|
$brands->each(function ($brandName) use ($progress) {
|
||||||
|
|
@ -445,7 +572,7 @@ return new class extends Migration
|
||||||
});
|
});
|
||||||
Schema::table('keywordables', function (Blueprint $table) {
|
Schema::table('keywordables', function (Blueprint $table) {
|
||||||
$table->foreign(['keyword_id'])->references(['id'])->on('keywords')
|
$table->foreign(['keyword_id'])->references(['id'])->on('keywords')
|
||||||
->restrictOnUpdate()->cascadeOnDelete();
|
->restrictOnUpdate()->cascadeOnDelete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,13 +588,42 @@ return new class extends Migration
|
||||||
});
|
});
|
||||||
Schema::table('processes', function (Blueprint $table) {
|
Schema::table('processes', function (Blueprint $table) {
|
||||||
$table->foreign(['user_id'])->references(['id'])->on('users')
|
$table->foreign(['user_id'])->references(['id'])->on('users')
|
||||||
->restrictOnUpdate()->restrictOnDelete();
|
->restrictOnUpdate()->restrictOnDelete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- END DB CORRECTION --
|
// -- END DB CORRECTION --
|
||||||
// --- LIB METHODS ---
|
// --- LIB METHODS ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get migration disk
|
||||||
|
*
|
||||||
|
* @param string|null $path Get a specific path.
|
||||||
|
* @return \Illuminate\Filesystem\FilesystemAdapter|null
|
||||||
|
* @throws \Error If veille folder is missing.
|
||||||
|
*/
|
||||||
|
private function getMigrationStorage(string $path = ''): \Illuminate\Filesystem\FilesystemAdapter|null
|
||||||
|
{
|
||||||
|
$storagePath = storage_path('app/migration');
|
||||||
|
$path = "/Veille/{$path}";
|
||||||
|
|
||||||
|
if (!File::exists("{$storagePath}{$path}")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$diskName = 'migration' . Str::of("{$storagePath}{$path}")->slug();
|
||||||
|
|
||||||
|
config()->set("filesystems.disks.{$diskName}", [
|
||||||
|
'driver' => 'local',
|
||||||
|
'root' => "{$storagePath}{$path}",
|
||||||
|
'throw' => false,
|
||||||
|
]);
|
||||||
|
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||||
|
$disk = Storage::disk($diskName);
|
||||||
|
|
||||||
|
|
||||||
|
return $disk;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Temp DB query builder
|
* Get Temp DB query builder
|
||||||
*
|
*
|
||||||
|
|
@ -513,7 +669,7 @@ return new class extends Migration
|
||||||
$tableComment = "{$tableColumn->name} {$tableColumn->type} {$tableColumn->size}";
|
$tableComment = "{$tableColumn->name} {$tableColumn->type} {$tableColumn->size}";
|
||||||
switch ($tableColumn->type) {
|
switch ($tableColumn->type) {
|
||||||
case 'NUMBER':
|
case 'NUMBER':
|
||||||
$table->bigInteger($tableColumn->name)
|
$table->double($tableColumn->name)
|
||||||
->nullable()->comment($tableComment);
|
->nullable()->comment($tableComment);
|
||||||
break;
|
break;
|
||||||
case 'VARCHAR2':
|
case 'VARCHAR2':
|
||||||
|
|
@ -549,7 +705,7 @@ return new class extends Migration
|
||||||
$this->getTableName($tableName),
|
$this->getTableName($tableName),
|
||||||
$header
|
$header
|
||||||
);
|
);
|
||||||
$message = str_pad("{$this->tablePrefix} {$tableName}", 24, ' ');
|
$message = str_pad("{$this->tablePrefix} {$tableName}", $this->consoleTabulation, ' ');
|
||||||
$section->write(" - {$message} -> Fetching OCI DATA..");
|
$section->write(" - {$message} -> Fetching OCI DATA..");
|
||||||
$content = $this->fetchOciTableContent($tableName, $header);
|
$content = $this->fetchOciTableContent($tableName, $header);
|
||||||
$section->clear();
|
$section->clear();
|
||||||
|
|
@ -561,7 +717,7 @@ return new class extends Migration
|
||||||
DB::table($this->getTableName($tableName))->insert((array)$row);
|
DB::table($this->getTableName($tableName))->insert((array)$row);
|
||||||
}
|
}
|
||||||
$progress->finish();
|
$progress->finish();
|
||||||
}//end foreach
|
} //end foreach
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -5,6 +5,7 @@ namespace Database\Seeders;
|
||||||
use App\Enums\KeywordCategoryEnum;
|
use App\Enums\KeywordCategoryEnum;
|
||||||
use App\Models\Keyword;
|
use App\Models\Keyword;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class KeywordInitSeeder extends Seeder
|
class KeywordInitSeeder extends Seeder
|
||||||
{
|
{
|
||||||
|
|
@ -12,186 +13,324 @@ class KeywordInitSeeder extends Seeder
|
||||||
* Run the database seeds.
|
* Run the database seeds.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
|
// phpcs:enable
|
||||||
/**
|
/**
|
||||||
* * INGREDIENTS
|
* * INGREDIENTS
|
||||||
*/
|
*/
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Sophistication";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Sophistication";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Exotisme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Exotisme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Fun";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Fun";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Clean label/naturalité";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Clean label/naturalité";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Végétarien/vegan";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Végétarien/vegan";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Bien être";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Bien être";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Solidarité";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Solidarité";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Écologie";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Écologie";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Emballage individuel";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Emballage individuel";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Facilité de mise en oeuvre";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Facilité de mise en oeuvre";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * PRODUCTS
|
* * PRODUCTS
|
||||||
*/
|
*/
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Sophistication";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Sophistication";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Exotisme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Exotisme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Variété des sens";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Variété des sens";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Fun";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Fun";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Minceur";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Minceur";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Énergie/Bien-être";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Énergie/Bien-être";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Cosmétique";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Cosmétique";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Manipulation produit";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Manipulation produit";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Gain de temps";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Gain de temps";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Nomadisme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Nomadisme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Naturalité";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Naturalité";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Végétal";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Végétal";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Médical";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Médical";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Solidarité";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Solidarité";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Écologie";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Écologie";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * PACKAGING
|
* * PACKAGING
|
||||||
*/
|
*/
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Sophistication";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Sophistication";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Exotisme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Exotisme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Fun";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Fun";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Manipulation produit";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Manipulation produit";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Gain de temps";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Gain de temps";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Nomadisme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Nomadisme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Décor/forme";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Décor/forme";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Matériaux";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Matériaux";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$keyword = new Keyword();
|
try {
|
||||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12];
|
$keyword = new Keyword();
|
||||||
$keyword->label = "Écologie";
|
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12];
|
||||||
$keyword->saveOrFail();
|
$keyword->label = "Écologie";
|
||||||
|
$keyword->saveQuietly();
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
Log::debug($e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
resources/lang/fr.json
Normal file
39
resources/lang/fr.json
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"(and :count more error)": "(et :count erreur en plus)",
|
||||||
|
"(and :count more errors)": "(et :count erreurs en plus)",
|
||||||
|
"All rights reserved.": "Tous droits réservés.",
|
||||||
|
"Forbidden": "Interdit",
|
||||||
|
"Go to page :page": "Aller à la page :page",
|
||||||
|
"Hello!": "Bonjour !",
|
||||||
|
"If you did not create an account, no further action is required.": "Si vous n'avez pas créé de compte, vous pouvez ignorer ce message.",
|
||||||
|
"If you did not request a password reset, no further action is required.": "Si vous n'avez pas demandé de réinitialisation de mot de passe, vous pouvez ignorer ce message.",
|
||||||
|
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "Si vous avez des difficultés à cliquer sur le bouton \":actionText\", copiez et collez l'URL ci-dessous\ndans votre navigateur Web :",
|
||||||
|
"Invalid JSON was returned from the route.": "Un JSON non valide a été renvoyé par la route.",
|
||||||
|
"Login": "Connexion",
|
||||||
|
"Logout": "Déconnexion",
|
||||||
|
"Not Found": "Non trouvé",
|
||||||
|
"of": "de",
|
||||||
|
"Page Expired": "Page expirée",
|
||||||
|
"Pagination Navigation": "Pagination",
|
||||||
|
"Payment Required": "Paiement requis",
|
||||||
|
"Please click the button below to verify your email address.": "Veuillez cliquer sur le bouton ci-dessous pour vérifier votre adresse e-mail :",
|
||||||
|
"Regards": "Cordialement",
|
||||||
|
"Register": "Inscription",
|
||||||
|
"Reset Password": "Réinitialisation du mot de passe",
|
||||||
|
"Reset Password Notification": "Notification de réinitialisation du mot de passe",
|
||||||
|
"results": "résultats",
|
||||||
|
"Server Error": "Erreur serveur",
|
||||||
|
"Service Unavailable": "Service indisponible",
|
||||||
|
"Showing": "Montrant",
|
||||||
|
"The given data was invalid.": "La donnée renseignée est incorrecte.",
|
||||||
|
"The response is not a streamed response.": "La réponse n'est pas une réponse diffusée.",
|
||||||
|
"The response is not a view.": "La réponse n'est pas une vue.",
|
||||||
|
"This password reset link will expire in :count minutes.": "Ce lien de réinitialisation du mot de passe expirera dans :count minutes.",
|
||||||
|
"to": "à",
|
||||||
|
"Toggle navigation": "Afficher / masquer le menu de navigation",
|
||||||
|
"Too Many Requests": "Trop de requêtes",
|
||||||
|
"Unauthorized": "Non autorisé",
|
||||||
|
"Verify Email Address": "Vérifier l'adresse e-mail",
|
||||||
|
"Whoops!": "Oups !",
|
||||||
|
"You are receiving this email because we received a password reset request for your account.": "Vous recevez cet e-mail car nous avons reçu une demande de réinitialisation de mot de passe pour votre compte."
|
||||||
|
}
|
||||||
9
resources/lang/fr/auth.php
Normal file
9
resources/lang/fr/auth.php
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'failed' => 'Ces identifiants ne correspondent pas à nos enregistrements.',
|
||||||
|
'password' => 'Le mot de passe est incorrect',
|
||||||
|
'throttle' => 'Tentatives de connexion trop nombreuses. Veuillez essayer de nouveau dans :seconds secondes.',
|
||||||
|
];
|
||||||
83
resources/lang/fr/crud.php
Normal file
83
resources/lang/fr/crud.php
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'actions' => [
|
||||||
|
'list' => 'Liste',
|
||||||
|
'view' => 'Voir',
|
||||||
|
'create' => 'Créer',
|
||||||
|
'duplicate' => 'Dupliquer',
|
||||||
|
'update' => 'Éditer',
|
||||||
|
'delete' => 'Supprimer',
|
||||||
|
'save' => 'Sauvegarder',
|
||||||
|
'edit' => 'Mettre à jour',
|
||||||
|
],
|
||||||
|
|
||||||
|
'helpers' => [
|
||||||
|
'list' => 'Liste',
|
||||||
|
'list_all' => 'Lister tous les :model',
|
||||||
|
'create_model' => 'Créer :model',
|
||||||
|
'view_model' => 'Voir :model',
|
||||||
|
'update_model' => 'Éditer :model',
|
||||||
|
'duplicate_model' => 'Dupliquer :model',
|
||||||
|
'delete_model' => 'Supprimer :model',
|
||||||
|
'save_model' => 'Sauvegarder :model',
|
||||||
|
'edit_model' => 'Mettre à jour :model',
|
||||||
|
'no_results' => 'Aucun résultat pour :model',
|
||||||
|
'publish' => 'Publié',
|
||||||
|
'unpublish' => 'Dépublié',
|
||||||
|
],
|
||||||
|
|
||||||
|
'libs' => [
|
||||||
|
'toolbox' => [
|
||||||
|
'assertFieldIsUnique' => 'La :valeur du champ :attribut est déjà utilisée',
|
||||||
|
'assertNoInternalBoUrls' => ':attribute : Il est interdit de coller l\'uri de back-office dans ce champ',
|
||||||
|
'assertNoInternalUrls' => ':attribute : Il est interdit de coller une url de :appname dans ce champ.',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
'messages' => [
|
||||||
|
'has_been_created' => ':model a été créé',
|
||||||
|
'cannot_be_created' => ':model ne peut être créé',
|
||||||
|
'has_been_updated' => ':model a été mis à jour',
|
||||||
|
'cannot_be_updated' => ':model ne peut être mis à jour',
|
||||||
|
'has_been_deleted' => ':model a été supprimé',
|
||||||
|
'cannot_be_deleted' => ':model ne peut être supprimé',
|
||||||
|
'order_changed' => 'L\'ordre a été changé !',
|
||||||
|
'order_not_changed' => 'L\'ordre n\'a pas été changé !',
|
||||||
|
'publish_status_saved' => 'Changement de l\'état de publication réussit !',
|
||||||
|
'right' => 'Vous n\'avez pas les droits pour accéder à cette partie !'
|
||||||
|
],
|
||||||
|
|
||||||
|
'minicrud' => [
|
||||||
|
'visibility_label' => 'Visibilité',
|
||||||
|
'visibility_helper' => 'Vérifier qu\'il est visible.',
|
||||||
|
'enum_select' => 'Sélectionnez :enum dans la liste.',
|
||||||
|
'associated_enum' => 'Associé :enum',
|
||||||
|
'dimensions_must_be' => 'Doit être :widthpx (largeur) par :heightpx (hauteur).',
|
||||||
|
'picture_title_helper' => 'Utile pour les utilisateurs, s\'affiche en passant la souris sur l\'image',
|
||||||
|
'picture_title_label' => 'Attribut du titre de l\'image',
|
||||||
|
'picture_alt_helper' => 'Doit décrire votre image pour les moteurs de recherche et les aveugles (5 à 6 mots)',
|
||||||
|
'picture_alt_label' => 'Attribut Alt de l\'image',
|
||||||
|
'text_warning' => 'Relisez votre contenu avant de le publier',
|
||||||
|
],
|
||||||
|
|
||||||
|
'pagination' => [
|
||||||
|
"previous" => "Page précédente",
|
||||||
|
"next" => "Page suivante",
|
||||||
|
"specific_page" => "Accéder à la page n°:id",
|
||||||
|
'paginate_list' => 'Nombre d\'éléments par page',
|
||||||
|
],
|
||||||
|
|
||||||
|
'other' => [
|
||||||
|
'up' => 'Modifier l\'ordre d\'apparition vers le haut',
|
||||||
|
'down' => 'Modifier l\'ordre d\'apparition vers le bas',
|
||||||
|
'no_model_found' => 'Aucun :model trouvés',
|
||||||
|
'publish' => 'Publié',
|
||||||
|
'unpublish' => 'Dépublié',
|
||||||
|
'sort_ascending' => 'Trier :name dans l\'ordre croissant',
|
||||||
|
'sort_descending' => 'Trier :name dans l\'ordre décroissant',
|
||||||
|
'sort_delete' => 'Supprimer le tri',
|
||||||
|
'sort_arrow' => 'Ici, les flèches sont utilisées pour trier et non pour filtrer',
|
||||||
|
'right' => 'Vous n\'avez pas les droits',
|
||||||
|
]
|
||||||
|
];
|
||||||
84
resources/lang/fr/http-statuses.php
Normal file
84
resources/lang/fr/http-statuses.php
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'0' => 'Erreur inconnue',
|
||||||
|
'100' => 'Continuer',
|
||||||
|
'101' => 'Protocoles de commutation',
|
||||||
|
'102' => 'En traitement',
|
||||||
|
'200' => 'D\'accord',
|
||||||
|
'201' => 'Créé',
|
||||||
|
'202' => 'Accepté',
|
||||||
|
'203' => 'Informations non autorisées',
|
||||||
|
'204' => 'Pas content',
|
||||||
|
'205' => 'Réinitialiser le contenu',
|
||||||
|
'206' => 'Contenu partiel',
|
||||||
|
'207' => 'Multi-statut',
|
||||||
|
'208' => 'Déjà rapporté',
|
||||||
|
'226' => 'J\'ai l\'habitude',
|
||||||
|
'300' => 'Choix multiples',
|
||||||
|
'301' => 'Déplacé de façon permanente',
|
||||||
|
'302' => 'A trouvé',
|
||||||
|
'303' => 'Voir autre',
|
||||||
|
'304' => 'Non modifié',
|
||||||
|
'305' => 'Utiliser un proxy',
|
||||||
|
'307' => 'Redirection temporaire',
|
||||||
|
'308' => 'Redirection permanente',
|
||||||
|
'400' => 'Mauvaise Demande',
|
||||||
|
'401' => 'Non autorisé',
|
||||||
|
'402' => 'Paiement Requis',
|
||||||
|
'403' => 'Interdit',
|
||||||
|
'404' => 'Page non trouvée',
|
||||||
|
'405' => 'Méthode Non Autorisée',
|
||||||
|
'406' => 'Pas acceptable',
|
||||||
|
'407' => 'Authentification proxy requise',
|
||||||
|
'408' => 'Délai d\'expiration de la demande',
|
||||||
|
'409' => 'Conflit',
|
||||||
|
'410' => 'Disparu',
|
||||||
|
'411' => 'Longueur requise',
|
||||||
|
'412' => 'La précondition a échoué',
|
||||||
|
'413' => 'Charge utile trop grande',
|
||||||
|
'414' => 'URI trop long',
|
||||||
|
'415' => 'Type de support non supporté',
|
||||||
|
'416' => 'Plage non satisfaisante',
|
||||||
|
'417' => 'Échec de l\'attente',
|
||||||
|
'418' => 'Je suis une théière',
|
||||||
|
'419' => 'La session a expiré',
|
||||||
|
'421' => 'Demande mal dirigée',
|
||||||
|
'422' => 'Entité non traitable',
|
||||||
|
'423' => 'Fermé à clef',
|
||||||
|
'424' => 'Dépendance échouée',
|
||||||
|
'425' => 'Trop tôt',
|
||||||
|
'426' => 'Mise à niveau requise',
|
||||||
|
'428' => 'Condition préalable requise',
|
||||||
|
'429' => 'Trop de demandes',
|
||||||
|
'431' => 'Demander des champs d\'en-tête trop grands',
|
||||||
|
'444' => 'Connexion fermée sans réponse',
|
||||||
|
'449' => 'Réessayer avec',
|
||||||
|
'451' => 'Indisponible pour des raisons légales',
|
||||||
|
'499' => 'Demande fermée du client',
|
||||||
|
'500' => 'Erreur Interne du Serveur',
|
||||||
|
'501' => 'Pas mis en œuvre',
|
||||||
|
'502' => 'Mauvaise passerelle',
|
||||||
|
'503' => 'Mode de Maintenance',
|
||||||
|
'504' => 'Délai d\'attente de la passerelle',
|
||||||
|
'505' => 'Version HTTP non prise en charge',
|
||||||
|
'506' => 'La variante négocie également',
|
||||||
|
'507' => 'Espace insuffisant',
|
||||||
|
'508' => 'Boucle détectée',
|
||||||
|
'509' => 'Limite de bande passante dépassée',
|
||||||
|
'510' => 'Non prolongé',
|
||||||
|
'511' => 'Authentification réseau requise',
|
||||||
|
'520' => 'Erreur inconnue',
|
||||||
|
'521' => 'Le serveur Web est en panne',
|
||||||
|
'522' => 'La connexion a expiré',
|
||||||
|
'523' => 'L\'origine est inaccessible',
|
||||||
|
'524' => 'Un dépassement de délai s\'est produit',
|
||||||
|
'525' => 'Échec de la prise de contact SSL',
|
||||||
|
'526' => 'Certificat SSL invalide',
|
||||||
|
'527' => 'Erreur de canon ferroviaire',
|
||||||
|
'598' => 'Erreur de délai de lecture réseau',
|
||||||
|
'599' => 'Erreur de délai de connexion réseau',
|
||||||
|
'unknownError' => 'Erreur inconnue',
|
||||||
|
];
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
return [
|
return [
|
||||||
'classes' => [
|
'classes' => [
|
||||||
'products' => 'Produits',
|
'products' => 'Produits',
|
||||||
|
'products_monitoring' => 'Veille produit|Veilles produit',
|
||||||
'brands' => 'Marques',
|
'brands' => 'Marques',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
|
||||||
8
resources/lang/fr/pagination.php
Normal file
8
resources/lang/fr/pagination.php
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'next' => 'Suivant »',
|
||||||
|
'previous' => '« Précédent',
|
||||||
|
];
|
||||||
11
resources/lang/fr/passwords.php
Normal file
11
resources/lang/fr/passwords.php
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'reset' => 'Votre mot de passe a été réinitialisé !',
|
||||||
|
'sent' => 'Nous vous avons envoyé par email le lien de réinitialisation du mot de passe !',
|
||||||
|
'throttled' => 'Veuillez patienter avant de réessayer.',
|
||||||
|
'token' => 'Ce jeton de réinitialisation du mot de passe n\'est pas valide.',
|
||||||
|
'user' => 'Aucun utilisateur n\'a été trouvé avec cette adresse email.',
|
||||||
|
];
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'accepted' => 'Le champ :attribute doit être accepté.',
|
'accepted' => 'Le champ :attribute doit être accepté.',
|
||||||
'accepted_if' => 'Le champ :attribute doit être accepté quand :other a la valeur :value.',
|
'accepted_if' => 'Le champ :attribute doit être accepté quand :other a la valeur :value.',
|
||||||
|
|
@ -10,6 +12,7 @@ return [
|
||||||
'alpha_dash' => 'Le champ :attribute doit contenir uniquement des lettres, des chiffres et des tirets.',
|
'alpha_dash' => 'Le champ :attribute doit contenir uniquement des lettres, des chiffres et des tirets.',
|
||||||
'alpha_num' => 'Le champ :attribute doit contenir uniquement des chiffres et des lettres.',
|
'alpha_num' => 'Le champ :attribute doit contenir uniquement des chiffres et des lettres.',
|
||||||
'array' => 'Le champ :attribute doit être un tableau.',
|
'array' => 'Le champ :attribute doit être un tableau.',
|
||||||
|
'ascii' => 'Le champ :attribute ne doit contenir que des caractères alphanumériques et des symboles codés sur un octet.',
|
||||||
'before' => 'Le champ :attribute doit être une date antérieure au :date.',
|
'before' => 'Le champ :attribute doit être une date antérieure au :date.',
|
||||||
'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale au :date.',
|
'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale au :date.',
|
||||||
'between' => [
|
'between' => [
|
||||||
|
|
@ -19,11 +22,18 @@ return [
|
||||||
'string' => 'Le texte :attribute doit contenir entre :min et :max caractères.',
|
'string' => 'Le texte :attribute doit contenir entre :min et :max caractères.',
|
||||||
],
|
],
|
||||||
'boolean' => 'Le champ :attribute doit être vrai ou faux.',
|
'boolean' => 'Le champ :attribute doit être vrai ou faux.',
|
||||||
|
'can' => 'Le champ :attribute contient une valeur non autorisée.',
|
||||||
|
'color' => ':attribute doit être un code couleur valide (hexadecimal, RGB, RGBA ou un nom de couleur CSS)',
|
||||||
|
'color_hex' => ':attribute doit être un code couleur hexadecimal valide',
|
||||||
|
'color_name' => ':attribute doit être un nom de couleur CSS valide',
|
||||||
|
'color_rgb' => ':attribute doit être un code couleur RGB valide',
|
||||||
|
'color_rgba' => ':attribute doit être un code couleur RGBA valide',
|
||||||
'confirmed' => 'Le champ de confirmation :attribute ne correspond pas.',
|
'confirmed' => 'Le champ de confirmation :attribute ne correspond pas.',
|
||||||
'current_password' => 'Le mot de passe est incorrect.',
|
'current_password' => 'Le mot de passe est incorrect.',
|
||||||
'date' => 'Le champ :attribute n\'est pas une date valide.',
|
'date' => 'Le champ :attribute n\'est pas une date valide.',
|
||||||
'date_equals' => 'Le champ :attribute doit être une date égale à :date.',
|
'date_equals' => 'Le champ :attribute doit être une date égale à :date.',
|
||||||
'date_format' => 'Le champ :attribute ne correspond pas au format :format.',
|
'date_format' => 'Le champ :attribute ne correspond pas au format :format.',
|
||||||
|
'decimal' => 'Le champ :attribute doit comporter :decimal décimales.',
|
||||||
'declined' => 'Le champ :attribute doit être décliné.',
|
'declined' => 'Le champ :attribute doit être décliné.',
|
||||||
'declined_if' => 'Le champ :attribute doit être décliné quand :other a la valeur :value.',
|
'declined_if' => 'Le champ :attribute doit être décliné quand :other a la valeur :value.',
|
||||||
'different' => 'Les champs :attribute et :other doivent être différents.',
|
'different' => 'Les champs :attribute et :other doivent être différents.',
|
||||||
|
|
@ -31,6 +41,8 @@ return [
|
||||||
'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.',
|
'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.',
|
||||||
'dimensions' => 'La taille de l\'image :attribute n\'est pas conforme.',
|
'dimensions' => 'La taille de l\'image :attribute n\'est pas conforme.',
|
||||||
'distinct' => 'Le champ :attribute a une valeur en double.',
|
'distinct' => 'Le champ :attribute a une valeur en double.',
|
||||||
|
'doesnt_end_with' => 'Le champ :attribute ne doit pas finir avec une des valeurs suivantes : :values.',
|
||||||
|
'doesnt_start_with' => 'Le champ :attribute ne doit pas commencer avec une des valeurs suivantes : :values.',
|
||||||
'email' => 'Le champ :attribute doit être une adresse e-mail valide.',
|
'email' => 'Le champ :attribute doit être une adresse e-mail valide.',
|
||||||
'ends_with' => 'Le champ :attribute doit se terminer par une des valeurs suivantes : :values',
|
'ends_with' => 'Le champ :attribute doit se terminer par une des valeurs suivantes : :values',
|
||||||
'enum' => 'Le champ :attribute sélectionné est invalide.',
|
'enum' => 'Le champ :attribute sélectionné est invalide.',
|
||||||
|
|
@ -57,6 +69,7 @@ return [
|
||||||
'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.',
|
'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.',
|
||||||
'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.',
|
'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.',
|
||||||
'json' => 'Le champ :attribute doit être un document JSON valide.',
|
'json' => 'Le champ :attribute doit être un document JSON valide.',
|
||||||
|
'lowercase' => 'Le champ :attribute doit être en minuscules.',
|
||||||
'lt' => [
|
'lt' => [
|
||||||
'array' => 'Le tableau :attribute doit contenir moins de :value éléments.',
|
'array' => 'Le tableau :attribute doit contenir moins de :value éléments.',
|
||||||
'file' => 'La taille du fichier de :attribute doit être inférieure à :value kilo-octets.',
|
'file' => 'La taille du fichier de :attribute doit être inférieure à :value kilo-octets.',
|
||||||
|
|
@ -71,24 +84,39 @@ return [
|
||||||
],
|
],
|
||||||
'mac_address' => 'Le champ :attribute doit être une adresse MAC valide.',
|
'mac_address' => 'Le champ :attribute doit être une adresse MAC valide.',
|
||||||
'max' => [
|
'max' => [
|
||||||
'array' => 'Le tableau :attribute ne peut contenir plus de :max éléments.',
|
'array' => 'Le tableau :attribute ne peut pas contenir plus que :max éléments.',
|
||||||
'file' => 'La taille du fichier de :attribute ne peut pas dépasser :max kilo-octets.',
|
'file' => 'La taille du fichier de :attribute ne peut pas dépasser :max kilo-octets.',
|
||||||
'numeric' => 'La valeur de :attribute ne peut être supérieure à :max.',
|
'numeric' => 'La valeur de :attribute ne peut pas être supérieure à :max.',
|
||||||
'string' => 'Le texte de :attribute ne peut contenir plus de :max caractères.',
|
'string' => 'Le texte de :attribute ne peut pas contenir plus de :max caractères.',
|
||||||
],
|
],
|
||||||
|
'max_digits' => 'Le champ :attribute ne doit pas avoir plus de :max chiffres.',
|
||||||
'mimes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
'mimes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
||||||
'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
||||||
'min' => [
|
'min' => [
|
||||||
'array' => 'Le tableau :attribute doit contenir au moins :min éléments.',
|
'array' => 'Le tableau :attribute doit contenir au moins :min éléments.',
|
||||||
'file' => 'La taille du fichier de :attribute doit être supérieure à :min kilo-octets.',
|
'file' => 'La taille du fichier de :attribute doit être supérieure ou égale à :min kilo-octets.',
|
||||||
'numeric' => 'La valeur de :attribute doit être supérieure ou égale à :min.',
|
'numeric' => 'La valeur de :attribute doit être supérieure ou égale à :min.',
|
||||||
'string' => 'Le texte :attribute doit contenir au moins :min caractères.',
|
'string' => 'Le texte de :attribute doit contenir au moins :min caractères.',
|
||||||
],
|
],
|
||||||
|
'min_digits' => 'Le champ :attribute doit avoir au moins :min chiffres.',
|
||||||
|
'missing' => 'Le champ :attribute doit être manquant.',
|
||||||
|
'missing_if' => 'Le champ :attribute doit être manquant quand :other a la valeur :value.',
|
||||||
|
'missing_unless' => 'Le champ :attribute doit être manquant sauf si :other a la valeur :value.',
|
||||||
|
'missing_with' => 'Le champ :attribute doit être manquant quand :values est présent.',
|
||||||
|
'missing_with_all' => 'Le champ :attribute doit être manquant quand :values sont présents.',
|
||||||
'multiple_of' => 'La valeur de :attribute doit être un multiple de :value',
|
'multiple_of' => 'La valeur de :attribute doit être un multiple de :value',
|
||||||
'not_in' => 'Le champ :attribute sélectionné n\'est pas valide.',
|
'not_in' => 'Le champ :attribute sélectionné n\'est pas valide.',
|
||||||
'not_regex' => 'Le format du champ :attribute n\'est pas valide.',
|
'not_regex' => 'Le format du champ :attribute n\'est pas valide.',
|
||||||
'numeric' => 'Le champ :attribute doit contenir un nombre.',
|
'numeric' => 'Le champ :attribute doit contenir un nombre.',
|
||||||
'password' => 'Le mot de passe est incorrect',
|
'password' => [
|
||||||
|
'letters' => 'Le champ :attribute doit contenir au moins une lettre.',
|
||||||
|
'mixed' => 'Le champ :attribute doit contenir au moins une majuscule et une minuscule.',
|
||||||
|
'numbers' => 'Le champ :attribute doit contenir au moins un chiffre.',
|
||||||
|
'symbols' => 'Le champ :attribute doit contenir au moins un symbole.',
|
||||||
|
'uncompromised' => 'La valeur du champ :attribute est apparue dans une fuite de données. Veuillez choisir une valeur différente.',
|
||||||
|
],
|
||||||
|
'phone' => 'Le champ :attribute n\'est pas un numéro de téléphone valide.',
|
||||||
|
'postal_code' => 'Le champ :attribute accepte les codes postaux des pays suivants :countries comme par exemple :examples.',
|
||||||
'present' => 'Le champ :attribute doit être présent.',
|
'present' => 'Le champ :attribute doit être présent.',
|
||||||
'prohibited' => 'Le champ :attribute est interdit.',
|
'prohibited' => 'Le champ :attribute est interdit.',
|
||||||
'prohibited_if' => 'Le champ :attribute est interdit quand :other a la valeur :value.',
|
'prohibited_if' => 'Le champ :attribute est interdit quand :other a la valeur :value.',
|
||||||
|
|
@ -98,6 +126,7 @@ return [
|
||||||
'required' => 'Le champ :attribute est obligatoire.',
|
'required' => 'Le champ :attribute est obligatoire.',
|
||||||
'required_array_keys' => 'Le champ :attribute doit contenir des entrées pour : :values.',
|
'required_array_keys' => 'Le champ :attribute doit contenir des entrées pour : :values.',
|
||||||
'required_if' => 'Le champ :attribute est obligatoire quand la valeur de :other est :value.',
|
'required_if' => 'Le champ :attribute est obligatoire quand la valeur de :other est :value.',
|
||||||
|
'required_if_accepted' => 'Le champ :attribute est obligatoire quand le champ :other a été accepté.',
|
||||||
'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est :values.',
|
'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est :values.',
|
||||||
'required_with' => 'Le champ :attribute est obligatoire quand :values est présent.',
|
'required_with' => 'Le champ :attribute est obligatoire quand :values est présent.',
|
||||||
'required_with_all' => 'Le champ :attribute est obligatoire quand :values sont présents.',
|
'required_with_all' => 'Le champ :attribute est obligatoire quand :values sont présents.',
|
||||||
|
|
@ -113,16 +142,83 @@ return [
|
||||||
'starts_with' => 'Le champ :attribute doit commencer avec une des valeurs suivantes : :values',
|
'starts_with' => 'Le champ :attribute doit commencer avec une des valeurs suivantes : :values',
|
||||||
'string' => 'Le champ :attribute doit être une chaîne de caractères.',
|
'string' => 'Le champ :attribute doit être une chaîne de caractères.',
|
||||||
'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.',
|
'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.',
|
||||||
|
'ulid' => 'Le champ :attribute doit être un ULID valide.',
|
||||||
'unique' => 'La valeur du champ :attribute est déjà utilisée.',
|
'unique' => 'La valeur du champ :attribute est déjà utilisée.',
|
||||||
'uploaded' => 'Le fichier du champ :attribute n\'a pu être téléversé.',
|
'uploaded' => 'Le fichier du champ :attribute n\'a pu être téléversé.',
|
||||||
|
'uppercase' => 'Le champ :attribute doit être en majuscules.',
|
||||||
'url' => 'Le format de l\'URL de :attribute n\'est pas valide.',
|
'url' => 'Le format de l\'URL de :attribute n\'est pas valide.',
|
||||||
'uuid' => 'Le champ :attribute doit être un UUID valide',
|
'uuid' => 'Le champ :attribute doit être un UUID valide',
|
||||||
'custom' => [],
|
'attributes' => [
|
||||||
'phone' => 'Le champ :attribute n\'est pas un numéro de téléphone valide.',
|
'address' => 'adresse',
|
||||||
'color' => ':attribute doit être un code couleur valide (hexadecimal, RGB, RGBA ou un nom de couleur CSS)',
|
'age' => 'âge',
|
||||||
'color_hex' => ':attribute doit être un code couleur hexadecimal valide',
|
'amount' => 'montant',
|
||||||
'color_rgb' => ':attribute doit être un code couleur RGB valide',
|
'area' => 'zone',
|
||||||
'color_rgba' => ':attribute doit être un code couleur RGBA valide',
|
'available' => 'disponible',
|
||||||
'color_name' => ':attribute doit être un nom de couleur CSS valide',
|
'birthday' => 'anniversaire',
|
||||||
'postal_code' => 'Le champ :attribute accepte les codes postaux des pays suivants :countries comme par exemple :examples.'
|
'body' => 'corps',
|
||||||
|
'city' => 'ville',
|
||||||
|
'content' => 'contenu',
|
||||||
|
'country' => 'pays',
|
||||||
|
'created_at' => 'créé à',
|
||||||
|
'creator' => 'créateur',
|
||||||
|
'current_password' => 'mot de passe actuel',
|
||||||
|
'date' => 'Date',
|
||||||
|
'date_of_birth' => 'date de naissance',
|
||||||
|
'day' => 'jour',
|
||||||
|
'deleted_at' => 'supprimé à',
|
||||||
|
'description' => 'la description',
|
||||||
|
'district' => 'quartier',
|
||||||
|
'duration' => 'durée',
|
||||||
|
'email' => 'adresse e-mail',
|
||||||
|
'excerpt' => 'extrait',
|
||||||
|
'filter' => 'filtre',
|
||||||
|
'first_name' => 'prénom',
|
||||||
|
'gender' => 'genre',
|
||||||
|
'group' => 'groupe',
|
||||||
|
'hour' => 'heure',
|
||||||
|
'image' => 'image',
|
||||||
|
'last_name' => 'nom',
|
||||||
|
'lesson' => 'leçon',
|
||||||
|
'line_address_1' => 'ligne d\'adresse 1',
|
||||||
|
'line_address_2' => 'ligne d\'adresse 2',
|
||||||
|
'message' => 'message',
|
||||||
|
'middle_name' => 'deuxième prénom',
|
||||||
|
'minute' => 'minute',
|
||||||
|
'mobile' => 'portable',
|
||||||
|
'month' => 'mois',
|
||||||
|
'name' => 'nom',
|
||||||
|
'national_code' => 'code national',
|
||||||
|
'number' => 'numéro',
|
||||||
|
'password' => 'mot de passe',
|
||||||
|
'password_confirmation' => 'confirmation du mot de passe',
|
||||||
|
'phone' => 'téléphone',
|
||||||
|
'photo' => 'photo',
|
||||||
|
'postal_code' => 'code postal',
|
||||||
|
'price' => 'prix',
|
||||||
|
'province' => 'région',
|
||||||
|
'recaptcha_response_field' => 'champ de réponse recaptcha',
|
||||||
|
'remember' => 'se souvenir',
|
||||||
|
'restored_at' => 'restauré à',
|
||||||
|
'result_text_under_image' => 'texte de résultat sous l\'image',
|
||||||
|
'role' => 'rôle',
|
||||||
|
'second' => 'seconde',
|
||||||
|
'sex' => 'sexe',
|
||||||
|
'short_text' => 'texte court',
|
||||||
|
'size' => 'taille',
|
||||||
|
'state' => 'état',
|
||||||
|
'street' => 'rue',
|
||||||
|
'student' => 'étudiant',
|
||||||
|
'subject' => 'sujet',
|
||||||
|
'teacher' => 'professeur',
|
||||||
|
'terms' => 'conditions',
|
||||||
|
'test_description' => 'description test',
|
||||||
|
'test_locale' => 'localisation test',
|
||||||
|
'test_name' => 'nom test',
|
||||||
|
'text' => 'texte',
|
||||||
|
'time' => 'heure',
|
||||||
|
'title' => 'titre',
|
||||||
|
'updated_at' => 'mis à jour à',
|
||||||
|
'username' => 'nom d\'utilisateur',
|
||||||
|
'year' => 'année',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.bo-image-preview {
|
.bo-image-preview {
|
||||||
max-height: 60px;
|
// max-height: 60px;
|
||||||
|
width: 180px;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-ellipsis {
|
.text-ellipsis {
|
||||||
|
|
@ -13,9 +15,20 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-md {
|
||||||
|
min-width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
// Print fiche commerciale
|
// Print fiche commerciale
|
||||||
@media print {
|
@media print {
|
||||||
#print-id-product {
|
#print-id-product {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination-custom .dropdown-menu {
|
||||||
|
overflow: auto;
|
||||||
|
min-width: 5rem;
|
||||||
|
max-height: 178px;
|
||||||
|
}
|
||||||
|
|
|
||||||
263
resources/ts/components/BelongsToDropdown.vue
Normal file
263
resources/ts/components/BelongsToDropdown.vue
Normal file
|
|
@ -0,0 +1,263 @@
|
||||||
|
<template>
|
||||||
|
<div class="belongs-to-dropdown">
|
||||||
|
<label
|
||||||
|
:for="name"
|
||||||
|
class="col-form-label"
|
||||||
|
>
|
||||||
|
<b>{{ label }} {{ required ? "*" : "" }}</b>
|
||||||
|
</label>
|
||||||
|
<Transition name="fade">
|
||||||
|
<p
|
||||||
|
v-if="message"
|
||||||
|
class="message"
|
||||||
|
>
|
||||||
|
{{ message }}
|
||||||
|
</p>
|
||||||
|
</Transition>
|
||||||
|
<div class="d-inline-block tagInput w-100">
|
||||||
|
<VueTagsInputCls
|
||||||
|
v-model="item"
|
||||||
|
:tags="selectedItem"
|
||||||
|
:autocomplete-items="filteredItems"
|
||||||
|
:autocomplete-min-length="0"
|
||||||
|
:max-tags="1"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@before-adding-tag="beforeTagSave"
|
||||||
|
@tags-changed="changedTags"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-if="!selectedItem.length"
|
||||||
|
:name="name"
|
||||||
|
type="hidden"
|
||||||
|
value=""
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
v-for="(sItem, index) in selectedItem"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<p class="text-danger m-0">
|
||||||
|
{{ parseValidationInput(`${name}`, allErrors) }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:name="`${name}`"
|
||||||
|
type="hidden"
|
||||||
|
:value="sItem.id"
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||||
|
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
||||||
|
import axios from "axios";
|
||||||
|
import slugify from "slugify";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||||
|
import route from "./../modules/route";
|
||||||
|
import trans from "./../modules/trans";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name:"BelongsToDropdown",
|
||||||
|
mixins: [route, trans, parseLaravelErrorMessages],
|
||||||
|
components: {
|
||||||
|
VueTagsInputCls,
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
if (!this.$attrs.json) {
|
||||||
|
throw new Error("this component requires json");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const json = String(this.$attrs.json ?? "{}"),
|
||||||
|
data = JSON.parse(json);
|
||||||
|
this.name = data.name;
|
||||||
|
this.labelField = data.labelField;
|
||||||
|
this.label = data.label;
|
||||||
|
this.required = data.require;
|
||||||
|
this.allItems = (data.itemsList as CustomTag[]).map(item => {item.text = item[this.labelField] as string; return item;});
|
||||||
|
this.selectedItem = this.parseTags([data.value]);
|
||||||
|
this.intStoreRoute = data.storeRoute ?? null;
|
||||||
|
this.placeholder = data.placeholder;
|
||||||
|
},
|
||||||
|
data(): {
|
||||||
|
selectedItem: CustomTag[];
|
||||||
|
allItems: CustomTag[];
|
||||||
|
name: string;
|
||||||
|
item: string;
|
||||||
|
message: string | null;
|
||||||
|
intStoreRoute: string | null;
|
||||||
|
placeholder: string;
|
||||||
|
label: string;
|
||||||
|
required: boolean;
|
||||||
|
labelField: string;
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
allItems: [],
|
||||||
|
selectedItem: [],
|
||||||
|
item: "",
|
||||||
|
name: "",
|
||||||
|
message: null,
|
||||||
|
intStoreRoute: null,
|
||||||
|
placeholder: "",
|
||||||
|
label: "",
|
||||||
|
required: false,
|
||||||
|
labelField: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
parseTags(intSelectedItem: number[]): CustomTag[] {
|
||||||
|
const out: CustomTag[] = [];
|
||||||
|
if (intSelectedItem[0] !== null) {
|
||||||
|
intSelectedItem.forEach((intItem: number) => {
|
||||||
|
const selectedItem = this.allItems.find(item => String(item.id) === String(intItem));
|
||||||
|
if (!selectedItem) {
|
||||||
|
console.debug(intItem);
|
||||||
|
throw new Error(`Could not find enum ${intItem}`);
|
||||||
|
}
|
||||||
|
out.push({
|
||||||
|
id: String(selectedItem.id),
|
||||||
|
value: String(selectedItem.id),
|
||||||
|
text: String(selectedItem[`${this.labelField}`])
|
||||||
|
} as LaravelModel as CustomTag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
parseNewlyCreated(newModel: LaravelModel): CustomTag {
|
||||||
|
let newOut: CustomTag;
|
||||||
|
newOut = {
|
||||||
|
id: String(newModel.id),
|
||||||
|
value: String(newModel.id),
|
||||||
|
text: String(newModel[`${this.labelField}`])
|
||||||
|
} as LaravelModel as CustomTag;
|
||||||
|
return newOut;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Add item
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
beforeTagSave(obj: VueTagsInput.IAddArgs): void {
|
||||||
|
if (this.selectedItem.length < 1) {
|
||||||
|
let customTag = this.tagExists(this.allItems, obj.tag);
|
||||||
|
if (customTag) {
|
||||||
|
obj.tag = customTag;
|
||||||
|
this.selectedItem.push(customTag);
|
||||||
|
this.item = "";
|
||||||
|
return;
|
||||||
|
} else if (this.intStoreRoute !== null) {
|
||||||
|
const storeRoute = route.methods.route(this.intStoreRoute);
|
||||||
|
if (!storeRoute) {
|
||||||
|
throw new Error("Undefined route " + this.intStoreRoute);
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.post(storeRoute, {
|
||||||
|
name: obj.tag.text
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.data.status === true) {
|
||||||
|
this.item = "";
|
||||||
|
const brandItem = this.parseNewlyCreated(response.data.brand);
|
||||||
|
this.allItems.push(brandItem);
|
||||||
|
this.selectedItem.push(brandItem);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.message = this.__("Nombre d'élements maximal atteint.");
|
||||||
|
setTimeout(() => (this.message = null), 1500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tagExists(
|
||||||
|
items: Array<CustomTag>,
|
||||||
|
tagToCheck: VueTagsInput.ITag
|
||||||
|
): CustomTag | null {
|
||||||
|
let customTag: CustomTag | null = null;
|
||||||
|
items.filter((item: CustomTag) => {
|
||||||
|
if (
|
||||||
|
item.id === (tagToCheck as CustomTag).id ||
|
||||||
|
item.slug === slugify(tagToCheck.text)
|
||||||
|
) {
|
||||||
|
customTag = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return customTag;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete item.
|
||||||
|
* @param newItems
|
||||||
|
*/
|
||||||
|
changedTags(newItems: Array<CustomTag>): void {
|
||||||
|
this.selectedItem = newItems as Array<CustomTag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredItems() {
|
||||||
|
return this.allItems.filter((i) => {
|
||||||
|
return i.text.toLowerCase().indexOf(this.item.toLowerCase()) !== -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.vue-tags-input {
|
||||||
|
max-width: 100% !important;
|
||||||
|
.ti- {
|
||||||
|
&autocomplete {
|
||||||
|
max-height: 10rem !important;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0 4px var(--bs-gray-400);
|
||||||
|
overflow-y: auto !important;
|
||||||
|
ul {
|
||||||
|
padding: 0.25rem 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&input {
|
||||||
|
padding: 0.375rem !important;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
&tags {
|
||||||
|
line-height: inherit !important;
|
||||||
|
}
|
||||||
|
&tag,
|
||||||
|
&new-tag-input-wrapper {
|
||||||
|
padding: 0.1rem !important;
|
||||||
|
margin: 0.1rem !important;
|
||||||
|
}
|
||||||
|
&new-tag-input-wrapper {
|
||||||
|
font-size: 1em !important;
|
||||||
|
input {
|
||||||
|
min-width: 165px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&tag {
|
||||||
|
padding: 0.1rem 0.3rem !important;
|
||||||
|
background-color: var(--bs-blue) !important;
|
||||||
|
border-radius: 0.375rem !important;
|
||||||
|
}
|
||||||
|
&selected-item {
|
||||||
|
background-color: var(--bs-gray-300) !important;
|
||||||
|
color: var(--bs-gray-900) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -63,15 +63,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||||
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
||||||
|
import axios from "axios";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||||
import route from "./../modules/route";
|
import route from "./../modules/route";
|
||||||
import trans from "./../modules/trans";
|
import trans from "./../modules/trans";
|
||||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "BelongsToManyDropdown",
|
||||||
mixins: [route, trans, parseLaravelErrorMessages],
|
mixins: [route, trans, parseLaravelErrorMessages],
|
||||||
components: {
|
components: {
|
||||||
VueTagsInputCls,
|
VueTagsInputCls,
|
||||||
|
|
@ -88,6 +90,7 @@ export default defineComponent({
|
||||||
this.selectedItems = this.parseTags(data.value);
|
this.selectedItems = this.parseTags(data.value);
|
||||||
this.allItems = this.parseTags(data.itemsList);
|
this.allItems = this.parseTags(data.itemsList);
|
||||||
this.placeholder = data.placeholder;
|
this.placeholder = data.placeholder;
|
||||||
|
this.intStoreRoute = data.storeRoute ?? null;
|
||||||
// * Min and max calc.
|
// * Min and max calc.
|
||||||
this.min = Number.parseInt((data?.itemLimit ?? [])[0] ?? 0);
|
this.min = Number.parseInt((data?.itemLimit ?? [])[0] ?? 0);
|
||||||
this.min = this.min < 0 ? 0 : this.min;
|
this.min = this.min < 0 ? 0 : this.min;
|
||||||
|
|
@ -108,6 +111,7 @@ export default defineComponent({
|
||||||
waitingListObjects: Array<VueTagsInput.IAddArgs>;
|
waitingListObjects: Array<VueTagsInput.IAddArgs>;
|
||||||
allErrors: Record<string, Array<string>>;
|
allErrors: Record<string, Array<string>>;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
|
intStoreRoute: string | null;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
name: "",
|
name: "",
|
||||||
|
|
@ -121,6 +125,7 @@ export default defineComponent({
|
||||||
waitingListObjects: [],
|
waitingListObjects: [],
|
||||||
allErrors: {},
|
allErrors: {},
|
||||||
message: null,
|
message: null,
|
||||||
|
intStoreRoute: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -143,6 +148,23 @@ export default defineComponent({
|
||||||
this.selectedItems.push(customTag);
|
this.selectedItems.push(customTag);
|
||||||
this.item = "";
|
this.item = "";
|
||||||
return;
|
return;
|
||||||
|
} else if (this.intStoreRoute !== null) {
|
||||||
|
const storeBrandRoute = route.methods.route("brands.store");
|
||||||
|
if (!storeBrandRoute) {
|
||||||
|
throw new Error("Undefined route brands.store");
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.post(storeBrandRoute, {
|
||||||
|
name: obj.tag.text
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.data.status === true) {
|
||||||
|
obj.addTag();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.message = this.__("Nombre d'élements maximal atteint.");
|
this.message = this.__("Nombre d'élements maximal atteint.");
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,27 @@
|
||||||
>
|
>
|
||||||
<template v-if="intIsAdded">
|
<template v-if="intIsAdded">
|
||||||
<FontAwesomeIcon icon="fa-solid fa-minus" />
|
<FontAwesomeIcon icon="fa-solid fa-minus" />
|
||||||
|
|
||||||
|
<FontAwesomeIcon icon="fa-solid fa-file-pdf" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<FontAwesomeIcon icon="fa-solid fa-plus" />
|
<FontAwesomeIcon icon="fa-solid fa-plus" />
|
||||||
|
|
||||||
|
<FontAwesomeIcon icon="fa-solid fa-file-pdf" />
|
||||||
</template>
|
</template>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import trans from "./../modules/trans";
|
|
||||||
import route from "./../modules/route";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||||
import Tooltip from "bootstrap/js/dist/tooltip";
|
import Tooltip from "bootstrap/js/dist/tooltip";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import route from "./../modules/route";
|
||||||
|
import trans from "./../modules/trans";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "ButtonMultiPdfComponent",
|
||||||
mixins: [trans, route],
|
mixins: [trans, route],
|
||||||
components: {
|
components: {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
</label>
|
</label>
|
||||||
<img
|
<img
|
||||||
v-if="intValue"
|
v-if="intValue"
|
||||||
class="img-fluid"
|
class="img-fluid img-preview"
|
||||||
:src="intValue"
|
:src="intValue"
|
||||||
:alt="__('Image placeholder')"
|
:alt="__('Image placeholder')"
|
||||||
:aria-describedby="`PreviewHelp${intId}`"
|
:aria-describedby="`PreviewHelp${intId}`"
|
||||||
|
|
@ -400,10 +400,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||||
import Cropper from "cropperjs";
|
|
||||||
import { Tooltip } from "bootstrap";
|
import { Tooltip } from "bootstrap";
|
||||||
|
import Cropper from "cropperjs";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
import trans from "./../modules/trans";
|
import trans from "./../modules/trans";
|
||||||
|
|
||||||
const UNITS = [
|
const UNITS = [
|
||||||
|
|
@ -417,6 +417,7 @@ const UNITS = [
|
||||||
const BYTES_PER_KB = 1024;
|
const BYTES_PER_KB = 1024;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "ImageInputComponent",
|
||||||
mixins: [trans],
|
mixins: [trans],
|
||||||
emits: ["browseFile"],
|
emits: ["browseFile"],
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -952,6 +953,10 @@ export default defineComponent({
|
||||||
transform: translateX(-50%) translateY(-50%);
|
transform: translateX(-50%) translateY(-50%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.img-preview {
|
||||||
|
width: 180px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
.right-aligned {
|
.right-aligned {
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
direction: ltr !important;
|
direction: ltr !important;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import WordCounter from "./WordCounterComponent.vue";
|
||||||
const textarea = ref<HTMLTextAreaElement | null>(null);
|
const textarea = ref<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "InputTextAutoComponent",
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
mixins: [trans],
|
mixins: [trans],
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@
|
||||||
type="button"
|
type="button"
|
||||||
data-bs-toggle="collapse"
|
data-bs-toggle="collapse"
|
||||||
:data-bs-target="'#comment' + commentIndex"
|
:data-bs-target="'#comment' + commentIndex"
|
||||||
aria-expanded="false"
|
:aria-expanded="intModel.length > 0 ? true : false"
|
||||||
:aria-controls="'comment' + commentIndex"
|
:aria-controls="'comment' + commentIndex"
|
||||||
>
|
>
|
||||||
{{ __("Commentaire n°" + (commentIndex + 1)) }}
|
{{ __("Commentaire n°" + (commentIndex + 1)) }}
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
class="border collapse"
|
:class="`border collapse ${intModel.length > 0 ? 'show' : ''}`"
|
||||||
:id="'comment' + commentIndex"
|
:id="'comment' + commentIndex"
|
||||||
>
|
>
|
||||||
<div class="row w-100 mx-auto mb-3">
|
<div class="row w-100 mx-auto mb-3">
|
||||||
|
|
@ -53,14 +53,13 @@
|
||||||
class="col-form-label"
|
class="col-form-label"
|
||||||
for="commentEvaluation"
|
for="commentEvaluation"
|
||||||
>
|
>
|
||||||
<b>{{ __("Évaluation du produit") }} *</b>
|
<b>{{ __("Appréciation globale") }} *</b>
|
||||||
</label>
|
</label>
|
||||||
<InputTextAutoComponent
|
<InputTextAutoComponent
|
||||||
:id="'commentEvaluation' + commentIndex"
|
:id="'commentEvaluation' + commentIndex"
|
||||||
:name="'evaluation[' + commentIndex + ']'"
|
:name="'evaluation[' + commentIndex + ']'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:value="comment?.evaluation"
|
:value="comment?.evaluation"
|
||||||
:placeholder="__('Un peu caoutchouteux')"
|
|
||||||
:ariadescribedby="'productcommentEvaluation' + commentIndex"
|
:ariadescribedby="'productcommentEvaluation' + commentIndex"
|
||||||
/>
|
/>
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
|
|
@ -77,7 +76,7 @@
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
__(
|
__(
|
||||||
"Doit détailler l'évaluation du produit (3 caractères minimum, 255 maximum)."
|
"Doit détailler l'appéciation globale (3 caractères minimum, 255 maximum)."
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</small>
|
</small>
|
||||||
|
|
@ -94,7 +93,6 @@
|
||||||
:name="'aspect[' + commentIndex + ']'"
|
:name="'aspect[' + commentIndex + ']'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:value="comment?.aspect"
|
:value="comment?.aspect"
|
||||||
:placeholder="__('Un peu caoutchouteux')"
|
|
||||||
:ariadescribedby="'productcommentAspect' + commentIndex"
|
:ariadescribedby="'productcommentAspect' + commentIndex"
|
||||||
/>
|
/>
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
|
|
@ -128,7 +126,6 @@
|
||||||
:name="'taste[' + commentIndex + ']'"
|
:name="'taste[' + commentIndex + ']'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:value="comment?.taste"
|
:value="comment?.taste"
|
||||||
:placeholder="__('Un peu caoutchouteux')"
|
|
||||||
:ariadescribedby="'productcommentTaste' + commentIndex"
|
:ariadescribedby="'productcommentTaste' + commentIndex"
|
||||||
/>
|
/>
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
|
|
@ -162,7 +159,6 @@
|
||||||
:name="'odor[' + commentIndex + ']'"
|
:name="'odor[' + commentIndex + ']'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:value="comment?.odor"
|
:value="comment?.odor"
|
||||||
:placeholder="__('Un peu caoutchouteux')"
|
|
||||||
:ariadescribedby="'productcommentOdor' + commentIndex"
|
:ariadescribedby="'productcommentOdor' + commentIndex"
|
||||||
/>
|
/>
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
|
|
@ -196,7 +192,6 @@
|
||||||
:name="'texture[' + commentIndex + ']'"
|
:name="'texture[' + commentIndex + ']'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:value="comment?.texture"
|
:value="comment?.texture"
|
||||||
:placeholder="__('Un peu caoutchouteux')"
|
|
||||||
:ariadescribedby="'productCommentTexture' + commentIndex"
|
:ariadescribedby="'productCommentTexture' + commentIndex"
|
||||||
/>
|
/>
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
|
|
@ -227,11 +222,12 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import InputTextAutoComponent from "./InputTextAutoComponent.vue";
|
|
||||||
import parseLaravelErrorMessages from "../modules/parseLaravelErrorMessages";
|
import parseLaravelErrorMessages from "../modules/parseLaravelErrorMessages";
|
||||||
import trans from "../modules/trans";
|
import trans from "../modules/trans";
|
||||||
|
import InputTextAutoComponent from "./InputTextAutoComponent.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "MultipleCommentsComponent",
|
||||||
components: {
|
components: {
|
||||||
InputTextAutoComponent,
|
InputTextAutoComponent,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@
|
||||||
<div class="col-12 d-flex form-group">
|
<div class="col-12 d-flex form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<button
|
<button
|
||||||
@click.prevent="chooseFiles"
|
@click.prevent="($refs.actualDocuments as HTMLInputElement).click()"
|
||||||
class="btn btn-secondary"
|
class="btn btn-secondary"
|
||||||
type="button"
|
type="button"
|
||||||
:title="__('Modifier les documents sources')"
|
:title="__('Modifier les documents sources')"
|
||||||
data-bs-tooltip="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
:disabled="intValues.length >= intItemLimit[1]"
|
:disabled="intValues.length >= intItemLimit[1]"
|
||||||
>
|
>
|
||||||
<i class="fa-solid fa-folder-open" />
|
<i class="fa-solid fa-folder-open" />
|
||||||
|
|
@ -19,16 +19,16 @@
|
||||||
<input
|
<input
|
||||||
:id="intId"
|
:id="intId"
|
||||||
ref="actualDocuments"
|
ref="actualDocuments"
|
||||||
@change="changedDocuments"
|
@change="loadDocuments([].slice.call(($refs.actualDocuments as HTMLInputElement).files))"
|
||||||
type="file"
|
type="file"
|
||||||
class="d-none"
|
class="d-none"
|
||||||
name="multipleInputDocuments"
|
name="multipleInputDocuments"
|
||||||
accept=".pdf"
|
:accept="intAccepts"
|
||||||
:aria-describedby="`Help${intId}`"
|
:aria-describedby="`Help${intId}`"
|
||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@click.prevent="chooseFiles"
|
@click.prevent="($refs.actualDocuments as HTMLInputElement).click()"
|
||||||
type="text"
|
type="text"
|
||||||
:value="
|
:value="
|
||||||
'Actuellement ' +
|
'Actuellement ' +
|
||||||
|
|
@ -39,31 +39,18 @@
|
||||||
"
|
"
|
||||||
class="form-control right-aligned"
|
class="form-control right-aligned"
|
||||||
:title="__('Modifier les documents sources')"
|
:title="__('Modifier les documents sources')"
|
||||||
data-bs-tooltip="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
:aria-describedby="`Help${intId}`"
|
:aria-describedby="`Help${intId}`"
|
||||||
:disabled="intValues.length >= intItemLimit[1]"
|
:disabled="intValues.length >= intItemLimit[1]"
|
||||||
readonly
|
readonly
|
||||||
>
|
>
|
||||||
<button
|
|
||||||
class="btn btn-primary btn-collapse collapsed"
|
|
||||||
type="button"
|
|
||||||
:title="__('Rouler/Dérouler la liste des documents')"
|
|
||||||
data-bs-tooltip="tooltip"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#multiple-documents"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-controls="multiple-documents"
|
|
||||||
:disabled="!intHasDocuments"
|
|
||||||
>
|
|
||||||
<i class="fa fa-arrow-down" />
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
v-if="intValues.length > intItemLimit[0]"
|
v-if="intValues.length > intItemLimit[0]"
|
||||||
@click.prevent="removeFiles"
|
@click.prevent="removeFiles"
|
||||||
class="btn btn-danger"
|
class="btn btn-danger"
|
||||||
type="button"
|
type="button"
|
||||||
:title="__('Supprimer tous les documents')"
|
:title="__('Supprimer tous les documents')"
|
||||||
data-bs-tooltip="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
:disabled="intValues.length <= 0"
|
:disabled="intValues.length <= 0"
|
||||||
>
|
>
|
||||||
<i class="fas fa-eraser" />
|
<i class="fas fa-eraser" />
|
||||||
|
|
@ -72,146 +59,94 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End main buttons -->
|
<!-- End main buttons -->
|
||||||
<!-- Content collapse -->
|
<!-- Documents list -->
|
||||||
<div
|
<div
|
||||||
class="collapse"
|
v-for="(value, valueIndex) of intValues"
|
||||||
id="multiple-documents"
|
:key="valueIndex"
|
||||||
|
class="row w-100 mx-auto my-2"
|
||||||
>
|
>
|
||||||
<div class="row w-100 mx-auto my-2">
|
<div class="col-12 form-group text-center px-1">
|
||||||
<div
|
<div
|
||||||
v-for="n = 0 in intValues.length"
|
class="d-flex justify-content-between align-items-center pb-1"
|
||||||
:key="n"
|
:class="valueIndex != 1 ? 'border-top' : ''"
|
||||||
class="col-12 form-group text-center px-1"
|
|
||||||
>
|
>
|
||||||
<div
|
<label
|
||||||
class="d-flex justify-content-between align-items-center pb-1"
|
v-if="value"
|
||||||
:class="n != 1 ? 'border-top' : ''"
|
class="col-form-label d-flex"
|
||||||
>
|
>
|
||||||
<label
|
<span
|
||||||
v-if="intValues[n - 1]"
|
class="text-start text-ellipsis"
|
||||||
class="col-form-label d-flex"
|
v-if="intOriginalFileName[valueIndex]"
|
||||||
>
|
>
|
||||||
<span class="text-start text-ellipsis">
|
{{ intOriginalFileName[valueIndex].split('.').pop() }}
|
||||||
{{ intOriginalFileName[n - 1] }}
|
|
||||||
</span>
|
</span>
|
||||||
</label>
|
<span class="text-start text-ellipsis">
|
||||||
<small
|
{{ intOriginalFileName[valueIndex] }}
|
||||||
v-if="intValues[n - 1]"
|
</span>
|
||||||
:id="`PreviewHelp${intId}`"
|
</label>
|
||||||
class="form-text text-muted d-block m-0"
|
<small
|
||||||
>
|
v-if="value"
|
||||||
<span v-if="intOriginalFile[n - 1]">
|
:id="`PreviewHelp${intId}`"
|
||||||
{{ humanFileSize(intOriginalFile[n - 1].size) }}.
|
class="form-text text-muted d-block m-0"
|
||||||
</span>
|
|
||||||
</small>
|
|
||||||
<div class="input-group justify-content-center mt-1 w-auto">
|
|
||||||
<button
|
|
||||||
@click.prevent="viewDocumentSource(n - 1)"
|
|
||||||
class="btn btn-warning"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
:data-bs-target="`#modalViewer${intId}`"
|
|
||||||
:title="__('Afficher le document')"
|
|
||||||
data-bs-tooltip="tooltip"
|
|
||||||
>
|
|
||||||
<i class="fa-solid fa-eye" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click.prevent="chooseAFile(n - 1)"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
type="button"
|
|
||||||
:title="__('Modifier le document source')"
|
|
||||||
data-bs-tooltip="tooltip"
|
|
||||||
>
|
|
||||||
<i class="fa-solid fa-folder-open" />
|
|
||||||
</button>
|
|
||||||
<input
|
|
||||||
:id="intId"
|
|
||||||
ref="actualDocument"
|
|
||||||
@change="changedDocument($event, n - 1)"
|
|
||||||
type="file"
|
|
||||||
class="d-none"
|
|
||||||
:name="intName"
|
|
||||||
accept=".pdf"
|
|
||||||
:aria-describedby="`Help${intId}`"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-if="intValues.length > intItemLimit[0]"
|
|
||||||
@click.prevent="removeFile(n - 1)"
|
|
||||||
class="btn btn-danger"
|
|
||||||
type="button"
|
|
||||||
:title="__('Supprimer le document')"
|
|
||||||
data-bs-tooltip="tooltip"
|
|
||||||
>
|
|
||||||
<i class="fas fa-trash" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="text-danger m-0">
|
|
||||||
{{
|
|
||||||
parseValidationInput(
|
|
||||||
`${intName.replace(/[\[\]']+/g, "")}.${n - 1}`,
|
|
||||||
intAllErrors
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<!-- Viewer modal -->
|
|
||||||
<div
|
|
||||||
:id="`modalViewer${intId}`"
|
|
||||||
class="modal"
|
|
||||||
tabindex="-1"
|
|
||||||
role="dialog"
|
|
||||||
data-bs-backdrop="static"
|
|
||||||
data-bs-keyboard="false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="modal-dialog modal-xl d-flex align-items-center h-100 my-0 py-4"
|
|
||||||
>
|
>
|
||||||
<div class="modal-content h-100">
|
<span v-if="intOriginalFile[valueIndex]">
|
||||||
<div class="modal-header">
|
{{ humanFileSize(intOriginalFile[valueIndex].size) }}.
|
||||||
<h5 class="modal-title">
|
</span>
|
||||||
{{ __("Prévisualisation du document") }}
|
</small>
|
||||||
</h5>
|
<div class="input-group justify-content-center mt-1 w-auto">
|
||||||
<button
|
<button
|
||||||
@click.prevent="removeDocumentSource"
|
@click.prevent="viewDocumentSource(valueIndex)"
|
||||||
type="button"
|
class="btn btn-warning"
|
||||||
class="btn-close"
|
type="button"
|
||||||
data-bs-dismiss="modal"
|
:title="__('Afficher le document')"
|
||||||
:aria-label="__('Fermer la fenêtre')"
|
data-bs-toggle="tooltip"
|
||||||
:title="__('Fermer la fenêtre')"
|
>
|
||||||
data-bs-tooltip="tooltip"
|
<i class="fa-solid fa-eye" />
|
||||||
/>
|
</button>
|
||||||
</div>
|
<input
|
||||||
<div class="modal-body text-center">
|
:id="intId"
|
||||||
<div
|
ref="actualDocument"
|
||||||
v-if="intViewerLoadDocument"
|
@change="changedDocument(($refs.actualDocument as HTMLInputElement[])[valueIndex], valueIndex)"
|
||||||
class="text-center w-100 h-100"
|
type="file"
|
||||||
>
|
class="d-none"
|
||||||
<div
|
:name="intName.replace('[]', '') + `[${valueIndex}]`"
|
||||||
class="spinner-border text-secondary"
|
:accept="intAccepts"
|
||||||
role="status"
|
:aria-describedby="`Help${intId}`"
|
||||||
>
|
:disabled="intPreviousFiles.has(intOriginalFileName[valueIndex])"
|
||||||
<span class="visually-hidden">
|
>
|
||||||
{{ __("Chargement du document") }}
|
<input
|
||||||
</span>
|
@change="changedDocument(($refs.actualDocument as HTMLInputElement[])[valueIndex], valueIndex)"
|
||||||
</div>
|
type="text"
|
||||||
</div>
|
class="d-none"
|
||||||
<object
|
:name="intName.replace('[]', '') + `[${valueIndex}]`"
|
||||||
class="w-100 h-100"
|
:aria-describedby="`Help${intId}`"
|
||||||
:class="intViewerLoadDocument ? 'd-none' : ''"
|
:disabled="!intPreviousFiles.has(intOriginalFileName[valueIndex])"
|
||||||
type="application/pdf"
|
:value="intValues[valueIndex]"
|
||||||
data=""
|
>
|
||||||
ref="documentViewer"
|
<button
|
||||||
:title="__('Document enregistré')"
|
v-if="intValues.length > intItemLimit[0]"
|
||||||
/>
|
@click.prevent="removeFile(valueIndex)"
|
||||||
</div>
|
class="btn btn-danger"
|
||||||
</div>
|
type="button"
|
||||||
|
:title="__('Supprimer le document')"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
>
|
||||||
|
<i class="fas fa-trash" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-danger m-0">
|
||||||
|
{{
|
||||||
|
parseValidationInput(
|
||||||
|
`${intName.replace(/[\[\]']+/g, "")}.${n - 1}`,
|
||||||
|
intAllErrors
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End content collapse -->
|
<!-- End documents list -->
|
||||||
<small
|
<small
|
||||||
:id="`Help${intId}`"
|
:id="`Help${intId}`"
|
||||||
class="form-text text-muted"
|
class="form-text text-muted"
|
||||||
|
|
@ -223,7 +158,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import { Tooltip } from "bootstrap";
|
import bsTooltips from "./../modules/bsTooltips";
|
||||||
import error from "./../modules/parseLaravelErrorMessages";
|
import error from "./../modules/parseLaravelErrorMessages";
|
||||||
import trans from "./../modules/trans";
|
import trans from "./../modules/trans";
|
||||||
|
|
||||||
|
|
@ -238,38 +173,37 @@ const UNITS = [
|
||||||
const BYTES_PER_KB = 1024;
|
const BYTES_PER_KB = 1024;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [error, trans],
|
name: "MultipleDocumentsInputComponent",
|
||||||
|
mixins: [error, trans, bsTooltips],
|
||||||
|
components: {
|
||||||
|
},
|
||||||
data(): {
|
data(): {
|
||||||
|
/** The file ext accepted */
|
||||||
|
intAccepts: string;
|
||||||
|
/** The file ext accepted */
|
||||||
intId: string;
|
intId: string;
|
||||||
intName: string;
|
intName: string;
|
||||||
intHasDocument: boolean[];
|
intPreviousFiles: Set<string>;
|
||||||
intHasDocuments: boolean;
|
|
||||||
intOriginalFile: File[];
|
intOriginalFile: File[];
|
||||||
intOriginalFileName: string[];
|
intOriginalFileName: string[];
|
||||||
intValues: string[];
|
intValues: string[];
|
||||||
intHelper: string;
|
intHelper: string;
|
||||||
intTooltipList: HTMLButtonElement[];
|
intTooltipList: HTMLButtonElement[];
|
||||||
intBtnCollapse: HTMLButtonElement | null;
|
|
||||||
intLoopLoadDocuments: number;
|
|
||||||
intViewerLoadDocument: boolean;
|
intViewerLoadDocument: boolean;
|
||||||
intInputDocuments: HTMLInputElement[];
|
|
||||||
intItemLimit: number[];
|
intItemLimit: number[];
|
||||||
intAllErrors: Record<string, string[]>;
|
intAllErrors: Record<string, string[]>;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
|
intAccepts: ".xls,.csv,.xlsx,.png,.jpg,.jpeg,.gif,.doc,.docx,.ppt,.pdf,.txt",
|
||||||
intId: "",
|
intId: "",
|
||||||
intName: "",
|
intName: "",
|
||||||
intHasDocument: [],
|
intPreviousFiles: new Set<string>(),
|
||||||
intHasDocuments: false,
|
|
||||||
intOriginalFile: [],
|
intOriginalFile: [],
|
||||||
intOriginalFileName: [],
|
intOriginalFileName: [],
|
||||||
intValues: [],
|
intValues: [],
|
||||||
intHelper: "",
|
intHelper: "",
|
||||||
intBtnCollapse: null,
|
|
||||||
intTooltipList: [],
|
intTooltipList: [],
|
||||||
intLoopLoadDocuments: 0,
|
|
||||||
intViewerLoadDocument: false,
|
intViewerLoadDocument: false,
|
||||||
intInputDocuments: [],
|
|
||||||
intItemLimit: [0, 0],
|
intItemLimit: [0, 0],
|
||||||
intAllErrors: {},
|
intAllErrors: {},
|
||||||
};
|
};
|
||||||
|
|
@ -285,153 +219,87 @@ export default defineComponent({
|
||||||
this.intAllErrors = data.errors ?? {};
|
this.intAllErrors = data.errors ?? {};
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.initComponent();
|
this.initComponent();
|
||||||
this.updateBootstrapTooltip();
|
});
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.initTooltips();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
documentInputs(): HTMLInputElement[] {
|
||||||
|
return this.$refs.actualDocument as HTMLInputElement[];
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/** Initialize the component with previously documents registered. */
|
||||||
* Initialise the component with previously documents registered.
|
|
||||||
*/
|
|
||||||
initComponent() {
|
initComponent() {
|
||||||
if (this.intValues.length > 0) {
|
if (this.intValues.length > 0) {
|
||||||
this.intBtnCollapse = document.querySelector(
|
|
||||||
"[data-bs-target=\"#multiple-documents\"]"
|
|
||||||
);
|
|
||||||
this.intValues.forEach((element, index) => {
|
this.intValues.forEach((element, index) => {
|
||||||
element.charAt(0) != "/" ? "/".concat(element) : "";
|
element.charAt(0) != "/" ? "/".concat(element) : "";
|
||||||
this.intValues.splice(index, 1, element.replace(/^\/|^/, "/"));
|
this.intValues.splice(index, 1, element.replace(/^\/|^/, "/"));
|
||||||
});
|
});
|
||||||
this.intHasDocument = Array(this.intValues.length).fill(false);
|
|
||||||
this.intHasDocuments = true;
|
|
||||||
this.initDocumentsSaved();
|
this.initDocumentsSaved();
|
||||||
} else {
|
|
||||||
this.intHasDocuments = false;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/** Assign previously documents registered to respective input. */
|
||||||
* Assign previously documents registered to respective input.
|
|
||||||
*/
|
|
||||||
initDocumentsSaved() {
|
initDocumentsSaved() {
|
||||||
var actualDocuments = this.$refs.actualDocument as HTMLInputElement[];
|
|
||||||
this.intValues.forEach((element, index) => {
|
this.intValues.forEach((element, index) => {
|
||||||
|
const documentName = element.substring(element.lastIndexOf("/") + 1);
|
||||||
|
this.intPreviousFiles.add(documentName);
|
||||||
this.createFile(
|
this.createFile(
|
||||||
element,
|
element,
|
||||||
"document_" + (index + 1) + ".pdf",
|
`${documentName}`
|
||||||
"application/pdf"
|
|
||||||
).then((file: File) => {
|
).then((file: File) => {
|
||||||
const container = new DataTransfer();
|
const container = new DataTransfer();
|
||||||
container.items.add(file);
|
container.items.add(file);
|
||||||
actualDocuments[index].files = container.files;
|
this.documentInputs[index].files = container.files;
|
||||||
this.intOriginalFile[index] = container.files[0];
|
this.intOriginalFile[index] = container.files[0];
|
||||||
this.intOriginalFileName[index] = container.files[0].name;
|
this.intOriginalFileName[index] = container.files[0].name;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
/** Create a file from a path. */
|
||||||
* Create a file from a path.
|
async createFile(path: string, name: string): Promise<File> {
|
||||||
*/
|
const response = await fetch(
|
||||||
async createFile(path: string, name: string, type: string): Promise<File> {
|
|
||||||
let response = await fetch(
|
|
||||||
window.location.protocol + "//" + window.location.host + "/" + path
|
window.location.protocol + "//" + window.location.host + "/" + path
|
||||||
);
|
);
|
||||||
let data = await response.blob();
|
const data = await response.blob();
|
||||||
let metadata = {
|
const type = await response.headers.get("content-type") ?? "application/pdf";
|
||||||
|
const metadata = {
|
||||||
type: type,
|
type: type,
|
||||||
};
|
};
|
||||||
return new File([data], name, metadata);
|
return new File([data], name, metadata);
|
||||||
},
|
},
|
||||||
/**
|
/** Remove one specific document. */
|
||||||
* Update Bootstrap tooltips.
|
|
||||||
*/
|
|
||||||
updateBootstrapTooltip() {
|
|
||||||
let newTooltipList = [].slice.call(
|
|
||||||
document.querySelectorAll(
|
|
||||||
".multiple-documents-input-" +
|
|
||||||
this.intId +
|
|
||||||
" [data-bs-tooltip=\"tooltip\"]"
|
|
||||||
)
|
|
||||||
) as HTMLButtonElement[];
|
|
||||||
let tmp = newTooltipList.filter((x) => !this.intTooltipList.includes(x));
|
|
||||||
tmp.map((tooltip) => {
|
|
||||||
return new Tooltip(tooltip);
|
|
||||||
});
|
|
||||||
this.intTooltipList = newTooltipList;
|
|
||||||
this.closeBootstrapTooltip();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Close all Bootstrap tooltips.
|
|
||||||
*/
|
|
||||||
closeBootstrapTooltip() {
|
|
||||||
this.intTooltipList.forEach((tooltip) => {
|
|
||||||
tooltip.blur();
|
|
||||||
Tooltip.getInstance(tooltip)?.hide();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Link button change document to the input file document.
|
|
||||||
*/
|
|
||||||
chooseAFile(n: number) {
|
|
||||||
var actualDocuments = this.$refs.actualDocument as HTMLInputElement[],
|
|
||||||
actualDocument = actualDocuments[n] as HTMLInputElement;
|
|
||||||
actualDocument.click();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Link button change documents to the input file documents.
|
|
||||||
*/
|
|
||||||
chooseFiles() {
|
|
||||||
const actualDocuments = this.$refs.actualDocuments as HTMLInputElement;
|
|
||||||
actualDocuments.click();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Remove one specific document.
|
|
||||||
*/
|
|
||||||
removeFile(n: number) {
|
removeFile(n: number) {
|
||||||
|
if(this.intPreviousFiles.has(this.intOriginalFileName[n])) {
|
||||||
|
this.intPreviousFiles.delete(this.intOriginalFileName[n]);
|
||||||
|
}
|
||||||
this.intValues.splice(n, 1);
|
this.intValues.splice(n, 1);
|
||||||
this.intHasDocument.splice(n, 1);
|
|
||||||
this.intOriginalFile.splice(n, 1);
|
this.intOriginalFile.splice(n, 1);
|
||||||
this.intOriginalFileName.splice(n, 1);
|
this.intOriginalFileName.splice(n, 1);
|
||||||
if (this.intValues.length <= 0) {
|
this.documentInputs.forEach((element, index) => {
|
||||||
this.intHasDocuments = false;
|
|
||||||
}
|
|
||||||
this.intInputDocuments = this.$refs.actualDocument as HTMLInputElement[];
|
|
||||||
this.intInputDocuments.forEach((element, index) => {
|
|
||||||
if (this.intOriginalFile[index] != undefined) {
|
if (this.intOriginalFile[index] != undefined) {
|
||||||
var dt = new DataTransfer();
|
const dt = new DataTransfer();
|
||||||
dt.items.add(this.intOriginalFile[index]);
|
dt.items.add(this.intOriginalFile[index]);
|
||||||
element.files = dt.files;
|
element.files = dt.files;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.closeBootstrapTooltip();
|
this.$nextTick(() => this.initTooltips());
|
||||||
},
|
},
|
||||||
/**
|
/** Remove all documents. */
|
||||||
* Remove all documents.
|
|
||||||
*/
|
|
||||||
removeFiles() {
|
removeFiles() {
|
||||||
this.intValues.length = this.intItemLimit[0];
|
this.intValues.length = this.intItemLimit[0];
|
||||||
this.intHasDocument.length = this.intItemLimit[0];
|
|
||||||
this.intOriginalFile.length = this.intItemLimit[0];
|
this.intOriginalFile.length = this.intItemLimit[0];
|
||||||
this.intOriginalFileName.length = this.intItemLimit[0];
|
this.intOriginalFileName.length = this.intItemLimit[0];
|
||||||
this.intItemLimit[0] > 0
|
|
||||||
? (this.intHasDocuments = true)
|
|
||||||
: (this.intHasDocuments = false);
|
|
||||||
this.intAllErrors = {};
|
this.intAllErrors = {};
|
||||||
this.closeBootstrapTooltip();
|
this.$nextTick(() => this.initTooltips());
|
||||||
},
|
},
|
||||||
/**
|
/** Change one specific document. */
|
||||||
* Change one specific document.
|
changedDocument(el: HTMLInputElement, n: number) {
|
||||||
*/
|
|
||||||
changedDocument(e: Event, n: number) {
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
const el = e.target;
|
|
||||||
if (!el || !(el instanceof HTMLInputElement)) {
|
|
||||||
throw new Error(
|
|
||||||
"confirmDoneJS can only be executed on an exising form"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!el.files) {
|
if (!el.files) {
|
||||||
throw new Error();
|
throw new Error("No files");
|
||||||
}
|
}
|
||||||
this.intHasDocument[n] = true;
|
|
||||||
reader.addEventListener(
|
reader.addEventListener(
|
||||||
"load",
|
"load",
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -446,82 +314,35 @@ export default defineComponent({
|
||||||
reader.readAsDataURL(el.files[0]);
|
reader.readAsDataURL(el.files[0]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/** Update inputs file. */
|
||||||
* Add documents to exists document(s).
|
|
||||||
*/
|
|
||||||
changedDocuments(e: Event) {
|
|
||||||
const el = e.target;
|
|
||||||
if (!el || !(el instanceof HTMLInputElement)) {
|
|
||||||
throw new Error(
|
|
||||||
"confirmDoneJS can only be executed on an exising form"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!el.files) {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
this.intLoopLoadDocuments = this.intValues.length;
|
|
||||||
this.loadDocuments([].slice.call(el.files));
|
|
||||||
this.intHasDocuments = true;
|
|
||||||
if (this.intBtnCollapse?.classList.contains("collapsed")) {
|
|
||||||
this.intBtnCollapse?.click();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Update inputs file.
|
|
||||||
*/
|
|
||||||
loadDocuments(files: Array<File>) {
|
loadDocuments(files: Array<File>) {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
if (this.intValues.length + files.length <= this.intItemLimit[1]) {
|
if (this.intValues.length + files.length <= this.intItemLimit[1]) {
|
||||||
let actualFile = files.shift() as File;
|
const actualFile = files.shift() as File;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(actualFile);
|
reader.readAsDataURL(actualFile);
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
// On convertit l'document en une chaîne de caractères base64.
|
// On convertit l'document en une chaîne de caractères base64.
|
||||||
this.intValues.push(String(reader.result));
|
this.intValues.push(String(reader.result));
|
||||||
|
this.intOriginalFileName[this.intValues.length - 1] = "";
|
||||||
};
|
};
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
this.intInputDocuments = this.$refs
|
const dt = new DataTransfer();
|
||||||
.actualDocument as HTMLInputElement[];
|
|
||||||
var dt = new DataTransfer();
|
|
||||||
dt.items.add(actualFile);
|
dt.items.add(actualFile);
|
||||||
this.intInputDocuments[this.intLoopLoadDocuments].files = dt.files;
|
this.documentInputs[this.documentInputs.length - 1].files = dt.files;
|
||||||
this.intOriginalFile[this.intLoopLoadDocuments] = actualFile;
|
this.intOriginalFile[this.documentInputs.length - 1] = actualFile;
|
||||||
this.intHasDocument[this.intValues.length - 1] = true;
|
this.intOriginalFileName[this.documentInputs.length - 1] = actualFile.name;
|
||||||
this.intOriginalFileName[this.intValues.length - 1] =
|
|
||||||
actualFile.name;
|
|
||||||
this.intLoopLoadDocuments++;
|
|
||||||
this.loadDocuments(files);
|
this.loadDocuments(files);
|
||||||
|
this.initTooltips();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.updateBootstrapTooltip();
|
|
||||||
this.intLoopLoadDocuments = this.intValues.length;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/** Update document source in the viewer. */
|
||||||
* Update document source in the viewer.
|
|
||||||
*/
|
|
||||||
viewDocumentSource(n: number) {
|
viewDocumentSource(n: number) {
|
||||||
const documentViewer = this.$refs.documentViewer as HTMLObjectElement;
|
window.open(URL.createObjectURL(this.intOriginalFile[n]));
|
||||||
this.intViewerLoadDocument = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
documentViewer.data = this.intValues[n];
|
|
||||||
documentViewer.onload = () => {
|
|
||||||
this.intViewerLoadDocument = false;
|
|
||||||
};
|
|
||||||
}, 10);
|
|
||||||
},
|
},
|
||||||
/**
|
/** Get size of a file. */
|
||||||
* Remove document source in the viewer.
|
|
||||||
*/
|
|
||||||
removeDocumentSource() {
|
|
||||||
this.intViewerLoadDocument = true;
|
|
||||||
const documentViewer = this.$refs.documentViewer as HTMLObjectElement;
|
|
||||||
documentViewer.data = "";
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get size of a file.
|
|
||||||
*/
|
|
||||||
humanFileSize(sizeBytes: number | bigint): string {
|
humanFileSize(sizeBytes: number | bigint): string {
|
||||||
let size = Math.abs(Number(sizeBytes));
|
let size = Math.abs(Number(sizeBytes));
|
||||||
let u = 0;
|
let u = 0;
|
||||||
|
|
|
||||||
|
|
@ -33,25 +33,15 @@
|
||||||
<p class="text-danger m-0">
|
<p class="text-danger m-0">
|
||||||
{{
|
{{
|
||||||
parseValidationInput(
|
parseValidationInput(
|
||||||
`${intName}[${String(index)}][name]`,
|
`${intName}[${String(index)}]`,
|
||||||
intAllErrors
|
intAllErrors
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<input
|
<input
|
||||||
:name="`${intName}[${String(index)}][id]`"
|
:name="`${intName}[${String(index)}]`"
|
||||||
type="hidden"
|
type="hidden"
|
||||||
:value="sItem.id"
|
:value="sItem.value"
|
||||||
>
|
|
||||||
<input
|
|
||||||
:name="`${intName}[${String(index)}][value]`"
|
|
||||||
type="hidden"
|
|
||||||
:value="sItem.id"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
:name="`${intName}[${String(index)}][label]`"
|
|
||||||
type="hidden"
|
|
||||||
:value="sItem.text"
|
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
<small class="form-text text-muted">{{ intHelper }}</small>
|
<small class="form-text text-muted">{{ intHelper }}</small>
|
||||||
|
|
@ -82,15 +72,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||||
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||||
import route from "./../modules/route";
|
import route from "./../modules/route";
|
||||||
import trans from "./../modules/trans";
|
import trans from "./../modules/trans";
|
||||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "SelectMultipleEnumComponent",
|
||||||
mixins: [route, trans, parseLaravelErrorMessages],
|
mixins: [route, trans, parseLaravelErrorMessages],
|
||||||
components: {
|
components: {
|
||||||
VueTagsInputCls,
|
VueTagsInputCls,
|
||||||
|
|
@ -144,7 +135,7 @@ export default defineComponent({
|
||||||
this.intName = data.name;
|
this.intName = data.name;
|
||||||
this.intLabel = data.label;
|
this.intLabel = data.label;
|
||||||
this.intHelper = data.helper;
|
this.intHelper = data.helper;
|
||||||
this.intAllItems = this.parseTags(data.itemsList);
|
this.intAllItems = (data.itemsList as CustomTag[]).map(item => {item.text = item.label; return item;});
|
||||||
this.intSelectedItem = this.parseTags(data.itemsSelected);
|
this.intSelectedItem = this.parseTags(data.itemsSelected);
|
||||||
this.intPlaceholder = data.placeholder;
|
this.intPlaceholder = data.placeholder;
|
||||||
this.intItemLimit = data.itemLimit;
|
this.intItemLimit = data.itemLimit;
|
||||||
|
|
@ -155,18 +146,21 @@ export default defineComponent({
|
||||||
this.checkSpecificItem();
|
this.checkSpecificItem();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
parseTags(intSelectedItem: CustomTag[]): CustomTag[] {
|
parseTags(intSelectedItem: number[]): CustomTag[] {
|
||||||
return intSelectedItem.map((intItem: CustomTag) => {
|
const out: CustomTag[] = [];
|
||||||
if (!intItem.value)
|
intSelectedItem.forEach((intItem: number) => {
|
||||||
intItem = this.intAllItems
|
const selectedItem = this.intAllItems.find(item => String(item.id ?? item.value) === String(intItem));
|
||||||
.filter((intItemEnum) => {
|
if (!selectedItem) {
|
||||||
return intItemEnum.value == intItem.id;
|
console.debug(intItem);
|
||||||
})
|
throw new Error(`Could not find enum ${intItem}`);
|
||||||
.shift() as CustomTag;
|
}
|
||||||
intItem.id = String(intItem.value);
|
out.push({
|
||||||
intItem.text = String(intItem.label);
|
id: String(selectedItem.id ?? selectedItem.value),
|
||||||
return intItem;
|
value: String(selectedItem.value),
|
||||||
|
text: String(selectedItem.text)
|
||||||
|
} as LaravelModel as CustomTag);
|
||||||
});
|
});
|
||||||
|
return out;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Add item
|
* Add item
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,17 @@
|
||||||
class="form-select source-select"
|
class="form-select source-select"
|
||||||
:name="intName"
|
:name="intName"
|
||||||
:aria-describedby="`${intId}Help`"
|
:aria-describedby="`${intId}Help`"
|
||||||
@change="setSelectedValue()"
|
@change="setSelectedValue(0)"
|
||||||
>
|
>
|
||||||
|
<option
|
||||||
|
:value="null"
|
||||||
|
:selected="intSelectedValue === 0"
|
||||||
|
/>
|
||||||
<option
|
<option
|
||||||
v-for="(itemEnum, indexEnum) in intSourceEnum"
|
v-for="(itemEnum, indexEnum) in intSourceEnum"
|
||||||
:key="indexEnum"
|
:key="indexEnum"
|
||||||
:value="itemEnum.value"
|
:value="itemEnum.value"
|
||||||
:selected="itemEnum.value === intModel?.source"
|
:selected="itemEnum.value === intModel?.source || itemEnum.value === intSelectedValue "
|
||||||
>
|
>
|
||||||
{{ itemEnum.label }}
|
{{ itemEnum.label }}
|
||||||
</option>
|
</option>
|
||||||
|
|
@ -34,15 +38,15 @@
|
||||||
for="catalogue"
|
for="catalogue"
|
||||||
class="col-form-label"
|
class="col-form-label"
|
||||||
>
|
>
|
||||||
<b>{{ __("Détail de la source Catalogue") }} *</b>
|
<b>{{ __("Détail de la source Catalogue") }}</b>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
name="catalogue"
|
name="catalogue"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Nom du catalogue"
|
placeholder=""
|
||||||
list="productsCatalog"
|
list="productsCatalog"
|
||||||
:value="intModel?.catalogue"
|
:value="intModel?.catalogue ?? intOldDetails"
|
||||||
>
|
>
|
||||||
<datalist id="productsCatalog">
|
<datalist id="productsCatalog">
|
||||||
<option
|
<option
|
||||||
|
|
@ -69,15 +73,15 @@
|
||||||
for="shop"
|
for="shop"
|
||||||
class="col-form-label"
|
class="col-form-label"
|
||||||
>
|
>
|
||||||
<b>{{ __("Détail de la source Magasin") }} *</b>
|
<b>{{ __("Détail de la source Magasin") }}</b>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
name="shop"
|
name="shop"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Nom du magasin"
|
placeholder=""
|
||||||
list="productsShop"
|
list="productsShop"
|
||||||
:value="intModel?.shop"
|
:value="intModel?.shop ?? intOldDetails"
|
||||||
>
|
>
|
||||||
<datalist id="productsShop">
|
<datalist id="productsShop">
|
||||||
<option
|
<option
|
||||||
|
|
@ -104,15 +108,15 @@
|
||||||
for="salon"
|
for="salon"
|
||||||
class="col-form-label"
|
class="col-form-label"
|
||||||
>
|
>
|
||||||
<b>{{ __("Détail de la source Salon") }} *</b>
|
<b>{{ __("Détail de la source Salon") }}</b>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
name="fair"
|
name="fair"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Nom du salon"
|
placeholder=""
|
||||||
list="productsFair"
|
list="productsFair"
|
||||||
:value="intModel?.fair"
|
:value="intModel?.fair ?? intOldDetails"
|
||||||
>
|
>
|
||||||
<datalist id="productsFair">
|
<datalist id="productsFair">
|
||||||
<option
|
<option
|
||||||
|
|
@ -138,6 +142,7 @@ import { defineComponent } from "vue";
|
||||||
import trans from "../modules/trans";
|
import trans from "../modules/trans";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "SourceInputsComponent",
|
||||||
mixins: [trans],
|
mixins: [trans],
|
||||||
mounted() {
|
mounted() {
|
||||||
const json = String(this.$attrs.json ?? "{}");
|
const json = String(this.$attrs.json ?? "{}");
|
||||||
|
|
@ -151,7 +156,9 @@ export default defineComponent({
|
||||||
this.intProductsCatalog = data.productsCatalog;
|
this.intProductsCatalog = data.productsCatalog;
|
||||||
this.intSourceEnum = data.sourceEnum;
|
this.intSourceEnum = data.sourceEnum;
|
||||||
this.intHelper = data.helper;
|
this.intHelper = data.helper;
|
||||||
this.setSelectedValue();
|
this.intSelectedValue = data.oldValue;
|
||||||
|
this.intOldDetails = data.oldDetails;
|
||||||
|
this.setSelectedValue(data.oldValue);
|
||||||
},
|
},
|
||||||
data(): {
|
data(): {
|
||||||
intId: string;
|
intId: string;
|
||||||
|
|
@ -167,6 +174,7 @@ export default defineComponent({
|
||||||
intSourceMagazin: boolean;
|
intSourceMagazin: boolean;
|
||||||
intSourceShow: boolean;
|
intSourceShow: boolean;
|
||||||
intHelper: string;
|
intHelper: string;
|
||||||
|
intOldDetails: string;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
intId: "",
|
intId: "",
|
||||||
|
|
@ -182,18 +190,19 @@ export default defineComponent({
|
||||||
intSourceMagazin: false,
|
intSourceMagazin: false,
|
||||||
intSourceShow: false,
|
intSourceShow: false,
|
||||||
intHelper: "",
|
intHelper: "",
|
||||||
|
intOldDetails: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* Set selected source variables.
|
* Set selected source variables.
|
||||||
*/
|
*/
|
||||||
setSelectedValue() {
|
setSelectedValue(oldValue: number) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const select = document.querySelector(
|
const select = document.querySelector(
|
||||||
".source-select"
|
".source-select"
|
||||||
) as HTMLSelectElement;
|
) as HTMLSelectElement;
|
||||||
this.intSelectedValue = Number(select.value);
|
this.intSelectedValue = isNaN(Number(select.value)) ? Number(oldValue) : Number(select.value) ;
|
||||||
this.updateVue();
|
this.updateVue();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,11 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import MultipleCommentsComponent from "./MultipleCommentsComponent.vue";
|
|
||||||
import trans from "../modules/trans";
|
import trans from "../modules/trans";
|
||||||
|
import MultipleCommentsComponent from "./MultipleCommentsComponent.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "TastedProductComponent",
|
||||||
components: {
|
components: {
|
||||||
MultipleCommentsComponent,
|
MultipleCommentsComponent,
|
||||||
},
|
},
|
||||||
|
|
@ -150,6 +151,8 @@ export default defineComponent({
|
||||||
: false
|
: false
|
||||||
) {
|
) {
|
||||||
this.updateBoolean();
|
this.updateBoolean();
|
||||||
|
} else {
|
||||||
|
this.intIsTasted = data.oldCheck;
|
||||||
}
|
}
|
||||||
this.intCommentModel =
|
this.intCommentModel =
|
||||||
data.commentOldModel.length > 0
|
data.commentOldModel.length > 0
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
:name="intName"
|
:name="intName"
|
||||||
type="text"
|
type="text"
|
||||||
:value="intValue"
|
:value="intValue"
|
||||||
:placeholder="__('112233445566')"
|
placeholder=""
|
||||||
class="form-control input-gencode"
|
class="form-control input-gencode"
|
||||||
:class="[
|
:class="[
|
||||||
intResult != undefined ? [intResult ? 'is-invalid' : 'is-valid'] : '',
|
intResult != undefined ? [intResult ? 'is-invalid' : 'is-valid'] : '',
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
:maxlength="typeof intMaxlength != 'undefined' ? intMaxlength : ''"
|
:maxlength="typeof intMaxlength != 'undefined' ? intMaxlength : ''"
|
||||||
:required="!!intRequired"
|
:required="!!intRequired"
|
||||||
:disabled="!!intLoader"
|
:disabled="!!intLoader"
|
||||||
@keyup="checkGencode()"
|
@input="checkGencode()"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
v-if="intResult"
|
v-if="intResult"
|
||||||
|
|
@ -43,13 +43,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
|
||||||
import { Tooltip } from "bootstrap";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||||
|
import { Tooltip } from "bootstrap";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
import route from "./../modules/route";
|
import route from "./../modules/route";
|
||||||
import trans from "./../modules/trans";
|
import trans from "./../modules/trans";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "VerificationCodeComponent",
|
||||||
mixins: [route, trans],
|
mixins: [route, trans],
|
||||||
components: {
|
components: {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
|
|
@ -161,7 +162,7 @@ export default defineComponent({
|
||||||
this.intCode = inputCode.value;
|
this.intCode = inputCode.value;
|
||||||
window.axios
|
window.axios
|
||||||
.post(this.getRouteProductGencode(), {
|
.post(this.getRouteProductGencode(), {
|
||||||
GENCODE: this.intCode,
|
GENCOD: this.intCode,
|
||||||
ID: this.intModel?.id,
|
ID: this.intModel?.id,
|
||||||
})
|
})
|
||||||
.then((reponse) => {
|
.then((reponse) => {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { defineComponent } from "vue";
|
||||||
import trans from "../modules/trans";
|
import trans from "../modules/trans";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: "WordCounterComponent",
|
||||||
mixins: [trans],
|
mixins: [trans],
|
||||||
mounted() {
|
mounted() {
|
||||||
const json = String(this.$attrs.json ?? "{}");
|
const json = String(this.$attrs.json ?? "{}");
|
||||||
|
|
|
||||||
6
resources/ts/index.d.ts
vendored
6
resources/ts/index.d.ts
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
export {};
|
export { };
|
||||||
|
|
||||||
import { AxiosStatic } from "axios";
|
|
||||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||||
|
import { AxiosStatic } from "axios";
|
||||||
|
|
||||||
// * Recursive List<string>
|
// * Recursive List<string>
|
||||||
type StringList = Record<PropertyKey, string>;
|
type StringList = Record<PropertyKey, string>;
|
||||||
|
|
@ -30,7 +30,7 @@ type NestedNumberList = NestedNumberListInterface | NumberList | number;
|
||||||
type ModelList = Array<Model>;
|
type ModelList = Array<Model>;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
type CustomTag = LaravelModel & VueTagsInput.ITag;
|
type CustomTag = LaravelModel & VueTagsInput.ITag & {name:string,label:string, value:number|string};
|
||||||
type LaravelModel = Model;
|
type LaravelModel = Model;
|
||||||
type LaravelModelList = ModelList;
|
type LaravelModelList = ModelList;
|
||||||
|
|
||||||
|
|
|
||||||
27
resources/ts/modules/bsTooltips.ts
Normal file
27
resources/ts/modules/bsTooltips.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Tooltip } from "bootstrap";
|
||||||
|
|
||||||
|
let tooltips: Array<bootstrap.Tooltip> = [];
|
||||||
|
|
||||||
|
/** ! Ignore here because there is no good TS vue mixin implementation at this time */
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
initTooltips() {
|
||||||
|
// Disable tooltips on reboot.
|
||||||
|
tooltips.forEach((tooltip) => {
|
||||||
|
tooltip.disable();
|
||||||
|
tooltip.hide();
|
||||||
|
});
|
||||||
|
tooltips = [].slice
|
||||||
|
.call(document.querySelectorAll("[data-bs-toggle=\"tooltip\"]"))
|
||||||
|
.map(function (tooltipTriggerEl) {
|
||||||
|
return new Tooltip(tooltipTriggerEl, {
|
||||||
|
customClass: "large-tooltip",
|
||||||
|
delay: {
|
||||||
|
show: 1250,
|
||||||
|
hide: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -1,42 +1,49 @@
|
||||||
import { dom, library, config } from "~/@fortawesome/fontawesome-svg-core";
|
import { config, dom, library } from "~/@fortawesome/fontawesome-svg-core";
|
||||||
import {
|
import {
|
||||||
faEraser,
|
faAnglesRight,
|
||||||
faArrowLeftLong,
|
|
||||||
faPlus,
|
|
||||||
faMinus,
|
|
||||||
faTrash,
|
|
||||||
faEye,
|
|
||||||
faFolderOpen,
|
|
||||||
faCrop,
|
|
||||||
faQuestionCircle,
|
|
||||||
faCheck,
|
|
||||||
faUndoAlt,
|
|
||||||
faRedoAlt,
|
|
||||||
faSyncAlt,
|
|
||||||
faSearchPlus,
|
|
||||||
faSearchMinus,
|
|
||||||
faArrowLeft,
|
|
||||||
faArrowRight,
|
|
||||||
faArrowUp,
|
|
||||||
faArrowDown,
|
|
||||||
faArrowsAltH,
|
|
||||||
faArrowsAltV,
|
|
||||||
faWandMagic,
|
|
||||||
faPencil,
|
|
||||||
faTimes,
|
|
||||||
faBackspace,
|
|
||||||
faSearch,
|
|
||||||
faArrowRightFromBracket,
|
|
||||||
faArrowAltCircleDown,
|
faArrowAltCircleDown,
|
||||||
faArrowAltCircleUp,
|
faArrowAltCircleUp,
|
||||||
faQuestion,
|
faArrowDown,
|
||||||
faXmark,
|
faArrowLeft,
|
||||||
|
faArrowLeftLong,
|
||||||
|
faArrowRight,
|
||||||
|
faArrowRightFromBracket,
|
||||||
|
faArrowUp,
|
||||||
|
faArrowsAltH,
|
||||||
|
faArrowsAltV,
|
||||||
|
faBackspace,
|
||||||
|
faCheck,
|
||||||
|
faChevronLeft,
|
||||||
|
faChevronRight,
|
||||||
|
faCircleNotch,
|
||||||
faCopy,
|
faCopy,
|
||||||
faFile,
|
faCrop,
|
||||||
faLink,
|
|
||||||
faPrint,
|
|
||||||
faImage,
|
|
||||||
faDownload,
|
faDownload,
|
||||||
|
faEraser,
|
||||||
|
faEye,
|
||||||
|
faFile,
|
||||||
|
faFilePdf,
|
||||||
|
faFolderOpen,
|
||||||
|
faHeading,
|
||||||
|
faImage,
|
||||||
|
faLink,
|
||||||
|
faListUl,
|
||||||
|
faMinus,
|
||||||
|
faPencil,
|
||||||
|
faPlus,
|
||||||
|
faPrint,
|
||||||
|
faQuestion,
|
||||||
|
faQuestionCircle,
|
||||||
|
faRedoAlt,
|
||||||
|
faSearch,
|
||||||
|
faSearchMinus,
|
||||||
|
faSearchPlus,
|
||||||
|
faSyncAlt,
|
||||||
|
faTimes,
|
||||||
|
faTrash,
|
||||||
|
faUndoAlt,
|
||||||
|
faWandMagic,
|
||||||
|
faXmark,
|
||||||
} from "~/@fortawesome/free-solid-svg-icons";
|
} from "~/@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
config.autoReplaceSvg = false;
|
config.autoReplaceSvg = false;
|
||||||
|
|
@ -77,5 +84,12 @@ library.add(faLink);
|
||||||
library.add(faPrint);
|
library.add(faPrint);
|
||||||
library.add(faImage);
|
library.add(faImage);
|
||||||
library.add(faDownload);
|
library.add(faDownload);
|
||||||
|
library.add(faFilePdf);
|
||||||
|
library.add(faListUl);
|
||||||
|
library.add(faHeading);
|
||||||
|
library.add(faAnglesRight);
|
||||||
|
library.add(faChevronLeft);
|
||||||
|
library.add(faChevronRight);
|
||||||
|
library.add(faCircleNotch);
|
||||||
|
|
||||||
dom.watch();
|
dom.watch();
|
||||||
|
|
|
||||||
|
|
@ -5,109 +5,119 @@
|
||||||
{{-- CONTENT --}}
|
{{-- CONTENT --}}
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="table-cell-text-center" width="30%">
|
@if (isset($product->picture) && !empty($product->picture))
|
||||||
@if (isset($product->picture))
|
<td class="table-cell-text-center" width="30%">
|
||||||
<img src="{{ public_path($product->picture) }}" alt="{{ $product->picture_alt }}" alt="{{ $product->picture_title }}">
|
<img src="{{ public_path($product->picture) }}" alt="{{ $product->picture_alt }}" alt="{{ $product->picture_title }}">
|
||||||
@endif
|
</td>
|
||||||
</td>
|
<td width="70%">
|
||||||
<td width="70%">
|
@else
|
||||||
@if (isset($product->brand_id->name))
|
<td width="100%">
|
||||||
<h2><strong>{{ __('Marque du produit : ') }}</strong><span>{{ $product->brand_id->name }}</span></h2>
|
@endif
|
||||||
@endif
|
<h2><strong>{{ __('Marque du produit : ') }}</strong><span>{{ $product->brand->name }}</span></h2>
|
||||||
@if (isset($product->name))
|
<h2><strong>{{ __('Nom du produit : ') }}</strong><span>{{ $product->name }}</span></h2>
|
||||||
<h2><strong>{{ __('Nom du produit : ') }}</strong><span>{{ $product->name }}</span></h2>
|
@if (isset($product->certification))
|
||||||
@endif
|
|
||||||
@if (isset($product->certification))
|
|
||||||
<p><strong>{{ __('Certification : ') }}</strong>{{ $product->certification }}</p>
|
<p><strong>{{ __('Certification : ') }}</strong>{{ $product->certification }}</p>
|
||||||
|
@endif
|
||||||
|
<p><strong>{{ __('Origines : ') }}</strong>{{ $product->origins }}</p>
|
||||||
|
<p><strong>{{ __('Allégations : ') }}</strong>
|
||||||
|
@php
|
||||||
|
$claims = Str::of($product->claims)->explode(', ');
|
||||||
|
$claimOthers = \App\Enums\Products\ClaimEnum::others->label();
|
||||||
|
@endphp
|
||||||
|
@if ($claims->contains($claimOthers))
|
||||||
|
@php
|
||||||
|
$product->claims = $claims->except(array_search('Autres', $claims->toArray()))->implode(', ');
|
||||||
|
@endphp
|
||||||
|
{{ $product->claims }}, {{ $claimOthers}}
|
||||||
|
@if ($product->specified_claim)
|
||||||
|
: {{ $product->specified_claim }}
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
{{ $product->claims }}
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->origins))
|
</p>
|
||||||
<p><strong>{{ __('Origines : ') }}</strong>{{ $product->origins }}</p>
|
<table class="table" width="100%">
|
||||||
@endif
|
<tr class="table-header">
|
||||||
@if (isset($product->claims))
|
@if (isset($product->gencod))
|
||||||
<p><strong>{{ __('Allégations : ') }}</strong>{{ $product->claims }}</p>
|
|
||||||
@endif
|
|
||||||
<table class="table" width="100%">
|
|
||||||
<tr class="table-header">
|
|
||||||
@if (isset($product->gencod))
|
|
||||||
<td class="table-cell-text-center"><strong>{{ __('GENCOD') }}</strong></td>
|
<td class="table-cell-text-center"><strong>{{ __('GENCOD') }}</strong></td>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->weight))
|
@if (isset($product->weight))
|
||||||
<td class="table-cell-text-center"><strong>{{ __('Poids UVC') }}</strong></td>
|
<td class="table-cell-text-center"><strong>{{ __('Poids UVC') }}</strong></td>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->pvc))
|
@if (isset($product->pvc))
|
||||||
<td class="table-cell-text-center"><strong>{{ __('PVC') }}</strong></td>
|
<td class="table-cell-text-center"><strong>{{ __('PVC') }}</strong></td>
|
||||||
@endif
|
@endif
|
||||||
<td class="table-cell-text-center"><strong>{{ __('Prix kg') }}</strong></td>
|
<td class="table-cell-text-center"><strong>{{ __('Prix kg') }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="table-body">
|
<tr class="table-body">
|
||||||
@if (isset($product->gencod))
|
@if (isset($product->gencod))
|
||||||
<td class="table-cell-text-center">{{ $product->gencod }}</td>
|
<td class="table-cell-text-center">{{ $product->gencod }}</td>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->weight))
|
@if (isset($product->weight))
|
||||||
<td class="table-cell-text-center">{{ $product->weight }}</td>
|
<td class="table-cell-text-center">{{ $product->weight }} g</td>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->pvc))
|
@if (isset($product->pvc))
|
||||||
<td class="table-cell-text-center">{{ $product->pvc }}€</td>
|
<td class="table-cell-text-center">{{ $product->pvc }}€</td>
|
||||||
@endif
|
@endif
|
||||||
<td class="table-cell-text-center">--,--€</td>
|
@php
|
||||||
</tr>
|
$priceKg = $product->weight ? (1000 * $product->pvc) / $product->weight : 0;
|
||||||
</table>
|
@endphp
|
||||||
@if (isset($product->productKeywords))
|
<td class="table-cell-text-center">{{ number_format(round($priceKg, 2), 2, ',', ' ') }}€</td>
|
||||||
<p><strong>{{ __('Tendances identifiées : ') }}</strong>{{ $product->productKeywords }}</p>
|
</tr>
|
||||||
@endif
|
</table>
|
||||||
@if (isset($product->distribution_network))
|
@if (isset($product->productKeywords))
|
||||||
|
<p><strong>{{ __('Tendances identifiées : ') }}</strong>{{ Str::replaceLast(', ', '', $product->productKeywords) }}</p>
|
||||||
|
@endif
|
||||||
|
@if (isset($product->distribution_network))
|
||||||
<p><strong>{{ __('Réseau de distribution : ') }}</strong>{{ $product->distribution_network }}</p>
|
<p><strong>{{ __('Réseau de distribution : ') }}</strong>{{ $product->distribution_network }}</p>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->ray))
|
@if (isset($product->ray))
|
||||||
<p><strong>{{ __('Rayon : ') }}</strong>{{ $product->ray }}</p>
|
<p><strong>{{ __('Rayon : ') }}</strong>{{ $product->ray }}</p>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->product_range))
|
@if (isset($product->product_range))
|
||||||
<p><strong>{{ __('Famille : ') }}</strong>{{ $product->product_range }}</p>
|
<p><strong>{{ __('Famille : ') }}</strong>{{ $product->product_range }}</p>
|
||||||
@endif
|
@endif
|
||||||
@if (isset($product->geo_area))
|
@if (isset($product->geo_area))
|
||||||
<p><strong>{{ __('Zone géographique : ') }}</strong>{{ $product->geo_area }}</p>
|
<p><strong>{{ __('Zone géographique : ') }}</strong>{{ $product->geo_area }}</p>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@if (isset($product->freeComment))
|
@if (isset($product->freeComment))
|
||||||
<p><strong>{{ __('Commentaire libre : ') }}</strong>{{ strip_tags($product->freeComment) }}</p>
|
<p><strong>{{ __('Commentaire libre : ') }}</strong>{{ strip_tags($product->freeComment) }}</p>
|
||||||
@endif
|
@endif
|
||||||
@if(isset($product->productComments))
|
|
||||||
@foreach ($product->productComments as $productComment)
|
@foreach ($product->productComments as $productComment)
|
||||||
<p><strong>{{ __('Commentaire dégustation du : ') }}</strong>{{ $productComment->date }}</p>
|
<p><strong>{{ __('Commentaire dégustation du : ') }}</strong>{{ $productComment->created_at }}</p>
|
||||||
<table class="table" width="100%">
|
<table class="table" width="100%">
|
||||||
<tr class="table-header">
|
<tr class="table-header">
|
||||||
<td class="table-cell-text-center" width="20%"><strong>{{ __('Appréciation') }}</strong></td>
|
<td class="table-cell-text-center" width="20%"><strong>{{ __('Appréciation') }}</strong></td>
|
||||||
<td class="table-cell-text-center" width="20%"><strong>{{ __('Aspect') }}</strong></td>
|
<td class="table-cell-text-center" width="20%"><strong>{{ __('Aspect') }}</strong></td>
|
||||||
<td class="table-cell-text-center" width="20%"><strong>{{ __('Odeur') }}</strong></td>
|
<td class="table-cell-text-center" width="20%"><strong>{{ __('Odeur') }}</strong></td>
|
||||||
<td class="table-cell-text-center" width="20%"><strong>{{ __('Texture') }}</strong></td>
|
<td class="table-cell-text-center" width="20%"><strong>{{ __('Texture') }}</strong></td>
|
||||||
<td class="table-cell-text-center" width="20%"><strong>{{ __('Goût') }}</strong></td>
|
<td class="table-cell-text-center" width="20%"><strong>{{ __('Goût') }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="table-body">
|
<tr class="table-body">
|
||||||
<td class="table-cell-text-center" width="20%">{{ $productComment->evaluation }}</td>
|
<td class="table-cell-text-center" width="20%">{{ $productComment->evaluation }}</td>
|
||||||
<td class="table-cell-text-center" width="20%">{{ $productComment->aspect }}</td>
|
<td class="table-cell-text-center" width="20%">{{ $productComment->aspect }}</td>
|
||||||
<td class="table-cell-text-center" width="20%">{{ $productComment->taste }}</td>
|
<td class="table-cell-text-center" width="20%">{{ $productComment->taste }}</td>
|
||||||
<td class="table-cell-text-center" width="20%">{{ $productComment->odor }}</td>
|
<td class="table-cell-text-center" width="20%">{{ $productComment->odor }}</td>
|
||||||
<td class="table-cell-text-center" width="20%">{{ $productComment->texture }}</td>
|
<td class="table-cell-text-center" width="20%">{{ $productComment->texture }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
<table class="product-saw" width="100%">
|
||||||
<table width="100%" class="product-saw">
|
|
||||||
<tr>
|
<tr>
|
||||||
@if (isset($product->seen_at))
|
|
||||||
<td class="table-cell-text-center" width="50%">
|
<td class="table-cell-text-center" width="50%">
|
||||||
<strong>{{ __('Téléchargez les documents :') }}</strong>
|
<strong>{{ __('Téléchargez les documents :') }}</strong>
|
||||||
<a href="{{ route('products.download', $product->id) }}">{{ __('ICI') }}</a>
|
<a href="{{ route('products.download', $product->id) }}">{{ __('ICI') }}</a>
|
||||||
</td>
|
</td>
|
||||||
@endif
|
|
||||||
@if (isset($product->source))
|
@if (isset($product->source))
|
||||||
<td class="table-cell-text-center" width="50%">
|
<td class="table-cell-text-center" width="50%">
|
||||||
<p><strong>{{ __('Vu le : ') }}</strong>{{ $product->seen_at }}</p>
|
<p><strong>{{ __('Vu le : ') }}</strong>{{ $product->seen_at }}</p>
|
||||||
<p><strong>{{ __('Lieu : ') }}</strong>{{ $product->source }}, {{ $product->fair }}{{ $product->shop }}{{ $product->catalogue }}</p>
|
<p><strong>{{ __('Lieu : ') }}</strong>{{ $product->source }}, {{ $product->fair }}{{ $product->shop }}{{ $product->catalogue }}
|
||||||
<p><strong>{{ __('Par : ') }}</strong>{{ $product->user_id->firstname }} {{ $product->user_id->lastname }}</p>
|
</p>
|
||||||
</td>
|
<p><strong>{{ __('Par : ') }}</strong>{{ $product->user->firstname }} {{ $product->user->lastname }}</p>
|
||||||
|
</td>
|
||||||
@endif
|
@endif
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
text-transform: uppercase;
|
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,11 +60,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-header {
|
.table-header {
|
||||||
background-color: black;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-header td {
|
.table-header td {
|
||||||
color: white;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-body td {
|
.table-body td {
|
||||||
|
|
@ -75,6 +74,10 @@
|
||||||
.table-cell-text-center {
|
.table-cell-text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-cell-text-start {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item @if(request()->routeIs('products.*')) active @endif"
|
<a class="dropdown-item @if(request()->routeIs('products.*')) active @endif"
|
||||||
href="{{ route('products.index') }}"
|
href="{{ route('products.index') }}"
|
||||||
title="{{ __('Administrer les :model', ['model' => __('models.classes.products')]) }}"
|
title="{{ __('Administrer les :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||||
data-bs="tooltip"
|
data-bs="tooltip"
|
||||||
data-bs-placement="right">
|
data-bs-placement="right">
|
||||||
{{ __('models.classes.products') }}
|
{{ trans_choice('models.classes.products_monitoring', 2) }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,115 @@
|
||||||
@if ($paginator->hasPages())
|
{{-- GET ACTUAL PAGINATION --}}
|
||||||
<nav>
|
@php
|
||||||
<ul class="pagination d-flex justify-content-center align-items-center m-0 mt-3">
|
$pagination = intval(
|
||||||
{{-- Previous Page Link --}}
|
Cache::get(
|
||||||
@if ($paginator->onFirstPage())
|
'pagination.' .
|
||||||
<li class="page-item disabled" data-bs="tooltip" data-bs-placement="top"
|
\Illuminate\Support\Str::slug(
|
||||||
title="{{ __('Page précédente') }}" aria-disabled="true" aria-label="@lang('Page précédente')">
|
request()
|
||||||
<span class="page-link" aria-hidden="true">‹</span>
|
->route()
|
||||||
</li>
|
->getName(),
|
||||||
@else
|
),
|
||||||
<li class="page-item">
|
),
|
||||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top"
|
);
|
||||||
title="{{ __('Page précédente') }}" href="{{ $paginator->previousPageUrl() }}"
|
@endphp
|
||||||
rel="prev" aria-label="@lang('Page précédente')">‹</a>
|
@if ($paginator->items())
|
||||||
</li>
|
<nav class="pagination-custom d-flex justify-content-between align-items-center">
|
||||||
@endif
|
{{-- SELECT ITEMS PER PAGE --}}
|
||||||
|
<div class="dropup-center d-flex justify-content-center align-items-center input-group w-fit">
|
||||||
{{-- Pagination Elements --}}
|
<span class="btn-md input-group-text" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
@foreach ($elements as $element)
|
title="{{ __('crud.pagination.paginate_list') }}">
|
||||||
{{-- "Three Dots" Separator --}}
|
<i class="fa-solid fa-list-ul"></i>
|
||||||
@if (is_string($element))
|
</span>
|
||||||
<li class="page-item disabled" aria-disabled="true"><span
|
<button class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" type="button" aria-expanded="false">
|
||||||
class="page-link">{{ $element }}</span></li>
|
{{ $pagination }}
|
||||||
@endif
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
{{-- Array Of Links --}}
|
@foreach (\App\Enums\Pagination\ItemsPerPaginationEnum::toArray() as $itemsPerPaginationEnum)
|
||||||
@if (is_array($element))
|
<li>
|
||||||
@foreach ($element as $page => $url)
|
<a class="dropdown-item user-select-none @if ($pagination === $itemsPerPaginationEnum->value) active @endif text-center"
|
||||||
@if ($page == $paginator->currentPage())
|
href="{{ request()->fullUrlWithQuery(['page' => 1, 'pagination' => $itemsPerPaginationEnum->value]) }}"
|
||||||
<li class="page-item active" data-bs="tooltip" data-bs-placement="top"
|
role="button">
|
||||||
title="{{ __('Page actuelle') }}" aria-current="page">
|
{{ $itemsPerPaginationEnum->value }}
|
||||||
<span class="page-link">{{ $page }}</span>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@else
|
@endforeach
|
||||||
<li class="page-item">
|
</ul>
|
||||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top"
|
</div>
|
||||||
title="{{ __('Page n°:id', ['id' => $page]) }}"
|
@if ($paginator->hasPages())
|
||||||
href="{{ $url }}">{{ $page }}</a>
|
{{-- PAGINATION --}}
|
||||||
</li>
|
<div class="d-flex justify-content-end align-items-center">
|
||||||
|
<ul class="pagination m-0">
|
||||||
|
{{-- PREVIOUS PAGE --}}
|
||||||
|
<li class="page-item @if ($paginator->onFirstPage()) disabled @endif">
|
||||||
|
<a class="page-link d-flex align-items-center h-100" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
|
title="{{ __('crud.pagination.previous') }}" aria-label="@lang('crud.pagination.previous')"
|
||||||
|
@if (!$paginator->onFirstPage()) href="{{ request()->fullUrlWithQuery(['page' => $paginator->currentPage() - 1]) }}" @endif
|
||||||
|
rel="prev" @if ($paginator->onFirstPage()) aria-hidden="true" disabled @endif>
|
||||||
|
<i class="fa-solid fa-chevron-left fa-2xs mt-1"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{-- FIRST PAGE --}}
|
||||||
|
@if ($paginator->currentPage() > 3)
|
||||||
|
<li class="page-item d-none d-sm-block" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
|
title="{{ __('crud.pagination.specific_page', ['id' => 1]) }}">
|
||||||
|
<a class="page-link" href="{{ request()->fullUrlWithQuery(['page' => 1]) }}">1</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
{{-- HIDE PAGES TOO FAR --}}
|
||||||
|
@if ($paginator->currentPage() > 4)
|
||||||
|
<li class="page-item d-none d-sm-block disabled"><span class="page-link">...</span></li>
|
||||||
|
@endif
|
||||||
|
{{-- SHOW ACTUAL PAGES + N-2/N+2 --}}
|
||||||
|
@foreach (range(1, $paginator->lastPage()) as $i)
|
||||||
|
@if ($i >= $paginator->currentPage() - 2 && $i <= $paginator->currentPage() + 2)
|
||||||
|
@if ($i == $paginator->currentPage())
|
||||||
|
<li class="page-item">
|
||||||
|
<div class="dropup-center">
|
||||||
|
<button class="btn btn-primary dropdown-toggle rounded-0" data-bs-toggle="dropdown" type="button"
|
||||||
|
aria-expanded="false">
|
||||||
|
{{ $i }}
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
@for ($i = 1; $i <= $paginator->lastPage(); $i++)
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item user-select-none @if ($paginator->currentPage() === $i) active @endif text-center"
|
||||||
|
href="{{ request()->fullUrlWithQuery(['page' => $i]) }}" role="button">
|
||||||
|
{{ $i }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@endfor
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@else
|
||||||
|
<li class="page-item d-none d-md-block" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
|
title="{{ __('crud.pagination.specific_page', ['id' => $i]) }}">
|
||||||
|
<a class="page-link" href="{{ request()->fullUrlWithQuery(['page' => $i]) }}">{{ $i }}</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
{{-- HIDE PAGES TOO FAR --}}
|
||||||
@endforeach
|
@if ($paginator->currentPage() < $paginator->lastPage() - 3)
|
||||||
|
<li class="page-item d-none d-sm-block disabled"><span class="page-link">...</span></li>
|
||||||
{{-- Next Page Link --}}
|
@endif
|
||||||
@if ($paginator->hasMorePages())
|
{{-- LAST PAGE --}}
|
||||||
<li class="page-item">
|
@if ($paginator->currentPage() < $paginator->lastPage() - 2)
|
||||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top" title="{{ __('Page suivante') }}"
|
<li class="page-item d-none d-sm-block" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
href="{{ $paginator->nextPageUrl() }}" rel="next"
|
title="{{ __('crud.pagination.specific_page', ['id' => $paginator->lastPage()]) }}">
|
||||||
aria-label="@lang('Page suivante')">›</a>
|
<a class="page-link"
|
||||||
</li>
|
href="{{ request()->fullUrlWithQuery(['page' => $paginator->lastPage()]) }}">{{ $paginator->lastPage() }}</a>
|
||||||
@else
|
</li>
|
||||||
<li class="page-item disabled" data-bs="tooltip" data-bs-placement="top"
|
@endif
|
||||||
title="{{ __('Page suivante') }}" aria-disabled="true" aria-label="@lang('Page suivante')">
|
{{-- NEXT PAGE --}}
|
||||||
<span class="page-link" aria-hidden="true">›</span>
|
<li class="page-item @if (!$paginator->hasMorePages()) disabled @endif">
|
||||||
</li>
|
<a class="page-link d-flex align-items-center h-100" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
@endif
|
title="{{ __('crud.pagination.next') }}" aria-label="{{ __('crud.pagination.next') }}"
|
||||||
</ul>
|
@if ($paginator->hasMorePages()) href="{{ request()->fullUrlWithQuery(['page' => $paginator->currentPage() + 1]) }}" @endif
|
||||||
|
rel="next" @if (!$paginator->hasMorePages()) aria-hidden="true" disabled @endif>
|
||||||
|
<i class="fa-solid fa-chevron-right fa-2xs mt-1"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</nav>
|
</nav>
|
||||||
@endif
|
@endif
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,7 @@
|
||||||
multipdf: "{{ route('products.multipdf.update', ['id' => 'ID']) }}",
|
multipdf: "{{ route('products.multipdf.update', ['id' => 'ID']) }}",
|
||||||
duplicate: "{{ route('products.duplicate', ['product' => 'PRODUCT']) }}"
|
duplicate: "{{ route('products.duplicate', ['product' => 'PRODUCT']) }}"
|
||||||
};
|
};
|
||||||
|
window.__SYSTEM._routes.brands = {
|
||||||
|
store: "{{ route('brands.store') }}",
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
||||||
@endphp
|
@endphp
|
||||||
{{-- NO Sort for order column --}}
|
{{-- NO Sort for order column --}}
|
||||||
@if($col === 'order' or in_array($col, $ignore))
|
@if($col === 'order' or in_array($col, $ignore))
|
||||||
@if(!$noOrder or $rst)
|
|
||||||
@if ($col === 'multi_pdf')
|
@if ($col === 'multi_pdf')
|
||||||
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
||||||
<span>{{ $colname }}</span>
|
<span>{{ $colname }}</span>
|
||||||
|
|
@ -35,7 +34,6 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
||||||
<span>{{ $colname }}</span>
|
<span>{{ $colname }}</span>
|
||||||
</th>
|
</th>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
|
||||||
@continue
|
@continue
|
||||||
@endif
|
@endif
|
||||||
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,14 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-center">
|
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-center">
|
||||||
<div class="text-center text-lg-start pb-2 p-lg-0">
|
<div class="text-center text-lg-start pb-2 p-lg-0">
|
||||||
<h5 class="card-title">{{ __('models.classes.products') }}</h5>
|
<h5 class="card-title">{{ trans_choice('models.classes.products_monitoring', 2) }}</h5>
|
||||||
<p class="card-text text-muted fst-italic">{{ __('- accéder à l\'ensemble des produits enregistrés') }}</p>
|
<p class="card-text text-muted fst-italic">{{ __('- accéder à l\'ensemble des produits enregistrés') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="{{ route('products.index') }}"
|
<a href="{{ route('products.index') }}"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
title="{{ __('Accéder à la liste des :model', ['model' => __('models.classes.products')]) }}"
|
title="{{ __('Accéder à la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
{{ __('Voir la liste') }}
|
{{ __('Consulter/Insérer une :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
@extends('layout')
|
@extends('layout')
|
||||||
|
|
||||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('création'))))
|
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 1), Str::ucfirst(__('création'))))
|
||||||
@section('description', __('Création d\'un produit'))
|
@section('description', __('Création d\'un produit'))
|
||||||
@section('breadcrumb', 'no')
|
@section('breadcrumb', 'no')
|
||||||
|
|
||||||
|
|
@ -14,17 +14,17 @@
|
||||||
class="btn btn-primary text-decoration-none m-0"
|
class="btn btn-primary text-decoration-none m-0"
|
||||||
data-bs="tooltip"
|
data-bs="tooltip"
|
||||||
data-bs-placement="top"
|
data-bs-placement="top"
|
||||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.products')]) }}"
|
title="{{ __('Retourner sur la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
<i class="fa-solid fa-arrow-left"></i>
|
<i class="fa-solid fa-arrow-left"></i>
|
||||||
</a>
|
</a>
|
||||||
<span class="fw-bold">{{ Str::singular(__('models.classes.products')) }}</span> <small class="text-muted">{{ Str::ucfirst(__('création')) }}</small>
|
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 1) }}</span> <small class="text-muted">{{ Str::ucfirst(__('création')) }}</small>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
||||||
<button id="formSubmitClone"
|
<button id="formSubmitClone"
|
||||||
class="btn btn-primary pull-end"
|
class="btn btn-success pull-end"
|
||||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
{{ __('Sauvegarder') }}
|
{{ __('Sauvegarder') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -39,8 +39,8 @@
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<button id="formSubmit"
|
<button id="formSubmit"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-primary"
|
class="btn btn-success"
|
||||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
data-bs="tooltip">{{ __('Sauvegarder') }}</button>
|
data-bs="tooltip">{{ __('Sauvegarder') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
@extends('layout')
|
@extends('layout')
|
||||||
|
|
||||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('édition'))))
|
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 1), Str::ucfirst(__('édition'))))
|
||||||
@section('description', __('Édition d\'un produit'))
|
@section('description', __('Édition d\'un produit'))
|
||||||
@section('breadcrumb', 'no')
|
@section('breadcrumb', 'no')
|
||||||
|
|
||||||
|
|
@ -14,11 +14,11 @@
|
||||||
class="btn btn-primary text-decoration-none m-0"
|
class="btn btn-primary text-decoration-none m-0"
|
||||||
data-bs="tooltip"
|
data-bs="tooltip"
|
||||||
data-bs-placement="top"
|
data-bs-placement="top"
|
||||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.products')]) }}"
|
title="{{ __('Retourner sur la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
<i class="fa-solid fa-arrow-left"></i>
|
<i class="fa-solid fa-arrow-left"></i>
|
||||||
</a>
|
</a>
|
||||||
<span class="fw-bold">{{ Str::singular(__('models.classes.products')) }}</span> <small class="text-muted">{{ Str::ucfirst(__('édition')) }}</small>
|
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 1) }}</span> <small class="text-muted">{{ Str::ucfirst(__('édition')) }}</small>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
||||||
|
|
@ -28,13 +28,13 @@
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button id="formSubmitClone"
|
<button id="formSubmitClone"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary pull-end"
|
class="btn btn-success pull-end"
|
||||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
{{ __('Sauvegarder') }}
|
{{ __('Sauvegarder') }}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-danger"
|
<button class="btn btn-danger"
|
||||||
title="{{ __('Supprimer ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Supprimer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
<i class="fa-solid fa-trash"></i>
|
<i class="fa-solid fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -52,8 +52,8 @@
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<button id="formSubmit"
|
<button id="formSubmit"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-primary"
|
class="btn btn-success"
|
||||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
data-bs="tooltip">
|
data-bs="tooltip">
|
||||||
{{ __('Sauvegarder') }}
|
{{ __('Sauvegarder') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{-- TITLE --}}
|
{{-- TITLE --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Titre') }}</legend>
|
<legend>{{ __('Nom') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
@include('partials.inputs.varchar', [
|
@include('partials.inputs.varchar', [
|
||||||
'id' => 'productName',
|
'id' => 'productName',
|
||||||
'label' => __('Titre du :model', ['model' => Str::singular(__('models.classes.products'))]),
|
'label' => __('Nom du :model', ['model' => Str::singular(__('models.classes.products'))]),
|
||||||
'hasWordCounter' => true,
|
'hasWordCounter' => true,
|
||||||
'name' => 'name',
|
'name' => 'name',
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
|
'placeholder' => '',
|
||||||
'helper' => __('Doit décrire précisément le produit (3 caractères minimum, 255 maximum).'),
|
'helper' => __('Doit décrire précisément le produit (3 caractères minimum, 255 maximum).'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -20,17 +21,21 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- BRANDS --}}
|
{{-- BRANDS --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('models.classes.brands') }}</legend>
|
<legend>{{ __('models.classes.brands') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
@include('partials.inputs.bigint-foreign-id', [
|
@include('partials.inputs.bigint-belongs-to', [
|
||||||
'id' => 'productBrand',
|
|
||||||
'label' => trans(':model associé(e)', ['model' => Str::singular(trans('models.classes.brands'))]),
|
|
||||||
'name' => 'brand_id',
|
'name' => 'brand_id',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'associatedModels' => $brands,
|
'itemLimit' => [0, 1],
|
||||||
'helper' => trans('Selectionnez un(e) :model parmis la liste.', ['model' => Str::singular(trans('models.classes.brands'))]),
|
'itemsList' => $brands,
|
||||||
|
'storeRoute' => 'brands.store',
|
||||||
|
'labelField' => 'name',
|
||||||
|
'helper' => __('La marque associée au produit.'),
|
||||||
|
'placeholder' => '',
|
||||||
|
'require' => true,
|
||||||
|
'label' => __('Marque associée'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -38,42 +43,47 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- SOURCE --}}
|
{{-- SOURCE --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __("Source") }}</legend>
|
<legend>{{ __('Source') }}</legend>
|
||||||
@php
|
@php
|
||||||
$data = [
|
$data = [
|
||||||
'id' => 'productSource',
|
'id' => 'productSource',
|
||||||
'label' => __('Source associé(e)'),
|
'label' => __('Source'),
|
||||||
'name' => 'source',
|
'name' => 'source',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'sourceEnum' => \App\Enums\Products\SourceEnum::toArray(),
|
'sourceEnum' => \App\Enums\Products\SourceEnum::toArray(),
|
||||||
'productsFair' => $productsFair,
|
'productsFair' => $productsFair,
|
||||||
'productsShop' => $productsShop,
|
'productsShop' => $productsShop,
|
||||||
'productsCatalog' => $productsCatalog,
|
'productsCatalog' => $productsCatalog,
|
||||||
'helper' => __('Selectionnez un(e) Source maximum parmis la liste.')
|
'oldValue' => old('source') ?? ($productModel->source ?? 0),
|
||||||
];
|
'oldDetails' => old('shop', old('fair', old('catalogue'))) ?? '',
|
||||||
|
'helper' => __('Selectionnez un(e) Source maximum parmi la liste.'),
|
||||||
|
];
|
||||||
@endphp
|
@endphp
|
||||||
<div class="source-inputs" data-json='@json($data)'></div>
|
<div class="source-inputs" data-json='@json($data)'></div>
|
||||||
@include('modules.input-error', ['inputName' => 'source'])
|
@include('modules.input-error', ['inputName' => 'source'])
|
||||||
|
@include('modules.input-error', ['inputName' => 'catalogue'])
|
||||||
|
@include('modules.input-error', ['inputName' => 'shop'])
|
||||||
|
@include('modules.input-error', ['inputName' => 'fair'])
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
{{-- GENCODE --}}
|
{{-- GENCOD --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('GENCODE') }}</legend>
|
<legend>{{ __('GENCOD') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@php
|
@php
|
||||||
$data = [
|
$data = [
|
||||||
'id' => 'productGencod',
|
'id' => 'productGencod',
|
||||||
'label' => __('Code'),
|
'label' => __('Code'),
|
||||||
'name' => 'gencod',
|
'name' => 'gencod',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'value' => old('gencod') ?? $productModel->gencod ?? null,
|
'value' => old('gencod') ?? ($productModel->gencod ?? null),
|
||||||
'maxlength' => 13,
|
'maxlength' => 13,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'helper' => __('Saisir une suite de 13 chiffres maximum.')
|
'helper' => __('Saisir une suite de 13 chiffres maximum.'),
|
||||||
];
|
];
|
||||||
@endphp
|
@endphp
|
||||||
<div class="verification-code" data-json='@json($data)'></div>
|
<div class="verification-code" data-json='@json($data)'></div>
|
||||||
@include('modules.input-error', ['inputName' => 'gencod'])
|
@include('modules.input-error', ['inputName' => 'gencod'])
|
||||||
|
|
@ -83,7 +93,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- URL --}}
|
{{-- URL --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('URL') }}</legend>
|
<legend>{{ __('URL') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -94,7 +104,7 @@
|
||||||
'name' => 'url',
|
'name' => 'url',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'placeholder' => __('https://google.com'),
|
'placeholder' => '',
|
||||||
'helper' => __('Doit être une url valide.'),
|
'helper' => __('Doit être une url valide.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -103,33 +113,9 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- IMAGE --}}
|
{{-- IMAGE --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Image') }}</legend>
|
<legend>{{ __('Visuel de référence') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{-- PICTURE_ALT --}}
|
|
||||||
<div class="col-12 col-md-6 mb-3">
|
|
||||||
@include('partials.inputs.varchar', [
|
|
||||||
'id' => 'homePart3PictureAlt',
|
|
||||||
'label' => __('Texte alternatif de :model', ['model' => Str::singular(__('models.classes.products'))]),
|
|
||||||
'hasWordCounter' => true,
|
|
||||||
'name' => 'picture_alt',
|
|
||||||
'required' => true,
|
|
||||||
'model' => $productModel ?? null,
|
|
||||||
'helper' => __('Doit décrire votre image pour les moteurs de recherches et les non voyants (5 à 6 mots, minimum 3 caractères).'),
|
|
||||||
])
|
|
||||||
</div>
|
|
||||||
{{-- PICTURE_TITLE --}}
|
|
||||||
<div class="col-12 col-md-6 mb-3">
|
|
||||||
@include('partials.inputs.varchar', [
|
|
||||||
'id' => 'homePart3PictureTitle',
|
|
||||||
'label' => __('Titre de :model', ['model' => Str::singular(__('models.classes.products'))]),
|
|
||||||
'hasWordCounter' => true,
|
|
||||||
'name' => 'picture_title',
|
|
||||||
'required' => true,
|
|
||||||
'model' => $productModel ?? null,
|
|
||||||
'helper' => __('Utile pour les utilisateurs, s\'affiche en passant la souris sur l\'image (minimum 3 caractères).'),
|
|
||||||
])
|
|
||||||
</div>
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@include('partials.inputs.varchar-picture', [
|
@include('partials.inputs.varchar-picture', [
|
||||||
'id' => 'productImage',
|
'id' => 'productImage',
|
||||||
|
|
@ -147,19 +133,33 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- DOCUMENTS --}}
|
{{-- DOCUMENTS --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Documents') }}</legend>
|
<legend>{{ __('Documents complémentaires') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
{{-- application/msword
|
||||||
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||||
|
image/jpeg
|
||||||
|
image/png
|
||||||
|
application/pdf
|
||||||
|
application/vnd.ms-powerpoint
|
||||||
|
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||||
|
application/vnd.ms-excel
|
||||||
|
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||||
|
text/csv
|
||||||
|
image/gif
|
||||||
|
text/plain pour .txt --}}
|
||||||
@php
|
@php
|
||||||
$data = [
|
$data = [
|
||||||
'id' => 'productDocs',
|
'id' => 'productDocs',
|
||||||
'name' => 'docs[]',
|
'name' => 'docs[]',
|
||||||
'value' => $productModel->docs ?? [],
|
'value' => $productModel->docs ?? [],
|
||||||
'limit' => [0,5],
|
'limit' => [0, 5],
|
||||||
'helper' => __('Doit respecter le format :format.', ['format' => '.pdf']),
|
'helper' => __('Doit respecter le format :format.', [
|
||||||
'errors' => $errors->getBag('default')->getMessages()
|
'format' => '.xls,.csv,.xlsx,.png,.jpg,.jpeg,.gif,.doc,.docx,.ppt,.pdf,.txt',
|
||||||
];
|
]),
|
||||||
|
'errors' => $errors->getBag('default')->getMessages(),
|
||||||
|
];
|
||||||
@endphp
|
@endphp
|
||||||
<div class="multiple-documents-input" data-json='@json($data)'></div>
|
<div class="multiple-documents-input" data-json='@json($data)'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -168,7 +168,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- CERTIFICATION --}}
|
{{-- CERTIFICATION --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Certification') }}</legend>
|
<legend>{{ __('Certification') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -179,7 +179,7 @@
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'require' => false,
|
'require' => false,
|
||||||
'associatedModels' => \App\Enums\Products\CertificationEnum::toArray(),
|
'associatedModels' => \App\Enums\Products\CertificationEnum::toArray(),
|
||||||
'helper' => trans('Selectionnez une Certification parmis la liste.'),
|
'helper' => trans('Selectionnez une Certification parmi la liste.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -187,18 +187,18 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- ORIGINS --}}
|
{{-- ORIGINS --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Origines') }}</legend>
|
<legend>{{ __('Origine') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@include('partials.inputs.select-multiple-enum', [
|
@include('partials.inputs.select-multiple-enum', [
|
||||||
'id' => 'productOrigins',
|
'id' => 'productOrigins',
|
||||||
'label' => __('Origines associées'),
|
'label' => __('Origine associée'),
|
||||||
'name' => 'origins',
|
'name' => 'origins',
|
||||||
'itemsSelected' => old('origins', $productModel->origins ?? []),
|
'itemsSelected' => old('origins', $productModel->origins ?? []),
|
||||||
'itemsList' => collect(\App\Enums\Products\OriginEnum::toArray())->values(),
|
'itemsList' => collect(\App\Enums\Products\OriginEnum::toArray())->values(),
|
||||||
'itemLimit' => [0, count(\App\Enums\Products\OriginEnum::toArray())],
|
'itemLimit' => [0, count(\App\Enums\Products\OriginEnum::toArray())],
|
||||||
'placeholder' => __('Recherchez une Origine a associer.'),
|
'placeholder' => '',
|
||||||
'helper' => __('Les Origines associées au produit.'),
|
'helper' => __('L\'origine associée au produit.'),
|
||||||
'require' => false,
|
'require' => false,
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -206,7 +206,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- CLAIMS --}}
|
{{-- CLAIMS --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Allégations') }}</legend>
|
<legend>{{ __('Allégations') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@include('partials.inputs.select-multiple-enum', [
|
@include('partials.inputs.select-multiple-enum', [
|
||||||
|
|
@ -219,13 +219,13 @@
|
||||||
'showSpecificItem' => [
|
'showSpecificItem' => [
|
||||||
'name' => 'specified_claim',
|
'name' => 'specified_claim',
|
||||||
'label' => 'Précision de l\'allégation',
|
'label' => 'Précision de l\'allégation',
|
||||||
'placeholder' => 'Sans sucre ajouté',
|
'placeholder' => '',
|
||||||
'value' => $productModel->specified_claim ?? null,
|
'value' => old('specified_claim', $productModel->specified_claim ?? null),
|
||||||
'showId' => 99,
|
'showId' => 99,
|
||||||
'helper' => __('Doit décrire précisément l\'allégation (3 caractères minimum, 255 maximum).')
|
'helper' => __('Doit décrire précisément l\'allégation (3 caractères minimum, 255 maximum).'),
|
||||||
],
|
],
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'placeholder' => __('Recherchez une Allégation a associer.'),
|
'placeholder' => '',
|
||||||
'require' => false,
|
'require' => false,
|
||||||
'helper' => __('Les Allégations associées au produit.'),
|
'helper' => __('Les Allégations associées au produit.'),
|
||||||
])
|
])
|
||||||
|
|
@ -234,7 +234,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- DISTRIBUTION NETWORK --}}
|
{{-- DISTRIBUTION NETWORK --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Réseau de distribution') }}</legend>
|
<legend>{{ __('Réseau de distribution') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -243,9 +243,9 @@
|
||||||
'label' => __('Réseau de distribution associé'),
|
'label' => __('Réseau de distribution associé'),
|
||||||
'name' => 'distribution_network',
|
'name' => 'distribution_network',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'require' => true,
|
'required' => true,
|
||||||
'associatedModels' => \App\Enums\Products\DistributionNetworkEnum::toArray(),
|
'associatedModels' => \App\Enums\Products\DistributionNetworkEnum::toArray(),
|
||||||
'helper' => trans('Selectionnez un Réseau de distribution parmis la liste.'),
|
'helper' => trans('Selectionnez un Réseau de distribution parmi la liste.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -253,7 +253,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- RAY --}}
|
{{-- RAY --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Rayon') }}</legend>
|
<legend>{{ __('Rayon') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -262,9 +262,9 @@
|
||||||
'label' => __('Rayon associé'),
|
'label' => __('Rayon associé'),
|
||||||
'name' => 'ray',
|
'name' => 'ray',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'require' => true,
|
'required' => true,
|
||||||
'associatedModels' => \App\Enums\Products\RayEnum::toArray(),
|
'associatedModels' => \App\Enums\Products\RayEnum::toArray(),
|
||||||
'helper' => trans('Selectionnez un Rayon parmis la liste.'),
|
'helper' => trans('Selectionnez un Rayon parmi la liste.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -272,7 +272,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- RANGE --}}
|
{{-- RANGE --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Famille de produit') }}</legend>
|
<legend>{{ __('Famille de produit') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -281,9 +281,9 @@
|
||||||
'label' => __('Famille de produit associée'),
|
'label' => __('Famille de produit associée'),
|
||||||
'name' => 'product_range',
|
'name' => 'product_range',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'require' => true,
|
'required' => true,
|
||||||
'associatedModels' => \App\Enums\Products\RangeEnum::toArray(),
|
'associatedModels' => \App\Enums\Products\RangeEnum::toArray(),
|
||||||
'helper' => trans('Selectionnez une Famille de produit parmis la liste.'),
|
'helper' => trans('Selectionnez une Famille de produit parmi la liste.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -291,7 +291,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- GEO AREA --}}
|
{{-- GEO AREA --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Zone géographique') }}</legend>
|
<legend>{{ __('Zone géographique') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -300,9 +300,9 @@
|
||||||
'label' => __('Zone géographique associée'),
|
'label' => __('Zone géographique associée'),
|
||||||
'name' => 'geo_area',
|
'name' => 'geo_area',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'require' => true,
|
'required' => true,
|
||||||
'associatedModels' => \App\Enums\Products\GeoAreaEnum::toArray(),
|
'associatedModels' => \App\Enums\Products\GeoAreaEnum::toArray(),
|
||||||
'helper' => trans('Selectionnez une Zone géographique parmis la liste.'),
|
'helper' => trans('Selectionnez une Zone géographique parmi la liste.'),
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -310,7 +310,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- WEIGHT --}}
|
{{-- WEIGHT --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Poids') }}</legend>
|
<legend>{{ __('Poids') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
|
|
@ -329,16 +329,17 @@
|
||||||
</div>
|
</div>
|
||||||
{{-- PVC --}}
|
{{-- PVC --}}
|
||||||
<div class="col-12 col-md-6 mb-3">
|
<div class="col-12 col-md-6 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('PVC') }}</legend>
|
<legend>{{ __('PVC') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
@include('partials.inputs.int-number', [
|
@include('partials.inputs.int-number', [
|
||||||
'id' => 'productWeight',
|
'id' => 'productPvc',
|
||||||
'label' => __('PVC de l\'UVC'),
|
'label' => __('PVC de l\'UVC'),
|
||||||
'name' => 'pvc',
|
'name' => 'pvc',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
|
'step' => 0.01,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'helper' => trans('Le prix doit être en euro (€).'),
|
'helper' => trans('Le prix doit être en euro (€).'),
|
||||||
])
|
])
|
||||||
|
|
@ -346,9 +347,51 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
{{-- Prix au kilo --}}
|
||||||
|
<div class="col-12 col-md-6 mb-3">
|
||||||
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
|
<legend>{{ __('Prix au kilo') }}</legend>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 mb-3">
|
||||||
|
@php
|
||||||
|
$priceKg = 0;
|
||||||
|
if ($productModel && $productModel->weight != 0) {
|
||||||
|
$priceKg = (1000 * $productModel->pvc) / $productModel->weight;
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('partials.inputs.int-number', [
|
||||||
|
'id' => 'productPriceKg',
|
||||||
|
'label' => __('Prix au kilo du produit'),
|
||||||
|
'name' => 'priceKg',
|
||||||
|
'model' => null,
|
||||||
|
'required' => false,
|
||||||
|
'disabled' => true,
|
||||||
|
'value' => $priceKg,
|
||||||
|
'helper' => trans('Le prix au kilo est calculé automatiquement.'),
|
||||||
|
])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
{{-- KEYWORDS --}}
|
||||||
|
<div class="col-12 mb-3">
|
||||||
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
|
<legend>{{ __('Précisez la ou les tendances') }}</legend>
|
||||||
|
<div class="row">
|
||||||
|
@include('partials.inputs.pivot-taggable', [
|
||||||
|
'name' => 'productKeywords',
|
||||||
|
'model' => $productModel ?? null,
|
||||||
|
'itemLimit' => [0, count($keywords)],
|
||||||
|
'itemsList' => $keywords,
|
||||||
|
'helper' => __('Les Tendances associées au produit.'),
|
||||||
|
'placeholder' => '',
|
||||||
|
])
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
{{-- COMMENT --}}
|
{{-- COMMENT --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
<fieldset class="h-100 border bg-white p-3">
|
||||||
<legend>{{ __('Commentaire libre') }}</legend>
|
<legend>{{ __('Commentaire libre') }}</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|
@ -358,63 +401,49 @@
|
||||||
'name' => 'comment',
|
'name' => 'comment',
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'helper' => __(' Doit décrire précisément le contenu du produit, requiert entre 50 et 160 caractères, balise <meta> description.'),
|
'helper' => __(
|
||||||
'placeholder' => __('Une description du contenu du produit pour les moteurs de recherche.'),
|
' Doit décrire précisément le contenu du produit, requiert entre 50 et 160 caractères, balise <meta> description.'),
|
||||||
|
'placeholder' => '',
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
{{-- KEYWORDS --}}
|
|
||||||
<div class="col-12 mb-3">
|
|
||||||
<fieldset class="border h-100 bg-white p-3">
|
|
||||||
<legend>{{ __('Tendances') }}</legend>
|
|
||||||
<div class="row">
|
|
||||||
@include('partials.inputs.pivot-taggable', [
|
|
||||||
'name' => 'productKeywords',
|
|
||||||
'model' => $productModel ?? null,
|
|
||||||
'itemLimit' => [0, count($keywords)],
|
|
||||||
'itemsList' => $keywords,
|
|
||||||
'helper' => __('Les Tendances associées au produit.'),
|
|
||||||
'placeholder' => __('Recherchez une Tendance a associer.'),
|
|
||||||
])
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
{{-- TASTED --}}
|
{{-- TASTED --}}
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
@php
|
@php
|
||||||
if (session()->getOldInput()['evaluation'] ?? null) {
|
if (session()->getOldInput()['evaluation'] ?? null) {
|
||||||
foreach (session()->getOldInput()['evaluation'] as $key => $value) {
|
foreach (session()->getOldInput()['evaluation'] as $key => $value) {
|
||||||
$commentOldModel[] = [
|
$commentOldModel[] = [
|
||||||
"evaluation" => session()->getOldInput()['evaluation'][$key] ?? null,
|
'evaluation' => session()->getOldInput()['evaluation'][$key] ?? null,
|
||||||
"aspect" => session()->getOldInput()['aspect'][$key] ?? null,
|
'aspect' => session()->getOldInput()['aspect'][$key] ?? null,
|
||||||
"taste" => session()->getOldInput()['taste'][$key] ?? null,
|
'taste' => session()->getOldInput()['taste'][$key] ?? null,
|
||||||
"odor" => session()->getOldInput()['odor'][$key] ?? null,
|
'odor' => session()->getOldInput()['odor'][$key] ?? null,
|
||||||
"texture" => session()->getOldInput()['texture'][$key] ?? null,
|
'texture' => session()->getOldInput()['texture'][$key] ?? null,
|
||||||
];
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
$data = [
|
||||||
$data = [
|
'id' => 'productSource',
|
||||||
'id' => 'productSource',
|
'title1' => __('Dégustation'),
|
||||||
'title1' => __("Dégustation"),
|
'label1' => __('Produit dégusté ?'),
|
||||||
'label1' => __('Produit dégusté ?'),
|
'name1' => 'is_tasted',
|
||||||
'name1' => 'is_tasted',
|
'oldCheck' => boolval(old('is_tasted', null)),
|
||||||
'model' => $productModel ?? null,
|
'model' => $productModel ?? null,
|
||||||
'oldModel' => session()->getOldInput(),
|
'oldModel' => session()->getOldInput(),
|
||||||
'max' => 15,
|
'max' => 15,
|
||||||
'min' => 1,
|
'min' => 1,
|
||||||
'helper1' => __('Le produit a été dégusté.'),
|
'helper1' => __('Le produit a été dégusté.'),
|
||||||
'required1' => false,
|
'required1' => false,
|
||||||
'title2' => __("Commentaires"),
|
'title2' => __('Commentaires'),
|
||||||
'name2' => 'tasters_number',
|
'name2' => 'tasters_number',
|
||||||
'label2' => __('Nombre de dégustation'),
|
'label2' => __('Nombre de dégustation'),
|
||||||
'helper2' => __('Doit être un chiffre ou un nombre (minimum 1 et maximum 15).'),
|
'helper2' => __('Doit être un chiffre ou un nombre (minimum 1 et maximum 15).'),
|
||||||
'required2' => false,
|
'required2' => false,
|
||||||
'commentModel' => $commentModel ?? [],
|
'commentModel' => $commentModel ?? [],
|
||||||
'commentOldModel' => $commentOldModel ?? [],
|
'commentOldModel' => $commentOldModel ?? [],
|
||||||
'errors' => $errors->getBag('default')->getMessages() ?? []
|
'errors' => $errors->getBag('default')->getMessages() ?? [],
|
||||||
];
|
];
|
||||||
@endphp
|
@endphp
|
||||||
<div class="tasted-product" data-json='@json($data)'></div>
|
<div class="tasted-product" data-json='@json($data)'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -429,5 +458,21 @@
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
submit.click('');
|
submit.click('');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const priceKgInput = document.getElementById('productPriceKg');
|
||||||
|
const priceInput = document.getElementById('productPvc');
|
||||||
|
const weightInput = document.getElementById('productWeight');
|
||||||
|
priceInput.addEventListener("change", updatePriceKg);
|
||||||
|
weightInput.addEventListener("change", updatePriceKg);
|
||||||
|
|
||||||
|
function updatePriceKg() {
|
||||||
|
if (weightInput.value != 0) {
|
||||||
|
$priceKg = 1000 * priceInput.value / weightInput.value;
|
||||||
|
priceKgInput.value = $priceKg.toFixed(2);
|
||||||
|
} else {
|
||||||
|
priceKgInput.value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
@extends('layout')
|
@extends('layout')
|
||||||
|
|
||||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('liste'))))
|
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 2), Str::ucfirst(__('liste'))))
|
||||||
@section('description', __('Liste des produits publiés'))
|
@section('description', __('Liste des produits publiés'))
|
||||||
@section('breadcrumb', 'no')
|
@section('breadcrumb', 'no')
|
||||||
|
|
||||||
|
|
@ -9,16 +9,15 @@
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h1 class="text-center text-md-start h2">
|
<h1 class="text-md-start h2 text-center">
|
||||||
<span class="fw-bold">{{ __('models.classes.products') }}</span> <span class="text-muted">{{ Str::ucfirst(__('liste')) }}</span>
|
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 2) }}</span> <span
|
||||||
|
class="text-muted">{{ Str::ucfirst(__('liste')) }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="input-group justify-content-end">
|
<div class="input-group justify-content-end">
|
||||||
<a href="{{ route('products.create') }}"
|
<a class="btn btn-success" data-bs="tooltip" href="{{ route('products.create') }}"
|
||||||
class="btn btn-primary"
|
title="{{ __('Ajouter une :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||||
title="{{ __('Ajouter un :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
|
||||||
data-bs="tooltip">
|
|
||||||
<i class="fa-solid fa-plus"></i>
|
<i class="fa-solid fa-plus"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -28,7 +27,7 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@include('pages.products.product-filters')
|
@include('pages.products.product-filters')
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-md-6 p-0">
|
<div class="col-12 col-md-6 p-3">
|
||||||
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -38,11 +37,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-md-6 p-0">
|
<div class="col-12 col-md-6 p-3">
|
||||||
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,115 +1,103 @@
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table fix-action m-0 mt-3">
|
<table class="fix-action m-0 mt-3 table">
|
||||||
<thead>
|
<thead>
|
||||||
@php
|
@php
|
||||||
$cols = [
|
$cols = [
|
||||||
'name' => __('Nom'),
|
'name' => __('Nom'),
|
||||||
'brand_id' => __('Marque'),
|
'brand_id' => __('Marque'),
|
||||||
'picture' => __('Image'),
|
'picture' => __('Image'),
|
||||||
'updated_at' => __('Mis à jour le'),
|
'multi_pdf' => __('Générer en pdf la sélection'),
|
||||||
'multi_pdf' => __('Multi .pdf'),
|
];
|
||||||
];
|
$routeName = request()
|
||||||
$routeName = request()->route()->getName();
|
->route()
|
||||||
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
|
->getName();
|
||||||
$noOrder = Session::get("$routeName.sort_col") !== 'order' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
|
||||||
$noOrder = Session::get("$routeName.sort_col") !== '' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
($noOrder = Session::get("$routeName.sort_col") !== 'order') and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||||
@endphp
|
($noOrder = Session::get("$routeName.sort_col") !== '') and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||||
@include('modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => [], 'ignore' => ['multi_pdf']])
|
@endphp
|
||||||
|
@include('modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => [], 'ignore' => ['multi_pdf']])
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@if ($products->count())
|
@if ($products->count())
|
||||||
@foreach ($products as $productModel)
|
@foreach ($products as $productModel)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="align-middle text-center">
|
<td class="text-center align-middle">
|
||||||
<span>{{ $productModel->name }}</span>
|
<span>{{ $productModel->name }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle text-center">
|
<td class="text-center align-middle">
|
||||||
@foreach($brands as $key => $brand)
|
@foreach ($brands as $key => $brand)
|
||||||
@if ($brand->id === $productModel->brand_id)
|
@if ($brand->id === $productModel->brand_id)
|
||||||
<p class="m-0">{{ $brand->name }}</p>
|
<p class="m-0">{{ $brand->name }}</p>
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle text-center">
|
<td class="text-center align-middle">
|
||||||
@if(isset($productModel->picture))
|
@if ($productModel->picture)
|
||||||
<img class="bo-image-preview" src="{{ asset($productModel->picture) }}">
|
<img class="bo-image-preview" src="{{ asset(resize($productModel->picture, 'productTiny')) }}">
|
||||||
@else
|
@else
|
||||||
<p class="text-muted">{{ __('Aucune image enregistée') }}</p>
|
<p class="text-muted">{{ __('Aucune image enregistée') }}</p>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle text-center">
|
{{-- @if (!$noOrder or $rst) --}}
|
||||||
<span class="badge bg-secondary text-wrap">
|
<td class="text-center align-middle">
|
||||||
{{ $productModel->updated_at->formatLocalized('%d/%m/%Y à %I:%M') }}
|
@php
|
||||||
</span>
|
$data = [
|
||||||
</td>
|
'id' => 'productSelectMultiPdf',
|
||||||
@if(!$noOrder or $rst)
|
'model' => $productModel,
|
||||||
<td class="align-middle text-center">
|
'printMultiProduct' => $printMultiProduct,
|
||||||
@php
|
];
|
||||||
$data = [
|
@endphp
|
||||||
'id' => 'productSelectMultiPdf',
|
<div class="button-multi-pdf" data-json='@json($data)'></div>
|
||||||
'model' => $productModel,
|
</td>
|
||||||
'printMultiProduct' => $printMultiProduct,
|
{{-- @endif --}}
|
||||||
];
|
<td class="text-end align-middle">
|
||||||
@endphp
|
<form class="d-inline confirmDeleteJS" action="{{ route('products.destroy', $productModel->id) }}"
|
||||||
<div class="button-multi-pdf" data-json='@json($data)'></div>
|
method="POST">
|
||||||
</td>
|
@method('DELETE')
|
||||||
@endif
|
@csrf
|
||||||
<td class="align-middle text-end">
|
<div class="btn-group" role="group">
|
||||||
<form action="{{ route('products.destroy', $productModel->id) }}" method="POST" class="d-inline confirmDeleteJS">
|
<a class="btn btn-sm btn-info glightbox" data-gallery="product{{ $productModel->id }}"
|
||||||
@method('DELETE')
|
data-bs-title="{{ __('Visionner l\'image de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
@csrf
|
data-bs="tooltip" type="button" href="{{ asset($productModel->picture) }}" target="_blank">
|
||||||
<div class="btn-group" role="group">
|
<i class="fa-solid fa-image"></i>
|
||||||
<a class="btn btn-sm btn-info glightbox" type="button"
|
</a>
|
||||||
href="{{ asset($productModel->picture) }}" target="_blank"
|
<a class="btn btn-sm btn-warning" data-bs="tooltip" type="button"
|
||||||
data-gallery="product{{ $productModel->id }}"
|
href="{{ route('products.download', $productModel) }}"
|
||||||
data-bs-title="{{ __('Visionner l\'image du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
title="{{ __('Télécharger les annexes de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||||
data-bs="tooltip">
|
<i class="fa-solid fa-download"></i>
|
||||||
<i class="fa-solid fa-image"></i>
|
</a>
|
||||||
</a>
|
<a class="btn btn-sm btn-secondary btn-printing" data-bs="tooltip" data-id="{{ $productModel->id }}"
|
||||||
<a class="btn btn-sm btn-warning" type="button"
|
type="button" href="{{ route('products.pdf.show', $productModel) }}"
|
||||||
href="{{ route('products.download', $productModel) }}"
|
title="{{ __('Fichier .pdf de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||||
title="{{ __('Télécharger les annexes du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
target="blank">
|
||||||
data-bs="tooltip">
|
<i class="fa-solid fa-print"></i>
|
||||||
<i class="fa-solid fa-download"></i>
|
</a>
|
||||||
</a>
|
<a class="btn btn-sm btn-success" data-bs="tooltip"
|
||||||
<a class="btn btn-sm btn-secondary btn-printing" type="button"
|
href="{{ route('products.duplicate', $productModel) }}"
|
||||||
href="{{ route('products.pdf.show', $productModel) }}"
|
title="{{ __('Dupliquer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||||
target="blank"
|
<i class="fa-solid fa-copy"></i>
|
||||||
title="{{ __('Fichier .pdf du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
</a>
|
||||||
data-bs="tooltip"
|
<a class="btn btn-sm btn-primary" data-bs="tooltip" href="{{ route('products.edit', $productModel) }}"
|
||||||
data-id="{{ $productModel->id }}">
|
title="{{ __('Modifier cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||||
<i class="fa-solid fa-print"></i>
|
<i class="fa-solid fa-pencil"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-success"
|
<button class="btn btn-sm btn-danger" data-bs="tooltip"
|
||||||
href="{{ route('products.duplicate', $productModel) }}"
|
title="{{ __('Supprimer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||||
title="{{ __('Dupliquer ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
<i class="fa-solid fa-trash"></i>
|
||||||
data-bs="tooltip">
|
</button>
|
||||||
<i class="fa-solid fa-copy"></i>
|
</div>
|
||||||
</a>
|
</form>
|
||||||
<a class="btn btn-sm btn-primary"
|
</td>
|
||||||
href="{{ route('products.edit', $productModel) }}"
|
</tr>
|
||||||
title="{{ __('Modifier ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
@endforeach
|
||||||
data-bs="tooltip">
|
|
||||||
<i class="fa-solid fa-pencil"></i>
|
|
||||||
</a>
|
|
||||||
<button class="btn btn-sm btn-danger"
|
|
||||||
title="{{ __('Supprimer ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
|
||||||
data-bs="tooltip">
|
|
||||||
<i class="fa-solid fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
@else
|
@else
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="{{ count($cols)+1 }}" class="text-center">
|
<td class="text-center" colspan="{{ count($cols) + 1 }}">
|
||||||
<span
|
<span
|
||||||
class="h3">{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.products')]) }}
|
class="h3">{{ __('Aucun résultat pour les :models', ['models' => trans_choice('models.classes.products_monitoring', 2)]) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endif
|
@endif
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
@php
|
@php
|
||||||
$iArgs = [];
|
$iArgs = [];
|
||||||
if(request()->sort_col) {
|
if (request()->sort_col) {
|
||||||
$iArgs['sort_col'] = request()->sort_col;
|
$iArgs['sort_col'] = request()->sort_col;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(request()->search) {
|
if (request()->search) {
|
||||||
$iArgs['search'] = request()->sort_way;
|
$iArgs['search'] = request()->sort_way;
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
|
|
@ -12,173 +12,181 @@
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header border-0 p-0">
|
<div class="card-header border-0 p-0">
|
||||||
<button class="btn border-0 dropdown-toggle w-100" type="button" data-bs-toggle="collapse" data-bs-target="#collapseProductsFilters" aria-expanded="false" aria-controls="collapseExample">
|
<button class="btn dropdown-toggle w-100 border-0" data-bs-toggle="collapse" data-bs-target="#collapseProductsFilters"
|
||||||
|
type="button" aria-expanded="false" aria-controls="collapseExample">
|
||||||
{{ __('Filtres') }}
|
{{ __('Filtres') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-top collapse" id="collapseProductsFilters">
|
<div class="border-top collapse" id="collapseProductsFilters">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form id="searchForm" action="{{ request()->url() }}">
|
<form id="searchForm" action="{{ request()->url() }}">
|
||||||
|
{{-- ALWAYS RESET SEARCH TO PAGE 1 --}}
|
||||||
|
<input name="page" type="hidden" value="1">
|
||||||
<!-- GENERAL INFORMATIONS -->
|
<!-- GENERAL INFORMATIONS -->
|
||||||
<div class="row w-100 mx-auto">
|
<div class="row w-100 mx-auto">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<input name="name" type="text" class="form-control" placeholder="Nom" value="{{ $queryParameters['name'] ?? null }}">
|
<input class="form-control" name="name" type="text" value="{{ request()->get('name') }}"
|
||||||
|
placeholder="Nom">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||||
<select class="form-select" name="brand_id">
|
<select class="form-select" name="brand_id">
|
||||||
<option value="0">{{ __('Marque') }}</option>
|
<option value="">{{ __('Marque') }}</option>
|
||||||
@foreach($brands as $key => $brand)
|
@foreach ($brands as $key => $brand)
|
||||||
<option @if($queryParameters['brand_id'] ?? null == $brand->id) selected @endif value="{{ $brand->id }}">{{ $brand->name }}</option>
|
<option value="{{ $brand->id }}" @if (request()->get('brand_id') == $brand->id) selected @endif>
|
||||||
|
{{ $brand->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<input name="gencod" type="text" class="form-control" placeholder="GENCODE" value="{{ $queryParameters['gencod'] ?? null }}">
|
<input class="form-control" name="gencod" type="text" value="{{ request()->get('gencod') }}"
|
||||||
|
placeholder="GENCOD">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- SOURCE -->
|
<!-- SOURCE -->
|
||||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
{{-- FIXME: Pourquoi dans le modèle il est Set une source, mais dans la recherche 3 champs complémentaire
|
||||||
|
peuvent etre utilisés, dans le modele également => il n'est pas nécessaire de cacher les
|
||||||
|
champs complémentaires dans le formulaire ? --}}
|
||||||
|
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<select class="form-select" name="source">
|
<select class="form-select" name="source">
|
||||||
<option value="0">{{ __('Source') }}</option>
|
<option value="">{{ __('Source') }}</option>
|
||||||
@foreach(\App\Enums\Products\SourceEnum::toArray() as $key => $source)
|
@foreach (\App\Enums\Products\SourceEnum::toArray() as $key => $source)
|
||||||
<option @if(intval($queryParameters['source'] ?? 0) === $source->value) selected @endif value="{{ $source->value }}">{{ $source->label }}</option>
|
<option value="{{ $source->value }}" @if (request()->get('source') == $source->value) selected @endif>
|
||||||
|
{{ $source->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||||
<input name="shop" type="text" class="form-control" placeholder="Magasin" value="{{ $queryParameters['shop'] ?? null }}">
|
<input class="form-control" name="shop" type="text" value="{{ request()->get('shop') }}"
|
||||||
|
placeholder="{{ __('Magasin') }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<input name="fair" type="text" class="form-control" placeholder="Salon" value="{{ $queryParameters['fair'] ?? null }}">
|
<input class="form-control" name="fair" type="text" value="{{ request()->get('fair') }}"
|
||||||
|
placeholder="{{ __('Salon') }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<input name="catalogue" type="text" class="form-control" placeholder="Catalogue" value="{{ $queryParameters['catalogue'] ?? null }}">
|
<input class="form-control" name="catalogue" type="text" value="{{ request()->get('catalogue') }}"
|
||||||
|
placeholder="{{ __('Catalogue') }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- CLAIMS -->
|
<!-- CLAIMS -->
|
||||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
@php
|
|
||||||
$itemsList = collect(\App\Enums\Products\ClaimEnum::toArray())->values();
|
|
||||||
$values = collect($queryParameters['claims'] ?? [])->values();
|
|
||||||
$selectedItemList = collect($itemsList)->filter(fn($claim) =>
|
|
||||||
$values->filter(fn($value) => intval($value['value']) === $claim->value)->count())->values();
|
|
||||||
@endphp
|
|
||||||
@include('partials.inputs.select-multiple-enum', [
|
@include('partials.inputs.select-multiple-enum', [
|
||||||
'id' => 'productsClaim',
|
'id' => 'productsClaim',
|
||||||
'name' => 'claims',
|
'name' => 'claims',
|
||||||
'itemsSelected' => $selectedItemList,
|
'itemsSelected' => collect(request()->get('claims', []))->filter(fn($value) => is_numeric($value)),
|
||||||
'itemsList' => $itemsList,
|
'itemsList' => collect(\App\Enums\Products\ClaimEnum::toArray())->values(),
|
||||||
'itemLimit' => [0, count($itemsList)],
|
'itemLimit' => [0, count(\App\Enums\Products\ClaimEnum::toArray())],
|
||||||
'placeholder' => __('Recherchez une Allégation'),
|
'placeholder' => __('Recherchez une Allégation'),
|
||||||
'simpleComponent' => true,
|
'simpleComponent' => true,
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||||
<input name="specified_claim" type="text" class="form-control" placeholder="Allégation complémentaire" value="{{ $queryParameters['specified_claim'] ?? null }}">
|
<input class="form-control" name="specified_claim" type="text"
|
||||||
|
value="{{ request()->get('specified_claim') }}" placeholder="Allégation complémentaire">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- OTHERS -->
|
<!-- OTHERS -->
|
||||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
@php
|
|
||||||
$itemsList = collect(\App\Enums\Products\OriginEnum::toArray())->values();
|
|
||||||
$values = collect($queryParameters['origins'] ?? [])->values();
|
|
||||||
$selectedItemList = collect($itemsList)->filter(fn($origin) =>
|
|
||||||
$values->filter(fn($value) => intval($value['value']) === $origin->value)->count())->values();
|
|
||||||
@endphp
|
|
||||||
@include('partials.inputs.select-multiple-enum', [
|
@include('partials.inputs.select-multiple-enum', [
|
||||||
'id' => 'productsOrigin',
|
'id' => 'productsOrigin',
|
||||||
'name' => 'origins',
|
'name' => 'origins',
|
||||||
'itemsSelected' => $selectedItemList,
|
'itemsSelected' => collect(request()->get('origins', []))->filter(
|
||||||
'itemsList' => $itemsList,
|
fn($value) => is_numeric($value)),
|
||||||
'itemLimit' => [0, count($itemsList)],
|
'itemsList' => collect(\App\Enums\Products\OriginEnum::toArray())->values(),
|
||||||
|
'itemLimit' => [0, count(\App\Enums\Products\OriginEnum::toArray())],
|
||||||
'placeholder' => __('Recherchez une Origine'),
|
'placeholder' => __('Recherchez une Origine'),
|
||||||
'simpleComponent' => true,
|
'simpleComponent' => true,
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||||
<select class="form-select" name="certification">
|
<select class="form-select" name="certification">
|
||||||
<option value="0">{{ __('Certification') }}</option>
|
<option value="">{{ __('Certification') }}</option>
|
||||||
@foreach(\App\Enums\Products\CertificationEnum::toArray() as $key => $certification)
|
@foreach (\App\Enums\Products\CertificationEnum::toArray() as $key => $certification)
|
||||||
<option @if(intval($queryParameters['certification'] ?? 0) == $certification->value) selected @endif value="{{ $certification->value }}">{{ $certification->label }}</option>
|
<option value="{{ $certification->value }}" @if (request()->get('certification') == $certification->value) selected @endif>
|
||||||
|
{{ $certification->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<select class="form-select" name="distribution_network">
|
<select class="form-select" name="distribution_network">
|
||||||
<option value="0">{{ __('Réseau de distribution') }}</option>
|
<option value="">{{ __('Réseau de distribution') }}</option>
|
||||||
@foreach(\App\Enums\Products\DistributionNetworkEnum::toArray() as $key => $distribution_network)
|
@foreach (\App\Enums\Products\DistributionNetworkEnum::toArray() as $key => $distribution_network)
|
||||||
<option @if(intval($queryParameters['distribution_network'] ?? 0) == $distribution_network->value) selected @endif value="{{ $distribution_network->value }}">{{ $distribution_network->label }}</option>
|
<option value="{{ $distribution_network->value }}"
|
||||||
|
@if (request()->get('distribution_network') == $distribution_network->value) selected @endif>{{ $distribution_network->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<select class="form-select" name="ray">
|
<select class="form-select" name="ray">
|
||||||
<option value="0">{{ __('Rayons') }}</option>
|
<option value="">{{ __('Rayons') }}</option>
|
||||||
@foreach(\App\Enums\Products\RayEnum::toArray() as $key => $ray)
|
@foreach (\App\Enums\Products\RayEnum::toArray() as $key => $ray)
|
||||||
<option @if(intval($queryParameters['ray'] ?? 0) == $ray->value) selected @endif value="{{ $ray->value }}">{{ $ray->label }}</option>
|
<option value="{{ $ray->value }}" @if (request()->get('ray') == $ray->value) selected @endif>
|
||||||
|
{{ $ray->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<select class="form-select" name="product_range">
|
<select class="form-select" name="product_range">
|
||||||
<option value="0">{{ __('Famille de produit') }}</option>
|
<option value="">{{ __('Famille de produit') }}</option>
|
||||||
@foreach(\App\Enums\Products\RangeEnum::toArray() as $key => $product_range)
|
@foreach (\App\Enums\Products\RangeEnum::toArray() as $key => $product_range)
|
||||||
<option @if(intval($queryParameters['product_range'] ?? 0) == $product_range->value) selected @endif value="{{ $product_range->value }}">{{ $product_range->label }}</option>
|
<option value="{{ $product_range->value }}" @if (request()->get('product_range') == $product_range->value) selected @endif>
|
||||||
|
{{ $product_range->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1">
|
<div class="col-12 col-md-6 mt-1">
|
||||||
<select class="form-select" name="geo_area">
|
<select class="form-select" name="geo_area">
|
||||||
<option value="0">{{ __('Secteur') }}</option>
|
<option value="">{{ __('Secteur') }}</option>
|
||||||
@foreach(\App\Enums\Products\GeoAreaEnum::toArray() as $key => $geo_area)
|
@foreach (\App\Enums\Products\GeoAreaEnum::toArray() as $key => $geo_area)
|
||||||
<option @if(intval($queryParameters['geo_area'] ?? 0) == $geo_area->value) selected @endif value="{{ $geo_area->value }}">{{ $geo_area->label }}</option>
|
<option value="{{ $geo_area->value }}" @if (request()->get('product_range') == $geo_area->value) selected @endif>
|
||||||
|
{{ $geo_area->label }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- KEYWORDS -->
|
<!-- KEYWORDS -->
|
||||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
@php
|
@php
|
||||||
$itemsList = collect($keywords)->map(function ($keyword) {
|
$itemsList = collect($keywords)->map(function ($keyword) {
|
||||||
return ["name" => $keyword->keyword_cat->value, "label" => $keyword->label, "value" => $keyword->id];
|
return ['name' => $keyword->keyword_cat->value, 'label' => $keyword->label, 'value' => $keyword->id];
|
||||||
})->values();
|
});
|
||||||
$values = collect($queryParameters['keywords'] ?? [])->values();
|
|
||||||
$selectedItemList = collect($itemsList)->filter(fn($keyword) =>
|
|
||||||
$values->filter(fn($value) => intval($value['value']) === $keyword['value'])->count())->values();
|
|
||||||
@endphp
|
@endphp
|
||||||
@include('partials.inputs.select-multiple-enum', [
|
@include('partials.inputs.select-multiple-enum', [
|
||||||
'id' => 'productsKeywordsn',
|
'id' => 'productsKeywords',
|
||||||
'name' => 'keywords',
|
'name' => 'keywords',
|
||||||
'itemsSelected' => $selectedItemList,
|
'itemsSelected' => collect(request()->get('keywords', []))->filter(
|
||||||
'itemsList' => $itemsList,
|
fn($value) => is_numeric($value)),
|
||||||
'itemLimit' => [0, count($itemsList)],
|
'itemsList' => $itemsList->values(),
|
||||||
'placeholder' => __('Recherchez un mot clé'),
|
'itemLimit' => [0, $itemsList->count()],
|
||||||
|
'placeholder' => __('Recherchez une tendance'),
|
||||||
'simpleComponent' => true,
|
'simpleComponent' => true,
|
||||||
])
|
])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- DATES -->
|
<!-- DATES -->
|
||||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||||
<label class="text-muted fst-italic">{{ __('Saisie après le :') }}</label>
|
<label class="text-muted fst-italic">{{ __('Saisie après le :') }}</label>
|
||||||
<input name="date_before" type="date" class="form-control" value="{{ $queryParameters['date_before'] ?? null }}">
|
<input class="form-control" name="date_after" type="date"
|
||||||
|
value="{{ request()->query('date_after') }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
<div class="col-12 col-md-6">
|
||||||
<label class="text-muted fst-italic">{{ __('Saisie avant le :') }}</label>
|
<label class="text-muted fst-italic">{{ __('Saisie avant le :') }}</label>
|
||||||
<input name="date_after" type="date" class="form-control" value="{{ $queryParameters['date_after'] ?? null }}">
|
<input class="form-control" name="date_before" type="date"
|
||||||
|
value="{{ request()->query('date_before') }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- BUTTONS -->
|
<!-- BUTTONS -->
|
||||||
<div class="d-flex justify-content-center input-group pt-3 mt-3 border-top">
|
<div class="d-flex justify-content-center input-group border-top mt-3 pt-3">
|
||||||
<button type="submit" class="btn btn-primary" data-bs="tooltip" title="{{ __('Lancer la recherche') }}">
|
<button class="btn btn-primary" data-bs="tooltip" type="submit" title="{{ __('Lancer la recherche') }}">
|
||||||
{{ __('Rechercher') }}
|
{{ __('Rechercher') }}
|
||||||
</button>
|
</button>
|
||||||
<a class="p-0" href="{{ request()->url() }}">
|
<a class="p-0" href="{{ request()->url() }}">
|
||||||
<button type="button" data-bs="tooltip" class="btn btn-danger rounded-0 rounded-end"
|
<button class="btn btn-danger rounded-0 rounded-end" data-bs="tooltip" type="button"
|
||||||
title="{{ __('Effacer la recherche') }}">
|
title="{{ __('Effacer la recherche') }}">
|
||||||
<i class="fas fa-backspace"></i>
|
<i class="fas fa-backspace"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
18
resources/views/partials/inputs/bigint-belongs-to.blade.php
Normal file
18
resources/views/partials/inputs/bigint-belongs-to.blade.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
@php
|
||||||
|
$value = old($name) ?? $model->{$name} ?? null;
|
||||||
|
$value = $value ? intval($value) : $value;
|
||||||
|
$data = [
|
||||||
|
'name' => $name,
|
||||||
|
'value' => $value,
|
||||||
|
'labelField' => $labelField,
|
||||||
|
'itemLimit' => $itemLimit,
|
||||||
|
'itemsList' => $itemsList,
|
||||||
|
'storeRoute' => $storeRoute ?? null,
|
||||||
|
'placeholder' => $placeholder,
|
||||||
|
'errors' => $errors->getBag('default')->getMessages(),
|
||||||
|
'label' => $label,
|
||||||
|
'require' => $require
|
||||||
|
];
|
||||||
|
@endphp
|
||||||
|
<div class="belongs-to-dropdown" data-json='@json($data)'></div>
|
||||||
|
@include('modules.input-error', ['helper' => $helper, 'inputName' => $name])
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }} *</b></label>
|
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }} *</b></label>
|
||||||
@endif
|
@endif
|
||||||
<select id="{{ $name }}" class="form-select" name="{{ $name }}" aria-describedby="{{ $id }}Help" @if(!empty($label))required @endif>
|
<select id="{{ $name }}" class="form-select" name="{{ $name }}" aria-describedby="{{ $id }}Help" @if(!empty($label))required @endif>
|
||||||
|
<option value="0" @if (!old($name, $model->{$name}->id ?? $value ?? null)) selected @endif>
|
||||||
|
</option>
|
||||||
@foreach ($associatedModels as $associatedModel)
|
@foreach ($associatedModels as $associatedModel)
|
||||||
<option value="{{ $associatedModel->id }}" @if (old($name, $model->{$name} ?? 1) == $associatedModel->id) selected @endif>
|
<option value="{{ $associatedModel->id }}" @if (old($name, $model->{$name} ?? $value ?? null) == $associatedModel->id) selected @endif>
|
||||||
{{ $associatedModel->name }}
|
{{ $associatedModel->name }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,14 @@
|
||||||
id="{{ $id }}"
|
id="{{ $id }}"
|
||||||
name="{{ $name }}"
|
name="{{ $name }}"
|
||||||
type="number"
|
type="number"
|
||||||
value="{{ old($name, $model->{$name} ?? 0) }}"
|
value="{{ old($name, $model->{$name} ?? $value ?? null) }}"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
aria-describedby="{{ $id }}Help"
|
aria-describedby="{{ $id }}Help"
|
||||||
|
@if(!empty($step))
|
||||||
|
step="{{ $step }}"
|
||||||
|
@else
|
||||||
step="1"
|
step="1"
|
||||||
|
@endif
|
||||||
@if(!empty($max))
|
@if(!empty($max))
|
||||||
max="{{ $max }}"
|
max="{{ $max }}"
|
||||||
@else
|
@else
|
||||||
|
|
@ -22,6 +26,8 @@
|
||||||
min="{{ !empty($unsigned) ? '0' : '-2147483648' }}"
|
min="{{ !empty($unsigned) ? '0' : '-2147483648' }}"
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($required))required @endif
|
@if(!empty($required))required @endif
|
||||||
|
@if(!empty($disabled))disabled @endif
|
||||||
|
@if(!empty($readonly))readonly @endif
|
||||||
>
|
>
|
||||||
@include('modules.input-error', [
|
@include('modules.input-error', [
|
||||||
'inputName' => $name,
|
'inputName' => $name,
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }}@if(!empty($required)) * @endif</b></label>
|
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }}@if(!empty($required)) * @endif</b></label>
|
||||||
@endif
|
@endif
|
||||||
<select id="{{ $name }}" class="form-select" name="{{ $name }}" aria-describedby="{{ $id }}Help" @if(!empty($require))required @endif>
|
<select id="{{ $name }}" class="form-select" name="{{ $name }}" aria-describedby="{{ $id }}Help" @if(!empty($require))required @endif>
|
||||||
|
<option value="0" @if (!old($name, $model->{$name}->value ?? $value ?? null)) selected @endif>
|
||||||
|
</option>
|
||||||
@foreach ($associatedModels as $associatedModel)
|
@foreach ($associatedModels as $associatedModel)
|
||||||
<option value="{{ $associatedModel->value}}" @if (old($name, $model->{$name}->value ?? $value ?? 1) == $associatedModel->value) selected @endif>
|
<option value="{{ $associatedModel->value}}" @if (old($name, $model->{$name}->value ?? $value ?? null) == $associatedModel->value) selected @endif>
|
||||||
{{ $associatedModel->label }}
|
{{ $associatedModel->label }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\BrandController;
|
||||||
use App\Http\Controllers\DashboardController;
|
use App\Http\Controllers\DashboardController;
|
||||||
use App\Http\Controllers\ProductController;
|
use App\Http\Controllers\ProductController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
@ -9,6 +10,10 @@ Route::get('/', [DashboardController::class, 'show'])->name('dashboard');
|
||||||
|
|
||||||
// * PRODUCTS
|
// * PRODUCTS
|
||||||
Route::resource('products', ProductController::class)->except(['show']);
|
Route::resource('products', ProductController::class)->except(['show']);
|
||||||
|
|
||||||
|
// * BRANDS
|
||||||
|
Route::resource('brands', BrandController::class)->only(['store']);
|
||||||
|
|
||||||
Route::prefix('/product')
|
Route::prefix('/product')
|
||||||
->name('products.')
|
->name('products.')
|
||||||
->group(function () {
|
->group(function () {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
import legacy from "@vitejs/plugin-legacy";
|
||||||
|
import vue from "@vitejs/plugin-vue";
|
||||||
|
import laravel from "laravel-vite-plugin";
|
||||||
|
import path from "path";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import checker from "vite-plugin-checker";
|
import checker from "vite-plugin-checker";
|
||||||
import eslint from "vite-plugin-eslint";
|
import eslint from "vite-plugin-eslint";
|
||||||
import laravel from "laravel-vite-plugin";
|
|
||||||
import legacy from "@vitejs/plugin-legacy";
|
|
||||||
import path from "path";
|
|
||||||
import stylelint from "vite-plugin-stylelint";
|
import stylelint from "vite-plugin-stylelint";
|
||||||
import vue from "@vitejs/plugin-vue";
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
|
|
@ -41,6 +41,7 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
checker({
|
checker({
|
||||||
|
enableBuild: true,
|
||||||
vueTsc: {
|
vueTsc: {
|
||||||
root: ".",
|
root: ".",
|
||||||
tsconfigPath: "tsconfig.json",
|
tsconfigPath: "tsconfig.json",
|
||||||
|
|
@ -74,7 +75,7 @@ export default defineConfig({
|
||||||
"**/vendor/**/*.scss",
|
"**/vendor/**/*.scss",
|
||||||
"**/vendor/**/*.css",
|
"**/vendor/**/*.css",
|
||||||
],
|
],
|
||||||
lintOnStart: true,
|
lintOnStart: false,
|
||||||
emitError: true,
|
emitError: true,
|
||||||
emitWarning: true,
|
emitWarning: true,
|
||||||
emitErrorAsWarning: false,
|
emitErrorAsWarning: false,
|
||||||
|
|
@ -84,7 +85,7 @@ export default defineConfig({
|
||||||
cache: false,
|
cache: false,
|
||||||
extensions: ["js", "ts"],
|
extensions: ["js", "ts"],
|
||||||
include: "**/*.ts",
|
include: "**/*.ts",
|
||||||
lintOnStart: true,
|
lintOnStart: false,
|
||||||
emitWarning: true,
|
emitWarning: true,
|
||||||
emitError: true,
|
emitError: true,
|
||||||
failOnWarning: false,
|
failOnWarning: false,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue