350 lines
19 KiB
PHP
350 lines
19 KiB
PHP
<?php
|
|
// salon.php — Scheda pubblica del salone (landing del QR code)
|
|
// Pubblica: nessun login richiesto. Carica salone da ?slug=... e i suoi servizi.
|
|
|
|
ini_set('display_errors', 1);
|
|
ini_set('display_startup_errors', 1);
|
|
error_reporting(E_ALL);
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
require_once(__DIR__ . '/userarea/class/db-functions.php');
|
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
|
|
|
// --- Salone dallo slug (o id di fallback) ---
|
|
$slug = trim($_GET['slug'] ?? '');
|
|
$id = (int)($_GET['id'] ?? 0);
|
|
|
|
if ($slug !== '') {
|
|
$stmt = $pdo->prepare("SELECT * FROM shops WHERE slug = ? AND active = 1 LIMIT 1");
|
|
$stmt->execute([$slug]);
|
|
} elseif ($id > 0) {
|
|
$stmt = $pdo->prepare("SELECT * FROM shops WHERE id = ? AND active = 1 LIMIT 1");
|
|
$stmt->execute([$id]);
|
|
} else {
|
|
header("Location: search.php");
|
|
exit;
|
|
}
|
|
$shop = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
// Salone inesistente o non attivo
|
|
if (!$shop) {
|
|
http_response_code(404);
|
|
$notFound = true;
|
|
} else {
|
|
$notFound = false;
|
|
$shop_id = (int)$shop['id'];
|
|
|
|
// Servizi attivi del salone, raggruppabili per categoria
|
|
$sstmt = $pdo->prepare("
|
|
SELECT id, name, description, duration_minutes, price, price_max, category, color_hex
|
|
FROM services
|
|
WHERE shop_id = ? AND is_active = 1
|
|
ORDER BY category ASC, `order` ASC, name ASC
|
|
");
|
|
$sstmt->execute([$shop_id]);
|
|
$services = $sstmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Raggruppa per categoria
|
|
$servicesByCat = [];
|
|
foreach ($services as $sv) {
|
|
$cat = $sv['category'] ?: 'Servizi';
|
|
$servicesByCat[$cat][] = $sv;
|
|
}
|
|
|
|
// Prezzo minimo (per il "Da:")
|
|
$minPrice = null;
|
|
foreach ($services as $sv) {
|
|
if ($sv['price'] !== null && ($minPrice === null || $sv['price'] < $minPrice)) {
|
|
$minPrice = (float)$sv['price'];
|
|
}
|
|
}
|
|
|
|
// È tra i preferiti dell'utente loggato?
|
|
$isFav = false;
|
|
if (!empty($_SESSION['iduserlogin'])) {
|
|
$fstmt = $pdo->prepare("SELECT 1 FROM user_favorite_shops WHERE user_id = ? AND shop_id = ? LIMIT 1");
|
|
$fstmt->execute([$_SESSION['iduserlogin'], $shop_id]);
|
|
$isFav = (bool)$fstmt->fetchColumn();
|
|
}
|
|
|
|
// Indirizzo completo e link mappa
|
|
$addrFull = trim(implode(', ', array_filter([
|
|
$shop['address'] ?? '',
|
|
$shop['city'] ?? '',
|
|
($shop['province'] ? '(' . $shop['province'] . ')' : ''),
|
|
])));
|
|
|
|
if ($shop['latitude'] !== null && $shop['longitude'] !== null) {
|
|
$mapDir = 'https://www.google.com/maps/dir/?api=1&destination='
|
|
. rawurlencode($shop['latitude'] . ',' . $shop['longitude']);
|
|
} else {
|
|
$mapDir = 'https://www.google.com/maps/search/?api=1&query=' . rawurlencode($addrFull);
|
|
}
|
|
|
|
// Cover e logo (percorsi relativi alla root pubblica: qui siamo già in public/)
|
|
$cover = !empty($shop['cover_image']) ? htmlspecialchars($shop['cover_image']) : 'assets/img/tour/details-3/gallery/thumb.jpg';
|
|
$logo = !empty($shop['logo']) ? htmlspecialchars($shop['logo']) : '';
|
|
}
|
|
|
|
function eur($n)
|
|
{
|
|
return number_format((float)$n, 2, ',', '.') . ' €';
|
|
}
|
|
?>
|
|
<!doctype html>
|
|
<html class="no-js" lang="it">
|
|
|
|
<head>
|
|
<?php include('tophead.php'); ?>
|
|
<?php include('cssinclude.php'); ?>
|
|
<?php if (!$notFound): ?>
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<?php endif; ?>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- preloader -->
|
|
<?php include('preloader.php'); ?>
|
|
|
|
<!-- back to top -->
|
|
<div class="back-to-top-wrapper">
|
|
<button id="back_to_top" type="button" class="back-to-top-btn">
|
|
<svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M11 6L6 1L1 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- offcanvas / menu mobile -->
|
|
<?php include('offcanvas.php'); ?>
|
|
|
|
<header class="tp-header-height">
|
|
<?php include('topbar.php'); ?>
|
|
</header>
|
|
|
|
<main>
|
|
|
|
<?php if ($notFound): ?>
|
|
<div class="container text-center pt-140 pb-140">
|
|
<h2 class="mb-3">Salone non trovato</h2>
|
|
<p class="text-muted mb-4">Il salone che cerchi non esiste o non è più disponibile.</p>
|
|
<a href="search.php" class="tp-btn tp-btn-xl">Cerca altri saloni</a>
|
|
</div>
|
|
<?php else: ?>
|
|
|
|
<!-- breadcrumb -->
|
|
<div class="tp-breadcrumb-area">
|
|
<div class="container container-1350">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<nav class="breadcrumbs">
|
|
<ul>
|
|
<li><a href="search.php">Saloni</a></li>
|
|
<li><?= htmlspecialchars($shop['name']) ?></li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- dettaglio salone -->
|
|
<div class="tp-tour-details-area pt-10">
|
|
<div class="container container-1350">
|
|
<div class="row gx-25">
|
|
<div class="col-12">
|
|
<div class="tp-tour-details">
|
|
|
|
<h2 class="tp-breadcrumb-title text-black mb-15"><?= htmlspecialchars($shop['name']) ?></h2>
|
|
|
|
<div class="tp-tour-details-price-wrap mb-35 d-flex align-items-center flex-wrap gap-2 justify-content-between">
|
|
<div class="d-flex align-items-center flex-wrap mb-10">
|
|
<div class="tp-tour-info">
|
|
<span>
|
|
<i class="fa-solid fa-location-dot"></i>
|
|
<?= htmlspecialchars($addrFull ?: '—') ?>
|
|
</span>
|
|
</div>
|
|
<?php /* Recensioni disattivate per ora */ ?>
|
|
</div>
|
|
<div class="tp-tour-details-wishlist d-flex align-items-center mb-10 gap-3">
|
|
<button type="button" class="js-fav <?= $isFav ? 'is-active' : '' ?>" data-id="<?= $shop_id ?>">
|
|
<i class="<?= $isFav ? 'fa-solid' : 'fa-regular' ?> fa-heart"></i>
|
|
<span class="ms-1"><?= $isFav ? 'Nei preferiti' : 'Aggiungi ai preferiti' ?></span>
|
|
</button>
|
|
<a href="<?= htmlspecialchars($mapDir) ?>" target="_blank" rel="noopener">
|
|
<i class="fa-solid fa-map-location-dot"></i>
|
|
<span class="ms-1">Indicazioni</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- immagine cover -->
|
|
<div class="tp-tour-details-gallery-wrap tp-tour-details-3-gallery-wrap">
|
|
<div class="row gx-10">
|
|
<div class="col-12 mb-10">
|
|
<div class="tp-tour-gallery-thumb p-relative fix">
|
|
<img class="w-100" src="<?= $cover ?>" alt="<?= htmlspecialchars($shop['name']) ?>" style="max-height:460px;object-fit:cover;border-radius:12px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tp-tour-details-content-wrap tp-tour-details-3-content-wrap mt-30">
|
|
<div class="row gx-25">
|
|
|
|
<!-- Colonna sinistra: descrizione, info, mappa -->
|
|
<div class="col-lg-7">
|
|
<div class="tp-tour-details-content tp-tour-details-3-content mb-30">
|
|
|
|
<?php if (!empty($shop['description'])): ?>
|
|
<p class="mb-40"><?= nl2br(htmlspecialchars($shop['description'])) ?></p>
|
|
<?php endif; ?>
|
|
|
|
<!-- Contatti rapidi -->
|
|
<h3 class="tp-tour-details-title fw-600 mb-25">Contatti</h3>
|
|
<div class="tp-tour-details-info tp-tour-details-border pb-45 mb-50">
|
|
<ul>
|
|
<?php if (!empty($shop['phone'])): ?>
|
|
<li>
|
|
<span class="tp-tour-details-info-icon"><i class="fa-solid fa-phone"></i></span>
|
|
<div class="tp-tour-details-info-content">
|
|
<h3 class="fw-600 tp-ff-inter mb-0">Telefono</h3>
|
|
<span><a href="tel:<?= htmlspecialchars($shop['phone']) ?>"><?= htmlspecialchars($shop['phone']) ?></a></span>
|
|
</div>
|
|
</li>
|
|
<?php endif; ?>
|
|
<?php if (!empty($shop['mobile'])): ?>
|
|
<li>
|
|
<span class="tp-tour-details-info-icon"><i class="fa-brands fa-whatsapp"></i></span>
|
|
<div class="tp-tour-details-info-content">
|
|
<h3 class="fw-600 tp-ff-inter mb-0">Cellulare</h3>
|
|
<span><?= htmlspecialchars($shop['mobile']) ?></span>
|
|
</div>
|
|
</li>
|
|
<?php endif; ?>
|
|
<?php if (!empty($shop['instagram'])): ?>
|
|
<li>
|
|
<span class="tp-tour-details-info-icon"><i class="fa-brands fa-instagram"></i></span>
|
|
<div class="tp-tour-details-info-content">
|
|
<h3 class="fw-600 tp-ff-inter mb-0">Instagram</h3>
|
|
<span><a href="https://instagram.com/<?= htmlspecialchars($shop['instagram']) ?>" target="_blank">@<?= htmlspecialchars($shop['instagram']) ?></a></span>
|
|
</div>
|
|
</li>
|
|
<?php endif; ?>
|
|
<?php if (!empty($shop['website'])): ?>
|
|
<li>
|
|
<span class="tp-tour-details-info-icon"><i class="fa-solid fa-globe"></i></span>
|
|
<div class="tp-tour-details-info-content">
|
|
<h3 class="fw-600 tp-ff-inter mb-0">Sito web</h3>
|
|
<span><a href="<?= htmlspecialchars($shop['website']) ?>" target="_blank"><?= htmlspecialchars($shop['website']) ?></a></span>
|
|
</div>
|
|
</li>
|
|
<?php endif; ?>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Mappa -->
|
|
<?php if ($shop['latitude'] !== null && $shop['longitude'] !== null): ?>
|
|
<div class="tp-tour-activity-item d-flex w-100 tp-tour-details-border pb-30 mb-50">
|
|
<h3 class="tp-tour-details-title fw-600 mb-10">Dove siamo</h3>
|
|
<div class="tp-tour-activity-content w-100">
|
|
<p class="mb-25"><?= htmlspecialchars($addrFull) ?></p>
|
|
<div id="salonMap" style="height:320px;border-radius:12px;overflow:hidden;"></div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Colonna destra: servizi + prenota -->
|
|
<div class="col-lg-5">
|
|
<div class="tp-booking-sidebar-wrap tp-booking-3-sidebar-wrap ml-30 mb-30">
|
|
<div class="tp-booking-sidebar-item mb-40 tp-booking-sidebar-form">
|
|
|
|
<?php if ($minPrice !== null): ?>
|
|
<div class="tp-tour-details-price d-flex align-items-end mb-25">
|
|
<div class="tp-tour-bottom-price">
|
|
<span class="tp-tour-prefix fw-600">A partire da </span>
|
|
<span class="tp-tour-new-price fw-700"><?= eur($minPrice) ?></span>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<h3 class="tp-tour-details-title fw-600 mb-20">Servizi</h3>
|
|
|
|
<?php if (empty($services)): ?>
|
|
<p class="text-muted">Nessun servizio pubblicato al momento.</p>
|
|
<?php else: ?>
|
|
<div class="tp-tour-details-border pb-20 mb-25">
|
|
<?php foreach ($servicesByCat as $cat => $items): ?>
|
|
<h4 class="fw-600 mt-3 mb-2" style="font-size:1rem;color:#666;"><?= htmlspecialchars($cat) ?></h4>
|
|
<?php foreach ($items as $sv): ?>
|
|
<div class="d-flex justify-content-between align-items-center py-2" style="border-bottom:1px solid #f0f0f0;">
|
|
<div>
|
|
<div class="fw-600"><?= htmlspecialchars($sv['name']) ?></div>
|
|
<small class="text-muted">
|
|
<?php if ($sv['duration_minutes']): ?>
|
|
<i class="fa-regular fa-clock"></i> <?= (int)$sv['duration_minutes'] ?> min
|
|
<?php endif; ?>
|
|
</small>
|
|
</div>
|
|
<div class="text-end">
|
|
<?php if ($sv['price'] !== null): ?>
|
|
<span class="fw-700"><?= eur($sv['price']) ?><?= $sv['price_max'] ? '+' : '' ?></span>
|
|
<?php endif; ?>
|
|
<a href="book.php?shop=<?= $shop_id ?>&service=<?= (int)$sv['id'] ?>"
|
|
class="tp-btn-sm d-block mt-1">Prenota</a>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<a href="book.php?shop=<?= $shop_id ?>" class="tp-btn tp-btn-xl w-100">Prenota un appuntamento</a>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php endif; ?>
|
|
|
|
</main>
|
|
|
|
<footer>
|
|
<?php include('footer.php'); ?>
|
|
</footer>
|
|
|
|
<?php include('jsinclude.php'); ?>
|
|
|
|
<?php if (!$notFound && $shop['latitude'] !== null && $shop['longitude'] !== null): ?>
|
|
<script>
|
|
(function() {
|
|
var lat = <?= (float)$shop['latitude'] ?>,
|
|
lng = <?= (float)$shop['longitude'] ?>;
|
|
var map = L.map('salonMap').setView([lat, lng], 16);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© OpenStreetMap'
|
|
}).addTo(map);
|
|
L.marker([lat, lng]).addTo(map)
|
|
.bindPopup(<?= json_encode($shop['name']) ?>).openPopup();
|
|
})();
|
|
</script>
|
|
<?php endif; ?>
|
|
</body>
|
|
|
|
</html>
|