408 lines
17 KiB
PHP
408 lines
17 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 primo salone (o quello attivo – puoi aggiungere switcher dopo)
|
||
$stmt = $pdo->prepare("
|
||
SELECT id, name
|
||
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'];
|
||
$shop_name = $shop['name'];
|
||
|
||
// =========================================================================
|
||
// Helpers
|
||
// =========================================================================
|
||
function isValidDateYmd(string $date): bool {
|
||
$d = DateTime::createFromFormat('Y-m-d', $date);
|
||
return $d && $d->format('Y-m-d') === $date;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
// =========================================================================
|
||
// Gestione POST (add / edit / delete)
|
||
// =========================================================================
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||
$action = $_POST['action'];
|
||
|
||
try {
|
||
if ($action === 'add') {
|
||
$start_date = trim($_POST['start_date'] ?? '');
|
||
$end_date = trim($_POST['end_date'] ?? '');
|
||
$title = trim($_POST['title'] ?? '');
|
||
$description = trim($_POST['description'] ?? '');
|
||
|
||
if ($start_date === '' || $end_date === '') {
|
||
setFlash('danger', "Le date di inizio e fine sono obbligatorie.");
|
||
} elseif (!isValidDateYmd($start_date) || !isValidDateYmd($end_date)) {
|
||
setFlash('danger', "Formato data non valido.");
|
||
} elseif (strtotime($end_date) < strtotime($start_date)) {
|
||
setFlash('danger', "La data di fine non può essere precedente alla data di inizio.");
|
||
} else {
|
||
$pdo->beginTransaction();
|
||
|
||
// Inserisco una riga per ogni giorno del range (B2)
|
||
$stmt = $pdo->prepare("
|
||
INSERT INTO shop_day_off (shop_id, date, title, description, is_recurring)
|
||
VALUES (?, ?, ?, ?, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
title = VALUES(title),
|
||
description = VALUES(description),
|
||
updated_at = CURRENT_TIMESTAMP
|
||
");
|
||
|
||
$start = new DateTime($start_date);
|
||
$end = new DateTime($end_date);
|
||
$end->setTime(0,0,0);
|
||
|
||
// +1 giorno per includere la fine
|
||
$period = new DatePeriod($start, new DateInterval('P1D'), (clone $end)->modify('+1 day'));
|
||
|
||
$inserted = 0;
|
||
foreach ($period as $dt) {
|
||
$day = $dt->format('Y-m-d');
|
||
$ok = $stmt->execute([
|
||
$shop_id,
|
||
$day,
|
||
$title !== '' ? $title : 'Chiusura',
|
||
$description
|
||
]);
|
||
if ($ok) $inserted++;
|
||
}
|
||
|
||
$pdo->commit();
|
||
|
||
setFlash('success', "Chiusura aggiunta: salvati/aggiornati {$inserted} giorni.");
|
||
}
|
||
|
||
header("Location: day_off.php");
|
||
exit;
|
||
}
|
||
|
||
if ($action === 'edit') {
|
||
$id = (int)($_POST['id'] ?? 0);
|
||
$date = trim($_POST['start_date'] ?? ''); // nel form edit usiamo start_date come "data singola"
|
||
$title = trim($_POST['title'] ?? '');
|
||
$description = trim($_POST['description'] ?? '');
|
||
|
||
if ($id <= 0) {
|
||
setFlash('danger', "ID non valido.");
|
||
} elseif ($date === '' || !isValidDateYmd($date)) {
|
||
setFlash('danger', "La data è obbligatoria e deve essere valida.");
|
||
} else {
|
||
$stmt = $pdo->prepare("
|
||
UPDATE shop_day_off
|
||
SET date = ?, title = ?, description = ?, updated_at = NOW()
|
||
WHERE id = ? AND shop_id = ?
|
||
");
|
||
$ok = $stmt->execute([
|
||
$date,
|
||
$title !== '' ? $title : 'Chiusura',
|
||
$description,
|
||
$id,
|
||
$shop_id
|
||
]);
|
||
|
||
setFlash($ok ? 'success' : 'danger', $ok ? "Giorno di chiusura aggiornato!" : "Errore durante l'aggiornamento.");
|
||
}
|
||
|
||
header("Location: day_off.php");
|
||
exit;
|
||
}
|
||
|
||
if ($action === 'delete') {
|
||
$id = (int)($_POST['id'] ?? 0);
|
||
|
||
if ($id <= 0) {
|
||
setFlash('danger', "ID non valido.");
|
||
} else {
|
||
$stmt = $pdo->prepare("DELETE FROM shop_day_off WHERE id = ? AND shop_id = ?");
|
||
$ok = $stmt->execute([$id, $shop_id]);
|
||
setFlash($ok ? 'success' : 'danger', $ok ? "Giorno di chiusura eliminato!" : "Errore durante l'eliminazione.");
|
||
}
|
||
|
||
header("Location: day_off.php");
|
||
exit;
|
||
}
|
||
|
||
// action sconosciuta
|
||
setFlash('danger', "Azione non valida.");
|
||
header("Location: day_off.php");
|
||
exit;
|
||
|
||
} catch (Throwable $e) {
|
||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||
setFlash('danger', "Errore: " . $e->getMessage());
|
||
header("Location: day_off.php");
|
||
exit;
|
||
}
|
||
}
|
||
|
||
// =========================================================================
|
||
// Recupera tutti i giorni di chiusura
|
||
// =========================================================================
|
||
$stmt = $pdo->prepare("
|
||
SELECT id, date, title, description, is_recurring
|
||
FROM shop_day_off
|
||
WHERE shop_id = ?
|
||
ORDER BY date ASC
|
||
");
|
||
$stmt->execute([$shop_id]);
|
||
$days_off = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
$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'); ?>
|
||
<title>Giorni di Chiusura - <?= htmlspecialchars($shop_name) ?></title>
|
||
</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 align-items-center justify-content-between">
|
||
<h6 class="mb-0">Giorni di Chiusura - <?= htmlspecialchars($shop_name) ?></h6>
|
||
<div>
|
||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addDayOffModal">
|
||
<i class="bx bx-plus me-1"></i> Aggiungi Chiusura
|
||
</button>
|
||
<a href="salon_dashboard.php" class="btn btn-outline-secondary ms-2">
|
||
<i class="bx bx-arrow-back me-1"></i> Dashboard
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<?php if ($flash): ?>
|
||
<div class="alert alert-<?= htmlspecialchars($flash['type']) ?> alert-dismissible fade show" role="alert">
|
||
<?= htmlspecialchars($flash['text']) ?>
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (empty($days_off)): ?>
|
||
<div class="alert alert-info text-center py-4">
|
||
Non hai ancora impostato giorni di chiusura.<br>
|
||
Aggiungine uno per bloccare le prenotazioni in quei giorni.
|
||
</div>
|
||
<?php else: ?>
|
||
<div class="table-responsive">
|
||
<table id="daysOffTable" class="table table-striped table-hover table-bordered">
|
||
<thead>
|
||
<tr>
|
||
<th>Data</th>
|
||
<th>Titolo / Descrizione</th>
|
||
<th>Ricorrente</th>
|
||
<th>Azioni</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($days_off as $day): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($day['date']) ?></td>
|
||
<td><?= htmlspecialchars(($day['title'] ?: '') . (($day['description'] ?? '') ? ' — ' . $day['description'] : '')) ?: 'Chiusura' ?></td>
|
||
<td>
|
||
<?php if (!empty($day['is_recurring'])): ?>
|
||
<span class="badge bg-success">Sì (ogni anno)</span>
|
||
<?php else: ?>
|
||
<span class="badge bg-secondary">No</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td>
|
||
<button type="button" class="btn btn-sm btn-warning me-1"
|
||
data-bs-toggle="modal" data-bs-target="#editDayOffModal"
|
||
onclick='fillEditModal(<?= json_encode([
|
||
"id" => (int)$day["id"],
|
||
"date" => $day["date"],
|
||
"title" => $day["title"] ?? "",
|
||
"description" => $day["description"] ?? ""
|
||
], JSON_HEX_APOS | JSON_HEX_QUOT) ?>)'>
|
||
<i class="bx bx-edit"></i> Modifica
|
||
</button>
|
||
|
||
<form action="" method="POST" style="display:inline;"
|
||
onsubmit="return confirm('Confermi l\'eliminazione?');">
|
||
<input type="hidden" name="action" value="delete">
|
||
<input type="hidden" name="id" value="<?= (int)$day['id'] ?>">
|
||
<button type="submit" class="btn btn-sm btn-danger">
|
||
<i class="bx bx-trash"></i> Elimina
|
||
</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php include('include/footer.php'); ?>
|
||
</div>
|
||
|
||
<!-- Modal Aggiungi -->
|
||
<div class="modal fade" id="addDayOffModal" tabindex="-1" aria-labelledby="addDayOffModalLabel">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content">
|
||
<div class="modal-header bg-primary text-white">
|
||
<h5 class="modal-title" id="addDayOffModalLabel">Aggiungi Giorni di Chiusura</h5>
|
||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<form action="" method="POST">
|
||
<div class="modal-body">
|
||
<input type="hidden" name="action" value="add">
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-bold">Dal <span class="text-danger">*</span></label>
|
||
<input type="date" class="form-control" name="start_date" required>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-bold">Al <span class="text-danger">*</span></label>
|
||
<input type="date" class="form-control" name="end_date" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Titolo (es. Ferie estive)</label>
|
||
<input type="text" class="form-control" name="title" placeholder="Titolo breve">
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Descrizione / Note</label>
|
||
<textarea class="form-control" name="description" rows="3"
|
||
placeholder="Dettagli (es. chiuso tutto il giorno per ferie)"></textarea>
|
||
</div>
|
||
|
||
<div class="alert alert-secondary mb-0">
|
||
Verrà salvata una riga per ogni giorno del range (così blocchi facilmente le prenotazioni).
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
|
||
<button type="submit" class="btn btn-primary">Aggiungi</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Modifica (singolo giorno) -->
|
||
<div class="modal fade" id="editDayOffModal" tabindex="-1" aria-labelledby="editDayOffModalLabel">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content">
|
||
<div class="modal-header bg-warning text-dark">
|
||
<h5 class="modal-title" id="editDayOffModalLabel">Modifica Giorno di Chiusura</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<form action="" method="POST">
|
||
<div class="modal-body">
|
||
<input type="hidden" name="action" value="edit">
|
||
<input type="hidden" name="id" id="edit_id">
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Data <span class="text-danger">*</span></label>
|
||
<input type="date" class="form-control" name="start_date" id="edit_date" required>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Titolo</label>
|
||
<input type="text" class="form-control" name="title" id="edit_title" placeholder="Es: Chiusura straordinaria">
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Descrizione / Motivo</label>
|
||
<input type="text" class="form-control" name="description" id="edit_description"
|
||
placeholder="Es: Ferie natalizie">
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
|
||
<button type="submit" class="btn btn-warning">Salva Modifiche</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php include('jsinclude.php'); ?>
|
||
|
||
<script>
|
||
$(document).ready(function () {
|
||
$('#daysOffTable').DataTable({
|
||
language: { url: '//cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json' },
|
||
order: [[0, 'asc']]
|
||
});
|
||
});
|
||
|
||
function fillEditModal(data) {
|
||
document.getElementById('edit_id').value = data.id;
|
||
document.getElementById('edit_date').value = data.date;
|
||
document.getElementById('edit_title').value = data.title || '';
|
||
document.getElementById('edit_description').value = data.description || '';
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|