feat(onticket): add immersive hero configuration and carousel, update tenant seeder and tests

This commit is contained in:
2026-09-18 09:39:25 -03:00
parent 164187f47b
commit 49be167029
12 changed files with 524 additions and 32 deletions

View File

@@ -0,0 +1,93 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
DB::transaction(function (): void {
$now = now();
DB::table('storefront_website_types')->updateOrInsert(
['codigo' => 'onticket_multi_event'],
[
'nombre' => 'OnTicket - múltiples eventos',
'header_type' => 'immersive',
'updated_at' => $now,
] + (DB::table('storefront_website_types')->where('codigo', 'onticket_multi_event')->exists()
? []
: ['created_at' => $now]),
);
$extraKey = [
'storefront_website_type_code' => 'onticket_multi_event',
'codigo' => 'immersiveHero',
];
DB::table('storefront_website_type_extras')->updateOrInsert(
$extraKey,
[
'nombre' => 'Textos del hero inmersivo',
'descripcion' => 'Frase superior, título y descripción de la portada.',
'is_required' => false,
'config_schema' => json_encode([
'request_rules' => [
'$' => 'required|array:eyebrow,title,description',
'eyebrow' => 'required|string|max:120',
'title' => 'required|string|max:120',
'description' => 'required|string|max:255',
],
'transforms' => [],
], JSON_THROW_ON_ERROR),
'updated_at' => $now,
] + (DB::table('storefront_website_type_extras')->where($extraKey)->exists()
? []
: ['created_at' => $now]),
);
$tenant = DB::table('tenants')
->where('codigo', 'onticket')
->whereIn('storefront_website_type_code', ['onticket', 'onticket_multi_event'])
->first(['codigo']);
if ($tenant === null) {
return;
}
DB::table('tenants')->where('codigo', $tenant->codigo)->update([
'storefront_website_type_code' => 'onticket_multi_event',
'display_seach_bar' => true,
'updated_at' => $now,
]);
$extraId = DB::table('storefront_website_type_extras')
->where($extraKey)
->value('id');
if (! DB::table('websites_extras')
->where('website_code', $tenant->codigo)
->where('website_type_extra_id', $extraId)
->exists()) {
DB::table('websites_extras')->insert([
'website_code' => $tenant->codigo,
'website_type_extra_id' => $extraId,
'config' => json_encode([
'eyebrow' => 'Encendé tu',
'title' => 'experiencia',
'description' => 'Reservá tu entrada y formá parte',
], JSON_THROW_ON_ERROR),
'is_enabled' => true,
'created_at' => $now,
'updated_at' => $now,
]);
}
});
}
public function down(): void
{
// This data change is intentionally retained to avoid removing tenant edits.
}
};

View File

