Deploy Ladill Events / deploy (push) Successful in 1m39s
Upload logo in account settings and prefer it over Ladill product marks in event notification headers. Co-authored-by: Cursor <cursoragent@cursor.com>
178 lines
5.6 KiB
PHP
178 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Support\Qr\QrStyleDefaults;
|
|
use App\Support\Qr\QrTypeCatalog;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/** Per-account Ladill Events preferences (notifications, event defaults, QR style). */
|
|
class QrSetting extends Model
|
|
{
|
|
protected $fillable = [
|
|
'user_id',
|
|
'notify_email',
|
|
'product_updates',
|
|
'low_balance_alerts',
|
|
'notify_registrations',
|
|
'notify_payouts',
|
|
'default_type',
|
|
'default_style',
|
|
'event_defaults',
|
|
'logo_path',
|
|
];
|
|
|
|
protected $casts = [
|
|
'product_updates' => 'boolean',
|
|
'low_balance_alerts' => 'boolean',
|
|
'notify_registrations' => 'boolean',
|
|
'notify_payouts' => 'boolean',
|
|
'default_style' => 'array',
|
|
'event_defaults' => 'array',
|
|
];
|
|
|
|
/** @return list<string> */
|
|
public static function storableEventDefaultKeys(): array
|
|
{
|
|
return [
|
|
'currency',
|
|
'mode',
|
|
'badge_size',
|
|
'brand_color',
|
|
'organizer',
|
|
'registration_open',
|
|
'badge_fields',
|
|
'format',
|
|
];
|
|
}
|
|
|
|
/** @return list<string> */
|
|
public static function storableStyleKeys(): array
|
|
{
|
|
return [
|
|
'foreground',
|
|
'background',
|
|
'error_correction',
|
|
'margin',
|
|
'module_style',
|
|
'finder_outer',
|
|
'finder_inner',
|
|
'frame_style',
|
|
'frame_text',
|
|
'frame_color',
|
|
'gradient_type',
|
|
'gradient_color1',
|
|
'gradient_color2',
|
|
'gradient_rotation',
|
|
];
|
|
}
|
|
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
public function resolvedDefaultType(): string
|
|
{
|
|
$type = (string) ($this->default_type ?? QrCode::TYPE_EVENT);
|
|
|
|
return in_array($type, QrTypeCatalog::eventsTypes(), true) ? $type : QrCode::TYPE_EVENT;
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
public function resolvedEventDefaults(): array
|
|
{
|
|
$defaults = [
|
|
'currency' => 'GHS',
|
|
'mode' => 'ticketing',
|
|
'badge_size' => '4x3',
|
|
'brand_color' => '#4f46e5',
|
|
'organizer' => '',
|
|
'registration_open' => true,
|
|
'badge_fields' => ['Company', 'Role'],
|
|
];
|
|
|
|
$stored = collect($this->event_defaults ?? [])
|
|
->only(self::storableEventDefaultKeys())
|
|
->filter(fn ($value) => $value !== null && $value !== '')
|
|
->all();
|
|
|
|
if (isset($stored['badge_fields']) && is_array($stored['badge_fields'])) {
|
|
$stored['badge_fields'] = array_values(array_filter(
|
|
array_map('strval', $stored['badge_fields']),
|
|
fn (string $field) => trim($field) !== '',
|
|
));
|
|
if ($stored['badge_fields'] === []) {
|
|
unset($stored['badge_fields']);
|
|
}
|
|
}
|
|
|
|
return array_merge($defaults, $stored);
|
|
}
|
|
|
|
/** @param array<string, mixed>|null $input */
|
|
public static function sanitizeEventDefaults(?array $input): ?array
|
|
{
|
|
if ($input === null) {
|
|
return null;
|
|
}
|
|
|
|
$allowedModes = ['ticketing', 'contributions', 'free'];
|
|
$allowedSizes = ['4x3', '4x6', 'cr80'];
|
|
$allowedCurrencies = ['GHS', 'USD', 'NGN', 'KES'];
|
|
|
|
$mode = (string) ($input['mode'] ?? 'ticketing');
|
|
$badgeSize = (string) ($input['badge_size'] ?? '4x3');
|
|
$currency = strtoupper(trim((string) ($input['currency'] ?? 'GHS')));
|
|
|
|
$badgeFields = array_values(array_filter(
|
|
array_map(fn ($field) => mb_substr(trim((string) $field), 0, 40), (array) ($input['badge_fields'] ?? [])),
|
|
fn (string $field) => $field !== '',
|
|
));
|
|
|
|
$brandColor = (string) ($input['brand_color'] ?? '#4f46e5');
|
|
if (! preg_match('/^#[0-9a-fA-F]{6}$/', $brandColor)) {
|
|
$brandColor = '#4f46e5';
|
|
}
|
|
|
|
return [
|
|
'currency' => in_array($currency, $allowedCurrencies, true) ? $currency : 'GHS',
|
|
'mode' => in_array($mode, $allowedModes, true) ? $mode : 'ticketing',
|
|
'badge_size' => in_array($badgeSize, $allowedSizes, true) ? $badgeSize : '4x3',
|
|
'brand_color' => $brandColor,
|
|
'organizer' => mb_substr(trim((string) ($input['organizer'] ?? '')), 0, 120),
|
|
'registration_open' => filter_var($input['registration_open'] ?? true, FILTER_VALIDATE_BOOL),
|
|
'badge_fields' => $badgeFields !== [] ? $badgeFields : ['Company', 'Role'],
|
|
'format' => in_array($input['format'] ?? 'in_person', ['in_person', 'virtual', 'hybrid'], true)
|
|
? ($input['format'] ?? 'in_person')
|
|
: 'in_person',
|
|
];
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
public function resolvedDefaultStyle(): array
|
|
{
|
|
$stored = collect($this->default_style ?? [])
|
|
->only(self::storableStyleKeys())
|
|
->filter(fn ($value) => $value !== null && $value !== '')
|
|
->all();
|
|
|
|
return QrStyleDefaults::merge($stored !== [] ? $stored : null);
|
|
}
|
|
|
|
/** @param array<string, mixed>|null $input */
|
|
public static function sanitizeDefaultStyle(?array $input): ?array
|
|
{
|
|
if ($input === null) {
|
|
return null;
|
|
}
|
|
|
|
$merged = QrStyleDefaults::merge(
|
|
collect($input)->only(self::storableStyleKeys())->all(),
|
|
);
|
|
|
|
return collect($merged)->only(self::storableStyleKeys())->all();
|
|
}
|
|
}
|