As the vibrant hues of fall give way to the crisp, cool days of winter, Vancouver’s dining scene undergoes a magical transformation. At the forefront is the Westin Bayshore’s H Tasting Lounge, bringing back its famed Winterlust dome dining experience. This unique concept reimagines outdoor dining, allowing guests to enjoy the beauty of Vancouver’s winters …
The Canyon Lights in Capilano Suspension bridge is back for 2023, and this attraction will once again enchant visitors to experience the countless twinkling lights adorning the forest and the suspension bridge. In this article, will guide you through this magical setting, highlighting why it’s an unmissable destination for both locals and tourists. …
Are you planning to catch Taylor Swift on her much-anticipated Eras Tour but worried about the cost of accommodation? Fear not, Swifties! With some savvy planning and a few insider tips, you can find affordable lodging that won’t break the bank, since tickets are already expensive. Here’s how to secure cheap accommodation for the Taylor …
As the festive season dawns, Metro Vancouver transforms into a wonderland of twinkling lights and festive cheer, with Christmas markets popping up across the city. These markets, each with its unique character and offerings, are not just about shopping; they represent the essence of community, culture, and the spirit of the holiday season in Vancouver. …
Vancouver, a city renowned for its diverse culinary landscape, is a haven for Korean BBQ enthusiasts. From the sizzle of premium meats on the grill to the rich, authentic flavors of Korea, these restaurants offer an unforgettable dining experience. Let’s embark on a gastronomic journey to explore some of the best Korean BBQ spots in …
Sleep is nowadays is a luxury when you travel, napping just to recharge is now treated is a premium for someone working in past-face environment. A young builder from NYC has a built a dream to help moms who work overnights at the hospital, his dream is to build a sleep station or sleeping pods, …
Whether you’re in Vancouver to stroll through the historic Gastown or simply bike the Stanley Park Seawall, packing right is always the first step. Here are the backpack essentials that you should not forget. Always Check the Weather The weather in Vancouver is always changing, the city is known for its unpredictable skies and …
Vancouver’s swag is starting to comeback and the rhythm of the rails is back once again as the Stanley Park train is back to brighten up our Christmas. The announcement that Bright Nights will illuminate the park this year comes as a sparkling gift to the community, with Mayor Ken Sim sharing the news …
It’s that time of the year again, Vancouver lights up with the spirit of the holiday season with a line up events. It’s a month of vibrant celebrations, heartwarming traditions, and electrifying concerts. Whether you’re a local or a visitor staying at the Panda Pod Hotel, there’s a festive event waiting for you. From …
Let’s face it, the views are great but the parking is a bit too much in Vancouver. Whether you’re a local or a tourist looking to cut costs from something boring like a parking spot, this article can help you find the cheapest parking spots in downtown and nearby neighbourhoods. But don’t let the thought …
${success ? "" : `Contact Us on WhatsApp`}`;
}
function showSameDayClosedMessage() {
const box = $("#ppc5-availability-result");
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard("Same-Day Booking Closed", "It is after 6:00 PM in Vancouver. Please contact us on WhatsApp, mention that you are a crew member, and ask for Front Desk.");
box.focus();
}
function availabilityFailure(result) {
if (result.nights.some(night => night.crewAllocation === 0)) return ["Crew Offer Unavailable for Selected Date", "Crew self-booking is not available for one or more selected dates. Please contact us on WhatsApp for alternate availability."];
if (result.nights.some(night => night.crewRemaining === 0)) return ["Crew Allocation Reached", "The crew allocation for one or more selected dates has been reached. Please contact us and we will check whether additional pods can be offered."];
return ["Crew Availability Is Not Available", "Crew availability is not available for one or more selected dates. Please contact us and we will check other options."];
}
async function runAvailability(advance) {
if (!validateStep(1)) return false;
const data = getFormData();
const pod = selectedPod();
const box = $("#ppc5-availability-result");
const button = $("#ppc5-check-availability");
availability = null;
box.classList.add("ppc5-hidden");
if (!config) {
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard("Crew Offer Is Still Loading", "Please wait a moment, then check availability again.");
box.focus();
return false;
}
if (!config.offerEnabled) {
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard("Crew Offer Unavailable", "Crew self-booking is currently unavailable. Please contact us on WhatsApp.");
box.focus();
return false;
}
if (!findRatePeriod(data.checkInDate, data.checkOutDate)) {
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard("Crew Offer Unavailable for Selected Date", "The crew offer does not cover all selected stay dates. Please contact us for alternate availability.");
box.focus();
return false;
}
button.disabled = true;
button.textContent = "Checking…";
try {
const result = await checkCrewAvailability({ checkInDate: data.checkInDate, checkOutDate: data.checkOutDate, roomTypeID: pod.roomTypeID });
availability = result;
if (result.available) {
const minimum = Math.min(...result.nights.map(night => Math.min(night.crewRemaining, night.cloudbedsRoomsAvailable)));
box.className = "ppc5-result ppc5-result--success";
box.innerHTML = resultCard("Crew Availability Confirmed", `${pod.label} is available for all ${result.nights.length} night${result.nights.length === 1 ? "" : "s"}. At least ${minimum} crew pod${minimum === 1 ? "" : "s"} remain per selected night.`, true);
$("#ppc5-live").textContent = "Crew availability confirmed for every selected night.";
if (advance) showStep(2);
} else {
const [title, message] = availabilityFailure(result);
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard(title, message);
box.focus();
}
return result.available;
} catch (error) {
box.className = "ppc5-result ppc5-result--error";
box.innerHTML = resultCard("Availability Check Unavailable", "We could not safely confirm availability. No booking was made. Please retry or contact us on WhatsApp.");
box.focus();
return false;
} finally {
button.disabled = false;
button.textContent = "Check Availability";
}
}
function buildPayload() {
const data = getFormData();
const pod = selectedPod();
return {
checkInDate: data.checkInDate,
checkOutDate: data.checkOutDate,
roomTypeID: pod.roomTypeID,
podType: pod.type,
guest: {
firstName: data.firstName.trim(), lastName: data.lastName.trim(), email: data.email.trim(),
phone: data.phone.trim(), airline: data.airline.trim(), crewRole: data.crewRole,
returningCrew: data.returningCrew === "true"
},
arrival: {
eta: data.eta,
earlyCheckInRequested: data.earlyRequested !== "none",
earlyCheckInOption: data.earlyRequested,
earlyCheckInTime: null,
lateCheckOutRequested: data.lateRequested !== "none",
lateCheckOutOption: data.lateRequested,
lateCheckOutTime: null
},
damageDepositAuthorizationConfirmed: data.cardAuthorizationComplete === "on",
policyAccepted: true
};
}
async function submitBooking(event) {
event.preventDefault();
if (!validateStep(5)) return;
// Recheck immediately before creation in case the guest crossed 6:00 PM during the form.
const cutoff = getSameDayCutoffState();
if ($("#ppc5-checkin").value === cutoff.date && cutoff.closed) {
showStep(1);
setError($("#ppc5-checkin"), "Same-day booking is closed after 6:00 PM. Please contact us on WhatsApp.");
showSameDayClosedMessage();
return;
}
const button = $("#ppc5-create");
const errorBox = $("#ppc5-submit-error");
errorBox.classList.add("ppc5-hidden");
button.disabled = true;
button.textContent = "Creating Reservation…";
try {
// FAIL CLOSED: first-time crew images require an approved private upload API.
// Do not remove this guard until the backend securely stores the image and
// returns an opaque upload token that can be linked to the reservation.
const returningCrewSelection = $("input[name=returningCrew]:checked");
if (!DEMO_MODE && returningCrewSelection && returningCrewSelection.value === "false") {
throw new Error("Secure RAIC/Crew ID image storage is not connected. No image or reservation was sent.");
}
if (!(await runAvailability(false))) throw new Error("Availability changed. Please return to Step 1 and review the message.");
const payload = buildPayload();
const response = await createCrewReservation(payload);
if (!response || !response.success || !response.reservationNumber) throw new Error("The reservation could not be created.");
const pod = selectedPod();
const rows = [
["Reservation number", response.reservationNumber], ["Check-in", formatDate(payload.checkInDate)],
["Check-out", formatDate(payload.checkOutDate)], ["Pod type", pod.label],
["Amount due", response.amountDue != null ? `${money(response.amountDue, response.currency || "CAD")} CAD` : "Provided by Panda Pod payment request"],
["Payment status", response.paymentStatus || "PENDING"]
];
$("#ppc5-success-summary").innerHTML = rows.map(([key, value]) => `
Recent Comments