fix: 🐛 processing of club feedback #179

This commit is contained in:
Alexis Gousseau 2024-10-09 14:29:27 +02:00
parent b32a9ab20e
commit cc3ad03aa4
16 changed files with 152 additions and 87 deletions

View file

@ -73,7 +73,7 @@ class StoreCustomerRequest extends FormRequest
'required',
'email:rfc,dns,spoof',
'max:255',
// * Does email already exists in CRM ?
// Does email already exists in CRM ?
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
function (string $attribute, $value, \Closure $fail) {
if (CrmCustomer::findWithEmail(\strval($value))) {
@ -113,8 +113,8 @@ class StoreCustomerRequest extends FormRequest
'email' => trans('validation.attributes.email'),
'password' => trans('validation.attributes.password'),
'password_confirmation' => trans('validation.attributes.password_confirmation'),
'ok_cgv' => trans('conditions d\'utilisation'),
'opt_in' => trans('newsletter'),
'ok_cgv' => trans('validation.custom.terms'),
'opt_in' => trans('validation.custom.newsletter'),
];
}
}

View file

@ -33,8 +33,10 @@ class UpdatePasswordRequest extends FormRequest
new CrmCustomerPassword($crmCustomer)
],
'password' => [
'required', 'string', 'max:255', 'confirmed',
Password::min(8)->mixedCase()->letters()->numbers()->uncompromised()
'required',
'string',
'confirmed',
Password::min(8)->max(255)->mixedCase()->letters()->numbers()->uncompromised()
]
];
}
@ -51,4 +53,22 @@ class UpdatePasswordRequest extends FormRequest
'password' => trans('validation.attributes.password'),
];
}
/**
* Get custom messages for validator errors.
*
* @return array
*/
public function messages(): array
{
return [
'password.max' => trans('255 caractères maximum'),
'password.min' => trans('8 caractères minimum'),
'password.letters' => trans('Au moins une lettre'),
'password.numbers' => trans('Au moins un chiffre'),
'password.mixed' => trans('Au moins une lettre majuscule et une lettre minuscule'),
'password.uncompromised' => trans('Ne doît pas être compromis'),
'password.confirmed' => trans('La confirmation doît correspondre au nouveau'),
];
}
}

View file

@ -277,6 +277,7 @@ return [
'multiple_answers' => 'multiple answers',
'nb_guests' => 'number of reference persons for the list of ingredients',
'new' => 'new',
'newsletter' => 'newsletter',
'on_homepage' => 'on homepage',
'order' => 'order',
'packaging' => 'packaging',

View file

@ -282,6 +282,7 @@ return [
'multiple_answers' => 'multiple réponses',
'nb_guests' => 'nombre de personnes de référence pour la liste des ingrédients',
'new' => 'nouveau',
'newsletter' => 'newsletter',
'old_password' => 'ancien mot de passe',
'on_homepage' => 'sur la page d\'accueil',
'order' => 'ordre',

View file

@ -30,8 +30,10 @@
}
.left-part {
position: sticky;
top: 2rem;
height: fit-content;
@include media-breakpoint-up(lg) {
position: sticky;
top: 2rem;
height: fit-content;
}
}
}

View file

