Compare commits
5 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69f3849350 | ||
|
|
351840db4c | ||
|
|
7579c7eb5b | ||
|
|
bcb6fd1709 | ||
|
|
a6de982ef1 |
92 changed files with 1497 additions and 3973 deletions
22
.vscode/settings.json
vendored
22
.vscode/settings.json
vendored
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"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,18 +9,14 @@ class Kernel extends ConsoleKernel
|
|||
{
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
<?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;
|
||||
|
||||
enum CertificationEnum: int
|
||||
enum CertificationEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
@ -12,8 +12,8 @@ enum CertificationEnum: int
|
|||
case labelRouge = 2;
|
||||
case certifiedCQ = 3;
|
||||
case standard = 4;
|
||||
case freeRange = 6;
|
||||
case others = 5;
|
||||
case freeRange = 5;
|
||||
case others = 6;
|
||||
|
||||
/**
|
||||
* Custom added functions definition
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum ClaimEnum: int
|
||||
enum ClaimEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum DistributionNetworkEnum: int
|
||||
enum DistributionNetworkEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum GeoAreaEnum: int
|
||||
enum GeoAreaEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum OriginEnum: int
|
||||
enum OriginEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum RangeEnum: int
|
||||
enum RangeEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
@ -18,9 +18,9 @@ enum RangeEnum: int
|
|||
case rawMeat = 8;
|
||||
case cookedMeats = 9;
|
||||
case farcis = 10;
|
||||
case plant = 12;
|
||||
case frozenSpecific = 13;
|
||||
case others = 11;
|
||||
case plant = 11;
|
||||
case frozenSpecific = 12;
|
||||
case others = 13;
|
||||
|
||||
/**
|
||||
* Custom added functions definition
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum RayEnum: int
|
||||
enum RayEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,24 +4,17 @@ namespace App\Enums\Products;
|
|||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum SourceEnum: int
|
||||
enum SourceEnum : int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
// * Catalogue argumentaire
|
||||
case catalogArgumentary = 7;
|
||||
// * Magasin
|
||||
case magazin = 1;
|
||||
// * Presse
|
||||
case press = 3;
|
||||
// * Salon Grand Public
|
||||
case showConsumer = 6;
|
||||
// * Salon Clients
|
||||
case showCustomer = 5;
|
||||
// * Salon Professionnel
|
||||
case showTrade = 4;
|
||||
// * Web
|
||||
case web = 2;
|
||||
case catalogArgumentary = 1;
|
||||
case magazin = 2;
|
||||
case press = 3;
|
||||
case showConsumer = 4;
|
||||
case showCustomer = 5;
|
||||
case showTrade = 6;
|
||||
case web = 7;
|
||||
|
||||
/**
|
||||
* Custom added functions definition
|
||||
|
|
|
|||
|
|
@ -12,14 +12,16 @@ class Handler extends ExceptionHandler
|
|||
*
|
||||
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
||||
*/
|
||||
protected $levels = [];
|
||||
protected $levels = [
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of the exception types that are not reported.
|
||||
*
|
||||
* @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.
|
||||
|
|
@ -34,8 +36,6 @@ class Handler extends ExceptionHandler
|
|||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
<?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,18 +2,13 @@
|
|||
|
||||
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\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
|
@ -127,26 +122,4 @@ class Controller extends BaseController
|
|||
}
|
||||
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,7 +3,6 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Products\IndexFilterRequest;
|
||||
use App\Http\Requests\Products\StoreProductRequest;
|
||||
use App\Http\Requests\Products\UpdateProductRequest;
|
||||
use App\Jobs\ExportProduct;
|
||||
|
|
@ -13,7 +12,6 @@ use App\Models\Product;
|
|||
use App\Traits\Controllers\HasDocuments;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
@ -24,54 +22,99 @@ class ProductController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Http\Requests\Products\IndexFilterRequest $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(IndexFilterRequest $request)
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
||||
$brandsQuery = Brand::query();
|
||||
$brands = Brand::get();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $productsQuery */
|
||||
$productsQuery = Product::query()->orderBy('created_at', 'desc');
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $products */
|
||||
$products = Product::query();
|
||||
|
||||
$this->requestFilters($request, $productsQuery);
|
||||
$this->requestFilters($products, $request);
|
||||
|
||||
$this->sortQuery($productsQuery);
|
||||
$this->sortQuery($products);
|
||||
|
||||
$products = $this->paginate($productsQuery);
|
||||
$products = $products->paginate(10);
|
||||
|
||||
/** @var array $printMultiProduct Array of id */
|
||||
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||
|
||||
$brands = $brandsQuery->get();
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
||||
$brands = Brand::get();
|
||||
|
||||
$keywords = Keyword::query()->where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $keyword */
|
||||
$keywords = Keyword::where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||
|
||||
return view('pages.products.index', [
|
||||
'products' => $products,
|
||||
'brands' => $brands,
|
||||
'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.
|
||||
*
|
||||
* @param App\Models\Product $productModel
|
||||
* @param Illuminate\Support\Collection $commentModel
|
||||
* @param App\Models\Product $productModel
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
* phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function create(Product $productModel, Collection $commentModel): \Illuminate\Contracts\View\View
|
||||
public function create(Product $productModel): \Illuminate\Contracts\View\View
|
||||
{
|
||||
//phpcs:enable
|
||||
$brands = Brand::all();
|
||||
$productsFair = Product::query()->pluck('fair');
|
||||
$productsShop = Product::query()->pluck('shop');
|
||||
$productsCatalog = Product::query()->pluck('catalogue');
|
||||
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||
$brands = Brand::get();
|
||||
$productsFair = Product::pluck('fair');
|
||||
$productsShop = Product::pluck('shop');
|
||||
$productsCatalog = Product::pluck('catalogue');
|
||||
$keywords = Keyword::where('keyword_cat', 'product_pleasure')
|
||||
->orWhere('keyword_cat', 'product_shape')
|
||||
->orWhere('keyword_cat', 'product_practicality')
|
||||
->orWhere('keyword_cat', 'product_health')
|
||||
|
|
@ -84,8 +127,7 @@ class ProductController extends Controller
|
|||
'productsFair',
|
||||
'productsShop',
|
||||
'productsCatalog',
|
||||
'keywords',
|
||||
'commentModel'
|
||||
'keywords'
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -128,12 +170,12 @@ class ProductController extends Controller
|
|||
*/
|
||||
public function edit(Product $product)
|
||||
{
|
||||
$brands = Brand::all();
|
||||
$productsFair = Product::query()->pluck('fair');
|
||||
$productsShop = Product::query()->pluck('shop');
|
||||
$productsCatalog = Product::query()->pluck('catalogue');
|
||||
$brands = Brand::get();
|
||||
$productsFair = Product::pluck('fair');
|
||||
$productsShop = Product::pluck('shop');
|
||||
$productsCatalog = Product::pluck('catalogue');
|
||||
$commentModel = $product->productComments;
|
||||
$keywords = Keyword::query()->where('keyword_cat', 'product_pleasure')
|
||||
$keywords = Keyword::where('keyword_cat', 'product_pleasure')
|
||||
->orWhere('keyword_cat', 'product_shape')
|
||||
->orWhere('keyword_cat', 'product_practicality')
|
||||
->orWhere('keyword_cat', 'product_health')
|
||||
|
|
@ -258,11 +300,7 @@ class ProductController extends Controller
|
|||
*/
|
||||
public function duplicate(Product $product)
|
||||
{
|
||||
$duplicatedProduct = $product->replicate();
|
||||
foreach ($product->productComments as $comment) {
|
||||
$duplicatedComments[] = $comment->replicate();
|
||||
}
|
||||
return $this->create($duplicatedProduct, collect($duplicatedComments ?? null));
|
||||
return $this->create($product->replicate());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -274,20 +312,20 @@ class ProductController extends Controller
|
|||
public function checkGencode(Request $request)
|
||||
{
|
||||
if (
|
||||
isset($request->GENCOD) &&
|
||||
$request->GENCOD !== null &&
|
||||
ctype_digit($request->GENCOD) &&
|
||||
strlen($request->GENCOD) > 0
|
||||
isset($request->GENCODE) &&
|
||||
$request->GENCODE !== null &&
|
||||
ctype_digit($request->GENCODE) &&
|
||||
strlen($request->GENCODE) > 0
|
||||
) {
|
||||
if (
|
||||
isset($request->ID) &&
|
||||
$request->ID !== null &&
|
||||
intval($request->GENCOD) === Product::where('id', $request->ID)->firstOrFail()->gencod
|
||||
intval($request->GENCODE) === Product::where('id', $request->ID)->firstOrFail()->gencod
|
||||
) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = in_array(intval($request->GENCOD), Product::pluck('gencod')->toArray()) ?
|
||||
Product::orderBy('created_at', 'desc')->where('gencod', intval($request->GENCOD))->first() : null;
|
||||
$result = in_array(intval($request->GENCODE), Product::pluck('gencod')->toArray()) ?
|
||||
Product::orderBy('created_at', 'desc')->where('gencod', intval($request->GENCODE))->first() : null;
|
||||
}
|
||||
} else {
|
||||
$result = null;
|
||||
|
|
@ -325,7 +363,6 @@ class ProductController extends Controller
|
|||
*/
|
||||
public function printMultiProductSheet()
|
||||
{
|
||||
// FIXME: This should not use session.
|
||||
/** @var array printMultiProduct */
|
||||
$printMultiProduct = session('printMultiProduct') ?? [];
|
||||
asort($printMultiProduct);
|
||||
|
|
@ -390,62 +427,4 @@ class ProductController extends Controller
|
|||
{
|
||||
\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>
|
||||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustHosts::class,
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ class Authenticate extends Middleware
|
|||
{
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
|
@ -12,15 +13,10 @@ class RedirectIfAuthenticated
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @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
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
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;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ class ValidateSignature extends Middleware
|
|||
* The names of the query string parameters that should be ignored.
|
||||
*
|
||||
* @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',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
<?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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
<?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\SourceEnum;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Requests\HasDocumentAndPictureList;
|
||||
use App\Traits\Requests\HasDocument;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
|
@ -20,7 +20,7 @@ use Illuminate\Validation\ValidationException;
|
|||
class StoreProductRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
use HasDocumentAndPictureList;
|
||||
use HasDocument;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
|
|
@ -44,9 +44,6 @@ class StoreProductRequest extends FormRequest
|
|||
'is_tasted' => $this->is_tasted ? true : false,
|
||||
'origins' => $this->origins ? $this->origins : [],
|
||||
'claims' => $this->claims ? $this->claims : [],
|
||||
'picture_alt' => $this->name,
|
||||
'picture_title' => $this->name,
|
||||
'certification' => $this->certification == 0 ? null : $this->certification,
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
$this->mergeDocuments('docs');
|
||||
|
|
@ -63,9 +60,9 @@ class StoreProductRequest extends FormRequest
|
|||
'name' => 'required|string|min:3|max:255',
|
||||
'brand_id' => 'required|exists:brands,id',
|
||||
'source' => [new Enum(SourceEnum::class)],
|
||||
'fair' => 'nullable|string|min:3|max:255',
|
||||
'shop' => 'nullable|string|min:3|max:255',
|
||||
'catalogue' => 'nullable|string|min:3|max:255',
|
||||
'fair' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::showConsumer->value . ',' . SourceEnum::showCustomer->value . ',' . SourceEnum::showTrade->value,
|
||||
'shop' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::magazin->value,
|
||||
'catalogue' => 'nullable|string|min:3|max:255|required_if:source,' . SourceEnum::catalogArgumentary->value,
|
||||
'gencod' => 'nullable|numeric|min:0',
|
||||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
|
|
@ -79,17 +76,19 @@ class StoreProductRequest extends FormRequest
|
|||
}
|
||||
],
|
||||
'certification' => ['nullable', new Enum(CertificationEnum::class)],
|
||||
'origins' => 'present|array',
|
||||
'origins.*' => [new Enum(OriginEnum::class)],
|
||||
'claims' => 'present|array',
|
||||
'claims.*' => [new Enum(ClaimEnum::class)],
|
||||
'origins' => 'nullable|array',
|
||||
'origins.*' => 'present|array',
|
||||
'origins.*.id' => [new Enum(OriginEnum::class)],
|
||||
'claims' => 'nullable|array',
|
||||
'claims.*' => 'present|array',
|
||||
'claims.*.id' => [new Enum(ClaimEnum::class)],
|
||||
'specified_claim' => 'string|min:3|max:255|required_if:claims,' . ClaimEnum::others->value,
|
||||
'distribution_network' => ['required', new Enum(DistributionNetworkEnum::class)],
|
||||
'ray' => ['required', new Enum(RayEnum::class)],
|
||||
'product_range' => ['required', new Enum(RangeEnum::class)],
|
||||
'geo_area' => ['required', new Enum(GeoAreaEnum::class)],
|
||||
'weight' => 'nullable|integer',
|
||||
'pvc' => 'nullable|decimal:0,2',
|
||||
'pvc' => 'nullable|integer',
|
||||
'comment' => 'nullable|string|min:15',
|
||||
'is_tasted' => 'required|boolean',
|
||||
'tasters_number' => 'nullable|integer',
|
||||
|
|
@ -107,7 +106,7 @@ class StoreProductRequest extends FormRequest
|
|||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', false, 1200, 900, 1200, 900),
|
||||
$this->documentsRules('docs'),
|
||||
$this->documentsRules('docs', false),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Enums\Products\CertificationEnum;
|
||||
use App\Enums\Products\ClaimEnum;
|
||||
use App\Enums\Products\OriginEnum;
|
||||
use App\Models\Keyword;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductComment;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductResource extends JsonResource
|
||||
|
|
@ -17,8 +19,8 @@ class ProductResource extends JsonResource
|
|||
/** @var array */
|
||||
private static $skeleton = [
|
||||
'id' => null,
|
||||
'user' => null,
|
||||
'brand' => null,
|
||||
'user_id' => null,
|
||||
'brand_id' => null,
|
||||
'name' => null,
|
||||
'seen_at' => null,
|
||||
'source' => null,
|
||||
|
|
@ -34,7 +36,6 @@ class ProductResource extends JsonResource
|
|||
'certification' => null,
|
||||
'origins' => null,
|
||||
'claims' => null,
|
||||
'specified_claim' => null,
|
||||
'distribution_network' => null,
|
||||
'ray' => null,
|
||||
'product_range' => null,
|
||||
|
|
@ -64,13 +65,54 @@ class ProductResource extends JsonResource
|
|||
*/
|
||||
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(
|
||||
[
|
||||
'id' => $this->product->id,
|
||||
'user' => (object)$this->product->user->toArray(),
|
||||
'brand' => (object)$this->product->brand->toArray(),
|
||||
'user_id' => User::where('id', $this->product->user_id)->firstOrFail(),
|
||||
'brand_id' => Brand::where('id', $this->product->brand_id)->firstOrFail(),
|
||||
'name' => $this->product->name,
|
||||
'seen_at' => $this->product->seen_at->isoFormat('DD\/MM\/YYYY'),
|
||||
'seen_at' => Carbon::createFromFormat('Y-m-d H:i:s', $this->product->seen_at)->format('d/m/Y'),
|
||||
'source' => $this->product->source->label(),
|
||||
'fair' => $this->product->fair,
|
||||
'shop' => $this->product->shop,
|
||||
|
|
@ -81,25 +123,16 @@ class ProductResource extends JsonResource
|
|||
'picture' => $this->product->picture,
|
||||
'picture_alt' => $this->product->picture_alt,
|
||||
'picture_title' => $this->product->picture_title,
|
||||
'certification' => \optional($this->product->certification)->label(),
|
||||
'origins' => $this->product->origins_enum->map(fn (OriginEnum $enum) => $enum->label())->implode(', '),
|
||||
'claims' => $this->product->claims_enum->map(fn (ClaimEnum $enum) => $enum->label())->implode(', '),
|
||||
'specified_claim' => $this->product->specified_claim,
|
||||
'certification' => $certification,
|
||||
'origins' => $origins ?? null,
|
||||
'claims' => $claims ?? null,
|
||||
'distribution_network' => $this->product->distribution_network->label(),
|
||||
'ray' => $this->product->ray->label(),
|
||||
'product_range' => $this->product->product_range->label(),
|
||||
'geo_area' => $this->product->geo_area->label(),
|
||||
'freeComment' => $this->product->comment,
|
||||
// FIXME: Use dedicaced resources for relations.
|
||||
'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(', '),
|
||||
'productComments' => $this->product->productComments,
|
||||
'productKeywords' => $productKeywords ?? null,
|
||||
],
|
||||
$this->getSkeleton()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ class ExportProduct implements ShouldQueue
|
|||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @param integer $productId
|
||||
* @return void
|
||||
* @throws \Error If file storage config is wrong.
|
||||
* @throws \RuntimeException If the storage disk export is not local file system.
|
||||
|
|
@ -51,10 +50,7 @@ class ExportProduct implements ShouldQueue
|
|||
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)) {
|
||||
throw new \RuntimeException("The folder cannot be created inside the ZIP.");
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
|
@ -139,15 +140,75 @@ class ToolboxHelper
|
|||
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
|
||||
* @param string|array $search
|
||||
* @param string|array $replace
|
||||
* @param mixed $subject
|
||||
* @param integer $count
|
||||
* @param mixed $search
|
||||
* @param mixed $replace
|
||||
* @param mixed $subject
|
||||
* @param integer $count
|
||||
* @return mixed
|
||||
*/
|
||||
public static function mbReplace(string|array $search, string|array $replace, mixed $subject, int &$count = 0)
|
||||
public static function mbReplace($search, $replace, $subject, int &$count = 0)
|
||||
{
|
||||
if (!is_array($search) && is_array($replace)) {
|
||||
return false;
|
||||
|
|
@ -192,7 +253,7 @@ class ToolboxHelper
|
|||
public static function assertFieldIsUnique(
|
||||
string $table,
|
||||
string $field,
|
||||
mixed $value,
|
||||
$value,
|
||||
?int $id = null,
|
||||
?callable $query = null
|
||||
) {
|
||||
|
|
@ -227,22 +288,4 @@ class ToolboxHelper
|
|||
{
|
||||
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 string $name
|
||||
* @property string $brand
|
||||
* @property string $filter
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
* @property \App\Enums\KeywordCategoryEnum $keyword_cat
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*
|
||||
* * RELATIONSHIPS
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Product> $products
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Keyword> $keywordables
|
||||
* @property Keywordable[] $keywordables
|
||||
*/
|
||||
class Keyword extends Model
|
||||
{
|
||||
|
|
@ -37,8 +34,6 @@ class Keyword extends Model
|
|||
'keyword_cat' => KeywordCategoryEnum::class
|
||||
];
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
namespace App\Models;
|
||||
|
||||
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;
|
||||
|
|
@ -15,53 +13,43 @@ use App\Lib\Helpers\FileStorageHelper;
|
|||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
/**
|
||||
* FIXME: using migration, do not set nullable props without a real need.
|
||||
*
|
||||
* @property integer $id
|
||||
* @property integer $user_id
|
||||
* @property integer $brand_id
|
||||
* @property string $name
|
||||
* @property \Carbon\Carbon $seen_at
|
||||
* @property \App\Enums\Products\SourceEnum $source
|
||||
* @property string|null $fair
|
||||
* @property string|null $shop
|
||||
* @property string|null $catalogue
|
||||
* @property string|null $gencod
|
||||
* @property string|null $picture
|
||||
* @property string $picture_alt
|
||||
* @property string $picture_title
|
||||
* @property array|null $docs
|
||||
* @property string|null $url
|
||||
* @property \App\Enums\Products\CertificationEnum|null $certification
|
||||
* @property array<integer>|null $origins
|
||||
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $origins_enum
|
||||
* @property array<integer>|null $claims
|
||||
* @property \Illuminate\Support\Collection<\App\Enums\Products\OriginEnum> $claims_enum
|
||||
* @property string|null $specified_claim
|
||||
* @property \App\Enums\Products\DistributionNetworkEnum $distribution_network
|
||||
* @property \App\Enums\Products\RayEnum $ray
|
||||
* @property \App\Enums\Products\RangeEnum $product_range
|
||||
* @property \App\Enums\Products\GeoAreaEnum $geo area
|
||||
* @property integer|null $weight
|
||||
* @property integer|null $pvc
|
||||
* @property string|null $comment
|
||||
* @property boolean $is_tasted
|
||||
* @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
|
||||
* @property integer $id
|
||||
* @property integer $user_id
|
||||
* @property integer $brand_id
|
||||
* @property string $name
|
||||
* @property string $brand
|
||||
* @property string $seen_at
|
||||
* @property enum $source
|
||||
* @property string $fair
|
||||
* @property string $shop
|
||||
* @property string $catalogue
|
||||
* @property string $gencod
|
||||
* @property string $picture
|
||||
* @property array $docs
|
||||
* @property string $url
|
||||
* @property enum $certification
|
||||
* @property object $origins
|
||||
* @property object $claims
|
||||
* @property string $specified_claim
|
||||
* @property enum $distribution_network
|
||||
* @property enum $ray
|
||||
* @property enum $product_range
|
||||
* @property enum $geo area
|
||||
* @property integer $weight
|
||||
* @property integer $pvc
|
||||
* @property string $comment
|
||||
* @property boolean $is_tasted
|
||||
* @property integer $tasters_number
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
* @property string $deleted_at
|
||||
* @property ProductComment[] $productComments
|
||||
* @property User $user
|
||||
*/
|
||||
class Product extends Model
|
||||
{
|
||||
|
|
@ -121,10 +109,10 @@ class Product extends Model
|
|||
'product_range' => RangeEnum::class,
|
||||
'geo_area' => GeoAreaEnum::class,
|
||||
'is_tasted' => 'boolean',
|
||||
'seen_at' => 'datetime',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
'seen_at' => 'datetime:Y-m-d',
|
||||
'created_at' => 'datetime:Y-m-d',
|
||||
'updated_at' => 'datetime:Y-m-d',
|
||||
'deleted_at' => 'datetime:Y-m-d',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
|
@ -144,7 +132,7 @@ class Product extends Model
|
|||
$model->user_id = 1;
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::deleteOldDocuments($model, true);
|
||||
self::deleteOldDocuments($model);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
self::updateSource($model);
|
||||
self::updateSpecifiedClaim($model);
|
||||
|
|
@ -183,11 +171,8 @@ class Product extends Model
|
|||
*/
|
||||
private static function updateSpecifiedClaim(Product $model)
|
||||
{
|
||||
$check = false;
|
||||
foreach ($model->claims as $claimValue) {
|
||||
if (!$check) {
|
||||
$check = (intval($claimValue) === \App\Enums\Products\ClaimEnum::others->value) ? true : false;
|
||||
}
|
||||
foreach ($model->claims as $claim) {
|
||||
$check = (intval($claim['id']) === \App\Enums\Products\ClaimEnum::others->value) ? true : false;
|
||||
}
|
||||
$model->specified_claim = ($check) ? $model->specified_claim : null;
|
||||
}
|
||||
|
|
@ -223,23 +208,15 @@ class Product extends Model
|
|||
/**
|
||||
* Delete old documents.
|
||||
*
|
||||
* @param self $model
|
||||
* @param boolean $onlyIfUpdated
|
||||
* @param self $model
|
||||
* @return void
|
||||
*/
|
||||
public static function deleteOldDocuments(self $model, bool $onlyIfUpdated = false)
|
||||
public static function deleteOldDocuments(self $model)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
foreach ($model->getOriginal('docs') as $document) {
|
||||
$originalPath = \ltrim(\urldecode($document), '/');
|
||||
if (\strpos($originalPath, 'storage') !== 0) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
||||
if (Storage::disk('public')->exists($originalPath)) {
|
||||
|
|
@ -306,27 +283,26 @@ class Product extends Model
|
|||
/**
|
||||
* Generate a pdf with multiple products.
|
||||
*
|
||||
* @param array<integer> $printMultiProduct
|
||||
* @param string $title
|
||||
* @param array $printMultiProduct
|
||||
* @param string $title
|
||||
* @return \Mccarlosen\LaravelMpdf\LaravelMpdf
|
||||
*/
|
||||
public static function generateMultipleProductPdf(array $printMultiProduct, string $title)
|
||||
{
|
||||
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf|null */
|
||||
/** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */
|
||||
$pdf = null;
|
||||
// * Loop all Model ids.
|
||||
// Loop all views.
|
||||
foreach ($printMultiProduct as $productId) {
|
||||
/** @var \App\Models\Product */
|
||||
$product = Product::query()->where('id', $productId)->firstOrFail();
|
||||
// * If not yet defined, set the first page.
|
||||
$product = Product::where('id', $productId)->firstOrFail();
|
||||
// If not yet defined, set the first page.
|
||||
if (is_null($pdf)) {
|
||||
$pdf = Product::generateProductPdf($product, $title);
|
||||
} 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()->WriteHTML((string)view(
|
||||
'documents.product-body',
|
||||
['product' => (object)(new ProductResource($product))->toArray()],
|
||||
['product' => \json_decode(\json_encode(new ProductResource($product)))],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -364,64 +340,14 @@ class Product extends Model
|
|||
])->send();
|
||||
}
|
||||
|
||||
// * 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
|
||||
// * RELATIONS
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function productComments()
|
||||
{
|
||||
return $this->hasMany(ProductComment::class);
|
||||
return $this->hasMany('App\Models\ProductComment');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -429,7 +355,7 @@ class Product extends Model
|
|||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
return $this->belongsTo('App\Models\User');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -437,7 +363,7 @@ class Product extends Model
|
|||
*/
|
||||
public function brand()
|
||||
{
|
||||
return $this->belongsTo(Brand::class);
|
||||
return $this->belongsTo('App\Models\Brand');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,18 +6,16 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property integer $id
|
||||
* @property integer $product_id
|
||||
* @property string $evaluation
|
||||
* @property string|null $aspect
|
||||
* @property string|null $taste
|
||||
* @property string|null $odor
|
||||
* @property string|null $texture
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*
|
||||
* * RELATIONSHIPS
|
||||
* @property-read \App\Models\Product $product
|
||||
* @property integer $id
|
||||
* @property integer $product_id
|
||||
* @property string $evaluation
|
||||
* @property string $aspect
|
||||
* @property string $taste
|
||||
* @property string $odor
|
||||
* @property string $texture
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
* @property Product $product
|
||||
*/
|
||||
class ProductComment extends Model
|
||||
{
|
||||
|
|
@ -37,23 +35,11 @@ class ProductComment extends Model
|
|||
'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
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
return $this->belongsTo('App\Models\Product');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ class AppServiceProvider extends ServiceProvider
|
|||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
|
|
@ -27,7 +25,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
return request()->getClientIp();
|
||||
} else {
|
||||
return request()->server('HTTP_X_FORWARDED_FOR') ??
|
||||
request()->getClientIp();
|
||||
request()->getClientIp();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
// use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
|
|
@ -11,12 +12,12 @@ class AuthServiceProvider extends ServiceProvider
|
|||
*
|
||||
* @var array<class-string, class-string>
|
||||
*/
|
||||
protected $policies = [];
|
||||
protected $policies = [
|
||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register any authentication / authorization services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class EventServiceProvider extends ServiceProvider
|
|||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
|
|
@ -29,7 +28,6 @@ class EventServiceProvider extends ServiceProvider
|
|||
|
||||
/**
|
||||
* Determine if events and listeners should be automatically discovered.
|
||||
* @return boolean
|
||||
*/
|
||||
public function shouldDiscoverEvents(): bool
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ trait HasDocuments
|
|||
*/
|
||||
private function storeDocuments(Request $request, Model $model): void
|
||||
{
|
||||
$model->docs = [];
|
||||
$model->docs = collect($request->docs)
|
||||
->map(function ($document) use ($model) {
|
||||
return FileStorageHelper::storeFile($model, $document);
|
||||
})->all();
|
||||
if (is_array($request->docs)) {
|
||||
$model->docs = [];
|
||||
$model->docs = collect($request->docs)
|
||||
->map(function ($document) use ($model) {
|
||||
return FileStorageHelper::storeFile($model, $document);
|
||||
})->all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,43 +4,24 @@ namespace App\Traits\Requests;
|
|||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait HasDocumentAndPictureList
|
||||
trait HasDocument
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $name
|
||||
* @param boolean $required
|
||||
* @return array
|
||||
*/
|
||||
public function documentsRules(
|
||||
string $name = 'docs',
|
||||
string $name = 'documents',
|
||||
?bool $required = null
|
||||
): array {
|
||||
return [
|
||||
"{$name}" => 'present|array',
|
||||
"{$name}" => ($required ? 'required' : 'nullable') . '|array',
|
||||
"{$name}.*" => [
|
||||
'required',
|
||||
$required ? 'required' : 'nullable',
|
||||
function (string $attribute, $value, callable $fail) {
|
||||
return $this->validateDocument($attribute, $value, $fail);
|
||||
}
|
||||
|
|
@ -57,36 +38,32 @@ trait HasDocumentAndPictureList
|
|||
* @return void
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
*/
|
||||
private function validateDocument(string $attribute, mixed $value, callable $fail)
|
||||
private function validateDocument(string $attribute, $value, callable $fail)
|
||||
{
|
||||
// phpcs:enable
|
||||
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||
return;
|
||||
}
|
||||
if (!\in_array($this->getUploadedFileMimeType($value, $useStorage), $this->autorisedMimTypes)) {
|
||||
$fail(trans(':attribute doit être un document de type :mimetypes', [
|
||||
'mimetypes' => Str::of($this->autorisedMimTypes)->implode(' ou ')
|
||||
]));
|
||||
}
|
||||
$maxSize = 6 * 1024 * 1024;
|
||||
if (File::size($value) > $maxSize) {
|
||||
$fail(trans(':attribute doit être inférieur à :size Mo', ['size' => $maxSize / (1024 * 1024)]));
|
||||
if (
|
||||
!\in_array($this->getUploadedFileMimeType($value, $useStorage), [
|
||||
'application/pdf'
|
||||
])
|
||||
) {
|
||||
$fail(trans(":attribute doit être une image de type 'application/pdf'"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges docs fields with request data.
|
||||
* Merges documents fields with request data.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
protected function mergeDocuments(string $name = 'docs'): void
|
||||
protected function mergeDocuments(string $name = 'documents'): void
|
||||
{
|
||||
$documents = $this->{$name};
|
||||
$this->merge([$name => $this->{$name} ?? []]);
|
||||
$this->merge(["{$name}Validate" => []]);
|
||||
if (is_array($documents)) {
|
||||
$this->merge(["{$name}Validate" => []]);
|
||||
foreach ($documents as $key => $documentPath) {
|
||||
// ! Empty document.
|
||||
if ($documentPath === 'false') {
|
||||
|
|
@ -123,7 +123,7 @@ trait HasPicture
|
|||
* @return void
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
*/
|
||||
private function validatePicture(string $attribute, mixed $value, callable $fail, object $sizes)
|
||||
private function validatePicture(string $attribute, $value, callable $fail, object $sizes)
|
||||
{
|
||||
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
|
||||
$fail(trans(":attribute n'existe pas dans le système de fichier"));
|
||||
|
|
@ -138,11 +138,6 @@ trait HasPicture
|
|||
) {
|
||||
$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])) {
|
||||
$fail(trans(":attribute impossible de valider les dimensions"));
|
||||
} else {
|
||||
|
|
@ -244,7 +239,7 @@ trait HasPicture
|
|||
*/
|
||||
private function getUploadedFileFullPath(string $value, bool $useStorage): string
|
||||
{
|
||||
return !$useStorage ? (realpath($value) ?: $value) : Storage::path($value);
|
||||
return !$useStorage ? realpath($value) ?: $value : Storage::getAdapter()->applyPathPrefix($value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
"carlos-meneses/laravel-mpdf": "^2.1",
|
||||
"diglactic/laravel-breadcrumbs": "^8.0",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"kwaadpepper/image-resizer": "^2.1",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/tinker": "^2.8"
|
||||
},
|
||||
|
|
@ -20,7 +19,6 @@
|
|||
"fakerphp/faker": "^1.9.1",
|
||||
"kitloong/laravel-migrations-generator": "^6.8",
|
||||
"krlove/eloquent-model-generator": "dev-l10-compatibility",
|
||||
"laravel-lang/common": "^4.0",
|
||||
"laravel/pint": "^1.0",
|
||||
"laravel/sail": "^1.18",
|
||||
"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' => [
|
||||
'driver' => 'file',
|
||||
// 'store' 'redis'
|
||||
// 'store' => 'redis',
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
@ -159,7 +159,6 @@ return [
|
|||
/*
|
||||
* Laravel Framework Service Providers...
|
||||
*/
|
||||
|
||||
Illuminate\Auth\AuthServiceProvider::class,
|
||||
Illuminate\Broadcasting\BroadcastServiceProvider::class,
|
||||
Illuminate\Bus\BusServiceProvider::class,
|
||||
|
|
@ -186,13 +185,11 @@ return [
|
|||
/*
|
||||
* Package Service Providers...
|
||||
*/
|
||||
|
||||
Krlove\EloquentModelGenerator\Provider\GeneratorServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
*/
|
||||
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ return [
|
|||
'driver' => 'eloquent',
|
||||
'model' => App\Models\User::class,
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// 'driver' => 'database',
|
||||
// 'table' => 'users',
|
||||
// ],
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ return [
|
|||
'encrypted' => true,
|
||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||
],
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html .
|
||||
'client_options' => [],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'ably' => [
|
||||
|
|
|
|||
|
|
@ -61,7 +61,9 @@ return [
|
|||
env('MEMCACHED_USERNAME'),
|
||||
env('MEMCACHED_PASSWORD'),
|
||||
],
|
||||
'options' => [],
|
||||
'options' => [
|
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||
],
|
||||
'servers' => [
|
||||
[
|
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ return [
|
|||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||
'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||
],
|
||||
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
<?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' => [
|
||||
'transport' => 'mailgun',
|
||||
'client' => [
|
||||
'timeout' => 5,
|
||||
],
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
'client' => [
|
||||
'timeout' => 5,
|
||||
],
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ final class BrandFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->unique()->word,
|
||||
'name' => fake()->word,
|
||||
'filter' => fake()->word,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,15 +34,9 @@ final class ProductFactory extends Factory
|
|||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$source = \collect(SourceEnum::toArray())->random()->value;
|
||||
$catalogue = null;
|
||||
$fair = null;
|
||||
$shop = null;
|
||||
if (
|
||||
$source === SourceEnum::showConsumer->value ||
|
||||
$source === SourceEnum::showCustomer->value ||
|
||||
$source === SourceEnum::showTrade->value
|
||||
) {
|
||||
$source = \collect(SourceEnum::toArray())->random()->value;
|
||||
$fair = $shop = $catalogue = null;
|
||||
if ($source === SourceEnum::showConsumer->value || $source === SourceEnum::showCustomer->value || $source === SourceEnum::showTrade->value) {
|
||||
$fair = fake()->word;
|
||||
} elseif ($source === SourceEnum::magazin->value) {
|
||||
$shop = fake()->word;
|
||||
|
|
@ -67,8 +61,8 @@ final class ProductFactory extends Factory
|
|||
'docs' => [],
|
||||
'url' => fake()->url,
|
||||
'certification' => \collect(CertificationEnum::toArray())->random()->value,
|
||||
'origins' => [\collect(OriginEnum::toArray())->random()->value],
|
||||
'claims' => [$claim],
|
||||
'origins' => [["id" => strval(\collect(OriginEnum::toArray())->random()->value)]],
|
||||
'claims' => [["id" => strval($claim)]],
|
||||
'specified_claim' => ($claim == OriginEnum::others->value) ? fake()->text : null,
|
||||
'distribution_network' => \collect(DistributionNetworkEnum::toArray())->random()->value,
|
||||
'ray' => \collect(RayEnum::toArray())->random()->value,
|
||||
|
|
|
|||
|
|
@ -9,16 +9,12 @@ use App\Enums\Products\OriginEnum;
|
|||
use App\Enums\Products\RangeEnum;
|
||||
use App\Enums\Products\RayEnum;
|
||||
use App\Enums\Products\SourceEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Keyword;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductComment;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\OutputStyle;
|
||||
use Illuminate\Contracts\Database\Query\Builder;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
|
@ -26,11 +22,8 @@ use Illuminate\Support\Facades\Artisan;
|
|||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\ItemNotFoundException;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
return new class extends Migration
|
||||
|
|
@ -54,18 +47,9 @@ return new class extends Migration
|
|||
'VEILLE_PROD', 'VEILLE_PROD_COMM',
|
||||
];
|
||||
|
||||
/**
|
||||
* Console tabulation (margin left)
|
||||
* @var integer
|
||||
*/
|
||||
private $consoleTabulation = 28;
|
||||
|
||||
/** @var \App\Models\User */
|
||||
/** @var \App\Model\User */
|
||||
private $dummyUser;
|
||||
|
||||
/** @var \App\Models\Brand */
|
||||
private $dummyBrand;
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
|
|
@ -74,14 +58,8 @@ return new class extends Migration
|
|||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$ouput = new ConsoleOutput();
|
||||
$input = new ArgvInput();
|
||||
$style = new OutputStyle($input, $ouput);
|
||||
$section = $ouput->section();
|
||||
|
||||
if (!$style->confirm('Do this migration or skip ?', false)) {
|
||||
return;
|
||||
}
|
||||
$console = new ConsoleOutput();
|
||||
$section = $console->section();
|
||||
|
||||
// * SEED KEYWORDS As they are needed on runtime.
|
||||
Schema::disableForeignKeyConstraints();
|
||||
|
|
@ -89,9 +67,6 @@ return new class extends Migration
|
|||
DB::table('keywordables')->truncate();
|
||||
DB::table('keywords')->truncate();
|
||||
DB::table('products')->truncate();
|
||||
DB::table('product_comments')->truncate();
|
||||
// * Remove previously uploaded files.
|
||||
File::deleteDirectory(storage_path('app/public/modelfiles/products'));
|
||||
Schema::enableForeignKeyConstraints();
|
||||
if (Artisan::call('db:seed', ['--class' => 'KeywordInitSeeder']) !== 0) {
|
||||
throw new \RuntimeException('Failed to seed keywords');
|
||||
|
|
@ -102,11 +77,6 @@ return new class extends Migration
|
|||
'firstname' => 'Dummy',
|
||||
'lastname' => 'User'
|
||||
]);
|
||||
// * Seed a dummy brand.
|
||||
$this->dummyBrand = Brand::factory()->createOne([
|
||||
'name' => Str::of('Sans Marque')->slug()->studly(),
|
||||
'filter' => null
|
||||
]);
|
||||
|
||||
// * Apply DB corrections
|
||||
$this->setUniqueOnBrandName();
|
||||
|
|
@ -118,13 +88,13 @@ return new class extends Migration
|
|||
$this->createAndFillTempTables();
|
||||
|
||||
// * Migrate PRODUCTS, comment all except the one you want to develop here.
|
||||
$this->migrateBrands($style);
|
||||
$this->migrateProducts($style);
|
||||
$this->migrateProductsComments($style);
|
||||
$this->migrateBrands();
|
||||
$this->migrateProducts();
|
||||
|
||||
|
||||
// ! 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();
|
||||
$section->clear();
|
||||
}
|
||||
|
|
@ -142,92 +112,22 @@ return new class extends Migration
|
|||
|
||||
// - MIGRATION METHODS -
|
||||
|
||||
/**
|
||||
* Migrate products comments
|
||||
*
|
||||
* @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 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
|
||||
private function migrateProducts(): void
|
||||
{
|
||||
// phpcs:enable
|
||||
$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();
|
||||
|
||||
$MOTKS = Keyword::query()->where('keyword_cat', 'LIKE', 'product_%')->get();
|
||||
$MOTKS = Keyword::all();
|
||||
/** @var \Illuminate\Support\Collection<string,string> */
|
||||
$START_SOURCES = $this->getQuery('SOURCE')->get();
|
||||
/** @var \Illuminate\Support\Collection<string,string> */
|
||||
|
|
@ -256,7 +156,7 @@ return new class extends Migration
|
|||
$console = new ConsoleOutput();
|
||||
$console->writeln('');
|
||||
$progress = new ProgressBar($console, $nbRowsToMigrate);
|
||||
$progress->setMessage(str_pad('Migrate Products', $this->consoleTabulation, ' '));
|
||||
$progress->setMessage(str_pad('Migrate Products', 24, ' '));
|
||||
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
||||
|
||||
while ($nbRowsToMigrate > 0) {
|
||||
|
|
@ -311,22 +211,22 @@ return new class extends Migration
|
|||
// * Uu OMG !!!
|
||||
if ($motk === 'Gain de temps Nomadisme') {
|
||||
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') {
|
||||
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') {
|
||||
return $MOTKS->where('label', 'Végétal')
|
||||
->where('keyword_cat', KeywordCategoryEnum::productHealth)->firstOrFail();
|
||||
->where('keyword_cat', KeywordCategoryEnum::productHealth)->firstOrFail();
|
||||
}
|
||||
try {
|
||||
return $MOTKS->firstOrFail(
|
||||
fn (Keyword $keyword) => Str::of($keyword->label)->ascii()->replace(' ', '')
|
||||
== Str::of($motk)->trim()->ascii()->replace(' ', '')
|
||||
);
|
||||
} catch (ItemNotFoundException) {
|
||||
} catch (\Exception) {
|
||||
dump(
|
||||
$motk,
|
||||
$MOTKS->pluck('label')
|
||||
|
|
@ -335,32 +235,28 @@ return new class extends Migration
|
|||
}
|
||||
};
|
||||
|
||||
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9740 .
|
||||
if (is_null($row->MARQUE)) {
|
||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9740 .
|
||||
if (empty($row->MARQUE)) {
|
||||
continue;
|
||||
}
|
||||
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 .
|
||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9750 .
|
||||
if (empty($row->NUM_RESEAU)) {
|
||||
continue;
|
||||
}
|
||||
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9758 .
|
||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9758 .
|
||||
if (empty($row->NUM_SECTEUR)) {
|
||||
continue;
|
||||
}
|
||||
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9760 .
|
||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9760 .
|
||||
if (empty($row->NUM_RAYON)) {
|
||||
continue;
|
||||
}
|
||||
// NOTE: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9767 .
|
||||
// FIXME: thread https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_9767 .
|
||||
if (empty($row->NUM_FAMILLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$brandName = Str::of($row->MARQUE)->trim()->title();
|
||||
$brandName = Str::of($row->MARQUE)->slug()->studly();
|
||||
/** name is unique on brand */
|
||||
$brand = null;
|
||||
try {
|
||||
|
|
@ -368,9 +264,9 @@ return new class extends Migration
|
|||
} catch (\Exception) {
|
||||
throw new \Error("brand` {$brandName}` not found");
|
||||
}
|
||||
$url = $row->URL ? Str::lower(url($row->URL)) : null;
|
||||
$url = $row->URL ? Str::of(url($row->URL))->lower() : null;
|
||||
$date_saisie = $row->DATE_SAISIE ? $this->tryToParseCarbon($row->DATE_SAISIE, true) : null;
|
||||
$is_tasted = Str::lower($row->DEGUSTER_O_N) === 'o' ? true : false;
|
||||
$is_tasted = Str::of($row->DEGUSTER_O_N)->lower() === 'o' ? true : false;
|
||||
$claimList = collect([
|
||||
$row->ALLEG0, $row->ALLEG1, $row->ALLEG2
|
||||
])->filter()->map(fn (string $alleg) => $resolveAllegation($alleg));
|
||||
|
|
@ -423,26 +319,7 @@ return new class extends Migration
|
|||
/** @var \App\Models\Product $product */
|
||||
$product = Product::query()->where('id', $row->{$index})->firstOrNew();
|
||||
$product->id = $row->NUM_VEILLE_PROD;
|
||||
|
||||
// * 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 = [
|
||||
$fill = [
|
||||
'brand_id' => $brand->id,
|
||||
'catalogue' => $row->CATALOGUE,
|
||||
'certification' => $certificationEnum,
|
||||
|
|
@ -464,11 +341,10 @@ return new class extends Migration
|
|||
'specified_claim' => $claim,
|
||||
'tasters_number' => $row->NB_DEGUST,
|
||||
'origins' => $originList,
|
||||
'docs' => $files,
|
||||
'picture_alt' => "Image de {$row->NOM}",
|
||||
'picture_title' => "Image de {$row->NOM}",
|
||||
'picture' => $picture,
|
||||
// NOTE: https://lab.s-web.fr/ldc-web/projets/startcoq/-/issues/28#note_10688 .
|
||||
'docs' => 'tttt',
|
||||
'picture_alt' => 'tttt',
|
||||
'picture_title' => 'tttt',
|
||||
'picture' => 'tttt',
|
||||
'user_id' => $this->dummyUser->id
|
||||
];
|
||||
if ($date_saisie) {
|
||||
|
|
@ -493,21 +369,18 @@ return new class extends Migration
|
|||
/**
|
||||
* Create unique brands using veille products
|
||||
*
|
||||
* @param \Illuminate\Console\OutputStyle $style
|
||||
* @return void
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||
*/
|
||||
private function migrateBrands(OutputStyle $style): void
|
||||
private function migrateBrands(): void
|
||||
{
|
||||
// phpcs:enable
|
||||
$query = $this->getQuery("VEILLE_PROD");
|
||||
/** @var \Illuminate\Support\Collection<string,string> */
|
||||
$brands = (clone $query)->pluck('MARQUE')->filter()
|
||||
->map(fn (string $brandName) => Str::of($brandName)->trim()->title())->unique();
|
||||
->map(fn (string $brandName) => Str::of($brandName)->slug()->studly())->unique();
|
||||
$console = new ConsoleOutput();
|
||||
$console->writeln('');
|
||||
$progress = new ProgressBar($console, $brands->count());
|
||||
$progress->setMessage(str_pad('Migrate Brands', $this->consoleTabulation, ' '));
|
||||
$progress->setMessage(str_pad('Migrate Brands', 24, ' '));
|
||||
$progress->setFormat(' - %message% [%bar%] %percent:3s%% %current%/%max% %elapsed:6s%/%estimated:-6s%');
|
||||
// FIXME: Insert brand->filter and find from where it should be fetched.
|
||||
$brands->each(function ($brandName) use ($progress) {
|
||||
|
|
@ -572,7 +445,7 @@ return new class extends Migration
|
|||
});
|
||||
Schema::table('keywordables', function (Blueprint $table) {
|
||||
$table->foreign(['keyword_id'])->references(['id'])->on('keywords')
|
||||
->restrictOnUpdate()->cascadeOnDelete();
|
||||
->restrictOnUpdate()->cascadeOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -588,42 +461,13 @@ return new class extends Migration
|
|||
});
|
||||
Schema::table('processes', function (Blueprint $table) {
|
||||
$table->foreign(['user_id'])->references(['id'])->on('users')
|
||||
->restrictOnUpdate()->restrictOnDelete();
|
||||
->restrictOnUpdate()->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
// -- END DB CORRECTION --
|
||||
// --- 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
|
||||
*
|
||||
|
|
@ -669,7 +513,7 @@ return new class extends Migration
|
|||
$tableComment = "{$tableColumn->name} {$tableColumn->type} {$tableColumn->size}";
|
||||
switch ($tableColumn->type) {
|
||||
case 'NUMBER':
|
||||
$table->double($tableColumn->name)
|
||||
$table->bigInteger($tableColumn->name)
|
||||
->nullable()->comment($tableComment);
|
||||
break;
|
||||
case 'VARCHAR2':
|
||||
|
|
@ -705,7 +549,7 @@ return new class extends Migration
|
|||
$this->getTableName($tableName),
|
||||
$header
|
||||
);
|
||||
$message = str_pad("{$this->tablePrefix} {$tableName}", $this->consoleTabulation, ' ');
|
||||
$message = str_pad("{$this->tablePrefix} {$tableName}", 24, ' ');
|
||||
$section->write(" - {$message} -> Fetching OCI DATA..");
|
||||
$content = $this->fetchOciTableContent($tableName, $header);
|
||||
$section->clear();
|
||||
|
|
@ -717,7 +561,7 @@ return new class extends Migration
|
|||
DB::table($this->getTableName($tableName))->insert((array)$row);
|
||||
}
|
||||
$progress->finish();
|
||||
} //end foreach
|
||||
}//end foreach
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
<?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();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -5,7 +5,6 @@ namespace Database\Seeders;
|
|||
use App\Enums\KeywordCategoryEnum;
|
||||
use App\Models\Keyword;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class KeywordInitSeeder extends Seeder
|
||||
{
|
||||
|
|
@ -13,324 +12,186 @@ class KeywordInitSeeder extends Seeder
|
|||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// phpcs:enable
|
||||
/**
|
||||
* * INGREDIENTS
|
||||
*/
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[0];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Clean label/naturalité";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Clean label/naturalité";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Végétarien/vegan";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Végétarien/vegan";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Bien être";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[1];
|
||||
$keyword->label = "Bien être";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||
$keyword->label = "Solidarité";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||
$keyword->label = "Solidarité";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[2];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||
$keyword->label = "Emballage individuel";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||
$keyword->label = "Emballage individuel";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||
$keyword->label = "Facilité de mise en oeuvre";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[3];
|
||||
$keyword->label = "Facilité de mise en oeuvre";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
/**
|
||||
* * PRODUCTS
|
||||
*/
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Variété des sens";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Variété des sens";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[4];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Minceur";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Minceur";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Énergie/Bien-être";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Énergie/Bien-être";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Cosmétique";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[5];
|
||||
$keyword->label = "Cosmétique";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Manipulation produit";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Manipulation produit";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Gain de temps";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Gain de temps";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Nomadisme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[6];
|
||||
$keyword->label = "Nomadisme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Naturalité";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Naturalité";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Végétal";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Végétal";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Médical";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[7];
|
||||
$keyword->label = "Médical";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||
$keyword->label = "Solidarité";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||
$keyword->label = "Solidarité";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[8];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
/**
|
||||
* * PACKAGING
|
||||
*/
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Sophistication";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Exotisme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[9];
|
||||
$keyword->label = "Fun";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Manipulation produit";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Manipulation produit";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Gain de temps";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Gain de temps";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Nomadisme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[10];
|
||||
$keyword->label = "Nomadisme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||
$keyword->label = "Décor/forme";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||
$keyword->label = "Décor/forme";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||
$keyword->label = "Matériaux";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[11];
|
||||
$keyword->label = "Matériaux";
|
||||
$keyword->saveOrFail();
|
||||
|
||||
try {
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveQuietly();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
$keyword = new Keyword();
|
||||
$keyword->keyword_cat = \collect(KeywordCategoryEnum::cases())[12];
|
||||
$keyword->label = "Écologie";
|
||||
$keyword->saveOrFail();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"(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."
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?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.',
|
||||
];
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
<?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',
|
||||
]
|
||||
];
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<?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,7 +3,6 @@
|
|||
return [
|
||||
'classes' => [
|
||||
'products' => 'Produits',
|
||||
'products_monitoring' => 'Veille produit|Veilles produit',
|
||||
'brands' => 'Marques',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'next' => 'Suivant »',
|
||||
'previous' => '« Précédent',
|
||||
];
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?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,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'accepted' => 'Le champ :attribute doit être accepté.',
|
||||
'accepted_if' => 'Le champ :attribute doit être accepté quand :other a la valeur :value.',
|
||||
|
|
@ -12,7 +10,6 @@ return [
|
|||
'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.',
|
||||
'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_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale au :date.',
|
||||
'between' => [
|
||||
|
|
@ -22,18 +19,11 @@ return [
|
|||
'string' => 'Le texte :attribute doit contenir entre :min et :max caractères.',
|
||||
],
|
||||
'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.',
|
||||
'current_password' => 'Le mot de passe est incorrect.',
|
||||
'date' => 'Le champ :attribute n\'est pas une date valide.',
|
||||
'date_equals' => 'Le champ :attribute doit être une date égale à :date.',
|
||||
'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_if' => 'Le champ :attribute doit être décliné quand :other a la valeur :value.',
|
||||
'different' => 'Les champs :attribute et :other doivent être différents.',
|
||||
|
|
@ -41,8 +31,6 @@ return [
|
|||
'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.',
|
||||
'dimensions' => 'La taille de l\'image :attribute n\'est pas conforme.',
|
||||
'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.',
|
||||
'ends_with' => 'Le champ :attribute doit se terminer par une des valeurs suivantes : :values',
|
||||
'enum' => 'Le champ :attribute sélectionné est invalide.',
|
||||
|
|
@ -69,7 +57,6 @@ return [
|
|||
'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.',
|
||||
'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.',
|
||||
'json' => 'Le champ :attribute doit être un document JSON valide.',
|
||||
'lowercase' => 'Le champ :attribute doit être en minuscules.',
|
||||
'lt' => [
|
||||
'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.',
|
||||
|
|
@ -84,39 +71,24 @@ return [
|
|||
],
|
||||
'mac_address' => 'Le champ :attribute doit être une adresse MAC valide.',
|
||||
'max' => [
|
||||
'array' => 'Le tableau :attribute ne peut pas contenir plus que :max éléments.',
|
||||
'array' => 'Le tableau :attribute ne peut contenir plus de :max éléments.',
|
||||
'file' => 'La taille du fichier de :attribute ne peut pas dépasser :max kilo-octets.',
|
||||
'numeric' => 'La valeur de :attribute ne peut pas être supérieure à :max.',
|
||||
'string' => 'Le texte de :attribute ne peut pas contenir plus de :max caractères.',
|
||||
'numeric' => 'La valeur de :attribute ne peut être supérieure à :max.',
|
||||
'string' => 'Le texte de :attribute ne peut 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.',
|
||||
'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
||||
'min' => [
|
||||
'array' => 'Le tableau :attribute doit contenir au moins :min éléments.',
|
||||
'file' => 'La taille du fichier de :attribute doit être supérieure ou égale à :min kilo-octets.',
|
||||
'file' => 'La taille du fichier de :attribute doit être supérieure à :min kilo-octets.',
|
||||
'numeric' => 'La valeur de :attribute doit être supérieure ou égale à :min.',
|
||||
'string' => 'Le texte de :attribute doit contenir au moins :min caractères.',
|
||||
'string' => 'Le texte :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',
|
||||
'not_in' => 'Le champ :attribute sélectionné n\'est pas valide.',
|
||||
'not_regex' => 'Le format du champ :attribute n\'est pas valide.',
|
||||
'numeric' => 'Le champ :attribute doit contenir un nombre.',
|
||||
'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.',
|
||||
'password' => 'Le mot de passe est incorrect',
|
||||
'present' => 'Le champ :attribute doit être présent.',
|
||||
'prohibited' => 'Le champ :attribute est interdit.',
|
||||
'prohibited_if' => 'Le champ :attribute est interdit quand :other a la valeur :value.',
|
||||
|
|
@ -126,7 +98,6 @@ return [
|
|||
'required' => 'Le champ :attribute est obligatoire.',
|
||||
'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_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_with' => 'Le champ :attribute est obligatoire quand :values est présent.',
|
||||
'required_with_all' => 'Le champ :attribute est obligatoire quand :values sont présents.',
|
||||
|
|
@ -142,83 +113,16 @@ return [
|
|||
'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.',
|
||||
'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.',
|
||||
'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.',
|
||||
'uuid' => 'Le champ :attribute doit être un UUID valide',
|
||||
'attributes' => [
|
||||
'address' => 'adresse',
|
||||
'age' => 'âge',
|
||||
'amount' => 'montant',
|
||||
'area' => 'zone',
|
||||
'available' => 'disponible',
|
||||
'birthday' => 'anniversaire',
|
||||
'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',
|
||||
],
|
||||
'custom' => [],
|
||||
'phone' => 'Le champ :attribute n\'est pas un numéro de téléphone valide.',
|
||||
'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_rgb' => ':attribute doit être un code couleur RGB valide',
|
||||
'color_rgba' => ':attribute doit être un code couleur RGBA valide',
|
||||
'color_name' => ':attribute doit être un nom de couleur CSS valide',
|
||||
'postal_code' => 'Le champ :attribute accepte les codes postaux des pays suivants :countries comme par exemple :examples.'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
}
|
||||
|
||||
.bo-image-preview {
|
||||
// max-height: 60px;
|
||||
width: 180px;
|
||||
height: auto;
|
||||
max-height: 60px;
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
|
|
@ -15,20 +13,9 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-md {
|
||||
min-width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
// Print fiche commerciale
|
||||
@media print {
|
||||
#print-id-product {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-custom .dropdown-menu {
|
||||
overflow: auto;
|
||||
min-width: 5rem;
|
||||
max-height: 178px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,263 +0,0 @@
|
|||
<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,17 +63,15 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
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";
|
||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||
|
||||
export default defineComponent({
|
||||
name: "BelongsToManyDropdown",
|
||||
mixins: [route, trans, parseLaravelErrorMessages],
|
||||
components: {
|
||||
VueTagsInputCls,
|
||||
|
|
@ -90,7 +88,6 @@ export default defineComponent({
|
|||
this.selectedItems = this.parseTags(data.value);
|
||||
this.allItems = this.parseTags(data.itemsList);
|
||||
this.placeholder = data.placeholder;
|
||||
this.intStoreRoute = data.storeRoute ?? null;
|
||||
// * Min and max calc.
|
||||
this.min = Number.parseInt((data?.itemLimit ?? [])[0] ?? 0);
|
||||
this.min = this.min < 0 ? 0 : this.min;
|
||||
|
|
@ -111,7 +108,6 @@ export default defineComponent({
|
|||
waitingListObjects: Array<VueTagsInput.IAddArgs>;
|
||||
allErrors: Record<string, Array<string>>;
|
||||
message: string | null;
|
||||
intStoreRoute: string | null;
|
||||
} {
|
||||
return {
|
||||
name: "",
|
||||
|
|
@ -125,7 +121,6 @@ export default defineComponent({
|
|||
waitingListObjects: [],
|
||||
allErrors: {},
|
||||
message: null,
|
||||
intStoreRoute: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -148,23 +143,6 @@ export default defineComponent({
|
|||
this.selectedItems.push(customTag);
|
||||
this.item = "";
|
||||
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 {
|
||||
this.message = this.__("Nombre d'élements maximal atteint.");
|
||||
|
|
|
|||
|
|
@ -10,27 +10,22 @@
|
|||
>
|
||||
<template v-if="intIsAdded">
|
||||
<FontAwesomeIcon icon="fa-solid fa-minus" />
|
||||
|
||||
<FontAwesomeIcon icon="fa-solid fa-file-pdf" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<FontAwesomeIcon icon="fa-solid fa-plus" />
|
||||
|
||||
<FontAwesomeIcon icon="fa-solid fa-file-pdf" />
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import trans from "./../modules/trans";
|
||||
import route from "./../modules/route";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import Tooltip from "bootstrap/js/dist/tooltip";
|
||||
import { defineComponent } from "vue";
|
||||
import route from "./../modules/route";
|
||||
import trans from "./../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ButtonMultiPdfComponent",
|
||||
mixins: [trans, route],
|
||||
components: {
|
||||
FontAwesomeIcon,
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
</label>
|
||||
<img
|
||||
v-if="intValue"
|
||||
class="img-fluid img-preview"
|
||||
class="img-fluid"
|
||||
:src="intValue"
|
||||
:alt="__('Image placeholder')"
|
||||
:aria-describedby="`PreviewHelp${intId}`"
|
||||
|
|
@ -400,10 +400,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import Cropper from "cropperjs";
|
||||
import { defineComponent } from "vue";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import Cropper from "cropperjs";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import trans from "./../modules/trans";
|
||||
|
||||
const UNITS = [
|
||||
|
|
@ -417,7 +417,6 @@ const UNITS = [
|
|||
const BYTES_PER_KB = 1024;
|
||||
|
||||
export default defineComponent({
|
||||
name: "ImageInputComponent",
|
||||
mixins: [trans],
|
||||
emits: ["browseFile"],
|
||||
components: {
|
||||
|
|
@ -953,10 +952,6 @@ export default defineComponent({
|
|||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
}
|
||||
.img-preview {
|
||||
width: 180px;
|
||||
height: auto;
|
||||
}
|
||||
.right-aligned {
|
||||
overflow: hidden !important;
|
||||
direction: ltr !important;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import WordCounter from "./WordCounterComponent.vue";
|
|||
const textarea = ref<HTMLTextAreaElement | null>(null);
|
||||
|
||||
export default defineComponent({
|
||||
name: "InputTextAutoComponent",
|
||||
inheritAttrs: false,
|
||||
mixins: [trans],
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@
|
|||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
:data-bs-target="'#comment' + commentIndex"
|
||||
:aria-expanded="intModel.length > 0 ? true : false"
|
||||
aria-expanded="false"
|
||||
:aria-controls="'comment' + commentIndex"
|
||||
>
|
||||
{{ __("Commentaire n°" + (commentIndex + 1)) }}
|
||||
</button>
|
||||
<div
|
||||
:class="`border collapse ${intModel.length > 0 ? 'show' : ''}`"
|
||||
class="border collapse"
|
||||
:id="'comment' + commentIndex"
|
||||
>
|
||||
<div class="row w-100 mx-auto mb-3">
|
||||
|
|
@ -53,13 +53,14 @@
|
|||
class="col-form-label"
|
||||
for="commentEvaluation"
|
||||
>
|
||||
<b>{{ __("Appréciation globale") }} *</b>
|
||||
<b>{{ __("Évaluation du produit") }} *</b>
|
||||
</label>
|
||||
<InputTextAutoComponent
|
||||
:id="'commentEvaluation' + commentIndex"
|
||||
:name="'evaluation[' + commentIndex + ']'"
|
||||
class="form-control"
|
||||
:value="comment?.evaluation"
|
||||
:placeholder="__('Un peu caoutchouteux')"
|
||||
:ariadescribedby="'productcommentEvaluation' + commentIndex"
|
||||
/>
|
||||
<p class="text-danger m-0">
|
||||
|
|
@ -76,7 +77,7 @@
|
|||
>
|
||||
{{
|
||||
__(
|
||||
"Doit détailler l'appéciation globale (3 caractères minimum, 255 maximum)."
|
||||
"Doit détailler l'évaluation du produit (3 caractères minimum, 255 maximum)."
|
||||
)
|
||||
}}
|
||||
</small>
|
||||
|
|
@ -93,6 +94,7 @@
|
|||
:name="'aspect[' + commentIndex + ']'"
|
||||
class="form-control"
|
||||
:value="comment?.aspect"
|
||||
:placeholder="__('Un peu caoutchouteux')"
|
||||
:ariadescribedby="'productcommentAspect' + commentIndex"
|
||||
/>
|
||||
<p class="text-danger m-0">
|
||||
|
|
@ -126,6 +128,7 @@
|
|||
:name="'taste[' + commentIndex + ']'"
|
||||
class="form-control"
|
||||
:value="comment?.taste"
|
||||
:placeholder="__('Un peu caoutchouteux')"
|
||||
:ariadescribedby="'productcommentTaste' + commentIndex"
|
||||
/>
|
||||
<p class="text-danger m-0">
|
||||
|
|
@ -159,6 +162,7 @@
|
|||
:name="'odor[' + commentIndex + ']'"
|
||||
class="form-control"
|
||||
:value="comment?.odor"
|
||||
:placeholder="__('Un peu caoutchouteux')"
|
||||
:ariadescribedby="'productcommentOdor' + commentIndex"
|
||||
/>
|
||||
<p class="text-danger m-0">
|
||||
|
|
@ -192,6 +196,7 @@
|
|||
:name="'texture[' + commentIndex + ']'"
|
||||
class="form-control"
|
||||
:value="comment?.texture"
|
||||
:placeholder="__('Un peu caoutchouteux')"
|
||||
:ariadescribedby="'productCommentTexture' + commentIndex"
|
||||
/>
|
||||
<p class="text-danger m-0">
|
||||
|
|
@ -222,12 +227,11 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import InputTextAutoComponent from "./InputTextAutoComponent.vue";
|
||||
import parseLaravelErrorMessages from "../modules/parseLaravelErrorMessages";
|
||||
import trans from "../modules/trans";
|
||||
import InputTextAutoComponent from "./InputTextAutoComponent.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MultipleCommentsComponent",
|
||||
components: {
|
||||
InputTextAutoComponent,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<div class="col-12 d-flex form-group">
|
||||
<div class="input-group">
|
||||
<button
|
||||
@click.prevent="($refs.actualDocuments as HTMLInputElement).click()"
|
||||
@click.prevent="chooseFiles"
|
||||
class="btn btn-secondary"
|
||||
type="button"
|
||||
:title="__('Modifier les documents sources')"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-tooltip="tooltip"
|
||||
:disabled="intValues.length >= intItemLimit[1]"
|
||||
>
|
||||
<i class="fa-solid fa-folder-open" />
|
||||
|
|
@ -19,16 +19,16 @@
|
|||
<input
|
||||
:id="intId"
|
||||
ref="actualDocuments"
|
||||
@change="loadDocuments([].slice.call(($refs.actualDocuments as HTMLInputElement).files))"
|
||||
@change="changedDocuments"
|
||||
type="file"
|
||||
class="d-none"
|
||||
name="multipleInputDocuments"
|
||||
:accept="intAccepts"
|
||||
accept=".pdf"
|
||||
:aria-describedby="`Help${intId}`"
|
||||
multiple
|
||||
>
|
||||
<input
|
||||
@click.prevent="($refs.actualDocuments as HTMLInputElement).click()"
|
||||
@click.prevent="chooseFiles"
|
||||
type="text"
|
||||
:value="
|
||||
'Actuellement ' +
|
||||
|
|
@ -39,18 +39,31 @@
|
|||
"
|
||||
class="form-control right-aligned"
|
||||
:title="__('Modifier les documents sources')"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-tooltip="tooltip"
|
||||
:aria-describedby="`Help${intId}`"
|
||||
:disabled="intValues.length >= intItemLimit[1]"
|
||||
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
|
||||
v-if="intValues.length > intItemLimit[0]"
|
||||
@click.prevent="removeFiles"
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
:title="__('Supprimer tous les documents')"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-tooltip="tooltip"
|
||||
:disabled="intValues.length <= 0"
|
||||
>
|
||||
<i class="fas fa-eraser" />
|
||||
|
|
@ -59,94 +72,146 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- End main buttons -->
|
||||
<!-- Documents list -->
|
||||
<!-- Content collapse -->
|
||||
<div
|
||||
v-for="(value, valueIndex) of intValues"
|
||||
:key="valueIndex"
|
||||
class="row w-100 mx-auto my-2"
|
||||
class="collapse"
|
||||
id="multiple-documents"
|
||||
>
|
||||
<div class="col-12 form-group text-center px-1">
|
||||
<div class="row w-100 mx-auto my-2">
|
||||
<div
|
||||
class="d-flex justify-content-between align-items-center pb-1"
|
||||
:class="valueIndex != 1 ? 'border-top' : ''"
|
||||
v-for="n = 0 in intValues.length"
|
||||
:key="n"
|
||||
class="col-12 form-group text-center px-1"
|
||||
>
|
||||
<label
|
||||
v-if="value"
|
||||
class="col-form-label d-flex"
|
||||
<div
|
||||
class="d-flex justify-content-between align-items-center pb-1"
|
||||
:class="n != 1 ? 'border-top' : ''"
|
||||
>
|
||||
<span
|
||||
class="text-start text-ellipsis"
|
||||
v-if="intOriginalFileName[valueIndex]"
|
||||
<label
|
||||
v-if="intValues[n - 1]"
|
||||
class="col-form-label d-flex"
|
||||
>
|
||||
{{ intOriginalFileName[valueIndex].split('.').pop() }}
|
||||
|
||||
</span>
|
||||
<span class="text-start text-ellipsis">
|
||||
{{ intOriginalFileName[valueIndex] }}
|
||||
</span>
|
||||
</label>
|
||||
<small
|
||||
v-if="value"
|
||||
:id="`PreviewHelp${intId}`"
|
||||
class="form-text text-muted d-block m-0"
|
||||
<span class="text-start text-ellipsis">
|
||||
{{ intOriginalFileName[n - 1] }}
|
||||
</span>
|
||||
</label>
|
||||
<small
|
||||
v-if="intValues[n - 1]"
|
||||
:id="`PreviewHelp${intId}`"
|
||||
class="form-text text-muted d-block m-0"
|
||||
>
|
||||
<span v-if="intOriginalFile[n - 1]">
|
||||
{{ humanFileSize(intOriginalFile[n - 1].size) }}.
|
||||
</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"
|
||||
>
|
||||
<span v-if="intOriginalFile[valueIndex]">
|
||||
{{ humanFileSize(intOriginalFile[valueIndex].size) }}.
|
||||
</span>
|
||||
</small>
|
||||
<div class="input-group justify-content-center mt-1 w-auto">
|
||||
<button
|
||||
@click.prevent="viewDocumentSource(valueIndex)"
|
||||
class="btn btn-warning"
|
||||
type="button"
|
||||
:title="__('Afficher le document')"
|
||||
data-bs-toggle="tooltip"
|
||||
>
|
||||
<i class="fa-solid fa-eye" />
|
||||
</button>
|
||||
<input
|
||||
:id="intId"
|
||||
ref="actualDocument"
|
||||
@change="changedDocument(($refs.actualDocument as HTMLInputElement[])[valueIndex], valueIndex)"
|
||||
type="file"
|
||||
class="d-none"
|
||||
:name="intName.replace('[]', '') + `[${valueIndex}]`"
|
||||
:accept="intAccepts"
|
||||
:aria-describedby="`Help${intId}`"
|
||||
:disabled="intPreviousFiles.has(intOriginalFileName[valueIndex])"
|
||||
>
|
||||
<input
|
||||
@change="changedDocument(($refs.actualDocument as HTMLInputElement[])[valueIndex], valueIndex)"
|
||||
type="text"
|
||||
class="d-none"
|
||||
:name="intName.replace('[]', '') + `[${valueIndex}]`"
|
||||
:aria-describedby="`Help${intId}`"
|
||||
:disabled="!intPreviousFiles.has(intOriginalFileName[valueIndex])"
|
||||
:value="intValues[valueIndex]"
|
||||
>
|
||||
<button
|
||||
v-if="intValues.length > intItemLimit[0]"
|
||||
@click.prevent="removeFile(valueIndex)"
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
:title="__('Supprimer le document')"
|
||||
data-bs-toggle="tooltip"
|
||||
>
|
||||
<i class="fas fa-trash" />
|
||||
</button>
|
||||
<div class="modal-content h-100">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
{{ __("Prévisualisation du document") }}
|
||||
</h5>
|
||||
<button
|
||||
@click.prevent="removeDocumentSource"
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
:aria-label="__('Fermer la fenêtre')"
|
||||
:title="__('Fermer la fenêtre')"
|
||||
data-bs-tooltip="tooltip"
|
||||
/>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<div
|
||||
v-if="intViewerLoadDocument"
|
||||
class="text-center w-100 h-100"
|
||||
>
|
||||
<div
|
||||
class="spinner-border text-secondary"
|
||||
role="status"
|
||||
>
|
||||
<span class="visually-hidden">
|
||||
{{ __("Chargement du document") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<object
|
||||
class="w-100 h-100"
|
||||
:class="intViewerLoadDocument ? 'd-none' : ''"
|
||||
type="application/pdf"
|
||||
data=""
|
||||
ref="documentViewer"
|
||||
:title="__('Document enregistré')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-danger m-0">
|
||||
{{
|
||||
parseValidationInput(
|
||||
`${intName.replace(/[\[\]']+/g, "")}.${n - 1}`,
|
||||
intAllErrors
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End documents list -->
|
||||
<!-- End content collapse -->
|
||||
<small
|
||||
:id="`Help${intId}`"
|
||||
class="form-text text-muted"
|
||||
|
|
@ -158,7 +223,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import bsTooltips from "./../modules/bsTooltips";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import error from "./../modules/parseLaravelErrorMessages";
|
||||
import trans from "./../modules/trans";
|
||||
|
||||
|
|
@ -173,37 +238,38 @@ const UNITS = [
|
|||
const BYTES_PER_KB = 1024;
|
||||
|
||||
export default defineComponent({
|
||||
name: "MultipleDocumentsInputComponent",
|
||||
mixins: [error, trans, bsTooltips],
|
||||
components: {
|
||||
},
|
||||
mixins: [error, trans],
|
||||
data(): {
|
||||
/** The file ext accepted */
|
||||
intAccepts: string;
|
||||
/** The file ext accepted */
|
||||
intId: string;
|
||||
intName: string;
|
||||
intPreviousFiles: Set<string>;
|
||||
intHasDocument: boolean[];
|
||||
intHasDocuments: boolean;
|
||||
intOriginalFile: File[];
|
||||
intOriginalFileName: string[];
|
||||
intValues: string[];
|
||||
intHelper: string;
|
||||
intTooltipList: HTMLButtonElement[];
|
||||
intBtnCollapse: HTMLButtonElement | null;
|
||||
intLoopLoadDocuments: number;
|
||||
intViewerLoadDocument: boolean;
|
||||
intInputDocuments: HTMLInputElement[];
|
||||
intItemLimit: number[];
|
||||
intAllErrors: Record<string, string[]>;
|
||||
} {
|
||||
return {
|
||||
intAccepts: ".xls,.csv,.xlsx,.png,.jpg,.jpeg,.gif,.doc,.docx,.ppt,.pdf,.txt",
|
||||
intId: "",
|
||||
intName: "",
|
||||
intPreviousFiles: new Set<string>(),
|
||||
intHasDocument: [],
|
||||
intHasDocuments: false,
|
||||
intOriginalFile: [],
|
||||
intOriginalFileName: [],
|
||||
intValues: [],
|
||||
intHelper: "",
|
||||
intBtnCollapse: null,
|
||||
intTooltipList: [],
|
||||
intLoopLoadDocuments: 0,
|
||||
intViewerLoadDocument: false,
|
||||
intInputDocuments: [],
|
||||
intItemLimit: [0, 0],
|
||||
intAllErrors: {},
|
||||
};
|
||||
|
|
@ -219,87 +285,153 @@ export default defineComponent({
|
|||
this.intAllErrors = data.errors ?? {};
|
||||
this.$nextTick(() => {
|
||||
this.initComponent();
|
||||
this.updateBootstrapTooltip();
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
this.initTooltips();
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
documentInputs(): HTMLInputElement[] {
|
||||
return this.$refs.actualDocument as HTMLInputElement[];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** Initialize the component with previously documents registered. */
|
||||
/**
|
||||
* Initialise the component with previously documents registered.
|
||||
*/
|
||||
initComponent() {
|
||||
if (this.intValues.length > 0) {
|
||||
this.intBtnCollapse = document.querySelector(
|
||||
"[data-bs-target=\"#multiple-documents\"]"
|
||||
);
|
||||
this.intValues.forEach((element, index) => {
|
||||
element.charAt(0) != "/" ? "/".concat(element) : "";
|
||||
this.intValues.splice(index, 1, element.replace(/^\/|^/, "/"));
|
||||
});
|
||||
this.intHasDocument = Array(this.intValues.length).fill(false);
|
||||
this.intHasDocuments = true;
|
||||
this.initDocumentsSaved();
|
||||
} else {
|
||||
this.intHasDocuments = false;
|
||||
}
|
||||
},
|
||||
/** Assign previously documents registered to respective input. */
|
||||
/**
|
||||
* Assign previously documents registered to respective input.
|
||||
*/
|
||||
initDocumentsSaved() {
|
||||
var actualDocuments = this.$refs.actualDocument as HTMLInputElement[];
|
||||
this.intValues.forEach((element, index) => {
|
||||
const documentName = element.substring(element.lastIndexOf("/") + 1);
|
||||
this.intPreviousFiles.add(documentName);
|
||||
this.createFile(
|
||||
element,
|
||||
`${documentName}`
|
||||
"document_" + (index + 1) + ".pdf",
|
||||
"application/pdf"
|
||||
).then((file: File) => {
|
||||
const container = new DataTransfer();
|
||||
container.items.add(file);
|
||||
this.documentInputs[index].files = container.files;
|
||||
actualDocuments[index].files = container.files;
|
||||
this.intOriginalFile[index] = container.files[0];
|
||||
this.intOriginalFileName[index] = container.files[0].name;
|
||||
});
|
||||
});
|
||||
},
|
||||
/** Create a file from a path. */
|
||||
async createFile(path: string, name: string): Promise<File> {
|
||||
const response = await fetch(
|
||||
/**
|
||||
* Create a file from a path.
|
||||
*/
|
||||
async createFile(path: string, name: string, type: string): Promise<File> {
|
||||
let response = await fetch(
|
||||
window.location.protocol + "//" + window.location.host + "/" + path
|
||||
);
|
||||
const data = await response.blob();
|
||||
const type = await response.headers.get("content-type") ?? "application/pdf";
|
||||
const metadata = {
|
||||
let data = await response.blob();
|
||||
let metadata = {
|
||||
type: type,
|
||||
};
|
||||
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) {
|
||||
if(this.intPreviousFiles.has(this.intOriginalFileName[n])) {
|
||||
this.intPreviousFiles.delete(this.intOriginalFileName[n]);
|
||||
}
|
||||
this.intValues.splice(n, 1);
|
||||
this.intHasDocument.splice(n, 1);
|
||||
this.intOriginalFile.splice(n, 1);
|
||||
this.intOriginalFileName.splice(n, 1);
|
||||
this.documentInputs.forEach((element, index) => {
|
||||
if (this.intValues.length <= 0) {
|
||||
this.intHasDocuments = false;
|
||||
}
|
||||
this.intInputDocuments = this.$refs.actualDocument as HTMLInputElement[];
|
||||
this.intInputDocuments.forEach((element, index) => {
|
||||
if (this.intOriginalFile[index] != undefined) {
|
||||
const dt = new DataTransfer();
|
||||
var dt = new DataTransfer();
|
||||
dt.items.add(this.intOriginalFile[index]);
|
||||
element.files = dt.files;
|
||||
}
|
||||
});
|
||||
this.$nextTick(() => this.initTooltips());
|
||||
this.closeBootstrapTooltip();
|
||||
},
|
||||
/** Remove all documents. */
|
||||
/**
|
||||
* Remove all documents.
|
||||
*/
|
||||
removeFiles() {
|
||||
this.intValues.length = this.intItemLimit[0];
|
||||
this.intHasDocument.length = this.intItemLimit[0];
|
||||
this.intOriginalFile.length = this.intItemLimit[0];
|
||||
this.intOriginalFileName.length = this.intItemLimit[0];
|
||||
this.intItemLimit[0] > 0
|
||||
? (this.intHasDocuments = true)
|
||||
: (this.intHasDocuments = false);
|
||||
this.intAllErrors = {};
|
||||
this.$nextTick(() => this.initTooltips());
|
||||
this.closeBootstrapTooltip();
|
||||
},
|
||||
/** Change one specific document. */
|
||||
changedDocument(el: HTMLInputElement, n: number) {
|
||||
/**
|
||||
* Change one specific document.
|
||||
*/
|
||||
changedDocument(e: Event, n: number) {
|
||||
const reader = new FileReader();
|
||||
if (!el.files) {
|
||||
throw new Error("No files");
|
||||
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.intHasDocument[n] = true;
|
||||
reader.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
|
|
@ -314,35 +446,82 @@ export default defineComponent({
|
|||
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>) {
|
||||
if (files.length > 0) {
|
||||
if (this.intValues.length + files.length <= this.intItemLimit[1]) {
|
||||
const actualFile = files.shift() as File;
|
||||
let actualFile = files.shift() as File;
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(actualFile);
|
||||
reader.onload = () => {
|
||||
// On convertit l'document en une chaîne de caractères base64.
|
||||
this.intValues.push(String(reader.result));
|
||||
this.intOriginalFileName[this.intValues.length - 1] = "";
|
||||
};
|
||||
reader.onloadend = () => {
|
||||
const dt = new DataTransfer();
|
||||
this.intInputDocuments = this.$refs
|
||||
.actualDocument as HTMLInputElement[];
|
||||
var dt = new DataTransfer();
|
||||
dt.items.add(actualFile);
|
||||
this.documentInputs[this.documentInputs.length - 1].files = dt.files;
|
||||
this.intOriginalFile[this.documentInputs.length - 1] = actualFile;
|
||||
this.intOriginalFileName[this.documentInputs.length - 1] = actualFile.name;
|
||||
this.intInputDocuments[this.intLoopLoadDocuments].files = dt.files;
|
||||
this.intOriginalFile[this.intLoopLoadDocuments] = actualFile;
|
||||
this.intHasDocument[this.intValues.length - 1] = true;
|
||||
this.intOriginalFileName[this.intValues.length - 1] =
|
||||
actualFile.name;
|
||||
this.intLoopLoadDocuments++;
|
||||
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) {
|
||||
window.open(URL.createObjectURL(this.intOriginalFile[n]));
|
||||
const documentViewer = this.$refs.documentViewer as HTMLObjectElement;
|
||||
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 {
|
||||
let size = Math.abs(Number(sizeBytes));
|
||||
let u = 0;
|
||||
|
|
|
|||
|
|
@ -33,15 +33,25 @@
|
|||
<p class="text-danger m-0">
|
||||
{{
|
||||
parseValidationInput(
|
||||
`${intName}[${String(index)}]`,
|
||||
`${intName}[${String(index)}][name]`,
|
||||
intAllErrors
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<input
|
||||
:name="`${intName}[${String(index)}]`"
|
||||
:name="`${intName}[${String(index)}][id]`"
|
||||
type="hidden"
|
||||
:value="sItem.value"
|
||||
:value="sItem.id"
|
||||
>
|
||||
<input
|
||||
:name="`${intName}[${String(index)}][value]`"
|
||||
type="hidden"
|
||||
:value="sItem.id"
|
||||
>
|
||||
<input
|
||||
:name="`${intName}[${String(index)}][label]`"
|
||||
type="hidden"
|
||||
:value="sItem.text"
|
||||
>
|
||||
</template>
|
||||
<small class="form-text text-muted">{{ intHelper }}</small>
|
||||
|
|
@ -72,16 +82,15 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
||||
import slugify from "slugify";
|
||||
import { defineComponent } from "vue";
|
||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||
import route from "./../modules/route";
|
||||
import trans from "./../modules/trans";
|
||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SelectMultipleEnumComponent",
|
||||
mixins: [route, trans, parseLaravelErrorMessages],
|
||||
components: {
|
||||
VueTagsInputCls,
|
||||
|
|
@ -135,7 +144,7 @@ export default defineComponent({
|
|||
this.intName = data.name;
|
||||
this.intLabel = data.label;
|
||||
this.intHelper = data.helper;
|
||||
this.intAllItems = (data.itemsList as CustomTag[]).map(item => {item.text = item.label; return item;});
|
||||
this.intAllItems = this.parseTags(data.itemsList);
|
||||
this.intSelectedItem = this.parseTags(data.itemsSelected);
|
||||
this.intPlaceholder = data.placeholder;
|
||||
this.intItemLimit = data.itemLimit;
|
||||
|
|
@ -146,21 +155,18 @@ export default defineComponent({
|
|||
this.checkSpecificItem();
|
||||
},
|
||||
methods: {
|
||||
parseTags(intSelectedItem: number[]): CustomTag[] {
|
||||
const out: CustomTag[] = [];
|
||||
intSelectedItem.forEach((intItem: number) => {
|
||||
const selectedItem = this.intAllItems.find(item => String(item.id ?? item.value) === String(intItem));
|
||||
if (!selectedItem) {
|
||||
console.debug(intItem);
|
||||
throw new Error(`Could not find enum ${intItem}`);
|
||||
}
|
||||
out.push({
|
||||
id: String(selectedItem.id ?? selectedItem.value),
|
||||
value: String(selectedItem.value),
|
||||
text: String(selectedItem.text)
|
||||
} as LaravelModel as CustomTag);
|
||||
parseTags(intSelectedItem: CustomTag[]): CustomTag[] {
|
||||
return intSelectedItem.map((intItem: CustomTag) => {
|
||||
if (!intItem.value)
|
||||
intItem = this.intAllItems
|
||||
.filter((intItemEnum) => {
|
||||
return intItemEnum.value == intItem.id;
|
||||
})
|
||||
.shift() as CustomTag;
|
||||
intItem.id = String(intItem.value);
|
||||
intItem.text = String(intItem.label);
|
||||
return intItem;
|
||||
});
|
||||
return out;
|
||||
},
|
||||
/**
|
||||
* Add item
|
||||
|
|
|
|||
|
|
@ -12,17 +12,13 @@
|
|||
class="form-select source-select"
|
||||
:name="intName"
|
||||
:aria-describedby="`${intId}Help`"
|
||||
@change="setSelectedValue(0)"
|
||||
@change="setSelectedValue()"
|
||||
>
|
||||
<option
|
||||
:value="null"
|
||||
:selected="intSelectedValue === 0"
|
||||
/>
|
||||
<option
|
||||
v-for="(itemEnum, indexEnum) in intSourceEnum"
|
||||
:key="indexEnum"
|
||||
:value="itemEnum.value"
|
||||
:selected="itemEnum.value === intModel?.source || itemEnum.value === intSelectedValue "
|
||||
:selected="itemEnum.value === intModel?.source"
|
||||
>
|
||||
{{ itemEnum.label }}
|
||||
</option>
|
||||
|
|
@ -38,15 +34,15 @@
|
|||
for="catalogue"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Détail de la source Catalogue") }}</b>
|
||||
<b>{{ __("Détail de la source Catalogue") }} *</b>
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
name="catalogue"
|
||||
type="text"
|
||||
placeholder=""
|
||||
placeholder="Nom du catalogue"
|
||||
list="productsCatalog"
|
||||
:value="intModel?.catalogue ?? intOldDetails"
|
||||
:value="intModel?.catalogue"
|
||||
>
|
||||
<datalist id="productsCatalog">
|
||||
<option
|
||||
|
|
@ -73,15 +69,15 @@
|
|||
for="shop"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Détail de la source Magasin") }}</b>
|
||||
<b>{{ __("Détail de la source Magasin") }} *</b>
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
name="shop"
|
||||
type="text"
|
||||
placeholder=""
|
||||
placeholder="Nom du magasin"
|
||||
list="productsShop"
|
||||
:value="intModel?.shop ?? intOldDetails"
|
||||
:value="intModel?.shop"
|
||||
>
|
||||
<datalist id="productsShop">
|
||||
<option
|
||||
|
|
@ -108,15 +104,15 @@
|
|||
for="salon"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Détail de la source Salon") }}</b>
|
||||
<b>{{ __("Détail de la source Salon") }} *</b>
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
name="fair"
|
||||
type="text"
|
||||
placeholder=""
|
||||
placeholder="Nom du salon"
|
||||
list="productsFair"
|
||||
:value="intModel?.fair ?? intOldDetails"
|
||||
:value="intModel?.fair"
|
||||
>
|
||||
<datalist id="productsFair">
|
||||
<option
|
||||
|
|
@ -142,7 +138,6 @@ import { defineComponent } from "vue";
|
|||
import trans from "../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SourceInputsComponent",
|
||||
mixins: [trans],
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}");
|
||||
|
|
@ -156,9 +151,7 @@ export default defineComponent({
|
|||
this.intProductsCatalog = data.productsCatalog;
|
||||
this.intSourceEnum = data.sourceEnum;
|
||||
this.intHelper = data.helper;
|
||||
this.intSelectedValue = data.oldValue;
|
||||
this.intOldDetails = data.oldDetails;
|
||||
this.setSelectedValue(data.oldValue);
|
||||
this.setSelectedValue();
|
||||
},
|
||||
data(): {
|
||||
intId: string;
|
||||
|
|
@ -174,7 +167,6 @@ export default defineComponent({
|
|||
intSourceMagazin: boolean;
|
||||
intSourceShow: boolean;
|
||||
intHelper: string;
|
||||
intOldDetails: string;
|
||||
} {
|
||||
return {
|
||||
intId: "",
|
||||
|
|
@ -190,19 +182,18 @@ export default defineComponent({
|
|||
intSourceMagazin: false,
|
||||
intSourceShow: false,
|
||||
intHelper: "",
|
||||
intOldDetails: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Set selected source variables.
|
||||
*/
|
||||
setSelectedValue(oldValue: number) {
|
||||
setSelectedValue() {
|
||||
this.$nextTick(() => {
|
||||
const select = document.querySelector(
|
||||
".source-select"
|
||||
) as HTMLSelectElement;
|
||||
this.intSelectedValue = isNaN(Number(select.value)) ? Number(oldValue) : Number(select.value) ;
|
||||
this.intSelectedValue = Number(select.value);
|
||||
this.updateVue();
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -75,11 +75,10 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import trans from "../modules/trans";
|
||||
import MultipleCommentsComponent from "./MultipleCommentsComponent.vue";
|
||||
import trans from "../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TastedProductComponent",
|
||||
components: {
|
||||
MultipleCommentsComponent,
|
||||
},
|
||||
|
|
@ -151,8 +150,6 @@ export default defineComponent({
|
|||
: false
|
||||
) {
|
||||
this.updateBoolean();
|
||||
} else {
|
||||
this.intIsTasted = data.oldCheck;
|
||||
}
|
||||
this.intCommentModel =
|
||||
data.commentOldModel.length > 0
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
:name="intName"
|
||||
type="text"
|
||||
:value="intValue"
|
||||
placeholder=""
|
||||
:placeholder="__('112233445566')"
|
||||
class="form-control input-gencode"
|
||||
:class="[
|
||||
intResult != undefined ? [intResult ? 'is-invalid' : 'is-valid'] : '',
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
:maxlength="typeof intMaxlength != 'undefined' ? intMaxlength : ''"
|
||||
:required="!!intRequired"
|
||||
:disabled="!!intLoader"
|
||||
@input="checkGencode()"
|
||||
@keyup="checkGencode()"
|
||||
>
|
||||
<a
|
||||
v-if="intResult"
|
||||
|
|
@ -43,14 +43,13 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import { defineComponent } from "vue";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import route from "./../modules/route";
|
||||
import trans from "./../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "VerificationCodeComponent",
|
||||
mixins: [route, trans],
|
||||
components: {
|
||||
FontAwesomeIcon,
|
||||
|
|
@ -162,7 +161,7 @@ export default defineComponent({
|
|||
this.intCode = inputCode.value;
|
||||
window.axios
|
||||
.post(this.getRouteProductGencode(), {
|
||||
GENCOD: this.intCode,
|
||||
GENCODE: this.intCode,
|
||||
ID: this.intModel?.id,
|
||||
})
|
||||
.then((reponse) => {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import { defineComponent } from "vue";
|
|||
import trans from "../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "WordCounterComponent",
|
||||
mixins: [trans],
|
||||
mounted() {
|
||||
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 type VueTagsInput from "@sipec/vue3-tags-input";
|
||||
import { AxiosStatic } from "axios";
|
||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||
|
||||
// * Recursive List<string>
|
||||
type StringList = Record<PropertyKey, string>;
|
||||
|
|
@ -30,7 +30,7 @@ type NestedNumberList = NestedNumberListInterface | NumberList | number;
|
|||
type ModelList = Array<Model>;
|
||||
|
||||
declare global {
|
||||
type CustomTag = LaravelModel & VueTagsInput.ITag & {name:string,label:string, value:number|string};
|
||||
type CustomTag = LaravelModel & VueTagsInput.ITag;
|
||||
type LaravelModel = Model;
|
||||
type LaravelModelList = ModelList;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
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,49 +1,42 @@
|
|||
import { config, dom, library } from "~/@fortawesome/fontawesome-svg-core";
|
||||
import { dom, library, config } from "~/@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faAnglesRight,
|
||||
faArrowAltCircleDown,
|
||||
faArrowAltCircleUp,
|
||||
faArrowDown,
|
||||
faArrowLeft,
|
||||
faEraser,
|
||||
faArrowLeftLong,
|
||||
faPlus,
|
||||
faMinus,
|
||||
faTrash,
|
||||
faEye,
|
||||
faFolderOpen,
|
||||
faCrop,
|
||||
faQuestionCircle,
|
||||
faCheck,
|
||||
faUndoAlt,
|
||||
faRedoAlt,
|
||||
faSyncAlt,
|
||||
faSearchPlus,
|
||||
faSearchMinus,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faArrowRightFromBracket,
|
||||
faArrowUp,
|
||||
faArrowDown,
|
||||
faArrowsAltH,
|
||||
faArrowsAltV,
|
||||
faBackspace,
|
||||
faCheck,
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
faCircleNotch,
|
||||
faCopy,
|
||||
faCrop,
|
||||
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,
|
||||
faPencil,
|
||||
faTimes,
|
||||
faBackspace,
|
||||
faSearch,
|
||||
faArrowRightFromBracket,
|
||||
faArrowAltCircleDown,
|
||||
faArrowAltCircleUp,
|
||||
faQuestion,
|
||||
faXmark,
|
||||
faCopy,
|
||||
faFile,
|
||||
faLink,
|
||||
faPrint,
|
||||
faImage,
|
||||
faDownload,
|
||||
} from "~/@fortawesome/free-solid-svg-icons";
|
||||
|
||||
config.autoReplaceSvg = false;
|
||||
|
|
@ -84,12 +77,5 @@ library.add(faLink);
|
|||
library.add(faPrint);
|
||||
library.add(faImage);
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -5,119 +5,109 @@
|
|||
{{-- CONTENT --}}
|
||||
<table width="100%">
|
||||
<tr>
|
||||
@if (isset($product->picture) && !empty($product->picture))
|
||||
<td class="table-cell-text-center" width="30%">
|
||||
<img src="{{ public_path($product->picture) }}" alt="{{ $product->picture_alt }}" alt="{{ $product->picture_title }}">
|
||||
</td>
|
||||
<td width="70%">
|
||||
@else
|
||||
<td width="100%">
|
||||
@endif
|
||||
<h2><strong>{{ __('Marque du produit : ') }}</strong><span>{{ $product->brand->name }}</span></h2>
|
||||
<h2><strong>{{ __('Nom du produit : ') }}</strong><span>{{ $product->name }}</span></h2>
|
||||
@if (isset($product->certification))
|
||||
<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 }}
|
||||
<td class="table-cell-text-center" width="30%">
|
||||
@if (isset($product->picture))
|
||||
<img src="{{ public_path($product->picture) }}" alt="{{ $product->picture_alt }}" alt="{{ $product->picture_title }}">
|
||||
@endif
|
||||
</p>
|
||||
<table class="table" width="100%">
|
||||
<tr class="table-header">
|
||||
@if (isset($product->gencod))
|
||||
</td>
|
||||
<td width="70%">
|
||||
@if (isset($product->brand_id->name))
|
||||
<h2><strong>{{ __('Marque du produit : ') }}</strong><span>{{ $product->brand_id->name }}</span></h2>
|
||||
@endif
|
||||
@if (isset($product->name))
|
||||
<h2><strong>{{ __('Nom du produit : ') }}</strong><span>{{ $product->name }}</span></h2>
|
||||
@endif
|
||||
@if (isset($product->certification))
|
||||
<p><strong>{{ __('Certification : ') }}</strong>{{ $product->certification }}</p>
|
||||
@endif
|
||||
@if (isset($product->origins))
|
||||
<p><strong>{{ __('Origines : ') }}</strong>{{ $product->origins }}</p>
|
||||
@endif
|
||||
@if (isset($product->claims))
|
||||
<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>
|
||||
@endif
|
||||
@if (isset($product->weight))
|
||||
@endif
|
||||
@if (isset($product->weight))
|
||||
<td class="table-cell-text-center"><strong>{{ __('Poids UVC') }}</strong></td>
|
||||
@endif
|
||||
@if (isset($product->pvc))
|
||||
@endif
|
||||
@if (isset($product->pvc))
|
||||
<td class="table-cell-text-center"><strong>{{ __('PVC') }}</strong></td>
|
||||
@endif
|
||||
<td class="table-cell-text-center"><strong>{{ __('Prix kg') }}</strong></td>
|
||||
</tr>
|
||||
<tr class="table-body">
|
||||
@if (isset($product->gencod))
|
||||
@endif
|
||||
<td class="table-cell-text-center"><strong>{{ __('Prix kg') }}</strong></td>
|
||||
</tr>
|
||||
<tr class="table-body">
|
||||
@if (isset($product->gencod))
|
||||
<td class="table-cell-text-center">{{ $product->gencod }}</td>
|
||||
@endif
|
||||
@if (isset($product->weight))
|
||||
<td class="table-cell-text-center">{{ $product->weight }} g</td>
|
||||
@endif
|
||||
@if (isset($product->pvc))
|
||||
@endif
|
||||
@if (isset($product->weight))
|
||||
<td class="table-cell-text-center">{{ $product->weight }}</td>
|
||||
@endif
|
||||
@if (isset($product->pvc))
|
||||
<td class="table-cell-text-center">{{ $product->pvc }}€</td>
|
||||
@endif
|
||||
@php
|
||||
$priceKg = $product->weight ? (1000 * $product->pvc) / $product->weight : 0;
|
||||
@endphp
|
||||
<td class="table-cell-text-center">{{ number_format(round($priceKg, 2), 2, ',', ' ') }}€</td>
|
||||
</tr>
|
||||
</table>
|
||||
@if (isset($product->productKeywords))
|
||||
<p><strong>{{ __('Tendances identifiées : ') }}</strong>{{ Str::replaceLast(', ', '', $product->productKeywords) }}</p>
|
||||
@endif
|
||||
@if (isset($product->distribution_network))
|
||||
@endif
|
||||
<td class="table-cell-text-center">--,--€</td>
|
||||
</tr>
|
||||
</table>
|
||||
@if (isset($product->productKeywords))
|
||||
<p><strong>{{ __('Tendances identifiées : ') }}</strong>{{ $product->productKeywords }}</p>
|
||||
@endif
|
||||
@if (isset($product->distribution_network))
|
||||
<p><strong>{{ __('Réseau de distribution : ') }}</strong>{{ $product->distribution_network }}</p>
|
||||
@endif
|
||||
@if (isset($product->ray))
|
||||
@endif
|
||||
@if (isset($product->ray))
|
||||
<p><strong>{{ __('Rayon : ') }}</strong>{{ $product->ray }}</p>
|
||||
@endif
|
||||
@if (isset($product->product_range))
|
||||
@endif
|
||||
@if (isset($product->product_range))
|
||||
<p><strong>{{ __('Famille : ') }}</strong>{{ $product->product_range }}</p>
|
||||
@endif
|
||||
@if (isset($product->geo_area))
|
||||
@endif
|
||||
@if (isset($product->geo_area))
|
||||
<p><strong>{{ __('Zone géographique : ') }}</strong>{{ $product->geo_area }}</p>
|
||||
@endif
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@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
|
||||
@if(isset($product->productComments))
|
||||
@foreach ($product->productComments as $productComment)
|
||||
<p><strong>{{ __('Commentaire dégustation du : ') }}</strong>{{ $productComment->created_at }}</p>
|
||||
<table class="table" width="100%">
|
||||
<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>{{ __('Aspect') }}</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>{{ __('Goût') }}</strong></td>
|
||||
</tr>
|
||||
<tr class="table-body">
|
||||
<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->taste }}</td>
|
||||
<td class="table-cell-text-center" width="20%">{{ $productComment->odor }}</td>
|
||||
<td class="table-cell-text-center" width="20%">{{ $productComment->texture }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><strong>{{ __('Commentaire dégustation du : ') }}</strong>{{ $productComment->date }}</p>
|
||||
<table class="table" width="100%">
|
||||
<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>{{ __('Aspect') }}</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>{{ __('Goût') }}</strong></td>
|
||||
</tr>
|
||||
<tr class="table-body">
|
||||
<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->taste }}</td>
|
||||
<td class="table-cell-text-center" width="20%">{{ $productComment->odor }}</td>
|
||||
<td class="table-cell-text-center" width="20%">{{ $productComment->texture }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endforeach
|
||||
<table class="product-saw" width="100%">
|
||||
@endif
|
||||
<table width="100%" class="product-saw">
|
||||
<tr>
|
||||
@if (isset($product->seen_at))
|
||||
<td class="table-cell-text-center" width="50%">
|
||||
<strong>{{ __('Téléchargez les documents :') }}</strong>
|
||||
<a href="{{ route('products.download', $product->id) }}">{{ __('ICI') }}</a>
|
||||
</td>
|
||||
@endif
|
||||
@if (isset($product->source))
|
||||
<td class="table-cell-text-center" width="50%">
|
||||
<p><strong>{{ __('Vu le : ') }}</strong>{{ $product->seen_at }}</p>
|
||||
<p><strong>{{ __('Lieu : ') }}</strong>{{ $product->source }}, {{ $product->fair }}{{ $product->shop }}{{ $product->catalogue }}
|
||||
</p>
|
||||
<p><strong>{{ __('Par : ') }}</strong>{{ $product->user->firstname }} {{ $product->user->lastname }}</p>
|
||||
</td>
|
||||
<td class="table-cell-text-center" width="50%">
|
||||
<p><strong>{{ __('Vu le : ') }}</strong>{{ $product->seen_at }}</p>
|
||||
<p><strong>{{ __('Lieu : ') }}</strong>{{ $product->source }}, {{ $product->fair }}{{ $product->shop }}{{ $product->catalogue }}</p>
|
||||
<p><strong>{{ __('Par : ') }}</strong>{{ $product->user_id->firstname }} {{ $product->user_id->lastname }}</p>
|
||||
</td>
|
||||
@endif
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
h2 {
|
||||
font-weight: lighter;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
|
|
@ -60,11 +61,11 @@
|
|||
}
|
||||
|
||||
.table-header {
|
||||
background-color: #FFFFFF;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.table-header td {
|
||||
color: #000000;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.table-body td {
|
||||
|
|
@ -74,10 +75,6 @@
|
|||
.table-cell-text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-cell-text-start {
|
||||
text-align: start;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
<li>
|
||||
<a class="dropdown-item @if(request()->routeIs('products.*')) active @endif"
|
||||
href="{{ route('products.index') }}"
|
||||
title="{{ __('Administrer les :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||
title="{{ __('Administrer les :model', ['model' => __('models.classes.products')]) }}"
|
||||
data-bs="tooltip"
|
||||
data-bs-placement="right">
|
||||
{{ trans_choice('models.classes.products_monitoring', 2) }}
|
||||
{{ __('models.classes.products') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,115 +1,60 @@
|
|||
{{-- GET ACTUAL PAGINATION --}}
|
||||
@php
|
||||
$pagination = intval(
|
||||
Cache::get(
|
||||
'pagination.' .
|
||||
\Illuminate\Support\Str::slug(
|
||||
request()
|
||||
->route()
|
||||
->getName(),
|
||||
),
|
||||
),
|
||||
);
|
||||
@endphp
|
||||
@if ($paginator->items())
|
||||
<nav class="pagination-custom d-flex justify-content-between align-items-center">
|
||||
{{-- SELECT ITEMS PER PAGE --}}
|
||||
<div class="dropup-center d-flex justify-content-center align-items-center input-group w-fit">
|
||||
<span class="btn-md input-group-text" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="{{ __('crud.pagination.paginate_list') }}">
|
||||
<i class="fa-solid fa-list-ul"></i>
|
||||
</span>
|
||||
<button class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" type="button" aria-expanded="false">
|
||||
{{ $pagination }}
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
@foreach (\App\Enums\Pagination\ItemsPerPaginationEnum::toArray() as $itemsPerPaginationEnum)
|
||||
<li>
|
||||
<a class="dropdown-item user-select-none @if ($pagination === $itemsPerPaginationEnum->value) active @endif text-center"
|
||||
href="{{ request()->fullUrlWithQuery(['page' => 1, 'pagination' => $itemsPerPaginationEnum->value]) }}"
|
||||
role="button">
|
||||
{{ $itemsPerPaginationEnum->value }}
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@if ($paginator->hasPages())
|
||||
{{-- PAGINATION --}}
|
||||
<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
|
||||
@if ($paginator->hasPages())
|
||||
<nav>
|
||||
<ul class="pagination d-flex justify-content-center align-items-center m-0 mt-3">
|
||||
{{-- Previous Page Link --}}
|
||||
@if ($paginator->onFirstPage())
|
||||
<li class="page-item disabled" data-bs="tooltip" data-bs-placement="top"
|
||||
title="{{ __('Page précédente') }}" aria-disabled="true" aria-label="@lang('Page précédente')">
|
||||
<span class="page-link" aria-hidden="true">‹</span>
|
||||
</li>
|
||||
@else
|
||||
<li class="page-item">
|
||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top"
|
||||
title="{{ __('Page précédente') }}" href="{{ $paginator->previousPageUrl() }}"
|
||||
rel="prev" aria-label="@lang('Page précédente')">‹</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
{{-- Pagination Elements --}}
|
||||
@foreach ($elements as $element)
|
||||
{{-- "Three Dots" Separator --}}
|
||||
@if (is_string($element))
|
||||
<li class="page-item disabled" aria-disabled="true"><span
|
||||
class="page-link">{{ $element }}</span></li>
|
||||
@endif
|
||||
|
||||
{{-- Array Of Links --}}
|
||||
@if (is_array($element))
|
||||
@foreach ($element as $page => $url)
|
||||
@if ($page == $paginator->currentPage())
|
||||
<li class="page-item active" data-bs="tooltip" data-bs-placement="top"
|
||||
title="{{ __('Page actuelle') }}" aria-current="page">
|
||||
<span class="page-link">{{ $page }}</span>
|
||||
</li>
|
||||
@else
|
||||
<li class="page-item">
|
||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top"
|
||||
title="{{ __('Page n°:id', ['id' => $page]) }}"
|
||||
href="{{ $url }}">{{ $page }}</a>
|
||||
</li>
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- HIDE PAGES TOO FAR --}}
|
||||
@if ($paginator->currentPage() < $paginator->lastPage() - 3)
|
||||
<li class="page-item d-none d-sm-block disabled"><span class="page-link">...</span></li>
|
||||
@endif
|
||||
{{-- LAST PAGE --}}
|
||||
@if ($paginator->currentPage() < $paginator->lastPage() - 2)
|
||||
<li class="page-item d-none d-sm-block" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="{{ __('crud.pagination.specific_page', ['id' => $paginator->lastPage()]) }}">
|
||||
<a class="page-link"
|
||||
href="{{ request()->fullUrlWithQuery(['page' => $paginator->lastPage()]) }}">{{ $paginator->lastPage() }}</a>
|
||||
</li>
|
||||
@endif
|
||||
{{-- NEXT PAGE --}}
|
||||
<li class="page-item @if (!$paginator->hasMorePages()) disabled @endif">
|
||||
<a class="page-link d-flex align-items-center h-100" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="{{ __('crud.pagination.next') }}" aria-label="{{ __('crud.pagination.next') }}"
|
||||
@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
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
{{-- Next Page Link --}}
|
||||
@if ($paginator->hasMorePages())
|
||||
<li class="page-item">
|
||||
<a class="page-link" data-bs="tooltip" data-bs-placement="top" title="{{ __('Page suivante') }}"
|
||||
href="{{ $paginator->nextPageUrl() }}" rel="next"
|
||||
aria-label="@lang('Page suivante')">›</a>
|
||||
</li>
|
||||
@else
|
||||
<li class="page-item disabled" data-bs="tooltip" data-bs-placement="top"
|
||||
title="{{ __('Page suivante') }}" aria-disabled="true" aria-label="@lang('Page suivante')">
|
||||
<span class="page-link" aria-hidden="true">›</span>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</nav>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,4 @@
|
|||
multipdf: "{{ route('products.multipdf.update', ['id' => 'ID']) }}",
|
||||
duplicate: "{{ route('products.duplicate', ['product' => 'PRODUCT']) }}"
|
||||
};
|
||||
window.__SYSTEM._routes.brands = {
|
||||
store: "{{ route('brands.store') }}",
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
|||
@endphp
|
||||
{{-- NO Sort for order column --}}
|
||||
@if($col === 'order' or in_array($col, $ignore))
|
||||
@if(!$noOrder or $rst)
|
||||
@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">
|
||||
<span>{{ $colname }}</span>
|
||||
|
|
@ -34,6 +35,7 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
|||
<span>{{ $colname }}</span>
|
||||
</th>
|
||||
@endif
|
||||
@endif
|
||||
@continue
|
||||
@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="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">
|
||||
<h5 class="card-title">{{ trans_choice('models.classes.products_monitoring', 2) }}</h5>
|
||||
<h5 class="card-title">{{ __('models.classes.products') }}</h5>
|
||||
<p class="card-text text-muted fst-italic">{{ __('- accéder à l\'ensemble des produits enregistrés') }}</p>
|
||||
</div>
|
||||
<a href="{{ route('products.index') }}"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Accéder à la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||
title="{{ __('Accéder à la liste des :model', ['model' => __('models.classes.products')]) }}"
|
||||
data-bs="tooltip">
|
||||
{{ __('Consulter/Insérer une :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}
|
||||
{{ __('Voir la liste') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@extends('layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 1), Str::ucfirst(__('création'))))
|
||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('création'))))
|
||||
@section('description', __('Création d\'un produit'))
|
||||
@section('breadcrumb', 'no')
|
||||
|
||||
|
|
@ -14,17 +14,17 @@
|
|||
class="btn btn-primary text-decoration-none m-0"
|
||||
data-bs="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.products')]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 1) }}</span> <small class="text-muted">{{ Str::ucfirst(__('création')) }}</small>
|
||||
<span class="fw-bold">{{ Str::singular(__('models.classes.products')) }}</span> <small class="text-muted">{{ Str::ucfirst(__('création')) }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-success pull-end"
|
||||
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
|
|
@ -39,8 +39,8 @@
|
|||
<div class="col text-center">
|
||||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-success"
|
||||
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">{{ __('Sauvegarder') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@extends('layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 1), Str::ucfirst(__('édition'))))
|
||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('édition'))))
|
||||
@section('description', __('Édition d\'un produit'))
|
||||
@section('breadcrumb', 'no')
|
||||
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
class="btn btn-primary text-decoration-none m-0"
|
||||
data-bs="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => trans_choice('models.classes.products_monitoring', 2)]) }}"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.products')]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 1) }}</span> <small class="text-muted">{{ Str::ucfirst(__('édition')) }}</small>
|
||||
<span class="fw-bold">{{ Str::singular(__('models.classes.products')) }}</span> <small class="text-muted">{{ Str::ucfirst(__('édition')) }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
<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">
|
||||
<button id="formSubmitClone"
|
||||
type="button"
|
||||
class="btn btn-success pull-end"
|
||||
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
<button class="btn btn-danger"
|
||||
title="{{ __('Supprimer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
title="{{ __('Supprimer ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
|
|
@ -52,8 +52,8 @@
|
|||
<div class="col text-center">
|
||||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-success"
|
||||
title="{{ __('Sauvegarder cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Sauvegarder ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
<div class="row">
|
||||
{{-- TITLE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('Nom') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Titre') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('partials.inputs.varchar', [
|
||||
'id' => 'productName',
|
||||
'label' => __('Nom du :model', ['model' => Str::singular(__('models.classes.products'))]),
|
||||
'label' => __('Titre du :model', ['model' => Str::singular(__('models.classes.products'))]),
|
||||
'hasWordCounter' => true,
|
||||
'name' => 'name',
|
||||
'required' => true,
|
||||
'model' => $productModel ?? null,
|
||||
'placeholder' => '',
|
||||
'helper' => __('Doit décrire précisément le produit (3 caractères minimum, 255 maximum).'),
|
||||
])
|
||||
</div>
|
||||
|
|
@ -21,21 +20,17 @@
|
|||
</div>
|
||||
{{-- BRANDS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('models.classes.brands') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('partials.inputs.bigint-belongs-to', [
|
||||
@include('partials.inputs.bigint-foreign-id', [
|
||||
'id' => 'productBrand',
|
||||
'label' => trans(':model associé(e)', ['model' => Str::singular(trans('models.classes.brands'))]),
|
||||
'name' => 'brand_id',
|
||||
'model' => $productModel ?? null,
|
||||
'itemLimit' => [0, 1],
|
||||
'itemsList' => $brands,
|
||||
'storeRoute' => 'brands.store',
|
||||
'labelField' => 'name',
|
||||
'helper' => __('La marque associée au produit.'),
|
||||
'placeholder' => '',
|
||||
'require' => true,
|
||||
'label' => __('Marque associée'),
|
||||
'associatedModels' => $brands,
|
||||
'helper' => trans('Selectionnez un(e) :model parmis la liste.', ['model' => Str::singular(trans('models.classes.brands'))]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -43,47 +38,42 @@
|
|||
</div>
|
||||
{{-- SOURCE --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('Source') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __("Source") }}</legend>
|
||||
@php
|
||||
$data = [
|
||||
'id' => 'productSource',
|
||||
'label' => __('Source'),
|
||||
'name' => 'source',
|
||||
'model' => $productModel ?? null,
|
||||
'sourceEnum' => \App\Enums\Products\SourceEnum::toArray(),
|
||||
'productsFair' => $productsFair,
|
||||
'productsShop' => $productsShop,
|
||||
'productsCatalog' => $productsCatalog,
|
||||
'oldValue' => old('source') ?? ($productModel->source ?? 0),
|
||||
'oldDetails' => old('shop', old('fair', old('catalogue'))) ?? '',
|
||||
'helper' => __('Selectionnez un(e) Source maximum parmi la liste.'),
|
||||
];
|
||||
$data = [
|
||||
'id' => 'productSource',
|
||||
'label' => __('Source associé(e)'),
|
||||
'name' => 'source',
|
||||
'model' => $productModel ?? null,
|
||||
'sourceEnum' => \App\Enums\Products\SourceEnum::toArray(),
|
||||
'productsFair' => $productsFair,
|
||||
'productsShop' => $productsShop,
|
||||
'productsCatalog' => $productsCatalog,
|
||||
'helper' => __('Selectionnez un(e) Source maximum parmis la liste.')
|
||||
];
|
||||
@endphp
|
||||
<div class="source-inputs" data-json='@json($data)'></div>
|
||||
@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>
|
||||
</div>
|
||||
{{-- GENCOD --}}
|
||||
{{-- GENCODE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('GENCOD') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('GENCODE') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@php
|
||||
$data = [
|
||||
'id' => 'productGencod',
|
||||
'label' => __('Code'),
|
||||
'name' => 'gencod',
|
||||
'model' => $productModel ?? null,
|
||||
'value' => old('gencod') ?? ($productModel->gencod ?? null),
|
||||
'maxlength' => 13,
|
||||
'required' => false,
|
||||
'helper' => __('Saisir une suite de 13 chiffres maximum.'),
|
||||
];
|
||||
$data = [
|
||||
'id' => 'productGencod',
|
||||
'label' => __('Code'),
|
||||
'name' => 'gencod',
|
||||
'model' => $productModel ?? null,
|
||||
'value' => old('gencod') ?? $productModel->gencod ?? null,
|
||||
'maxlength' => 13,
|
||||
'required' => false,
|
||||
'helper' => __('Saisir une suite de 13 chiffres maximum.')
|
||||
];
|
||||
@endphp
|
||||
<div class="verification-code" data-json='@json($data)'></div>
|
||||
@include('modules.input-error', ['inputName' => 'gencod'])
|
||||
|
|
@ -93,7 +83,7 @@
|
|||
</div>
|
||||
{{-- URL --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('URL') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -104,7 +94,7 @@
|
|||
'name' => 'url',
|
||||
'required' => false,
|
||||
'model' => $productModel ?? null,
|
||||
'placeholder' => '',
|
||||
'placeholder' => __('https://google.com'),
|
||||
'helper' => __('Doit être une url valide.'),
|
||||
])
|
||||
</div>
|
||||
|
|
@ -113,9 +103,33 @@
|
|||
</div>
|
||||
{{-- IMAGE --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('Visuel de référence') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Image') }}</legend>
|
||||
<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">
|
||||
@include('partials.inputs.varchar-picture', [
|
||||
'id' => 'productImage',
|
||||
|
|
@ -133,33 +147,19 @@
|
|||
</div>
|
||||
{{-- DOCUMENTS --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('Documents complémentaires') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Documents') }}</legend>
|
||||
<div class="row">
|
||||
<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
|
||||
$data = [
|
||||
'id' => 'productDocs',
|
||||
'name' => 'docs[]',
|
||||
'value' => $productModel->docs ?? [],
|
||||
'limit' => [0, 5],
|
||||
'helper' => __('Doit respecter le format :format.', [
|
||||
'format' => '.xls,.csv,.xlsx,.png,.jpg,.jpeg,.gif,.doc,.docx,.ppt,.pdf,.txt',
|
||||
]),
|
||||
'errors' => $errors->getBag('default')->getMessages(),
|
||||
];
|
||||
$data = [
|
||||
'id' => 'productDocs',
|
||||
'name' => 'docs[]',
|
||||
'value' => $productModel->docs ?? [],
|
||||
'limit' => [0,5],
|
||||
'helper' => __('Doit respecter le format :format.', ['format' => '.pdf']),
|
||||
'errors' => $errors->getBag('default')->getMessages()
|
||||
];
|
||||
@endphp
|
||||
<div class="multiple-documents-input" data-json='@json($data)'></div>
|
||||
</div>
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
</div>
|
||||
{{-- CERTIFICATION --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Certification') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
'model' => $productModel ?? null,
|
||||
'require' => false,
|
||||
'associatedModels' => \App\Enums\Products\CertificationEnum::toArray(),
|
||||
'helper' => trans('Selectionnez une Certification parmi la liste.'),
|
||||
'helper' => trans('Selectionnez une Certification parmis la liste.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -187,18 +187,18 @@
|
|||
</div>
|
||||
{{-- ORIGINS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<legend>{{ __('Origine') }}</legend>
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Origines') }}</legend>
|
||||
<div class="row">
|
||||
@include('partials.inputs.select-multiple-enum', [
|
||||
'id' => 'productOrigins',
|
||||
'label' => __('Origine associée'),
|
||||
'label' => __('Origines associées'),
|
||||
'name' => 'origins',
|
||||
'itemsSelected' => old('origins', $productModel->origins ?? []),
|
||||
'itemsList' => collect(\App\Enums\Products\OriginEnum::toArray())->values(),
|
||||
'itemLimit' => [0, count(\App\Enums\Products\OriginEnum::toArray())],
|
||||
'placeholder' => '',
|
||||
'helper' => __('L\'origine associée au produit.'),
|
||||
'placeholder' => __('Recherchez une Origine a associer.'),
|
||||
'helper' => __('Les Origines associées au produit.'),
|
||||
'require' => false,
|
||||
])
|
||||
</div>
|
||||
|
|
@ -206,7 +206,7 @@
|
|||
</div>
|
||||
{{-- CLAIMS --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Allégations') }}</legend>
|
||||
<div class="row">
|
||||
@include('partials.inputs.select-multiple-enum', [
|
||||
|
|
@ -219,13 +219,13 @@
|
|||
'showSpecificItem' => [
|
||||
'name' => 'specified_claim',
|
||||
'label' => 'Précision de l\'allégation',
|
||||
'placeholder' => '',
|
||||
'value' => old('specified_claim', $productModel->specified_claim ?? null),
|
||||
'placeholder' => 'Sans sucre ajouté',
|
||||
'value' => $productModel->specified_claim ?? null,
|
||||
'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,
|
||||
'placeholder' => '',
|
||||
'placeholder' => __('Recherchez une Allégation a associer.'),
|
||||
'require' => false,
|
||||
'helper' => __('Les Allégations associées au produit.'),
|
||||
])
|
||||
|
|
@ -234,7 +234,7 @@
|
|||
</div>
|
||||
{{-- DISTRIBUTION NETWORK --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Réseau de distribution') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -243,9 +243,9 @@
|
|||
'label' => __('Réseau de distribution associé'),
|
||||
'name' => 'distribution_network',
|
||||
'model' => $productModel ?? null,
|
||||
'required' => true,
|
||||
'require' => true,
|
||||
'associatedModels' => \App\Enums\Products\DistributionNetworkEnum::toArray(),
|
||||
'helper' => trans('Selectionnez un Réseau de distribution parmi la liste.'),
|
||||
'helper' => trans('Selectionnez un Réseau de distribution parmis la liste.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
</div>
|
||||
{{-- RAY --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Rayon') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -262,9 +262,9 @@
|
|||
'label' => __('Rayon associé'),
|
||||
'name' => 'ray',
|
||||
'model' => $productModel ?? null,
|
||||
'required' => true,
|
||||
'require' => true,
|
||||
'associatedModels' => \App\Enums\Products\RayEnum::toArray(),
|
||||
'helper' => trans('Selectionnez un Rayon parmi la liste.'),
|
||||
'helper' => trans('Selectionnez un Rayon parmis la liste.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -272,7 +272,7 @@
|
|||
</div>
|
||||
{{-- RANGE --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Famille de produit') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -281,9 +281,9 @@
|
|||
'label' => __('Famille de produit associée'),
|
||||
'name' => 'product_range',
|
||||
'model' => $productModel ?? null,
|
||||
'required' => true,
|
||||
'require' => true,
|
||||
'associatedModels' => \App\Enums\Products\RangeEnum::toArray(),
|
||||
'helper' => trans('Selectionnez une Famille de produit parmi la liste.'),
|
||||
'helper' => trans('Selectionnez une Famille de produit parmis la liste.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -291,7 +291,7 @@
|
|||
</div>
|
||||
{{-- GEO AREA --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Zone géographique') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -300,9 +300,9 @@
|
|||
'label' => __('Zone géographique associée'),
|
||||
'name' => 'geo_area',
|
||||
'model' => $productModel ?? null,
|
||||
'required' => true,
|
||||
'require' => true,
|
||||
'associatedModels' => \App\Enums\Products\GeoAreaEnum::toArray(),
|
||||
'helper' => trans('Selectionnez une Zone géographique parmi la liste.'),
|
||||
'helper' => trans('Selectionnez une Zone géographique parmis la liste.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -310,7 +310,7 @@
|
|||
</div>
|
||||
{{-- WEIGHT --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Poids') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
|
|
@ -329,17 +329,16 @@
|
|||
</div>
|
||||
{{-- PVC --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('PVC') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('partials.inputs.int-number', [
|
||||
'id' => 'productPvc',
|
||||
'id' => 'productWeight',
|
||||
'label' => __('PVC de l\'UVC'),
|
||||
'name' => 'pvc',
|
||||
'model' => $productModel ?? null,
|
||||
'min' => 0,
|
||||
'step' => 0.01,
|
||||
'required' => false,
|
||||
'helper' => trans('Le prix doit être en euro (€).'),
|
||||
])
|
||||
|
|
@ -347,51 +346,9 @@
|
|||
</div>
|
||||
</fieldset>
|
||||
</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 --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border bg-white p-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Commentaire libre') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
|
@ -401,49 +358,63 @@
|
|||
'name' => 'comment',
|
||||
'model' => $productModel ?? null,
|
||||
'required' => false,
|
||||
'helper' => __(
|
||||
' Doit décrire précisément le contenu du produit, requiert entre 50 et 160 caractères, balise <meta> description.'),
|
||||
'placeholder' => '',
|
||||
'helper' => __(' Doit décrire précisément le contenu du produit, requiert entre 50 et 160 caractères, balise <meta> description.'),
|
||||
'placeholder' => __('Une description du contenu du produit pour les moteurs de recherche.'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</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 --}}
|
||||
<div class="col-12 mb-3">
|
||||
@php
|
||||
if (session()->getOldInput()['evaluation'] ?? null) {
|
||||
foreach (session()->getOldInput()['evaluation'] as $key => $value) {
|
||||
$commentOldModel[] = [
|
||||
'evaluation' => session()->getOldInput()['evaluation'][$key] ?? null,
|
||||
'aspect' => session()->getOldInput()['aspect'][$key] ?? null,
|
||||
'taste' => session()->getOldInput()['taste'][$key] ?? null,
|
||||
'odor' => session()->getOldInput()['odor'][$key] ?? null,
|
||||
'texture' => session()->getOldInput()['texture'][$key] ?? null,
|
||||
];
|
||||
}
|
||||
if (session()->getOldInput()['evaluation'] ?? null) {
|
||||
foreach (session()->getOldInput()['evaluation'] as $key => $value) {
|
||||
$commentOldModel[] = [
|
||||
"evaluation" => session()->getOldInput()['evaluation'][$key] ?? null,
|
||||
"aspect" => session()->getOldInput()['aspect'][$key] ?? null,
|
||||
"taste" => session()->getOldInput()['taste'][$key] ?? null,
|
||||
"odor" => session()->getOldInput()['odor'][$key] ?? null,
|
||||
"texture" => session()->getOldInput()['texture'][$key] ?? null,
|
||||
];
|
||||
}
|
||||
$data = [
|
||||
'id' => 'productSource',
|
||||
'title1' => __('Dégustation'),
|
||||
'label1' => __('Produit dégusté ?'),
|
||||
'name1' => 'is_tasted',
|
||||
'oldCheck' => boolval(old('is_tasted', null)),
|
||||
'model' => $productModel ?? null,
|
||||
'oldModel' => session()->getOldInput(),
|
||||
'max' => 15,
|
||||
'min' => 1,
|
||||
'helper1' => __('Le produit a été dégusté.'),
|
||||
'required1' => false,
|
||||
'title2' => __('Commentaires'),
|
||||
'name2' => 'tasters_number',
|
||||
'label2' => __('Nombre de dégustation'),
|
||||
'helper2' => __('Doit être un chiffre ou un nombre (minimum 1 et maximum 15).'),
|
||||
'required2' => false,
|
||||
'commentModel' => $commentModel ?? [],
|
||||
'commentOldModel' => $commentOldModel ?? [],
|
||||
'errors' => $errors->getBag('default')->getMessages() ?? [],
|
||||
];
|
||||
}
|
||||
$data = [
|
||||
'id' => 'productSource',
|
||||
'title1' => __("Dégustation"),
|
||||
'label1' => __('Produit dégusté ?'),
|
||||
'name1' => 'is_tasted',
|
||||
'model' => $productModel ?? null,
|
||||
'oldModel' => session()->getOldInput(),
|
||||
'max' => 15,
|
||||
'min' => 1,
|
||||
'helper1' => __('Le produit a été dégusté.'),
|
||||
'required1' => false,
|
||||
'title2' => __("Commentaires"),
|
||||
'name2' => 'tasters_number',
|
||||
'label2' => __('Nombre de dégustation'),
|
||||
'helper2' => __('Doit être un chiffre ou un nombre (minimum 1 et maximum 15).'),
|
||||
'required2' => false,
|
||||
'commentModel' => $commentModel ?? [],
|
||||
'commentOldModel' => $commentOldModel ?? [],
|
||||
'errors' => $errors->getBag('default')->getMessages() ?? []
|
||||
];
|
||||
@endphp
|
||||
<div class="tasted-product" data-json='@json($data)'></div>
|
||||
</div>
|
||||
|
|
@ -458,21 +429,5 @@
|
|||
event.preventDefault();
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@extends('layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', trans_choice('models.classes.products_monitoring', 2), Str::ucfirst(__('liste'))))
|
||||
@section('title', sprintf('%s - %s', __('models.classes.products'), Str::ucfirst(__('liste'))))
|
||||
@section('description', __('Liste des produits publiés'))
|
||||
@section('breadcrumb', 'no')
|
||||
|
||||
|
|
@ -9,15 +9,16 @@
|
|||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="text-md-start h2 text-center">
|
||||
<span class="fw-bold">{{ trans_choice('models.classes.products_monitoring', 2) }}</span> <span
|
||||
class="text-muted">{{ Str::ucfirst(__('liste')) }}</span>
|
||||
<h1 class="text-center text-md-start h2">
|
||||
<span class="fw-bold">{{ __('models.classes.products') }}</span> <span class="text-muted">{{ Str::ucfirst(__('liste')) }}</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="input-group justify-content-end">
|
||||
<a class="btn btn-success" data-bs="tooltip" href="{{ route('products.create') }}"
|
||||
title="{{ __('Ajouter une :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||
<a href="{{ route('products.create') }}"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Ajouter un :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
<div class="card-body">
|
||||
@include('pages.products.product-filters')
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6 p-3">
|
||||
<div class="col-12 col-md-6 p-0">
|
||||
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -37,10 +38,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6 p-3">
|
||||
<div class="col-12 col-md-6 p-0">
|
||||
{{ $products->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
|
|
|||
|
|
@ -1,103 +1,115 @@
|
|||
<div class="table-responsive">
|
||||
<table class="fix-action m-0 mt-3 table">
|
||||
<table class="table fix-action m-0 mt-3">
|
||||
<thead>
|
||||
@php
|
||||
$cols = [
|
||||
'name' => __('Nom'),
|
||||
'brand_id' => __('Marque'),
|
||||
'picture' => __('Image'),
|
||||
'multi_pdf' => __('Générer en pdf la sélection'),
|
||||
];
|
||||
$routeName = request()
|
||||
->route()
|
||||
->getName();
|
||||
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
|
||||
($noOrder = Session::get("$routeName.sort_col") !== 'order') and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
($noOrder = Session::get("$routeName.sort_col") !== '') and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
@endphp
|
||||
@include('modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => [], 'ignore' => ['multi_pdf']])
|
||||
@php
|
||||
$cols = [
|
||||
'name' => __('Nom'),
|
||||
'brand_id' => __('Marque'),
|
||||
'picture' => __('Image'),
|
||||
'updated_at' => __('Mis à jour le'),
|
||||
'multi_pdf' => __('Multi .pdf'),
|
||||
];
|
||||
$routeName = request()->route()->getName();
|
||||
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
|
||||
$noOrder = Session::get("$routeName.sort_col") !== 'order' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
$noOrder = Session::get("$routeName.sort_col") !== '' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
@endphp
|
||||
@include('modules.table-col-sorter', ['cols' => $cols, 'mobileHide' => [], 'ignore' => ['multi_pdf']])
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($products->count())
|
||||
@foreach ($products as $productModel)
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<span>{{ $productModel->name }}</span>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
@foreach ($brands as $key => $brand)
|
||||
@if ($brand->id === $productModel->brand_id)
|
||||
<p class="m-0">{{ $brand->name }}</p>
|
||||
@endif
|
||||
@endforeach
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
@if ($productModel->picture)
|
||||
<img class="bo-image-preview" src="{{ asset(resize($productModel->picture, 'productTiny')) }}">
|
||||
@else
|
||||
<p class="text-muted">{{ __('Aucune image enregistée') }}</p>
|
||||
@endif
|
||||
</td>
|
||||
{{-- @if (!$noOrder or $rst) --}}
|
||||
<td class="text-center align-middle">
|
||||
@php
|
||||
$data = [
|
||||
'id' => 'productSelectMultiPdf',
|
||||
'model' => $productModel,
|
||||
'printMultiProduct' => $printMultiProduct,
|
||||
];
|
||||
@endphp
|
||||
<div class="button-multi-pdf" data-json='@json($data)'></div>
|
||||
</td>
|
||||
{{-- @endif --}}
|
||||
<td class="text-end align-middle">
|
||||
<form class="d-inline confirmDeleteJS" action="{{ route('products.destroy', $productModel->id) }}"
|
||||
method="POST">
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<a class="btn btn-sm btn-info glightbox" data-gallery="product{{ $productModel->id }}"
|
||||
data-bs-title="{{ __('Visionner l\'image de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
data-bs="tooltip" type="button" href="{{ asset($productModel->picture) }}" target="_blank">
|
||||
<i class="fa-solid fa-image"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-warning" data-bs="tooltip" type="button"
|
||||
href="{{ route('products.download', $productModel) }}"
|
||||
title="{{ __('Télécharger les annexes de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-secondary btn-printing" data-bs="tooltip" data-id="{{ $productModel->id }}"
|
||||
type="button" href="{{ route('products.pdf.show', $productModel) }}"
|
||||
title="{{ __('Fichier .pdf de la :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}"
|
||||
target="blank">
|
||||
<i class="fa-solid fa-print"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-success" data-bs="tooltip"
|
||||
href="{{ route('products.duplicate', $productModel) }}"
|
||||
title="{{ __('Dupliquer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||
<i class="fa-solid fa-copy"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-primary" data-bs="tooltip" href="{{ route('products.edit', $productModel) }}"
|
||||
title="{{ __('Modifier cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</a>
|
||||
<button class="btn btn-sm btn-danger" data-bs="tooltip"
|
||||
title="{{ __('Supprimer cette :model', ['model' => trans_choice('models.classes.products_monitoring', 1)]) }}">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@foreach ($products as $productModel)
|
||||
<tr>
|
||||
<td class="align-middle text-center">
|
||||
<span>{{ $productModel->name }}</span>
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
@foreach($brands as $key => $brand)
|
||||
@if ($brand->id === $productModel->brand_id)
|
||||
<p class="m-0">{{ $brand->name }}</p>
|
||||
@endif
|
||||
@endforeach
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
@if(isset($productModel->picture))
|
||||
<img class="bo-image-preview" src="{{ asset($productModel->picture) }}">
|
||||
@else
|
||||
<p class="text-muted">{{ __('Aucune image enregistée') }}</p>
|
||||
@endif
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
<span class="badge bg-secondary text-wrap">
|
||||
{{ $productModel->updated_at->formatLocalized('%d/%m/%Y à %I:%M') }}
|
||||
</span>
|
||||
</td>
|
||||
@if(!$noOrder or $rst)
|
||||
<td class="align-middle text-center">
|
||||
@php
|
||||
$data = [
|
||||
'id' => 'productSelectMultiPdf',
|
||||
'model' => $productModel,
|
||||
'printMultiProduct' => $printMultiProduct,
|
||||
];
|
||||
@endphp
|
||||
<div class="button-multi-pdf" data-json='@json($data)'></div>
|
||||
</td>
|
||||
@endif
|
||||
<td class="align-middle text-end">
|
||||
<form action="{{ route('products.destroy', $productModel->id) }}" method="POST" class="d-inline confirmDeleteJS">
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<a class="btn btn-sm btn-info glightbox" type="button"
|
||||
href="{{ asset($productModel->picture) }}" target="_blank"
|
||||
data-gallery="product{{ $productModel->id }}"
|
||||
data-bs-title="{{ __('Visionner l\'image du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-image"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-warning" type="button"
|
||||
href="{{ route('products.download', $productModel) }}"
|
||||
title="{{ __('Télécharger les annexes du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-secondary btn-printing" type="button"
|
||||
href="{{ route('products.pdf.show', $productModel) }}"
|
||||
target="blank"
|
||||
title="{{ __('Fichier .pdf du :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip"
|
||||
data-id="{{ $productModel->id }}">
|
||||
<i class="fa-solid fa-print"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-success"
|
||||
href="{{ route('products.duplicate', $productModel) }}"
|
||||
title="{{ __('Dupliquer ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
data-bs="tooltip">
|
||||
<i class="fa-solid fa-copy"></i>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-primary"
|
||||
href="{{ route('products.edit', $productModel) }}"
|
||||
title="{{ __('Modifier ce :model', ['model' => Str::singular(__('models.classes.products'))]) }}"
|
||||
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
|
||||
<tr>
|
||||
<td class="text-center" colspan="{{ count($cols) + 1 }}">
|
||||
<span
|
||||
class="h3">{{ __('Aucun résultat pour les :models', ['models' => trans_choice('models.classes.products_monitoring', 2)]) }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="{{ count($cols)+1 }}" class="text-center">
|
||||
<span
|
||||
class="h3">{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.products')]) }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
@php
|
||||
$iArgs = [];
|
||||
if (request()->sort_col) {
|
||||
if(request()->sort_col) {
|
||||
$iArgs['sort_col'] = request()->sort_col;
|
||||
}
|
||||
|
||||
if (request()->search) {
|
||||
if(request()->search) {
|
||||
$iArgs['search'] = request()->sort_way;
|
||||
}
|
||||
@endphp
|
||||
|
|
@ -12,181 +12,173 @@
|
|||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header border-0 p-0">
|
||||
<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">
|
||||
<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">
|
||||
{{ __('Filtres') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="border-top collapse" id="collapseProductsFilters">
|
||||
<div class="card-body">
|
||||
<form id="searchForm" action="{{ request()->url() }}">
|
||||
{{-- ALWAYS RESET SEARCH TO PAGE 1 --}}
|
||||
<input name="page" type="hidden" value="1">
|
||||
<!-- GENERAL INFORMATIONS -->
|
||||
<div class="row w-100 mx-auto">
|
||||
<div class="col-12 col-md-6">
|
||||
<input class="form-control" name="name" type="text" value="{{ request()->get('name') }}"
|
||||
placeholder="Nom">
|
||||
<input name="name" type="text" class="form-control" placeholder="Nom" value="{{ $queryParameters['name'] ?? null }}">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
||||
<select class="form-select" name="brand_id">
|
||||
<option value="">{{ __('Marque') }}</option>
|
||||
@foreach ($brands as $key => $brand)
|
||||
<option value="{{ $brand->id }}" @if (request()->get('brand_id') == $brand->id) selected @endif>
|
||||
{{ $brand->name }}</option>
|
||||
<option value="0">{{ __('Marque') }}</option>
|
||||
@foreach($brands as $key => $brand)
|
||||
<option @if($queryParameters['brand_id'] ?? null == $brand->id) selected @endif value="{{ $brand->id }}">{{ $brand->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<input class="form-control" name="gencod" type="text" value="{{ request()->get('gencod') }}"
|
||||
placeholder="GENCOD">
|
||||
<input name="gencod" type="text" class="form-control" placeholder="GENCODE" value="{{ $queryParameters['gencod'] ?? null }}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- SOURCE -->
|
||||
{{-- 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="row w-100 pt-3 mt-3 mx-auto border-top">
|
||||
<div class="col-12 col-md-6">
|
||||
<select class="form-select" name="source">
|
||||
<option value="">{{ __('Source') }}</option>
|
||||
@foreach (\App\Enums\Products\SourceEnum::toArray() as $key => $source)
|
||||
<option value="{{ $source->value }}" @if (request()->get('source') == $source->value) selected @endif>
|
||||
{{ $source->label }}</option>
|
||||
<option value="0">{{ __('Source') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||
<input class="form-control" name="shop" type="text" value="{{ request()->get('shop') }}"
|
||||
placeholder="{{ __('Magasin') }}">
|
||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
||||
<input name="shop" type="text" class="form-control" placeholder="Magasin" value="{{ $queryParameters['shop'] ?? null }}">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<input class="form-control" name="fair" type="text" value="{{ request()->get('fair') }}"
|
||||
placeholder="{{ __('Salon') }}">
|
||||
<input name="fair" type="text" class="form-control" placeholder="Salon" value="{{ $queryParameters['fair'] ?? null }}">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<input class="form-control" name="catalogue" type="text" value="{{ request()->get('catalogue') }}"
|
||||
placeholder="{{ __('Catalogue') }}">
|
||||
<input name="catalogue" type="text" class="form-control" placeholder="Catalogue" value="{{ $queryParameters['catalogue'] ?? null }}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- CLAIMS -->
|
||||
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
||||
<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', [
|
||||
'id' => 'productsClaim',
|
||||
'name' => 'claims',
|
||||
'itemsSelected' => collect(request()->get('claims', []))->filter(fn($value) => is_numeric($value)),
|
||||
'itemsList' => collect(\App\Enums\Products\ClaimEnum::toArray())->values(),
|
||||
'itemLimit' => [0, count(\App\Enums\Products\ClaimEnum::toArray())],
|
||||
'itemsSelected' => $selectedItemList,
|
||||
'itemsList' => $itemsList,
|
||||
'itemLimit' => [0, count($itemsList)],
|
||||
'placeholder' => __('Recherchez une Allégation'),
|
||||
'simpleComponent' => true,
|
||||
])
|
||||
</div>
|
||||
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||
<input class="form-control" name="specified_claim" type="text"
|
||||
value="{{ request()->get('specified_claim') }}" placeholder="Allégation complémentaire">
|
||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
||||
<input name="specified_claim" type="text" class="form-control" placeholder="Allégation complémentaire" value="{{ $queryParameters['specified_claim'] ?? null }}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- OTHERS -->
|
||||
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
||||
<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', [
|
||||
'id' => 'productsOrigin',
|
||||
'name' => 'origins',
|
||||
'itemsSelected' => collect(request()->get('origins', []))->filter(
|
||||
fn($value) => is_numeric($value)),
|
||||
'itemsList' => collect(\App\Enums\Products\OriginEnum::toArray())->values(),
|
||||
'itemLimit' => [0, count(\App\Enums\Products\OriginEnum::toArray())],
|
||||
'itemsSelected' => $selectedItemList,
|
||||
'itemsList' => $itemsList,
|
||||
'itemLimit' => [0, count($itemsList)],
|
||||
'placeholder' => __('Recherchez une Origine'),
|
||||
'simpleComponent' => true,
|
||||
])
|
||||
</div>
|
||||
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
||||
<select class="form-select" name="certification">
|
||||
<option value="">{{ __('Certification') }}</option>
|
||||
@foreach (\App\Enums\Products\CertificationEnum::toArray() as $key => $certification)
|
||||
<option value="{{ $certification->value }}" @if (request()->get('certification') == $certification->value) selected @endif>
|
||||
{{ $certification->label }}</option>
|
||||
<option value="0">{{ __('Certification') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<select class="form-select" name="distribution_network">
|
||||
<option value="">{{ __('Réseau de distribution') }}</option>
|
||||
@foreach (\App\Enums\Products\DistributionNetworkEnum::toArray() as $key => $distribution_network)
|
||||
<option value="{{ $distribution_network->value }}"
|
||||
@if (request()->get('distribution_network') == $distribution_network->value) selected @endif>{{ $distribution_network->label }}</option>
|
||||
<option value="0">{{ __('Réseau de distribution') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<select class="form-select" name="ray">
|
||||
<option value="">{{ __('Rayons') }}</option>
|
||||
@foreach (\App\Enums\Products\RayEnum::toArray() as $key => $ray)
|
||||
<option value="{{ $ray->value }}" @if (request()->get('ray') == $ray->value) selected @endif>
|
||||
{{ $ray->label }}</option>
|
||||
<option value="0">{{ __('Rayons') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<select class="form-select" name="product_range">
|
||||
<option value="">{{ __('Famille de produit') }}</option>
|
||||
@foreach (\App\Enums\Products\RangeEnum::toArray() as $key => $product_range)
|
||||
<option value="{{ $product_range->value }}" @if (request()->get('product_range') == $product_range->value) selected @endif>
|
||||
{{ $product_range->label }}</option>
|
||||
<option value="0">{{ __('Famille de produit') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1">
|
||||
<select class="form-select" name="geo_area">
|
||||
<option value="">{{ __('Secteur') }}</option>
|
||||
@foreach (\App\Enums\Products\GeoAreaEnum::toArray() as $key => $geo_area)
|
||||
<option value="{{ $geo_area->value }}" @if (request()->get('product_range') == $geo_area->value) selected @endif>
|
||||
{{ $geo_area->label }}</option>
|
||||
<option value="0">{{ __('Secteur') }}</option>
|
||||
@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>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- KEYWORDS -->
|
||||
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
||||
<div class="col-12 col-md-6">
|
||||
@php
|
||||
$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
|
||||
@include('partials.inputs.select-multiple-enum', [
|
||||
'id' => 'productsKeywords',
|
||||
'id' => 'productsKeywordsn',
|
||||
'name' => 'keywords',
|
||||
'itemsSelected' => collect(request()->get('keywords', []))->filter(
|
||||
fn($value) => is_numeric($value)),
|
||||
'itemsList' => $itemsList->values(),
|
||||
'itemLimit' => [0, $itemsList->count()],
|
||||
'placeholder' => __('Recherchez une tendance'),
|
||||
'itemsSelected' => $selectedItemList,
|
||||
'itemsList' => $itemsList,
|
||||
'itemLimit' => [0, count($itemsList)],
|
||||
'placeholder' => __('Recherchez un mot clé'),
|
||||
'simpleComponent' => true,
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
<!-- DATES -->
|
||||
<div class="row w-100 border-top mx-auto mt-3 pt-3">
|
||||
<div class="col-12 col-md-6 m-md-0 mt-1">
|
||||
<label class="text-muted fst-italic">{{ __('Saisie après le :') }}</label>
|
||||
<input class="form-control" name="date_after" type="date"
|
||||
value="{{ request()->query('date_after') }}">
|
||||
</div>
|
||||
<div class="row w-100 pt-3 mt-3 mx-auto border-top">
|
||||
<div class="col-12 col-md-6">
|
||||
<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 }}">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mt-1 m-md-0">
|
||||
<label class="text-muted fst-italic">{{ __('Saisie avant le :') }}</label>
|
||||
<input class="form-control" name="date_before" type="date"
|
||||
value="{{ request()->query('date_before') }}">
|
||||
<input name="date_after" type="date" class="form-control" value="{{ $queryParameters['date_after'] ?? null }}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- BUTTONS -->
|
||||
<div class="d-flex justify-content-center input-group border-top mt-3 pt-3">
|
||||
<button class="btn btn-primary" data-bs="tooltip" type="submit" title="{{ __('Lancer la recherche') }}">
|
||||
<div class="d-flex justify-content-center input-group pt-3 mt-3 border-top">
|
||||
<button type="submit" class="btn btn-primary" data-bs="tooltip" title="{{ __('Lancer la recherche') }}">
|
||||
{{ __('Rechercher') }}
|
||||
</button>
|
||||
<a class="p-0" href="{{ request()->url() }}">
|
||||
<button class="btn btn-danger rounded-0 rounded-end" data-bs="tooltip" type="button"
|
||||
<button type="button" data-bs="tooltip" class="btn btn-danger rounded-0 rounded-end"
|
||||
title="{{ __('Effacer la recherche') }}">
|
||||
<i class="fas fa-backspace"></i>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
@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,10 +2,8 @@
|
|||
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }} *</b></label>
|
||||
@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)
|
||||
<option value="{{ $associatedModel->id }}" @if (old($name, $model->{$name} ?? $value ?? null) == $associatedModel->id) selected @endif>
|
||||
<option value="{{ $associatedModel->id }}" @if (old($name, $model->{$name} ?? 1) == $associatedModel->id) selected @endif>
|
||||
{{ $associatedModel->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -7,14 +7,10 @@
|
|||
id="{{ $id }}"
|
||||
name="{{ $name }}"
|
||||
type="number"
|
||||
value="{{ old($name, $model->{$name} ?? $value ?? null) }}"
|
||||
value="{{ old($name, $model->{$name} ?? 0) }}"
|
||||
class="form-control"
|
||||
aria-describedby="{{ $id }}Help"
|
||||
@if(!empty($step))
|
||||
step="{{ $step }}"
|
||||
@else
|
||||
step="1"
|
||||
@endif
|
||||
@if(!empty($max))
|
||||
max="{{ $max }}"
|
||||
@else
|
||||
|
|
@ -26,8 +22,6 @@
|
|||
min="{{ !empty($unsigned) ? '0' : '-2147483648' }}"
|
||||
@endif
|
||||
@if(!empty($required))required @endif
|
||||
@if(!empty($disabled))disabled @endif
|
||||
@if(!empty($readonly))readonly @endif
|
||||
>
|
||||
@include('modules.input-error', [
|
||||
'inputName' => $name,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }}@if(!empty($required)) * @endif</b></label>
|
||||
@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)
|
||||
<option value="{{ $associatedModel->value}}" @if (old($name, $model->{$name}->value ?? $value ?? null) == $associatedModel->value) selected @endif>
|
||||
<option value="{{ $associatedModel->value}}" @if (old($name, $model->{$name}->value ?? $value ?? 1) == $associatedModel->value) selected @endif>
|
||||
{{ $associatedModel->label }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\BrandController;
|
||||
use App\Http\Controllers\DashboardController;
|
||||
use App\Http\Controllers\ProductController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -10,10 +9,6 @@ Route::get('/', [DashboardController::class, 'show'])->name('dashboard');
|
|||
|
||||
// * PRODUCTS
|
||||
Route::resource('products', ProductController::class)->except(['show']);
|
||||
|
||||
// * BRANDS
|
||||
Route::resource('brands', BrandController::class)->only(['store']);
|
||||
|
||||
Route::prefix('/product')
|
||||
->name('products.')
|
||||
->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 checker from "vite-plugin-checker";
|
||||
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 vue from "@vitejs/plugin-vue";
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
|
|
@ -41,7 +41,6 @@ export default defineConfig({
|
|||
},
|
||||
plugins: [
|
||||
checker({
|
||||
enableBuild: true,
|
||||
vueTsc: {
|
||||
root: ".",
|
||||
tsconfigPath: "tsconfig.json",
|
||||
|
|
@ -75,7 +74,7 @@ export default defineConfig({
|
|||
"**/vendor/**/*.scss",
|
||||
"**/vendor/**/*.css",
|
||||
],
|
||||
lintOnStart: false,
|
||||
lintOnStart: true,
|
||||
emitError: true,
|
||||
emitWarning: true,
|
||||
emitErrorAsWarning: false,
|
||||
|
|
@ -85,7 +84,7 @@ export default defineConfig({
|
|||
cache: false,
|
||||
extensions: ["js", "ts"],
|
||||
include: "**/*.ts",
|
||||
lintOnStart: false,
|
||||
lintOnStart: true,
|
||||
emitWarning: true,
|
||||
emitError: true,
|
||||
failOnWarning: false,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue