Трансфер До фестиваля «Красный Шатёр» — с комфортом
Организованный трансфер из Калининграда до фестиваля и обратно. Не нужно искать парковку и идти с вещами по лесной дороге.
- Автобус привозит прямо ко входу в зону регистрации
- Фиксированная цена делится между всеми пассажирами
- Спокойный отдых на фестивале — без мыслей о дороге обратно
- Дорога — это уже начало фестиваля
Посмотреть рейсы Расписание рейсов
При наборе 50 пассажиров стоимость составит всего 350 ₽ за рейс. Цена делится между всеми участниками.
И самое приятное… Для многих участниц трансфер становится первой частью фестиваля.
Именно в дороге начинаются знакомства, появляются первые разговоры и ощущение, что вы уже стали частью большого женского круга.
Начало пути — уже магия
→
${dirLabel(t.dir)}
${isBack ? 'Старт' : 'Выезд'} ${t.depart}${t.arrive && t.arrive !== 'Калининград' ? ' · прибытие к ' + t.arrive + '' : ' · прибытие в Калининград'}
${isFull ? 'Мест нет' : (isReserved ? 'Резервируется…' : 'Мест есть')}
${isFull ? '—' : priceFor(t.booked) + ' ₽'}за место
`;
return row;
}
function renderTrips() {
listEl.innerHTML = '';
TRIPS.forEach(t => listEl.appendChild(buildRow(t)));
}
renderTrips();
// ===== form references =====
const select = document.getElementById('tfTrip');
const summaryEl = document.getElementById('tfSummary');
const summaryTitle = document.getElementById('tfSummaryTitle');
const summaryMeta = document.getElementById('tfSummaryMeta');
const summaryPrice = document.getElementById('tfSummaryPrice');
const changeBtn = document.getElementById('tfSummaryChange');
const tripDateField = document.getElementById('tfTripDate');
const tripTimeField = document.getElementById('tfTripTime');
const tripRouteField = document.getElementById('tfTripRoute');
const tripPriceField = document.getElementById('tfTripPrice');
const payBtn = document.getElementById('tfPayBtn');
const consentPD = document.getElementById('tfAgreePD');
const reserveTimerEl = document.getElementById('tfReserveTimer');
const timerCountEl = document.getElementById('tfTimerCount');
const paymentStatusField = document.getElementById('tfPaymentStatus');
const form = document.getElementById('tfTransferForm');
function rebuildSelect() {
const current = select.value;
select.innerHTML = '
';
TRIPS.forEach(t => {
const isReserved = !!t.reservedUntil && t.reservedUntil > Date.now();
if (t.total - t.booked <= 0 || isReserved) return;
const isBack = t.dir === 'back';
const timeNote = isBack ? 'старт ' + t.depart : 'выезд ' + t.depart;
const opt = document.createElement('option');
opt.value = t.id;
opt.textContent = `${t.day} (${t.weekday}) · ${timeNote} · ${dirLabel(t.dir)} — ${priceFor(t.booked)} ₽`;
select.appendChild(opt);
});
if (current && TRIPS.some(t => t.id === current && t.total - t.booked > 0 && !(t.reservedUntil > Date.now()))) {
select.value = current;
}
}
rebuildSelect();
function updateSummary(tripId) {
const trip = TRIPS.find(x => x.id === tripId);
if (!trip) {
summaryEl.classList.remove('tf-summary--show');
tripDateField.value = '';
tripTimeField.value = '';
tripRouteField.value = '';
tripPriceField.value = '';
syncPayBtn();
return;
}
const price = priceFor(trip.booked);
const timeNote = trip.dir === 'back' ? 'Старт ' + trip.depart : 'Выезд ' + trip.depart;
const arriveNote = trip.arrive && trip.arrive !== 'Калининград' ? 'прибытие к ' + trip.arrive : 'прибытие в Калининград';
summaryTitle.textContent = `${trip.day} (${trip.weekday}) · ${dirLabel(trip.dir)}`;
summaryMeta.textContent = `${timeNote} · ${arriveNote}`;
summaryPrice.textContent = price + ' ₽';
summaryEl.classList.add('tf-summary--show');
// Скрытые поля → CRM
tripDateField.value = trip.day + ' (' + trip.weekday + ')';
tripTimeField.value = trip.depart;
tripRouteField.value = dirLabel(trip.dir);
tripPriceField.value = price;
syncPayBtn();
}
select.addEventListener('change', function() { updateSummary(this.value); });
changeBtn.addEventListener('click', function() {
select.value = '';
updateSummary('');
select.focus();
});
// ===== pick from schedule -> scroll =====
document.addEventListener('click', function(e) {
const btn = e.target.closest('.tf-pick');
if (!btn || btn.disabled) return;
const tripId = btn.dataset.trip;
if (tripId) {
select.value = tripId;
updateSummary(tripId);
}
const target = document.getElementById('tfFormSection');
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
setTimeout(() => {
const nameField = document.getElementById('tfName');
if (nameField) nameField.focus({ preventScroll: true });
}, 600);
}
});
// ===== pay button gate =====
function syncPayBtn() {
const hasTrip = !!select.value;
const hasConsent = consentPD && consentPD.checked;
payBtn.disabled = !(hasTrip && hasConsent);
}
if (consentPD) consentPD.addEventListener('change', syncPayBtn);
// ===== reservation timer =====
let reserveInterval = null;
let currentReservationTrip = null;
function startReservation(tripId) {
const trip = TRIPS.find(x => x.id === tripId);
if (!trip) return;
trip.reservedUntil = Date.now() + RESERVE_MS;
currentReservationTrip = tripId;
reserveTimerEl.classList.add('tf-reservetimer--show');
paymentStatusField.value = 'резервируется, ждём оплату';
rebuildSelect();
renderTrips();
if (reserveInterval) clearInterval(reserveInterval);
reserveInterval = setInterval(() => {
const left = trip.reservedUntil - Date.now();
if (left <= 0) {
clearInterval(reserveInterval);
reserveInterval = null;
trip.reservedUntil = null;
currentReservationTrip = null;
reserveTimerEl.classList.remove('tf-reservetimer--show');
paymentStatusField.value = 'резерв истёк';
rebuildSelect();
renderTrips();
return;
}
const m = Math.floor(left / 60000);
const s = Math.floor((left % 60000) / 1000);
timerCountEl.textContent = String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0');
}, 1000);
}
function clearReservation() {
if (reserveInterval) { clearInterval(reserveInterval); reserveInterval = null; }
if (currentReservationTrip) {
const trip = TRIPS.find(x => x.id === currentReservationTrip);
if (trip) trip.reservedUntil = null;
}
currentReservationTrip = null;
reserveTimerEl.classList.remove('tf-reservetimer--show');
}
// ===== Tilda Pay integration =====
function openTildaPay() {
const trip = TRIPS.find(x => x.id === select.value);
if (!trip) return;
const amount = priceFor(trip.booked);
if (window.tildaPay && typeof window.tildaPay.open === 'function') {
window.tildaPay.open({
product: 'Трансфер «' + dirLabel(trip.dir) + '» — ' + trip.day + ' ' + trip.depart,
amount: amount,
currency: 'RUB',
email: document.getElementById('tfEmail').value || '',
phone: document.getElementById('tfPhone').value || '',
name: document.getElementById('tfName').value || '',
onSuccess: function() { onPaymentSuccess(); },
onFail: function() { paymentStatusField.value = 'ошибка оплаты'; },
onClose: function() {}
});
} else {
// Fallback: если Tilda Payments не подгрузился — отправляем как заявку
paymentStatusField.value = 'офлайн-заявка';
submitAsLead();
}
}
function submitAsLead() {
if (window.t_forms__initBtnClick) {
window.t_forms__initBtnClick({
target: payBtn,
srcElement: payBtn,
preventDefault: function() {}
});
}
}
function onPaymentSuccess() {
const trip = TRIPS.find(x => x.id === currentReservationTrip) || TRIPS.find(x => x.id === select.value);
if (trip) {
trip.booked = Math.min(trip.total, trip.booked + 1);
paymentStatusField.value = 'оплачено';
document.getElementById('tfSuccessTrip').textContent = trip.day + ' ' + trip.depart + ' · ' + dirLabel(trip.dir);
clearReservation();
renderTrips();
rebuildSelect();
submitAsLead();
const sb = form.querySelector('.js-successbox');
if (sb) {
sb.style.display = 'block';
sb.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
}
window.onReceiverSuccess = function() { /* места уже обновлены в onPaymentSuccess */ };
payBtn.addEventListener('click', function() {
if (payBtn.disabled) return;
const reqFields = form.querySelectorAll('[data-tilda-req="1"]');
let valid = true;
reqFields.forEach(function(f) {
if (f.type === 'checkbox' && !f.checked) {
valid = false;
const lbl = f.closest('.tf-consent__row');
if (lbl) lbl.style.outline = '1px solid var(--red)';
} else if (f.type !== 'checkbox' && !f.value.trim()) {
valid = false;
f.style.borderColor = 'var(--red)';
}
});
if (!valid) return;
if (!select.value) { select.style.borderColor = 'var(--red)'; return; }
startReservation(select.value);
openTildaPay();
});
form.addEventListener('input', function(e) {
if (e.target.matches('input, textarea, select')) {
e.target.style.borderColor = '';
const lbl = e.target.closest('.tf-consent__row');
if (lbl) lbl.style.outline = '';
}
});
})();