feat: ✨ set authorized countries in settings #42
This commit is contained in:
parent
3ee3b5c69a
commit
e6839a71c8
11 changed files with 510 additions and 132 deletions
|
|
@ -3,10 +3,11 @@
|
|||
namespace App\Http\Controllers\Fo\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Settings;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -56,19 +57,30 @@ class LoginController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* The user has been authenticated.
|
||||
* Check if the authenticated user can access the game
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Database\Eloquent\Model $user
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\Models\Customer $user
|
||||
* @return void
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing, Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
*/
|
||||
protected function authenticated(Request $request, Model $user): void
|
||||
protected function authenticated(Request $request, Customer $user): void
|
||||
{
|
||||
/** @var \App\Models\Customer $user */
|
||||
$user->last_connection = \now();
|
||||
$user->saveOrFail();
|
||||
Session::flash('info', trans('Vous êtes à présent connecté'));
|
||||
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
|
||||
$crmCustomer = $user->api_data;
|
||||
|
||||
/** @var \App\Models\Settings */
|
||||
$settings = app(Settings::class);
|
||||
$countries = $settings->authorized_countries;
|
||||
|
||||
if (count($countries) && !in_array($crmCustomer->country->value, $countries)) {
|
||||
$this->logout($request);
|
||||
Session::flash('info', trans('Ce jeu n\'est pas disponible dans votre pays'));
|
||||
} else {
|
||||
$user->last_connection = \now();
|
||||
$user->saveOrFail();
|
||||
Session::flash('info', trans('Vous êtes à présent connecté'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use App\Lib\Helpers\ToolboxHelper;
|
|||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
use LDC\LDCCRM\Enums\Country;
|
||||
|
||||
class UpdateSettingsRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -14,7 +16,7 @@ class UpdateSettingsRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('settings'));
|
||||
}
|
||||
|
|
@ -25,26 +27,27 @@ class UpdateSettingsRequest extends FormRequest
|
|||
* @return void
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
// phpcs:enable
|
||||
$this->merge([
|
||||
// Checkboxes.
|
||||
'notify_prize_sent' => $this->boolean('notify_prize_sent'),
|
||||
'use_ean_codes' => $this->boolean('use_ean_codes'),
|
||||
'activated_teaser' => $this->boolean('activated_teaser'),
|
||||
'activated_close_page' => $this->boolean('activated_close_page'),
|
||||
'discounts_activated' => $this->boolean('discounts_activated'),
|
||||
'winning_proof' => $this->boolean('winning_proof'),
|
||||
'notify_prize_sent' => $this->boolean('notify_prize_sent'),
|
||||
'use_ean_codes' => $this->boolean('use_ean_codes'),
|
||||
'activated_teaser' => $this->boolean('activated_teaser'),
|
||||
'activated_close_page' => $this->boolean('activated_close_page'),
|
||||
'discounts_activated' => $this->boolean('discounts_activated'),
|
||||
'winning_proof' => $this->boolean('winning_proof'),
|
||||
// Arrays.
|
||||
'notification_emails' => collect($this->input('notification_emails'))->filter()->all(),
|
||||
'notification_emails' => collect($this->input('notification_emails'))->filter()->all(),
|
||||
'authorized_countries' => collect($this->input('authorized_countries'))->filter()->all(),
|
||||
// Remove some dates if the checkbox is uncheck.
|
||||
'close_page_active_date' => $this->input('activated_close_page') ?
|
||||
$this->input('close_page_active_date') : null,
|
||||
// Remove discounts datas if the discount checkbox is uncheck.
|
||||
'discounts_site' => $this->input('discounts_activated') ? $this->input('discounts_site') : null,
|
||||
'discounts_campaign' => $this->input('discounts_activated') ? $this->input('discounts_campaign') : null,
|
||||
'web_coupons' => collect($this->input('web_coupons'))->filter()->all(),
|
||||
'discounts_site' => $this->input('discounts_activated') ? $this->input('discounts_site') : null,
|
||||
'discounts_campaign' => $this->input('discounts_activated') ? $this->input('discounts_campaign') : null,
|
||||
'web_coupons' => collect($this->input('web_coupons'))->filter()->all(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +56,7 @@ class UpdateSettingsRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:3|max:255',
|
||||
|
|
@ -105,9 +108,9 @@ class UpdateSettingsRequest extends FormRequest
|
|||
$fail,
|
||||
(object)[
|
||||
'maxHeight' => 409,
|
||||
'maxWith' => 920,
|
||||
'maxWith' => 920,
|
||||
'minHeight' => 409,
|
||||
'minWith' => 920
|
||||
'minWith' => 920
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
@ -116,6 +119,12 @@ class UpdateSettingsRequest extends FormRequest
|
|||
'notification_emails' => 'required|array|min:1',
|
||||
'notification_emails.*' => 'email:rfc,spoof,dns',
|
||||
|
||||
'authorized_countries' => 'sometimes|array|max:' . count(Country::getValidCountries()),
|
||||
'authorized_countries.*' => [
|
||||
'sometimes',
|
||||
Rule::in(Country::getValidCountries())
|
||||
],
|
||||
|
||||
'winning_proof' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
|
@ -128,33 +137,36 @@ class UpdateSettingsRequest extends FormRequest
|
|||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'name' => trans('validation.attributes.name'),
|
||||
'company' => trans('validation.custom.company'),
|
||||
'start_date' => trans('validation.custom.start_date'),
|
||||
'end_date' => trans('validation.custom.end_date'),
|
||||
'nb_participation_player' => trans('validation.custom.nb_participation_player'),
|
||||
'nb_participation_ip' => trans('validation.custom.nb_participation_ip'),
|
||||
'nb_unique_code_use' => trans('validation.custom.nb_unique_code_use'),
|
||||
'use_ean_codes' => trans('validation.custom.use_ean_codes'),
|
||||
'activated_teaser' => trans('validation.custom.activated_teaser'),
|
||||
'activated_close_page' => trans('validation.custom.activated_close_page'),
|
||||
'close_page_active_date' => trans('validation.custom.close_page_active_date'),
|
||||
'redirect_close' => trans('validation.custom.redirect_close'),
|
||||
'winning_proof' => trans('validation.custom.winning_proof'),
|
||||
'discounts_activated' => trans('validation.custom.discounts_activated'),
|
||||
'discounts_site' => trans('validation.custom.discounts_site'),
|
||||
'discounts_campaign' => trans('validation.custom.discounts_campaign'),
|
||||
'notify_prize_sent' => trans('validation.custom.notify_prize_sent'),
|
||||
'name' => trans('validation.attributes.name'),
|
||||
'company' => trans('validation.custom.company'),
|
||||
'start_date' => trans('validation.custom.start_date'),
|
||||
'end_date' => trans('validation.custom.end_date'),
|
||||
'nb_participation_player' => trans('validation.custom.nb_participation_player'),
|
||||
'nb_participation_ip' => trans('validation.custom.nb_participation_ip'),
|
||||
'nb_unique_code_use' => trans('validation.custom.nb_unique_code_use'),
|
||||
'use_ean_codes' => trans('validation.custom.use_ean_codes'),
|
||||
'activated_teaser' => trans('validation.custom.activated_teaser'),
|
||||
'activated_close_page' => trans('validation.custom.activated_close_page'),
|
||||
'close_page_active_date' => trans('validation.custom.close_page_active_date'),
|
||||
'redirect_close' => trans('validation.custom.redirect_close'),
|
||||
'winning_proof' => trans('validation.custom.winning_proof'),
|
||||
'discounts_activated' => trans('validation.custom.discounts_activated'),
|
||||
'discounts_site' => trans('validation.custom.discounts_site'),
|
||||
'discounts_campaign' => trans('validation.custom.discounts_campaign'),
|
||||
'notify_prize_sent' => trans('validation.custom.notify_prize_sent'),
|
||||
|
||||
'web_coupons' => trans('Tableau des coupons'),
|
||||
'web_coupons' => trans('Tableau des coupons'),
|
||||
'web_coupons.*.web_coupon_identifiant' => trans('Identifiant coupon :index'),
|
||||
'web_coupons.*.percentage' => trans('Pourcentage :index'),
|
||||
'web_coupons.*.face_value' => trans('Valeur faciale :index'),
|
||||
'web_coupons.*.valid_on' => trans('Valable sur :index'),
|
||||
'web_coupons.*.img_name' => trans('Nom image :index'),
|
||||
|
||||
'notification_emails' => trans('Tableau des email à notifier'),
|
||||
'notification_emails.*.email' => trans('validation.attributes.email')
|
||||
'notification_emails' => trans('Tableau des email à notifier'),
|
||||
'notification_emails.*.email' => trans('validation.attributes.email'),
|
||||
|
||||
'authorized_countries' => trans('Tableau des pays éligibles au jeu'),
|
||||
'authorized_countries.*' => trans('validation.custom.authorized_countries'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Fo\Customers;
|
||||
|
||||
use App\Models\Settings;
|
||||
use App\Repositories\Fo\CrmRepository;
|
||||
use App\Rules\IsAdult;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
|
@ -20,7 +21,7 @@ class CreateAccountRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Auth::guard('frontend')->check();
|
||||
}
|
||||
|
|
@ -30,10 +31,10 @@ class CreateAccountRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareForValidation()
|
||||
public function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'phone' => $this->input('phone'),
|
||||
'phone' => $this->input('phone'),
|
||||
'opt_in' => $this->boolean('opt_in'),
|
||||
'ok_cgv' => $this->boolean('ok_cgv')
|
||||
]);
|
||||
|
|
@ -44,9 +45,12 @@ class CreateAccountRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var \App\Models\Customer */
|
||||
/** @var \App\Models\Settings $settings */
|
||||
$settings = app(Settings::class);
|
||||
|
||||
/** @var \App\Models\Customer|null */
|
||||
$authUser = auth('frontend')->user();
|
||||
$countryCode = null;
|
||||
|
||||
|
|
@ -55,43 +59,43 @@ class CreateAccountRequest extends FormRequest
|
|||
(new CrmRepository())->fetchCrmCustomer($authUser)->country->value : 0);
|
||||
$countryRules = match ($countryCode) {
|
||||
Country::belgium()->value => [
|
||||
'phone' => 'phone:BE',
|
||||
'phone' => 'phone:BE',
|
||||
'postal_code' => 'postal_code:BE',
|
||||
],
|
||||
Country::luxembourg()->value => [
|
||||
'phone' => 'phone:LU',
|
||||
'phone' => 'phone:LU',
|
||||
'postal_code' => 'postal_code:LU',
|
||||
],
|
||||
default => [
|
||||
'phone' => 'phone:FR',
|
||||
'phone' => 'phone:FR',
|
||||
'postal_code' => 'postal_code:FR',
|
||||
]
|
||||
};
|
||||
|
||||
return [
|
||||
'lastname' => 'required|string|max:255',
|
||||
'firstname' => 'required|string|max:255',
|
||||
'phone' => [
|
||||
'lastname' => 'required|string|max:255',
|
||||
'firstname' => 'required|string|max:255',
|
||||
'phone' => [
|
||||
'nullable',
|
||||
'max:255',
|
||||
$countryRules['phone'],
|
||||
],
|
||||
'address' => 'required|string|min:1|max:255',
|
||||
'address2' => 'nullable|string|min:1|max:255',
|
||||
'address' => 'required|string|min:1|max:255',
|
||||
'address2' => 'nullable|string|min:1|max:255',
|
||||
'postal_code' => [
|
||||
'required',
|
||||
'string',
|
||||
'min:1',
|
||||
$countryRules['postal_code'],
|
||||
],
|
||||
'city' => 'required|string|min:2|max:255',
|
||||
'birth_date' => ['required', new IsAdult(trans('Vous devez être majeur pour vous inscrire.'))],
|
||||
'country' => [
|
||||
'city' => 'required|string|min:2|max:255',
|
||||
'birth_date' => ['required', new IsAdult(trans('Vous devez être majeur pour vous inscrire.'))],
|
||||
'country' => [
|
||||
'required',
|
||||
new EnumIsValidRule(Country::class),
|
||||
Rule::in(Country::getValidCountries())
|
||||
Rule::in($settings->getAuthorizedCountries()),
|
||||
],
|
||||
'email' => [
|
||||
'email' => [
|
||||
'required',
|
||||
'email:rfc,dns,spoof',
|
||||
'max:255',
|
||||
|
|
@ -104,14 +108,14 @@ class CreateAccountRequest extends FormRequest
|
|||
},
|
||||
'unique:customers,email',
|
||||
],
|
||||
'password' => [
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
Password::min(8)->mixedCase()
|
||||
->numbers()->symbols()->uncompromised()
|
||||
],
|
||||
'ok_cgv' => 'accepted',
|
||||
'opt_in' => 'required|boolean',
|
||||
'ok_cgv' => 'accepted',
|
||||
'opt_in' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -120,23 +124,23 @@ class CreateAccountRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'lastname' => trans('validation.attributes.first_name'),
|
||||
'firstname' => trans('validation.attributes.first_name'),
|
||||
'phone' => trans('validation.attributes.phone'),
|
||||
'address' => trans('validation.attributes.line_address_1'),
|
||||
'address2' => trans('validation.attributes.line_address_2'),
|
||||
'country' => trans('validation.attributes.country'),
|
||||
'postal_code' => trans('validation.attributes.postal_code'),
|
||||
'city' => trans('validation.attributes.city'),
|
||||
'birth_date' => trans('validation.attributes.date_of_birth'),
|
||||
'email' => trans('validation.attributes.email'),
|
||||
'password' => trans('validation.attributes.password'),
|
||||
'lastname' => trans('validation.attributes.first_name'),
|
||||
'firstname' => trans('validation.attributes.first_name'),
|
||||
'phone' => trans('validation.attributes.phone'),
|
||||
'address' => trans('validation.attributes.line_address_1'),
|
||||
'address2' => trans('validation.attributes.line_address_2'),
|
||||
'country' => trans('validation.attributes.country'),
|
||||
'postal_code' => trans('validation.attributes.postal_code'),
|
||||
'city' => trans('validation.attributes.city'),
|
||||
'birth_date' => trans('validation.attributes.date_of_birth'),
|
||||
'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('conditions d\'utilisation'),
|
||||
'opt_in' => trans('newsletter'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -145,17 +149,17 @@ class CreateAccountRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
public function messages(): array
|
||||
{
|
||||
$messages = [
|
||||
'postal_code' => trans('validation.postal_code', [
|
||||
'postal_code' => trans('validation.postal_code', [
|
||||
'countries' => \implode(', ', Country::getValidCountriesLabel()),
|
||||
'examples' => 72000
|
||||
'examples' => 72000
|
||||
]),
|
||||
'phone.phone' => trans('validation.phone', [
|
||||
'phone.phone' => trans('validation.phone', [
|
||||
'countries' => \implode(', ', Country::getValidCountriesLabel())
|
||||
]),
|
||||
'email.unique' => trans('Un compte existe déjà avec cette adresse.'),
|
||||
'email.unique' => trans('Un compte existe déjà avec cette adresse.'),
|
||||
'ok_cgv.accepted' => trans('Vous devez accepter les conditions d\'utilisation du site pour continuer.')
|
||||
];
|
||||
|
||||
|
|
@ -165,7 +169,7 @@ class CreateAccountRequest extends FormRequest
|
|||
[
|
||||
'postal_code' => trans('validation.postal_code', [
|
||||
'countries' => Country::belgium()->label,
|
||||
'examples' => 1000
|
||||
'examples' => 1000
|
||||
]),
|
||||
]
|
||||
),
|
||||
|
|
@ -174,7 +178,7 @@ class CreateAccountRequest extends FormRequest
|
|||
[
|
||||
'postal_code' => trans('validation.postal_code', [
|
||||
'countries' => Country::luxembourg()->label,
|
||||
'examples' => 1111
|
||||
'examples' => 1111
|
||||
]),
|
||||
]
|
||||
),
|
||||
|
|
@ -189,7 +193,7 @@ class CreateAccountRequest extends FormRequest
|
|||
array_search(Country::luxembourg()->label, Country::getValidCountriesLabel()),
|
||||
]
|
||||
)),
|
||||
'examples' => 72000
|
||||
'examples' => 72000
|
||||
]),
|
||||
]
|
||||
),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Carbon\CarbonInterval;
|
|||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use LDC\LDCCRM\Enums\Country;
|
||||
|
||||
/**
|
||||
* Settings.
|
||||
|
|
@ -36,6 +37,7 @@ use Illuminate\Support\Facades\Cache;
|
|||
* @property string $discounts_campaign Discount MesBr campaign
|
||||
* @property array<\App\Lib\Discount> $web_coupons Array of web coupons
|
||||
* @property array<string> $notification_emails Array of email to notify when there's a winnner
|
||||
* @property array<string> $authorized_countries All countries eligible to participate.
|
||||
* @property boolean $winning_proof Is the winning proof needed
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Creation Date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Last update Date.
|
||||
|
|
@ -75,6 +77,7 @@ class Settings extends Model
|
|||
'discounts_site',
|
||||
'discounts_campaign',
|
||||
'web_coupons',
|
||||
'authorized_countries',
|
||||
'notification_emails',
|
||||
'winning_proof',
|
||||
'analytics',
|
||||
|
|
@ -87,17 +90,18 @@ class Settings extends Model
|
|||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'notify_prize_sent' => 'bool',
|
||||
'use_ean_codes' => 'bool',
|
||||
'activated_teaser' => 'bool',
|
||||
'activated_close_page' => 'bool',
|
||||
'discounts_activated' => 'bool',
|
||||
'winning_proof' => 'bool',
|
||||
'start_date' => 'datetime',
|
||||
'end_date' => 'datetime',
|
||||
'notify_prize_sent' => 'bool',
|
||||
'use_ean_codes' => 'bool',
|
||||
'activated_teaser' => 'bool',
|
||||
'activated_close_page' => 'bool',
|
||||
'discounts_activated' => 'bool',
|
||||
'winning_proof' => 'bool',
|
||||
'start_date' => 'datetime',
|
||||
'end_date' => 'datetime',
|
||||
'close_page_active_date' => 'datetime',
|
||||
'web_coupons' => AsArrayOfDiscount::class,
|
||||
'notification_emails' => 'array',
|
||||
'web_coupons' => AsArrayOfDiscount::class,
|
||||
'authorized_countries' => 'array',
|
||||
'notification_emails' => 'array',
|
||||
];
|
||||
|
||||
// * EVENTS
|
||||
|
|
@ -159,23 +163,23 @@ class Settings extends Model
|
|||
{
|
||||
/** @var \App\Models\Settings */
|
||||
$settings = app(Settings::class);
|
||||
if (!(bool)Prize::getCached()->count()) {
|
||||
if (!(bool) Prize::getCached()->count()) {
|
||||
report(new \RuntimeException('Need prizes to enable the game'));
|
||||
return false;
|
||||
}
|
||||
if (!(bool)Cache::remember('codes.count', CarbonInterval::day(), fn () => Code::query()->count())) {
|
||||
if (!(bool) Cache::remember('codes.count', CarbonInterval::day(), fn() => Code::query()->count())) {
|
||||
report(new \RuntimeException('Need codes to enable the game'));
|
||||
return false;
|
||||
}
|
||||
if (!(bool)InstantWin::getCached()->count()) {
|
||||
if (!(bool) InstantWin::getCached()->count()) {
|
||||
report(new \RuntimeException('Need instant win to enable the game'));
|
||||
return false;
|
||||
}
|
||||
if ($settings->use_ean_codes and !(bool)Product::getCached()->count()) {
|
||||
if ($settings->use_ean_codes and !(bool) Product::getCached()->count()) {
|
||||
report(new \RuntimeException('Need products to enable the game using ean codes'));
|
||||
return false;
|
||||
}
|
||||
if ($settings->discounts_activated and !(bool)collect($this->web_coupons)->count()) {
|
||||
if ($settings->discounts_activated and !(bool) collect($this->web_coupons)->count()) {
|
||||
report(new \RuntimeException('Need MesBr coupons to enable the game using discounts'));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -194,7 +198,7 @@ class Settings extends Model
|
|||
public function gameHasBegun(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (): bool => $this->start_date->lte(now())
|
||||
get: fn(): bool => $this->start_date->lte(now())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +212,7 @@ class Settings extends Model
|
|||
public function gameHasEnded(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (): bool => $this->game_has_begun and $this->end_date->lte(now())
|
||||
get: fn(): bool => $this->game_has_begun and $this->end_date->lte(now())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +226,7 @@ class Settings extends Model
|
|||
public function gameIsOpen(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (): bool => $this->game_has_begun and !$this->game_has_ended
|
||||
get: fn(): bool => $this->game_has_begun and !$this->game_has_ended
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +240,7 @@ class Settings extends Model
|
|||
public function shouldDisplayTeaserPage(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (): bool => !$this->game_has_begun and
|
||||
get: fn(): bool => !$this->game_has_begun and
|
||||
!$this->game_has_ended and
|
||||
$this->activated_teaser
|
||||
);
|
||||
|
|
@ -252,13 +256,37 @@ class Settings extends Model
|
|||
public function shouldDisplayEndPage(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (): bool => $this->game_has_begun and
|
||||
get: fn(): bool => $this->game_has_begun and
|
||||
$this->game_has_ended and
|
||||
$this->activated_close_page and
|
||||
$this->close_page_active_date->gte(now())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all authorized countries.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getAuthorizedCountries(): \Illuminate\Support\Collection
|
||||
{
|
||||
/** @var \App\Models\Settings $settings */
|
||||
$settings = app(Settings::class);
|
||||
if (count($settings->authorized_countries)) {
|
||||
// * Authorized countries defined in settings.
|
||||
$countries = collect(Country::toArray())
|
||||
->filter(fn($enum) => in_array($enum->value, $settings->authorized_countries));
|
||||
} else {
|
||||
// * Only DROM-COM + France.
|
||||
$franceCountries = collect(Country::getValidCountries())
|
||||
->filter(fn($enum) => !in_array($enum, [Country::belgium(), Country::luxembourg()]));
|
||||
$otherCountries = collect(Country::getValidCountries())
|
||||
->filter(fn($enum) => !$franceCountries->contains($enum));
|
||||
$countries = $franceCountries->merge($otherCountries);
|
||||
}
|
||||
return $countries;
|
||||
}
|
||||
|
||||
// * RELATIONS
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->json('authorized_countries')->after('discounts_campaign')
|
||||
->comment('All countries eligible to participate.');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('authorized_countries');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -30,9 +30,10 @@ class SettingsSeeder extends Seeder
|
|||
$settings->notify_prize_sent = false;
|
||||
$settings->redirect_close = "https://example.test";
|
||||
$settings->discounts_activated = false;
|
||||
$settings->authorized_countries = [];
|
||||
$settings->notification_emails = [];
|
||||
$settings->winning_proof = 0;
|
||||
$settings->web_coupons = [];
|
||||
$settings->winning_proof = 0;
|
||||
$settings->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,17 +220,18 @@ return [
|
|||
'female' => 'of the ',
|
||||
'vowel' => 'of the '
|
||||
],
|
||||
'event' => 'event',
|
||||
'model' => 'target element',
|
||||
'order' => 'order',
|
||||
'publication' => 'publication',
|
||||
'activated' => 'activated',
|
||||
'target' => 'target',
|
||||
'static_page_type' => 'static page type',
|
||||
'seo_title' => 'SEO title',
|
||||
'seo_description' => 'SEO description',
|
||||
'event' => 'event',
|
||||
'model' => 'target element',
|
||||
'order' => 'order',
|
||||
'publication' => 'publication',
|
||||
'activated' => 'activated',
|
||||
'target' => 'target',
|
||||
'static_page_type' => 'static page type',
|
||||
'seo_title' => 'SEO title',
|
||||
'seo_description' => 'SEO description',
|
||||
'authorized_countries' => 'eligible countries at game',
|
||||
|
||||
'postal_code' => 'the :attribute field accepts postal codes from the following
|
||||
'postal_code' => 'the :attribute field accepts postal codes from the following
|
||||
:countries such as :examples',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ return [
|
|||
'mixed' => 'Le champ :attribute doit contenir au moins une majuscule et une minuscule.',
|
||||
'numbers' => 'Le champ :attribute doit contenir au moins un chiffre.',
|
||||
'symbols' => 'Le champ :attribute doit contenir au moins un symbole.',
|
||||
'uncompromised' => 'La valeur du champ :attribute est apparue dans une fuite de données. Veuillez choisir une valeur différente.',
|
||||
'uncompromised' => 'La valeur du champ :attribute est apparue dans une fuite de données.
|
||||
Veuillez choisir une valeur différente.',
|
||||
],
|
||||
'present' => 'Le champ :attribute doit être présent.',
|
||||
'prohibited' => 'Le champ :attribute est interdit.',
|
||||
|
|
@ -274,6 +275,7 @@ return [
|
|||
'game_rules' => 'règlement du jeu',
|
||||
'notify_prize_sent' => 'notification de lot envoyé au participant',
|
||||
'comment' => 'commentaire',
|
||||
'authorized_countries' => 'pays éligibles au jeu',
|
||||
|
||||
'barcode' => 'code-barres du produit',
|
||||
'ticket' => 'ticket de caisse avec la date',
|
||||
|
|
|
|||
261
resources/ts/components/SelectMultipleEnumComponent.vue
Normal file
261
resources/ts/components/SelectMultipleEnumComponent.vue
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
<template>
|
||||
<div class="select-multiple-enum user-select-none row w-100 mx-auto">
|
||||
<div
|
||||
class="col-12 p-0"
|
||||
:class="intSpecificItem ? 'col-md-6' : ''"
|
||||
>
|
||||
<label
|
||||
:for="intName"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ intLabel }} {{ intRequired ? "*" : "" }}</b>
|
||||
</label>
|
||||
<div class="d-inline-block w-100">
|
||||
<VueTagsInputCls
|
||||
v-model="intItem"
|
||||
:tags="intSelectedItem"
|
||||
:autocomplete-items="filteredItems"
|
||||
:autocomplete-min-length="0"
|
||||
@before-adding-tag="beforeTagSave"
|
||||
@tags-changed="changedTags"
|
||||
:max-tags="6"
|
||||
:placeholder="intPlaceholder"
|
||||
/>
|
||||
</div>
|
||||
<template
|
||||
v-for="(sItem, index) in intSelectedItem"
|
||||
:key="index"
|
||||
>
|
||||
<p class="text-danger m-0">
|
||||
{{
|
||||
parseLaravelErrorMessages.methods.parseValidationInput(
|
||||
`${intName}[${String(index)}][name]`,
|
||||
intAllErrors
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<input
|
||||
:name="`${intName}[${String(index)}]`"
|
||||
type="hidden"
|
||||
:value="sItem.id"
|
||||
>
|
||||
</template>
|
||||
<small class="form-text text-muted">{{ intHelper }}</small>
|
||||
</div>
|
||||
<div
|
||||
v-if="intSpecificItem && intShowSpecificItem"
|
||||
class="col-12 col-md-6 mb-3"
|
||||
>
|
||||
<label
|
||||
for="shop"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ intSpecificItem.label }}</b>
|
||||
</label>
|
||||
<p class="text-danger m-0">
|
||||
{{ parseLaravelErrorMessages.methods.parseValidationInput(`${intSpecificItem.name}`, intAllErrors) }}
|
||||
</p>
|
||||
<input
|
||||
class="form-control"
|
||||
:name="intSpecificItem.name"
|
||||
type="text"
|
||||
:placeholder="intSpecificItem.placeholder"
|
||||
>
|
||||
<small class="form-text text-muted">{{ intSpecificItem.helper }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineOptions, onMounted, ref, useAttrs } from "vue";
|
||||
import type VueTagsInput from "@sipec/vue3-tags-input";
|
||||
import { VueTagsInput as VueTagsInputCls } from "@sipec/vue3-tags-input";
|
||||
import slugify from "slugify";
|
||||
import parseLaravelErrorMessages from "./../modules/parseLaravelErrorMessages";
|
||||
|
||||
defineOptions({
|
||||
name: "SelectMultipleEnumComponent"
|
||||
});
|
||||
|
||||
// * ATTRIBUTES
|
||||
const attrs = useAttrs();
|
||||
|
||||
// * DATA
|
||||
const intName = ref<string>("");
|
||||
const intLabel = ref<string>("");
|
||||
const intHelper = ref<string>("");
|
||||
const intItem = ref<string>("");
|
||||
const intSelectedItem = ref<CustomTag[]>([]);
|
||||
const intAllItems = ref<CustomTag[]>([]);
|
||||
const intPlaceholder = ref<string>("");
|
||||
const intItemLimit = ref<number[]>([0, 0]);
|
||||
const intAllErrors = ref<Record<string, string[]>>({});
|
||||
const intSpecificItem = ref<{
|
||||
name: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
showId: number;
|
||||
helper: string;
|
||||
} | null>(null);
|
||||
const intShowSpecificItem = ref<boolean>(false);
|
||||
const intRequired = ref<boolean>(false);
|
||||
|
||||
// * LIFECYCLE
|
||||
onMounted(() => {
|
||||
const json = String(attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
if (!isUsedWithProps.value) {
|
||||
intName.value = data.name;
|
||||
intLabel.value = data.label;
|
||||
intHelper.value = data.helper;
|
||||
intAllItems.value = parseTags(data.itemsList);
|
||||
intSelectedItem.value = parseTags(data.itemsSelected);
|
||||
intPlaceholder.value = data.placeholder;
|
||||
intItemLimit.value = data.itemLimit;
|
||||
intAllErrors.value = data.errors;
|
||||
intSpecificItem.value = data.showSpecificItem;
|
||||
intRequired.value = data.required;
|
||||
}
|
||||
checkSpecificItem();
|
||||
});
|
||||
|
||||
// * COMPUTED
|
||||
const isUsedWithProps = computed<boolean>(() => attrs.json === undefined);
|
||||
const filteredItems = computed(() => {
|
||||
return intAllItems.value.filter((i) => {
|
||||
const label = i.label as string;
|
||||
return label.toLowerCase().indexOf(intItem.value.toLowerCase()) !== -1;
|
||||
});
|
||||
});
|
||||
|
||||
function parseTags(intSelectedItem: CustomTag[]): CustomTag[] {
|
||||
return intSelectedItem.map((intItem: CustomTag) => {
|
||||
if (!intItem.value)
|
||||
intItem = intAllItems.value
|
||||
.filter((intItemEnum) => {
|
||||
return intItemEnum.value === intItem;
|
||||
})
|
||||
.shift() as CustomTag;
|
||||
intItem.id = String(intItem.value);
|
||||
intItem.text = String(intItem.label);
|
||||
return intItem;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item
|
||||
* @param obj
|
||||
*/
|
||||
function beforeTagSave(obj: VueTagsInput.IAddArgs): void {
|
||||
if (intSelectedItem.value.length < intItemLimit.value[1]) {
|
||||
let customTag = tagExists(intAllItems.value, obj.tag);
|
||||
if (customTag) {
|
||||
obj.tag = customTag as unknown as VueTagsInput.ITag;
|
||||
intSelectedItem.value.push(customTag);
|
||||
intItem.value = "";
|
||||
checkSpecificItem();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specific item must be shown.
|
||||
* @param newItem
|
||||
*/
|
||||
function checkSpecificItem(): void {
|
||||
if (intSpecificItem.value) {
|
||||
intSelectedItem.value.some((item) => {
|
||||
return item.value == String(intSpecificItem.value?.showId);
|
||||
})
|
||||
? (intShowSpecificItem.value = true)
|
||||
: (intShowSpecificItem.value = false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete item.
|
||||
* @param newItem
|
||||
*/
|
||||
function changedTags(newItem: CustomTag[]): void {
|
||||
intSelectedItem.value = newItem as CustomTag[];
|
||||
checkSpecificItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the tag exist.
|
||||
* @param newItem
|
||||
*/
|
||||
function tagExists(
|
||||
items: CustomTag[],
|
||||
tagToCheck: VueTagsInput.ITag
|
||||
): CustomTag | null {
|
||||
let customTag: CustomTag | null = null;
|
||||
items.filter((intItem: CustomTag) => {
|
||||
if (
|
||||
intItem.value === (tagToCheck as unknown as CustomTag).value ||
|
||||
intItem.label === slugify(tagToCheck.text)
|
||||
) {
|
||||
customTag = intItem;
|
||||
}
|
||||
});
|
||||
return customTag;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.select-multiple-enum {
|
||||
max-width: 100% !important;
|
||||
|
||||
.vue-tags-input {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.ti- {
|
||||
&autocomplete {
|
||||
max-height: 10rem !important;
|
||||
border-radius: 0.375rem;
|
||||
box-shadow: 0 0 4px var(--bs-gray-400);
|
||||
overflow-y: auto !important;
|
||||
|
||||
ul {
|
||||
padding: 0.25rem 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&input {
|
||||
padding: 0.375rem !important;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
&tags {
|
||||
line-height: inherit !important;
|
||||
}
|
||||
|
||||
&tag,
|
||||
&new-tag-input-wrapper {
|
||||
padding: 0.1rem !important;
|
||||
margin: 0.1rem !important;
|
||||
}
|
||||
|
||||
&new-tag-input-wrapper {
|
||||
font-size: 1em !important;
|
||||
|
||||
input {
|
||||
min-width: 17rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&tag {
|
||||
padding: 0.1rem 0.3rem !important;
|
||||
background-color: #0d6efd !important;
|
||||
border-radius: 0.375rem !important;
|
||||
}
|
||||
|
||||
&selected-item {
|
||||
background-color: var(--bs-gray-300) !important;
|
||||
color: var(--bs-gray-900) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -134,6 +134,27 @@
|
|||
{{-- Force next columns to break to new line --}}
|
||||
<div class="w-100"></div>
|
||||
|
||||
{{-- AUTHORIZED_COUNTRIES --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border p-3">
|
||||
<legend>{{ str(__('validation.custom.authorized_countries'))->ucfirst() }}</legend>
|
||||
<div>
|
||||
@php $itemsList = collect(\LDC\LDCCRM\Enums\Country::getValidCountries())->values(); @endphp
|
||||
@include('back::partials.inputs.select-multiple-enum', [
|
||||
'name' => 'authorized_countries',
|
||||
'label' => str(__('validation.custom.authorized_countries'))->ucfirst(),
|
||||
'placeholder' => str(__('rechercher parmi les :field', ['field' => __('validation.custom.authorized_countries')]))->ucfirst(),
|
||||
'model' => $settingsModel ?? null,
|
||||
'itemsList' => $itemsList,
|
||||
'itemLimit' => [0, count($itemsList)],
|
||||
'helper' => sprintf('%s %s', __('crud.minicrud.enum_select', [
|
||||
'enum' => str(__('validation.custom.authorized_countries'))->ucfirst(),
|
||||
]), __('Laisser vide afin de ne pas appliquer de restrictions.')),
|
||||
'required' => false,
|
||||
])
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- NB_PARTICIPATION_PLAYER --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="h-100 border p-3">
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
@php
|
||||
$data = [
|
||||
"name" => $name,
|
||||
"label" => $label,
|
||||
"value" => $value ?? [],
|
||||
"placeholder" => $placeholder,
|
||||
"itemsSelected" => $itemsSelected,
|
||||
"itemsList" => $itemsList,
|
||||
"itemLimit" => $itemLimit,
|
||||
"showSpecificItem" => $showSpecificItem ?? null,
|
||||
"errors" => $errors->getBag("default")->getMessages() ?? [],
|
||||
'helper' => $helper,
|
||||
'require' => $require
|
||||
];
|
||||
$values = collect(old($name, $model->{$name} ?? []))->values();
|
||||
$itemsSelected = collect($itemsList)
|
||||
->filter(fn($item) => $values->filter(fn($value) => intval($value) === $item->value)->count())
|
||||
->values();
|
||||
$data = [
|
||||
"name" => $name,
|
||||
"label" => $label,
|
||||
"placeholder" => $placeholder,
|
||||
"itemsSelected" => $itemsSelected,
|
||||
"itemsList" => $itemsList,
|
||||
"itemLimit" => $itemLimit,
|
||||
"showSpecificItem" => $showSpecificItem ?? null,
|
||||
"errors" => $errors->getBag("default")->getMessages() ?? [],
|
||||
'helper' => $helper,
|
||||
'required' => $required
|
||||
];
|
||||
@endphp
|
||||
<div class="select-multiple-enum" data-json='@json($data)'></div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue