Ultimate Spring Hiking Guide in Vancouver Image courtesy: Unsplash Vancouver’s Scenic Trails Let’s embark on a journey through Vancouver’s breathtaking landscapes, where every trail tells a story and every step brings a new adventure. Nestled between the Pacific Ocean and the Coast Mountains, Vancouver offers a hiking paradise for enthusiasts of all levels. From the …
Embarking on your first journey in the lavish realms of first and business class can be an exhilarating experience. With their promise of indulgence, relaxation, and superior service, these premium cabins offer more than just a travel service; they are an experience in themselves. However, stepping into this world of luxury comes with its unspoken …
🚨 Get ready to sail through new waters as BC Ferries plans a 3.2% fare increase across all routes. But hold on, there’s more to this wave of changes than meets the eye! 🌊 Discover how this move aims to streamline travel, reduce congestion, and even save you money! 💰 Dive deeper into the details …
🚗 By Car: Zoom to the park in 20-25 mins, taking Taylor Way exit for a direct route. Scenic drive takes 30-35 mins. 🚌 Public Transit: Bus 246 gets you there in 45 mins for $3.05. Bus 250 offers a scenic ride in 55 mins. 🚲 Cycling: For the adventurous, cycle there in 1.5 hours …
Exploring the nomadic lifestyle brings freedom but can feel lonely. Here are top tips for building connections: 💃 Attend Local Events: Dive into food festivals and cultural events to mingle and embrace local traditions. 📸 Visit Tourist Attractions: Meet fellow nomads at iconic spots. Don’t miss our guide on Vancouver’s attractions! 👥 **Join Social Media …
ultimate spring hiking guide in vancouver Ultimate Spring Hiking Guide in Vancouver Image courtesy: Unsplash Vancouver’s Scenic Trails Let’s embark on a journey through Vancouver’s breathtaking landscapes, where every trail tells a story and every step brings a new adventure. Nestled between the Pacific Ocean and the Coast Mountains, Vancouver offers a hiking paradise for …
Embarking on your first journey in the lavish realms of first and business class can be an exhilarating experience. With their promise of indulgence, relaxation, and superior service, these premium cabins offer more than just a travel service; they are an experience in themselves. However, stepping into this world of luxury comes with its unspoken …
Boeing plane missing external panel lands in Oregon airport Introduction Imagine embarking on a routine flight and upon landing, discovering your aircraft was missing a vital piece of its exterior. This exact scenario unfolded for passengers and crew aboard a Boeing 737-800, highlighting yet another incident in Boeing’s recent string of aircraft malfunctions. On a …
YVR Food Workers Strike Introduction Welcome to our blog where we dive deep into the latest updates and coverage surrounding the Vancouver Airport (YVR) Food Workers Strike. The impending strike is a pivotal event that could potentially disrupt services at YVR, one of Canada’s busiest airports, especially during the critical spring break and Easter travel …
A Winter Getaway in the Canadian Rockies: Snowshoeing, Hot Springs, and Mountain Views Introduction Welcome to the winter wonderland of the Canadian Rockies, where adventure awaits around every snow-covered corner! Imagine stepping into a world where the air is crisp, the snow crunches underfoot, and the views are straight out of a postcard. This isn’t …
${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