feat: differentiate between header and footer colors

This commit is contained in:
ncoronel 2026-07-01 15:37:46 -03:00
parent 52b422c1ca
commit 3285015841
12 changed files with 123 additions and 33 deletions

View File

@ -50,7 +50,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme\",\n \"dominio\": \"acme.test\",\n \"primary_color\": \"#111111\",\n \"secondary_color\": \"#222222\",\n \"danger_color\": \"#ff0000\",\n \"header_footer_bg_color\": \"#333333\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n}"
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme\",\n \"dominio\": \"acme.test\",\n \"primary_color\": \"#111111\",\n \"secondary_color\": \"#222222\",\n \"danger_color\": \"#ff0000\",\n \"header_bg_color\": \"#333333\",\n \"footer_bg_color\": \"#333333\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n}"
},
"url": {
"raw": "{{base_url}}/api/tenants",
@ -110,7 +110,12 @@
"type": "text"
},
{
"key": "header_footer_bg_color",
"key": "header_bg_color",
"value": "#333333",
"type": "text"
},
{
"key": "footer_bg_color",
"value": "#333333",
"type": "text"
},

View File

@ -73,7 +73,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme Corporation\",\n \"dominio\": \"acme.com\",\n \"primary_color\": \"#111111\",\n \"secondary_color\": \"#222222\",\n \"danger_color\": \"#333333\",\n \"header_footer_bg_color\": \"#444444\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n}"
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme Corporation\",\n \"dominio\": \"acme.com\",\n \"primary_color\": \"#111111\",\n \"secondary_color\": \"#222222\",\n \"danger_color\": \"#333333\",\n \"header_bg_color\": \"#444444\",\n \"footer_bg_color\": \"#444444\",\n \"header_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"footer_logo\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n}"
},
"url": {
"raw": "{{base_url}}/api/tenants",
@ -133,7 +133,12 @@
"type": "text"
},
{
"key": "header_footer_bg_color",
"key": "header_bg_color",
"value": "#444444",
"type": "text"
},
{
"key": "footer_bg_color",
"value": "#444444",
"type": "text"
},
@ -205,7 +210,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme Corporation Updated\",\n \"dominio\": \"acme.com\",\n \"primary_color\": \"#555555\",\n \"secondary_color\": \"#666666\",\n \"danger_color\": \"#777777\",\n \"header_footer_bg_color\": \"#888888\"\n}"
"raw": "{\n \"codigo\": \"acme\",\n \"nombre\": \"Acme Corporation Updated\",\n \"dominio\": \"acme.com\",\n \"primary_color\": \"#555555\",\n \"secondary_color\": \"#666666\",\n \"danger_color\": \"#777777\",\n \"header_bg_color\": \"#888888\",\n \"footer_bg_color\": \"#888888\"\n}"
},
"url": {
"raw": "{{base_url}}/api/tenants/acme",
@ -271,7 +276,12 @@
"type": "text"
},
{
"key": "header_footer_bg_color",
"key": "header_bg_color",
"value": "#888888",
"type": "text"
},
{
"key": "footer_bg_color",
"value": "#888888",
"type": "text"
},

View File

@ -18,7 +18,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
'secondary_color',
'danger_color',
'success_color',
'header_footer_bg_color',
'header_bg_color',
'footer_bg_color',
'header_logo_id',
'footer_logo_id',
])]

View File

@ -57,7 +57,8 @@ class StoreTenantRequest extends FormRequest
'secondary_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'danger_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'success_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_footer_bg_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_bg_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'footer_bg_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_logo' => $logoRule,
'footer_logo' => $logoRule,
];

View File

@ -68,7 +68,8 @@ class UpdateTenantRequest extends FormRequest
'secondary_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'danger_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'success_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_footer_bg_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_bg_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'footer_bg_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
'header_logo' => $logoRule,
'footer_logo' => $logoRule,
];

View File

