Compare commits

..

89 commits

Author SHA1 Message Date
Vincent BRIDIER
c5ef81f668 Merge branch 'trunk' 2026-10-23 15:30:00 +02:00
Vincent BRIDIER
4fcc529864 Merge branch 'develop' into trunk 2026-10-23 15:29:41 +02:00
Vincent BRIDIER
bfbf4e9e01 feat: Change Apache PID 2026-10-23 15:29:33 +02:00
K.
500f127090 Merge branch 'hotfix' into 'master'
Hotfix

See merge request ldc-web/projets/jeusselin!31
2026-10-22 15:51:59 +00:00
Jeremy Munsch
54848f4be6
chore: bump php deps to 8.5 2026-10-22 17:43:14 +02:00
Jeremy Munsch
23b40f4d63
build: bump php version 2026-10-22 17:43:05 +02:00
Noah Lancien
250058c085 Merge branch 'develop' into trunk 2026-10-22 17:37:30 +02:00
Noix
b52e4d2747 Merge branch 'bump-php' into 'develop'
Bump php

See merge request ldc-web/projets/jeusselin!30
2026-10-22 15:36:06 +00:00
Jeremy Munsch
883060e2dd
chore: bump php deps to 8.5 2026-10-22 17:23:08 +02:00
Jeremy Munsch
b8005a2a04
build: bump php version 2026-10-22 17:22:17 +02:00
K Muller
d8428b494e Merge branch 'develop' into trunk 2026-10-08 13:06:04 +02:00
Karl M'muller
470a84ae86 Merge branch 'fix-wysiwyg' into 'develop'
fix: 🐛 missing exclude sanitize html on news->content

See merge request ldc-web/projets/jeusselin!27
2026-10-08 11:05:04 +00:00
K Muller
8d281c2159 fix: 🐛 missing exclude sanitize html on news->content 2026-10-05 11:23:26 +02:00
Noah Lancien
a8426f80c6 Merge branch 'develop' into trunk 2026-10-01 10:37:41 +02:00
Noix
872332ea9a Merge branch 'issue-21' into 'develop'
feat: ✨ update info on cantact-us page

See merge request ldc-web/projets/jeusselin!26
2026-10-01 08:31:26 +00:00
Abdel LAMRANI
7c134c1fb2 feat: ✨ update info on cantact-us page 2026-09-29 09:30:30 +02:00
Noah Lancien
1c18491a86 Merge branch 'develop' into trunk 2026-09-28 11:08:04 +02:00
Noah Lancien
71b8339d96 fix: 🐛 fix compilation for prod 2026-09-28 11:07:24 +02:00
Noah Lancien
fcf49ba582 Merge branch 'develop' into trunk 2026-09-25 16:58:40 +02:00
Noix
968ee32e8d Merge branch 'create-customer' into 'develop'
fix: 🐛 add missing fields when creating local customer when exists in CRM #30

See merge request ldc-web/projets/jeusselin!20
2026-09-25 10:43:57 +00:00
Noix
a41085e550 Merge branch 'attempt-null' into 'develop'
fix: 🐛 determines whether show cotations or not when the base is empty #32

See merge request ldc-web/projets/jeusselin!21
2026-09-25 10:16:20 +00:00
Noix
040efd9ec3 Merge branch 'issue-12' into 'develop'
feat: ✨ handle image on general config

See merge request ldc-web/projets/jeusselin!25
2026-09-25 10:15:34 +00:00
Noix
4785300c85 Merge branch 'issue-24' into 'develop'
fix: 🐛 filter and show objectives

See merge request ldc-web/projets/jeusselin!24
2026-09-25 10:13:56 +00:00
Noix
74692d7664 Merge branch 'issue-13' into 'develop'
feat: ✨ update section

See merge request ldc-web/projets/jeusselin!23
2026-09-25 10:13:29 +00:00
Abdel LAMRANI
0b33324ff5 add alt and title 2026-09-24 16:41:59 +02:00
Abdel LAMRANI
4c45312724 feat: ✨ handle image on general config 2026-09-24 16:16:23 +02:00
Abdel LAMRANI
8a28d31e5f bug: 🐛 fix filter and show objectives 2026-09-24 12:37:43 +02:00
Abdel LAMRANI
0e430f84d0 feat: ✨ update section 2026-09-23 15:56:57 +02:00
Noah Lancien
c9178a139d Merge branch 'develop' into trunk 2026-09-10 12:32:28 +02:00
Noix
159b96b8db Merge branch '27-add-missing-links' into 'develop'
feat: ✨ add missing links to register page

See merge request ldc-web/projets/jeusselin!22
2026-09-10 10:29:01 +00:00
Corentin Huet
3a7b4a9bf2 feat: ✨ add missing links to register page 2026-09-02 15:05:42 +02:00
Alexis Gousseau
8346e604e3
fix: 🐛 determines whether show cotations or not when the base is empty #32 2026-08-04 17:15:14 +02:00
Alexis Gousseau
b60f61ad1f
fix: 🐛 add missing fields when update local customer when exists in CRM #30 #31 2026-08-04 15:16:05 +02:00
K Muller
09959e412b Merge branch 'trunk' 2026-07-31 14:04:46 +02:00
K Muller
76824459f8 Merge branch 'develop' into trunk 2026-07-31 14:04:30 +02:00
Karl M'muller
9a0c18b6dc Merge branch '28-disconnect' into 'develop'
fix: 🐛 disconnect bouton was broken

See merge request ldc-web/projets/jeusselin!19
2026-07-31 12:03:35 +00:00
Noah Lancien
dcf00f61ac fix: 🐛 disconnect bouton was broken 2026-07-30 16:57:03 +02:00
K Muller
6ea7a4117f Merge branch 'trunk' 2026-07-17 15:39:05 +02:00
K Muller
4ea9f35108 Merge branch 'develop' into trunk 2026-07-17 14:31:42 +02:00
Karl M'muller
e3eb3167ec Merge branch 'issue-25' into 'develop'
fix: 🐛 error with trash customer model

See merge request ldc-web/projets/jeusselin!18
2026-07-17 12:31:05 +00:00
K Muller
89db64859b fix: 🐛 error with trash customer model 2026-07-17 14:01:31 +02:00
Noix
702ea23e02 Merge branch 'hotfix' into 'master'
HOTFIX -> à répliquer sur Develop, fix: Fixes #23 correction sur l'affichage des dates isoFormat

See merge request ldc-web/projets/jeusselin!16
2026-05-04 15:16:31 +00:00
Noah Lancien
a10ff94d4a Merge branch 'trunk' 2026-04-24 11:36:44 +02:00
Noah Lancien
6583a8f01e Merge branch 'develop' into trunk 2026-04-24 11:36:31 +02:00
Noah Lancien
3c6762ae2d Merge branch 'trunk' 2026-04-21 16:51:27 +02:00
Noah Lancien
ee1e33e036 Merge branch 'develop' into trunk 2026-04-21 16:51:11 +02:00
Noah Lancien
8c52e52079 Merge branch 'develop' into trunk 2026-03-25 16:43:59 +01:00
Noah Lancien
2023eca826 Merge branch 'develop' into trunk 2026-03-24 15:27:39 +01:00
Noah Lancien
48a50d07f8 Merge branch 'develop' into trunk 2026-03-24 15:05:49 +01:00
Noah Lancien
81125b461e Merge branch 'develop' into trunk 2026-03-24 14:53:01 +01:00
Noah Lancien
f813cc214a Merge branch 'develop' into trunk 2026-03-24 14:46:41 +01:00
Noah Lancien
42da6618dc Merge branch 'develop' into trunk 2026-03-24 14:39:28 +01:00
Noah Lancien
6013663d73 Merge branch 'trunk' 2026-03-04 16:40:11 +01:00
Noah Lancien
ba79189293 Merge branch 'develop' into trunk 2026-03-04 16:25:08 +01:00
Noah Lancien
29ef828dbe Merge branch 'trunk' 2026-02-13 12:51:17 +01:00
Noah Lancien
ed8798ac66 Merge branch 'develop' into trunk 2026-02-13 12:50:53 +01:00
Noah Lancien
76edd08394 Merge branch 'develop' into trunk 2026-01-08 17:06:19 +01:00
Noah Lancien
a8d34cd23b Merge branch 'trunk' 2025-10-09 13:11:31 +02:00
Noah Lancien
eb51d562c1 Merge branch 'develop' into trunk 2025-10-09 13:02:12 +02:00
Noah Lancien
fa19527c3e Merge branch 'trunk' 2025-10-09 12:11:51 +02:00
Noah Lancien
e6b8b7402a Merge branch 'develop' into trunk 2025-10-09 12:11:35 +02:00
Noah Lancien
bc53526a08 Merge branch 'trunk' 2025-01-14 12:39:44 +01:00
Noah Lancien
86052f72b5 Merge branch 'develop' into trunk 2025-01-14 12:39:05 +01:00
Noah Lancien
e1275ecf96 Merge branch 'trunk' 2024-09-10 12:13:19 +02:00
Noah Lancien
52b80aba00 Merge branch 'develop' into trunk 2024-09-10 12:12:54 +02:00
Noah Lancien
13a1340a61 Merge branch 'trunk' 2024-09-10 11:41:26 +02:00
Noah Lancien
63548d0e3c Merge branch 'develop' into trunk 2024-09-10 11:27:26 +02:00
Noah Lancien
8d351fbc6c Merge branch 'develop' into trunk 2024-09-10 11:03:24 +02:00
Noah Lancien
b16c89eb88 Merge branch 'trunk' 2024-09-03 10:11:23 +02:00
Noah Lancien
6fa7f53714 Merge branch 'develop' into trunk 2024-09-03 10:11:07 +02:00
Noah Lancien
579eff439f Merge branch 'trunk' 2024-09-02 14:39:54 +02:00
Noah Lancien
6c47de0cf0 Merge branch 'develop' into trunk 2024-09-02 14:39:20 +02:00
Noah Lancien
3f7059e9fb Merge branch 'trunk' 2024-08-13 15:25:57 +02:00
Noah Lancien
4b522e7c21 Merge branch 'develop' into trunk 2024-08-13 15:25:32 +02:00
Vincent BRIDIER
66e0f1d523
Merge branch 'trunk' 2024-08-13 14:34:33 +02:00
Noah Lancien
456a5deeab Merge branch 'develop' into trunk 2024-08-13 12:55:53 +02:00
Noah Lancien
e35081cfa7 Merge branch 'develop' into trunk 2024-08-13 12:46:39 +02:00
Noah Lancien
c9ac965e74 Merge branch 'develop' into trunk 2024-08-05 10:50:37 +02:00
Noah Lancien
2bb81e7bcd Merge branch 'develop' into trunk 2024-08-05 09:44:27 +02:00
Jérémy Munsch
bfb62cf5ba
Merge branch 'develop' into trunk 2024-01-29 17:11:32 +01:00
Jérémy Munsch
df4db5fb5a
Merge branch 'develop' into trunk 2024-01-29 10:39:08 +01:00
Vincent BRIDIER
655eedb52e
Merge branch 'trunk' 2023-07-26 11:15:40 +02:00
Vincent BRIDIER
aec90d91e8
Merge branch 'develop' into trunk 2023-07-26 11:15:08 +02:00
Olivier Legat
a5c72b9cbe Merge branch 'trunk' 2022-03-15 14:12:34 +01:00
Olivier Legat
a473d4a49c Merge branch 'develop' into trunk 2022-03-15 14:12:18 +01:00
Olivier Legat
dbf2d39f8a Merge branch 'trunk' 2022-03-14 16:45:46 +01:00
Olivier Legat
1f1ccf0807 Merge branch 'develop' into trunk 2022-03-14 16:45:20 +01:00
Olivier Legat
194bf51032 Merge branch 'trunk' 2022-01-24 15:32:19 +01:00
Olivier Legat
90451c7a89 Merge branch 'develop' into trunk 2022-01-24 15:31:44 +01:00
34 changed files with 1454 additions and 1069 deletions

View file

@ -1,5 +1,9 @@
ARG PHP_8_5_TAG=latest
FROM composer:2.9.2 AS vendor
WORKDIR /app
ARG GITLAB_USER
ARG GITLAB_PASSWORD
@ -8,7 +12,7 @@ COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
RUN composer config gitlab-token.lab.s-web.fr "${GITLAB_USER}" "${GITLAB_PASSWORD}"
RUN composer install \
--ignore-platform-reqs \
--no-interaction \
@ -28,9 +32,10 @@ COPY resources/ /app/resources/
WORKDIR /app
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
RUN npm ci && npm run prod
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.4:170625-130159
ARG PHP_8_5_TAG
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
ARG USER=www-data

View file

