262 lines
7.6 KiB
Vue

<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import Dialog from 'primevue/dialog';
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import Dropdown from 'primevue/dropdown';
import InputSwitch from 'primevue/inputswitch';
import { satUnitsService } from '../../services/sat-units.services';
import type { UnitOfMeasure, CreateUnitOfMeasureData, SatUnit } from '../../types/unit-measure.interfaces';
interface Props {
visible: boolean;
unit?: UnitOfMeasure | null;
isEditing?: boolean;
}
interface Emits {
(e: 'update:visible', value: boolean): void;
(e: 'save', data: CreateUnitOfMeasureData): void;
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
unit: null,
isEditing: false
});
const emit = defineEmits<Emits>();
// Form data
const formData = ref<CreateUnitOfMeasureData>({
name: '',
abbreviation: '',
code_sat: 1,
is_active: 1
});
// Estado interno del switch (boolean para el UI)
const isActiveSwitch = ref(true);
// SAT Units
const satUnits = ref<SatUnit[]>([]);
const loadingSatUnits = ref(false);
const searchQuery = ref('');
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
// Options para el dropdown
const satUnitOptions = computed(() =>
satUnits.value.map(unit => ({
label: `${unit.code} - ${unit.name}`,
value: unit.id
}))
);
// Computed
const dialogTitle = computed(() =>
props.isEditing ? 'Editar Unidad de Medida' : 'Nueva Unidad de Medida'
);
const isFormValid = computed(() => {
return !!(formData.value.name && formData.value.abbreviation);
});
const emptyMessage = computed(() => {
if (props.isEditing && satUnits.value.length === 1) {
return 'Escribe para buscar otra unidad SAT...';
}
return 'No se encontraron unidades. Escribe para buscar.';
});
// Load SAT Units
const loadSatUnits = async (search: string) => {
// Solo buscar si hay texto
if (!search || search.trim().length === 0) {
// Si estamos editando y hay una unidad actual, mantenerla
if (props.unit?.sat_unit) {
satUnits.value = [props.unit.sat_unit];
} else {
satUnits.value = [];
}
return;
}
try {
loadingSatUnits.value = true;
const response = await satUnitsService.getSatUnits(search);
satUnits.value = response.data;
} catch (error) {
console.error('Error loading SAT units:', error);
// Si hay error y estamos editando, mantener la unidad actual
if (props.unit?.sat_unit) {
satUnits.value = [props.unit.sat_unit];
} else {
satUnits.value = [];
}
} finally {
loadingSatUnits.value = false;
}
};
// Debounced search
const handleSearchChange = (event: any) => {
const query = event.value || '';
searchQuery.value = query;
// Limpiar timeout anterior
if (searchTimeout) {
clearTimeout(searchTimeout);
}
// Aplicar debounce de 500ms
searchTimeout = setTimeout(() => {
loadSatUnits(query);
}, 500);
};
// Methods
const resetForm = () => {
formData.value = {
name: '',
abbreviation: '',
code_sat: null,
is_active: 1
};
isActiveSwitch.value = true;
};
// Watch para actualizar el formulario cuando cambie la unidad
watch(() => props.unit, (newUnit) => {
if (newUnit) {
formData.value = {
name: newUnit.name,
abbreviation: newUnit.abbreviation,
code_sat: newUnit.code_sat,
is_active: newUnit.is_active
};
isActiveSwitch.value = newUnit.is_active === 1;
// Precargar la unidad SAT actual en el dropdown
if (newUnit.sat_unit) {
satUnits.value = [newUnit.sat_unit];
}
} else {
resetForm();
satUnits.value = []; // Limpiar el dropdown
}
}, { immediate: true });
const handleClose = () => {
emit('update:visible', false);
satUnits.value = []; // Limpiar las opciones del dropdown
resetForm();
};
const handleSave = () => {
// Convertir el switch boolean a number para el backend
formData.value.is_active = isActiveSwitch.value ? 1 : 0;
emit('save', { ...formData.value });
handleClose();
};
</script>
<template>
<Dialog
:visible="visible"
@update:visible="emit('update:visible', $event)"
:header="dialogTitle"
:modal="true"
:closable="true"
:draggable="false"
class="w-full max-w-md"
>
<div class="space-y-4 pt-4">
<!-- Name -->
<div>
<label for="name" class="block text-sm font-medium mb-2">
Nombre <span class="text-red-500">*</span>
</label>
<InputText
id="name"
v-model="formData.name"
class="w-full"
placeholder="Ej: PIEZA, KILOGRAMO, METRO"
:required="true"
/>
</div>
<!-- Abbreviation -->
<div>
<label for="abbreviation" class="block text-sm font-medium mb-2">
Abreviatura <span class="text-red-500">*</span>
</label>
<InputText
id="abbreviation"
v-model="formData.abbreviation"
class="w-full"
placeholder="Ej: PZA, kg, m"
:required="true"
/>
</div>
<!-- Code SAT -->
<div>
<label for="code_sat" class="block text-sm font-medium mb-2">
Unidad SAT <span class="text-red-500">*</span>
</label>
<Dropdown
id="code_sat"
v-model="formData.code_sat"
:options="satUnitOptions"
optionLabel="label"
optionValue="value"
:loading="loadingSatUnits"
placeholder="Escribe para buscar una unidad SAT..."
class="w-full"
:filter="true"
filterPlaceholder="Buscar unidad SAT"
:showClear="false"
@filter="handleSearchChange"
:emptyFilterMessage="emptyMessage"
/>
<small class="text-surface-500 dark:text-surface-400">
Unidad del catálogo SAT
</small>
</div>
<!-- Status -->
<div>
<label for="is_active" class="block text-sm font-medium mb-2">
Estado
</label>
<div class="flex items-center gap-3">
<InputSwitch
id="is_active"
v-model="isActiveSwitch"
/>
<span class="text-sm font-medium">
{{ isActiveSwitch ? 'Activa' : 'Inactiva' }}
</span>
</div>
</div>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<Button
label="Cancelar"
severity="secondary"
outlined
@click="handleClose"
/>
<Button
:label="isEditing ? 'Actualizar' : 'Crear'"
:disabled="!isFormValid"
@click="handleSave"
/>
</div>
</template>
</Dialog>
</template>