feat: redesign tickets main view and basket view with improved styles and layout
- Updated SCSS for tickets main view and basket view, enhancing visual design and responsiveness. - Added new calendar functionality in the admin panel for managing ticket availability. - Implemented error handling for ticket availability in the basket view. - Introduced a new calendar availability table in the database for tracking ticket dates. - Added a new link to the calendar in the logged-in user navigation. - Improved ticket selection logic to disable unavailable tickets in the main view. - Created guidelines for code standards in AGENTS.md.
This commit is contained in:
167
templates/admin-panel/calendar.php
Normal file
167
templates/admin-panel/calendar.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/pl.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
|
||||
<div id="tickets-calendar-admin">
|
||||
<div class="container">
|
||||
<div class="tickets-orders">
|
||||
<h1>Kalendarz</h1>
|
||||
|
||||
<div class="calendar-controls">
|
||||
<div class="mb-3">
|
||||
<label for="ticket_group" class="form-label"><strong>Rodzaj biletu</strong></label>
|
||||
<select id="ticket_group" class="form-select">
|
||||
<?php foreach ($this->calendar_groups as $groupKey => $groupData) : ?>
|
||||
<option value="<?= htmlspecialchars($groupKey, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<?= htmlspecialchars($groupData['label'], ENT_QUOTES, 'UTF-8'); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="calendar_csrf_token" value="<?= htmlspecialchars($this->csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
|
||||
<div id="admin-flatpickr"></div>
|
||||
|
||||
<div class="calendar-buttons mt-3">
|
||||
<button type="button" class="btn btn-outline-success" id="enable-month">Odblokuj cały miesiąc</button>
|
||||
<button type="button" class="btn btn-outline-danger" id="disable-month">Zablokuj cały miesiąc</button>
|
||||
<button type="button" class="btn btn-primary" id="save-calendar">Zapisz</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
let enabledDatesSet = new Set();
|
||||
|
||||
const calendarInstance = flatpickr("#admin-flatpickr", {
|
||||
inline: true,
|
||||
mode: "multiple",
|
||||
dateFormat: "Y-m-d",
|
||||
disableMobile: true,
|
||||
locale: "pl",
|
||||
onChange: function(selectedDates, dateStr, instance) {
|
||||
syncSetWithPicker(instance);
|
||||
}
|
||||
});
|
||||
|
||||
function formatDateToYmd(dateObject) {
|
||||
const year = dateObject.getFullYear();
|
||||
const month = String(dateObject.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(dateObject.getDate()).padStart(2, "0");
|
||||
return year + "-" + month + "-" + day;
|
||||
}
|
||||
|
||||
function syncSetWithPicker(instance) {
|
||||
enabledDatesSet = new Set(instance.selectedDates.map(function(dateObject) {
|
||||
return formatDateToYmd(dateObject);
|
||||
}));
|
||||
}
|
||||
|
||||
function renderCurrentSetToPicker() {
|
||||
calendarInstance.setDate(Array.from(enabledDatesSet), false, "Y-m-d");
|
||||
}
|
||||
|
||||
function getCurrentGroup() {
|
||||
return $('#ticket_group').val();
|
||||
}
|
||||
|
||||
function handleError(message) {
|
||||
if ($.alert) {
|
||||
$.alert(message);
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchDatesForGroup() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/apanel/calendar_dates/',
|
||||
data: {
|
||||
ticket_group: getCurrentGroup()
|
||||
},
|
||||
success: function(rawResponse) {
|
||||
const response = $.parseJSON(rawResponse);
|
||||
if (response.status !== 'ok') {
|
||||
handleError(response.message || 'Nie udało się pobrać danych kalendarza.');
|
||||
return;
|
||||
}
|
||||
|
||||
enabledDatesSet = new Set(response.enabled_dates || []);
|
||||
renderCurrentSetToPicker();
|
||||
},
|
||||
error: function() {
|
||||
handleError('Błąd połączenia podczas pobierania kalendarza.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateWholeMonth(enableMonth) {
|
||||
const year = calendarInstance.currentYear;
|
||||
const monthIndex = calendarInstance.currentMonth;
|
||||
const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
|
||||
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const dateObject = new Date(year, monthIndex, day);
|
||||
const dateString = formatDateToYmd(dateObject);
|
||||
if (enableMonth) {
|
||||
enabledDatesSet.add(dateString);
|
||||
} else {
|
||||
enabledDatesSet.delete(dateString);
|
||||
}
|
||||
}
|
||||
|
||||
renderCurrentSetToPicker();
|
||||
}
|
||||
|
||||
function saveCalendar() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
url: '/apanel/calendar_save/',
|
||||
data: {
|
||||
ticket_group: getCurrentGroup(),
|
||||
dates: Array.from(enabledDatesSet),
|
||||
csrf_token: $('#calendar_csrf_token').val()
|
||||
},
|
||||
success: function(rawResponse) {
|
||||
const response = $.parseJSON(rawResponse);
|
||||
if (response.status !== 'ok') {
|
||||
handleError(response.message || 'Nie udało się zapisać kalendarza.');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($.alert) {
|
||||
$.alert('Kalendarz został zapisany.');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
handleError('Błąd połączenia podczas zapisu kalendarza.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('body').on('change', '#ticket_group', function() {
|
||||
fetchDatesForGroup();
|
||||
});
|
||||
|
||||
$('body').on('click', '#enable-month', function() {
|
||||
updateWholeMonth(true);
|
||||
});
|
||||
|
||||
$('body').on('click', '#disable-month', function() {
|
||||
updateWholeMonth(false);
|
||||
});
|
||||
|
||||
$('body').on('click', '#save-calendar', function() {
|
||||
saveCalendar();
|
||||
});
|
||||
|
||||
fetchDatesForGroup();
|
||||
});
|
||||
</script>
|
||||
@@ -74,6 +74,11 @@
|
||||
Cennik
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/apanel/calendar/">
|
||||
Kalendarz
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/apanel/settings/">
|
||||
Ustawienia
|
||||
@@ -139,4 +144,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if (!empty($_GET['calendar_error'])) : ?>
|
||||
<div class="container mt-3">
|
||||
<div class="alert alert-danger">
|
||||
Co najmniej jeden bilet jest już niedostępny w wybranym terminie. Zmień datę w koszyku.
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="basket_page">
|
||||
<div class="basket_content">
|
||||
<div class="container">
|
||||
@@ -202,6 +210,15 @@ $(function() {
|
||||
},
|
||||
success: function(data) {
|
||||
response = jQuery.parseJSON(data);
|
||||
if (response.status === 'error') {
|
||||
if ($.alert) {
|
||||
$.alert(response.message);
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$('.box_01').html(response.basket_form);
|
||||
$('.box_02 .basket_summary').html(response.basket_summary);
|
||||
}
|
||||
@@ -296,4 +313,4 @@ $(function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
<?php
|
||||
$ticketAvailability = $this->ticket_availability ?? [];
|
||||
$isTicketAvailable = static function ($ticketId) use ($ticketAvailability) {
|
||||
if (!array_key_exists($ticketId, $ticketAvailability)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $ticketAvailability[$ticketId];
|
||||
};
|
||||
|
||||
if (isset($_POST['selected_date'])) {
|
||||
$selected_date = $_POST['selected_date'];
|
||||
$selected = DateTime::createFromFormat('d-m-Y', $selected_date);
|
||||
@@ -35,6 +44,7 @@ if (isset($_POST['selected_date'])) {
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/pl.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
|
||||
<div id="tickets-main-view">
|
||||
<div class="tickets_calendar container" >
|
||||
<form id="dateForm" method="POST">
|
||||
<div class="_title">Wybierz datę przyjazdu:</div>
|
||||
@@ -62,6 +72,7 @@ if (isset($_POST['selected_date'])) {
|
||||
</div>
|
||||
<?php for ($i = 0; $i < $count; $i++) : ?>
|
||||
<?php if (isset($ulgowe[$i])) : $item = $ulgowe[$i]; ?>
|
||||
<?php $canBuyTicket = $isTicketAvailable($item); ?>
|
||||
<div class="ticket">
|
||||
<div class="ticket-description ticket-description--<?= $this->settings['tickets'][$item]['color']; ?>">
|
||||
<h3 class="ticket__name"><?= $this->settings['tickets'][$item]['name']; ?></h3>
|
||||
@@ -74,11 +85,14 @@ if (isset($_POST['selected_date'])) {
|
||||
<?php echo date_price($this->settings['tickets'][$item], $days_diff, $is_weekend); ?>
|
||||
</h3>
|
||||
<div class="ticket-quantity">
|
||||
<button class="add button" ticket_id="<?= $item; ?>">Dodaj do koszyka</button>
|
||||
<button class="add button" ticket_id="<?= $item; ?>" <?= $canBuyTicket ? '' : 'disabled'; ?>>
|
||||
<?= $canBuyTicket ? 'Dodaj do koszyka' : 'Niedostępny'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($normalne[$i])) : $item = $normalne[$i]; ?>
|
||||
<?php $canBuyTicket = $isTicketAvailable($item); ?>
|
||||
<div class="ticket">
|
||||
<div class="ticket-description ticket-description--<?= $this->settings['tickets'][$item]['color']; ?>">
|
||||
<h3 class="ticket__name"><?= $this->settings['tickets'][$item]['name']; ?></h3>
|
||||
@@ -91,7 +105,9 @@ if (isset($_POST['selected_date'])) {
|
||||
<?php echo date_price($this->settings['tickets'][$item], $days_diff, $is_weekend); ?>
|
||||
</h3>
|
||||
<div class="ticket-quantity">
|
||||
<button class="add button" ticket_id="<?= $item; ?>">Dodaj do koszyka</button>
|
||||
<button class="add button" ticket_id="<?= $item; ?>" <?= $canBuyTicket ? '' : 'disabled'; ?>>
|
||||
<?= $canBuyTicket ? 'Dodaj do koszyka' : 'Niedostępny'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
@@ -107,6 +123,7 @@ if (isset($_POST['selected_date'])) {
|
||||
</div>
|
||||
|
||||
<? foreach($this -> settings['bilety-all-open'] as $key => $item) : ?>
|
||||
<?php $canBuyTicket = $isTicketAvailable($item); ?>
|
||||
<? $pattern = "/All Open -/"; ?>
|
||||
<div class="ticket">
|
||||
<div class="ticket-description ticket-description--<?= $this -> settings['tickets'][$item]['color']; ?>">
|
||||
@@ -123,7 +140,9 @@ if (isset($_POST['selected_date'])) {
|
||||
?>
|
||||
</h3>
|
||||
<div class="ticket-quantity">
|
||||
<button class="add button" ticket_id="<?= $item; ?>">Dodaj do koszyka</button>
|
||||
<button class="add button" ticket_id="<?= $item; ?>" <?= $canBuyTicket ? '' : 'disabled'; ?>>
|
||||
<?= $canBuyTicket ? 'Dodaj do koszyka' : 'Niedostępny'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<? endforeach; ?>
|
||||
@@ -137,6 +156,7 @@ if (isset($_POST['selected_date'])) {
|
||||
<p class="description">bilety dla rodzin</p>
|
||||
</div>
|
||||
<? foreach($this -> settings['bilety-rodzinne'] as $key => $item) : ?>
|
||||
<?php $canBuyTicket = $isTicketAvailable($item); ?>
|
||||
<div class="ticket">
|
||||
<div class="ticket-description ticket-description--<?= $this -> settings['tickets'][$item]['color']; ?>">
|
||||
<h3 class="ticket__name"><?= $this -> settings['tickets'][$item]['name']; ?></h3>
|
||||
@@ -151,7 +171,9 @@ if (isset($_POST['selected_date'])) {
|
||||
?>
|
||||
</h3>
|
||||
<div class="ticket-quantity">
|
||||
<button class="add button" ticket_id="<?= $item; ?>">Dodaj do koszyka</button>
|
||||
<button class="add button" ticket_id="<?= $item; ?>" <?= $canBuyTicket ? '' : 'disabled'; ?>>
|
||||
<?= $canBuyTicket ? 'Dodaj do koszyka' : 'Niedostępny'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<? endforeach; ?>
|
||||
@@ -164,6 +186,7 @@ if (isset($_POST['selected_date'])) {
|
||||
<p class="description">Na cały sezon</p>
|
||||
</div>
|
||||
<? foreach($this -> settings['karnety'] as $key => $item) : ?>
|
||||
<?php $canBuyTicket = $isTicketAvailable($item); ?>
|
||||
<div class="ticket">
|
||||
<div class="ticket-description ticket-description--<?= $this -> settings['tickets'][$item]['color']; ?>">
|
||||
<h3 class="ticket__name"><?= $this -> settings['tickets'][$item]['name']; ?></h3>
|
||||
@@ -179,7 +202,9 @@ if (isset($_POST['selected_date'])) {
|
||||
?>
|
||||
</h3>
|
||||
<div class="ticket-quantity">
|
||||
<button class="add button" ticket_id="<?= $item; ?>">Dodaj do koszyka</button>
|
||||
<button class="add button" ticket_id="<?= $item; ?>" <?= $canBuyTicket ? '' : 'disabled'; ?>>
|
||||
<?= $canBuyTicket ? 'Dodaj do koszyka' : 'Niedostępny'; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<? endforeach; ?>
|
||||
@@ -242,6 +267,7 @@ if (isset($_POST['selected_date'])) {
|
||||
<img src="/layout/images/shopping-basket.svg" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
@@ -297,6 +323,15 @@ $(function() {
|
||||
beforeSend: function() {},
|
||||
success: function(data) {
|
||||
response = jQuery.parseJSON(data);
|
||||
if (response.status === 'error') {
|
||||
if ($.alert) {
|
||||
$.alert(response.message);
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$('.shopping-cart-container').html(response.shopping_cart);
|
||||
|
||||
// animacja przycisku
|
||||
@@ -350,7 +385,6 @@ document.addEventListener('onChange', () => {
|
||||
})
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var dates = [ "19-05-2025", "20-05-2025", "21-05-2025", "22-05-2025", "23-05-2025", "26-05-2025", "27-05-2025", "28-05-2025", "29-05-2025", "30-05-2025", "02-06-2025", "03-06-2025", "04-06-2025", "05-06-2025", "06-06-2025", "09-06-2025", "10-06-2025", "11-06-2025", "12-06-2025", "13-06-2025", "16-06-2025", "17-06-2025", "18-06-2025", "20-06-2025", "23-06-2025", "24-06-2025", "25-06-2025", "26-06-2025", "27-06-2025" ];
|
||||
flatpickr("#flatpickr", {
|
||||
inline: true,
|
||||
dateFormat: "d-m-Y",
|
||||
@@ -358,11 +392,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
minDate: "today",
|
||||
locale: "pl",
|
||||
theme: "material_blue",
|
||||
disable: dates,
|
||||
onChange: function(selectedDates, dateStr, instance) {
|
||||
document.getElementById('dateForm').submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user