update
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/* Yacht Calendar (All) — wspólny widok wszystkich jachtów.
|
||||
Layout, instrukcja, legenda i formularz dziedziczą z calendar.css
|
||||
(klasy .yacht-inquiry-layout, .yacht-calendar-instructions, .yacht-calendar-legend,
|
||||
.yacht-inquiry-form-container, .yacht-inquiry-form). Tutaj tylko nadpisania
|
||||
specyficzne dla widgetu zbiorczego. */
|
||||
|
||||
.yacht-calendar-all-wrapper {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto 40px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.yacht-calendar-all {
|
||||
width: 100%;
|
||||
/* Ciemne granatowe tło — emuluje styl /rezerwacja-maja/ gdzie komórki bg-event
|
||||
są semi-transparent (#f5f9ff @ 0.66) nad ciemnym tłem parent containera. */
|
||||
background: #0e2036;
|
||||
}
|
||||
|
||||
/* Komórki przyszłe — semi-transparent biały, daje ciemnoszary efekt nad #0e2036
|
||||
(efekt identyczny jak yacht-day-available bg-event w single-yacht widget). */
|
||||
.yacht-calendar-all .fc-daygrid-day {
|
||||
background: rgba(245, 249, 255, 0.4);
|
||||
}
|
||||
|
||||
/* Przeszłe — białe (jak yacht-day-available .fc-event-past w single-yacht). */
|
||||
.yacht-calendar-all .fc-daygrid-day.fc-day-past {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
/* Dziś — lekko jaśniejszy ciemny. */
|
||||
.yacht-calendar-all .fc-daygrid-day.fc-day-today {
|
||||
background: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
/* Sąsiedni miesiąc — taki sam jak przyszłe (spójny ciemny). */
|
||||
.yacht-calendar-all .fc-daygrid-day.fc-day-other {
|
||||
background: rgba(245, 249, 255, 0.32);
|
||||
}
|
||||
|
||||
|
||||
/* Select w formularzu zapytania — calendar.css nie ma reguł dla <select>,
|
||||
wymuszamy ten sam styl co inputy (ciemnoprzezroczysty, biały tekst, custom strzałka). */
|
||||
.yacht-inquiry-form select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid hsla(0, 0%, 100%, 0.2);
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
||||
background-color: hsla(0, 0%, 100%, 0.1);
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' stroke='white' stroke-width='2' fill='none'/></svg>");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 12px center;
|
||||
padding-right: 32px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.yacht-inquiry-form select:focus {
|
||||
outline: none;
|
||||
border-color: #bc1834;
|
||||
box-shadow: 0 0 0 3px rgba(188, 24, 52, 0.3);
|
||||
background-color: hsla(0, 0%, 100%, 0.15);
|
||||
}
|
||||
|
||||
.yacht-inquiry-form select option {
|
||||
background: #021526;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Event styling — pełne wypełnienie kafelka kolorem jachtu, bez kropek/czasu */
|
||||
.yacht-calendar-all .fc-event {
|
||||
border: none !important;
|
||||
padding: 2px 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.yacht-calendar-all .fc-event-title,
|
||||
.yacht-calendar-all .fc-daygrid-event-dot,
|
||||
.yacht-calendar-all .fc-event-time {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Pasek eventu zawsze wyższy żeby był czytelny bez tekstu */
|
||||
.yacht-calendar-all .fc-daygrid-event {
|
||||
min-height: 18px;
|
||||
}
|
||||
|
||||
/* Half-day visual: gradient wpisywany przez calendar-all.js (eventDidMount), który
|
||||
liczy szerokość komórki dnia i ustawia background-image dla danego segmentu. */
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 600px) {
|
||||
.yacht-calendar-all .fc-event {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.yacht-calendar-all .fc-toolbar.fc-header-toolbar {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Yacht Calendar (All) — wspólny widok wszystkich jachtów.
|
||||
*
|
||||
* Inicjalizuje FullCalendar dayGridMonth dla każdego elementu .yacht-calendar-all-wrapper
|
||||
* na stronie. Pobiera eventy z REST `/availability/all` (timed 12:00→12:00), renderuje
|
||||
* legendę kolorów wyciągniętą z eventów i dodaje klasy half-day na pierwszym/ostatnim
|
||||
* dniu każdej rezerwacji.
|
||||
*/
|
||||
(function ($) {
|
||||
'use strict';
|
||||
|
||||
if (typeof window.FullCalendar === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
function pad(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
function ymd(date) {
|
||||
return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate());
|
||||
}
|
||||
|
||||
function initCalendar(wrapper) {
|
||||
var $wrapper = $(wrapper);
|
||||
var $cal = $wrapper.find('.yacht-calendar-all');
|
||||
if (!$cal.length) return;
|
||||
|
||||
var restUrl = $wrapper.data('rest');
|
||||
if (!restUrl) return;
|
||||
|
||||
var heightPx = parseInt($wrapper.data('height'), 10);
|
||||
if (!heightPx || heightPx < 200) heightPx = 650;
|
||||
|
||||
var calendar = new window.FullCalendar.Calendar($cal.get(0), {
|
||||
initialView: 'dayGridMonth',
|
||||
locale: 'pl',
|
||||
firstDay: 1,
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: ''
|
||||
},
|
||||
height: heightPx,
|
||||
displayEventTime: false,
|
||||
eventDisplay: 'block',
|
||||
events: function (fetchInfo, successCallback, failureCallback) {
|
||||
var url = restUrl
|
||||
+ (restUrl.indexOf('?') === -1 ? '?' : '&')
|
||||
+ 'start=' + ymd(fetchInfo.start)
|
||||
+ '&end=' + ymd(fetchInfo.end);
|
||||
|
||||
$.getJSON(url)
|
||||
.done(function (data) {
|
||||
successCallback(data || []);
|
||||
})
|
||||
.fail(function () {
|
||||
failureCallback(new Error('Failed to fetch /availability/all'));
|
||||
});
|
||||
},
|
||||
eventDidMount: function (info) {
|
||||
// Per-event color via CSS variable.
|
||||
var color = info.event.backgroundColor || '#3498db';
|
||||
info.el.style.setProperty('--yc-event-color', color);
|
||||
|
||||
// Half-day visual: gradient z half-cell transparent na pierwszym/ostatnim dniu.
|
||||
// Liczone po renderze (wymaga znajomości szerokości komórki dnia w siatce).
|
||||
// Przekładamy na requestAnimationFrame żeby DOM był ułożony.
|
||||
window.requestAnimationFrame(function () {
|
||||
applyHalfDayGradient(info);
|
||||
});
|
||||
},
|
||||
eventContent: function () {
|
||||
// Pasek koloru bez treści — privacy: nie pokazujemy nazwisk klientów ani nazw jachtów.
|
||||
return { html: '' };
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
|
||||
// Inquiry form submission (yacht select dropdown).
|
||||
var $form = $wrapper.find('.yacht-calendar-all-inquiry-form');
|
||||
if ($form.length) {
|
||||
$form.on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $submitBtn = $form.find('.yacht-booking-submit');
|
||||
var $response = $form.find('.yacht-calendar-all-inquiry-response');
|
||||
var originalBtnText = $submitBtn.text();
|
||||
var i18n = (window.yachtBookingData && window.yachtBookingData.i18n) || {};
|
||||
|
||||
var yachtId = parseInt($form.find('[name="yacht_id"]').val(), 10) || 0;
|
||||
if (!yachtId) {
|
||||
$response.html('<div class="booking-error" style="padding: 12px; background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; border-radius: 4px;"><strong>' +
|
||||
(i18n.errorTitle || 'Błąd!') + '</strong> Wybierz jacht z listy.</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
$submitBtn.prop('disabled', true).text(i18n.submitting || 'Wysyłanie...');
|
||||
$response.html('');
|
||||
|
||||
var formData = {
|
||||
yacht_id: yachtId,
|
||||
customer_name: $form.find('[name="customer_name"]').val(),
|
||||
customer_email: $form.find('[name="customer_email"]').val(),
|
||||
customer_phone: $form.find('[name="customer_phone"]').val(),
|
||||
preferred_dates: $form.find('[name="preferred_dates"]').val(),
|
||||
message: $form.find('[name="message"]').val()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: window.yachtBookingData.apiUrl + '/inquiries',
|
||||
method: 'POST',
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader('X-WP-Nonce', window.yachtBookingData.nonce);
|
||||
},
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(formData),
|
||||
success: function (resp) {
|
||||
$response.html('<div class="booking-success" style="padding: 12px; background: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"><strong>' +
|
||||
(i18n.successTitle || 'Sukces!') + '</strong> ' +
|
||||
((resp && resp.message) || i18n.inquirySuccess || 'Twoje zapytanie zostało wysłane.') +
|
||||
'</div>');
|
||||
$form[0].reset();
|
||||
},
|
||||
error: function (xhr) {
|
||||
var msg = i18n.errorMessage || 'Wystąpił błąd. Spróbuj ponownie.';
|
||||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||||
msg = xhr.responseJSON.message;
|
||||
}
|
||||
$response.html('<div class="booking-error" style="padding: 12px; background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; border-radius: 4px;"><strong>' +
|
||||
(i18n.errorTitle || 'Błąd!') + '</strong> ' + msg + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$submitBtn.prop('disabled', false).text(originalBtnText);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply half-day gradient to event bar. Pierwsze dni rezerwacji: lewa połowa pierwszej
|
||||
* komórki transparentna (yacht wraca w południe). Ostatnie: prawa połowa ostatniej
|
||||
* komórki transparentna (yacht wypływa w południe). Dla segmentów środkowych — pełny kolor.
|
||||
*/
|
||||
function applyHalfDayGradient(info) {
|
||||
var el = info.el;
|
||||
var rect = el.getBoundingClientRect();
|
||||
if (!rect.width) return;
|
||||
|
||||
// Find a sibling day cell to read its width.
|
||||
var dayCell = el.closest('.fc-daygrid-day') || el.closest('td');
|
||||
// Fallback: scan parent for any .fc-daygrid-day sibling.
|
||||
if (!dayCell) {
|
||||
var grid = el.closest('.fc-daygrid');
|
||||
if (grid) {
|
||||
dayCell = grid.querySelector('.fc-daygrid-day');
|
||||
}
|
||||
}
|
||||
if (!dayCell) return;
|
||||
|
||||
var cellRect = dayCell.getBoundingClientRect();
|
||||
if (!cellRect.width) return;
|
||||
|
||||
var halfPct = (cellRect.width / 2) / rect.width * 100;
|
||||
// Clamp to safe bounds.
|
||||
if (halfPct < 1) halfPct = 1;
|
||||
if (halfPct > 49) halfPct = 49;
|
||||
|
||||
var color = el.style.getPropertyValue('--yc-event-color') || '#3498db';
|
||||
var startTrans = info.isStart;
|
||||
var endTrans = info.isEnd;
|
||||
|
||||
// Build gradient.
|
||||
var stops;
|
||||
if (startTrans && endTrans) {
|
||||
// Single segment containing both start and end.
|
||||
stops = [
|
||||
'transparent 0%',
|
||||
'transparent ' + halfPct.toFixed(2) + '%',
|
||||
color + ' ' + halfPct.toFixed(2) + '%',
|
||||
color + ' ' + (100 - halfPct).toFixed(2) + '%',
|
||||
'transparent ' + (100 - halfPct).toFixed(2) + '%',
|
||||
'transparent 100%'
|
||||
];
|
||||
} else if (startTrans) {
|
||||
stops = [
|
||||
'transparent 0%',
|
||||
'transparent ' + halfPct.toFixed(2) + '%',
|
||||
color + ' ' + halfPct.toFixed(2) + '%',
|
||||
color + ' 100%'
|
||||
];
|
||||
} else if (endTrans) {
|
||||
stops = [
|
||||
color + ' 0%',
|
||||
color + ' ' + (100 - halfPct).toFixed(2) + '%',
|
||||
'transparent ' + (100 - halfPct).toFixed(2) + '%',
|
||||
'transparent 100%'
|
||||
];
|
||||
} else {
|
||||
// Middle segment — pełny kolor.
|
||||
el.style.backgroundColor = color;
|
||||
el.style.backgroundImage = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
el.style.backgroundImage = 'linear-gradient(to right, ' + stops.join(', ') + ')';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
return String(str).replace(/[&<>"']/g, function (m) {
|
||||
return ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
})[m];
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('.yacht-calendar-all-wrapper').each(function () {
|
||||
initCalendar(this);
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user