486 lines
11 KiB
Vue
486 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { businessService } from '@/services/businessService'
|
|
import { couponsService } from '@/services/couponsService'
|
|
import { API_URL } from '@/services/apiClient'
|
|
import type { Business, Coupon } from '@/types'
|
|
import FavoriteButton from '@/components/FavoriteButton.vue'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const business = ref<Business | null>(null)
|
|
const coupons = ref<Coupon[]>([])
|
|
const isLoading = ref(true)
|
|
|
|
import { analyticsService } from '@/services/analyticsService'
|
|
|
|
onMounted(async () => {
|
|
const id = route.params.id as string
|
|
try {
|
|
const [bizData, allCoupons] = await Promise.all([
|
|
businessService.getBusiness(id),
|
|
couponsService.getAllCoupons({ active_only: true })
|
|
])
|
|
business.value = bizData
|
|
// Filter coupons for this business
|
|
coupons.value = allCoupons.filter(c => c.business_id === id)
|
|
|
|
analyticsService.logEvent({
|
|
event_name: 'screen_view',
|
|
screen_name: 'BusinessDetails',
|
|
item_id: bizData.name,
|
|
properties: { business_id: id }
|
|
})
|
|
} catch (e) {
|
|
console.error('Failed to load business details', e)
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
})
|
|
|
|
function getImageUrl(path: string | null | undefined) {
|
|
if (!path) return '/default-business.jpg'
|
|
if (path.startsWith('http')) return path
|
|
return `${API_URL}${path.startsWith('/') ? '' : '/'}${path}`
|
|
}
|
|
|
|
const goBack = () => router.back()
|
|
|
|
function handleDirections() {
|
|
analyticsService.logEvent({
|
|
event_name: 'promo_click',
|
|
item_id: 'directions_' + business.value?.name,
|
|
properties: {
|
|
business_id: business.value?.id,
|
|
action: 'get_directions'
|
|
}
|
|
})
|
|
window.open(`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(business.value?.address || '')}`, '_blank')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="business-details-view" v-if="!isLoading && business">
|
|
<!-- Hero Section -->
|
|
<div class="hero-section">
|
|
<img :src="getImageUrl(business.image_url)" alt="Business Image" class="hero-image" />
|
|
<div class="hero-overlay"></div>
|
|
|
|
<button class="back-floating" @click="goBack">
|
|
<span class="material-icons">arrow_back</span>
|
|
</button>
|
|
|
|
<div class="fav-floating">
|
|
<FavoriteButton
|
|
item-type="business"
|
|
:item-id="business.id"
|
|
:item-name="business.name"
|
|
:item-image="business.image_url || undefined"
|
|
/>
|
|
</div>
|
|
|
|
<div class="hero-content">
|
|
<div class="category-badge premium-font">{{ business.category }}</div>
|
|
<h1 class="business-name premium-font">{{ business.name }}</h1>
|
|
<div class="area-tag">
|
|
<span class="material-icons">location_on</span>
|
|
{{ business.area }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Details Content -->
|
|
<div class="details-container">
|
|
<div class="premium-story">
|
|
<h2 class="premium-font">Explora Nuestra Historia Para Una Cocina Refinada Y Un Ambiente Atemporal</h2>
|
|
<p>"Nuestra historia es una de crecimiento, exploración y recuerdos culinarios inolvidables, donde cada capítulo se sirve con elegancia."</p>
|
|
</div>
|
|
|
|
<!-- Highlights Grid (Inspired by the frame) -->
|
|
<div class="highlights-grid">
|
|
<div class="highlight-item">
|
|
<div class="highlight-header">
|
|
<h3 class="premium-font">Herencia Atemporal</h3>
|
|
<div class="divider"></div>
|
|
</div>
|
|
<p>Platos de autor que evolucionan con inspiración y cultura local.</p>
|
|
</div>
|
|
|
|
<div class="highlight-item">
|
|
<div class="highlight-header">
|
|
<h3 class="premium-font">Platos de Clase Mundial</h3>
|
|
<div class="divider"></div>
|
|
</div>
|
|
<p>Experiencia gastronómica diseñada para deleitar los sentidos más exigentes.</p>
|
|
</div>
|
|
|
|
<div class="highlight-item">
|
|
<div class="highlight-header">
|
|
<h3 class="premium-font">Emoción y Elegancia</h3>
|
|
<div class="divider"></div>
|
|
</div>
|
|
<p>Veladas realzadas por el encanto atemporal de un ambiente exclusivo.</p>
|
|
</div>
|
|
|
|
<div class="highlight-item">
|
|
<div class="highlight-header">
|
|
<h3 class="premium-font">Experiencia Inigualable</h3>
|
|
<div class="divider"></div>
|
|
</div>
|
|
<p>Servicio personalizado desde un anfitrión dedicado para tu comodidad.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Info Section -->
|
|
<div class="info-sections">
|
|
<div class="info-card">
|
|
<span class="material-icons">map</span>
|
|
<div class="info-text">
|
|
<h4>Dirección</h4>
|
|
<p>{{ business.address }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-card">
|
|
<span class="material-icons">phone</span>
|
|
<div class="info-text">
|
|
<h4>Contacto</h4>
|
|
<p>{{ business.phone || 'No disponible' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="business.social_media" class="info-card">
|
|
<span class="material-icons">language</span>
|
|
<div class="info-text">
|
|
<h4>Redes Sociales</h4>
|
|
<p>{{ business.social_media }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="info-card">
|
|
<span class="material-icons">directions</span>
|
|
<div class="info-text">
|
|
<h4>Cómo llegar</h4>
|
|
<button class="track-directions-btn" @click="handleDirections">
|
|
Ver mapa y ruta
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Offers Section -->
|
|
<div v-if="coupons.length > 0" class="offers-section">
|
|
<h2 class="section-title premium-font">Ofertas Disponibles</h2>
|
|
<div class="coupons-grid">
|
|
<div v-for="coupon in coupons" :key="coupon.id" class="coupon-card-detail">
|
|
<div class="coupon-header-flex">
|
|
<div class="coupon-discount">{{ coupon.discount_percentage }}% OFF</div>
|
|
<FavoriteButton
|
|
item-type="coupon"
|
|
:item-id="coupon.id"
|
|
:item-name="coupon.title"
|
|
:item-image="coupon.image_url || undefined"
|
|
/>
|
|
</div>
|
|
<div class="coupon-info">
|
|
<h3>{{ coupon.title }}</h3>
|
|
<p>{{ coupon.description }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else-if="isLoading" class="loading-full">
|
|
<div class="loader"></div>
|
|
<p>Cargando experiencia premium...</p>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.business-details-view {
|
|
min-height: 100vh;
|
|
background: var(--bg-primary);
|
|
color: var(--text-primary);
|
|
padding-bottom: 60px;
|
|
}
|
|
|
|
.premium-font {
|
|
font-family: 'Playfair Display', serif;
|
|
}
|
|
|
|
/* Hero Section */
|
|
.hero-section {
|
|
position: relative;
|
|
height: 60vh;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hero-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.hero-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(to bottom, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.8) 100%);
|
|
}
|
|
|
|
.back-floating {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
background: rgba(255,255,255,0.2);
|
|
backdrop-filter: blur(10px);
|
|
border: none;
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: 50%;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
}
|
|
|
|
.fav-floating {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 20px;
|
|
z-index: 10;
|
|
}
|
|
|
|
.coupon-header-flex {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.hero-content {
|
|
position: absolute;
|
|
bottom: 40px;
|
|
left: 40px;
|
|
right: 40px;
|
|
color: white;
|
|
}
|
|
|
|
.category-badge {
|
|
background: var(--active-color);
|
|
color: white;
|
|
padding: 6px 16px;
|
|
border-radius: 100px;
|
|
display: inline-block;
|
|
font-size: 0.9rem;
|
|
font-weight: 700;
|
|
margin-bottom: 16px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.business-name {
|
|
font-size: 3.5rem;
|
|
margin: 0 0 12px 0;
|
|
line-height: 1.1;
|
|
}
|
|
|
|
.area-tag {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 1.2rem;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* Content */
|
|
.details-container {
|
|
max-width: 1000px;
|
|
margin: -40px auto 0;
|
|
position: relative;
|
|
background: var(--bg-primary);
|
|
border-radius: 30px 30px 0 0;
|
|
padding: 60px 40px;
|
|
box-shadow: 0 -20px 40px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.premium-story {
|
|
text-align: center;
|
|
max-width: 700px;
|
|
margin: 0 auto 60px;
|
|
}
|
|
|
|
.premium-story h2 {
|
|
font-size: 2.2rem;
|
|
margin-bottom: 24px;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.premium-story p {
|
|
font-size: 1.2rem;
|
|
font-style: italic;
|
|
color: var(--text-secondary);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* Highlights Grid */
|
|
.highlights-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 40px;
|
|
margin-bottom: 80px;
|
|
}
|
|
|
|
.highlight-item {
|
|
padding: 20px;
|
|
}
|
|
|
|
.highlight-header {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.highlight-header h3 {
|
|
font-size: 1.4rem;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.divider {
|
|
width: 100%;
|
|
height: 1px;
|
|
background: var(--border-color);
|
|
}
|
|
|
|
.highlight-item p {
|
|
color: var(--text-secondary);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Info Cards */
|
|
.info-sections {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 80px;
|
|
}
|
|
|
|
.info-card {
|
|
background: var(--bg-secondary);
|
|
padding: 24px;
|
|
border-radius: 20px;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 16px;
|
|
}
|
|
|
|
.info-card .material-icons {
|
|
color: var(--active-color);
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.info-text h4 {
|
|
margin: 0 0 4px 0;
|
|
font-size: 0.9rem;
|
|
text-transform: uppercase;
|
|
color: var(--text-secondary);
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.info-text p {
|
|
margin: 0;
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.track-directions-btn {
|
|
background: var(--active-color);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 8px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* Offers Section */
|
|
.offers-section {
|
|
border-top: 1px solid var(--border-color);
|
|
padding-top: 60px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 2rem;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
.coupons-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 24px;
|
|
}
|
|
|
|
.coupon-card-detail {
|
|
background: var(--card-bg);
|
|
border: 2px dashed var(--active-color);
|
|
padding: 24px;
|
|
border-radius: 16px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.coupon-discount {
|
|
font-size: 1.5rem;
|
|
font-weight: 900;
|
|
color: var(--active-color);
|
|
}
|
|
|
|
.coupon-info h3 {
|
|
margin: 0 0 8px 0;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.coupon-info p {
|
|
margin: 0;
|
|
color: var(--text-secondary);
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
/* Loader */
|
|
.loading-full {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
}
|
|
|
|
.loader {
|
|
width: 50px;
|
|
height: 50px;
|
|
border: 3px solid var(--bg-secondary);
|
|
border-top-color: var(--active-color);
|
|
border-radius: 50%;
|
|
animation: spin 1s infinite linear;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.hero-section { height: 50vh; }
|
|
.business-name { font-size: 2.5rem; }
|
|
.highlights-grid { grid-template-columns: 1fr; }
|
|
.details-container { padding: 40px 20px; }
|
|
.hero-content { left: 20px; bottom: 30px; }
|
|
}
|
|
</style>
|