Files
Laucha1312 cc049c6cb6 3
2026-06-04 15:20:26 -03:00

276 lines
12 KiB
PHP

@extends('layouts.app')
@section('title', 'Lugares - OnAPB')
@section('styles')
<link rel="stylesheet" href="{{ asset('static/lugares.css?v=5') }}">
@endsection
@section('content')
<div class="container-fluid py-5" style="background: var(--surface);">
<div class="container py-4">
<div class="mb-5">
<span class="text-primary fw-bold tracking-widest text-uppercase d-block mb-2">Comunidad</span>
<h1 class="display-1 fw-bold mb-3" style="line-height: 0.9;">Lugares de Interés</h1>
<div style="width: 150px; height: 10px; background: var(--primary);"></div>
</div>
<!-- Filters Editorial -->
<div class="bg-white p-5 mb-5 shadow-sm" style="border-left: 10px solid var(--primary-container);">
<div class="row g-4 align-items-end">
<div class="col-md-5">
<label class="small fw-bold text-uppercase text-muted mb-2 d-block">Búsqueda</label>
<input type="text" id="searchFilter" class="form-control form-control-lg border-0 bg-light p-3" placeholder="Club, comercio, etc..." oninput="filterPromos()" style="border-radius: 0;">
</div>
<div class="col-md-5">
<label class="small fw-bold text-uppercase text-muted mb-2 d-block">Categoría</label>
<select id="categoryFilter" class="form-select form-select-lg border-0 bg-light p-3" onchange="filterPromos()" style="border-radius: 0;">
<option value="">Todas</option>
@foreach($categorias as $cat)
<option value="{{ strtolower($cat) }}">{{ ucfirst($cat) }}</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<button class="btn-kinetic-primary w-100 py-3" onclick="filterPromos()">FILTRAR</button>
</div>
</div>
</div>
<!-- Promo Grid -->
<div id="promo-grid" class="row g-4">
@forelse($promociones as $p)
<div class="col-md-4 promo-card" data-categoria="{{ strtolower($p->categoria ?? '') }}" data-nombre="{{ strtolower($p->nombre) }}">
<div class="kinetic-card p-0 h-100 overflow-hidden d-flex flex-column" onclick="showPromoDetail({{ $p->id }})" style="cursor: pointer; border-radius: 0;">
@if($p->imagen)
<div style="height: 250px; overflow: hidden; position: relative;">
<img src="{{ asset('storage/' . $p->imagen) }}" class="w-100 h-100" style="object-fit: cover;" alt="{{ $p->nombre }}">
<div class="position-absolute bottom-0 start-0 bg-primary text-white px-3 py-1 small fw-bold text-uppercase">{{ $p->categoria }}</div>
</div>
@endif
<div class="p-4 flex-grow-1">
<h4 class="h3 fw-bold mb-3">{{ $p->nombre }}</h4>
<p class="text-muted small mb-4">{{ Str::limit($p->descripcion_lugar ?? $p->descripcion, 100) }}</p>
@if($p->descripcion && trim($p->descripcion))
<span class="text-primary small fw-bold"><i class="bi bi-star-fill"></i> BENEFICIO ACTIVO</span>
@endif
<p class="small text-muted mb-0 mt-3"><i class="bi bi-geo-alt"></i> {{ $p->direccion }}</p>
</div>
</div>
</div>
@empty
<div class="col-12 text-center py-5">
<div class="kinetic-card p-5">
<i class="bi bi-geo text-muted mb-3" style="font-size: 3rem;"></i>
<p class="fs-4 text-muted">No se encontraron lugares.</p>
</div>
</div>
@endforelse
</div>
<!-- Detail Modal Redux (Inline) -->
<div id="promo-detail" class="bg-white shadow-lg p-5 my-5" style="display: none; border: 2px solid var(--primary-container);">
<div class="row g-5 align-items-center">
<div class="col-md-5">
<img id="detail-img" src="" class="w-100 shadow-sm" style="height: 350px; object-fit: cover;" alt="Promo detail">
</div>
<div class="col-md-7">
<div class="d-flex justify-content-between align-items-start mb-3">
<div>
<span id="detail-categoria" class="badge bg-primary text-uppercase mb-2"></span>
<h2 id="detail-nombre" class="display-3 fw-bold mb-0"></h2>
</div>
<button class="btn-close" onclick="closeDetail()"></button>
</div>
<p id="detail-descripcion" class="fs-5 text-muted mb-4"></p>
<p class="fs-5 mb-4"><i class="bi bi-geo-alt-fill text-primary"></i> <span id="detail-direccion"></span></p>
<div id="detail-promo" class="p-4 bg-light mb-4 border-start border-primary border-5" style="display: none;">
<h5 class="fw-bold text-primary mb-2">Beneficio para Asociados:</h5>
<p id="detail-promo-text" class="fs-5 mb-0 fw-bold"></p>
</div>
<div class="d-flex gap-3 mt-4">
<div id="detail-actions"></div>
<button class="btn btn-dark btn-lg px-4" onclick="ubicarEnMapa()" style="border-radius: 0;">VER MAPA</button>
</div>
</div>
</div>
</div>
@if(session('admin_logged_in'))
<div class="text-center mt-5">
<a href="{{ route('admin.promociones.index') }}" class="btn-kinetic-primary px-5 py-3">ADMINISTRAR LUGARES</a>
</div>
@endif
</div>
</div>
<!-- Mapa -->
<div class="container-fluid mt-4 px-0">
<div id="map" style="height: 400px;"></div>
</div>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css" />
<script>
const promos = @json($promociones);
let map;
let markers = {};
let markersCluster;
let selectedPromoId = null;
function formatCategoria(c) {
if (!c) return "Sin categoría";
return c.charAt(0).toUpperCase() + c.slice(1).toLowerCase();
}
function getIcon(categoria) {
const colors = {
'clubes': '#e74c3c',
'comida': '#f39c12',
'salud': '#27ae60',
'vestimenta_y_estilo': '#9b59b6',
'calzado_deportivo': '#3498db',
'entretenimiento': '#1abc9c',
'hospedaje': '#34495e'
};
const color = colors[categoria?.toLowerCase()] || '#95a5a6';
return L.divIcon({
className: 'custom-marker',
html: `<div style="background:${color};width:30px;height:30px;border-radius:50%;border:3px solid white;box-shadow:0 2px 5px rgba(0,0,0,0.3);"></div>`,
iconSize: [30, 30],
iconAnchor: [15, 15]
});
}
function initMap() {
map = L.map('map').setView([-31.744, -60.53], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
markersCluster = L.markerClusterGroup({
disableClusteringAtZoom: 13,
spiderfyOnMaxZoom: true,
showCoverageOnHover: false,
maxClusterRadius: 50
});
promos.forEach(p => {
if (p.lat && p.lng) {
const marker = L.marker([p.lat, p.lng], { icon: getIcon(p.categoria) });
const popupContent = `
<strong>${p.nombre}</strong><br>
<small>${p.direccion || ''}</small><br>
<small>${p.descripcion_lugar || p.descripcion || ''}</small><br>
<a href="javascript:void(0)" onclick="event.preventDefault(); showPromoDetail(${p.id});">Ver detalle</a>
`;
marker.bindPopup(popupContent);
markersCluster.addLayer(marker);
markers[p.id] = marker;
}
});
map.addLayer(markersCluster);
}
function filterPromos() {
const search = document.getElementById('searchFilter').value.toLowerCase().trim();
const cat = document.getElementById('categoryFilter').value;
document.querySelectorAll('.promo-card').forEach(card => {
const nombre = card.dataset.nombre;
const categoria = card.dataset.categoria;
const matchSearch = !search || nombre.includes(search);
const matchCat = !cat || categoria === cat;
card.style.display = (matchSearch && matchCat) ? 'block' : 'none';
});
}
function showPromoDetail(id) {
const p = promos.find(x => x.id === id);
if (!p) return;
selectedPromoId = id;
document.getElementById('detail-img').src = p.imagen ? '/storage/' + p.imagen : '';
document.getElementById('detail-nombre').textContent = p.nombre;
document.getElementById('detail-categoria').innerHTML = '<span class="badge bg-secondary">' + formatCategoria(p.categoria) + '</span>';
document.getElementById('detail-descripcion').textContent = p.descripcion_lugar || '';
document.getElementById('detail-direccion').textContent = p.direccion || '';
if (p.descripcion && p.descripcion.trim()) {
document.getElementById('detail-promo').style.display = 'block';
document.getElementById('detail-promo-text').textContent = p.descripcion;
} else {
document.getElementById('detail-promo').style.display = 'none';
}
// Mostrar botón solo si tiene beneficio y está logueado
const actionsDiv = document.getElementById('detail-actions');
@if(session('user_logged_in'))
if (p.descripcion && p.descripcion.trim()) {
actionsDiv.innerHTML = '<form method="POST" action="{{ route('panel.generar.promo.qr') }}" class="d-inline confirm-submit" data-confirm-text="¿Generar QR de beneficio?" data-confirm-button="Generar QR" data-confirm-icon="question"><input type="hidden" name="_token" value="{{ csrf_token() }}"><input type="hidden" name="id_promo" value="' + id + '"><button type="submit" class="btn btn-success">🎟️ Solicitar beneficio</button></form>';
} else {
actionsDiv.innerHTML = '';
}
@else
if (p.descripcion && p.descripcion.trim()) {
actionsDiv.innerHTML = '<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#loginModal">Iniciá sesión para el beneficio</button>';
} else {
actionsDiv.innerHTML = '';
}
@endif
document.getElementById('promo-detail').style.display = 'block';
// Scroll hacia el detalle
document.getElementById('promo-detail').scrollIntoView({ behavior: 'smooth' });
// Auto-ubicar en el mapa
if (p.lat && p.lng) {
map.setView([p.lat, p.lng], 16);
if (markers[id]) {
markers[id].openPopup();
}
}
}
function ubicarEnMapa() {
if (selectedPromoId && markers[selectedPromoId]) {
const p = promos.find(x => x.id === selectedPromoId);
if (p && p.lat && p.lng) {
map.setView([p.lat, p.lng], 16);
markers[selectedPromoId].openPopup();
document.getElementById('map').scrollIntoView({ behavior: 'smooth' });
}
}
}
function closeDetail() {
document.getElementById('promo-detail').style.display = 'none';
selectedPromoId = null;
}
document.addEventListener('DOMContentLoaded', function() {
initMap();
});
</script>
<style>
.custom-marker { background: transparent; border: none; }
.promo-clickable { cursor: pointer; transition: transform 0.2s; }
.promo-clickable:hover { transform: scale(1.02); }
</style>
@endsection