@ -24,7 +24,8 @@ class TenantResource extends JsonResource
'secondary_color' => $this->secondary_color,
'danger_color' => $this->danger_color,
'success_color' => $this->success_color,
'header_footer_bg_color' => $this->header_footer_bg_color,
'header_bg_color' => $this->header_bg_color,
'footer_bg_color' => $this->footer_bg_color,
// 1 day
'header_logo' => $this->headerLogo?->getTemporaryUrl(1440),
'footer_logo' => $this->footerLogo?->getTemporaryUrl(1440 ),

View File

@ -0,0 +1,53 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('tenants', function (Blueprint $table) {
$table->string('header_bg_color')->nullable()->after('success_color');
$table->string('footer_bg_color')->nullable()->after('header_bg_color');
});
// Copy existing values
DB::table('tenants')->update([
'header_bg_color' => DB::raw('header_footer_bg_color'),
'footer_bg_color' => DB::raw('header_footer_bg_color'),
]);
// Make columns required and drop old column
Schema::table('tenants', function (Blueprint $table) {
$table->string('header_bg_color')->nullable(false)->change();
$table->string('footer_bg_color')->nullable(false)->change();
$table->dropColumn('header_footer_bg_color');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('tenants', function (Blueprint $table) {
$table->string('header_footer_bg_color')->nullable()->after('success_color');
});
// Copy back one of the values (fallback to default color if null)
DB::table('tenants')->update([
'header_footer_bg_color' => DB::raw("COALESCE(header_bg_color, footer_bg_color, '#313131')"),
]);
Schema::table('tenants', function (Blueprint $table) {
$table->string('header_footer_bg_color')->nullable(false)->change();
$table->dropColumn(['header_bg_color', 'footer_bg_color']);
});
}
};

View File

@ -75,7 +75,8 @@ class TenantSeeder extends Seeder
'secondary_color' => '#A0A0A0',
'danger_color' => '#FF8888',
'success_color' => '#198754',
'header_footer_bg_color' => '#313131',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#313131',
'header_logo' => $headerLogo,
'footer_logo' => $footerLogo,
]);

View File

@ -40,7 +40,6 @@ class AttributeControllerTest extends TestCase
$response
->assertCreated()
->assertJsonPath('data.tenant_codigo', 'acme')
->assertJsonPath('data.codigo', 'color')
->assertJsonPath('data.type', 'select')
->assertJsonPath('data.options.0.value', 'red')
@ -123,7 +122,8 @@ class AttributeControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#28a745',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
]);

View File

@ -807,7 +807,8 @@ class ProductControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#28a745',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
]);

View File

@ -42,7 +42,8 @@ class ProductVariantAttachmentTest extends TestCase
'secondary_color' => '#ffffff',
'danger_color' => '#ffffff',
'success_color' => '#ffffff',
'header_footer_bg_color' => '#ffffff',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#ffffff',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
]);
@ -119,7 +120,8 @@ class ProductVariantAttachmentTest extends TestCase
'primary_color' => '#ffffff',
'secondary_color' => '#ffffff',
'danger_color' => '#ffffff',
'header_footer_bg_color' => '#ffffff',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#ffffff',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
]);

View File

@ -41,7 +41,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#00ff00',
'danger_color' => '#0000ff',
'success_color' => '#00ff00',
'header_footer_bg_color' => '#ffffff',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#ffffff',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
]);
@ -56,7 +57,7 @@ class BootstrapTenantControllerTest extends TestCase
->assertJsonPath('data.secondary_color', '#00ff00')
->assertJsonPath('data.danger_color', '#0000ff')
->assertJsonPath('data.success_color', '#00ff00')
->assertJsonPath('data.header_footer_bg_color', '#ffffff');
->assertJsonPath('data.header_bg_color', '#ffffff')->assertJsonPath('data.footer_bg_color', '#ffffff');
$headerUrl = $response->json('data.header_logo');
$footerUrl = $response->json('data.footer_logo');
@ -110,7 +111,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => $base64Image,
'footer_logo' => $base64Image,
]);
@ -122,7 +124,7 @@ class BootstrapTenantControllerTest extends TestCase
->assertJsonPath('data.secondary_color', '#222222')
->assertJsonPath('data.danger_color', '#333333')
->assertJsonPath('data.success_color', '#555555')
->assertJsonPath('data.header_footer_bg_color', '#444444');
->assertJsonPath('data.header_bg_color', '#444444')->assertJsonPath('data.footer_bg_color', '#444444');
$tenant = Tenant::query()->with(['headerLogo', 'footerLogo'])->where('codigo', 'acme')->firstOrFail();
@ -135,7 +137,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo_id' => $tenant->header_logo_id,
'footer_logo_id' => $tenant->footer_logo_id,
]);
@ -160,7 +163,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => (string) Str::uuid(),
'footer_logo' => (string) Str::uuid(),
]);
@ -210,7 +214,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#666666',
'danger_color' => '#777777',
'success_color' => '#999999',
'header_footer_bg_color' => '#888888',
'header_bg_color' => '#888888',
'footer_bg_color' => '#888888',
'header_logo' => $hdrUuid,
'footer_logo' => $ftrUuid,
]);
@ -223,7 +228,7 @@ class BootstrapTenantControllerTest extends TestCase
->assertJsonPath('data.secondary_color', '#666666')
->assertJsonPath('data.danger_color', '#777777')
->assertJsonPath('data.success_color', '#999999')
->assertJsonPath('data.header_footer_bg_color', '#888888');
->assertJsonPath('data.header_bg_color', '#888888')->assertJsonPath('data.footer_bg_color', '#888888');
$headerUrl = $successfulResponse->json('data.header_logo');
$footerUrl = $successfulResponse->json('data.footer_logo');
@ -243,7 +248,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#666666',
'danger_color' => '#777777',
'success_color' => '#999999',
'header_footer_bg_color' => '#888888',
'header_bg_color' => '#888888',
'footer_bg_color' => '#888888',
'header_logo_id' => $hdrAttachment->id,
'footer_logo_id' => $ftrAttachment->id,
]);
@ -296,7 +302,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => (string) Str::uuid(),
'footer_logo' => (string) Str::uuid(),
]);
@ -311,7 +318,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => (string) Str::uuid(),
'footer_logo' => (string) Str::uuid(),
]);
@ -326,7 +334,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => 'invalid-color',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => (string) Str::uuid(),
'footer_logo' => (string) Str::uuid(),
]);
@ -346,7 +355,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => UploadedFile::fake()->create('document.pdf', 10, 'application/pdf'),
'footer_logo' => (string) Str::uuid(),
]);
@ -361,7 +371,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => 'data:application/pdf;base64,JVBERi0xLjQKJdcfqksKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAvUGFnZXMgMiAwIFI...',
'footer_logo' => (string) Str::uuid(),
]);
@ -384,7 +395,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => $header,
'footer_logo' => $footer,
]);
@ -440,7 +452,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#00ff00',
'danger_color' => '#0000ff',
'success_color' => '#00ff00',
'header_footer_bg_color' => '#ffffff',
'header_bg_color' => '#ffffff',
'footer_bg_color' => '#ffffff',
'header_logo_id' => $headerAttachment->id,
'footer_logo_id' => $footerAttachment->id,
], $attributes));
@ -469,7 +482,8 @@ class BootstrapTenantControllerTest extends TestCase
'secondary_color' => '#222222',
'danger_color' => '#333333',
'success_color' => '#555555',
'header_footer_bg_color' => '#444444',
'header_bg_color' => '#444444',
'footer_bg_color' => '#444444',
'header_logo' => $base64Image,
'footer_logo' => $ftrUuid,
]);