feature/correccion-file-picker
This commit is contained in:
102
frontend/src/lib/components/ui/input/file-picker-input.svelte
Normal file
102
frontend/src/lib/components/ui/input/file-picker-input.svelte
Normal file
@@ -0,0 +1,102 @@
|
||||
<script lang="ts">
|
||||
import { Folder } from 'lucide-svelte';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
value = '',
|
||||
placeholder = 'Seleccionar archivo',
|
||||
accept = '',
|
||||
disabled = false,
|
||||
onchange,
|
||||
class: className = '',
|
||||
id = ''
|
||||
}: {
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
accept?: string;
|
||||
disabled?: boolean;
|
||||
onchange?: (file: File) => void;
|
||||
class?: string;
|
||||
id?: string;
|
||||
} = $props();
|
||||
|
||||
let fileInputEl: HTMLInputElement | null = $state(null);
|
||||
let buttonEl: HTMLButtonElement | null = $state(null);
|
||||
let focused = $state(false);
|
||||
|
||||
function handleButtonClick() {
|
||||
if (disabled) return;
|
||||
fileInputEl?.click();
|
||||
}
|
||||
|
||||
function handleContainerClick(event: MouseEvent) {
|
||||
if (disabled) return;
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.closest('button')) return;
|
||||
handleButtonClick();
|
||||
}
|
||||
|
||||
function handleFileChange(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
if (file) onchange?.(file);
|
||||
// Resetear para que el mismo archivo pueda re-seleccionarse
|
||||
input.value = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Contenedor unificado: el input de texto es sólo display (tabindex="-1"),
|
||||
el botón de carpeta recibe el foco y su focus-state dibuja el halo sobre ambos.
|
||||
-->
|
||||
<div
|
||||
class={cn(
|
||||
'border-input bg-background dark:bg-input/30 shadow-xs flex h-9 w-full items-center rounded-md border transition-[color,box-shadow]',
|
||||
!disabled && 'cursor-pointer',
|
||||
focused && 'border-ring ring-ring/50 ring-[3px]',
|
||||
disabled && 'cursor-not-allowed opacity-50',
|
||||
className
|
||||
)}
|
||||
onclick={handleContainerClick}
|
||||
>
|
||||
<!-- read-only display: sin tabstop, sin foco propio.
|
||||
Cuando value coincide con el placeholder (sin archivo seleccionado),
|
||||
dejamos value vacío para que el navegador muestre el placeholder muted. -->
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
value={value === placeholder ? '' : value}
|
||||
{placeholder}
|
||||
{disabled}
|
||||
class="placeholder:text-muted-foreground min-w-0 flex-1 border-0 bg-transparent px-3 py-1 text-base shadow-none outline-none md:text-sm"
|
||||
onfocus={() => buttonEl?.focus()}
|
||||
/>
|
||||
|
||||
<!-- input file real, oculto -->
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
{accept}
|
||||
{id}
|
||||
bind:this={fileInputEl}
|
||||
onchange={handleFileChange}
|
||||
/>
|
||||
|
||||
<!-- separador + botón, único elemento focusable -->
|
||||
<button
|
||||
type="button"
|
||||
{disabled}
|
||||
bind:this={buttonEl}
|
||||
class="hover:text-foreground text-muted-foreground flex h-full w-10 shrink-0 items-center justify-center rounded-r-md border-0 bg-transparent outline-none transition-colors disabled:cursor-not-allowed"
|
||||
onclick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleButtonClick();
|
||||
}}
|
||||
onfocus={() => (focused = true)}
|
||||
onblur={() => (focused = false)}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,7 +1,9 @@
|
||||
import Root from "./input.svelte";
|
||||
import FilePickerInput from "./file-picker-input.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Input,
|
||||
FilePickerInput,
|
||||
};
|
||||
|
||||
@@ -5,6 +5,8 @@ export const obtenerAtajosEdicionAgente = (acciones: {
|
||||
irContacto: () => void;
|
||||
irDireccion: () => void;
|
||||
irVU: () => void;
|
||||
irDoda: () => void;
|
||||
irAnam: () => void;
|
||||
guardar: () => void;
|
||||
cancelar: () => void;
|
||||
}): ShortcutDef[] => [
|
||||
@@ -28,6 +30,16 @@ export const obtenerAtajosEdicionAgente = (acciones: {
|
||||
description: 'Tab Ventanilla Única',
|
||||
action: acciones.irVU
|
||||
},
|
||||
{
|
||||
key: 'Alt+Digit5',
|
||||
description: 'Tab DODA',
|
||||
action: acciones.irDoda
|
||||
},
|
||||
{
|
||||
key: 'Alt+Digit6',
|
||||
description: 'Tab ANAM',
|
||||
action: acciones.irAnam
|
||||
},
|
||||
{
|
||||
key: 'Ctrl+S',
|
||||
description: 'Guardar',
|
||||
|
||||
@@ -11,6 +11,11 @@ export const obtenerAtajosFormularioEmpresa = (acciones: {
|
||||
{ key: 'Alt+Digit4', description: 'Pestaña Certificaciones', action: () => acciones.cambiarPestana('certificaciones') },
|
||||
{ key: 'Alt+Digit5', description: 'Pestaña Direcciones', action: () => acciones.cambiarPestana('direcciones') },
|
||||
{ key: 'Alt+Digit6', description: 'Pestaña Config', action: () => acciones.cambiarPestana('config') },
|
||||
{
|
||||
key: 'Alt+Digit7',
|
||||
description: 'Pestaña Certificados Digitales',
|
||||
action: () => acciones.cambiarPestana('certificados')
|
||||
},
|
||||
{
|
||||
key: 'Control+KeyS',
|
||||
description: 'Guardar Empresa',
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import CountryDialog from '$lib/components/dashboard/invoices/edit/items/fa/country-dialog.svelte';
|
||||
import StateDialog from '$lib/components/dashboard/invoices/edit/items/fa/state-dialog.svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Input, FilePickerInput } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
@@ -32,7 +32,6 @@
|
||||
FileKey,
|
||||
Key,
|
||||
Globe,
|
||||
Folder,
|
||||
Mail,
|
||||
UserRound,
|
||||
Fingerprint,
|
||||
@@ -127,21 +126,6 @@
|
||||
});
|
||||
|
||||
// --- 5. FUNCIONES ---
|
||||
function handleLocalFileSelect(event: Event, targetKey: keyof typeof vuData) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
if (file) {
|
||||
vuData[targetKey] = file.name;
|
||||
if (targetKey === 'certificate_path') pendingVuFiles.certificate = file;
|
||||
if (targetKey === 'key_path') pendingVuFiles.key = file;
|
||||
if (targetKey === 'xml_files_path') pendingVuFiles.cove = file;
|
||||
if (targetKey === 'doda_certificate_path') pendingVuFiles.dodaCertificate = file;
|
||||
if (targetKey === 'doda_key_path') pendingVuFiles.dodaKey = file;
|
||||
if (targetKey === 'doda_xml_files_path') pendingVuFiles.dodaCove = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadPendingVuFiles(companyId: string, brokerKey: string) {
|
||||
if (pendingVuFiles.certificate) {
|
||||
const res = await uploadCustomsBrokerVuFile(
|
||||
@@ -408,6 +392,8 @@
|
||||
irContacto: () => (activeTab = 'contact'),
|
||||
irDireccion: () => (activeTab = 'address'),
|
||||
irVU: () => (activeTab = 'vu'),
|
||||
irDoda: () => (activeTab = 'doda'),
|
||||
irAnam: () => (activeTab = 'anam'),
|
||||
guardar: handleSave,
|
||||
cancelar: handleCancel
|
||||
})
|
||||
@@ -791,35 +777,17 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.certificate_path,
|
||||
'CER',
|
||||
'Seleccionar archivo .cer'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'certificate_path')}
|
||||
id="vu-cert-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('vu-cert-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.certificate_path, 'CER', 'Seleccionar archivo .cer')}
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
accept=".cer"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.certificate_path = file.name;
|
||||
pendingVuFiles.certificate = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label
|
||||
@@ -828,35 +796,17 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.key_path,
|
||||
'KEY',
|
||||
'Seleccionar archivo .key'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo .key"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'key_path')}
|
||||
id="vu-key-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('vu-key-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.key_path, 'KEY', 'Seleccionar archivo .key')}
|
||||
placeholder="Seleccionar archivo .key"
|
||||
accept=".key"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.key_path = file.name;
|
||||
pendingVuFiles.key = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -884,7 +834,7 @@
|
||||
/></Label
|
||||
>
|
||||
<Select.Root type="single" bind:value={vuData.vu_figure_type} disabled={loading}>
|
||||
<Select.Trigger class="h-10">
|
||||
<Select.Trigger class="h-10 w-full">
|
||||
{vuData.vu_figure_type || 'Seleccionar tipo de figura'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
@@ -936,35 +886,16 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.xml_files_path,
|
||||
'COVE',
|
||||
'Seleccionar archivo COVE'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo COVE"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'xml_files_path')}
|
||||
id="vu-cove-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('vu-cove-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.xml_files_path, 'COVE', 'Seleccionar archivo COVE')}
|
||||
placeholder="Seleccionar archivo COVE"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.xml_files_path = file.name;
|
||||
pendingVuFiles.cove = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1062,35 +993,17 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.doda_certificate_path,
|
||||
'CER',
|
||||
'Seleccionar archivo .cer'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'doda_certificate_path')}
|
||||
id="doda-cert-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('doda-cert-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.doda_certificate_path, 'CER', 'Seleccionar archivo .cer')}
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
accept=".cer"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.doda_certificate_path = file.name;
|
||||
pendingVuFiles.dodaCertificate = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label
|
||||
@@ -1099,35 +1012,17 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.doda_key_path,
|
||||
'KEY',
|
||||
'Seleccionar archivo .key'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo .key"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'doda_key_path')}
|
||||
id="doda-key-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('doda-key-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.doda_key_path, 'KEY', 'Seleccionar archivo .key')}
|
||||
placeholder="Seleccionar archivo .key"
|
||||
accept=".key"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.doda_key_path = file.name;
|
||||
pendingVuFiles.dodaKey = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1154,35 +1049,16 @@
|
||||
class="ml-1 inline text-muted-foreground"
|
||||
/></Label
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={getFileDisplayName(
|
||||
vuData.doda_xml_files_path,
|
||||
'XML',
|
||||
'Seleccionar archivo XML'
|
||||
)}
|
||||
readonly
|
||||
placeholder="Seleccionar archivo XML"
|
||||
disabled={loading}
|
||||
class="h-10 flex-1"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
onchange={(e) => handleLocalFileSelect(e, 'doda_xml_files_path')}
|
||||
id="doda-xml-file"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="h-10 w-10 shrink-0"
|
||||
disabled={loading}
|
||||
onclick={() => document.getElementById('doda-xml-file')?.click()}
|
||||
>
|
||||
<Folder class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(vuData.doda_xml_files_path, 'XML', 'Seleccionar archivo XML')}
|
||||
placeholder="Seleccionar archivo XML"
|
||||
disabled={loading}
|
||||
onchange={(file) => {
|
||||
vuData.doda_xml_files_path = file.name;
|
||||
pendingVuFiles.dodaCove = file;
|
||||
toast.success(`Archivo ${file.name} seleccionado`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input, FilePickerInput } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Tabs from '$lib/components/ui/tabs';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
@@ -460,66 +460,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCertificateSelect(event: Event, type: string) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const file = target.files?.[0];
|
||||
|
||||
if (!file) return;
|
||||
|
||||
// Validar extensión de forma estricta según el tipo de campo:
|
||||
// - *_cer => solo .cer
|
||||
// - *_key => solo .key
|
||||
async function handleCertificateFile(file: File, type: string) {
|
||||
const ext = file.name.split('.').pop()?.toLowerCase();
|
||||
if (type.toLowerCase().endsWith('_cer') && ext !== 'cer') {
|
||||
error = 'El archivo debe ser .cer';
|
||||
target.value = ''; // Reset
|
||||
return;
|
||||
}
|
||||
if (type.toLowerCase().endsWith('_key') && ext !== 'key') {
|
||||
error = 'El archivo debe ser .key';
|
||||
target.value = ''; // Reset
|
||||
return;
|
||||
}
|
||||
|
||||
// Validar tamaño (5MB)
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
error = 'El archivo es demasiado grande. Máximo 5MB';
|
||||
target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEdit) {
|
||||
error = 'Debes guardar la empresa primero antes de subir certificados.';
|
||||
target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
successMessage = null;
|
||||
|
||||
try {
|
||||
const response = await uploadCompanyCertificate(Number(id), type, file);
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
// Actualizar el valor en el formulario para reflejar que hay un archivo
|
||||
// Nota: La respuesta trae file_path
|
||||
if (response.error) throw new Error(response.error);
|
||||
if (response.data) {
|
||||
const path = response.data.file_path;
|
||||
// Actualizar el campo correspondiente en formData
|
||||
// type coincide con las claves del formData (fiel_cer, fiel_key, etc.)
|
||||
(formData as any)[type] = path;
|
||||
(formData as any)[type] = response.data.file_path;
|
||||
successMessage = `Certificado ${type} subido correctamente`;
|
||||
|
||||
// Opcional: recargar datos completos para asegurar consistencia
|
||||
// await fetchData(String(id));
|
||||
}
|
||||
} catch (e: any) {
|
||||
error = `Error al subir certificado: ${e.message}`;
|
||||
target.value = '';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
@@ -1600,47 +1570,23 @@
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="fiel_cer">Archivo .CER</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="fiel_cer"
|
||||
type="file"
|
||||
accept=".cer"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'fiel_cer')}
|
||||
/>
|
||||
<Label
|
||||
for="fiel_cer"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(formData.fiel_cer, 'CER', 'Seleccionar archivo .cer')}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.fiel_cer, 'CER', 'Seleccionar archivo .cer')}
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
accept=".cer"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'fiel_cer')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fiel_key">Archivo .KEY</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="fiel_key"
|
||||
type="file"
|
||||
accept=".key"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'fiel_key')}
|
||||
/>
|
||||
<Label
|
||||
for="fiel_key"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(formData.fiel_key, 'KEY', 'Seleccionar archivo .key')}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.fiel_key, 'KEY', 'Seleccionar archivo .key')}
|
||||
placeholder="Seleccionar archivo .key"
|
||||
accept=".key"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'fiel_key')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fiel_pass">Contraseña</Label>
|
||||
@@ -1670,55 +1616,23 @@
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="cfdi_cert_cer">Archivo .CER</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="cfdi_cert_cer"
|
||||
type="file"
|
||||
accept=".cer"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'cfdi_cert_cer')}
|
||||
/>
|
||||
<Label
|
||||
for="cfdi_cert_cer"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(
|
||||
formData.cfdi_cert_cer,
|
||||
'CER',
|
||||
'Seleccionar archivo .cer'
|
||||
)}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.cfdi_cert_cer, 'CER', 'Seleccionar archivo .cer')}
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
accept=".cer"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'cfdi_cert_cer')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="cfdi_cert_key">Archivo .KEY</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="cfdi_cert_key"
|
||||
type="file"
|
||||
accept=".key"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'cfdi_cert_key')}
|
||||
/>
|
||||
<Label
|
||||
for="cfdi_cert_key"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(
|
||||
formData.cfdi_cert_key,
|
||||
'KEY',
|
||||
'Seleccionar archivo .key'
|
||||
)}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.cfdi_cert_key, 'KEY', 'Seleccionar archivo .key')}
|
||||
placeholder="Seleccionar archivo .key"
|
||||
accept=".key"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'cfdi_cert_key')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="cfdi_cert_pass">Contraseña</Label>
|
||||
@@ -1760,47 +1674,23 @@
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid gap-2">
|
||||
<Label for="cancel_cer">Archivo .CER</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="cancel_cer"
|
||||
type="file"
|
||||
accept=".cer"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'cancel_cer')}
|
||||
/>
|
||||
<Label
|
||||
for="cancel_cer"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(formData.cancel_cer, 'CER', 'Seleccionar archivo .cer')}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.cancel_cer, 'CER', 'Seleccionar archivo .cer')}
|
||||
placeholder="Seleccionar archivo .cer"
|
||||
accept=".cer"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'cancel_cer')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="cancel_key">Archivo .KEY</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
id="cancel_key"
|
||||
type="file"
|
||||
accept=".key"
|
||||
class="hidden"
|
||||
onchange={(e) => handleCertificateSelect(e, 'cancel_key')}
|
||||
/>
|
||||
<Label
|
||||
for="cancel_key"
|
||||
class={buttonVariants({ variant: 'outline', size: 'default' }) +
|
||||
' w-full cursor-pointer justify-start text-left font-normal'}
|
||||
>
|
||||
<Upload class="mr-2 h-4 w-4" />
|
||||
<span class="truncate">
|
||||
{getFileDisplayName(formData.cancel_key, 'KEY', 'Seleccionar archivo .key')}
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<FilePickerInput
|
||||
value={getFileDisplayName(formData.cancel_key, 'KEY', 'Seleccionar archivo .key')}
|
||||
placeholder="Seleccionar archivo .key"
|
||||
accept=".key"
|
||||
disabled={loading}
|
||||
onchange={(file) => handleCertificateFile(file, 'cancel_key')}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="cancel_pass">Contraseña</Label>
|
||||
|
||||
Reference in New Issue
Block a user