fix contact page

This commit is contained in:
Alexis Gousseau 2023-10-27 15:42:59 +02:00
parent 87b2ca2368
commit 45ff265caf
21 changed files with 372 additions and 338 deletions

View file

@ -5,8 +5,8 @@ namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\ContactRequest;
use App\Mail\SendContactForm;
use App\Models\Explorerpage;
use App\Mail\SendContactMail;
use App\Models\Homepage;
use App\Models\News;
use App\Models\Range;
@ -94,7 +94,7 @@ class StaticPageController extends Controller
*/
public function contactForm(ContactRequest $request): \Illuminate\Http\RedirectResponse
{
Mail::to(\config('mail.from.address'))->send(new SendContactForm($request->validated()));
Mail::to(\config('mail.from.address'))->send(new SendContactMail((object)$request->validated()));
return redirect()->route('fo.contact.show')
->with(

View file

@ -90,6 +90,8 @@ class SecureHeaders
'https://www.googletagmanager.com',
'https://cdnjs.cloudflare.com',
"$scheme://www.google-analytics.com",
'https://www.google.com/recaptcha/',
'https://www.gstatic.com/recaptcha/',
// * VITE DEV
config('app.debug') ? "https://{$host}:4443" : '',
]) . ';'

View file

@ -4,6 +4,7 @@ namespace App\Http\Requests\Fo;
use App\Enums\Contact\CivilityEnum;
use App\Enums\Contact\ObjectEnum;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
@ -12,16 +13,6 @@ class ContactRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize(): bool
{
return true;
}
/**
* Prepare the data for validation.
*
@ -43,6 +34,8 @@ class ContactRequest extends FormRequest
*/
public function rules()
{
ToolboxHelper::validateRecaptcha($this, \config('services.google.recaptcha.version'));
$rules = [
'civility' => ['sometimes', 'nullable', new Enum(CivilityEnum::class)],
'last_name' => 'sometimes|nullable|string|between:3,255',
@ -53,7 +46,7 @@ class ContactRequest extends FormRequest
'address' => 'sometimes|nullable|string|between:3,255',
'postal_code' => 'sometimes|nullable|numeric|min:0',
'city' => 'sometimes|nullable|string|between:3,255',
'object' => ['sometimes', 'nullable', new Enum(ObjectEnum::class)],
'object' => ['required', new Enum(ObjectEnum::class)],
'product_name' => [
'nullable', 'string', 'between:3,255',
// @phpcs:ignore Generic.Files.LineLength.TooLong
@ -144,12 +137,21 @@ class ContactRequest extends FormRequest
}
}
],
'message' => 'sometimes|nullable|string|between:3,255',
'message' => 'required|string|between:3,255',
'accept_rules' => 'required|boolean',
'send_data' => 'required|boolean',
];
return \array_merge($rules, $this->pictureRules('file', 0, 0, 1920, 1080, true));
return \array_merge($rules, $this->pictureRules(
'file',
0,
0,
1920,
1080,
3000,
true,
'product_name,product_date_limit,product_barcode,product_lot,product_date_consumption,product_location'
));
}
/**

View file

@ -1,208 +0,0 @@
<?php
namespace App\Mail;
use App\Enums\Contact\CivilityEnum;
use App\Enums\Contact\ObjectEnum;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendContactForm extends Mailable
{
use Queueable;
use SerializesModels;
/**
* The civility.
*
* @var \App\Enums\Contact\CivilityEnum|null
*/
private $civility;
/**
* The first name.
*
* @var string|null
*/
private $first_name;
/**
* The last name.
*
* @var string|null
*/
private $last_name;
/**
* The society.
*
* @var string|null
*/
private $society;
/**
* The email.
*
* @var string
*/
private $email;
/**
* The phone.
*
* @var string|null
*/
private $phone;
/**
* The address.
*
* @var string|null
*/
private $address;
/**
* The postal code.
*
* @var string|null
*/
private $postal_code;
/**
* The city.
*
* @var string|null
*/
private $city;
/**
* The object.
*
* @var \App\Enums\Contact\ObjectEnum|null
*/
private $object;
/**
* The product name.
*
* @var string
*/
private $product_name;
/**
* The product date limit.
*
* @var string
*/
private $product_date_limit;
/**
* The product barcode.
*
* @var string
*/
private $product_barcode;
/**
* The product lot.
*
* @var string
*/
private $product_lot;
/**
* The product date consumption.
*
* @var string
*/
private $product_date_consumption;
/**
* The product_location.
*
* @var string
*/
private $product_location;
/**
* The message.
*
* @var string|null
*/
private $message;
/**
* The file.
*
* @var string|null
*/
private $file;
/**
* Create a new message instance.
*
* @param array $edition
* @return void
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function __construct(array $edition)
{
// phpcs:enable
$this->civility = (isset($edition['civility'])) ? CivilityEnum::make(intval($edition['civility']))->label() : null;
$this->first_name = $edition['first_name'] ?? null;
$this->last_name = $edition['last_name'] ?? null;
$this->society = $edition['society'] ?? null;
$this->email = $edition['email'];
$this->phone = $edition['phone'] ?? null;
$this->address = $edition['address'] ?? null;
$this->postal_code = $edition['postal_code'] ?? null;
$this->city = $edition['city'] ?? null;
$this->object = (isset($edition['object'])) ? ObjectEnum::make(intval($edition['object']))->label() : null;
$this->product_name = $edition['product_name'];
$this->product_date_limit = $edition['product_date_limit'];
$this->product_barcode = $edition['product_barcode'];
$this->product_lot = $edition['product_lot'];
$this->product_date_consumption = $edition['product_date_consumption'];
$this->product_location = $edition['product_location'];
$this->message = $edition['message'] ?? null;
$this->file = $edition['file'] ?? null;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$mail = $this->subject(\config('app.name') . ' - contact formulaire')
->markdown('emails.send-contact-form')
->with([
'civility' => $this->civility,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'society' => $this->society,
'email' => $this->email,
'phone' => $this->phone,
'address' => $this->address,
'postal_code' => $this->postal_code,
'city' => $this->city,
'object' => $this->object,
'product_name' => $this->product_name,
'product_date_limit' => $this->product_date_limit,
'product_barcode' => $this->product_barcode,
'product_lot' => $this->product_lot,
'product_date_consumption' => $this->product_date_consumption,
'product_location' => $this->product_location,
'message' => $this->message,
]);
if (isset($this->file)) {
$mail = $mail->attach($this->file->getRealPath(), [
'as' => $this->file->getClientOriginalName(),
'mime' => $this->file->getClientMimeType(),
]);
}
return $mail;
}
}

View file

@ -0,0 +1,110 @@
<?php
namespace App\Mail;
use App\Enums\Contact\ObjectEnum;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class SendContactMail extends Mailable
{
use Queueable;
use SerializesModels;
/**
* @var \App\Mail\Contact
*/
private \stdClass $data;
/**
* Create a new message instance.
*
* @param \stdClass $data
* @return void
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function __construct(\stdClass $data)
{
$this->data = clone $data;
}
/**
* Get the message envelope.
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope(): \Illuminate\Mail\Mailables\Envelope
{
return new Envelope(
from: new Address(
$this->data->email,
($this->data->first_name !== null || $this->data->last_name !== null) ?
(($this->data->first_name ?? '') . " " . ($this->data->last_name ?? '')) :
null
),
to: [new Address(config('mail.from.address'), config('mail.from.name'))],
subject: sprintf('%s - %s', ObjectEnum::make($this->data->object)->label() ?? __('Nouveau message'), config('app.name')),
);
}
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content(): \Illuminate\Mail\Mailables\Content
{
return new Content(
markdown: 'emails.send-contact-form',
with: ['data' => $this->data],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
$attachments = [];
if (isset($this->data->file)) {
$attachments[] = Attachment::fromPath($this->data->file->getRealPath())
->as($this->data->file->getClientOriginalName())
->withMime($this->data->file->getClientMimeType());
}
return $attachments;
}
}
/**
* @property integer $civility
* @property string $last_name
* @property string $first_name
* @property string $society
* @property string $email
* @property string $phone
* @property string $address
* @property string $postal_code
* @property boolean $city
* @property integer $object
* @property string $message
* @property string $product_name
* @property string $product_date_limit
* @property string $product_barcode
* @property string $product_lot
* @property string $product_date_consumption
* @property string $product_location
* @property boolean $accept_rules
* @property boolean $send_data
* @property \Illuminate\Http\UploadedFile $file
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class Contact extends \stdClass
{
}

View file

@ -26,10 +26,9 @@ class AppServiceProvider extends ServiceProvider
App::singleton('clientIp', function () {
if (config('app.env') === 'local') {
return request()->getClientIp();
} else {
return request()->server('HTTP_X_FORWARDED_FOR') ??
request()->getClientIp();
}
return request()->server('HTTP_X_FORWARDED_FOR') ??
request()->getClientIp();
});
// * LOCAL FORCE eg: for Carbon

View file

@ -45,7 +45,9 @@ trait HasPicture
* @param integer|null $minHeight
* @param integer|null $maxWith
* @param integer|null $maxHeight
* @param integer|null $size
* @param boolean $nullable
* @param string|null $requiredWith
* @return array
*/
public function pictureRules(
@ -54,9 +56,11 @@ trait HasPicture
?int $minHeight = null,
?int $maxWith = null,
?int $maxHeight = null,
bool $nullable = false
?int $size = null,
bool $nullable = false,
?string $requiredWith = null,
): array {
$sizes = (object)[
$dimensions = (object)[
'minWith' => $minWith ?? $this->minWith,
'minHeight' => $minHeight ?? $this->minHeight,
'maxWith' => $maxWith ?? $this->maxWith,
@ -65,8 +69,10 @@ trait HasPicture
return [
$name => [
!$nullable ? 'required' : 'nullable',
function (string $attribute, $value, callable $fail) use ($sizes) {
return ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes);
(strlen($requiredWith)) ? 'required_with:' . $requiredWith : '',
($size) ? 'max:' . $size : '',
function (string $attribute, $value, callable $fail) use ($dimensions) {
return ToolboxHelper::validatePicture($attribute, $value, $fail, $dimensions);
}
]
];

View file

@ -31,4 +31,11 @@ return [
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'google' => [
'recaptcha' => [
'public' => env('GOOGLE_RECAPTCHA_PUBLIC'),
'private' => env('GOOGLE_RECAPTCHA_PRIVATE'),
'version' => env('GOOGLE_RECAPTCHA_VERSION', "3") === "3" ? true : false
]
],
];

2
package-lock.json generated
View file

@ -1,5 +1,5 @@
{
"name": "agis",
"name": "srcs",
"lockfileVersion": 3,
"requires": true,
"packages": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Calque_2" data-name="Calque 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.38 22.17">
<g id="Contact_survol" data-name="Contact / survol">
<g>
<polygon points="4.85 22.17 1.79 17.14 7.03 11.25 18.42 0 21.76 5.46 4.85 22.17"/>
<polygon points="0 5.19 5.52 .62 11.08 6.3 23.38 16.55 18.27 20.4 0 5.19"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 397 B

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
// phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found
return [
'acceptcgu' => "J’autorise AGIS à traiter mes données personnelles " .
"conformément à la :startACharte de confidentialité:endA.",
'senddata' => "I authorize AGIS to process my personal data in accordance " .
"with the :startA Privacy Policy :endA.",
'send' => 'Send'
];

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
// phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found
return [
'acceptcgu' => "J’autorise AGIS à traiter mes données personnelles " .
"conformément à la :startACharte de confidentialité:endA.",
'senddata' => "J'ai lu et j'accepte la politique de confidentialité " .
"de ce site: :startA Voir nos mentions légales:endA.",
'send' => 'Envoyer'
];

View file

@ -6,6 +6,10 @@ img {
max-width: 100%;
}
.form-check-input[type="checkbox"]:checked {
#{--bs-form-check-bg-image}: url("@/images/global/checkbox-cross.svg");
}
.bg-agis-yellow {
background-image: url('@/images/global/bg-yellow.svg');
background-position: center;

View file

@ -18,15 +18,11 @@
}
&.active::after {
background: url("@/images/global/btn-arrow-dark.png");
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
transform: rotate(270deg);
}
}
&-products-input {
display: none;
&.active {
display: flex;
}
}
}

View file

@ -1,35 +1,57 @@
document.addEventListener("DOMContentLoaded", function () {
// Select after animation
const selects = document.querySelectorAll(".contact .select-form") as NodeListOf<HTMLFieldSetElement>;
const contactPage = document.querySelector("section.contact");
if (contactPage === null) {
return;
}
document.body.addEventListener("click", function (event) {
const target = event.target as Node | null;
selects.forEach(select => {
if(select.contains(target)){
selectToggleArrowClass(select);
// * Return string error.
function getErrorString(fieldName: string) {
return `Élement du dom ${fieldName} inexistant.`;
}
// * Toggle la dropdown Arrow du select.
const contactFormSelectList = contactPage.querySelectorAll("select") as NodeListOf<HTMLSelectElement>;
document.body.addEventListener("click", function (e: MouseEvent) {
const target = e.target as HTMLElement | null;
contactFormSelectList.forEach(select => {
if (select.contains(target)) {
select.parentElement!.classList.toggle("active");
} else {
selectRemoveArrowClass(select);
select.parentElement!.classList.remove("active");
}
});
});
function selectToggleArrowClass(select: HTMLFieldSetElement) {
select.classList.toggle("active");
// * Show more input on specific option selected.
const selectObject = contactPage.querySelector("select[name=\"object\"]") as HTMLSelectElement | null;
const contactProductsInput = contactPage.querySelector(".contact-products-input") as HTMLDivElement | null;
if (contactProductsInput === null) {
throw new Error(getErrorString(".contact-products-input"));
}
function selectRemoveArrowClass(select: HTMLFieldSetElement) {
select.classList.remove("active");
if (selectObject === null) {
throw new Error(getErrorString("select[name=\"object\"]"));
}
// Show more input on specific option selected
const selectObject = document.getElementsByName("object")[0] as unknown as HTMLSelectElement;
selectObject.addEventListener("click", function () {
const contactProductsInput = document.querySelector(".contact-products-input") as HTMLDivElement;
if (Number(selectObject.value) === 1) {
contactProductsInput.classList.remove("d-none");
}
selectObject.addEventListener("change", () => {
if (Number(selectObject.value) === 1) {
contactProductsInput.classList.add("active");
}
else {
contactProductsInput.classList.remove("active");
contactProductsInput.classList.remove("d-none");
} else {
contactProductsInput.classList.add("d-none");
}
});
// * Get filename.
const inputFile = contactPage.querySelector("input[name=\"file\"]") as HTMLSelectElement | null;
const renderFileName = contactPage.querySelector("#input-file-name") as HTMLParagraphElement | null;
if (inputFile === null) {
throw new Error(getErrorString("input[name=\"file\"]"));
}
if (renderFileName === null) {
throw new Error(getErrorString("#input-file-name"));
}
inputFile.addEventListener("change", function () {
renderFileName.textContent = this.value;
});
});

View file

@ -1,28 +1,41 @@
@component('mail::message')
# Bonjour,
# Bonjour,
Voici un message depuis le formulaire de contact du site web {{ config('app.name') }} :
## Voici un message envoyé depuis le formulaire de contact du site web {{ config('app.name') }} :
Information sur l'utilisateur:
{{ __('validation.custom.civility') }}: {{ $civility }}
{{ __('validation.attributes.first_name') }}: {{ $first_name }}
{{ __('validation.attributes.last_name') }}: {{ $last_name }}
{{ __('validation.custom.society') }}: {{ $society }}
{{ __('validation.attributes.email') }}: {{ $email }}
{{ __('validation.attributes.password') }}: {{ $phone }}
{{ __('validation.attributes.address') }}: {{ $address }}
{{ __('validation.attributes.postal_code') }}: {{ $postal_code }}
{{ __('validation.attributes.city') }}: {{ $city }}
{{ __('validation.custom.object') }}: {{ $object }}
{{ __('validation.attributes.message') }}: {{ $message }}
Information sur le produit:
{{ __('validation.custom.product_name') }}: {{ $product_name }}
{{ __('validation.custom.product_date_limit') }}: {{ $product_date_limit }}
{{ __('validation.custom.product_barcode') }}: {{ $product_barcode }}
{{ __('validation.custom.product_lot') }}: {{ $product_lot }}
{{ __('validation.custom.product_date_consumption') }}: {{ $product_date_consumption }}
{{ __('validation.custom.product_location') }}: {{ $product_location }}
{{ config('app.name') }}.
### Information sur l'utilisateur:
@component('mail::panel')
- **{{ __('validation.custom.civility') }}:** {{ \App\Enums\Contact\CivilityEnum::make($data->civility)->label() ?? '' }}
- **{{ __('validation.attributes.first_name') }}:** {{ $data->first_name ?? '' }}
- **{{ __('validation.attributes.last_name') }}:** {{ $data->last_name ?? '' }}
- **{{ __('validation.custom.society') }}:** {{ $data->society ?? '' }}
- **{{ __('validation.attributes.email') }}:** {{ $data->email }}
- **{{ __('validation.attributes.phone') }}:** {{ $data->phone ?? '' }}
- **{{ __('validation.attributes.address') }}:** {{ $data->address ?? '' }}
- **{{ __('validation.attributes.postal_code') }}:** {{ $data->postal_code ?? '' }}
- **{{ __('validation.attributes.city') }}:** {{ $data->city ?? '' }}
- **{{ __('validation.custom.object') }}:** {{ \App\Enums\Contact\ObjectEnum::make($data->object)->label() }}
- **{{ __('validation.attributes.message') }}:** {{ $data->message }}
@endcomponent
@if(
$data->product_name !== null ||
$data->product_date_limit !== null ||
$data->product_barcode !== null ||
$data->product_lot !== null ||
$data->product_date_consumption !== null ||
$data->product_location !== null
)
### Information sur le produit:
@component('mail::panel')
- **{{ __('validation.custom.product_name') }}:** {{ $data->product_name ?? '' }}
- **{{ __('validation.custom.product_date_limit') }}:** {{ $data->product_date_limit ?? '' }}
- **{{ __('validation.custom.product_barcode') }}:** {{ $data->product_barcode ?? '' }}
- **{{ __('validation.custom.product_lot') }}:** {{ $data->product_lot ?? '' }}
- **{{ __('validation.custom.product_date_consumption') }}:** {{ $data->product_date_consumption ?? '' }}
- **{{ __('validation.custom.product_location') }}:** {{ $data->product_location ?? '' }}
@endcomponent
@endif
L'équipe {{ config('app.name') }}
@endcomponent

View file

@ -22,10 +22,10 @@
</div>
</div>
</div>
<form method="POST" action="{{ route('fo.contact.store') }}" enctype="multipart/form-data">
<form id="contact-form" method="POST" action="{{ route('fo.contact.store') }}" enctype="multipart/form-data">
@method('POST')
@csrf
<div class="bg-agis-yellow mb-md-5 pb-md-5 m-0 p-0">
<div class="bg-agis-yellow mb-md-5 m-0 pb-5">
<div class="container">
<div class="position-relative px-md-0 mt-5 px-2 py-5">
<p
@ -39,7 +39,7 @@
<option class="text-capitalize" disabled selected>{{ __('validation.custom.civility') }}</option>
@foreach (\App\Enums\Contact\CivilityEnum::toArray() as $key => $enumObject)
<option class="text-capitalize" value="{{ $enumObject->value }}"
@if (old('civility') == $key) selected @endif>
@if (intval(old('civility')) === $enumObject->value) selected @endif>
{{ $enumObject->label }}
</option>
@endforeach
@ -98,11 +98,11 @@
<div class="col-12 col-md-6 p-0">
<div class="ms-md-5 position-relative pt-md-0 h-100 pt-4">
<fieldset class="select-form d-flex flex-column justify-content-end align-items-start h-100">
<select class="form-control text-capitalize" name="object" role="button">
<select class="form-control text-capitalize" name="object" role="button" required>
<option class="text-capitalize" disabled selected>{{ __('validation.custom.object') }}</option>
@foreach (\App\Enums\Contact\ObjectEnum::toArray() as $key => $enumObject)
<option class="text-capitalize" value="{{ $enumObject->value }}"
@if (old('object') === $key) selected @endif>
@if (intval(old('object')) === $enumObject->value) selected @endif>
{{ $enumObject->label }}
</option>
@endforeach
@ -110,7 +110,7 @@
</fieldset>
</div>
</div>
<div class="contact-products-input row mx-auto p-0">
<div class="contact-products-input row d-none mx-auto p-0">
<p class="highlight black m-0 mx-auto my-5 w-fit px-5 text-center text-white">
{{ Str::of(__('pour pouvoir vous répondre nous avons besoin de quelques informations :'))->ucFirst()->value() }}
</p>
@ -171,15 +171,20 @@
<div class="col-12 my-5 p-0">
<fieldset class="row">
<div class="col-12 col-md-6 pe-md-5">
<label class="mt-1" for="file">
<p class="mb-0 mt-1">
{{ Str::of(__('souhaitez-vous joindre une photo ?'))->ucFirst()->value() }}
</label>
<span
class="text-body-secondary">{{ Str::of(__('formats acceptés : jpg, png'))->ucFirst()->value() }}</span>
</p>
<span class="text-body-secondary">
{{ Str::of(__('formats acceptés : jpg, png'))->ucFirst()->value() }}
</span>
</div>
<div class="col-12 col-md-6 ps-md-5">
<input class="form-control" id ="file" name="file" type="file"
value="{{ old('file') }}" role="button" accept="image/*">
<label class="btn btn-primary w-100" for="file">
{{ Str::of(__('ajouter un fichier'))->ucFirst()->value() }}
</label>
<input class="d-none" id ="file" name="file" type="file" value="{{ old('file') }}"
role="button" accept="image/*">
<p class="m-0" id="input-file-name"></p>
</div>
</fieldset>
</div>
@ -187,9 +192,9 @@
<div class="col-12 mb-5 p-0">
<fieldset class="d-flex flex-column justify-content-center align-items-start">
<label class="mt-1" for="message">
{{ Str::of(__('message'))->ucFirst()->value() }}&nbsp;:
{{ Str::of(__('message'))->ucFirst()->value() }}*&nbsp;:
</label>
<textarea class="form-control" id="message" name="message" rows="6">{{ old('message') }}</textarea>
<textarea class="form-control" id="message" name="message" rows="6" required>{{ old('message') }}</textarea>
</fieldset>
</div>
<div class="col-12 mb-1 p-0">
@ -197,8 +202,12 @@
<input class="form-check-input rounded-0 mt-2 p-3" id="accept_rules" name="accept_rules" type="checkbox"
value="{{ old('accept_rules') }}" role="button" required>
<label class="ms-2 mt-1" for="accept_rules" role="button">
{{ Str::of(__('j\'ai lu et j\'accepte la politique de confidentialité de ce site.'))->ucFirst()->value() }}&nbsp;:
<a href="{{ route('fo.legals.show') }}" target="_blank">{{ __('Voir nos mentions légales') }}</a>
{!! nl2br(
__('contact.acceptcgu', [
'startA' => '<a href="' . route('fo.policies.show') . '">',
'endA' => '</a>',
]),
) !!}
</label>
</fieldset>
</div>
@ -207,19 +216,57 @@
<input class="form-check-input rounded-0 mt-2 p-3" id="send_data" name="send_data" type="checkbox"
value="{{ old('send_data') }}" role="button" required>
<label class="ms-2 mt-1" for="send_data" role="button">
{{ Str::of(__('j\'autorise Agis à enregistrer mes données à fin de traiter ma demande'))->ucFirst()->value() }}&nbsp;:
{!! nl2br(
__('contact.senddata', [
'startA' => '<a href="' . route('fo.legals.show') . '">',
'endA' => '</a>',
]),
) !!}
</label>
</fieldset>
</div>
<p>{{ __('*Champ obligatoire') }}</p>
<a class="cn-cookie-link" id="recaptcha-warning" href="" rel="nofollow">
<strong class="text-underline text-bold text-normal text-danger">
{{ __('cookie-notice.custom.recaptcha.warning') }}
</strong>
</a>
<div class="d-flex flex-column justify-content-center align-items-center">
<div id="r_captcha"></div>
@if ($errors->has('g-recaptcha-response'))
<div class="mb-6">
<span class="text-danger">{{ $errors->first('g-recaptcha-response') }}</span>
</div>
@endif
<p>{{ __('*Champ obligatoire') }}</p>
</div>
</div>
</div>
<button class="btn btn-primary d-none d-md-block w-100 text-capitalize" type="submit">{{ __('envoyer') }}</button>
<button class="g-recaptcha btn btn-primary w-100 text-capitalize"
data-sitekey="{{ config('services.google.recaptcha.public') }}"
type="submit">{{ Str::ucfirst(__('contact.send')) }}</button>
</div>
</div>
<div class="px-3">
<button class="btn btn-primary d-block d-md-none w-100 mb-5 mt-3" type="submit">{{ __('envoyer') }}</button>
</div>
</form>
</section>
@endsection
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function() {
window.__CN_Recaptcha = function() {
(function(d, t) {
let g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.src = 'https://www.google.com/recaptcha/api.js?render=explicit&onload=__CN_Recaptcha_Loaded';
s.parentNode.insertBefore(g, s)
}(document, 'script'));
};
window.__CN_Recaptcha_Loaded = function() {
grecaptcha.render('r_captcha', {
'sitekey': '{{ config('services.google.recaptcha.public') }}'
});
document.getElementById('recaptcha-warning').remove();
document.getElementById('contact-form').inert = false;
};
});
</script>
@endpush

View file

@ -4,40 +4,38 @@
$site_name = Str::ucfirst(config('app.name'));
$logo_picture_url = Vite::asset('resources/assets/images/layout/logo.svg', 'build');
$logo_alt_text = "Logo {$site_name}";
// $confidentiality_page_url = route('page.confidentiality');
// TODO : Changer qd la page existera
$confidentiality_page_url = "#";
$confidentiality_page_url = route('fo.policies.show');
$strings = (object)[
'button_customize_cookies' => __('cookie-notice.button_customize_cookies'),
'button_forbid' => __('cookie-notice.button_forbid'),
'button_allow' => __('cookie-notice.button_allow'),
'button_forbid_all' => Str::upper(__('cookie-notice.button_forbid_all')),
'button_allow_all' => Str::upper(__('cookie-notice.button_allow_all')),
'button_customize' => Str::upper(__('cookie-notice.button_customize')),
'button_back' => Str::upper(__('cookie-notice.button_back')),
'banner_title' => __('cookie-notice.banner_title', ['site_name' => $site_name]),
'banner_text_open' => __('cookie-notice.banner_text_open', ['site_name' => $site_name]),
'banner_text' => __('cookie-notice.banner_text'),
'banner_details' => __('cookie-notice.banner_details'),
'banner_details_link' => __('cookie-notice.banner_details_link'),
'button_customize_cookies' => __('cookie-notice.button_customize_cookies'),
'button_forbid' => __('cookie-notice.button_forbid'),
'button_allow' => __('cookie-notice.button_allow'),
'button_forbid_all' => Str::upper(__('cookie-notice.button_forbid_all')),
'button_allow_all' => Str::upper(__('cookie-notice.button_allow_all')),
'button_customize' => Str::upper(__('cookie-notice.button_customize')),
'button_back' => Str::upper(__('cookie-notice.button_back')),
'banner_title' => __('cookie-notice.banner_title', ['site_name' => $site_name]),
'banner_text_open' => __('cookie-notice.banner_text_open', ['site_name' => $site_name]),
'banner_text' => __('cookie-notice.banner_text'),
'banner_details' => __('cookie-notice.banner_details'),
'banner_details_link' => __('cookie-notice.banner_details_link'),
'banner_details_link_title' => __('cookie-notice.banner_details_link_title'),
'banner_more_details' => __('cookie-notice.banner_more_details'),
'banner_less_details' => __('cookie-notice.banner_less_details'),
'Panel_title' => __('cookie-notice.Panel_title'),
'Panel_subtitle' => __('cookie-notice.Panel_subtitle'),
'Panel_details' => __('cookie-notice.Panel_details'),
'banner_more_details' => __('cookie-notice.banner_more_details'),
'banner_less_details' => __('cookie-notice.banner_less_details'),
'Panel_title' => __('cookie-notice.Panel_title'),
'Panel_subtitle' => __('cookie-notice.Panel_subtitle'),
'Panel_details' => __('cookie-notice.Panel_details'),
];
$cookies = [];
// RECAPTCHA
$cookies['recaptcha'] = [
'name' => __('cookie-notice.custom.recaptcha.title'),
'description' => __('cookie-notice.custom.recaptcha.description'),
'link' => 'https://policies.google.com/privacy',
'labelLink' => __('En savoir +'),
'cookies' => ['NID', '__Secure-3PAPISID', '__Secure-3PSID', '__Secure-3PSIDCC']
'name' => __('cookie-notice.custom.recaptcha.title'),
'description' => __('cookie-notice.custom.recaptcha.description'),
'link' => 'https://policies.google.com/privacy',
'labelLink' => __('En savoir +'),
'cookies' => ['NID', '__Secure-3PAPISID', '__Secure-3PSID', '__Secure-3PSIDCC']
];
$cookies['recaptcha']['script'] = <<<SCRIPT
@ -50,11 +48,11 @@ SCRIPT;
// MATOMO
$cookies['matomo'] = [
'name' => __('cookie-notice.custom.matomo.title'),
'name' => __('cookie-notice.custom.matomo.title'),
'description' => __('cookie-notice.custom.matomo.description'),
'link' => 'https://fr.matomo.org/gdpr-analytics/',
'labelLink' => __('En savoir +'),
'cookies' => ['_pk']
'link' => 'https://fr.matomo.org/gdpr-analytics/',
'labelLink' => __('En savoir +'),
'cookies' => ['_pk']
];
$cookies['matomo']['script'] = <<<SCRIPT

View file

@ -4,7 +4,7 @@
@if (trim($slot) === 'Laravel')
<img class="logo" src="https://laravel.com/img/notification-logo.png" alt="Laravel Logo">
@else
<img class="logo img-fluid" src="{{ Vite::asset('resources/assets/images/global/logo.png') }}" alt="{{ config('app.name') }}">
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/global/logo.png') }}" alt="{{ config('app.name') }}">
@endif
</a>
</td>

View file

@ -10,8 +10,11 @@ Route::middleware(['throttle:credentials'])
Route::get('/explorateur-et-gastronome', [StaticPageController::class, 'explorer'])->name('explorer');
Route::view('/bs-demo', 'fo.pages.bs-demo')->name('bs-demo');
// * CONTACT
Route::get('/contact', [StaticPageController::class, 'contact'])->name('contact.show');
Route::post('/contact-form', [StaticPageController::class, 'contactForm'])->name('contact.store');
// * LEGALS
Route::get('/mentions-legales', [StaticPageController::class, 'legals'])->name('legals.show');
Route::get('/charte-de-confidentialite', [StaticPageController::class, 'policies'])->name('policies.show');
});