@ -8,7 +8,6 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
@ -34,8 +33,8 @@ class CrmUserProvider extends EloquentUserProvider implements UserProvider
*/
public function retrieveByCredentials(array $credentials): \Illuminate\Contracts\Auth\Authenticatable|null
{
// * Let laravel find a model
$model = parent::retrieveByCredentials($credentials) ?? self::retrieveTrashed($credentials);
/** @var \Illuminate\Contracts\Auth\Authenticatable|null $model */
$model = parent::retrieveByCredentials($credentials);
try {
/** @var \LDC\LDCCRM\CrmApiV4 */
@ -90,22 +89,12 @@ class CrmUserProvider extends EloquentUserProvider implements UserProvider
/** @var \LDC\LDCCRM\CrmApiV4 */
$crm = app('crmAPI');
// * If has trait soft delete and customer trashed, then restore customer.
if (
\in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, \class_uses_recursive($model)) and
// @phpstan-ignore-next-line
$model->trashed()
) {
// @phpstan-ignore-next-line
$model->restore();
}
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed
return $crm->login($credentials['email'], $credentials['password']);
} catch (ApiErrorException $e) {
// @phpstan-ignore-next-line
if (!$model->hashcode or !CrmCustomer::find($model->hashcode)) {
$model->forceDelete();
$model->delete();
return false;
}
if ($e->getApiError()->equals(ApiError::authFailed)) {
@ -140,7 +129,9 @@ class CrmUserProvider extends EloquentUserProvider implements UserProvider
{
/** @var \Illuminate\Database\Eloquent\Model $model */
$model = $this->usedModel::firstOrNew([
'email' => $crmCustomer->email
'email' => $crmCustomer->email,
'firstname' => $crmCustomer->firstname,
'lastname' => $crmCustomer->lastname,
]);
// @phpstan-ignore-next-line
$model->hashcode = $crmCustomer->hashcode;
@ -150,33 +141,4 @@ class CrmUserProvider extends EloquentUserProvider implements UserProvider
return $model;
}
/**
* Retrieve a trashed customer by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
* @throws \ErrorException If cannot connect to LDAP.
*/
private function retrieveTrashed(array $credentials): ?\Illuminate\Contracts\Auth\Authenticatable
{
// * Make changes
if (empty($credentials)) {
return null;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a customer, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (!Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
// @phpstan-ignore-next-line
return $query->withTrashed()->first();
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\GeneralConfig;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
class GeneralConfigController extends Controller
{
/**
* Display the general configuration edit form.
*
* @return View
*/
public function edit(): View
{
return view('bo.general-config.edit', [
'config' => GeneralConfig::current(),
]);
}
/**
* Upload and store the "Nos métiers" page image.
*
* @param Request $request
* @return RedirectResponse
*/
public function upload(Request $request): RedirectResponse
{
$config = GeneralConfig::current();
$ancienne = $config->get('image');
$request->validate(
[
'image' => [$ancienne ? 'nullable' : 'required', 'image', 'mimes:jpeg,png,jpg', 'max:2048', 'dimensions:width=742,height=464'],
'image_alt' => ['required', 'string', 'min:5','max:50'],
'image_title' => ['required', 'string', 'min:5','max:50'],
],
['image.dimensions' => "L'image doit faire exactement 742 × 464 px."]
);
if ($request->hasFile('image')) {
$photo = $request->file('image');
$imageName = 'image-' . now()->format('YmdHis') . '.' . $photo->extension();
$path = $photo->storeAs(
sprintf('modelfiles/general-config/%s/%s', date('Y'), date('m')),
$imageName,
'public'
);
$config->put('image', $path);
}
$config
->put('image_alt', $request->input('image_alt'))
->put('image_title', $request->input('image_title'))
->save();
if ($request->hasFile('image') && $ancienne && $ancienne !== $config->get('image')) {
Storage::disk('public')->delete($ancienne);
}
return redirect()
->route('bo.general-config.edit')
->with('success', 'Configuration mise à jour.');
}
}

View file

@ -115,7 +115,11 @@ class LoginController extends Controller
}
/** @var \App\Models\Customer $customerModel */
$customerModel = new Customer(Arr::only($crmCustomer->jsonSerialize(), ['email']));
$customerModel = new Customer(Arr::only($crmCustomer->jsonSerialize(), [
'firstname',
'lastname',
'email',
]));
$customerModel->hashcode = $crmCustomer->hashcode;
if (!$customerModel->saveOrFail()) {

View file

@ -158,17 +158,17 @@ class RegisterController extends Controller
return \array_intersect_key(
$data,
[
'firstname' => '',
'lastname' => '',
'firstname' => '',
'lastname' => '',
'birth_date' => '',
'address' => '',
'postcode' => '',
'country' => '',
'city' => '',
'phone' => '',
'email' => '',
'password' => '',
'opt_in' => '',
'address' => '',
'postcode' => '',
'country' => '',
'city' => '',
'phone' => '',
'email' => '',
'password' => '',
'opt_in' => '',
]
);
}

View file

@ -65,9 +65,6 @@ class ResetPasswordController extends Controller
*/
protected function resetPassword($customer, $password)
{
/** @var \App\Models\Customer\Customer $user */
/** @var string $password */
/** @var \LDC\LDCCRM\CrmApiV4 */
$crm = app('crmAPI');

View file

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\GeneralConfig;
use App\Models\HomeSliders;
class HomeController extends Controller
@ -16,7 +17,9 @@ class HomeController extends Controller
$slides = HomeSliders::where([
['status', 1]
])->orderBy('order', 'ASC')->get();
$generalConfig = GeneralConfig::current();
return view('fo.home', compact('slides'));
return view('fo.home', compact('slides', 'generalConfig'));
}
}

View file

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\BusinessSector;
use App\Models\Employees;
use App\Models\GeneralConfig;
class OurTradeController extends Controller
{
@ -24,6 +25,8 @@ class OurTradeController extends Controller
$nine_videos = Employees::query()->select('video', 'photo', 'firstname', 'lastname', 'job_title')
->whereNotNull('video')->inRandomOrder()->limit(9)->get();
return view('fo.ourtrade', compact('secteurs_simples', 'secteurs_complexes', 'nine_videos'));
$generalConfig = GeneralConfig::current();
return view('fo.ourtrade', compact('secteurs_simples', 'secteurs_complexes', 'nine_videos', 'generalConfig'));
}
}

View file

@ -79,28 +79,34 @@ class DashboardController extends Controller
}
}
$dayMaj = Carbon::createFromFormat('Y-m-d H:i:s', $dateMajCotations->updated_at)->startOfDay();
$today = Carbon::now()->startOfDay();
// * we suppose we have cotations today
$noCotationsYet = false;
if ($today > $dayMaj) {
// * we don't have the cotations yet
if (!$dateMajCotations) {
$noCotationsYet = true;
} else {
$dayMaj = Carbon::createFromFormat('Y-m-d H:i:s', $dateMajCotations->updated_at)->startOfDay();
$today = Carbon::now()->startOfDay();
// * we suppose we have cotations today
$noCotationsYet = false;
if ($today > $dayMaj) {
// * we don't have the cotations yet
$noCotationsYet = true;
}
}
$articles = Articles::where([
['status', 1],
['category_id', 2]
])->orderBy('created_at', 'ASC')->paginate(4);
$objectivesData = [
'dbobjectif' => $dbobjectif,
'dbmyObjectives' => $dbmyObjectives,
'formEnums' => $formEnums,
];
return view(
'fo.pro.dashboard.index',
compact(
'cotations',
'mps',
'dbobjectif',
'dbmyObjectives',
'formEnums',
'objectivesData',
'pdfsAnalyse',
'pdfsMarches',
'dateMajCotations',

View file

@ -31,16 +31,16 @@ class CustomerCrmResource extends JsonResource
/** @var \LDC\LDCCRM\Models\Customer */
$crmCustomer = $this->customer->api_data;
return [
'hashcode' => $this->customer->hashcode,
'hashcode' => $this->customer->hashcode,
'firstname' => $crmCustomer->firstname,
'lastname' => $crmCustomer->lastname,
'opt_in' => $crmCustomer->opt_in,
'lastname' => $crmCustomer->lastname,
'opt_in' => $crmCustomer->opt_in,
'birthdate' => $crmCustomer->birth_date,
'phone' => $crmCustomer->phone,
'address' => $crmCustomer->address,
'address2' => $crmCustomer->address2,
'city' => $crmCustomer->city,
'postcode' => $crmCustomer->postcode
'phone' => $crmCustomer->phone,
'address' => $crmCustomer->address,
'address2' => $crmCustomer->address2,
'city' => $crmCustomer->city,
'postcode' => $crmCustomer->postcode
];
}
}

View file

@ -284,17 +284,17 @@ class Customer extends Authenticatable implements MustVerifyEmail, CanResetPassw
parent::toArray(),
(array)$this->apiData
))->intersectByKeys([
'email' => '',
'firstname' => '',
'lastname' => '',
'address' => '',
'address2' => '',
'postcode' => '',
'email' => '',
'firstname' => '',
'lastname' => '',
'address' => '',
'address2' => '',
'postcode' => '',
'birth_date' => '',
'city' => '',
'country' => '',
'opt_in' => '',
'phone' => ''
'city' => '',
'country' => '',
'opt_in' => '',
'phone' => '',
])->toArray();
} else {
return parent::toArray();

View file

@ -0,0 +1,59 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property array<string, mixed>|null $data
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
*/
class GeneralConfig extends Model
{
protected $fillable = ['data'];
protected $casts = [
'data' => 'array',
];
/**
* Get the unique configuration row.
*
* @return self
*/
public static function current(): self
{
return static::query()->firstOrCreate([], ['data' => []]);
}
/**
* Get a setting value from the JSON data.
*
* @param string $key Setting key.
* @param mixed $default Value returned.
* @return mixed
*/
public function get(string $key, mixed $default = null): mixed
{
return data_get($this->data, $key, $default);
}
/**
* Set a setting value in the JSON data.
*
* @param string $key Setting key.
* @param mixed $value Value to store.
* @return self
*/
public function put(string $key, mixed $value): self
{
$data = $this->data ?? [];
data_set($data, $key, $value);
$this->data = $data;
return $this;
}
}

View file

@ -8,7 +8,7 @@
],
"license": "MIT",
"require": {
"php": "^8.4",
"php": "^8.5",
"24slides/laravel-saml2": "^2.4",
"guzzlehttp/guzzle": "^7.5.0",
"laravel/framework": "^12.0",
@ -46,7 +46,9 @@
"dealerdirect/phpcodesniffer-composer-installer": true,
"php-http/discovery": true
},
"gitlab-domains": ["lab.s-web.fr"]
"gitlab-domains": [
"lab.s-web.fr"
]
},
"extra": {
"laravel": {

1575
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('general_configs', function (Blueprint $table) {
$table->id();
$table->json('data')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('general_configs');
}
};

View file

@ -10,7 +10,8 @@ data:
APP_DEBUG: "${APP_APP_DEBUG}"
APP_URL: "https://${APP_DOMAIN}"
LOG_CHANNEL: "k8s"
DB_HOST: "${APP_DB_HOST}"
DB_HOST: "${APP_GLOBAL_OVH_MYSQL_HOST}"
DB_PORT: "${APP_GLOBAL_OVH_MYSQL_PORT}"
DB_DATABASE: "${APP_DB_DATABASE}"
DB_USERNAME: "${APP_DB_USERNAME}"
DB_PASSWORD: "${APP_DB_PASSWORD}"
@ -83,9 +84,9 @@ spec:
imagePullSecrets:
- name: docker-registry-credentials
securityContext:
runAsUser: 33
runAsGroup: 33
fsGroup: 33
runAsUser: 82
runAsGroup: 82
fsGroup: 82
fsGroupChangePolicy: "OnRootMismatch"
volumes:
- name: storage
@ -171,8 +172,8 @@ spec:
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
securityContext:
runAsUser: 33
runAsGroup: 33
fsGroup: 33
runAsUser: 82
runAsGroup: 82
fsGroup: 82
fsGroupChangePolicy: "OnRootMismatch"
restartPolicy: OnFailure

110
package-lock.json generated
View file

@ -10,6 +10,7 @@
"@fancyapps/ui": "^6.1.12",
"@sipec/vue3-tags-input": "^3.0.4",
"chart.js": "^2.9.4",
"meow": "9.0",
"v-clipboard": "^2.2.3",
"vue-select-image": "^1.9.0"
},
@ -76,7 +77,6 @@
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.28.5",
@ -1704,7 +1704,6 @@
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
@ -1721,7 +1720,6 @@
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/semver": {
@ -2820,7 +2818,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -3111,10 +3108,7 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
@ -3123,10 +3117,7 @@
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
"integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"camelcase": "^5.3.1",
"map-obj": "^4.0.0",
@ -3483,7 +3474,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -3493,7 +3483,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
"integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
"dev": true,
"license": "MIT",
"dependencies": {
"decamelize": "^1.1.0",
@ -3510,7 +3499,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -3674,7 +3662,6 @@
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
@ -4556,7 +4543,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -4850,7 +4836,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
"integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@ -4951,7 +4936,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@ -4974,7 +4958,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
"integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
"dev": true,
"license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
@ -4987,7 +4970,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@ -5000,7 +4982,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true,
"license": "ISC"
},
"node_modules/html-tags": {
@ -5074,10 +5055,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -5147,7 +5125,6 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true,
"license": "MIT"
},
"node_modules/is-async-function": {
@ -5237,7 +5214,6 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@ -5427,7 +5403,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -5672,7 +5647,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@ -5712,7 +5686,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true,
"license": "MIT"
},
"node_modules/json-schema-traverse": {
@ -5766,7 +5739,6 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -5824,7 +5796,6 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true,
"license": "MIT"
},
"node_modules/loader-runner": {
@ -5902,7 +5873,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -5943,10 +5913,7 @@
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
"integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/minimist": "^1.2.0",
"camelcase-keys": "^6.2.2",
@ -5972,10 +5939,7 @@
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
"integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
},
@ -6042,10 +6006,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=4"
}
@ -6078,7 +6039,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
"integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
"dev": true,
"license": "MIT",
"dependencies": {
"arrify": "^1.0.1",
@ -6180,7 +6140,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
"integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"hosted-git-info": "^4.0.1",
@ -6196,7 +6155,6 @@
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@ -6427,10 +6385,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
@ -6459,7 +6414,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
@ -6485,7 +6439,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -6515,9 +6468,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/path-scurry": {
"version": "1.11.1",
@ -6811,10 +6762,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -6834,10 +6782,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
"integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/normalize-package-data": "^2.4.0",
"normalize-package-data": "^2.5.0",
@ -6852,10 +6797,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
"integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"find-up": "^4.1.0",
"read-pkg": "^5.2.0",
@ -6872,10 +6814,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@ -6888,10 +6827,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"p-locate": "^4.1.0"
},
@ -6903,10 +6839,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"p-try": "^2.0.0"
},
@ -6921,10 +6854,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"p-limit": "^2.2.0"
},
@ -6936,10 +6866,7 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -6948,19 +6875,13 @@
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"license": "ISC"
},
"node_modules/read-pkg/node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"license": "BSD-2-Clause",
"optional": true,
"peer": true,
"dependencies": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
@ -6972,10 +6893,7 @@
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver"
}
@ -6984,10 +6902,7 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
"integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -7010,10 +6925,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"indent-string": "^4.0.0",
"strip-indent": "^3.0.0"
@ -7082,9 +6994,7 @@
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
@ -7677,7 +7587,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
"integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"spdx-expression-parse": "^3.0.0",
@ -7688,14 +7597,12 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
"dev": true,
"license": "CC-BY-3.0"
},
"node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"spdx-exceptions": "^2.1.0",
@ -7706,7 +7613,6 @@
"version": "3.0.23",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz",
"integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/stop-iteration-iterator": {
@ -7859,10 +7765,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"min-indent": "^1.0.0"
},
@ -8364,9 +8267,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.4"
},
@ -8614,10 +8515,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -9227,7 +9125,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"spdx-correct": "^3.0.0",
@ -10260,7 +10157,6 @@
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10"