@@ -0,0 +1,53 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
$key = ['storefront_website_type_code' => 'onticket_multi_event'];
$definitions = DB::table('storefront_website_type_extras')->where($key);
if ((clone $definitions)->where('codigo', 'immersiveHeroCarousel')->exists()) {
return;
}
if ((clone $definitions)->where('codigo', 'heroCarousel')->exists()) {
(clone $definitions)->where('codigo', 'heroCarousel')->update([
'codigo' => 'immersiveHeroCarousel',
'updated_at' => now(),
]);
return;
}
DB::table('storefront_website_type_extras')->insert([
...$key,
'codigo' => 'immersiveHeroCarousel',
'nombre' => 'Carrusel del hero',
'descripcion' => 'Lista ordenada de imágenes del hero.',
'is_required' => false,
'config_schema' => json_encode([
'request_rules' => [
'$' => 'required|array|max:10',
'$.*' => 'required|image_or_base64|distinct',
],
'transforms' => [
'$.*' => [
'handler' => 'attachment',
'attachment_type' => 'image',
],
],
], JSON_THROW_ON_ERROR),
'created_at' => now(),
'updated_at' => now(),
]);
}
public function down(): void
{
// Preserve configured images and tenant edits.
}
};

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
if (! DB::table('tenants')->where('codigo', 'onticket')->exists()) {
return;
}
DB::transaction(function (): void {
$now = now();
foreach (['Música', 'Teatro', 'Deportes', 'Infantiles', 'Otros'] as $nombre) {
$category = ['tenant_code' => 'onticket', 'nombre' => $nombre];
if (! DB::table('categorias')->where($category)->exists()) {
DB::table('categorias')->insert($category + [
'is_enabled' => true,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
});
}
public function down(): void
{
// Retain categories because they may have been edited or assigned to products.
}
};

View File

@@ -13,6 +13,17 @@ class CategorySeeder extends Seeder
*/
public function run(): void
{
$onTicket = Tenant::query()->where('codigo', 'onticket')->first();
if ($onTicket instanceof Tenant) {
foreach (['Música', 'Teatro', 'Deportes', 'Infantiles', 'Otros'] as $nombre) {
Category::firstOrCreate([
'nombre' => $nombre,
'tenant_code' => $onTicket->codigo,
]);
}
}
$tenant = Tenant::query()->where('codigo', 'sonder')->first();
if (! $tenant instanceof Tenant) {

View File

@@ -0,0 +1,59 @@
<?php
namespace Database\Seeders;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Services\WebsiteExtraService;
use Illuminate\Database\Seeder;
use Illuminate\Http\UploadedFile;
use RuntimeException;
class OnticketImmersiveHeroCarouselSeeder extends Seeder
{
private const IMAGES = [
'onticket_hero_carousel_1.png',
'onticket_hero_carousel_2.png',
'onticket_hero_carousel_3.avif',
'onticket_hero_carousel_4.jfif',
'onticket_hero_carousel_5.jfif',
'onticket_hero_carousel_6.jfif',
'onticket_hero_carousel_7.avif',
'onticket_hero_carousel_8.avif',
];
public function __construct(private readonly WebsiteExtraService $websiteExtraService) {}
public function run(): void
{
$tenant = Tenant::query()->where('codigo', 'onticket')->first();
if ($tenant?->storefront_website_type_code !== 'onticket_multi_event') {
return;
}
if ($tenant->websiteExtras()->whereHas(
'websiteTypeExtra',
fn ($query) => $query->where('codigo', 'immersiveHeroCarousel')
)->exists()) {
return;
}
$images = array_map(function (string $filename): UploadedFile {
$path = public_path("images/tennants/onticket/onticket_tennant_hero_carousel/{$filename}");
if (! is_file($path)) {
throw new RuntimeException("Image not found at path: {$path}");
}
$mimeType = match (strtolower(pathinfo($filename, PATHINFO_EXTENSION))) {
'jpg', 'jpeg', 'jfif' => 'image/jpeg',
'avif' => 'image/avif',
default => 'image/png',
};
return new UploadedFile($path, $filename, $mimeType, null, true);
}, self::IMAGES);
$this->websiteExtraService->updateForTenant($tenant, 'immersiveHeroCarousel', $images);
}
}

View File

@@ -20,17 +20,6 @@ class TenantSeeder extends Seeder
private const SONDER_CLIENT_CODE = 'sonder';
private const ONTICKET_HERO_CAROUSEL_IMAGES = [
'onticket_hero_carousel_1.png',
'onticket_hero_carousel_2.png',
'onticket_hero_carousel_3.avif',
'onticket_hero_carousel_4.jfif',
'onticket_hero_carousel_5.jfif',
'onticket_hero_carousel_6.jfif',
'onticket_hero_carousel_7.avif',
'onticket_hero_carousel_8.avif',
];
private const SOCIAL_MEDIA = [
[
'code' => 'instagram',
@@ -89,7 +78,7 @@ class TenantSeeder extends Seeder
'header_bg_color' => $onTicketType->surface_color,
'footer_bg_color' => $onTicketType->surface_color,
'display_categories' => false,
'display_seach_bar' => false,
'display_seach_bar' => true,
'admin_website_type_code' => $onTicketType->codigo,
'storefront_website_type_code' => 'onticket_multi_event',
'header_logo' => $this->uploadedImage(
@@ -124,23 +113,23 @@ class TenantSeeder extends Seeder
$onTicketTenant = Tenant::query()->where('codigo', 'onticket')->firstOrFail();
if ($onTicketTenant->storefront_website_type_code === 'onticket_multi_event' && ! $onTicketTenant->display_seach_bar) {
$onTicketTenant->update(['display_seach_bar' => true]);
}
if (
$onTicketTenant->storefront_website_type_code === 'onticket_multi_event'
&& ! $onTicketTenant->websiteExtras()->whereHas('websiteTypeExtra', fn ($query) => $query->where('codigo', 'heroCarousel'))->exists()
&& ! $onTicketTenant->websiteExtras()->whereHas('websiteTypeExtra', fn ($query) => $query->where('codigo', 'immersiveHero'))->exists()
) {
$this->websiteExtraService->updateForTenant(
$onTicketTenant,
'heroCarousel',
array_map(
fn (string $filename): UploadedFile => $this->uploadedImage(
"images/tennants/onticket/onticket_tennant_hero_carousel/{$filename}",
$filename,
),
self::ONTICKET_HERO_CAROUSEL_IMAGES,
),
);
$this->websiteExtraService->updateForTenant($onTicketTenant, 'immersiveHero', [
'eyebrow' => 'Encendé tu',
'title' => 'experiencia',
'description' => 'Reservá tu entrada y formá parte',
]);
}
$this->call(OnticketImmersiveHeroCarouselSeeder::class);
$this->deleteTenant('sonder');
Tenant::query()

View File

@@ -94,7 +94,7 @@ class WebsiteTypeSeeder extends Seeder
);
$multiEventStorefront->extras()->updateOrCreate(
['codigo' => 'heroCarousel'],
['codigo' => 'immersiveHeroCarousel'],
[
'nombre' => 'Carrusel del hero',
'descripcion' => 'Lista ordenada de imágenes del hero.',
@@ -103,6 +103,24 @@ class WebsiteTypeSeeder extends Seeder
],
);
$multiEventStorefront->extras()->updateOrCreate(
['codigo' => 'immersiveHero'],
[
'nombre' => 'Textos del hero inmersivo',
'descripcion' => 'Frase superior, título y descripción de la portada.',
'is_required' => false,
'config_schema' => [
'request_rules' => [
'$' => 'required|array:eyebrow,title,description',
'eyebrow' => 'required|string|max:120',
'title' => 'required|string|max:120',
'description' => 'required|string|max:255',
],
'transforms' => [],
],
],
);
$onTicketStorefront->extras()->updateOrCreate(
['codigo' => 'heroConfig'],
[