feat(admin): new AdminBusinessEditor with live mobile preview + fix admin logout bug on file picker timeout
This commit is contained in:
@ -24,11 +24,7 @@ const categories = ['Todas', 'Restaurante', 'Turismo', 'Bebidas', 'Comercio']
|
||||
|
||||
// Modals
|
||||
const showModal = ref(false)
|
||||
const showBusinessModal = ref(false)
|
||||
const isEditing = ref(false)
|
||||
const isEditingBusiness = ref(false)
|
||||
const businessImageFile = ref<File | null>(null)
|
||||
const businessImagePreview = ref<string | null>(null)
|
||||
|
||||
|
||||
// Current data
|
||||
@ -47,24 +43,6 @@ const currentCoupon = ref<Partial<Coupon>>({
|
||||
is_active: true
|
||||
})
|
||||
|
||||
const currentBusiness = ref<Partial<Business>>({
|
||||
name: '',
|
||||
address: '',
|
||||
phone: '',
|
||||
image_url: '',
|
||||
social_media: '',
|
||||
category: 'Restaurante',
|
||||
area: 'Boquete',
|
||||
description: '',
|
||||
website: '',
|
||||
// Template fields
|
||||
schedule: '',
|
||||
whatsapp: '',
|
||||
instagram: '',
|
||||
facebook: '',
|
||||
gallery_images: []
|
||||
})
|
||||
|
||||
const userName = localStorage.getItem('user_name') || 'Promotor'
|
||||
|
||||
onMounted(async () => {
|
||||
@ -174,82 +152,15 @@ async function deleteShuttle(id: string) {
|
||||
}
|
||||
|
||||
// Business Methods
|
||||
import { useRouter } from 'vue-router'
|
||||
const localRouter = useRouter()
|
||||
|
||||
function openCreateBusinessModal() {
|
||||
isEditingBusiness.value = false
|
||||
currentBusiness.value = {
|
||||
name: '',
|
||||
address: '',
|
||||
phone: '',
|
||||
image_url: '',
|
||||
social_media: '',
|
||||
category: 'Restaurante',
|
||||
area: 'Boquete',
|
||||
description: '',
|
||||
website: '',
|
||||
schedule: '',
|
||||
whatsapp: '',
|
||||
instagram: '',
|
||||
facebook: '',
|
||||
gallery_images: []
|
||||
}
|
||||
showBusinessModal.value = true
|
||||
businessImageFile.value = null
|
||||
businessImagePreview.value = null
|
||||
}
|
||||
|
||||
|
||||
function handleBusinessImage(event: any) {
|
||||
const file = event.target.files[0]
|
||||
if (file) {
|
||||
businessImageFile.value = file
|
||||
businessImagePreview.value = URL.createObjectURL(file)
|
||||
}
|
||||
localRouter.push('/admin/business-edit/new')
|
||||
}
|
||||
|
||||
function openEditBusinessModal(biz: Business) {
|
||||
isEditingBusiness.value = true
|
||||
currentBusiness.value = { ...biz }
|
||||
showBusinessModal.value = true
|
||||
businessImageFile.value = null
|
||||
businessImagePreview.value = getImageUrl(biz.image_url)
|
||||
}
|
||||
|
||||
async function saveBusiness() {
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('name', currentBusiness.value.name || '')
|
||||
formData.append('category', currentBusiness.value.category || 'Restaurante')
|
||||
formData.append('address', currentBusiness.value.address || '')
|
||||
formData.append('phone', currentBusiness.value.phone || '')
|
||||
formData.append('social_media', currentBusiness.value.social_media || '')
|
||||
formData.append('area', currentBusiness.value.area || 'Boquete')
|
||||
formData.append('description', currentBusiness.value.description || '')
|
||||
formData.append('website', currentBusiness.value.website || '')
|
||||
// Template fields
|
||||
formData.append('schedule', currentBusiness.value.schedule || '')
|
||||
formData.append('whatsapp', currentBusiness.value.whatsapp || '')
|
||||
formData.append('instagram', currentBusiness.value.instagram || '')
|
||||
formData.append('facebook', currentBusiness.value.facebook || '')
|
||||
// gallery_images handled separately via JSON
|
||||
if (currentBusiness.value.gallery_images?.length) {
|
||||
formData.append('gallery_images', JSON.stringify(currentBusiness.value.gallery_images))
|
||||
}
|
||||
|
||||
if (businessImageFile.value) {
|
||||
formData.append('image', businessImageFile.value)
|
||||
}
|
||||
|
||||
if (isEditingBusiness.value && currentBusiness.value.id) {
|
||||
await businessService.updateBusiness(currentBusiness.value.id, formData)
|
||||
} else {
|
||||
await businessService.createBusiness(formData)
|
||||
}
|
||||
showBusinessModal.value = false
|
||||
await loadBusinesses()
|
||||
} catch (e) {
|
||||
console.error('Error saving business:', e)
|
||||
alert('Error al guardar el negocio')
|
||||
}
|
||||
localRouter.push(`/admin/business-edit/${biz.id}`)
|
||||
}
|
||||
|
||||
async function deleteBusiness(id: string) {
|
||||
@ -704,125 +615,6 @@ async function toggleCouponStatus(coupon: Coupon) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Business Modal -->
|
||||
<div v-if="showBusinessModal" class="modal-overlay" @click.self="showBusinessModal = false">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>{{ isEditingBusiness ? 'Editar Negocio' : 'Registrar Negocio' }}</h2>
|
||||
<button class="close-btn" @click="showBusinessModal = false"><span class="material-icons">close</span></button>
|
||||
</div>
|
||||
<form @submit.prevent="saveBusiness" class="coupon-form">
|
||||
|
||||
<!-- ── Info básica ── -->
|
||||
<div class="form-section-label">📋 Información Básica</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Nombre del Negocio *</label>
|
||||
<input v-model="currentBusiness.name" type="text" required placeholder="Ej: Restaurante La Casona">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Categoría</label>
|
||||
<select v-model="currentBusiness.category">
|
||||
<option value="Restaurante">Restaurante</option>
|
||||
<option value="Hotel">Hotel</option>
|
||||
<option value="Café">Café</option>
|
||||
<option value="Bebidas">Bar / Bebidas</option>
|
||||
<option value="Comercio">Comercio</option>
|
||||
<option value="Turismo">Turismo</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Área / Región</label>
|
||||
<select v-model="currentBusiness.area">
|
||||
<option value="Boquete">Boquete</option>
|
||||
<option value="Alto Boquete">Alto Boquete</option>
|
||||
<option value="Dolega">Dolega</option>
|
||||
<option value="David">David</option>
|
||||
<option value="Caldera">Caldera</option>
|
||||
<option value="Chiriquí">Chiriquí</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Teléfono</label>
|
||||
<input v-model="currentBusiness.phone" type="text" placeholder="+507 6000-0000">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>🕐 Horario de Atención</label>
|
||||
<input v-model="currentBusiness.schedule" type="text" placeholder="Ej: Lun-Sáb 8am-10pm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Dirección Física</label>
|
||||
<input v-model="currentBusiness.address" type="text" placeholder="Ej: Calle Principal #123, Frente al Parque">
|
||||
</div>
|
||||
|
||||
<!-- ── Imagen principal ── -->
|
||||
<div class="form-section-label">🖼️ Imagen de Portada</div>
|
||||
<div class="form-group">
|
||||
<label>Foto Principal (Logo o Fachada)</label>
|
||||
<div class="file-upload-wrapper">
|
||||
<input type="file" @change="handleBusinessImage" accept="image/*" class="file-input">
|
||||
<div class="file-preview" v-if="businessImagePreview">
|
||||
<img :src="businessImagePreview" alt="Vista previa">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Descripción ── -->
|
||||
<div class="form-section-label">📝 Descripción</div>
|
||||
<div class="form-group">
|
||||
<label>Sobre el Negocio (Texto de marketing)</label>
|
||||
<textarea v-model="currentBusiness.description" placeholder="Describe la experiencia del lugar, su especialidad y ambiente para atraer clientes..." rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- ── Redes Sociales y Contacto ── -->
|
||||
<div class="form-section-label">🌐 Contacto y Redes Sociales</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>💬 WhatsApp</label>
|
||||
<input v-model="currentBusiness.whatsapp" type="text" placeholder="50760000000 (con código de país)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>📸 Instagram</label>
|
||||
<input v-model="currentBusiness.instagram" type="text" placeholder="@usuario">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>👍 Facebook</label>
|
||||
<input v-model="currentBusiness.facebook" type="text" placeholder="/nombre-de-pagina">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>🌐 Página Web</label>
|
||||
<input v-model="currentBusiness.website" type="url" placeholder="https://www.ejemplo.com">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Galería ── -->
|
||||
<div class="form-section-label">📸 Galería de Imágenes (Carrusel)</div>
|
||||
<div class="form-group">
|
||||
<label>URLs de fotos adicionales (una por línea)</label>
|
||||
<textarea
|
||||
:value="currentBusiness.gallery_images?.join('\n') || ''"
|
||||
@input="(e: any) => currentBusiness.gallery_images = e.target.value.split('\n').map((s: string) => s.trim()).filter((s: string) => s.length > 0)"
|
||||
placeholder="https://url-foto1.jpg https://url-foto2.jpg https://url-foto3.jpg"
|
||||
rows="3"
|
||||
></textarea>
|
||||
<small class="form-hint">Agrega URLs de imágenes para el carrusel (menú, ambiente, experiencias). Una URL por línea.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="submit-btn">
|
||||
<span class="material-icons">{{ isEditingBusiness ? 'save' : 'store' }}</span>
|
||||
{{ isEditingBusiness ? 'Guardar Cambios' : 'Publicar Negocio' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user