All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m8s
- Backend: Nuevo soporte en endpoint /send para tipos contact, poll, event - UI: Modales para crear y enviar contactos, encuestas y eventos - Visualización: Componentes MessagePoll y MessageEvent para mostrar mensajes recibidos - Tipos: Agregar PollInfo, EventInfo y tipo 'event' a MessageType
258 lines
7.0 KiB
Vue
258 lines
7.0 KiB
Vue
<template>
|
|
<UModal v-model:open="isOpen">
|
|
<template #content>
|
|
<UCard>
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-lg font-semibold text-white">Crear Evento</h3>
|
|
<UButton
|
|
variant="ghost"
|
|
icon="i-lucide-x"
|
|
size="sm"
|
|
@click="isOpen = false"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="space-y-4 max-h-[60vh] overflow-y-auto">
|
|
<!-- Event name -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Nombre del evento *
|
|
</label>
|
|
<UInput
|
|
v-model="eventName"
|
|
placeholder="Reunión de equipo"
|
|
icon="i-lucide-calendar"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Start date/time -->
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Fecha inicio *
|
|
</label>
|
|
<UInput
|
|
v-model="startDate"
|
|
type="date"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Hora inicio *
|
|
</label>
|
|
<UInput
|
|
v-model="startTime"
|
|
type="time"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- End date/time (optional) -->
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<UCheckbox v-model="hasEndDate" />
|
|
<span class="text-sm text-[var(--wa-text-muted)]">Agregar fecha de fin</span>
|
|
</div>
|
|
|
|
<div v-if="hasEndDate" class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Fecha fin
|
|
</label>
|
|
<UInput
|
|
v-model="endDate"
|
|
type="date"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Hora fin
|
|
</label>
|
|
<UInput
|
|
v-model="endTime"
|
|
type="time"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--wa-text-muted)] mb-1">
|
|
Descripción (opcional)
|
|
</label>
|
|
<UTextarea
|
|
v-model="description"
|
|
placeholder="Detalles del evento..."
|
|
:rows="2"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Location -->
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<UCheckbox v-model="hasLocation" />
|
|
<span class="text-sm text-[var(--wa-text-muted)]">Agregar ubicación</span>
|
|
</div>
|
|
|
|
<div v-if="hasLocation" class="space-y-3 p-3 rounded-lg bg-[var(--wa-bg-light)]">
|
|
<UInput
|
|
v-model="locationName"
|
|
placeholder="Nombre del lugar"
|
|
icon="i-lucide-map-pin"
|
|
/>
|
|
<UInput
|
|
v-model="locationAddress"
|
|
placeholder="Dirección"
|
|
icon="i-lucide-navigation"
|
|
/>
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<UInput
|
|
v-model.number="latitude"
|
|
type="number"
|
|
step="any"
|
|
placeholder="Latitud"
|
|
/>
|
|
<UInput
|
|
v-model.number="longitude"
|
|
type="number"
|
|
step="any"
|
|
placeholder="Longitud"
|
|
/>
|
|
</div>
|
|
<p class="text-xs text-[var(--wa-text-muted)]">
|
|
Las coordenadas son opcionales pero permiten mostrar el mapa
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<div class="flex justify-end gap-2">
|
|
<UButton variant="ghost" @click="isOpen = false">
|
|
Cancelar
|
|
</UButton>
|
|
<UButton
|
|
:disabled="!isValid"
|
|
:loading="isSending"
|
|
@click="handleSend"
|
|
>
|
|
Crear evento
|
|
</UButton>
|
|
</div>
|
|
</template>
|
|
</UCard>
|
|
</template>
|
|
</UModal>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
interface EventData {
|
|
name: string
|
|
startDate: string
|
|
endDate?: string
|
|
description?: string
|
|
location?: {
|
|
name?: string
|
|
address?: string
|
|
latitude?: number
|
|
longitude?: number
|
|
}
|
|
}
|
|
|
|
const isOpen = defineModel<boolean>('open', { default: false })
|
|
|
|
const emit = defineEmits<{
|
|
send: [event: EventData]
|
|
}>()
|
|
|
|
const isSending = ref(false)
|
|
|
|
// Form fields
|
|
const eventName = ref('')
|
|
const startDate = ref('')
|
|
const startTime = ref('')
|
|
const hasEndDate = ref(false)
|
|
const endDate = ref('')
|
|
const endTime = ref('')
|
|
const description = ref('')
|
|
const hasLocation = ref(false)
|
|
const locationName = ref('')
|
|
const locationAddress = ref('')
|
|
const latitude = ref<number | undefined>(undefined)
|
|
const longitude = ref<number | undefined>(undefined)
|
|
|
|
const isValid = computed(() => {
|
|
return eventName.value.trim() && startDate.value && startTime.value
|
|
})
|
|
|
|
const handleSend = async () => {
|
|
if (!isValid.value) return
|
|
|
|
isSending.value = true
|
|
try {
|
|
const startDateTime = new Date(`${startDate.value}T${startTime.value}`)
|
|
|
|
const eventData: EventData = {
|
|
name: eventName.value.trim(),
|
|
startDate: startDateTime.toISOString()
|
|
}
|
|
|
|
if (hasEndDate.value && endDate.value && endTime.value) {
|
|
const endDateTime = new Date(`${endDate.value}T${endTime.value}`)
|
|
eventData.endDate = endDateTime.toISOString()
|
|
}
|
|
|
|
if (description.value.trim()) {
|
|
eventData.description = description.value.trim()
|
|
}
|
|
|
|
if (hasLocation.value) {
|
|
eventData.location = {}
|
|
if (locationName.value.trim()) {
|
|
eventData.location.name = locationName.value.trim()
|
|
}
|
|
if (locationAddress.value.trim()) {
|
|
eventData.location.address = locationAddress.value.trim()
|
|
}
|
|
if (latitude.value !== undefined && longitude.value !== undefined) {
|
|
eventData.location.latitude = latitude.value
|
|
eventData.location.longitude = longitude.value
|
|
}
|
|
}
|
|
|
|
emit('send', eventData)
|
|
|
|
// Reset form
|
|
resetForm()
|
|
isOpen.value = false
|
|
} finally {
|
|
isSending.value = false
|
|
}
|
|
}
|
|
|
|
const resetForm = () => {
|
|
eventName.value = ''
|
|
startDate.value = ''
|
|
startTime.value = ''
|
|
hasEndDate.value = false
|
|
endDate.value = ''
|
|
endTime.value = ''
|
|
description.value = ''
|
|
hasLocation.value = false
|
|
locationName.value = ''
|
|
locationAddress.value = ''
|
|
latitude.value = undefined
|
|
longitude.value = undefined
|
|
}
|
|
|
|
// Reset form when modal opens
|
|
watch(isOpen, (open) => {
|
|
if (open) {
|
|
resetForm()
|
|
// Set default start date to today
|
|
const today = new Date()
|
|
startDate.value = today.toISOString().split('T')[0]
|
|
startTime.value = '12:00'
|
|
}
|
|
})
|
|
</script>
|