diff --git a/app/Domains/Tenant/Models/WebsiteType.php b/app/Domains/Tenant/Models/WebsiteType.php index c92840b..b8376f5 100644 --- a/app/Domains/Tenant/Models/WebsiteType.php +++ b/app/Domains/Tenant/Models/WebsiteType.php @@ -17,6 +17,12 @@ use Illuminate\Database\Eloquent\Relations\HasMany; 'secondary_color', 'danger_color', 'success_color', + 'warning_color', + 'body_color', + 'darker_body_color', + 'surface_color', + 'background_color', + 'border_color', 'login_header_footer_color', 'site_logo', ])] diff --git a/app/Domains/Tenant/Services/WebsiteTypeService.php b/app/Domains/Tenant/Services/WebsiteTypeService.php index cc0a49e..3ed20f7 100644 --- a/app/Domains/Tenant/Services/WebsiteTypeService.php +++ b/app/Domains/Tenant/Services/WebsiteTypeService.php @@ -21,27 +21,58 @@ class WebsiteTypeService */ public function create(array $data): WebsiteType { - return DB::transaction(function () use ($data): WebsiteType { + return $this->save(new WebsiteType, $data); + } + + /** + * Create or update a website type and replace its site logo when provided. + * + * @param array $attributes + * @param array $values + */ + public function updateOrCreate(array $attributes, array $values = []): WebsiteType + { + /** @var WebsiteType $websiteType */ + $websiteType = WebsiteType::query()->firstOrNew($attributes); + + return $this->save($websiteType, [...$attributes, ...$values]); + } + + /** + * @param array $data + */ + private function save(WebsiteType $websiteType, array $data): WebsiteType + { + return DB::transaction(function () use ($websiteType, $data): WebsiteType { + $hasSiteLogo = array_key_exists('site_logo', $data); $siteLogo = $data['site_logo'] ?? null; + $previousSiteLogo = $websiteType->exists + ? $websiteType->siteLogo()->first() + : null; unset($data['site_logo']); - $siteLogoAttachmentId = null; + if ($hasSiteLogo) { + $attachment = null; - if ($siteLogo) { - $attachment = Str::isUuid($siteLogo) - ? Attachment::query()->where('key', $siteLogo)->first() - : $this->attachmentService->store($siteLogo, 'website-types'); - - if ($attachment) { - $siteLogoAttachmentId = $attachment->id; + if ($siteLogo) { + $attachment = is_string($siteLogo) && Str::isUuid($siteLogo) + ? Attachment::query()->where('key', $siteLogo)->first() + : $this->attachmentService->store($siteLogo, 'website-types'); } + + $data['site_logo'] = $attachment?->id; } - $data['site_logo'] = $siteLogoAttachmentId; + $websiteType->fill($data)->save(); - /** @var WebsiteType $websiteType */ - $websiteType = WebsiteType::query()->create($data); + if ( + $hasSiteLogo + && $previousSiteLogo instanceof Attachment + && $previousSiteLogo->id !== $websiteType->site_logo + ) { + $this->attachmentService->delete($previousSiteLogo); + } return $websiteType; }); diff --git a/database/migrations/2026_07_31_000500_add_presentation_fields_to_website_type_table.php b/database/migrations/2026_07_31_000500_add_presentation_fields_to_website_type_table.php index 7c26500..e63baf4 100644 --- a/database/migrations/2026_07_31_000500_add_presentation_fields_to_website_type_table.php +++ b/database/migrations/2026_07_31_000500_add_presentation_fields_to_website_type_table.php @@ -14,7 +14,13 @@ return new class extends Migration $table->string('secondary_color')->nullable()->after('primary_color'); $table->string('danger_color')->nullable()->after('secondary_color'); $table->string('success_color')->nullable()->after('danger_color'); - $table->string('login_header_footer_color')->nullable()->after('success_color'); + $table->string('warning_color')->nullable()->after('success_color'); + $table->string('body_color')->nullable()->after('warning_color'); + $table->string('darker_body_color')->nullable()->after('body_color'); + $table->string('surface_color')->nullable()->after('darker_body_color'); + $table->string('background_color')->nullable()->after('surface_color'); + $table->string('border_color')->nullable()->after('background_color'); + $table->string('login_header_footer_color')->nullable()->after('border_color'); $table->unsignedBigInteger('site_logo')->nullable()->after('login_header_footer_color'); $table->foreign('site_logo') @@ -37,6 +43,12 @@ return new class extends Migration 'secondary_color', 'danger_color', 'success_color', + 'warning_color', + 'body_color', + 'darker_body_color', + 'surface_color', + 'background_color', + 'border_color', 'login_header_footer_color', 'site_logo', ]); diff --git a/database/seeders/WebsiteTypeSeeder.php b/database/seeders/WebsiteTypeSeeder.php index 489446c..c1e75ec 100644 --- a/database/seeders/WebsiteTypeSeeder.php +++ b/database/seeders/WebsiteTypeSeeder.php @@ -2,16 +2,37 @@ namespace Database\Seeders; -use App\Domains\Tenant\Models\WebsiteType; +use App\Domains\Tenant\Services\WebsiteTypeService; use Illuminate\Database\Seeder; +use Illuminate\Http\UploadedFile; +use RuntimeException; class WebsiteTypeSeeder extends Seeder { + private const PRESENTATION = [ + 'primary_color' => '#FF7006', + 'secondary_color' => '#777777', + 'danger_color' => '#E04A4A', + 'success_color' => '#81BC73', + 'warning_color' => '#81BC73', + 'body_color' => '#666666', + 'darker_body_color' => '#333333', + 'surface_color' => '#ffffff', + 'background_color' => '#f8f8f8', + 'border_color' => '#f8f8f8', + ]; + + public function __construct(private readonly WebsiteTypeService $websiteTypeService) {} + public function run(): void { - $shopIt = WebsiteType::query()->updateOrCreate( + $shopIt = $this->websiteTypeService->updateOrCreate( ['codigo' => 'shopit'], - ['nombre' => 'ShopIt'], + [ + 'nombre' => 'ShopIt', + ...self::PRESENTATION, + 'site_logo' => $this->onTicketLogo(), + ], ); $shopIt->extras()->updateOrCreate( @@ -35,9 +56,13 @@ class WebsiteTypeSeeder extends Seeder ], ); - $onTicket = WebsiteType::query()->updateOrCreate( + $onTicket = $this->websiteTypeService->updateOrCreate( ['codigo' => 'onticket'], - ['nombre' => 'OnTicket'], + [ + 'nombre' => 'OnTicket', + ...self::PRESENTATION, + 'site_logo' => $this->onTicketLogo(), + ], ); $onTicket->extras()->updateOrCreate( @@ -85,4 +110,21 @@ class WebsiteTypeSeeder extends Seeder ], ); } + + private function onTicketLogo(): UploadedFile + { + $path = public_path('images/website_types/shopit_logo.png'); + + if (! file_exists($path)) { + throw new RuntimeException("OnTicket logo not found at path: {$path}"); + } + + return new UploadedFile( + $path, + 'onticket_logo.png', + 'image/png', + null, + true, + ); + } } diff --git a/tests/Feature/Seeders/WebsiteTypeSeederTest.php b/tests/Feature/Seeders/WebsiteTypeSeederTest.php index 2d39e9f..54c2132 100644 --- a/tests/Feature/Seeders/WebsiteTypeSeederTest.php +++ b/tests/Feature/Seeders/WebsiteTypeSeederTest.php @@ -2,9 +2,11 @@ namespace Tests\Feature\Seeders; +use App\Domains\Attachable\Models\Attachment; use App\Domains\Tenant\Models\WebsiteType; use Database\Seeders\WebsiteTypeSeeder; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Storage; use Tests\TestCase; class WebsiteTypeSeederTest extends TestCase @@ -13,10 +15,26 @@ class WebsiteTypeSeederTest extends TestCase public function test_it_seeds_website_types_and_their_config_schemas_idempotently(): void { + Storage::fake('s3'); + $this->seed(WebsiteTypeSeeder::class); $this->seed(WebsiteTypeSeeder::class); $this->assertSame(2, WebsiteType::query()->count()); + $this->assertSame(2, Attachment::query()->count()); + + $expectedPresentation = [ + 'primary_color' => '#FF7006', + 'secondary_color' => '#777777', + 'danger_color' => '#E04A4A', + 'success_color' => '#81BC73', + 'warning_color' => '#81BC73', + 'body_color' => '#666666', + 'darker_body_color' => '#333333', + 'surface_color' => '#ffffff', + 'background_color' => '#f8f8f8', + 'border_color' => '#f8f8f8', + ]; $shopIt = WebsiteType::query() ->where('codigo', 'shopit') @@ -24,6 +42,9 @@ class WebsiteTypeSeederTest extends TestCase ->sole(); $this->assertSame('ShopIt', $shopIt->nombre); + $this->assertSame($expectedPresentation, $shopIt->only(array_keys($expectedPresentation))); + $this->assertSame('onticket_logo.png', $shopIt->siteLogo->filename); + Storage::disk('s3')->assertExists($shopIt->siteLogo->path); $this->assertSame(['carousel'], $shopIt->extras->pluck('codigo')->all()); $this->assertSame('Carrusel principal', $shopIt->extras->sole()->nombre); $this->assertSame([ @@ -45,6 +66,10 @@ class WebsiteTypeSeederTest extends TestCase ->sole(); $this->assertSame('OnTicket', $onTicket->nombre); + $this->assertSame($expectedPresentation, $onTicket->only(array_keys($expectedPresentation))); + $this->assertSame('onticket_logo.png', $onTicket->siteLogo->filename); + Storage::disk('s3')->assertExists($onTicket->siteLogo->path); + $this->assertNotSame($shopIt->site_logo, $onTicket->site_logo); $this->assertEqualsCanonicalizing( ['heroConfig', 'eventConfig'], $onTicket->extras->pluck('codigo')->all(), diff --git a/tests/Feature/Tenant/WebsiteExtrasTest.php b/tests/Feature/Tenant/WebsiteExtrasTest.php index 00c7e8d..2ab0c6b 100644 --- a/tests/Feature/Tenant/WebsiteExtrasTest.php +++ b/tests/Feature/Tenant/WebsiteExtrasTest.php @@ -27,6 +27,12 @@ class WebsiteExtrasTest extends TestCase 'secondary_color', 'danger_color', 'success_color', + 'warning_color', + 'body_color', + 'darker_body_color', + 'surface_color', + 'background_color', + 'border_color', 'login_header_footer_color', 'site_logo', 'created_at', @@ -73,6 +79,12 @@ class WebsiteExtrasTest extends TestCase 'secondary_color' => '#222222', 'danger_color' => '#ff0000', 'success_color' => '#00aa55', + 'warning_color' => '#ffaa00', + 'body_color' => '#666666', + 'darker_body_color' => '#333333', + 'surface_color' => '#ffffff', + 'background_color' => '#f8f8f8', + 'border_color' => '#dddddd', 'login_header_footer_color' => '#333333', 'site_logo' => $siteLogo->id, ]); @@ -100,6 +112,12 @@ class WebsiteExtrasTest extends TestCase $this->assertSame('#222222', $type->secondary_color); $this->assertSame('#ff0000', $type->danger_color); $this->assertSame('#00aa55', $type->success_color); + $this->assertSame('#ffaa00', $type->warning_color); + $this->assertSame('#666666', $type->body_color); + $this->assertSame('#333333', $type->darker_body_color); + $this->assertSame('#ffffff', $type->surface_color); + $this->assertSame('#f8f8f8', $type->background_color); + $this->assertSame('#dddddd', $type->border_color); $this->assertSame('#333333', $type->login_header_footer_color); $this->assertTrue($type->siteLogo()->firstOrFail()->is($siteLogo)); $this->assertSame($type->codigo, $typeExtra->website_type_code); diff --git a/tests/Feature/Tenant/WebsiteTypeServiceTest.php b/tests/Feature/Tenant/WebsiteTypeServiceTest.php index 5c99aae..ea3edd4 100644 --- a/tests/Feature/Tenant/WebsiteTypeServiceTest.php +++ b/tests/Feature/Tenant/WebsiteTypeServiceTest.php @@ -24,6 +24,12 @@ class WebsiteTypeServiceTest extends TestCase 'secondary_color' => '#222222', 'danger_color' => '#ff0000', 'success_color' => '#00aa55', + 'warning_color' => '#ffaa00', + 'body_color' => '#666666', + 'darker_body_color' => '#333333', + 'surface_color' => '#ffffff', + 'background_color' => '#f8f8f8', + 'border_color' => '#dddddd', 'login_header_footer_color' => '#333333', 'site_logo' => UploadedFile::fake()->image('site-logo.png'), ]); @@ -37,6 +43,12 @@ class WebsiteTypeServiceTest extends TestCase $this->assertDatabaseHas('website_type', [ 'codigo' => 'marketplace', 'dominio' => 'marketplace.test', + 'warning_color' => '#ffaa00', + 'body_color' => '#666666', + 'darker_body_color' => '#333333', + 'surface_color' => '#ffffff', + 'background_color' => '#f8f8f8', + 'border_color' => '#dddddd', 'login_header_footer_color' => '#333333', 'site_logo' => $siteLogo->id, ]);