2 Commits

43 changed files with 187 additions and 13 deletions

View File

@@ -2,14 +2,21 @@
namespace App\Domains\Tenant\Models;
use App\Domains\Attachable\Models\Attachment;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable([
'codigo',
'nombre',
'primary_color',
'secondary_color',
'danger_color',
'success_color',
'site_logo',
])]
class WebsiteType extends Model
{
@@ -17,6 +24,14 @@ class WebsiteType extends Model
protected $table = 'website_type';
/**
* @return BelongsTo<Attachment, $this>
*/
public function siteLogo(): BelongsTo
{
return $this->belongsTo(Attachment::class, 'site_logo');
}
/**
* @return HasMany<WebsiteTypeExtra, $this>
*/

View File

@@ -37,6 +37,11 @@ class TenantResource extends JsonResource
fn () => $this->websiteType ? [
'codigo' => $this->websiteType->codigo,
'nombre' => $this->websiteType->nombre,
'primary_color' => $this->websiteType->primary_color,
'secondary_color' => $this->websiteType->secondary_color,
'danger_color' => $this->websiteType->danger_color,
'success_color' => $this->websiteType->success_color,
'site_logo' => $this->websiteType->siteLogo?->getTemporaryUrl(1440),
] : null
),
'extras' => $this->whenLoaded(

View File

@@ -14,7 +14,7 @@ class TenantInformationService
'headerLogo',
'footerLogo',
'socialMedia',
'websiteType',
'websiteType.siteLogo',
'websiteExtras.websiteTypeExtra',
];

View File

@@ -0,0 +1,49 @@
<?php
namespace App\Domains\Tenant\Services;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Attachable\Services\AttachmentService;
use App\Domains\Tenant\Models\WebsiteType;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class WebsiteTypeService
{
public function __construct(
protected AttachmentService $attachmentService,
) {}
/**
* Create a website type and store its site logo.
*
* @param array<string, mixed> $data
*/
public function create(array $data): WebsiteType
{
return DB::transaction(function () use ($data): WebsiteType {
$siteLogo = $data['site_logo'] ?? null;
unset($data['site_logo']);
$siteLogoAttachmentId = null;
if ($siteLogo) {
$attachment = Str::isUuid($siteLogo)
? Attachment::query()->where('key', $siteLogo)->first()
: $this->attachmentService->store($siteLogo, 'website-types');
if ($attachment) {
$siteLogoAttachmentId = $attachment->id;
}
}
$data['site_logo'] = $siteLogoAttachmentId;
/** @var WebsiteType $websiteType */
$websiteType = WebsiteType::query()->create($data);
return $websiteType;
});
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('website_type', function (Blueprint $table): void {
$table->string('primary_color')->nullable()->after('nombre');
$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->unsignedBigInteger('site_logo')->nullable()->after('success_color');
$table->foreign('site_logo')
->references('id')
->on('attachments')
->nullOnDelete();
});
}
public function down(): void
{
Schema::table('website_type', function (Blueprint $table): void {
if (Schema::getConnection()->getDriverName() !== 'sqlite') {
$table->dropForeign(['site_logo']);
}
$table->dropColumn([
'primary_color',
'secondary_color',
'danger_color',
'success_color',
'site_logo',
]);
});
}
};

View File