View file

@ -77,6 +77,7 @@
"@fancyapps/ui": "^6.1.12",
"@sipec/vue3-tags-input": "^3.0.4",
"chart.js": "^2.9.4",
"meow": "9.0",
"v-clipboard": "^2.2.3",
"vue-select-image": "^1.9.0"
}

View file

@ -11,3 +11,6 @@
@import "./base/fonts";
@import "./base/classes";
@import "./base/common";
// * PAGE
@import "./pages/general-config";

View file

@ -0,0 +1,42 @@
.gc-image {
width: 464px;
max-width: 100%;
margin: 0 auto;
}
.gc-preview {
position: relative;
overflow: hidden;
border: 1px solid var(--bs-border-color, #dee2e6);
border-radius: var(--bs-border-radius, 0.375rem);
margin-bottom: 1.5rem;
aspect-ratio: 742 / 464;
background-color: var(--bs-light, #f8f9fa);
}
.gc-preview-img {
position: absolute;
width: 100%;
height: 100%;
inset: 0;
object-fit: contain;
}
.gc-preview-empty {
position: absolute;
top: 50%;
left: 50%;
color: var(--bs-secondary-color, #6c757d);
transform: translate(-50%, -50%);
}
.gc-image-actions {
margin-top: 1rem;
text-align: center;
}
#general-config-accordion {
--bs-accordion-active-bg: #f8f8f8;
--bs-accordion-active-color: #212529;
--bs-accordion-btn-focus-box-shadow: none;
}

View file

@ -39,6 +39,7 @@
@import "bootstrap/scss/breadcrumb";
@import "bootstrap/scss/badge";
@import "bootstrap/scss/offcanvas";
@import "bootstrap/scss/accordion";
// 6. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "bootstrap/scss/utilities/api";

View file

@ -35,6 +35,15 @@ a{
&:hover{color: $tertiary;}
}
.text-decoration-underline {
text-decoration: underline !important;
}
.small {
font-size: .875rem;
}
.flex {display: flex;}
.grid {display: grid;}

View file

@ -168,7 +168,8 @@
}
}
.edito{
.edito {
display: grid;
padding: 30px 40px;
background-color: $beige-clair;
grid-template-areas:
@ -178,20 +179,43 @@
"sign";
grid-template-columns: 1fr;
div:nth-child(1) {
&-p,
ul {
margin-bottom: 1rem;
}
&__intro {
grid-area: first-p;
text-align: start;
}
&__text {
grid-area: second-p;
}
&__img {
grid-area: img;
text-align: center;
}
div:nth-child(2) {grid-area: first-p;}
div:nth-child(3) {grid-area: second-p;}
div:nth-child(4) {
&__quote {
display: block;
font-style: italic;
text-align: end;
}
&__sign {
margin-top: 20px;
grid-area: sign;
text-align: right;
text-align: end;
p{margin: 0;}
p:first-child{font-weight: bold;}
&-p {
margin: 0;
}
}
&__sign-name {
font-weight: 700;
}
ul li {

View file

@ -25,18 +25,17 @@ window.addEventListener("DOMContentLoaded", function () {
});
// * DECONNEXION
const disconnectButtons = document.querySelectorAll<HTMLElement>(
"header .disconnect, header .mobile-disconnect"
);
const connectText = document.querySelector<HTMLElement>(
"header .connect-contain p"
);
disconnectButtons.forEach((btn) => {
btn.addEventListener("click", (e) => {
e.preventDefault();
btn.classList.remove("logged");
connectText?.classList.remove("logged");
});
document.getElementById("logout-form-button")?.addEventListener("click", () => {
const logoutForm = document.querySelector<HTMLFormElement>("#logout-form");
if (logoutForm) {
logoutForm.submit();
}
});
document.getElementById("logout-form-button-mobile")?.addEventListener("click", () => {
const logoutForm = document.querySelector<HTMLFormElement>("#logout-form-mobile");
if (logoutForm) {
logoutForm.submit();
}
});
// * BORDER VISIBLE SUR LE MENU AFFICHE

View file

@ -25,48 +25,66 @@
</transition>
<form>
<div class="flex row">
<select name="produit" id="produit" v-model="objectif.produit" @change="populate">
<option value="--">Selectionner un produit*</option>
<option v-for="produit in enums.produit" :key="produit.value" :value="produit.value">
{{ produit.value }}
</option>
</select>
<div class="flex row">
<select name="produit" id="produit" v-model="objectif.produit" @change="populate">
<option value="--">Selectionner un produit*</option>
<option v-for="produit in enums.produit" :key="produit.value" :value="produit.value">
{{ produit.value }}
</option>
</select>
<select name="qualite" v-model="objectif.qualite">
<option value="--">Qualité</option>
<option v-for="qualite in qualiteEnums" :key="qualite.value" :value="qualite.value">
{{ qualite.value }}
</option>
</select>
</div>
<select name="qualite" v-model="objectif.qualite">
<option value="--">Qualité*</option>
<option v-for="qualite in qualiteEnums" :key="qualite.value" :value="qualite.value">
{{ qualite.value }}
</option>
</select>
</div>
<div class="validate">
<button class="first-btn" @click.prevent="saveData" :disabled="processing">
Enregistrer l'objectif
</button>
</div>
</form>
<div class="flex row">
<select name="campagne" v-model="objectif.campagne" @change="populate">
<option value="--">Campagne*</option>
<option v-for="campagne in campagneEnums" :key="campagne.value" :value="campagne.value">
{{ campagne.value }}
</option>
</select>
<select name="echeance" v-model="objectif.echeance">
<option value="--">Échéance*</option>
<option v-for="echeance in echeanceEnums" :key="echeance.value" :value="echeance.value">
{{ echeance.value }}
</option>
</select>
</div>
<div class="flex row">
<input type="number" name="quantite" v-model.number="objectif.quantite" min="0" placeholder="Quantité*">
<input type="number" name="prix" v-model.number="objectif.prix" min="0" step="0.01" placeholder="Prix (€)*">
</div>
<div class="validate">
<button class="first-btn" @click.prevent="saveData" :disabled="processing">
Enregistrer l'objectif
</button>
</div>
</form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { ref } from "vue"
import axios from "axios"
interface Props {
name: string
dbobjectif: string
dbmyObjectives: string
formEnums: string
}
const props = defineProps<{ json: string }>()
const props = defineProps<Props>()
const initial = JSON.parse(props.json)
const objectif = ref<any>({})
const myobjectives = ref<any[]>([])
const enums = ref<any>({})
initial.dbobjectif.quantite = null
const objectif = ref<any>(structuredClone(initial.dbobjectif))
const myobjectives = ref<any[]>(initial.dbmyObjectives)
const enums = ref<any>(initial.formEnums)
const qualiteEnums = ref<any[]>([])
const campagneEnums = ref<any[]>([])
const echeanceEnums = ref<any[]>([])
@ -76,12 +94,6 @@ const success = ref(false)
const errors = ref<string[]>([])
const response = ref("")
onMounted(() => {
console.log("Objectives Component mounted.")
enums.value = JSON.parse(props.formEnums)
objectif.value = JSON.parse(props.dbobjectif)
myobjectives.value = JSON.parse(props.dbmyObjectives)
})
function populate(event: Event) {
const target = event.target as HTMLSelectElement
@ -175,10 +187,14 @@ function saveData() {
objectif: objectif.value,
})
.then((res) => {
objectif.value = JSON.parse(props.dbobjectif)
success.value = true
response.value = "Sauvegarde terminée !"
myobjectives.value.push(res.data)
objectif.value = structuredClone(initial.dbobjectif)
qualiteEnums.value = []
campagneEnums.value = []
echeanceEnums.value = []
setTimeout(() => (success.value = false), 3000)
})
.catch(() => {
errors.value.push("Erreur lors de la sauvegarde.")

View file

@ -0,0 +1,109 @@
@extends('layouts.bo')
@section('content')
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Configuration générale</h5>
<a href="{{ route('bo.dashboard') }}" class="btn btn-sm btn-primary">Retour</a>
</div>
<div class="card-body">
<div class="accordion" id="general-config-accordion">
<div class="accordion-item">
<h2 class="accordion-header" id="heading-metiers">
<button class="accordion-button" type="button" data-bs-toggle="collapse"
data-bs-target="#collapse-metiers" aria-expanded="true" aria-controls="collapse-metiers">
Image de la page : <strong> Nos métiers</strong>
</button>
</h2>
<div id="collapse-metiers" class="accordion-collapse collapse show" aria-labelledby="heading-metiers"
data-bs-parent="#general-config-accordion">
<div class="accordion-body">
<form action="{{ route('bo.general-config.upload') }}" method="POST"
enctype="multipart/form-data">
@csrf
@method('PATCH')
<div class="gc-image">
<div class="gc-preview">
<img id="preview-image"
src="{{ $config->get('image') ? Storage::url($config->get('image')) : '' }}"
alt="Image de la page Nos métiers"
class="gc-preview-img {{ $config->get('image') ? '' : 'd-none' }}">
<span id="preview-empty"
class="gc-preview-empty {{ $config->get('image') ? 'd-none' : '' }}">
Aucune image
</span>
</div>
<div class="mb-3">
<label for="image" class="form-label">
Photo @unless ($config->get('image'))
<span class="text-danger">*</span>
@endunless
</label>
<input type="file" id="image" name="image" accept="image/png, image/jpeg"
class="form-control @error('image') is-invalid @enderror"
@unless ($config->get('image')) required @endunless>
<div class="form-text">JPEG ou PNG, 2 Mo max., 742 × 464 px.</div>
@error('image')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="image_alt" class="form-label">Texte (Alt)</label>
<input type="text" id="image_alt" name="image_alt" maxlength="255"
class="form-control @error('image_alt') is-invalid @enderror"
value="{{ old('image_alt', $config->get('image_alt')) }}">
@error('image_alt')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="image_title" class="form-label">Titre (title)</label>
<input type="text" id="image_title" name="image_title" maxlength="255"
class="form-control @error('image_title') is-invalid @enderror"
value="{{ old('image_title', $config->get('image_title')) }}">
@error('image_title')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="gc-image-actions">
<button type="submit" class="btn btn-secondary">Enregistrer</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('image');
const img = document.getElementById('preview-image');
const empty = document.getElementById('preview-empty');
const original = img.getAttribute('src');
input.addEventListener('change', () => {
const file = input.files[0];
const src = file ? URL.createObjectURL(file) : original;
if (src) img.src = src;
img.classList.toggle('d-none', !src);
empty.classList.toggle('d-none', Boolean(src));
});
});
</script>
@endpush

View file

@ -15,7 +15,15 @@
<div class="check">
<input type="checkbox" name="ok_cgv" id="ok_cgv">
<label for="ok_cgv">&nbsp;&nbsp;<span>J'ai lu et j'accepte les conditions générales d'utilisation</span></label>
<label for="ok_cgv">
&nbsp;&nbsp;
<span>
J'ai lu et j'accepte les
<a class="text-decoration-underline" href="{{ route('fo.legalnotice') }}">
conditions générales d'utilisation et conditions générales de vente
</a>
</span>
</label>
</div>
<div class="flex row">
@foreach ($errors->get('ok_cgv') as $message)
@ -25,6 +33,16 @@
<div class="validate">
<input type="submit" value="{{ __('Register') }}" class="first-btn">
</div>
<div>
<p class="small">
Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour donner suite à votre demande de contact.
Pour connaître vos droits, vous pouvez consulter la
<a class="small text-decoration-underline" href="{{ route('fo.privacypolicy') }}">
Charte de confidentialité
</a>
.
</p>
</div>
</form>
</section>
</div>

View file

@ -116,8 +116,8 @@
<img src="{{ Vite::asset('resources/assets/images/collecte-marolles.jpg') }}" alt="Site de Marolles">
</div>
<div class="bloc--business">
<strong>Responsable commercial</strong>
<p>Jérémy Parmentier<br>06.30.86.03.50</p>
<strong>Responsable Appro</strong>
<p>Anthony Dubief<br>06.48.47.41.84</p>
<strong>Responsable Appro</strong>
<p>Thierry Foulard<br>06.85.07.60.46</p>
</div>
@ -177,7 +177,6 @@
<div class="bloc-title">
<h2 class="paragraph-title">Cherré</h2>
<p>Téléphone : 02.43.93.16.56</p>
<p>Mobile : 06.07.77.23.34</p>
</div>
<div class="bloc--img">
<img src="{{ Vite::asset('resources/assets/images/collecte-cherre.jpg') }}" alt="Site de Cherré">
@ -345,7 +344,6 @@
<div class="bloc-title">
<h2 class="paragraph-title">Nogent le Bernard</h2>
<p>Téléphone : 02.43.29.33.03</p>
<p>Mobile : 06.89.19.77.15</p>
</div>
<div class="bloc--img">
<img src="{{ Vite::asset('resources/assets/images/collecte-nogent-le-bernard.jpg') }}" alt="Site de Nogent le Bernard">

View file

@ -60,41 +60,48 @@
</div>
<div class="info">
<h3 class="post-chapter">40 salarié(e)s</h3>
<img src="{{ Vite::asset('resources/assets/images/quarante-salaries.jpg') }}" alt="40 salarié(e)s">
<img src="{{ $generalConfig->get('image')
? Storage::url($generalConfig->get('image'))
: Vite::asset('resources/assets/images/quarante-salaries.jpg', 'build') }}"
width="363" height="227"
alt="{{ $generalConfig->get('image_alt', '') }}"
@if ($generalConfig->get('image_title')) title="{{ $generalConfig->get('image_title') }}" @endif
>
<div><a class="second-btn" href="{{ route('fo.ourtrade') }}">Rencontrez l'équipe Jeusselin</a></div>
</div>
</div>
</section>
<section class="edito container grid">
<div class="img-edito">
<img src="{{ Vite::asset('resources/assets/images/jeusselin-photo.jpg') }}" alt="Gaël Le Conte">
</div>
<section class="edito container">
<div>
<p class="paragraph-title"><strong>&Eacute;dito</strong></p>
<h2 class="post-subtitle">Jeusselin, au fil du grain</h2><br>
<p>Depuis plus de 50 ans la société Jeusselin est une entreprise de proximité. <br>Ancrée dans le paysage local nous apportons
un service de qualité avec comme axes principaux :</p><br>
<p class="paragraph-title edito-p"><strong>&Eacute;dito</strong></p>
<h2 class="post-subtitle">Jeusselin, notre lien c’est le grain</h2><br>
<p class="edito-p">Depuis plus de 55 ans la société Jeusselin se renouvelle à la fois, dans ses équipes, comme dans ses
infrastructures pour pouvoir continuer de relever les défis qui l’attendent. Fort de son appartenance au
Pôle Amont
de LDC (dirigé par Bruno Mousset), l’entreprise déploie une politique tant en termes d’investissements,
de sécurité que de RSE.</p><p class="edito-p">Nous partageons les mêmes valeurs de travail, de respect, d‘innovation, de
performance, de responsabilité et de simplicité.</p>
<span class="edito__quote">« Agir avec nos territoires »</span><br>
<p class="edito-p">Voilà une phrase qui résume l’ambition et le rôle de l’entreprise dans son environnement.<br>
Sa structure, son maillage territorial et ses salariés permettent de proposer des services auprès de ses
clients:
</p><br>
<ul>
<li>Le conseil et la préconisation en semence et engrais ainsi que la vente de produits phytosanitaires,</li>
<li>Les achats de céréales ainsi que leur stockage dans les 7 silos situés principalement dans le nord de la Sarthe en
grande proximité des exploitations céréalières de nos clients agriculteurs,</li>
<li>Nous mettons en marché les céréales selon la demande intérieure (usines d’aliments, meuneries etc) ou extérieure
(portuaire essentiellement à Rouen)</li>
<li>Nous innovons en proposant à nos agriculteurs des céréales avec des filières spécifiques tels que le blé agri éthique,
le blé améliorants, le soja...</li>
<li>Le conseil et la préconisation en semences, produits d’agroéquipement et engrais ainsi que la vente de produits phytosanitaires, ainsi que le développement de solutions de biocontrôle et de biostimulation,
</li>
<li>Les achats de céréales ainsi que leur stockage dans les 7 silos situés principalement dans le nord de la Sarthe, en grande proximité des exploitations de polyculture élevage de nos clients agriculteurs,</li>
<li>Nous mettons en marché les céréales selon la demande intérieure (usines d’aliments, meuneries etc) ou extérieure (portuaire essentiellement à Rouen),</li>
<li>Nous innovons en proposant à nos agriculteurs des céréales avec des filières spécifiques telles que le blé améliorant,</li>
<li>Nous possédons également un magasin LISA « France Rurale » sur le site de Marolles les Braults où nous accueillons le grand public.</li>
</ul><br>
</div>
<div>
<p>Nous sommes également dans une démarche d’agriculture raisonnée et bio. <br>En partenariat depuis 2001 avec le groupe
agroalimentaire Sarthois LDC, nous partageons les mêmes valeurs de travail, de respect, d‘innovation, de performance de
responsabilité et de simplicité.</p><br>
<p>L’ensemble de l’équipe Jeusselin - les commerciaux, responsables de silos, chauffeurs ainsi que l’équipe administrative - est
à votre entière disposition et met tout en œuvre pour vous garantir le meilleur service et répondre à vos attentes.</p><br>
<div class="edito__text">
<p class="edito-p">L’ensemble de l’équipe Jeusselin est à votre disposition pour répondre à vos besoins.</p><br>
</div>
<div>
<p>Gaël Le Conte</p>
<p>Directeur Général</p>
<div class="edito__sign">
<p class="edito__sign-name edito-p edito__sign-p">Gaël Le Conte</p>
<p class="edito-p edito__sign-p">Directeur Général</p>
</div>
</section>

View file

@ -8,7 +8,16 @@
<section class="work--head container flex">
<h1 class="post-title">Nos métiers</h1>
<div class="work--head--detail grid">
<div class="detail--img"><img src="{{ Vite::asset('resources/assets/images/quarante-salaries-large.jpg', 'build') }}" alt="L'Equipe Jeusselin"></div>
<div class="detail--img">
<img src="{{ $generalConfig->get('image')
? Storage::url($generalConfig->get('image'))
: Vite::asset('resources/assets/images/quarante-salaries-large.jpg', 'build') }}"
alt="{{ $generalConfig->get('image_alt', '') }}"
@if ($generalConfig->get('image_title')) title="{{ $generalConfig->get('image_title') }}" @endif
>
</div>
{{-- <div class="detail--txt">
<h2 class="post-chapter">Rencontrez l'équipe en vidéo</h2>
<p>Progressively disseminate high-payoff niche markets without enterprise action items. Completely provide access to cutting-edge methods of empowerment before synergistic networks. Conveniently orchestrate user friendly data before.</p>

View file

@ -92,8 +92,8 @@
<p>Ces cotations n'ont pas de valeurs contractuelles</p>
</div>
</div>
<objectives dbobjectif='@json($dbobjectif)' dbmy-objectives='@json($dbmyObjectives)' form-enums='@json($formEnums)'></objectives>
<div id="objectives" data-json='@json($objectivesData)'></div>
<div class="pro--analyse">
<h2 class="post-title">Analyse technique</h2>
@ -154,38 +154,24 @@
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
const selectMP = document.querySelector('select[name="mps"]');
if (!selectMP) return;
<script>
document.addEventListener('DOMContentLoaded', () => {
const select = document.querySelector('select[name=mps]');
const blocs = document.querySelectorAll('.cotations--grid .mp--bloc');
selectMP.addEventListener('change', function() {
const value = this.value;
const blocs = document.querySelectorAll('.mp--bloc');
if (value === 'All') {
this.selectedIndex = 0;
document.querySelectorAll('.mp--bloc .mp--bloc--header .cotations--mp span').forEach(function(span) {
span.style.display = '';
});
blocs.forEach(function(bloc) {
bloc.classList.remove('final');
bloc.style.display = '';
});
} else {
blocs.forEach(function(bloc) {
bloc.style.display = 'none';
bloc.classList.remove('final');
});
document.querySelectorAll('.mp--bloc.' + CSS.escape(value)).forEach(function(bloc) {
bloc.classList.add('final');
bloc.style.display = '';
});
}
const filtrer = () => {
const val = select.value;
blocs.forEach(b => {
const visible = val === 'All' || b.classList.contains(val);
b.style.display = visible ? '' : 'none';
b.classList.toggle('final', val !== 'All' && visible);
});
});
</script>
};
select.value = 'All';
filtrer();
select.addEventListener('change', filtrer);
});
</script>
@endpush

View file

@ -31,9 +31,9 @@
</div>
@if (Auth::guard('frontend')->check())
<div class="disconnect">
<form id="logout-form" action="{{route('logout')}}" method="POST">
<form id="logout-form" action="{{ route('logout') }}" method="POST">
@csrf
<input type="image" src="{{ Vite::asset('resources/assets/images/stop.png') }}" alt="Déconnexion" style="max-height: 30px;" onclick="submit();" />
<input type="image" id="logout-form-button" src="{{ Vite::asset('resources/assets/images/stop.png') }}" alt="Déconnexion" style="max-height: 30px;" />
</form>
</div>
@endif
@ -68,7 +68,7 @@
@if (Auth::guard('frontend')->check())
<form id="logout-form-mobile" action="{{route('logout')}}" method="POST">
@csrf
<input type="image" src="{{ Vite::asset('resources/assets/images/stop.png') }}" alt="Déconnexion" style="max-height: 30px;" />
<input type="image" id="logout-form-button-mobile" src="{{ Vite::asset('resources/assets/images/stop.png') }}" alt="Déconnexion" style="max-height: 30px;" />
</form>
@endif

View file

@ -70,6 +70,7 @@
<div class="dropdown-menu">
<a class="dropdown-item" href="{{route('bo.business-sector.index')}}">Secteurs</a>
<a class="dropdown-item" href="{{route('bo.employees.index')}}">Employés</a>
<a class="dropdown-item" href="{{route('bo.general-config.edit')}}">Configuration générale</a>
</div>
</li>
<a class="nav-link" href="{{route('bo.home-sliders.index')}}">Slider de l'accueil</a>

View file

@ -6,6 +6,7 @@ use App\Http\Controllers\Bo\CotationsController;
use App\Http\Controllers\Bo\CustomerController;
use App\Http\Controllers\Bo\DashboardController;
use App\Http\Controllers\Bo\EmployeesController;
use App\Http\Controllers\Bo\GeneralConfigController;
use App\Http\Controllers\Bo\HomeSlidersController;
use App\Http\Controllers\Bo\ObjectivesController;
use App\Http\Controllers\Bo\PublicPdfsController;
@ -34,18 +35,26 @@ Route::prefix('bo')->name('bo.')->middleware('admin-secure')->group(function ()
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// * Utilisateurs BO
Route::resource('objectives', ObjectivesController::class)->except([
'create', 'edit'
'create',
'edit'
]);
Route::resources([
'users' => UsersController::class,
'employees' => EmployeesController::class,
'home-sliders' => HomeSlidersController::class,
'articles' => ArticlesController::class,
'cotations' => CotationsController::class,
'public-pdfs' => PublicPdfsController::class,
]);
// * ARTICLES
Route::resource(
'articles',
ArticlesController::class,
)->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:content');
Route::resource('customers', CustomerController::class)
->only(['index', 'edit', 'update']);
->only(['index', 'edit', 'update']);
// *ordres
Route::get(
@ -82,5 +91,10 @@ Route::prefix('bo')->name('bo.')->middleware('admin-secure')->group(function ()
->only(['index', 'edit', 'update'])
->withoutMiddleware('htmlsanitize')
->middleware('htmlsanitize:content');
// * GENERAL CONFIG
Route::get('/config-general', [GeneralConfigController::class, 'edit'])->name('general-config.edit');
Route::patch('/config-general', [GeneralConfigController::class, 'upload'])->name('general-config.upload');
});
});