Se corrigio el problema de los logos

This commit is contained in:
2026-01-22 08:10:57 -06:00
parent 7658c19661
commit d4e4e1f7f8
8 changed files with 227 additions and 123 deletions

View File

@@ -183,7 +183,7 @@ export interface UnitOfMeasureGeneralUpdate {
}
export interface UnitOfMeasureGeneralListResponse {
items: UnitOfMeasureGeneral[];
items: UnitOfMeasureGeneral[];
total: number;
page: number;
page_size: number;

View File

@@ -10,10 +10,10 @@
const sidebar = useSidebar();
// Derivar la URL del logo
// Derivar la URL del logo usando el endpoint específico
let activeCompanyLogoUrl = $derived(
companyStore.activeCompany?.logo
? getBackendAssetUrl(companyStore.activeCompany.logo)
? getBackendAssetUrl(`v1/a76/company/${companyStore.activeCompany.id}/logo/image?t=${new Date().getTime()}`)
: null
);
@@ -89,7 +89,7 @@
<div class="flex size-6 items-center justify-center rounded-md border overflow-hidden">
{#if company.logo}
<img
src={getBackendAssetUrl(company.logo)}
src={getBackendAssetUrl(`v1/a76/company/${company.id}/logo/image`)}
alt={company.name}
class="size-full rounded object-cover"
/>

View File

@@ -144,6 +144,30 @@ class CompanyStore {
}
}
/**
* Actualiza los datos de une empresa en el store localmente
* Útil para reflejar cambios inmediatos (ej: cambio de logo) sin recargar
*/
updateCompany(id: number, data: Partial<Company>) {
// 1. Actualizar en la lista
const index = this._companies.findIndex(c => c.id === id);
if (index !== -1) {
this._companies[index] = { ...this._companies[index], ...data };
// 2. Si es la activa, actualizar también
if (this._activeCompany?.id === id) {
this._activeCompany = { ...this._activeCompany, ...data };
// Actualizar persistencia si es necesario
if (typeof window !== 'undefined') {
// Disparar evento para notificar cambios a componentes que no usan el store reactivo directo (si los hay)
window.dispatchEvent(new CustomEvent('companyChanged', {
detail: { companyId: id }
}));
}
}
}
}
/**
* Restaura la compañía activa desde localStorage
*/

View File

@@ -14,6 +14,7 @@
uploadCompanyLogo,
type Company
} from '$lib/api/dashboard/a76/general_catalogs/company';
import { companyStore } from '$lib/stores/company.svelte';
import { getBackendAssetUrl } from '$lib/utils';
import { ArrowLeft, LoaderCircle, Save, Upload, X, Building2, FileText, User, Settings } from 'lucide-svelte';
@@ -25,15 +26,18 @@
let loading = $state(false);
let uploading = $state(false);
let error = $state<string | null>(null);
let activeTab = $state('general');
let logoFile = $state<File | null>(null);
let logoPreview = $state<string | null>(null);
let currentLogo = $state<string | null>(null);
let uploadingLogo = $state(false);
let activeTab = $state('general');
// URL completa del logo derivada
let currentLogoUrl = $derived(
logoPreview || getBackendAssetUrl(currentLogo) || ''
logoPreview
? logoPreview
: (currentLogo ? getBackendAssetUrl(`v1/a76/company/${id}/logo/image?t=${new Date().getTime()}`) : '')
);
// 2. Estado Inicial (Reset)
@@ -104,7 +108,15 @@
is_service_company: item.is_service_company || false,
order_format_type: item.order_format_type || '',
ctpat_svi: item.ctpat_svi || '',
trusted_exporter_number: item.trusted_exporter_number || ''
trusted_exporter_number: item.trusted_exporter_number || '',
logo: item.logo || '',
previous_code: item.previous_code || 0,
client_name: item.client_name || '',
subassembly_mode: item.subassembly_mode || '',
broker_company: item.broker_company || '',
inter_db_name: item.inter_db_name || '',
prevalidator_key: item.prevalidator_key || '',
seventh_amendment: item.seventh_amendment || false
};
// Guardar la URL del logo actual si existe
if (item.logo) {
@@ -118,6 +130,9 @@
}
}
const clean = (value: any) => (typeof value === 'string' ? value.trim() || null : value);
function handleLogoChange(event: Event) {
const target = event.target as HTMLInputElement;
const file = target.files?.[0];
@@ -170,6 +185,9 @@
currentLogo = response.data.logo_path;
logoFile = null;
logoPreview = null;
// Actualizar el store reactivamente
companyStore.updateCompany(companyId, { logo: response.data.logo_path });
}
} catch (e: any) {
error = `Error al subir el logo: ${e.message}`;
@@ -178,33 +196,6 @@
}
}
const clean = (value: any) => (typeof value === 'string' ? value.trim() || null : value);
async function handleFileSelect(e: Event) {
const input = e.target as HTMLInputElement;
if (!input.files || input.files.length === 0) return;
const file = input.files[0];
if (!isEdit) {
alert("Primero debes guardar la empresa antes de subir un logo.");
return;
}
uploading = true;
try {
const res = await uploadCompanyLogo(Number(id), file);
if (res.data) {
formData.logo = res.data.path;
} else if (res.error) {
alert("Error al subir imagen: " + res.error);
}
} catch (err) {
alert("Error al intentar subir la imagen");
} finally {
uploading = false;
}
}
async function handleSubmit() {
error = null;
loading = true;
@@ -222,6 +213,7 @@
main_activity: clean(formData.main_activity),
program: clean(formData.program),
program_number: clean(formData.program_number),
prosec: Number(formData.prosec) || 0,
prosec_authorization: clean(formData.prosec_authorization),
responsible_name: clean(formData.responsible_name),
responsible_last_name: clean(formData.responsible_last_name),
@@ -239,7 +231,10 @@
broker_company: clean(formData.broker_company),
inter_db_name: clean(formData.inter_db_name),
prevalidator_key: clean(formData.prevalidator_key),
seventh_amendment: formData.seventh_amendment
seventh_amendment: formData.seventh_amendment,
// Ensure optional booleans are passed correctly or default to false/null if needed
has_express_line: formData.has_express_line,
is_service_company: formData.is_service_company
};
const response = isEdit
@@ -285,6 +280,8 @@
<Tabs.Root bind:value={activeTab} class="w-full">
<div class="min-h-[400px]">
<Tabs.Content value="general" class="space-y-4 pt-4">
<!-- Logo Upload Section -->
<div class="grid gap-4 p-4 border rounded-lg bg-muted/30">
<Label>Logo de la Empresa</Label>
@@ -344,36 +341,9 @@
<Label for="main_activity">Actividad Principal</Label>
<Input id="main_activity" bind:value={formData.main_activity} />
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="grid gap-2">
<Label for="logo">Ruta del Logo</Label>
<div class="flex items-center gap-2">
<Input id="logo" bind:value={formData.logo} placeholder="/path/to/logo.png" />
{#if isEdit}
<div class="relative">
<Button variant="outline" size="icon" disabled={uploading}>
{#if uploading}
<LoaderCircle class="h-4 w-4 animate-spin" />
{:else}
<Upload class="h-4 w-4" />
{/if}
</Button>
<input
type="file"
accept="image/*"
class="absolute inset-0 opacity-0 cursor-pointer"
onchange={handleFileSelect}
disabled={uploading}
/>
</div>
{/if}
</div>
<p class="text-[0.8rem] text-muted-foreground">Sube una imagen para obtener su ruta local.</p>
</div>
<div class="grid gap-2">
<Label for="client_name">Nombre Cliente (Maquila)</Label>
<Input id="client_name" bind:value={formData.client_name} />
</div>
<div class="grid gap-2">
<Label for="client_name">Nombre Cliente (Maquila)</Label>
<Input id="client_name" bind:value={formData.client_name} />
</div>
</Tabs.Content>