@ -4,12 +4,12 @@
<div class="col-sm-12 col-md-6 col-lg-8">
<div
v-if="sellItems.length"
class="row"
:class="['row', {'justify-content-end': sellItems.length <= 1}]"
>
<div
v-for="sellItem in sellItems"
:key="sellItem.id"
class="col-sm-12 col-md-12 col-lg-6 pb-3 pb-lg-0"
class="col-sm-12 col-lg-6 py-3 pb-lg-0"
>
<div class="card bg-light text-bg-light border-0 rounded-4">
<img
@ -45,8 +45,8 @@
</p>
</div>
<!-- COMMAND -->
<div class="col-sm-12 col-md-6 col-lg-4">
<div class="bg-light text-bg-light rounded-4 w-100 mx-auto p-4">
<div class="col-sm-12 col-md-6 col-lg-4 pt-3">
<div class="recap-command bg-light position-sticky text-bg-light rounded-4 w-100 mx-auto p-4">
<h2 class="f-bourton-base">
{{ trans.methods.__('Ma commande') }}
</h2>
@ -123,7 +123,7 @@
</ul>
<div class="d-flex justify-content-between align-items-start">
<p class="f-bourton-base mt-2 mb-0">
{{ trans.methods.__('Montant Total') }}&nbsp;:
{{ trans.methods.__('Montant Total (TTC)') }}&nbsp;:
</p>
<p class="d-flex flex-column justify-content-center align-items-center">
<span class="fs-1 f-bourton-base text-warning">{{ formatPrice(currentShop.total) }}</span><br>
@ -267,4 +267,7 @@ function formatPrice(number: number): string {
.fade-leave-to {
opacity: 0;
}
.recap-command {
top: 1.5rem;
}
</style>

View file

@ -236,7 +236,7 @@
colspan="4"
>
<div class="d-flex flex-column flex-md-row justify-content-end align-items-end align-items-md-start">
<label class="f-bourton-base pt-2 mt-1">{{ trans.methods.__('Montant Total') }} :</label>
<label class="f-bourton-base pt-2 mt-1">{{ trans.methods.__('Montant Total (TTC)') }} :</label>
<p class="d-flex flex-column justify-content-center align-items-center ms-md-3 m-0">
<span class="fs-1 f-bourton-base text-warning">{{ formatPrice(currentShop.total) }}</span>
<span>{{ trans.methods.__('Frais de port inclus') }}</span>

View file

@ -78,7 +78,7 @@
<small>
{!! clean(
__(
'Le mot de passe doit avoir une longueur de 8 caractères minimum,<br>doit contenir une lettre majuscule et une lettre minucule,<br>doit contenir un caractère spécial comme une virgule par exemple,<br>doit contenir un chiffre.',
'Le mot de passe doît respecter certaines règles :<br>8 caractères minimum,<br>Au moins une lettre majuscule et une lettre minucule,<br>Au moins un caractère spécial : \ / * ! « ? : @ |,<br>Au moins un chiffre.',
),
) !!}
</small>

View file

@ -195,7 +195,7 @@
<small>
{!! clean(
__(
'Le mot de passe doit avoir une longueur de 8 caractères minimum,<br>doit contenir une lettre majuscule et une lettre minucule,<br>doit contenir un caractère spécial comme une virgule par exemple,<br>doit contenir un chiffre.',
'Le mot de passe doît respecter certaines règles :<br>8 caractères minimum,<br>Au moins une lettre majuscule et une lettre minucule,<br>Au moins un caractère spécial : \ / * ! « ? : @ |,<br>Au moins un chiffre.',
),
) !!}
</small>

View file

@ -1,70 +1,102 @@
<form class="text-bg-light form-customer-info rounded-4 container container p-3" method="POST"
action="{{ route('club.customers.password.update') }}">
@csrf
@php
$columns = [
'label' => 'col-sm-4 col-md-2',
'input' => 'col-sm-7 offset-sm-1 col-md-4 offset-md-0',
];
@endphp
<fieldset class="row mb-3">
<legend class="col-12 f-bourton-base mb-4">{{ __('Modification du mot de passe') }}</legend>
{{-- OLD PASSWORD --}}
<label for="info-old-password" @class(array_merge(['mb-3', Arr::first($columns)]))>
{{ Str::ucfirst(__('validation.custom.old_password')) }} *
</label>
<div @class(array_merge(['mb-3', Arr::last($columns)]))>
<div class="col-12 col-lg-6 p-0">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-old-password @if ($errors->has('old_password')) is-invalid @endif"
id="old_password" name="old_password" type="password" aria-label="{{ __('validation.custom.old_password') }}"
autocomplete="old_password" required />
@php $dataPassword = ['id' => 'old_password']; @endphp
<span class="btn-group password-visibility" data-json='@json($dataPassword)'></span>
<div class="col-sm-4 col-lg-12 fw-semibold m-0">
<label for="old_password" class="mt-md-3 mt-lg-0 mb-3">
{{ str(__('validation.custom.old_password'))->ucfirst() }} *
</label>
</div>
<div class="col-sm-8 col-lg-12">
<div class="mb-3">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-old-password @if ($errors->has('old_password')) is-invalid @endif"
id="old_password" name="old_password" type="password" aria-label="{{ __('validation.custom.old_password') }}"
autocomplete="old_password" required />
<span class="btn-group password-visibility" data-json='@json(['id' => 'old_password'])'></span>
</div>
</div>
</div>
</div>
<div class="col-12">
@if ($errors->get('old_password'))
@foreach ($errors->get('old_password') as $message)
<p class="text-danger py-1">{{ $message }}</p>
@endforeach
@endif
</div>
@foreach ($errors->get('old_password') as $message)
<div class="invalid-feedback d-block">{{ $message }}</div>
@endforeach
</div>
</div>
{{-- PASSWORD --}}
<label for="info-password-confirmation" @class(array_merge(['mb-3', Arr::first($columns)]))>
{{ Str::ucfirst(__('validation.attributes.password')) }} *
</label>
<div @class(array_merge(['mb-3', Arr::last($columns)]))>
<div class="col-12 col-lg-6 p-0">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-password @if ($errors->has('password')) is-invalid @endif"
id="password" name="password" type="password" aria-label="{{ __('validation.attributes.password') }}"
autocomplete="password" required />
@php $dataPassword = ['id' => 'password']; @endphp
<span class="btn-group password-visibility" data-json='@json($dataPassword)'></span>
<div class="col-sm-4 col-lg-12 fw-semibold m-0">
<label for="old_password" class="mt-md-3 mt-lg-0 mb-3">
{{ str(__('validation.attributes.password'))->ucfirst() }} *
</label>
</div>
<div class="col-sm-8 col-lg-12">
<div class="mb-3">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-password @if ($errors->has('password')) is-invalid @endif"
id="password" name="password" type="password" aria-label="{{ __('validation.attributes.password') }}"
autocomplete="password" required />
<span class="btn-group password-visibility" data-json='@json(['id' => 'password'])'></span>
</div>
</div>
</div>
</div>
<div class="col-12">
@if ($errors->get('password'))
<ul class="list-group list-group-flush text-danger">
<span class="mb-1">{{ __('Le mot de passe doît respecter certaines règles :') }}</span>
@foreach ($errors->get('password') as $message)
<li class="list-group-item list-group-item-danger bg-transparent text-danger border-0 py-1">{{ $message }}</li>
@endforeach
</ul>
@endif
</div>
@foreach ($errors->get('password') as $message)
<div class="invalid-feedback d-block">{{ $message }}</div>
@endforeach
</div>
</div>
{{-- PASSWORD CONFIRMATION --}}
<label for="info-password-confirmation" @class(array_merge(['mb-3', Arr::first($columns)]))>
{{ Str::ucfirst(__('validation.attributes.password_confirmation')) }} *
</label>
<div @class(array_merge(['mb-3', Arr::last($columns)]))>
<div class="col-12 col-lg-6 p-0">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-password @if ($errors->has('password_confirmation')) is-invalid @endif"
id="password_confirmation" name="password_confirmation" type="password"
aria-label="{{ __('validation.attributes.password_confirmation') }}"
autocomplete="new-password" required />
@php $dataConfirmPassword = ['id' => 'password_confirmation']; @endphp
<span class="btn-group password-visibility" data-json='@json($dataConfirmPassword)'></span>
<div class="col-sm-4 col-lg-12 fw-semibold m-0">
<label for="password_confirmation" class="mt-md-3 mt-lg-0 mb-3">
{{ str(__('validation.attributes.password_confirmation'))->ucfirst() }} *
</label>
</div>
<div class="col-sm-8 col-lg-12">
<div class="mb-3">
<div class="row w-100 mx-auto">
<div class="col-12 input-group d-flex justify-content-center p-0">
<input class="form-control custom-input-password @if ($errors->has('password_confirmation')) is-invalid @endif"
id="password_confirmation" name="password_confirmation" type="password"
aria-label="{{ __('validation.attributes.password_confirmation') }}"
autocomplete="new-password" required />
<span class="btn-group password-visibility" data-json='@json(['id' => 'password_confirmation'])'></span>
</div>
</div>
</div>
</div>
<div class="col-12">
@if ($errors->get('password_confirmation'))
<ul class="list-group list-group-flush text-danger">{{ __('Le mot de passe doit avoir :') }}
@foreach ($errors->get('password_confirmation') as $message)
<li class="list-group-item list-group-item-danger bg-transparent text-danger border-0 py-1">{{ $message }}</li>
@endforeach
</ul>
@endif
</div>
@foreach ($errors->get('password') as $message)
<div class="invalid-feedback d-block">{{ $message }}</div>
@endforeach
</div>
</div>
</fieldset>

View file

@ -31,10 +31,12 @@
</div>
<div class="col-12 col-md-6">
<span class="d-block h2 f-bourton-base">{{ __('La bourse aux échanges') }}</span>
<p>{{ __('Le Gaulois vous aide à gérer votre collection et vous met en relation avec d’autres collectionneurs pour échanger vos doubles et/ou trouver les magnets Départ’Aimants qu’il vous manquent.') }}
<p>
{{ __('Le Gaulois vous aide à gérer votre collection et vous met en relation avec d’autres collectionneurs pour échanger vos doubles et/ou trouver les magnets Départ’Aimants qu’il vous manquent.') }}
</p>
<a class="link-white" href="#FIXME:conditions bourse"
title="{{ __('Go to page', ['page' => 'PAGE']) }}">{{ __('Voir les conditions d\'utilisation du Club des Gaulois') }}</a>
<a class="link-white" href="{{ route('fo.legals.show') }}" target="_blank" title="{{ __('Go to page', ['page' => 'PAGE']) }}">
{{ __('Voir les conditions d\'utilisation du Club des Gaulois') }}
</a>
</div>
</div>
</section>

View file

@ -29,7 +29,7 @@
@if ($models->count())
@foreach($models as $model)
<div class="col-12 col-sm-6 col-lg-4 mx-auto">
@include($__env->yieldContent('blade'), ['model' => $model])
<div>@include($__env->yieldContent('blade'), ['model' => $model])</div>
</div>
@endforeach
<div class="col-12 mb-5 mt-3">

View file

@ -40,7 +40,7 @@
'contentClass' => 'text-bg-quint',
'membersAmount' => $customerModelsCount,
])
@include('club.partials.card-club-home', [
{{-- @include('club.partials.card-club-home', [
'outterClass' => 'm-3',
'picture' => Vite::asset('resources/assets/images/club/homepage/card-3.png'),
'line1' => __('Des jeux'),
@ -59,7 +59,7 @@
'line2Class' => 'fs-4',
'content' => __('Peluche, Chaussette, Set couverts, stylos Le Gaulois...'),
'contentClass' => 'text-bg-danger',
])
]) --}}
</div>
</div>
</section>

