Merge branch 'trunk'

This commit is contained in:
Vincent BRIDIER 2026-10-23 15:30:00 +02:00
commit c5ef81f668
29 changed files with 581 additions and 264 deletions

View file

@ -129,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;

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

@ -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

@ -84,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
@ -172,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,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,30 +154,24 @@
@endsection
@push('scripts')
<script>
function setMpSelector() {
var selectMP = $('select[name=mps]');
$('.mp--bloc:visible:first').find('.mp--bloc--header .cotations--mp span').hide();
$('.mp--bloc:visible:first').find('.mp--bloc--header .cotations--mp').append(selectMP);
}
<script>
document.addEventListener('DOMContentLoaded', () => {
const select = document.querySelector('select[name=mps]');
const blocs = document.querySelectorAll('.cotations--grid .mp--bloc');
$(document).ready(function() {
setMpSelector();
$('select[name=mps]').change(function (){
if($(this).val() == 'All') {
$('select[name=mps]')[0].selectedIndex = 0;
$('.mp--bloc .mp--bloc--header .cotations--mp span').show();
$('.mp--bloc').removeClass('final');
$('.mp--bloc').show();
} else {
$('.mp--bloc').hide();
$('.mp--bloc.'+$(this).val()).addClass('final');
$('.mp--bloc.'+$(this).val()).show();
}
setMpSelector();
//restore
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

@ -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');
});
});