feat(social-media): add 'orden' field to social media pivot table and update related functionality

This commit is contained in:
ncoronel 2026-07-23 15:19:17 -03:00
parent 25891cefbc
commit 217f86f624
7 changed files with 70 additions and 7 deletions

View File

@ -28,7 +28,8 @@ class SocialMedia extends Model
'code', 'code',
'codigo' 'codigo'
) )
->withPivot('url') ->withPivot(['url', 'orden'])
->withTimestamps(); ->withTimestamps()
->orderByPivot('orden');
} }
} }

View File

@ -107,8 +107,9 @@ class Tenant extends Model
'codigo', 'codigo',
'code' 'code'
) )
->withPivot('url') ->withPivot(['url', 'orden'])
->withTimestamps(); ->withTimestamps()
->orderByPivot('orden');
} }
public function menues(): BelongsToMany public function menues(): BelongsToMany

View File

@ -71,6 +71,7 @@ class StoreTenantRequest extends FormRequest
Rule::exists('social_media', 'code'), Rule::exists('social_media', 'code'),
], ],
'social_media.*.url' => ['required', 'url', 'max:2048'], 'social_media.*.url' => ['required', 'url', 'max:2048'],
'social_media.*.orden' => ['sometimes', 'integer', 'min:0', 'distinct'],
'hero_config' => ['nullable', 'array'], 'hero_config' => ['nullable', 'array'],
'hero_config.title_html' => ['nullable', 'string'], 'hero_config.title_html' => ['nullable', 'string'],
'hero_config.description_html' => ['nullable', 'string'], 'hero_config.description_html' => ['nullable', 'string'],

View File

@ -82,6 +82,7 @@ class UpdateTenantRequest extends FormRequest
Rule::exists('social_media', 'code'), Rule::exists('social_media', 'code'),
], ],
'social_media.*.url' => ['required', 'url', 'max:2048'], 'social_media.*.url' => ['required', 'url', 'max:2048'],
'social_media.*.orden' => ['sometimes', 'integer', 'min:0', 'distinct'],
'hero_config' => ['nullable', 'array'], 'hero_config' => ['nullable', 'array'],
'hero_config.title_html' => ['nullable', 'string'], 'hero_config.title_html' => ['nullable', 'string'],
'hero_config.description_html' => ['nullable', 'string'], 'hero_config.description_html' => ['nullable', 'string'],

View File

@ -197,14 +197,17 @@ class TenantService
} }
/** /**
* @param array<int, array{code: string, url: string}> $socialMedia * @param array<int, array{code: string, url: string, orden?: int}> $socialMedia
*/ */
private function syncSocialMedia(Tenant $tenant, array $socialMedia): void private function syncSocialMedia(Tenant $tenant, array $socialMedia): void
{ {
$associations = []; $associations = [];
foreach ($socialMedia as $item) { foreach (array_values($socialMedia) as $index => $item) {
$associations[$item['code']] = ['url' => $item['url']]; $associations[$item['code']] = [
'url' => $item['url'],
'orden' => $item['orden'] ?? $index,
];
} }
$tenant->socialMedia()->sync($associations); $tenant->socialMedia()->sync($associations);

View File

@ -0,0 +1,24 @@
<?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('tenant_social_media', function (Blueprint $table): void {
$table->unsignedInteger('orden')->default(0)->after('url');
$table->index(['tenant_code', 'orden']);
});
}
public function down(): void
{
Schema::table('tenant_social_media', function (Blueprint $table): void {
$table->dropIndex(['tenant_code', 'orden']);
$table->dropColumn('orden');
});
}
};

View File

@ -30,6 +30,7 @@ class TenantSocialMediaTest extends TestCase
'tenant_code', 'tenant_code',
'social_media_code', 'social_media_code',
'url', 'url',
'orden',
'created_at', 'created_at',
'updated_at', 'updated_at',
], Schema::getColumnListing('tenant_social_media')); ], Schema::getColumnListing('tenant_social_media'));
@ -46,6 +47,7 @@ class TenantSocialMediaTest extends TestCase
$tenant->socialMedia()->attach($instagram->code, [ $tenant->socialMedia()->attach($instagram->code, [
'url' => 'https://instagram.com/acme', 'url' => 'https://instagram.com/acme',
'orden' => 3,
]); ]);
$this->assertTrue($tenant->socialMedia()->firstOrFail()->is($instagram)); $this->assertTrue($tenant->socialMedia()->firstOrFail()->is($instagram));
@ -53,6 +55,7 @@ class TenantSocialMediaTest extends TestCase
'https://instagram.com/acme', 'https://instagram.com/acme',
$tenant->socialMedia()->firstOrFail()->pivot->url $tenant->socialMedia()->firstOrFail()->pivot->url
); );
$this->assertSame(3, $tenant->socialMedia()->firstOrFail()->pivot->orden);
$this->assertTrue($instagram->tenants()->firstOrFail()->is($tenant)); $this->assertTrue($instagram->tenants()->firstOrFail()->is($tenant));
} }
@ -91,6 +94,7 @@ class TenantSocialMediaTest extends TestCase
[ [
'code' => $instagram->code, 'code' => $instagram->code,
'url' => 'https://instagram.com/acme', 'url' => 'https://instagram.com/acme',
'orden' => 4,
], ],
], ],
]) ])
@ -105,6 +109,7 @@ class TenantSocialMediaTest extends TestCase
'tenant_code' => $tenant->codigo, 'tenant_code' => $tenant->codigo,
'social_media_code' => $instagram->code, 'social_media_code' => $instagram->code,
'url' => 'https://instagram.com/acme', 'url' => 'https://instagram.com/acme',
'orden' => 4,
]); ]);
$this->assertDatabaseMissing('tenant_social_media', [ $this->assertDatabaseMissing('tenant_social_media', [
'tenant_code' => $tenant->codigo, 'tenant_code' => $tenant->codigo,
@ -112,6 +117,33 @@ class TenantSocialMediaTest extends TestCase
]); ]);
} }
public function test_tenant_social_media_are_returned_in_configured_order(): void
{
$tenant = $this->createTenant();
$instagram = $this->createSocialMedia('instagram', 'Instagram');
$facebook = $this->createSocialMedia('facebook', 'Facebook');
$this->putJson("/api/tenants/{$tenant->codigo}", [
'social_media' => [
[
'code' => $instagram->code,
'url' => 'https://instagram.com/acme',
'orden' => 20,
],
[
'code' => $facebook->code,
'url' => 'https://facebook.com/acme',
'orden' => 10,
],
],
])
->assertOk()
->assertJsonPath('data.social_media.0.code', 'facebook')
->assertJsonPath('data.social_media.1.code', 'instagram')
->assertJsonMissingPath('data.social_media.0.orden')
->assertJsonMissingPath('data.social_media.1.orden');
}
public function test_tenant_store_synchronizes_social_media(): void public function test_tenant_store_synchronizes_social_media(): void
{ {
$instagram = $this->createSocialMedia('instagram', 'Instagram'); $instagram = $this->createSocialMedia('instagram', 'Instagram');