View file

@ -14,7 +14,7 @@
<div class="col-12 mb-2 mt-3">
<h1 class="f-bakerie-rough text-center">
{{ __('Bonjour :username !', [
'username' => Str::title(auth('club')->user()->username),
'username' => str(auth('club')->user()->username)->title(),
]) }}
</h1>
</div>
@ -82,23 +82,27 @@
<span class="text-bg-warning">{{ __('Économiser aujourd’hui') }}</span>
<span class="text-bg-danger">@money($discountsTotal)</span>
</h2>
<span class="d-block fs-5 fw-bold mb-5">
{{ __('En bons de réduction sur une sélection de produits Le Gaulois') }}
</span>
<div class="d-flex mb-5">
<div class="swiper d-none d-md-block w-100 mb-3" id="swiper-discounts">
<div class="swiper-wrapper w-fit">
@foreach ($discountModels as $discountModel)
<div class="swiper-slide">
@include('club.partials.club-card-coupon', [
'discount' => $discountModel,
'outerClass' => 'mx-3',
])
</div>
@endforeach
@if ($discountModels->count())
<span class="d-block fs-5 fw-bold mb-5">
{{ __('En bons de réduction sur une sélection de produits Le Gaulois') }}
</span>
<div class="d-flex mb-5">
<div class="swiper d-none d-md-block w-100 mb-3" id="swiper-discounts">
<div class="swiper-wrapper w-fit">
@foreach ($discountModels as $discountModel)
<div class="swiper-slide">
@include('club.partials.club-card-coupon', [
'discount' => $discountModel,
'outerClass' => 'mx-3',
])
</div>
@endforeach
</div>
</div>
</div>
</div>
@else
<p class="text-center">{{ __('Aucun bon de réduction n\'est actuellement disponible !') }}</p>
@endif
<div class="d-flex justify-content-center">
<div class="swiper-discounts-pagination py-4"></div>
</div>

View file

@ -241,7 +241,7 @@
</tbody>
</table>
<div class="text-end">
<p class="f-bourbon-base fs-title w-fit">{{ __('Montant total :') }}
<p class="f-bourbon-base fs-title w-fit">{{ __('Montant total (TTC) :') }}
<span class="text-center text-yellow w-fit">
{{ e(app('phpMoneyFormatter')->format(new Money($total * 100, app('phpMoneyCurrency')))) }}
</span>

View file

@ -1,4 +1,4 @@
<div @class(['card card-club-home rounded-5 border-0', $outterClass ?? ''])>
<a @class(['card card-club-home rounded-5 border-0', $outterClass ?? '']) href="{{ route('club.login') }}">
<img class="card-img-top rounded-5" src="{{ $picture }}" alt="{{ $picture_alt ?? __('Image de fond') }}">
<div class="card-body p-0">
<div class="lines d-inline-flex flex-column align-items-start flex-wrap">
@ -23,4 +23,4 @@
])>{{ clean($content) }}
</div>
</div>
</div>
</a>