comelifacciamo/public/userarea/salon_profile.php
2026-01-27 14:53:37 +01:00

552 lines
24 KiB
PHP

<?php
// Forza la visualizzazione degli errori (solo dev)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
include('include/headscript.php');
// Connessione DB
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
// Verifica utente loggato
if (!isset($iduserlogin)) {
header("Location: login.php");
exit;
}
// Controlla se esiste almeno un salone
$stmt = $pdo->prepare("SELECT COUNT(*) FROM shops WHERE owner_id = ?");
$stmt->execute([$iduserlogin]);
if ((int)$stmt->fetchColumn() === 0) {
header("Location: onboarding_salon.php");
exit;
}
// Prendi il salone
$stmt = $pdo->prepare("
SELECT *
FROM shops
WHERE owner_id = ?
ORDER BY created_at ASC
LIMIT 1
");
$stmt->execute([$iduserlogin]);
$shop = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$shop) {
die("Errore: salone non trovato.");
}
$shop_id = (int)$shop['id'];
// ===========================
// Helper: Flash messages
// ===========================
function setFlash(string $type, string $text): void
{
$_SESSION['flash'] = ['type' => $type, 'text' => $text];
}
function getFlash(): ?array
{
if (!isset($_SESSION['flash'])) return null;
$f = $_SESSION['flash'];
unset($_SESSION['flash']);
return $f;
}
// ===========================
// Helper: Ridimensiona immagine (come nel tuo template)
// ===========================
function resizeImage($source_path, $dest_path, $max_width = 800)
{
list($width, $height, $type) = getimagesize($source_path);
if ($width <= $max_width) {
copy($source_path, $dest_path);
return;
}
$new_width = $max_width;
$new_height = (int)(($height * $new_width) / $width);
switch ($type) {
case IMAGETYPE_JPEG:
$source = imagecreatefromjpeg($source_path);
break;
case IMAGETYPE_PNG:
$source = imagecreatefrompng($source_path);
break;
case IMAGETYPE_GIF:
$source = imagecreatefromgif($source_path);
break;
default:
throw new Exception("Formato non supportato.");
}
$dest = imagecreatetruecolor($new_width, $new_height);
if ($type == IMAGETYPE_PNG) {
imagealphablending($dest, false);
imagesavealpha($dest, true);
}
imagecopyresampled($dest, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($dest, $dest_path, 90);
break;
case IMAGETYPE_PNG:
imagepng($dest, $dest_path);
break;
case IMAGETYPE_GIF:
imagegif($dest, $dest_path);
break;
}
imagedestroy($source);
imagedestroy($dest);
}
// ===========================
// Helper: Geolocalizzazione con Nominatim
// ===========================
function geocodeAddress(string $address): array
{
$url = 'https://nominatim.openstreetmap.org/search';
$params = http_build_query([
'q' => $address,
'format' => 'json',
'limit' => 1,
'addressdetails' => 1,
'countrycodes' => 'it',
]);
$ch = curl_init($url . '?' . $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'HairBook Salon Manager/1.0 (contact: info@hairbook.it)');
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || !$response) {
return ['success' => false, 'message' => 'Errore connessione Nominatim'];
}
$data = json_decode($response, true);
if (empty($data) || !isset($data[0])) {
return ['success' => false, 'message' => 'Indirizzo non trovato'];
}
$result = $data[0];
return [
'success' => true,
'lat' => (float)$result['lat'],
'lon' => (float)$result['lon'],
'display' => $result['display_name'] ?? ''
];
}
// ===========================
// POST - Salva profilo + geocode se necessario
// ===========================
$flash = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_POST['action'])) { // normale submit form
try {
$name = trim($_POST['name'] ?? '');
$description = trim($_POST['description'] ?? '');
$address = trim($_POST['address'] ?? '');
$address_extra = trim($_POST['address_extra'] ?? '');
$city = trim($_POST['city'] ?? '');
$province = strtoupper(trim($_POST['province'] ?? ''));
$zip_code = trim($_POST['zip_code'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$mobile = trim($_POST['mobile'] ?? '');
$email = trim($_POST['email'] ?? '');
$website = trim($_POST['website'] ?? '');
$instagram = trim(ltrim($_POST['instagram'] ?? '', '@'));
$facebook = trim($_POST['facebook'] ?? '');
$google_maps_url = trim($_POST['google_maps_url'] ?? '');
$latitude = !empty($_POST['latitude']) ? (float)$_POST['latitude'] : null;
$longitude = !empty($_POST['longitude']) ? (float)$_POST['longitude'] : null;
$active = isset($_POST['active']) ? 1 : 0;
// Validazioni
if ($name === '') {
throw new Exception("Nome salone obbligatorio.");
}
if ($city === '') {
throw new Exception("Città obbligatoria.");
}
// Tenta geocode automatico se lat/lon vuoti
if ($latitude === null || $longitude === null) {
$full_address = implode(', ', array_filter([
$address,
$address_extra,
$zip_code,
$city,
$province ? $province : '',
'Italia'
]));
$geocode = geocodeAddress($full_address);
if ($geocode['success']) {
$latitude = $geocode['lat'];
$longitude = $geocode['lon'];
setFlash('info', "Coordinate calcolate automaticamente!");
}
}
// Upload logo
$logo = $shop['logo'];
if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['logo'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$new_filename = "logos/{$shop_id}-" . time() . "." . $ext;
resizeImage($file['tmp_name'], $new_filename, 400);
if ($logo && file_exists($logo)) @unlink($logo);
$logo = $new_filename;
}
}
// Upload cover
$cover = $shop['cover_image'];
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['cover_image'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$new_filename = "covers/{$shop_id}-" . time() . "." . $ext;
resizeImage($file['tmp_name'], $new_filename, 1200);
if ($cover && file_exists($cover)) @unlink($cover);
$cover = $new_filename;
}
}
// Update DB
$stmt = $pdo->prepare("
UPDATE shops SET
name = ?, description = ?, address = ?, address_extra = ?, city = ?, province = ?,
zip_code = ?, phone = ?, mobile = ?, email = ?, website = ?, instagram = ?, facebook = ?,
google_maps_url = ?, latitude = ?, longitude = ?, logo = ?, cover_image = ?, active = ?,
updated_at = NOW()
WHERE id = ? AND owner_id = ?
");
$ok = $stmt->execute([
$name,
$description ?: null,
$address,
$address_extra ?: null,
$city,
$province,
$zip_code,
$phone ?: null,
$mobile ?: null,
$email ?: null,
$website ?: null,
$instagram ?: null,
$facebook ?: null,
$google_maps_url ?: null,
$latitude,
$longitude,
$logo,
$cover,
$active,
$shop_id,
$iduserlogin
]);
setFlash($ok ? 'success' : 'danger', $ok ? "Profilo aggiornato!" : "Errore salvataggio.");
header("Location: salon_profile.php");
exit;
} catch (Exception $e) {
setFlash('danger', $e->getMessage());
header("Location: salon_profile.php");
exit;
}
}
// Flash
$flash = getFlash();
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<?php include('siteinfo.php'); ?>
<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>
<title>Profilo Salone - <?= htmlspecialchars($shop['name']) ?></title>
<style>
#map {
height: 350px;
border: 1px solid #dee2e6;
border-radius: 8px;
margin-top: 10px;
}
.form-label {
font-weight: 600;
}
.input-group-text {
background: #f8f9fa;
}
</style>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="card radius-10">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<h6 class="mb-0">Modifica Profilo Salone</h6>
<a href="salon_dashboard.php" class="btn btn-outline-secondary">
<i class="bx bx-arrow-back me-1"></i> Dashboard
</a>
</div>
<div class="card-body">
<?php if ($flash): ?>
<div class="alert alert-<?= htmlspecialchars($flash['type']) ?> alert-dismissible fade show">
<?= htmlspecialchars($flash['text']) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<form action="" method="POST" enctype="multipart/form-data">
<div class="row g-4">
<!-- Colonna sinistra: dati principali -->
<div class="col-lg-8">
<div class="mb-3">
<label class="form-label">Nome Salone <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="name" value="<?= htmlspecialchars($shop['name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Descrizione</label>
<textarea class="form-control" name="description" rows="4"><?= htmlspecialchars($shop['description'] ?? '') ?></textarea>
</div>
<div class="row g-3">
<div class="col-md-8">
<label class="form-label">Indirizzo <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="address" id="address" value="<?= htmlspecialchars($shop['address']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label">Indirizzo extra</label>
<input type="text" class="form-control" name="address_extra" value="<?= htmlspecialchars($shop['address_extra'] ?? '') ?>">
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Città <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="city" id="city" value="<?= htmlspecialchars($shop['city']) ?>" required>
</div>
<div class="col-md-3">
<label class="form-label">Provincia</label>
<input type="text" class="form-control text-uppercase" name="province" maxlength="2" value="<?= htmlspecialchars($shop['province'] ?? '') ?>">
</div>
<div class="col-md-3">
<label class="form-label">CAP</label>
<input type="text" class="form-control" name="zip_code" value="<?= htmlspecialchars($shop['zip_code']) ?>">
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Telefono</label>
<input type="text" class="form-control" name="phone" value="<?= htmlspecialchars($shop['phone'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label">Cellulare / WhatsApp</label>
<input type="text" class="form-control" name="mobile" value="<?= htmlspecialchars($shop['mobile'] ?? '') ?>">
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" value="<?= htmlspecialchars($shop['email'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label">Sito Web</label>
<input type="url" class="form-control" name="website" value="<?= htmlspecialchars($shop['website'] ?? '') ?>">
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Instagram (solo username)</label>
<div class="input-group">
<span class="input-group-text">@</span>
<input type="text" class="form-control" name="instagram" value="<?= htmlspecialchars($shop['instagram'] ?? '') ?>">
</div>
</div>
<div class="col-md-6">
<label class="form-label">Facebook</label>
<input type="text" class="form-control" name="facebook" value="<?= htmlspecialchars($shop['facebook'] ?? '') ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label">Link Google Maps (opzionale)</label>
<input type="url" class="form-control" name="google_maps_url" value="<?= htmlspecialchars($shop['google_maps_url'] ?? '') ?>">
</div>
</div>
<!-- Colonna destra: immagini + mappa -->
<div class="col-lg-4">
<div class="mb-3">
<label class="form-label">Logo Salone (quadrato)</label>
<?php if ($shop['logo']): ?>
<img src="<?= htmlspecialchars($shop['logo']) ?>" alt="Logo" class="img-fluid rounded mb-2" style="max-height:120px;">
<?php endif; ?>
<input type="file" class="form-control" name="logo" accept="image/*">
</div>
<div class="mb-4">
<label class="form-label">Immagine di Copertina (orizzontale)</label>
<?php if ($shop['cover_image']): ?>
<img src="<?= htmlspecialchars($shop['cover_image']) ?>" alt="Cover" class="img-fluid rounded mb-2" style="max-height:120px; width:100%;">
<?php endif; ?>
<input type="file" class="form-control" name="cover_image" accept="image/*">
</div>
<!-- Geolocalizzazione -->
<div class="mb-3">
<label class="form-label">Coordinate</label>
<div class="input-group mb-2">
<input type="number" step="any" class="form-control" name="latitude" id="lat"
value="<?= htmlspecialchars($shop['latitude'] ?? '') ?>" placeholder="Latitudine">
<input type="number" step="any" class="form-control" name="longitude" id="lng"
value="<?= htmlspecialchars($shop['longitude'] ?? '') ?>" placeholder="Longitudine">
</div>
<button type="button" class="btn btn-outline-info w-100" id="geocodeBtn">
<i class="bx bx-current-location"></i> Geolocalizza indirizzo
</button>
<small class="form-text text-muted mt-1 d-block">
Clicca per calcolare lat/lon da indirizzo (usa OpenStreetMap)
</small>
</div>
<!-- Mappa -->
<div id="map"></div>
<div class="form-check mt-4">
<input class="form-check-input" type="checkbox" name="active" id="active" <?= $shop['active'] ? 'checked' : '' ?>>
<label class="form-check-label fw-bold" for="active">
Salone attivo e visibile online
</label>
</div>
</div>
</div>
<div class="d-grid mt-5">
<button type="submit" class="btn btn-primary btn-lg">Salva Modifiche</button>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script>
// Inizializza mappa
var map = L.map('map').setView([45.4642, 9.1900], 13); // default Milano
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
var marker = null;
<?php if ($shop['latitude'] && $shop['longitude']): ?>
var initLat = <?= (float)$shop['latitude'] ?>;
var initLng = <?= (float)$shop['longitude'] ?>;
map.setView([initLat, initLng], 15);
marker = L.marker([initLat, initLng]).addTo(map);
<?php endif; ?>
// Click su mappa → aggiorna coordinate
map.on('click', function(e) {
document.getElementById('lat').value = e.latlng.lat.toFixed(8);
document.getElementById('lng').value = e.latlng.lng.toFixed(8);
if (marker) map.removeLayer(marker);
marker = L.marker(e.latlng).addTo(map);
});
// Bottone Geolocalizza
document.getElementById('geocodeBtn').addEventListener('click', function() {
const addr = document.querySelector('[name="address"]').value.trim();
const extra = document.querySelector('[name="address_extra"]').value.trim();
const zip = document.querySelector('[name="zip_code"]').value.trim();
const city = document.querySelector('[name="city"]').value.trim();
const prov = document.querySelector('[name="province"]').value.trim().toUpperCase();
if (!addr || !city) {
alert("Compila almeno Indirizzo e Città.");
return;
}
const full = [addr, extra, zip, city, prov ? prov : '', 'Italia'].filter(Boolean).join(', ');
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'action=geocode&address=' + encodeURIComponent(full)
})
.then(r => r.json())
.then(data => {
if (data.success) {
document.getElementById('lat').value = data.lat;
document.getElementById('lng').value = data.lon;
map.setView([data.lat, data.lon], 15);
if (marker) map.removeLayer(marker);
marker = L.marker([data.lat, data.lon]).addTo(map);
alert("Trovato!\nLat: " + data.lat + "\nLon: " + data.lon);
} else {
alert("Non trovato: " + (data.message || "Indirizzo non riconosciuto"));
}
})
.catch(err => alert("Errore: " + err));
});
</script>
</body>
</html>
<?php
// Gestione AJAX geocode (in fondo alla pagina)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'geocode') {
$addr = trim($_POST['address'] ?? '');
if ($addr === '') {
echo json_encode(['success' => false, 'message' => 'Indirizzo vuoto']);
exit;
}
$result = geocodeAddress($addr);
header('Content-Type: application/json');
echo json_encode($result);
exit;
}
?>