Traducciones corregidas en porveedored y clientes
This commit is contained in:
@@ -1801,5 +1801,10 @@
|
||||
"th_reason": "Reason",
|
||||
"download_csv": "Download CSV"
|
||||
}
|
||||
},
|
||||
"clients_providers": {
|
||||
"type_client": "Client",
|
||||
"type_provider": "Provider",
|
||||
"type_both": "Both"
|
||||
}
|
||||
}
|
||||
@@ -1801,5 +1801,10 @@
|
||||
"th_reason": "Motivo",
|
||||
"download_csv": "Descargar CSV"
|
||||
}
|
||||
},
|
||||
"clients_providers": {
|
||||
"type_client": "Cliente",
|
||||
"type_provider": "Proveedor",
|
||||
"type_both": "Ambos"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,28 @@
|
||||
canDeleteClientsAndProviders,
|
||||
canEditClientsAndProviders
|
||||
} from '$lib/permissions/clients-providers-permissions';
|
||||
import { m } from '$lib/i18n/messages';
|
||||
import { getLocale } from '$lib/paraglide/runtime.js';
|
||||
|
||||
const canCreatePartner = $derived(canCreateClientsAndProviders($currentUser));
|
||||
const canEditPartner = $derived(canEditClientsAndProviders($currentUser));
|
||||
const canDeletePartner = $derived(canDeleteClientsAndProviders($currentUser));
|
||||
|
||||
const typeLabels: Record<string, string> = $derived({
|
||||
client: getLocale() === 'en' ? 'Client' : 'Cliente',
|
||||
provider: getLocale() === 'en' ? 'Provider' : 'Proveedor',
|
||||
both: getLocale() === 'en' ? 'Both' : 'Ambos'
|
||||
});
|
||||
|
||||
const statusLabels = $derived({
|
||||
active: getLocale() === 'en' ? 'Active' : 'Activo',
|
||||
inactive: getLocale() === 'en' ? 'Inactive' : 'Inactivo'
|
||||
});
|
||||
|
||||
function t(es: string, en: string) {
|
||||
return getLocale() === 'en' ? en : es;
|
||||
}
|
||||
|
||||
// Los datos iniciales vienen del servidor
|
||||
let { data }: { data: any } = $props();
|
||||
|
||||
@@ -232,9 +249,9 @@
|
||||
<div class="flex flex-col h-[calc(100vh-4rem)] p-4 gap-4 pb-15">
|
||||
<!-- Title -->
|
||||
<div class="flex flex-col gap-1">
|
||||
<h1 class="text-2xl font-bold">CLIENTES Y PROVEEDORES</h1>
|
||||
<h1 class="text-2xl font-bold uppercase">{t('Clientes y Proveedores', 'Clients and Providers')}</h1>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Gestiona el catálogo de clientes y proveedores de tu empresa
|
||||
{t('Gestiona el catálogo de clientes y proveedores de tu empresa', 'Manage your company\'s client and provider catalog')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -259,15 +276,15 @@
|
||||
<div class="border rounded-lg bg-card">
|
||||
<div class="p-4 space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-sm font-semibold">Filtros</h2>
|
||||
<span class="text-xs text-muted-foreground">Busque por nombre, RFC/TAX-ID o tipo</span>
|
||||
<h2 class="text-sm font-semibold">{t('Filtros', 'Filters')}</h2>
|
||||
<span class="text-xs text-muted-foreground">{t('Busque por nombre, RFC/TAX-ID o tipo', 'Search by name, RFC/TAX-ID or type')}</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Nombre / Razón Social</Label>
|
||||
<Label class="text-xs">{t('Nombre / Razón Social', 'Name / Business Name')}</Label>
|
||||
<Input
|
||||
bind:value={searchName}
|
||||
placeholder="Buscar por nombre..."
|
||||
placeholder={t('Buscar por nombre...', 'Search by name...')}
|
||||
class="h-9"
|
||||
/>
|
||||
</div>
|
||||
@@ -334,13 +351,13 @@
|
||||
<tbody>
|
||||
{#if isLoading && allItems.length === 0}
|
||||
<tr
|
||||
><td colspan="5" class="text-center py-8 text-muted-foreground">Cargando...</td
|
||||
><td colspan="5" class="text-center py-8 text-muted-foreground">{t('Cargando...', 'Loading...')}</td
|
||||
></tr
|
||||
>
|
||||
{:else if allItems.length === 0}
|
||||
<tr
|
||||
><td colspan="5" class="text-center py-8 text-muted-foreground"
|
||||
>No se encontraron registros</td
|
||||
>{t('No se encontraron registros', 'No records found')}</td
|
||||
></tr
|
||||
>
|
||||
{:else}
|
||||
@@ -357,22 +374,14 @@
|
||||
<td class="px-3 py-2 font-mono font-medium">{item.rfc}</td>
|
||||
<td class="px-3 py-2">{item.name}</td>
|
||||
<td class="px-3 py-2">
|
||||
{#if item.client_or_provider === 'client'}
|
||||
<span
|
||||
class="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700"
|
||||
>Cliente</span
|
||||
>
|
||||
{:else if item.client_or_provider === 'provider'}
|
||||
<span
|
||||
class="inline-flex items-center rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-700"
|
||||
>Proveedor</span
|
||||
>
|
||||
{:else}
|
||||
<span
|
||||
class="inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-700"
|
||||
>Ambos</span
|
||||
>
|
||||
{/if}
|
||||
<span
|
||||
class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
|
||||
{item.client_or_provider === 'client' ? 'bg-blue-100 text-blue-700' :
|
||||
item.client_or_provider === 'provider' ? 'bg-purple-100 text-purple-700' :
|
||||
'bg-gray-100 text-gray-700'}"
|
||||
>
|
||||
{typeLabels[item.client_or_provider] || item.client_or_provider}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 py-2">
|
||||
<span
|
||||
@@ -380,7 +389,7 @@
|
||||
? 'bg-green-100 text-green-700'
|
||||
: 'bg-red-100 text-red-700'}"
|
||||
>
|
||||
{item.is_active ? 'Activo' : 'Inactivo'}
|
||||
{item.is_active ? statusLabels.active : statusLabels.inactive}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -391,9 +400,9 @@
|
||||
<td colspan="5" class="p-0">
|
||||
<div bind:this={loadingTrigger} class="flex items-center justify-center py-5">
|
||||
{#if isLoading}
|
||||
<span class="text-xs text-muted-foreground">Cargando más registros...</span>
|
||||
<span class="text-xs text-muted-foreground">{t('Cargando más registros...', 'Loading more records...')}</span>
|
||||
{:else}
|
||||
<span class="text-xs text-muted-foreground">Desplázate para cargar más</span>
|
||||
<span class="text-xs text-muted-foreground">{t('Desplázate para cargar más', 'Scroll to load more')}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
@@ -404,7 +413,7 @@
|
||||
</div>
|
||||
<div class="p-2 border-t flex justify-end">
|
||||
<span class="flex items-center text-xs text-muted-foreground px-2">
|
||||
Mostrando {allItems.length} de {totalItems}
|
||||
{t('Mostrando', 'Showing')} {allItems.length} {t('de', 'of')} {totalItems}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -416,7 +425,7 @@
|
||||
>
|
||||
<div class="p-4 border-b bg-card">
|
||||
<p class="text-[10px] uppercase tracking-widest opacity-80 text-muted-foreground">
|
||||
Detalles del Registro
|
||||
{t('Detalles del Registro', 'Record Details')}
|
||||
</p>
|
||||
<h2
|
||||
class="text-xl font-black font-mono tracking-tighter truncate"
|
||||
@@ -439,7 +448,9 @@
|
||||
>
|
||||
<Users size={10} /> Tipo
|
||||
</Label>
|
||||
<p class="text-sm font-medium capitalize">{selectedItem.client_or_provider}</p>
|
||||
<p class="text-sm font-medium capitalize">
|
||||
{typeLabels[selectedItem.client_or_provider] || selectedItem.client_or_provider}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if selectedItem.address}
|
||||
@@ -447,7 +458,7 @@
|
||||
<Label
|
||||
class="text-[10px] uppercase text-muted-foreground font-bold flex items-center gap-1"
|
||||
>
|
||||
<MapPin size={10} /> Dirección
|
||||
<MapPin size={10} /> {t('Dirección', 'Address')}
|
||||
</Label>
|
||||
<div class="text-sm space-y-1">
|
||||
<p>
|
||||
@@ -469,7 +480,7 @@
|
||||
<Label
|
||||
class="text-[10px] uppercase text-muted-foreground font-bold flex items-center gap-1"
|
||||
>
|
||||
<Hash size={10} /> Contacto
|
||||
<Hash size={10} /> {t('Contacto', 'Contact')}
|
||||
</Label>
|
||||
{#if selectedItem.address.email}
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
@@ -488,7 +499,7 @@
|
||||
<div
|
||||
class="p-4 rounded-md bg-yellow-50 dark:bg-yellow-900/10 border border-yellow-200 dark:border-yellow-900"
|
||||
>
|
||||
<p class="text-xs text-yellow-600 dark:text-yellow-400">Sin dirección registrada</p>
|
||||
<p class="text-xs text-yellow-600 dark:text-yellow-400">{t('Sin dirección registrada', 'No address registered')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -497,15 +508,15 @@
|
||||
<Label
|
||||
class="text-[10px] uppercase text-muted-foreground font-bold flex items-center gap-1"
|
||||
>
|
||||
<Building2 size={10} /> Programas
|
||||
<Building2 size={10} /> {t('Programas', 'Programs')}
|
||||
</Label>
|
||||
<div class="grid grid-cols-2 gap-2 text-sm">
|
||||
<div>
|
||||
<span class="text-xs text-muted-foreground block">Programa</span>
|
||||
<span class="text-xs text-muted-foreground block">{t('Programa', 'Program')}</span>
|
||||
<span class="font-medium">{selectedItem.programs.program || '-'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-muted-foreground block">Número</span>
|
||||
<span class="text-xs text-muted-foreground block">{t('Número', 'Number')}</span>
|
||||
<span class="font-medium">{selectedItem.programs.program_number || '-'}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -517,7 +528,7 @@
|
||||
class="flex flex-col items-center justify-center h-full text-center text-muted-foreground opacity-50"
|
||||
>
|
||||
<Building2 class="h-12 w-12 mb-3" />
|
||||
<p class="text-sm">Selecciona un registro</p>
|
||||
<p class="text-sm">{t('Selecciona un registro', 'Select a record')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { getLocale } from '$lib/paraglide/runtime.js';
|
||||
import { m } from '$lib/i18n/messages';
|
||||
|
||||
// Componentes UI
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
@@ -69,11 +71,15 @@
|
||||
// State for Tabs
|
||||
let activeTab = $state('general');
|
||||
|
||||
const typeLabels: Record<string, string> = {
|
||||
client: 'Cliente',
|
||||
provider: 'Proveedor',
|
||||
both: 'Ambos'
|
||||
};
|
||||
const typeLabels: Record<string, string> = $derived({
|
||||
client: getLocale() === 'en' ? 'Client' : 'Cliente',
|
||||
provider: getLocale() === 'en' ? 'Provider' : 'Proveedor',
|
||||
both: getLocale() === 'en' ? 'Both' : 'Ambos'
|
||||
});
|
||||
|
||||
function t(es: string, en: string) {
|
||||
return getLocale() === 'en' ? en : es;
|
||||
}
|
||||
|
||||
// --- ESTADO INICIAL (PLANO) ---
|
||||
const getEmptyForm = () => ({
|
||||
@@ -207,12 +213,12 @@
|
||||
return;
|
||||
}
|
||||
if (!companyStore.activeCompany) {
|
||||
error = 'Selecciona una compañía';
|
||||
error = t('Selecciona una compañía', 'Select a company');
|
||||
toast.error(error);
|
||||
return;
|
||||
}
|
||||
if (!formData.rfc.trim() || !formData.name.trim()) {
|
||||
error = 'Identificador fiscal (RFC/TAX-ID) y Nombre son obligatorios';
|
||||
error = t('Identificador fiscal (RFC/TAX-ID) y Nombre son obligatorios', 'Tax Identifier (RFC/TAX-ID) and Name are required');
|
||||
toast.error(error);
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +289,7 @@
|
||||
if (response.error) throw new Error(response.error);
|
||||
|
||||
toast.success(
|
||||
isEditing ? 'Registro actualizado correctamente' : 'Registro creado correctamente'
|
||||
isEditing ? t('Registro actualizado correctamente', 'Record updated successfully') : t('Registro creado correctamente', 'Record created successfully')
|
||||
);
|
||||
goto('/dashboard/clients_and_providers');
|
||||
} catch (e: any) {
|
||||
@@ -328,20 +334,20 @@
|
||||
<ArrowLeft size={20} />
|
||||
</Button>
|
||||
<h1 class="text-3xl font-bold tracking-tight">
|
||||
{isEditing ? `Socio Comercial #${id}` : 'Nuevo Socio Comercial'}
|
||||
{isEditing ? `${t('Socio Comercial', 'Business Partner')} #${id}` : t('Nuevo Socio Comercial', 'New Business Partner')}
|
||||
</h1>
|
||||
{#if isEditing}
|
||||
<Badge variant={formData.is_active ? 'default' : 'secondary'}>
|
||||
{formData.is_active ? 'Activo' : 'Inactivo'}
|
||||
{formData.is_active ? t('Activo', 'Active') : t('Inactivo', 'Inactive')}
|
||||
</Badge>
|
||||
{:else}
|
||||
<Badge variant="default">Nuevo</Badge>
|
||||
<Badge variant="default">{t('Nuevo', 'New')}</Badge>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="ml-12 text-muted-foreground">
|
||||
{isEditing
|
||||
? 'Edita la información del cliente o proveedor'
|
||||
: 'Registra un nuevo cliente o proveedor en el sistema'}
|
||||
? t('Edita la información del cliente o proveedor', 'Edit client or provider information')
|
||||
: t('Registra un nuevo cliente o proveedor en el sistema', 'Register a new client or provider in the system')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -362,9 +368,9 @@
|
||||
<Tabs.Content value="general">
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Información General</Card.Title>
|
||||
<Card.Title>{t('Información General', 'General Information')}</Card.Title>
|
||||
<Card.Description
|
||||
>Datos principales de identificación y clasificación.</Card.Description
|
||||
>{t('Datos principales de identificación y clasificación.', 'Primary identification and classification data.')}</Card.Description
|
||||
>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-4">
|
||||
@@ -387,12 +393,12 @@
|
||||
onValueChange={(v) => (formData.client_or_provider = v)}
|
||||
>
|
||||
<Select.Trigger id="type">
|
||||
{typeLabels[formData.client_or_provider] || 'Selecciona un tipo'}
|
||||
{typeLabels[formData.client_or_provider] || t('Selecciona un tipo', 'Select a type')}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="client" label="Cliente">Cliente</Select.Item>
|
||||
<Select.Item value="provider" label="Proveedor">Proveedor</Select.Item>
|
||||
<Select.Item value="both" label="Ambos">Ambos</Select.Item>
|
||||
<Select.Item value="client" label={t('Cliente', 'Client')}>{t('Cliente', 'Client')}</Select.Item>
|
||||
<Select.Item value="provider" label={t('Proveedor', 'Provider')}>{t('Proveedor', 'Provider')}</Select.Item>
|
||||
<Select.Item value="both" label={t('Ambos', 'Both')}>{t('Ambos', 'Both')}</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
@@ -400,11 +406,11 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-4">
|
||||
<div class="grid gap-2 md:col-span-3">
|
||||
<Label for="name">Razón Social <span class="text-destructive">*</span></Label>
|
||||
<Label for="name">{t('Razón Social', 'Business Name')} <span class="text-destructive">*</span></Label>
|
||||
<Input
|
||||
id="name"
|
||||
bind:value={formData.name}
|
||||
placeholder="Nombre completo"
|
||||
placeholder={t('Nombre completo', 'Full name')}
|
||||
maxlength={256}
|
||||
disabled={loading}
|
||||
/>
|
||||
@@ -435,14 +441,14 @@
|
||||
>
|
||||
<Select.Trigger id="type_nat">
|
||||
{formData.type_nat_foreign === 'N'
|
||||
? 'Nacional'
|
||||
? t('Nacional', 'National')
|
||||
: formData.type_nat_foreign === 'E'
|
||||
? 'Extranjero'
|
||||
: 'Seleccione'}
|
||||
? t('Extranjero', 'Foreign')
|
||||
: t('Seleccione', 'Select')}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="N" label="Nacional">Nacional</Select.Item>
|
||||
<Select.Item value="E" label="Extranjero">Extranjero</Select.Item>
|
||||
<Select.Item value="N" label={t('Nacional', 'National')}>{t('Nacional', 'National')}</Select.Item>
|
||||
<Select.Item value="E" label={t('Extranjero', 'Foreign')}>{t('Extranjero', 'Foreign')}</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
@@ -450,11 +456,11 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="responsible">Responsable</Label>
|
||||
<Label for="responsible">{t('Responsable', 'Responsible')}</Label>
|
||||
<Input id="responsible" bind:value={formData.responsible} disabled={loading} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="position">Puesto</Label>
|
||||
<Label for="position">{t('Puesto', 'Position')}</Label>
|
||||
<Input id="position" bind:value={formData.position} disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -466,13 +472,13 @@
|
||||
<Tabs.Content value="address">
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Dirección y Contacto</Card.Title>
|
||||
<Card.Description>Ubicación fiscal y datos de contacto.</Card.Description>
|
||||
<Card.Title>{t('Dirección y Contacto', 'Address and Contact')}</Card.Title>
|
||||
<Card.Description>{t('Ubicación fiscal y datos de contacto.', 'Fiscal location and contact details.')}</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="street">Calle</Label>
|
||||
<Label for="street">{t('Calle', 'Street')}</Label>
|
||||
<Input
|
||||
id="street"
|
||||
bind:value={formData.streets}
|
||||
@@ -482,7 +488,7 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="ext">No. Exterior</Label>
|
||||
<Label for="ext">{t('No. Exterior', 'Ext. Number')}</Label>
|
||||
<Input
|
||||
id="ext"
|
||||
bind:value={formData.exterior_number}
|
||||
@@ -491,7 +497,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="int">No. Interior</Label>
|
||||
<Label for="int">{t('No. Interior', 'Int. Number')}</Label>
|
||||
<Input
|
||||
id="int"
|
||||
bind:value={formData.interior_number}
|
||||
@@ -504,7 +510,7 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
<div class="grid gap-2">
|
||||
<Label for="col">Colonia</Label>
|
||||
<Label for="col">{t('Colonia', 'Neighborhood')}</Label>
|
||||
<Input
|
||||
id="col"
|
||||
bind:value={formData.neighborhood}
|
||||
@@ -513,7 +519,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="cp">C.P.</Label>
|
||||
<Label for="cp">{t('C.P.', 'Postal Code')}</Label>
|
||||
<Input
|
||||
id="cp"
|
||||
bind:value={formData.postal_code}
|
||||
@@ -522,7 +528,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="mun">Municipio</Label>
|
||||
<Label for="mun">{t('Municipio', 'Municipality')}</Label>
|
||||
<Input
|
||||
id="mun"
|
||||
bind:value={formData.municipality}
|
||||
@@ -534,11 +540,11 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
<div class="grid gap-2">
|
||||
<Label for="city">Ciudad</Label>
|
||||
<Label for="city">{t('Ciudad', 'City')}</Label>
|
||||
<Input id="city" bind:value={formData.city} maxlength={30} disabled={loading} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="state">Estado</Label>
|
||||
<Label for="state">{t('Estado', 'State')}</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
id="state"
|
||||
@@ -551,14 +557,14 @@
|
||||
size="icon"
|
||||
onclick={() => (stateModalOpen = true)}
|
||||
disabled={loading}
|
||||
title="Buscar Estado"
|
||||
title={t('Buscar Estado', 'Search State')}
|
||||
>
|
||||
<Search size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="country">País (ISO)</Label>
|
||||
<Label for="country">{t('País (ISO)', 'Country (ISO)')}</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
id="country"
|
||||
@@ -572,7 +578,7 @@
|
||||
size="icon"
|
||||
onclick={() => (countryModalOpen = true)}
|
||||
disabled={loading}
|
||||
title="Buscar País"
|
||||
title={t('Buscar País', 'Search Country')}
|
||||
>
|
||||
<Globe size={16} />
|
||||
</Button>
|
||||
@@ -584,11 +590,11 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="email">Email de Contacto</Label>
|
||||
<Label for="email">{t('Email de Contacto', 'Contact Email')}</Label>
|
||||
<Input id="email" type="email" bind:value={formData.email} disabled={loading} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="phone">Teléfono</Label>
|
||||
<Label for="phone">{t('Teléfono', 'Phone')}</Label>
|
||||
<Input id="phone" bind:value={formData.phone} disabled={loading} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -600,9 +606,9 @@
|
||||
<Tabs.Content value="programs">
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Programas y Certificaciones</Card.Title>
|
||||
<Card.Title>{t('Programas y Certificaciones', 'Programs and Certifications')}</Card.Title>
|
||||
<Card.Description
|
||||
>Información sobre IMMEX, PROSEC y otras certificaciones.</Card.Description
|
||||
>{t('Información sobre IMMEX, PROSEC y otras certificaciones.', 'Information about IMMEX, PROSEC and other certifications.')}</Card.Description
|
||||
>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-8">
|
||||
@@ -610,14 +616,14 @@
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-2 text-sm font-semibold text-white">
|
||||
<Briefcase size={18} />
|
||||
<span>Programas de Fomento</span>
|
||||
<span>{t('Programas de Fomento', 'Promotion Programs')}</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4">
|
||||
<div class="grid gap-2 lg:col-span-1">
|
||||
<Label for="program" class="flex items-center gap-2">
|
||||
<Building2 size={14} class="text-muted-foreground" />
|
||||
Programa
|
||||
{t('Programa', 'Program')}
|
||||
</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
@@ -626,7 +632,7 @@
|
||||
disabled={loading}
|
||||
>
|
||||
<Select.Trigger id="program" class="w-full">
|
||||
{formData.program || 'Selecciona un programa'}
|
||||
{formData.program || t('Selecciona un programa', 'Select a program')}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each scaiiPrograms as prog}
|
||||
@@ -640,20 +646,20 @@
|
||||
<div class="grid gap-2">
|
||||
<Label for="program_num" class="flex items-center gap-2">
|
||||
<Hash size={14} class="text-muted-foreground" />
|
||||
Número de Programa
|
||||
{t('Número de Programa', 'Program Number')}
|
||||
</Label>
|
||||
<Input
|
||||
id="program_num"
|
||||
bind:value={formData.program_number}
|
||||
maxlength={40}
|
||||
disabled={loading}
|
||||
placeholder="P. ej. 1234-2024"
|
||||
placeholder={t('P. ej. 1234-2024', 'E.g. 1234-2024')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="auth_date" class="flex items-center gap-2">
|
||||
<Calendar size={14} class="text-muted-foreground" />
|
||||
Fecha Autorización
|
||||
{t('Fecha Autorización', 'Authorization Date')}
|
||||
</Label>
|
||||
<Input
|
||||
id="auth_date"
|
||||
@@ -665,7 +671,7 @@
|
||||
<div class="grid gap-2">
|
||||
<Label for="prosec" class="flex items-center gap-2">
|
||||
<Factory size={14} class="text-muted-foreground" />
|
||||
PROSEC (Sector)
|
||||
PROSEC ({t('Sector', 'Sector')})
|
||||
</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
@@ -679,7 +685,7 @@
|
||||
size="icon"
|
||||
onclick={() => (sectorModalOpen = true)}
|
||||
disabled={loading}
|
||||
title="Buscar Sector"
|
||||
title={t('Buscar Sector', 'Search Sector')}
|
||||
>
|
||||
<Search size={16} />
|
||||
</Button>
|
||||
@@ -692,7 +698,7 @@
|
||||
<div class="space-y-4 pt-4">
|
||||
<div class="flex items-center gap-2 text-sm font-semibold text-white">
|
||||
<Fingerprint size={18} />
|
||||
<span>Identificación Industrial</span>
|
||||
<span>{t('Identificación Industrial', 'Industrial Identification')}</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
@@ -706,7 +712,7 @@
|
||||
bind:value={formData.manufacturer_id}
|
||||
maxlength={25}
|
||||
disabled={loading}
|
||||
placeholder="P. ej. MXABCD12345"
|
||||
placeholder={t('P. ej. MXABCD12345', 'E.g. MXABCD12345')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -716,7 +722,7 @@
|
||||
<div class="space-y-4 pt-4">
|
||||
<div class="flex items-center gap-2 text-sm font-semibold text-white">
|
||||
<ShieldCheck size={18} />
|
||||
<span>Certificaciones y Seguridad</span>
|
||||
<span>{t('Certificaciones y Seguridad', 'Certifications and Security')}</span>
|
||||
</div>
|
||||
<Separator />
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
@@ -730,7 +736,7 @@
|
||||
bind:value={formData.ctpat_svi}
|
||||
maxlength={100}
|
||||
disabled={loading}
|
||||
placeholder="P. ej. SVI-12345"
|
||||
placeholder={t('P. ej. SVI-12345', 'E.g. SVI-12345')}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 rounded-lg border bg-card/50 p-4">
|
||||
@@ -740,9 +746,9 @@
|
||||
disabled={loading}
|
||||
/>
|
||||
<div class="grid gap-0.5">
|
||||
<Label for="is_certified">Empresa Certificada</Label>
|
||||
<Label for="is_certified">{t('Empresa Certificada', 'Certified Company')}</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Indica si cuenta con certificación de empresa
|
||||
{t('Indica si cuenta con certificación de empresa', 'Indicates if it has company certification')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -756,17 +762,17 @@
|
||||
<Tabs.Content value="config">
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Configuración</Card.Title>
|
||||
<Card.Description>Ajustes de estado y atributos especiales.</Card.Description>
|
||||
<Card.Title>{t('Configuración', 'Settings')}</Card.Title>
|
||||
<Card.Description>{t('Ajustes de estado y atributos especiales.', 'Status settings and special attributes.')}</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-4">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<div class="flex items-center gap-3 rounded-lg border bg-card p-4">
|
||||
<Switch id="is_active" bind:checked={formData.is_active} disabled={loading} />
|
||||
<div class="grid gap-0.5">
|
||||
<Label for="is_active">Registro Activo</Label>
|
||||
<Label for="is_active">{t('Registro Activo', 'Active Record')}</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Habilitar o deshabilitar este socio comercial
|
||||
{t('Habilitar o deshabilitar este socio comercial', 'Enable or disable this business partner')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -789,16 +795,16 @@
|
||||
<div class="w-full overflow-x-auto pb-2">
|
||||
<Tabs.List class="inline-flex md:grid md:w-full md:grid-cols-4">
|
||||
<Tabs.Trigger value="general" class="whitespace-nowrap">
|
||||
<Building2 size={16} class="mr-2" /> General
|
||||
<Building2 size={16} class="mr-2" /> {t('General', 'General')}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="address" class="whitespace-nowrap">
|
||||
<MapPin size={16} class="mr-2" /> Dirección
|
||||
<MapPin size={16} class="mr-2" /> {t('Dirección', 'Address')}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="programs" class="whitespace-nowrap">
|
||||
<FileText size={16} class="mr-2" /> Programas
|
||||
<FileText size={16} class="mr-2" /> {t('Programas', 'Programs')}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="config" class="whitespace-nowrap">
|
||||
<Settings size={16} class="mr-2" /> Config
|
||||
<Settings size={16} class="mr-2" /> {t('Config', 'Config')}
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
@@ -806,20 +812,20 @@
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex justify-end gap-3">
|
||||
<Button variant="outline" onclick={handleCancel} disabled={loading}>Cancelar</Button>
|
||||
<Button variant="outline" onclick={handleCancel} disabled={loading}>{t('Cancelar', 'Cancel')}</Button>
|
||||
{#if !isEditing}
|
||||
<Button variant="outline" onclick={() => (formData = getEmptyForm())} disabled={loading}>
|
||||
<!-- <Trash2 size={16} class="mr-2" /> -->
|
||||
Limpiar
|
||||
{t('Limpiar', 'Clear')}
|
||||
</Button>
|
||||
{/if}
|
||||
<Button onclick={handleSubmit} disabled={loading}>
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
Guardando...
|
||||
{t('Guardando...', 'Saving...')}
|
||||
{:else}
|
||||
<Save size={16} class="mr-2" />
|
||||
{isEditing ? 'Actualizar Socio' : 'Guardar Socio'}
|
||||
{isEditing ? t('Actualizar Socio', 'Update Partner') : t('Guardar Socio', 'Save Partner')}
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user