@@ -80,7 +80,7 @@ class ProductCatalogFromImagesSeeder extends Seeder
throw new RuntimeException("Tenant 'sonder' not found.");
}
$catalogPath = storage_path('public/catalog');
$catalogPath = public_path('images/catalog');
if (! is_dir($catalogPath)) {
throw new RuntimeException("Catalog directory not found at path: {$catalogPath}");

View File

@@ -56,34 +56,34 @@ class TenantSeeder extends Seeder
'success_color' => '#198754',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#313131',
'header_logo' => $this->uploadedImage('images/sonder_header.png', 'sonder_header.png'),
'footer_logo' => $this->uploadedImage('images/sonder_footer.png', 'sonder_footer.png'),
'header_logo' => $this->uploadedImage('images/tennants/sonder/sonder_header.png', 'sonder_header.png'),
'footer_logo' => $this->uploadedImage('images/tennants/sonder/sonder_footer.png', 'sonder_footer.png'),
'social_media' => self::SOCIAL_MEDIA,
'website_type_code' => 'shopit',
'extras' => [
'carousel' => [
$this->uploadedImage(
'images/sonder-main-carousel/01-urban-team.png',
'images/tennants/sonder/sonder-main-carousel/01-urban-team.png',
'01-urban-team.png',
),
$this->uploadedImage(
'images/sonder-main-carousel/02-running-shoes.png',
'images/tennants/sonder/sonder-main-carousel/02-running-shoes.png',
'02-running-shoes.png',
),
$this->uploadedImage(
'images/sonder-main-carousel/03-streetwear.png',
'images/tennants/sonder/sonder-main-carousel/03-streetwear.png',
'03-streetwear.png',
),
$this->uploadedImage(
'images/sonder-main-carousel/04-football-training.png',
'images/tennants/sonder/sonder-main-carousel/04-football-training.png',
'04-football-training.png',
),
$this->uploadedImage(
'images/sonder-main-carousel/05-activewear-essentials.png',
'images/tennants/sonder/sonder-main-carousel/05-activewear-essentials.png',
'05-activewear-essentials.png',
),
$this->uploadedImage(
'images/sonder-main-carousel/06-city-runners.png',
'images/tennants/sonder/sonder-main-carousel/06-city-runners.png',
'06-city-runners.png',
),
],
@@ -108,11 +108,11 @@ class TenantSeeder extends Seeder
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#015327',
'header_logo' => $this->uploadedImage(
'images/futbol_infantil_header.png',
'images/tennants/fiesta_futbol_infantil/futbol_infantil_header.png',
'futbol_infantil_header.png',
),
'footer_logo' => $this->uploadedImage(
'images/futbol_infantil_footer.png',
'images/tennants/fiesta_futbol_infantil/futbol_infantil_footer.png',
'futbol_infantil_footer.png',
),
'social_media' => self::SOCIAL_MEDIA,
@@ -124,7 +124,7 @@ class TenantSeeder extends Seeder
'button_text' => 'Comprar entradas',
'button_href' => '/tickets',
'background_image_id' => $this->uploadedImage(
'images/futbol_infantil_hero.jpg',
'images/tennants/fiesta_futbol_infantil/futbol_infantil_hero.jpg',
'futbol_infantil_hero.jpg',
),
],

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 458 KiB

After

Width:  |  Height:  |  Size: 458 KiB

View File

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 208 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 165 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 386 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -2,6 +2,8 @@
namespace Tests\Feature\Tenant;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType;
use Illuminate\Foundation\Testing\RefreshDatabase;
@@ -20,6 +22,11 @@ class WebsiteExtrasTest extends TestCase
'id',
'codigo',
'nombre',
'primary_color',
'secondary_color',
'danger_color',
'success_color',
'site_logo',
'created_at',
'updated_at',
], Schema::getColumnListing('website_type'));
@@ -49,9 +56,21 @@ class WebsiteExtrasTest extends TestCase
public function test_models_map_the_diagram_relations_and_casts(): void
{
$siteLogo = Attachment::query()->create([
'key' => '92bb3986-fb22-4871-b98c-fc5663d78aa6',
'path' => 'website-types/site-logo.png',
'filename' => 'site-logo.png',
'type' => AttachmentType::Image,
'mime_type' => 'image/png',
]);
$type = WebsiteType::query()->create([
'codigo' => 'store',
'nombre' => 'Tienda',
'primary_color' => '#111111',
'secondary_color' => '#222222',
'danger_color' => '#ff0000',
'success_color' => '#00aa55',
'site_logo' => $siteLogo->id,
]);
$typeExtra = $type->extras()->create([
'codigo' => 'whatsapp',
@@ -72,6 +91,11 @@ class WebsiteExtrasTest extends TestCase
]);
$this->assertTrue($type->extras()->firstOrFail()->is($typeExtra));
$this->assertSame('#111111', $type->primary_color);
$this->assertSame('#222222', $type->secondary_color);
$this->assertSame('#ff0000', $type->danger_color);
$this->assertSame('#00aa55', $type->success_color);
$this->assertTrue($type->siteLogo()->firstOrFail()->is($siteLogo));
$this->assertSame($type->codigo, $typeExtra->website_type_code);
$this->assertSame('whatsapp', $typeExtra->codigo);
$this->assertTrue($type->tenants()->firstOrFail()->is($tenant));

View File

@@ -0,0 +1,40 @@
<?php
namespace Tests\Feature\Tenant;
use App\Domains\Tenant\Services\WebsiteTypeService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class WebsiteTypeServiceTest extends TestCase
{
use RefreshDatabase;
public function test_it_creates_a_website_type_and_uploads_its_logo_to_s3(): void
{
Storage::fake('s3');
$websiteType = app(WebsiteTypeService::class)->create([
'codigo' => 'marketplace',
'nombre' => 'Marketplace',
'primary_color' => '#111111',
'secondary_color' => '#222222',
'danger_color' => '#ff0000',
'success_color' => '#00aa55',
'site_logo' => UploadedFile::fake()->image('site-logo.png'),
]);
$siteLogo = $websiteType->siteLogo()->firstOrFail();
$this->assertSame('marketplace', $websiteType->codigo);
$this->assertSame($siteLogo->id, $websiteType->site_logo);
$this->assertStringStartsWith('website-types/', $siteLogo->path);
Storage::disk('s3')->assertExists($siteLogo->path);
$this->assertDatabaseHas('website_type', [
'codigo' => 'marketplace',
'site_logo' => $siteLogo->id,
]);
}
}