Viewing Itinerary
Only the creator can edit this itinerary
{
if (typeof p === 'string') {
return parseInt(p.replace(/[^0-9]/g, ''));
} else if (typeof p === 'number') {
return p;
}
return 0;
})
.filter((p) => p > 0);
} else if (typeof priceData === 'string') {
const priceStrings = priceData
.split(/[\n,-]+/)
.map((s) => s.trim())
.filter((s) => s);
prices = priceStrings
.map((p) => parseInt(p.replace(/[^0-9]/g, '')))
.filter((p) => p > 0);
}
if (prices.length === 0) return null;
const minPrice = Math.min(...prices);
const maxPrice = Math.max(...prices);
if (minPrice === maxPrice) {
return this.formatPriceForItinerary(minPrice);
} else {
return `${this.formatPriceForItinerary(minPrice)} - ${this.formatPriceForItinerary(maxPrice)}`;
}
} catch (e) {
return null;
}
},
formatOperationalHours(operationalHours) {
if (!operationalHours || !Array.isArray(operationalHours) || operationalHours.length === 0) {
return '-';
}
try {
const timeRanges = {};
operationalHours.forEach((hour) => {
if (hour.opening && hour.closing) {
const timeKey = `${hour.opening}-${hour.closing}`;
if (!timeRanges[timeKey]) {
timeRanges[timeKey] = [];
}
timeRanges[timeKey].push(hour.day);
}
});
const ranges = [];
Object.keys(timeRanges).forEach((timeKey) => {
const days = timeRanges[timeKey];
const [opening, closing] = timeKey.split('-');
if (days.length === 7) {
ranges.push(`Everyday: ${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`);
} else if (
days.length === 5 &&
days.includes('Monday') &&
days.includes('Tuesday') &&
days.includes('Wednesday') &&
days.includes('Thursday') &&
days.includes('Friday')
) {
ranges.push(`Weekdays: ${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`);
} else if (
days.length === 2 &&
days.includes('Saturday') &&
days.includes('Sunday')
) {
ranges.push(`Weekend: ${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`);
} else {
const dayOrder = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
const sortedDays = days.sort((a, b) => dayOrder.indexOf(a) - dayOrder.indexOf(b));
const isConsecutive = this.areDaysConsecutive(sortedDays, dayOrder);
if (isConsecutive && sortedDays.length > 1) {
const firstDay = sortedDays[0].substring(0, 3);
const lastDay = sortedDays[sortedDays.length - 1].substring(0, 3);
ranges.push(`${firstDay}-${lastDay}: ${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`);
} else {
const dayAbbr = sortedDays.map((day) => day.substring(0, 3));
ranges.push(`${dayAbbr.join(', ')}: ${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`);
}
}
});
return ranges.join(' | ');
} catch (e) {
return '-';
}
},
getSimplifiedHours(operationalHours) {
if (!operationalHours || !Array.isArray(operationalHours)) return '-';
const timeCounts = {};
operationalHours.forEach((hour) => {
if (hour.opening && hour.closing) {
const key = `${hour.opening}-${hour.closing}`;
timeCounts[key] = (timeCounts[key] || 0) + 1;
}
});
let mostCommon = null;
let maxCount = 0;
Object.keys(timeCounts).forEach((key) => {
if (timeCounts[key] > maxCount) {
maxCount = timeCounts[key];
mostCommon = key;
}
});
if (mostCommon) {
const [opening, closing] = mostCommon.split('-');
return `${this.formatTime12Hour(opening)} - ${this.formatTime12Hour(closing)}`;
}
return '-';
},
formatTime12Hour(timeString) {
if (!timeString) return '';
try {
let time = timeString.toLowerCase().replace(/\s/g, '');
if (time.includes('am') || time.includes('pm')) {
return timeString;
}
const [hours, minutes] = time.split(':');
const hourNum = parseInt(hours);
const minuteNum = minutes ? parseInt(minutes) : 0;
if (isNaN(hourNum)) return timeString;
const period = hourNum >= 12 ? 'pm' : 'am';
const displayHour = hourNum % 12 || 12;
const displayMinutes = minuteNum > 0 ? `:${String(minuteNum).padStart(2, '0')}` : '';
return `${displayHour}${displayMinutes} ${period}`;
} catch (e) {
return timeString;
}
},
areDaysConsecutive(days, dayOrder) {
for (let i = 0; i < days.length - 1; i++) {
const currentIndex = dayOrder.indexOf(days[i]);
const nextIndex = dayOrder.indexOf(days[i + 1]);
if (nextIndex - currentIndex !== 1) {
return false;
}
}
return true;
},
// Summary calculations
calculateSummary(day) {
const calc = day.calculations || {
totalDistance: 0,
totalTravelTime: 0,
totalTransportCost: 0,
totalPlacesCost: 0,
};
return {
distance: calc.totalDistance || 0,
time: calc.totalTravelTime || 0,
transportCost: calc.totalTransportCost || 0,
placesCost: calc.totalPlacesCost || 0,
hasPriceRange: false,
};
},
getSummaryDisplay(day) {
const summary = this.calculateSummary(day);
return {
distance: this.formatDistance(summary.distance) + ' km',
time: this.formatTime(summary.time),
transportCost: this.formatPriceForItinerary(summary.transportCost),
placesCost: this.formatPriceForItinerary(summary.placesCost),
};
},
// Time formatting for display
formatDuration(hours) {
if (isNaN(hours)) return '0h';
const wholeHours = Math.floor(hours);
const minutes = Math.round((hours - wholeHours) * 60);
return minutes > 0 ? `${wholeHours}h ${minutes}m` : `${wholeHours}h`;
},
// Calculate travel time between places
getSegmentDisplay(segment) {
if (!segment) return null;
return {
distance: segment.distance ? segment.distance.toFixed(2) + ' km' : '0 km',
travelTime: this.formatDuration(segment.travelTime || 0.17),
price: this.formatPriceForItinerary(segment.cost || 0),
};
},
// Initialize all days as open for view mode
initViewMode() {
this.days.forEach(day => {
day.open = true;
day.displayDate = day.displayDate || '';
});
}
}" x-init="initViewMode()" class="itinerary-app ibw-app view-mode-app">
Day
Start time:
km
•
•
Trip Distance:
Trip Duration:
Transport Cost:
Places Cost:
