Blog

The cold pressing of olive oil

Extra virgin olive oil is a well-known gourmet element in our cuisine and also a key ingredient for our cardiovascular health. We all know it comes from olives, but how well do we know how the oil is extracted from the olive?

What is cold pressing of olive oil?

Oil’s cold pressing is the system used to extract the juice from olives, by separating oil and water that compose them. The extraction takes place, as the name suggests, using pressure. Once the olive has been harvested, it is crushed and kneaded to obtain a product known as “olive paste”. An oil with the “extra virgin olive oil” (EVOO) denomination must be extracted from the olive paste using only mechanical means (centrifuge machines), since the hot extraction process is the one used to get refined oils.
COLD PRESSING OF OLIVE OIL

When an oil isn’t cold pressed?

The oil makes up between 15% and 20% of the olive paste. Heating this paste at high temperatures would favours the oil particles concentration and, therefore, their extraction. However, above 27º C the oil loses its organoleptic properties (flavour and smell) as well as the benefits for the consumers health.

Oil extraction systems

Cold pressed, the traditional system.

Traditionally, olive oil was obtained by introducing the olive paste between two mats made from esparto to which pressure was applied by metal plate means. The result of this process was a juice, made up of olive oil and water, which was allowed to flow into tanks where the oil was separated from the water by decantation. The different densities of water and oil made the latter occupy the upper part of the tank. However, this system became outdated due to:
  • Hygienic-sanitary reasons, since current food regulations advised against the use of this system for obvious reasons.
  • Economic reasons, since the yield was lower and the costs associated with its extraction made it extremely expensive.
This system had drawbacks that made the olive oil often present some organoleptic defects.
  • The esparto mats were requiring scrupulous cleaning after each use, since the organic remains that could accumulate in them were fermenting by bacterial action and transmitting smells and flavours to the new oil.
  • Contact with the ambient oxygen and with the water obtained from the decantation was initiating the oxidation process much earlier which, again, reducing oil’s properties.
  • This process was usually repeated two or three times, in order to obtain the maximum yield. This was making both the olive paste and the water start the fermentation process between each pressing, which was increasing oil degradation in each cycle.
Oil cold pressing mats

Cold extraction, the current method

The use of more modern, clean and profitable extraction means has displaced the traditional system, which will remain as the oil’s history. Nowadays, we us centrifuge machines, which ensure the compliance of health regulations and help to produce an oil of the highest quality, free of impurities and oxidation processes as it’s not in contact with air. These centrifugal machines, also called decanters, use the density of each element present in the paste (oil, water, bone and skin) to proceed to its separation in a clean way, preserving all the oil’s properties. This centrifugation process is carried out in order to eliminate as much bone and skin particles – that can sneak into the process–  as possible. Even so, there are still small olive remains that are eliminated by filtering the oil and decanting it into storage tanks, ensuring that the oil reaches the consumer’s table in perfect condition.

Would you like to know an olive grove and the oil is produced?

Learn to recognise a high quality extra virgin olive oil, the olive cycle and all about Mallorca’s cuisine. Treurer is also a touristic emplacement in Mallorca based on oil production. Visiting to our farm will be quite an experience!

Susbcribe to our newsletter

Reservar mesa ▲

Reserva tu mesa en Qanat

Selecciona fecha, hora y número de comensales

1
Reserva tu mesa
2
Pagar y confirmar
Reserva tu mesa
Comensales
Fecha
Hora

Selecciona una fecha para ver los horarios disponibles

Tus datos
Deseo mesa compartida
Confirma tu reserva
Comensales
—
Fecha
—
Hora
—
Nombre
—
Email
—
Teléfono
—
Mesa compartida
—
Observaciones
—
Se requiere un depósito para confirmar tu reserva
0.00 €
Reembolsable si cancelas con 24h de antelación
Datos de la tarjeta
Acepto las condiciones de reserva y la política de privacidad
Condiciones de reserva

Reserva y puntualidad
Mantendremos tu mesa reservada durante 15 minutos de cortesía. Si prevés llegar más tarde, te agradeceremos que nos lo comuniques. En caso contrario, no podremos garantizar la disponibilidad de la reserva.

Cancelaciones
Las cancelaciones realizadas con menos de 24 horas de antelación no serán reembolsables en ningún caso.

Edad mínima
El acceso está permitido únicamente a mayores de 14 años.

Mascotas
Las mascotas son bienvenidas en nuestra terraza, siempre que permanezcan limpias, tranquilas, atadas y bajo la supervisión de su responsable, evitando en todo momento molestias al resto de los clientes. Nos reservamos el derecho de asignar la mesa que consideremos más adecuada. Durante la temporada de invierno, te rogamos que nos consultes antes de realizar la reserva.

Código de vestimenta
Agradecemos una vestimenta smart casual: elegante, cómoda e informal.

Convivencia
Te rogamos mantener un ambiente tranquilo, evitando alzar la voz y mostrando respeto tanto hacia los demás clientes como hacia nuestro equipo. Está permitido fumar únicamente en la zona habilitada para ello.

Restricciones alimentarias
Si tienes alguna alergia, intolerancia o restricción alimentaria, te agradeceremos que nos lo comuniques antes de tu llegada. Una vez iniciado el servicio, no podemos garantizar que sea posible realizar modificaciones en el menú.

Con el fin de preservar el ambiente y el bienestar de todos los presentes, nos reservamos el derecho de solicitar el abandono del establecimiento en caso de comportamientos que alteren la convivencia o el normal desarrollo del servicio.

Procesando...

Gestionar reserva

← Volver a reservar
📅
🕐
👥
👤
✉️
📞
⚠️
🥗
📝

🍽️ Selección del menú

Entrantes
Principales
Postres

Modificar reserva

🍽️ Selección del menú

'; }).join(''); var offset = (new Date(flavorCalYear, flavorCalMonth, 1).getDay() + 6) % 7; var dim = new Date(flavorCalYear, flavorCalMonth + 1, 0).getDate(); for (var i = 0; i < offset; i++) h += '
'; var minStr = formatDateLocal(flavorMinDate); var maxStr = formatDateLocal(flavorMaxDate); for (var d = 1; d <= dim; d++) { var date = new Date(flavorCalYear, flavorCalMonth, d); var dateStr = formatDateLocal(date); var isSel = flavorData.date === dateStr; var isToday = date.toDateString() === today.toDateString(); var isPast = dateStr < minStr || dateStr > maxStr; var isClosed = !isPast && flavorOpenDays.indexOf(date.getDay()) === -1; var isBlocked = !isPast && !isClosed && flavorBlockedDates[dateStr]; var cls = 'flavor-cal-day'; if (isPast) cls += ' past'; else if (isClosed || isBlocked) cls += ' closed'; else if (isSel) cls += ' on'; else if (isToday) cls += ' today'; if (isPast || isClosed || isBlocked) { h += '
' + d + '
'; } else { h += ''; } } grid.innerHTML = h; grid.querySelectorAll('.flavor-cal-day[data-date]').forEach(function(b) { b.addEventListener('click', function() { flavorData.date = b.dataset.date; flavorData.time = null; flavorRenderCalendar(); flavorLoadTimeSlots(flavorData.date); }); }); } document.getElementById('flavorCalPrev').addEventListener('click', function() { var now = new Date(); if (flavorCalMonth <= now.getMonth() && flavorCalYear <= now.getFullYear()) return; flavorCalMonth--; if (flavorCalMonth < 0) { flavorCalMonth = 11; flavorCalYear--; } flavorRenderCalendar(); }); document.getElementById('flavorCalNext').addEventListener('click', function() { flavorCalMonth++; if (flavorCalMonth > 11) { flavorCalMonth = 0; flavorCalYear++; } flavorRenderCalendar(); }); // ===================== // TIME SLOTS // ===================== function flavorLoadTimeSlots(dateStr) { var container = document.getElementById('flavorSlots'); var guests = flavorData.guests || 2; container.innerHTML = '

' + flavorI18n.loadingTimes + '

'; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + dateStr + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data && data.data.length > 0) { var html = ''; data.data.forEach(function(slot) { var timeShort = slot.time.substring(0, 5); if (slot.available) { var cls = 'flavor-slot' + (flavorData.time === timeShort ? ' on' : ''); html += ''; } else { var reasonText = flavorI18n.notAvailable; if (slot.reason === 'capacity') reasonText = flavorI18n.capacityFull; else if (slot.reason === 'max_reservations') reasonText = flavorI18n.maxReservations; else if (slot.reason === 'min_advance') reasonText = flavorI18n.minAdvance; html += ''; } }); container.innerHTML = html; container.querySelectorAll('.flavor-slot:not(.busy)').forEach(function(b) { b.addEventListener('click', function() { flavorData.time = b.dataset.t; container.querySelectorAll('.flavor-slot').forEach(function(s) { s.classList.remove('on'); }); b.classList.add('on'); flavorCheckStep1(); }); }); } else { container.innerHTML = '

' + flavorI18n.noTimesAvailable + '

'; } }) .catch(function() { container.innerHTML = '

' + flavorI18n.errorLoadingTimes + '

'; }); } // ===================== // CHIPS (Guests) // ===================== document.getElementById('flavorChips').addEventListener('click', function(e) { var c = e.target.closest('.flavor-chip'); if (!c) return; flavorData.guests = parseInt(c.dataset.val); document.querySelectorAll('.flavor-chip').forEach(function(x) { x.classList.remove('on'); }); c.classList.add('on'); if (flavorData.date) { flavorData.time = null; flavorLoadTimeSlots(flavorData.date); } flavorCheckStep1(); }); // ===================== // SHARED TABLE TOGGLE // ===================== var sharedToggle = document.getElementById('flavorSharedToggle'); if (sharedToggle) { sharedToggle.addEventListener('click', function() { flavorData.shared = !flavorData.shared; sharedToggle.classList.toggle('on', flavorData.shared); }); } // ===================== // VALIDATIONS // ===================== function flavorCheckStep1() { var hasBooking = !!(flavorData.date && flavorData.time); if (flavorTotalSteps === 2) { // In 2-step mode, step 1 also contains data fields var hasData = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); document.getElementById('flavorBtn1Next').disabled = !(hasBooking && hasData); } else { document.getElementById('flavorBtn1Next').disabled = !hasBooking; } } function flavorCheckStep2() { var ok = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); var btn2 = document.getElementById('flavorBtn2Next'); if (btn2) btn2.disabled = !ok; } function flavorCheckStep3() { var chk = document.getElementById('flavor-accept-terms'); // El checkbox solo existe si procede; si no está, el botón queda disponible document.getElementById('flavorBtn3Confirm').disabled = chk ? !chk.checked : false; } ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].forEach(function(id) { document.getElementById(id).addEventListener('input', function() { flavorCheckStep2(); if (flavorTotalSteps === 2) flavorCheckStep1(); }); }); (function(){ var chk = document.getElementById('flavor-accept-terms'); if (chk) chk.addEventListener('change', flavorCheckStep3); })(); function flavorValidateStep2() { var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); var em = document.getElementById('flavor-email').value.trim(); var ph = document.getElementById('flavor-phone').value.trim(); if (!fn) { flavorToast(flavorI18n.nameRequired); return false; } if (!ln) { flavorToast(flavorI18n.lastNameRequired); return false; } if (!em) { flavorToast(flavorI18n.emailRequired); return false; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { flavorToast(flavorI18n.emailInvalid); return false; } if (!ph) { flavorToast(flavorI18n.phoneRequired); return false; } return true; } // ===================== // SUMMARY // ===================== function flavorBuildSummary() { document.getElementById('sumGuests').textContent = flavorData.guests + ' ' + (flavorData.guests === 1 ? flavorI18n.person : flavorI18n.people); if (flavorData.date) { var parts = flavorData.date.split('-'); var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); var dn = flavorI18n.dayNames[d.getDay()].toLowerCase(); document.getElementById('sumDate').textContent = dn + ', ' + parseInt(parts[2]) + ' de ' + flavorI18n.months[parseInt(parts[1]) - 1].toLowerCase() + ' ' + parts[0]; } document.getElementById('sumTime').textContent = flavorData.time ? flavorData.time + 'h' : '\u2014'; var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); document.getElementById('sumName').textContent = (fn + ' ' + ln).trim() || '\u2014'; document.getElementById('sumEmail').textContent = document.getElementById('flavor-email').value.trim() || '\u2014'; var pre = document.getElementById('flavor-prefix').value; var ph = document.getElementById('flavor-phone').value.trim(); document.getElementById('sumPhone').textContent = ph ? pre + ph : '\u2014'; document.getElementById('sumShared').textContent = flavorData.shared ? flavorI18n.yes : flavorI18n.no; document.getElementById('sumNotes').textContent = document.getElementById('flavor-notes').value.trim() || '\u2014'; var depositAmount = flavorCalculateDeposit(); var depositBox = document.getElementById('flavorDepositBox'); var cardBox = document.getElementById('flavorCardInputBox'); if (depositAmount > 0 && flavorStripeKey) { depositBox.style.display = 'block'; cardBox.style.display = 'block'; document.getElementById('flavorDepAmount').textContent = depositAmount.toFixed(2) + ' \u20AC'; var perPerson = flavorDepositPerPerson > 0 ? (flavorData.guests + ' \u00D7 ' + flavorDepositPerPerson.toFixed(2) + ' \u20AC ' + flavorI18n.perPerson) : ''; document.getElementById('flavorDepSub').textContent = perPerson; document.getElementById('flavor-submit-text').style.display = 'none'; document.getElementById('flavor-submit-text-pay').style.display = 'inline'; } else { depositBox.style.display = 'none'; cardBox.style.display = 'none'; document.getElementById('flavor-submit-text').style.display = 'inline'; document.getElementById('flavor-submit-text-pay').style.display = 'none'; } } // ===================== // NAVIGATION BUTTONS // ===================== document.getElementById('flavorBtn1Next').addEventListener('click', function() { if (!flavorData.guests) { flavorToast(flavorI18n.selectGuests); return; } if (!flavorData.date) { flavorToast(flavorI18n.selectDate); return; } if (!flavorData.time) { flavorToast(flavorI18n.selectTime); return; } if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; flavorGoStep(2); }); var btn2Back = document.getElementById('flavorBtn2Back'); if (btn2Back) btn2Back.addEventListener('click', function() { flavorGoStep(1); }); var btn2Next = document.getElementById('flavorBtn2Next'); if (btn2Next) btn2Next.addEventListener('click', function() { if (!flavorValidateStep2()) return; flavorGoStep(3); }); document.getElementById('flavorBtn3Back').addEventListener('click', function() { flavorGoStep(flavorTotalSteps === 2 ? 1 : 2); }); document.getElementById('flavorBtn3Confirm').addEventListener('click', function() { flavorSubmit(); }); // Stepper click document.querySelectorAll('.flavor-step-ind').forEach(function(el) { el.addEventListener('click', function() { var target = parseInt(el.dataset.step); if (target < flavorStep) flavorGoStep(target); }); }); // ===================== // DEPOSIT & STRIPE // ===================== function flavorCalculateDeposit() { if (!flavorRequireDeposit) return 0; return flavorDepositPerReservation + (flavorDepositPerPerson * (flavorData.guests || 0)); } function flavorInitStripe() { var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && !flavorStripe) { flavorStripe = Stripe(flavorStripeKey); var elements = flavorStripe.elements({locale: 'es'}); flavorCardElement = elements.create('card', { style: { base: { fontSize: '14px', color: '#1a1a1a', fontFamily: 'Inter, -apple-system, sans-serif', '::placeholder': { color: '#c0c0c0' } }, invalid: { color: '#dc2626' } } }); flavorCardElement.mount('#flavor-card-element'); flavorCardElement.on('change', function(event) { document.getElementById('flavor-card-errors').textContent = event.error ? event.error.message : ''; }); } } // ===================== // SUBMIT // ===================== function flavorSubmit() { var _chk = document.getElementById('flavor-accept-terms'); if (_chk && !_chk.checked) { flavorToast(flavorI18n.acceptTerms); return; } // In 2-step mode, validate step2 fields before submit if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && flavorCardElement) { flavorSubmitWithPayment(); } else { flavorSubmitWithoutPayment(); } } function flavorGetPostData() { var prefix = document.getElementById('flavor-prefix').value; var phone = document.getElementById('flavor-phone').value.trim(); return { restaurant_id: flavorRestaurantId, shortcode_key: flavorShortcodeKey, guests: flavorData.guests, reservation_date: flavorData.date, reservation_time: flavorData.time, first_name: document.getElementById('flavor-first-name').value, last_name: document.getElementById('flavor-last-name').value, email: document.getElementById('flavor-email').value, phone: prefix + phone, allergies: document.getElementById('flavor-allergies').value, dietary_restrictions: '', notes: document.getElementById('flavor-notes').value, shared_table: flavorData.shared ? 1 : 0 }; } function flavorSubmitWithoutPayment() { document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(flavorGetPostData()) }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (r.success) { flavorShowSuccess(r.reservation.reservation || r.reservation); } else { flavorShowError(r.message || 'Error al crear la reserva'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorShowError(flavorI18n.error); }); } function flavorSubmitWithPayment() { var submitBtn = document.getElementById('flavorBtn3Confirm'); submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; var postData = flavorGetPostData(); var customerName = postData.first_name + ' ' + postData.last_name; var customerEmail = postData.email; fetch(flavorRestUrl + 'payment/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ restaurant_id: flavorRestaurantId, guests: flavorData.guests, name: customerName, email: customerEmail }) }) .then(function(resp) { return resp.json(); }) .then(function(paymentData) { if (!paymentData.success) throw new Error(paymentData.message || 'Error al iniciar el pago'); return flavorStripe.confirmCardPayment(paymentData.data.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: customerEmail } } }).then(function(result) { if (result.error) throw new Error(result.error.message); return result.paymentIntent.id; }); }) .then(function(paymentIntentId) { postData.payment_intent_id = paymentIntentId; postData.deposit_paid = 1; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(response) { return response.json(); }) .then(function(r) { if (!r.success) throw new Error(r.message || 'Error al crear la reserva'); submitBtn.disabled = false; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(error) { submitBtn.disabled = false; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; document.getElementById('flavor-card-errors').textContent = error.message; flavorToast(error.message); }); } // ===================== // SUCCESS / ERROR // ===================== // Ejecuta un snippet de tracking pegado por el restaurante desde el backoffice. // El snippet se sirve como
' : ''; var notesHtml = postData.notes && postData.notes.trim() ? '
' + flavorI18n.notes + ' ' + flavorEscapeHtml(postData.notes) + '
' : ''; var depositHtml = ''; var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0) { depositHtml = '
\uD83D\uDCB3 ' + flavorI18n.depositPaid + ' ' + depositAmount.toFixed(2) + ' \u20AC
'; } flavorContainer.innerHTML = '
' + '
\u2713
' + '

' + flavorI18n.reservationConfirmed + '

' + '

' + flavorI18n.reservationSuccess + '

' + '
' + code + '
' + '
' + '
' + flavorI18n.date + ' ' + dateStr + '
' + '
' + flavorI18n.time + ' ' + flavorData.time + '
' + '
' + flavorI18n.guests + ' ' + flavorData.guests + ' ' + flavorI18n.people + '
' + '
' + flavorI18n.name + ' ' + flavorEscapeHtml(postData.first_name) + ' ' + flavorEscapeHtml(postData.last_name) + '
' + '
' + flavorI18n.email + ' ' + flavorEscapeHtml(postData.email) + '
' + '
' + flavorI18n.phone + ' ' + flavorEscapeHtml(postData.phone) + '
' + '
' + flavorI18n.sharedTable + ' ' + shared + '
' + allergiesHtml + notesHtml + depositHtml + '
' + '

' + flavorI18n.receiveEmail + '

' + '' + '
'; // Disparar snippet de tracking "reserva creada" (Meta Pixel, GA, etc. según lo que haya configurado el restaurante). flavorRunTrackingSnippet('flavor-tracking-reservation'); // Si el depósito ya se ha cobrado en el mismo flujo (Stripe Elements dentro del form), el evento de pago // también corresponde ahora; el retorno de Stripe con ?payment=success cubre el otro caso (Checkout externo). if (depositAmount > 0) { flavorRunTrackingSnippet('flavor-tracking-payment'); } } function flavorShowError(message) { flavorContainer.innerHTML = '
' + '
\u2717
' + '

' + flavorI18n.error + '

' + '

' + message + '

' + '' + '
'; } // ===================== // TOAST // ===================== function flavorToast(message, type) { type = type || 'warning'; var existing = document.querySelector('.flavor-toast-modal'); var existingOverlay = document.querySelector('.flavor-toast-overlay'); if (existing) existing.remove(); if (existingOverlay) existingOverlay.remove(); var overlay = document.createElement('div'); overlay.className = 'flavor-toast-overlay'; document.body.appendChild(overlay); var toast = document.createElement('div'); toast.className = 'flavor-toast-modal'; toast.innerHTML = '
' + message + '
'; document.body.appendChild(toast); function closeToast() { toast.classList.remove('show'); overlay.classList.remove('show'); setTimeout(function() { toast.remove(); overlay.remove(); }, 250); } overlay.onclick = closeToast; setTimeout(function() { overlay.classList.add('show'); toast.classList.add('show'); }, 10); setTimeout(closeToast, 2500); } // ===================== // BLOCKED DATES & INIT // ===================== fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/blocked-dates') .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data) { flavorBlockedDates = data.data; flavorRenderCalendar(); flavorSelectFirstAvailableDate(); } }) .catch(function() { flavorSelectFirstAvailableDate(); }); function flavorSelectFirstAvailableDate() { var today = new Date(); today.setHours(0,0,0,0); for (var i = 0; i <= flavorMaxAdvanceDays; i++) { var check = new Date(today); check.setDate(today.getDate() + i); var dateStr = formatDateLocal(check); if (flavorOpenDays.indexOf(check.getDay()) === -1) continue; if (flavorBlockedDates[dateStr]) continue; if (i === 0) { var hoursLeft = 24 - new Date().getHours(); if (hoursLeft < flavorMinAdvanceHours) continue; } flavorSelectDate(dateStr); return; } } function flavorSelectDate(dateStr) { flavorData.date = dateStr; flavorData.time = null; flavorRenderCalendar(); flavorLoadTimeSlots(dateStr); } // ===================== // GESTION DE RESERVAS // ===================== var flavorCurrentReservation = null; function flavorShowManage() { document.querySelectorAll('.flavor-panel').forEach(function(s) { s.style.display = 'none'; }); document.querySelector('.flavor-stepper').style.display = 'none'; document.querySelector('.flavor-manage-view').style.display = 'block'; document.querySelector('.flavor-manage-search').style.display = 'block'; document.querySelector('.flavor-manage-result').style.display = 'none'; document.querySelector('.flavor-manage-modify').style.display = 'none'; } function flavorHideManage() { document.querySelector('.flavor-manage-view').style.display = 'none'; document.querySelectorAll('.flavor-panel').forEach(function(s) { s.style.display = 'none'; }); document.getElementById('flavorPanel1').style.display = 'block'; document.getElementById('flavorPanel1').classList.add('active'); document.querySelector('.flavor-stepper').style.display = 'flex'; flavorStep = 1; flavorUpdateStepper(); flavorCurrentReservation = null; } function flavorManageTab(tab) { document.querySelectorAll('.flavor-manage-tab').forEach(function(t) { t.classList.remove('active'); }); document.querySelectorAll('.flavor-manage-tab-content').forEach(function(c) { c.classList.remove('active'); }); document.querySelector('.flavor-manage-tab-content[data-tab="' + tab + '"]').classList.add('active'); event.target.classList.add('active'); } function flavorSearchByCode() { var code = document.getElementById('flavor-manage-code').value.trim(); if (!code) { flavorToast(flavorI18n.enterCode); return; } flavorSearchReservation({ code: code }); } function flavorSearchByData() { var firstName = document.getElementById('flavor-manage-firstname').value.trim(); var lastName = document.getElementById('flavor-manage-lastname').value.trim(); var phone = document.getElementById('flavor-manage-phone').value.trim(); var date = document.getElementById('flavor-manage-date').value; var time = document.getElementById('flavor-manage-time').value; if (!firstName) { flavorToast(flavorI18n.enterName); return; } if (!lastName) { flavorToast(flavorI18n.enterLastName); return; } if (!phone) { flavorToast(flavorI18n.enterPhone); return; } if (!date) { flavorToast(flavorI18n.enterDate); return; } if (!time) { flavorToast(flavorI18n.enterTime); return; } flavorSearchReservation({ first_name: firstName, last_name: lastName, phone: phone, date: date, time: time + ':00' }); } function flavorSearchReservation(params) { document.querySelector('.flavor-loader').style.display = 'flex'; var url = flavorRestUrl + 'reservations/search?restaurant_id=' + flavorRestaurantId; if (params.code) { url += '&code=' + encodeURIComponent(params.code); } else { url += '&first_name=' + encodeURIComponent(params.first_name); url += '&last_name=' + encodeURIComponent(params.last_name); url += '&phone=' + encodeURIComponent(params.phone); url += '&date=' + encodeURIComponent(params.date); url += '&time=' + encodeURIComponent(params.time); } fetch(url) .then(function(r) { return r.json(); }) .then(function(data) { document.querySelector('.flavor-loader').style.display = 'none'; if (data.success && data.data) { flavorCurrentReservation = data.data; flavorShowReservationResult(data.data); } else { flavorToast(data.message || flavorI18n.reservationNotFound, 'error'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorToast(flavorI18n.searchError, 'error'); }); } function flavorShowReservationResult(res) { document.querySelector('.flavor-manage-search').style.display = 'none'; document.querySelector('.flavor-manage-result').style.display = 'block'; document.querySelector('.flavor-manage-modify').style.display = 'none'; var dateParts = res.reservation_date.split('-'); var dateStr = dateParts[2] + '/' + dateParts[1] + '/' + dateParts[0]; var statusText = flavorI18n.confirmed, statusClass = 'confirmed'; if (res.status === 'pending') { statusText = flavorI18n.pending; statusClass = 'pending'; } if (res.status === 'cancelled') { statusText = flavorI18n.cancelled; statusClass = 'cancelled'; } document.querySelector('.flavor-reservation-code').textContent = res.reservation_code; document.querySelector('.flavor-reservation-status').textContent = statusText; document.querySelector('.flavor-reservation-status').className = 'flavor-reservation-status ' + statusClass; document.querySelector('.flavor-reservation-date').textContent = dateStr; document.querySelector('.flavor-reservation-time').textContent = res.reservation_time.substring(0, 5); document.querySelector('.flavor-reservation-guests').textContent = res.guests + ' ' + flavorI18n.people; document.querySelector('.flavor-reservation-name').textContent = res.first_name + ' ' + res.last_name; document.querySelector('.flavor-reservation-email').textContent = res.email || ''; document.querySelector('.flavor-reservation-phone').textContent = res.phone || ''; var allergiesRow = document.querySelector('.flavor-reservation-allergies'); if (res.allergies && res.allergies.trim()) { allergiesRow.style.display = 'flex'; document.querySelector('.flavor-reservation-allergies-text').textContent = res.allergies; } else { allergiesRow.style.display = 'none'; } var dietaryRow = document.querySelector('.flavor-reservation-dietary'); if (res.dietary_restrictions && res.dietary_restrictions.trim()) { dietaryRow.style.display = 'flex'; document.querySelector('.flavor-reservation-dietary-text').textContent = res.dietary_restrictions; } else { dietaryRow.style.display = 'none'; } var notesRow = document.querySelector('.flavor-reservation-notes'); if (res.notes && res.notes.trim()) { notesRow.style.display = 'flex'; document.querySelector('.flavor-reservation-notes-text').textContent = res.notes; } else { notesRow.style.display = 'none'; } var menuSection = document.querySelector('.flavor-reservation-menu'); var hasMenu = (res.menu_starters && res.menu_starters.trim()) || (res.menu_mains && res.menu_mains.trim()) || (res.menu_desserts && res.menu_desserts.trim()); if (hasMenu) { menuSection.style.display = 'block'; var st = document.querySelector('.flavor-reservation-starters'); if (res.menu_starters && res.menu_starters.trim()) { st.style.display = 'block'; document.querySelector('.flavor-reservation-starters-text').textContent = res.menu_starters; } else { st.style.display = 'none'; } var mn = document.querySelector('.flavor-reservation-mains'); if (res.menu_mains && res.menu_mains.trim()) { mn.style.display = 'block'; document.querySelector('.flavor-reservation-mains-text').textContent = res.menu_mains; } else { mn.style.display = 'none'; } var ds = document.querySelector('.flavor-reservation-desserts'); if (res.menu_desserts && res.menu_desserts.trim()) { ds.style.display = 'block'; document.querySelector('.flavor-reservation-desserts-text').textContent = res.menu_desserts; } else { ds.style.display = 'none'; } } else { menuSection.style.display = 'none'; } var actionsDiv = document.querySelector('.flavor-manage-actions'); if (res.status === 'cancelled') { actionsDiv.style.display = 'none'; } else { actionsDiv.style.display = 'flex'; } } function flavorShowModify() { document.querySelector('.flavor-manage-result').style.display = 'none'; document.querySelector('.flavor-manage-modify').style.display = 'block'; var res = flavorCurrentReservation; var select = document.getElementById('flavor-modify-guests'); select.innerHTML = ''; for (var i = flavorMinGuests; i <= Math.min(flavorMaxGuests, 12); i++) { var opt = document.createElement('option'); opt.value = i; opt.textContent = i + ' ' + (i === 1 ? flavorI18n.person : flavorI18n.people); if (i === parseInt(res.guests)) opt.selected = true; select.appendChild(opt); } document.getElementById('flavor-modify-date').value = res.reservation_date; document.getElementById('flavor-modify-first-name').value = res.first_name || ''; document.getElementById('flavor-modify-last-name').value = res.last_name || ''; document.getElementById('flavor-modify-email').value = res.email || ''; document.getElementById('flavor-modify-phone').value = res.phone || ''; document.getElementById('flavor-modify-allergies').value = res.allergies || ''; document.getElementById('flavor-modify-dietary').value = res.dietary_restrictions || ''; document.getElementById('flavor-modify-notes').value = res.notes || ''; document.getElementById('flavor-modify-shared-table').checked = parseInt(res.shared_table) === 1; document.getElementById('flavor-modify-starters').value = res.menu_starters || ''; document.getElementById('flavor-modify-mains').value = res.menu_mains || ''; document.getElementById('flavor-modify-desserts').value = res.menu_desserts || ''; flavorLoadModifyTimeSlots(res.reservation_date); } function flavorLoadModifyTimeSlots(date) { var select = document.getElementById('flavor-modify-time'); select.innerHTML = ''; var guests = document.getElementById('flavor-modify-guests').value; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + date + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { select.innerHTML = ''; if (data.success && data.data && data.data.length > 0) { data.data.forEach(function(slot) { if (slot.available) { var opt = document.createElement('option'); opt.value = slot.time.substring(0, 5); opt.textContent = slot.time.substring(0, 5); select.appendChild(opt); } }); var currentTime = flavorCurrentReservation.reservation_time; var hasCurrentTime = false; for (var i = 0; i < select.options.length; i++) { if (select.options[i].value === currentTime) { hasCurrentTime = true; break; } } if (!hasCurrentTime && date === flavorCurrentReservation.reservation_date) { var opt = document.createElement('option'); opt.value = currentTime; opt.textContent = currentTime.substring(0, 5) + ' ' + flavorI18n.current; opt.selected = true; select.insertBefore(opt, select.firstChild); } } else { select.innerHTML = ''; } }) .catch(function() { select.innerHTML = ''; }); } document.getElementById('flavor-modify-date').addEventListener('change', function() { flavorLoadModifyTimeSlots(this.value); }); function flavorBackToResult() { document.querySelector('.flavor-manage-modify').style.display = 'none'; document.querySelector('.flavor-manage-result').style.display = 'block'; } function flavorSaveModification() { if (!flavorCurrentReservation) return; var newTime = document.getElementById('flavor-modify-time').value; if (!newTime) { flavorToast(flavorI18n.selectTimeFirst); return; } document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations/' + flavorCurrentReservation.id + '/modify', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ guests: parseInt(document.getElementById('flavor-modify-guests').value), reservation_date: document.getElementById('flavor-modify-date').value, reservation_time: newTime, first_name: document.getElementById('flavor-modify-first-name').value, last_name: document.getElementById('flavor-modify-last-name').value, email: document.getElementById('flavor-modify-email').value, phone: document.getElementById('flavor-modify-phone').value, allergies: document.getElementById('flavor-modify-allergies').value, dietary_restrictions: document.getElementById('flavor-modify-dietary').value, notes: document.getElementById('flavor-modify-notes').value, shared_table: document.getElementById('flavor-modify-shared-table').checked ? 1 : 0, menu_starters: document.getElementById('flavor-modify-starters').value, menu_mains: document.getElementById('flavor-modify-mains').value, menu_desserts: document.getElementById('flavor-modify-desserts').value }) }) .then(function(r) { return r.json(); }) .then(function(data) { document.querySelector('.flavor-loader').style.display = 'none'; if (data.success) { flavorCurrentReservation = data.data; flavorShowReservationResult(data.data); flavorToast(flavorI18n.modifySuccess, 'success'); } else { flavorToast(data.message || flavorI18n.modifyError, 'error'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorToast(flavorI18n.modifyError, 'error'); }); } function flavorCancelReservation() { if (!flavorCurrentReservation) return; if (!confirm(flavorI18n.cancelConfirm)) return; document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations/' + flavorCurrentReservation.id + '/cancel-public', { method: 'PUT', headers: { 'Content-Type': 'application/json' } }) .then(function(r) { return r.json(); }) .then(function(data) { document.querySelector('.flavor-loader').style.display = 'none'; if (data.success) { flavorCurrentReservation.status = 'cancelled'; flavorShowReservationResult(flavorCurrentReservation); flavorToast(flavorI18n.cancelSuccess, 'success'); } else { flavorToast(data.message || flavorI18n.cancelError, 'error'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorToast(flavorI18n.cancelError, 'error'); }); } // == Init == flavorRenderCalendar(); flavorCheckStep1(); // Detect manage_code in URL (function() { var urlParams = new URLSearchParams(window.location.search); var manageCode = urlParams.get('manage_code'); if (manageCode || window.location.hash === '#manage') { flavorShowManage(); setTimeout(function() { var el = document.getElementById('manage'); if (el) { window.scrollTo({ top: window.pageYOffset + el.getBoundingClientRect().top - 20, behavior: 'smooth' }); } }, 500); if (manageCode) { document.getElementById('flavor-manage-code').value = manageCode; setTimeout(function() { flavorSearchReservation({ code: manageCode }); }, 300); } } })(); // Detectar retorno de Stripe Checkout externo con ?payment=success (link de pago enviado por email). // Dispara el snippet de tracking de pago del depósito. Se ejecuta una sola vez y limpiamos el // parámetro de la URL para que un F5 no vuelva a disparar el evento. (function() { try { var params = new URLSearchParams(window.location.search); if (params.get('payment') === 'success') { flavorRunTrackingSnippet('flavor-tracking-payment'); // Limpiar los parámetros payment=success&code=... de la URL sin recargar if (window.history && window.history.replaceState) { params.delete('payment'); params.delete('code'); var qs = params.toString(); var cleanUrl = window.location.pathname + (qs ? '?' + qs : '') + window.location.hash; window.history.replaceState({}, document.title, cleanUrl); } } } catch (e) {} })();
1
Reserva la teva taula
2
Pagar i confirmar
Reserva la teva taula
Comensals
Data
Hora

Selecciona una data per veure els horaris disponibles

Les teves dades
Desitjo taula compartida
Confirma la teva reserva
Comensals
—
Data
—
Hora
—
Nom
—
Email
—
Telèfon
—
Taula compartida
—
Observacions
—
Es requereix un dipòsit per confirmar la teva reserva
0.00 €
Reembolsable si cancelas con 24h de antelación
Dades de la targeta
Accepto les condicions de reserva i la política de privacitat
Condiciones de reserva

Reserva y puntualidad
Mantendremos tu mesa reservada durante 15 minutos de cortesía. Si prevés llegar más tarde, te agradeceremos que nos lo comuniques. En caso contrario, no podremos garantizar la disponibilidad de la reserva.

Cancelaciones
Las cancelaciones realizadas con menos de 24 horas de antelación no serán reembolsables en ningún caso.

Edad mínima
El acceso está permitido únicamente a mayores de 14 años.

Mascotas
Las mascotas son bienvenidas en nuestra terraza, siempre que permanezcan limpias, tranquilas, atadas y bajo la supervisión de su responsable, evitando en todo momento molestias al resto de los clientes. Nos reservamos el derecho de asignar la mesa que consideremos más adecuada. Durante la temporada de invierno, te rogamos que nos consultes antes de realizar la reserva.

Código de vestimenta
Agradecemos una vestimenta smart casual: elegante, cómoda e informal.

Convivencia
Te rogamos mantener un ambiente tranquilo, evitando alzar la voz y mostrando respeto tanto hacia los demás clientes como hacia nuestro equipo. Está permitido fumar únicamente en la zona habilitada para ello.

Restricciones alimentarias
Si tienes alguna alergia, intolerancia o restricción alimentaria, te agradeceremos que nos lo comuniques antes de tu llegada. Una vez iniciado el servicio, no podemos garantizar que sea posible realizar modificaciones en el menú.

Con el fin de preservar el ambiente y el bienestar de todos los presentes, nos reservamos el derecho de solicitar el abandono del establecimiento en caso de comportamientos que alteren la convivencia o el normal desarrollo del servicio.

Processant...

Gestionar reserva

← Tornar a reservar
📅
🕐
👥
👤
✉️
📞
⚠️
🥗
📝

🍽️ Selecció del menú

Entrants
Principals
Postres

Modificar reserva

🍽️ Selecció del menú

'; }).join(''); var offset = (new Date(flavorCalYear, flavorCalMonth, 1).getDay() + 6) % 7; var dim = new Date(flavorCalYear, flavorCalMonth + 1, 0).getDate(); for (var i = 0; i < offset; i++) h += '
'; var minStr = formatDateLocal(flavorMinDate); var maxStr = formatDateLocal(flavorMaxDate); for (var d = 1; d <= dim; d++) { var date = new Date(flavorCalYear, flavorCalMonth, d); var dateStr = formatDateLocal(date); var isSel = flavorData.date === dateStr; var isToday = date.toDateString() === today.toDateString(); var isPast = dateStr < minStr || dateStr > maxStr; var isClosed = !isPast && flavorOpenDays.indexOf(date.getDay()) === -1; var isBlocked = !isPast && !isClosed && flavorBlockedDates[dateStr]; var cls = 'flavor-cal-day'; if (isPast) cls += ' past'; else if (isClosed || isBlocked) cls += ' closed'; else if (isSel) cls += ' on'; else if (isToday) cls += ' today'; if (isPast || isClosed || isBlocked) { h += '
' + d + '
'; } else { h += ''; } } grid.innerHTML = h; grid.querySelectorAll('.flavor-cal-day[data-date]').forEach(function(b) { b.addEventListener('click', function() { flavorData.date = b.dataset.date; flavorData.time = null; flavorRenderCalendar(); flavorLoadTimeSlots(flavorData.date); }); }); } document.getElementById('flavorCalPrev').addEventListener('click', function() { var now = new Date(); if (flavorCalMonth <= now.getMonth() && flavorCalYear <= now.getFullYear()) return; flavorCalMonth--; if (flavorCalMonth < 0) { flavorCalMonth = 11; flavorCalYear--; } flavorRenderCalendar(); }); document.getElementById('flavorCalNext').addEventListener('click', function() { flavorCalMonth++; if (flavorCalMonth > 11) { flavorCalMonth = 0; flavorCalYear++; } flavorRenderCalendar(); }); // ===================== // TIME SLOTS // ===================== function flavorLoadTimeSlots(dateStr) { var container = document.getElementById('flavorSlots'); var guests = flavorData.guests || 2; container.innerHTML = '

' + flavorI18n.loadingTimes + '

'; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + dateStr + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data && data.data.length > 0) { var html = ''; data.data.forEach(function(slot) { var timeShort = slot.time.substring(0, 5); if (slot.available) { var cls = 'flavor-slot' + (flavorData.time === timeShort ? ' on' : ''); html += ''; } else { var reasonText = flavorI18n.notAvailable; if (slot.reason === 'capacity') reasonText = flavorI18n.capacityFull; else if (slot.reason === 'max_reservations') reasonText = flavorI18n.maxReservations; else if (slot.reason === 'min_advance') reasonText = flavorI18n.minAdvance; html += ''; } }); container.innerHTML = html; container.querySelectorAll('.flavor-slot:not(.busy)').forEach(function(b) { b.addEventListener('click', function() { flavorData.time = b.dataset.t; container.querySelectorAll('.flavor-slot').forEach(function(s) { s.classList.remove('on'); }); b.classList.add('on'); flavorCheckStep1(); }); }); } else { container.innerHTML = '

' + flavorI18n.noTimesAvailable + '

'; } }) .catch(function() { container.innerHTML = '

' + flavorI18n.errorLoadingTimes + '

'; }); } // ===================== // CHIPS (Guests) // ===================== document.getElementById('flavorChips').addEventListener('click', function(e) { var c = e.target.closest('.flavor-chip'); if (!c) return; flavorData.guests = parseInt(c.dataset.val); document.querySelectorAll('.flavor-chip').forEach(function(x) { x.classList.remove('on'); }); c.classList.add('on'); if (flavorData.date) { flavorData.time = null; flavorLoadTimeSlots(flavorData.date); } flavorCheckStep1(); }); // ===================== // SHARED TABLE TOGGLE // ===================== var sharedToggle = document.getElementById('flavorSharedToggle'); if (sharedToggle) { sharedToggle.addEventListener('click', function() { flavorData.shared = !flavorData.shared; sharedToggle.classList.toggle('on', flavorData.shared); }); } // ===================== // VALIDATIONS // ===================== function flavorCheckStep1() { var hasBooking = !!(flavorData.date && flavorData.time); if (flavorTotalSteps === 2) { // In 2-step mode, step 1 also contains data fields var hasData = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); document.getElementById('flavorBtn1Next').disabled = !(hasBooking && hasData); } else { document.getElementById('flavorBtn1Next').disabled = !hasBooking; } } function flavorCheckStep2() { var ok = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); var btn2 = document.getElementById('flavorBtn2Next'); if (btn2) btn2.disabled = !ok; } function flavorCheckStep3() { var chk = document.getElementById('flavor-accept-terms'); // El checkbox solo existe si procede; si no está, el botón queda disponible document.getElementById('flavorBtn3Confirm').disabled = chk ? !chk.checked : false; } ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].forEach(function(id) { document.getElementById(id).addEventListener('input', function() { flavorCheckStep2(); if (flavorTotalSteps === 2) flavorCheckStep1(); }); }); (function(){ var chk = document.getElementById('flavor-accept-terms'); if (chk) chk.addEventListener('change', flavorCheckStep3); })(); function flavorValidateStep2() { var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); var em = document.getElementById('flavor-email').value.trim(); var ph = document.getElementById('flavor-phone').value.trim(); if (!fn) { flavorToast(flavorI18n.nameRequired); return false; } if (!ln) { flavorToast(flavorI18n.lastNameRequired); return false; } if (!em) { flavorToast(flavorI18n.emailRequired); return false; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { flavorToast(flavorI18n.emailInvalid); return false; } if (!ph) { flavorToast(flavorI18n.phoneRequired); return false; } return true; } // ===================== // SUMMARY // ===================== function flavorBuildSummary() { document.getElementById('sumGuests').textContent = flavorData.guests + ' ' + (flavorData.guests === 1 ? flavorI18n.person : flavorI18n.people); if (flavorData.date) { var parts = flavorData.date.split('-'); var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); var dn = flavorI18n.dayNames[d.getDay()].toLowerCase(); document.getElementById('sumDate').textContent = dn + ', ' + parseInt(parts[2]) + ' de ' + flavorI18n.months[parseInt(parts[1]) - 1].toLowerCase() + ' ' + parts[0]; } document.getElementById('sumTime').textContent = flavorData.time ? flavorData.time + 'h' : '\u2014'; var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); document.getElementById('sumName').textContent = (fn + ' ' + ln).trim() || '\u2014'; document.getElementById('sumEmail').textContent = document.getElementById('flavor-email').value.trim() || '\u2014'; var pre = document.getElementById('flavor-prefix').value; var ph = document.getElementById('flavor-phone').value.trim(); document.getElementById('sumPhone').textContent = ph ? pre + ph : '\u2014'; document.getElementById('sumShared').textContent = flavorData.shared ? flavorI18n.yes : flavorI18n.no; document.getElementById('sumNotes').textContent = document.getElementById('flavor-notes').value.trim() || '\u2014'; var depositAmount = flavorCalculateDeposit(); var depositBox = document.getElementById('flavorDepositBox'); var cardBox = document.getElementById('flavorCardInputBox'); if (depositAmount > 0 && flavorStripeKey) { depositBox.style.display = 'block'; cardBox.style.display = 'block'; document.getElementById('flavorDepAmount').textContent = depositAmount.toFixed(2) + ' \u20AC'; var perPerson = flavorDepositPerPerson > 0 ? (flavorData.guests + ' \u00D7 ' + flavorDepositPerPerson.toFixed(2) + ' \u20AC ' + flavorI18n.perPerson) : ''; document.getElementById('flavorDepSub').textContent = perPerson; document.getElementById('flavor-submit-text').style.display = 'none'; document.getElementById('flavor-submit-text-pay').style.display = 'inline'; } else { depositBox.style.display = 'none'; cardBox.style.display = 'none'; document.getElementById('flavor-submit-text').style.display = 'inline'; document.getElementById('flavor-submit-text-pay').style.display = 'none'; } } // ===================== // NAVIGATION BUTTONS // ===================== document.getElementById('flavorBtn1Next').addEventListener('click', function() { if (!flavorData.guests) { flavorToast(flavorI18n.selectGuests); return; } if (!flavorData.date) { flavorToast(flavorI18n.selectDate); return; } if (!flavorData.time) { flavorToast(flavorI18n.selectTime); return; } if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; flavorGoStep(2); }); var btn2Back = document.getElementById('flavorBtn2Back'); if (btn2Back) btn2Back.addEventListener('click', function() { flavorGoStep(1); }); var btn2Next = document.getElementById('flavorBtn2Next'); if (btn2Next) btn2Next.addEventListener('click', function() { if (!flavorValidateStep2()) return; flavorGoStep(3); }); document.getElementById('flavorBtn3Back').addEventListener('click', function() { flavorGoStep(flavorTotalSteps === 2 ? 1 : 2); }); document.getElementById('flavorBtn3Confirm').addEventListener('click', function() { flavorSubmit(); }); // Stepper click document.querySelectorAll('.flavor-step-ind').forEach(function(el) { el.addEventListener('click', function() { var target = parseInt(el.dataset.step); if (target < flavorStep) flavorGoStep(target); }); }); // ===================== // DEPOSIT & STRIPE // ===================== function flavorCalculateDeposit() { if (!flavorRequireDeposit) return 0; return flavorDepositPerReservation + (flavorDepositPerPerson * (flavorData.guests || 0)); } function flavorInitStripe() { var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && !flavorStripe) { flavorStripe = Stripe(flavorStripeKey); var elements = flavorStripe.elements({locale: 'es'}); flavorCardElement = elements.create('card', { style: { base: { fontSize: '14px', color: '#1a1a1a', fontFamily: 'Inter, -apple-system, sans-serif', '::placeholder': { color: '#c0c0c0' } }, invalid: { color: '#dc2626' } } }); flavorCardElement.mount('#flavor-card-element'); flavorCardElement.on('change', function(event) { document.getElementById('flavor-card-errors').textContent = event.error ? event.error.message : ''; }); } } // ===================== // SUBMIT // ===================== function flavorSubmit() { var _chk = document.getElementById('flavor-accept-terms'); if (_chk && !_chk.checked) { flavorToast(flavorI18n.acceptTerms); return; } // In 2-step mode, validate step2 fields before submit if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && flavorCardElement) { flavorSubmitWithPayment(); } else { flavorSubmitWithoutPayment(); } } function flavorGetPostData() { var prefix = document.getElementById('flavor-prefix').value; var phone = document.getElementById('flavor-phone').value.trim(); return { restaurant_id: flavorRestaurantId, shortcode_key: flavorShortcodeKey, guests: flavorData.guests, reservation_date: flavorData.date, reservation_time: flavorData.time, first_name: document.getElementById('flavor-first-name').value, last_name: document.getElementById('flavor-last-name').value, email: document.getElementById('flavor-email').value, phone: prefix + phone, allergies: document.getElementById('flavor-allergies').value, dietary_restrictions: '', notes: document.getElementById('flavor-notes').value, shared_table: flavorData.shared ? 1 : 0 }; } function flavorSubmitWithoutPayment() { document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(flavorGetPostData()) }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (r.success) { flavorShowSuccess(r.reservation.reservation || r.reservation); } else { flavorShowError(r.message || 'Error al crear la reserva'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorShowError(flavorI18n.error); }); } function flavorSubmitWithPayment() { var submitBtn = document.getElementById('flavorBtn3Confirm'); submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; var postData = flavorGetPostData(); var customerName = postData.first_name + ' ' + postData.last_name; var customerEmail = postData.email; fetch(flavorRestUrl + 'payment/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ restaurant_id: flavorRestaurantId, guests: flavorData.guests, name: customerName, email: customerEmail }) }) .then(function(resp) { return resp.json(); }) .then(function(paymentData) { if (!paymentData.success) throw new Error(paymentData.message || 'Error al iniciar el pago'); return flavorStripe.confirmCardPayment(paymentData.data.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: customerEmail } } }).then(function(result) { if (result.error) throw new Error(result.error.message); return result.paymentIntent.id; }); }) .then(function(paymentIntentId) { postData.payment_intent_id = paymentIntentId; postData.deposit_paid = 1; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(response) { return response.json(); }) .then(function(r) { if (!r.success) throw new Error(r.message || 'Error al crear la reserva'); submitBtn.disabled = false; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(error) { submitBtn.disabled = false; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; document.getElementById('flavor-card-errors').textContent = error.message; flavorToast(error.message); }); } // ===================== // SUCCESS / ERROR // ===================== // Ejecuta un snippet de tracking pegado por el restaurante desde el backoffice. // El snippet se sirve como
1
Book your table
2
Pay and confirm
Book your table
Guests
Date
Time

Select a date to see available times

Your details
I prefer shared table
Confirm your reservation
Guests
—
Date
—
Time
—
First name
—
Email
—
Phone
—
Shared table
—
Notes
—
A deposit is required to confirm your reservation
0.00 €
Reembolsable si cancelas con 24h de antelación
Card details
I accept the booking conditions and the privacy policy
Condiciones de reserva

Reserva y puntualidad
Mantendremos tu mesa reservada durante 15 minutos de cortesía. Si prevés llegar más tarde, te agradeceremos que nos lo comuniques. En caso contrario, no podremos garantizar la disponibilidad de la reserva.

Cancelaciones
Las cancelaciones realizadas con menos de 24 horas de antelación no serán reembolsables en ningún caso.

Edad mínima
El acceso está permitido únicamente a mayores de 14 años.

Mascotas
Las mascotas son bienvenidas en nuestra terraza, siempre que permanezcan limpias, tranquilas, atadas y bajo la supervisión de su responsable, evitando en todo momento molestias al resto de los clientes. Nos reservamos el derecho de asignar la mesa que consideremos más adecuada. Durante la temporada de invierno, te rogamos que nos consultes antes de realizar la reserva.

Código de vestimenta
Agradecemos una vestimenta smart casual: elegante, cómoda e informal.

Convivencia
Te rogamos mantener un ambiente tranquilo, evitando alzar la voz y mostrando respeto tanto hacia los demás clientes como hacia nuestro equipo. Está permitido fumar únicamente en la zona habilitada para ello.

Restricciones alimentarias
Si tienes alguna alergia, intolerancia o restricción alimentaria, te agradeceremos que nos lo comuniques antes de tu llegada. Una vez iniciado el servicio, no podemos garantizar que sea posible realizar modificaciones en el menú.

Con el fin de preservar el ambiente y el bienestar de todos los presentes, nos reservamos el derecho de solicitar el abandono del establecimiento en caso de comportamientos que alteren la convivencia o el normal desarrollo del servicio.

Processing...

Manage reservation

← Back to booking
📅
🕐
👥
👤
✉️
📞
⚠️
🥗
📝

🍽️ Menu selection

Starters
Main courses
Desserts

Modify reservation

🍽️ Menu selection

'; }).join(''); var offset = (new Date(flavorCalYear, flavorCalMonth, 1).getDay() + 6) % 7; var dim = new Date(flavorCalYear, flavorCalMonth + 1, 0).getDate(); for (var i = 0; i < offset; i++) h += '
'; var minStr = formatDateLocal(flavorMinDate); var maxStr = formatDateLocal(flavorMaxDate); for (var d = 1; d <= dim; d++) { var date = new Date(flavorCalYear, flavorCalMonth, d); var dateStr = formatDateLocal(date); var isSel = flavorData.date === dateStr; var isToday = date.toDateString() === today.toDateString(); var isPast = dateStr < minStr || dateStr > maxStr; var isClosed = !isPast && flavorOpenDays.indexOf(date.getDay()) === -1; var isBlocked = !isPast && !isClosed && flavorBlockedDates[dateStr]; var cls = 'flavor-cal-day'; if (isPast) cls += ' past'; else if (isClosed || isBlocked) cls += ' closed'; else if (isSel) cls += ' on'; else if (isToday) cls += ' today'; if (isPast || isClosed || isBlocked) { h += '
' + d + '
'; } else { h += ''; } } grid.innerHTML = h; grid.querySelectorAll('.flavor-cal-day[data-date]').forEach(function(b) { b.addEventListener('click', function() { flavorData.date = b.dataset.date; flavorData.time = null; flavorRenderCalendar(); flavorLoadTimeSlots(flavorData.date); }); }); } document.getElementById('flavorCalPrev').addEventListener('click', function() { var now = new Date(); if (flavorCalMonth <= now.getMonth() && flavorCalYear <= now.getFullYear()) return; flavorCalMonth--; if (flavorCalMonth < 0) { flavorCalMonth = 11; flavorCalYear--; } flavorRenderCalendar(); }); document.getElementById('flavorCalNext').addEventListener('click', function() { flavorCalMonth++; if (flavorCalMonth > 11) { flavorCalMonth = 0; flavorCalYear++; } flavorRenderCalendar(); }); // ===================== // TIME SLOTS // ===================== function flavorLoadTimeSlots(dateStr) { var container = document.getElementById('flavorSlots'); var guests = flavorData.guests || 2; container.innerHTML = '

' + flavorI18n.loadingTimes + '

'; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + dateStr + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data && data.data.length > 0) { var html = ''; data.data.forEach(function(slot) { var timeShort = slot.time.substring(0, 5); if (slot.available) { var cls = 'flavor-slot' + (flavorData.time === timeShort ? ' on' : ''); html += ''; } else { var reasonText = flavorI18n.notAvailable; if (slot.reason === 'capacity') reasonText = flavorI18n.capacityFull; else if (slot.reason === 'max_reservations') reasonText = flavorI18n.maxReservations; else if (slot.reason === 'min_advance') reasonText = flavorI18n.minAdvance; html += ''; } }); container.innerHTML = html; container.querySelectorAll('.flavor-slot:not(.busy)').forEach(function(b) { b.addEventListener('click', function() { flavorData.time = b.dataset.t; container.querySelectorAll('.flavor-slot').forEach(function(s) { s.classList.remove('on'); }); b.classList.add('on'); flavorCheckStep1(); }); }); } else { container.innerHTML = '

' + flavorI18n.noTimesAvailable + '

'; } }) .catch(function() { container.innerHTML = '

' + flavorI18n.errorLoadingTimes + '

'; }); } // ===================== // CHIPS (Guests) // ===================== document.getElementById('flavorChips').addEventListener('click', function(e) { var c = e.target.closest('.flavor-chip'); if (!c) return; flavorData.guests = parseInt(c.dataset.val); document.querySelectorAll('.flavor-chip').forEach(function(x) { x.classList.remove('on'); }); c.classList.add('on'); if (flavorData.date) { flavorData.time = null; flavorLoadTimeSlots(flavorData.date); } flavorCheckStep1(); }); // ===================== // SHARED TABLE TOGGLE // ===================== var sharedToggle = document.getElementById('flavorSharedToggle'); if (sharedToggle) { sharedToggle.addEventListener('click', function() { flavorData.shared = !flavorData.shared; sharedToggle.classList.toggle('on', flavorData.shared); }); } // ===================== // VALIDATIONS // ===================== function flavorCheckStep1() { var hasBooking = !!(flavorData.date && flavorData.time); if (flavorTotalSteps === 2) { // In 2-step mode, step 1 also contains data fields var hasData = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); document.getElementById('flavorBtn1Next').disabled = !(hasBooking && hasData); } else { document.getElementById('flavorBtn1Next').disabled = !hasBooking; } } function flavorCheckStep2() { var ok = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); var btn2 = document.getElementById('flavorBtn2Next'); if (btn2) btn2.disabled = !ok; } function flavorCheckStep3() { var chk = document.getElementById('flavor-accept-terms'); // El checkbox solo existe si procede; si no está, el botón queda disponible document.getElementById('flavorBtn3Confirm').disabled = chk ? !chk.checked : false; } ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].forEach(function(id) { document.getElementById(id).addEventListener('input', function() { flavorCheckStep2(); if (flavorTotalSteps === 2) flavorCheckStep1(); }); }); (function(){ var chk = document.getElementById('flavor-accept-terms'); if (chk) chk.addEventListener('change', flavorCheckStep3); })(); function flavorValidateStep2() { var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); var em = document.getElementById('flavor-email').value.trim(); var ph = document.getElementById('flavor-phone').value.trim(); if (!fn) { flavorToast(flavorI18n.nameRequired); return false; } if (!ln) { flavorToast(flavorI18n.lastNameRequired); return false; } if (!em) { flavorToast(flavorI18n.emailRequired); return false; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { flavorToast(flavorI18n.emailInvalid); return false; } if (!ph) { flavorToast(flavorI18n.phoneRequired); return false; } return true; } // ===================== // SUMMARY // ===================== function flavorBuildSummary() { document.getElementById('sumGuests').textContent = flavorData.guests + ' ' + (flavorData.guests === 1 ? flavorI18n.person : flavorI18n.people); if (flavorData.date) { var parts = flavorData.date.split('-'); var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); var dn = flavorI18n.dayNames[d.getDay()].toLowerCase(); document.getElementById('sumDate').textContent = dn + ', ' + parseInt(parts[2]) + ' de ' + flavorI18n.months[parseInt(parts[1]) - 1].toLowerCase() + ' ' + parts[0]; } document.getElementById('sumTime').textContent = flavorData.time ? flavorData.time + 'h' : '\u2014'; var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); document.getElementById('sumName').textContent = (fn + ' ' + ln).trim() || '\u2014'; document.getElementById('sumEmail').textContent = document.getElementById('flavor-email').value.trim() || '\u2014'; var pre = document.getElementById('flavor-prefix').value; var ph = document.getElementById('flavor-phone').value.trim(); document.getElementById('sumPhone').textContent = ph ? pre + ph : '\u2014'; document.getElementById('sumShared').textContent = flavorData.shared ? flavorI18n.yes : flavorI18n.no; document.getElementById('sumNotes').textContent = document.getElementById('flavor-notes').value.trim() || '\u2014'; var depositAmount = flavorCalculateDeposit(); var depositBox = document.getElementById('flavorDepositBox'); var cardBox = document.getElementById('flavorCardInputBox'); if (depositAmount > 0 && flavorStripeKey) { depositBox.style.display = 'block'; cardBox.style.display = 'block'; document.getElementById('flavorDepAmount').textContent = depositAmount.toFixed(2) + ' \u20AC'; var perPerson = flavorDepositPerPerson > 0 ? (flavorData.guests + ' \u00D7 ' + flavorDepositPerPerson.toFixed(2) + ' \u20AC ' + flavorI18n.perPerson) : ''; document.getElementById('flavorDepSub').textContent = perPerson; document.getElementById('flavor-submit-text').style.display = 'none'; document.getElementById('flavor-submit-text-pay').style.display = 'inline'; } else { depositBox.style.display = 'none'; cardBox.style.display = 'none'; document.getElementById('flavor-submit-text').style.display = 'inline'; document.getElementById('flavor-submit-text-pay').style.display = 'none'; } } // ===================== // NAVIGATION BUTTONS // ===================== document.getElementById('flavorBtn1Next').addEventListener('click', function() { if (!flavorData.guests) { flavorToast(flavorI18n.selectGuests); return; } if (!flavorData.date) { flavorToast(flavorI18n.selectDate); return; } if (!flavorData.time) { flavorToast(flavorI18n.selectTime); return; } if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; flavorGoStep(2); }); var btn2Back = document.getElementById('flavorBtn2Back'); if (btn2Back) btn2Back.addEventListener('click', function() { flavorGoStep(1); }); var btn2Next = document.getElementById('flavorBtn2Next'); if (btn2Next) btn2Next.addEventListener('click', function() { if (!flavorValidateStep2()) return; flavorGoStep(3); }); document.getElementById('flavorBtn3Back').addEventListener('click', function() { flavorGoStep(flavorTotalSteps === 2 ? 1 : 2); }); document.getElementById('flavorBtn3Confirm').addEventListener('click', function() { flavorSubmit(); }); // Stepper click document.querySelectorAll('.flavor-step-ind').forEach(function(el) { el.addEventListener('click', function() { var target = parseInt(el.dataset.step); if (target < flavorStep) flavorGoStep(target); }); }); // ===================== // DEPOSIT & STRIPE // ===================== function flavorCalculateDeposit() { if (!flavorRequireDeposit) return 0; return flavorDepositPerReservation + (flavorDepositPerPerson * (flavorData.guests || 0)); } function flavorInitStripe() { var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && !flavorStripe) { flavorStripe = Stripe(flavorStripeKey); var elements = flavorStripe.elements({locale: 'es'}); flavorCardElement = elements.create('card', { style: { base: { fontSize: '14px', color: '#1a1a1a', fontFamily: 'Inter, -apple-system, sans-serif', '::placeholder': { color: '#c0c0c0' } }, invalid: { color: '#dc2626' } } }); flavorCardElement.mount('#flavor-card-element'); flavorCardElement.on('change', function(event) { document.getElementById('flavor-card-errors').textContent = event.error ? event.error.message : ''; }); } } // ===================== // SUBMIT // ===================== function flavorSubmit() { var _chk = document.getElementById('flavor-accept-terms'); if (_chk && !_chk.checked) { flavorToast(flavorI18n.acceptTerms); return; } // In 2-step mode, validate step2 fields before submit if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && flavorCardElement) { flavorSubmitWithPayment(); } else { flavorSubmitWithoutPayment(); } } function flavorGetPostData() { var prefix = document.getElementById('flavor-prefix').value; var phone = document.getElementById('flavor-phone').value.trim(); return { restaurant_id: flavorRestaurantId, shortcode_key: flavorShortcodeKey, guests: flavorData.guests, reservation_date: flavorData.date, reservation_time: flavorData.time, first_name: document.getElementById('flavor-first-name').value, last_name: document.getElementById('flavor-last-name').value, email: document.getElementById('flavor-email').value, phone: prefix + phone, allergies: document.getElementById('flavor-allergies').value, dietary_restrictions: '', notes: document.getElementById('flavor-notes').value, shared_table: flavorData.shared ? 1 : 0 }; } function flavorSubmitWithoutPayment() { document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(flavorGetPostData()) }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (r.success) { flavorShowSuccess(r.reservation.reservation || r.reservation); } else { flavorShowError(r.message || 'Error al crear la reserva'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorShowError(flavorI18n.error); }); } function flavorSubmitWithPayment() { var submitBtn = document.getElementById('flavorBtn3Confirm'); submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; var postData = flavorGetPostData(); var customerName = postData.first_name + ' ' + postData.last_name; var customerEmail = postData.email; fetch(flavorRestUrl + 'payment/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ restaurant_id: flavorRestaurantId, guests: flavorData.guests, name: customerName, email: customerEmail }) }) .then(function(resp) { return resp.json(); }) .then(function(paymentData) { if (!paymentData.success) throw new Error(paymentData.message || 'Error al iniciar el pago'); return flavorStripe.confirmCardPayment(paymentData.data.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: customerEmail } } }).then(function(result) { if (result.error) throw new Error(result.error.message); return result.paymentIntent.id; }); }) .then(function(paymentIntentId) { postData.payment_intent_id = paymentIntentId; postData.deposit_paid = 1; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(response) { return response.json(); }) .then(function(r) { if (!r.success) throw new Error(r.message || 'Error al crear la reserva'); submitBtn.disabled = false; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(error) { submitBtn.disabled = false; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; document.getElementById('flavor-card-errors').textContent = error.message; flavorToast(error.message); }); } // ===================== // SUCCESS / ERROR // ===================== // Ejecuta un snippet de tracking pegado por el restaurante desde el backoffice. // El snippet se sirve como
1
Tisch reservieren
2
Bezahlen und bestätigen
Tisch reservieren
Gäste
Datum
Zeit

Wählen Sie ein Datum, um verfügbare Zeiten zu sehen

Ihre Daten
Ich wünsche geteilten Tisch
Reservierung bestätigen
Gäste
—
Datum
—
Zeit
—
Vorname
—
E-Mail
—
Telefon
—
Geteilter Tisch
—
Bemerkungen
—
Eine Anzahlung ist erforderlich, um Ihre Reservierung zu bestätigen
0.00 €
Reembolsable si cancelas con 24h de antelación
Kartendaten
Ich akzeptiere die Reservierungsbedingungen und die Datenschutzrichtlinie
Condiciones de reserva

Reserva y puntualidad
Mantendremos tu mesa reservada durante 15 minutos de cortesía. Si prevés llegar más tarde, te agradeceremos que nos lo comuniques. En caso contrario, no podremos garantizar la disponibilidad de la reserva.

Cancelaciones
Las cancelaciones realizadas con menos de 24 horas de antelación no serán reembolsables en ningún caso.

Edad mínima
El acceso está permitido únicamente a mayores de 14 años.

Mascotas
Las mascotas son bienvenidas en nuestra terraza, siempre que permanezcan limpias, tranquilas, atadas y bajo la supervisión de su responsable, evitando en todo momento molestias al resto de los clientes. Nos reservamos el derecho de asignar la mesa que consideremos más adecuada. Durante la temporada de invierno, te rogamos que nos consultes antes de realizar la reserva.

Código de vestimenta
Agradecemos una vestimenta smart casual: elegante, cómoda e informal.

Convivencia
Te rogamos mantener un ambiente tranquilo, evitando alzar la voz y mostrando respeto tanto hacia los demás clientes como hacia nuestro equipo. Está permitido fumar únicamente en la zona habilitada para ello.

Restricciones alimentarias
Si tienes alguna alergia, intolerancia o restricción alimentaria, te agradeceremos que nos lo comuniques antes de tu llegada. Una vez iniciado el servicio, no podemos garantizar que sea posible realizar modificaciones en el menú.

Con el fin de preservar el ambiente y el bienestar de todos los presentes, nos reservamos el derecho de solicitar el abandono del establecimiento en caso de comportamientos que alteren la convivencia o el normal desarrollo del servicio.

Wird verarbeitet...

Reservierung verwalten

← Zurück zur Buchung
📅
🕐
👥
👤
✉️
📞
⚠️
🥗
📝

🍽️ Menüauswahl

Vorspeisen
Hauptgerichte
Desserts

Reservierung ändern

🍽️ Menüauswahl

'; }).join(''); var offset = (new Date(flavorCalYear, flavorCalMonth, 1).getDay() + 6) % 7; var dim = new Date(flavorCalYear, flavorCalMonth + 1, 0).getDate(); for (var i = 0; i < offset; i++) h += '
'; var minStr = formatDateLocal(flavorMinDate); var maxStr = formatDateLocal(flavorMaxDate); for (var d = 1; d <= dim; d++) { var date = new Date(flavorCalYear, flavorCalMonth, d); var dateStr = formatDateLocal(date); var isSel = flavorData.date === dateStr; var isToday = date.toDateString() === today.toDateString(); var isPast = dateStr < minStr || dateStr > maxStr; var isClosed = !isPast && flavorOpenDays.indexOf(date.getDay()) === -1; var isBlocked = !isPast && !isClosed && flavorBlockedDates[dateStr]; var cls = 'flavor-cal-day'; if (isPast) cls += ' past'; else if (isClosed || isBlocked) cls += ' closed'; else if (isSel) cls += ' on'; else if (isToday) cls += ' today'; if (isPast || isClosed || isBlocked) { h += '
' + d + '
'; } else { h += ''; } } grid.innerHTML = h; grid.querySelectorAll('.flavor-cal-day[data-date]').forEach(function(b) { b.addEventListener('click', function() { flavorData.date = b.dataset.date; flavorData.time = null; flavorRenderCalendar(); flavorLoadTimeSlots(flavorData.date); }); }); } document.getElementById('flavorCalPrev').addEventListener('click', function() { var now = new Date(); if (flavorCalMonth <= now.getMonth() && flavorCalYear <= now.getFullYear()) return; flavorCalMonth--; if (flavorCalMonth < 0) { flavorCalMonth = 11; flavorCalYear--; } flavorRenderCalendar(); }); document.getElementById('flavorCalNext').addEventListener('click', function() { flavorCalMonth++; if (flavorCalMonth > 11) { flavorCalMonth = 0; flavorCalYear++; } flavorRenderCalendar(); }); // ===================== // TIME SLOTS // ===================== function flavorLoadTimeSlots(dateStr) { var container = document.getElementById('flavorSlots'); var guests = flavorData.guests || 2; container.innerHTML = '

' + flavorI18n.loadingTimes + '

'; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + dateStr + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data && data.data.length > 0) { var html = ''; data.data.forEach(function(slot) { var timeShort = slot.time.substring(0, 5); if (slot.available) { var cls = 'flavor-slot' + (flavorData.time === timeShort ? ' on' : ''); html += ''; } else { var reasonText = flavorI18n.notAvailable; if (slot.reason === 'capacity') reasonText = flavorI18n.capacityFull; else if (slot.reason === 'max_reservations') reasonText = flavorI18n.maxReservations; else if (slot.reason === 'min_advance') reasonText = flavorI18n.minAdvance; html += ''; } }); container.innerHTML = html; container.querySelectorAll('.flavor-slot:not(.busy)').forEach(function(b) { b.addEventListener('click', function() { flavorData.time = b.dataset.t; container.querySelectorAll('.flavor-slot').forEach(function(s) { s.classList.remove('on'); }); b.classList.add('on'); flavorCheckStep1(); }); }); } else { container.innerHTML = '

' + flavorI18n.noTimesAvailable + '

'; } }) .catch(function() { container.innerHTML = '

' + flavorI18n.errorLoadingTimes + '

'; }); } // ===================== // CHIPS (Guests) // ===================== document.getElementById('flavorChips').addEventListener('click', function(e) { var c = e.target.closest('.flavor-chip'); if (!c) return; flavorData.guests = parseInt(c.dataset.val); document.querySelectorAll('.flavor-chip').forEach(function(x) { x.classList.remove('on'); }); c.classList.add('on'); if (flavorData.date) { flavorData.time = null; flavorLoadTimeSlots(flavorData.date); } flavorCheckStep1(); }); // ===================== // SHARED TABLE TOGGLE // ===================== var sharedToggle = document.getElementById('flavorSharedToggle'); if (sharedToggle) { sharedToggle.addEventListener('click', function() { flavorData.shared = !flavorData.shared; sharedToggle.classList.toggle('on', flavorData.shared); }); } // ===================== // VALIDATIONS // ===================== function flavorCheckStep1() { var hasBooking = !!(flavorData.date && flavorData.time); if (flavorTotalSteps === 2) { // In 2-step mode, step 1 also contains data fields var hasData = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); document.getElementById('flavorBtn1Next').disabled = !(hasBooking && hasData); } else { document.getElementById('flavorBtn1Next').disabled = !hasBooking; } } function flavorCheckStep2() { var ok = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); var btn2 = document.getElementById('flavorBtn2Next'); if (btn2) btn2.disabled = !ok; } function flavorCheckStep3() { var chk = document.getElementById('flavor-accept-terms'); // El checkbox solo existe si procede; si no está, el botón queda disponible document.getElementById('flavorBtn3Confirm').disabled = chk ? !chk.checked : false; } ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].forEach(function(id) { document.getElementById(id).addEventListener('input', function() { flavorCheckStep2(); if (flavorTotalSteps === 2) flavorCheckStep1(); }); }); (function(){ var chk = document.getElementById('flavor-accept-terms'); if (chk) chk.addEventListener('change', flavorCheckStep3); })(); function flavorValidateStep2() { var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); var em = document.getElementById('flavor-email').value.trim(); var ph = document.getElementById('flavor-phone').value.trim(); if (!fn) { flavorToast(flavorI18n.nameRequired); return false; } if (!ln) { flavorToast(flavorI18n.lastNameRequired); return false; } if (!em) { flavorToast(flavorI18n.emailRequired); return false; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { flavorToast(flavorI18n.emailInvalid); return false; } if (!ph) { flavorToast(flavorI18n.phoneRequired); return false; } return true; } // ===================== // SUMMARY // ===================== function flavorBuildSummary() { document.getElementById('sumGuests').textContent = flavorData.guests + ' ' + (flavorData.guests === 1 ? flavorI18n.person : flavorI18n.people); if (flavorData.date) { var parts = flavorData.date.split('-'); var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); var dn = flavorI18n.dayNames[d.getDay()].toLowerCase(); document.getElementById('sumDate').textContent = dn + ', ' + parseInt(parts[2]) + ' de ' + flavorI18n.months[parseInt(parts[1]) - 1].toLowerCase() + ' ' + parts[0]; } document.getElementById('sumTime').textContent = flavorData.time ? flavorData.time + 'h' : '\u2014'; var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); document.getElementById('sumName').textContent = (fn + ' ' + ln).trim() || '\u2014'; document.getElementById('sumEmail').textContent = document.getElementById('flavor-email').value.trim() || '\u2014'; var pre = document.getElementById('flavor-prefix').value; var ph = document.getElementById('flavor-phone').value.trim(); document.getElementById('sumPhone').textContent = ph ? pre + ph : '\u2014'; document.getElementById('sumShared').textContent = flavorData.shared ? flavorI18n.yes : flavorI18n.no; document.getElementById('sumNotes').textContent = document.getElementById('flavor-notes').value.trim() || '\u2014'; var depositAmount = flavorCalculateDeposit(); var depositBox = document.getElementById('flavorDepositBox'); var cardBox = document.getElementById('flavorCardInputBox'); if (depositAmount > 0 && flavorStripeKey) { depositBox.style.display = 'block'; cardBox.style.display = 'block'; document.getElementById('flavorDepAmount').textContent = depositAmount.toFixed(2) + ' \u20AC'; var perPerson = flavorDepositPerPerson > 0 ? (flavorData.guests + ' \u00D7 ' + flavorDepositPerPerson.toFixed(2) + ' \u20AC ' + flavorI18n.perPerson) : ''; document.getElementById('flavorDepSub').textContent = perPerson; document.getElementById('flavor-submit-text').style.display = 'none'; document.getElementById('flavor-submit-text-pay').style.display = 'inline'; } else { depositBox.style.display = 'none'; cardBox.style.display = 'none'; document.getElementById('flavor-submit-text').style.display = 'inline'; document.getElementById('flavor-submit-text-pay').style.display = 'none'; } } // ===================== // NAVIGATION BUTTONS // ===================== document.getElementById('flavorBtn1Next').addEventListener('click', function() { if (!flavorData.guests) { flavorToast(flavorI18n.selectGuests); return; } if (!flavorData.date) { flavorToast(flavorI18n.selectDate); return; } if (!flavorData.time) { flavorToast(flavorI18n.selectTime); return; } if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; flavorGoStep(2); }); var btn2Back = document.getElementById('flavorBtn2Back'); if (btn2Back) btn2Back.addEventListener('click', function() { flavorGoStep(1); }); var btn2Next = document.getElementById('flavorBtn2Next'); if (btn2Next) btn2Next.addEventListener('click', function() { if (!flavorValidateStep2()) return; flavorGoStep(3); }); document.getElementById('flavorBtn3Back').addEventListener('click', function() { flavorGoStep(flavorTotalSteps === 2 ? 1 : 2); }); document.getElementById('flavorBtn3Confirm').addEventListener('click', function() { flavorSubmit(); }); // Stepper click document.querySelectorAll('.flavor-step-ind').forEach(function(el) { el.addEventListener('click', function() { var target = parseInt(el.dataset.step); if (target < flavorStep) flavorGoStep(target); }); }); // ===================== // DEPOSIT & STRIPE // ===================== function flavorCalculateDeposit() { if (!flavorRequireDeposit) return 0; return flavorDepositPerReservation + (flavorDepositPerPerson * (flavorData.guests || 0)); } function flavorInitStripe() { var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && !flavorStripe) { flavorStripe = Stripe(flavorStripeKey); var elements = flavorStripe.elements({locale: 'es'}); flavorCardElement = elements.create('card', { style: { base: { fontSize: '14px', color: '#1a1a1a', fontFamily: 'Inter, -apple-system, sans-serif', '::placeholder': { color: '#c0c0c0' } }, invalid: { color: '#dc2626' } } }); flavorCardElement.mount('#flavor-card-element'); flavorCardElement.on('change', function(event) { document.getElementById('flavor-card-errors').textContent = event.error ? event.error.message : ''; }); } } // ===================== // SUBMIT // ===================== function flavorSubmit() { var _chk = document.getElementById('flavor-accept-terms'); if (_chk && !_chk.checked) { flavorToast(flavorI18n.acceptTerms); return; } // In 2-step mode, validate step2 fields before submit if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && flavorCardElement) { flavorSubmitWithPayment(); } else { flavorSubmitWithoutPayment(); } } function flavorGetPostData() { var prefix = document.getElementById('flavor-prefix').value; var phone = document.getElementById('flavor-phone').value.trim(); return { restaurant_id: flavorRestaurantId, shortcode_key: flavorShortcodeKey, guests: flavorData.guests, reservation_date: flavorData.date, reservation_time: flavorData.time, first_name: document.getElementById('flavor-first-name').value, last_name: document.getElementById('flavor-last-name').value, email: document.getElementById('flavor-email').value, phone: prefix + phone, allergies: document.getElementById('flavor-allergies').value, dietary_restrictions: '', notes: document.getElementById('flavor-notes').value, shared_table: flavorData.shared ? 1 : 0 }; } function flavorSubmitWithoutPayment() { document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(flavorGetPostData()) }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (r.success) { flavorShowSuccess(r.reservation.reservation || r.reservation); } else { flavorShowError(r.message || 'Error al crear la reserva'); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorShowError(flavorI18n.error); }); } function flavorSubmitWithPayment() { var submitBtn = document.getElementById('flavorBtn3Confirm'); submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; var postData = flavorGetPostData(); var customerName = postData.first_name + ' ' + postData.last_name; var customerEmail = postData.email; fetch(flavorRestUrl + 'payment/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ restaurant_id: flavorRestaurantId, guests: flavorData.guests, name: customerName, email: customerEmail }) }) .then(function(resp) { return resp.json(); }) .then(function(paymentData) { if (!paymentData.success) throw new Error(paymentData.message || 'Error al iniciar el pago'); return flavorStripe.confirmCardPayment(paymentData.data.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: customerEmail } } }).then(function(result) { if (result.error) throw new Error(result.error.message); return result.paymentIntent.id; }); }) .then(function(paymentIntentId) { postData.payment_intent_id = paymentIntentId; postData.deposit_paid = 1; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(response) { return response.json(); }) .then(function(r) { if (!r.success) throw new Error(r.message || 'Error al crear la reserva'); submitBtn.disabled = false; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(error) { submitBtn.disabled = false; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; document.getElementById('flavor-card-errors').textContent = error.message; flavorToast(error.message); }); } // ===================== // SUCCESS / ERROR // ===================== // Ejecuta un snippet de tracking pegado por el restaurante desde el backoffice. // El snippet se sirve como
Miguel Miralles

Miquel Miralles, Treurer's CEO, is part of the owner family, being already the second generation involved in the project. He has a background in economics and law, and has taken numerous courses related to foreign trade, olive agronomy and extra virgin olive oil production techniques. His training and experience of more than 15 years in the world of olive oil are her guarantee to lead this project.

Entradas recientes

  • Blog
  • Uncategorized
  • Turismo

Pollença: heritage, art and spirituality in the heart of Mallorca

Discover Pollença, cradle of art and spirituality in Mallorca: churches, the Calvary, artistic tradition and…

3 weeks hace
  • Blog
  • Blog
  • Gourmet
  • Gourmet

Winter Gastronomy in Mallorca: Seasonal Dishes and New-Harvest Olive Oil

Discover winter gastronomy in Mallorca: seasonal dishes, traditional recipes and the new-harvest olive oil that…

4 weeks hace
  • Uncategorized

Oli Treurer, Gold Award at the NYIOOC 2026 for the Fourth Consecutive Year

Oli Treurer wins the Gold Award at the NYIOOC World Olive Oil Competition 2026 for…

3 months hace
  • Uncategorized

Luxury Couscous

The perfect salad for spring! A delicious and easy couscous salad recipe, quick to prepare…

3 months hace
  • Uncategorized

Power Salad

Chickpea salad with beetroot and avocado made by Chef Thomas kocht.

3 months hace
  • Uncategorized

Panzanella

A delicious bread salad recipe by German Chef Thomas Kocht. Made with very ripe tomatoes…

3 months hace