fixing jsonSchema validation by using zod
This commit is contained in:
92
src/data/airlines.ts
Normal file
92
src/data/airlines.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Airline mock data with IATA codes, names, and countries
|
||||
* Covers 30+ major carriers worldwide
|
||||
*/
|
||||
|
||||
export const airlines = [
|
||||
// United States Carriers
|
||||
{ code: 'AA', name: 'American Airlines', country: 'US', alliance: 'oneworld' },
|
||||
{ code: 'DL', name: 'Delta Air Lines', country: 'US', alliance: 'SkyTeam' },
|
||||
{ code: 'UA', name: 'United Airlines', country: 'US', alliance: 'Star Alliance' },
|
||||
{ code: 'WN', name: 'Southwest Airlines', country: 'US', alliance: null },
|
||||
{ code: 'B6', name: 'JetBlue Airways', country: 'US', alliance: null },
|
||||
{ code: 'AS', name: 'Alaska Airlines', country: 'US', alliance: 'oneworld' },
|
||||
{ code: 'F9', name: 'Frontier Airlines', country: 'US', alliance: null },
|
||||
{ code: 'NK', name: 'Spirit Airlines', country: 'US', alliance: null },
|
||||
|
||||
// European Carriers
|
||||
{ code: 'BA', name: 'British Airways', country: 'GB', alliance: 'oneworld' },
|
||||
{ code: 'AF', name: 'Air France', country: 'FR', alliance: 'SkyTeam' },
|
||||
{ code: 'LH', name: 'Lufthansa', country: 'DE', alliance: 'Star Alliance' },
|
||||
{ code: 'KL', name: 'KLM Royal Dutch Airlines', country: 'NL', alliance: 'SkyTeam' },
|
||||
{ code: 'IB', name: 'Iberia', country: 'ES', alliance: 'oneworld' },
|
||||
{ code: 'AZ', name: 'ITA Airways', country: 'IT', alliance: 'SkyTeam' },
|
||||
{ code: 'LX', name: 'Swiss International Air Lines', country: 'CH', alliance: 'Star Alliance' },
|
||||
{ code: 'VS', name: 'Virgin Atlantic', country: 'GB', alliance: null },
|
||||
|
||||
// Asian Carriers
|
||||
{ code: 'NH', name: 'All Nippon Airways', country: 'JP', alliance: 'Star Alliance' },
|
||||
{ code: 'JL', name: 'Japan Airlines', country: 'JP', alliance: 'oneworld' },
|
||||
{ code: 'SQ', name: 'Singapore Airlines', country: 'SG', alliance: 'Star Alliance' },
|
||||
{ code: 'CX', name: 'Cathay Pacific', country: 'HK', alliance: 'oneworld' },
|
||||
{ code: 'KE', name: 'Korean Air', country: 'KR', alliance: 'SkyTeam' },
|
||||
{ code: 'OZ', name: 'Asiana Airlines', country: 'KR', alliance: 'Star Alliance' },
|
||||
{ code: 'TG', name: 'Thai Airways', country: 'TH', alliance: 'Star Alliance' },
|
||||
{ code: 'CA', name: 'Air China', country: 'CN', alliance: 'Star Alliance' },
|
||||
{ code: 'MU', name: 'China Eastern Airlines', country: 'CN', alliance: 'SkyTeam' },
|
||||
|
||||
// Middle East Carriers
|
||||
{ code: 'EK', name: 'Emirates', country: 'AE', alliance: null },
|
||||
{ code: 'QR', name: 'Qatar Airways', country: 'QA', alliance: 'oneworld' },
|
||||
{ code: 'EY', name: 'Etihad Airways', country: 'AE', alliance: null },
|
||||
|
||||
// Other Major Carriers
|
||||
{ code: 'AC', name: 'Air Canada', country: 'CA', alliance: 'Star Alliance' },
|
||||
{ code: 'QF', name: 'Qantas', country: 'AU', alliance: 'oneworld' },
|
||||
{ code: 'NZ', name: 'Air New Zealand', country: 'NZ', alliance: 'Star Alliance' },
|
||||
{ code: 'AM', name: 'Aeroméxico', country: 'MX', alliance: 'SkyTeam' },
|
||||
{ code: 'LA', name: 'LATAM Airlines', country: 'CL', alliance: 'oneworld' }
|
||||
];
|
||||
|
||||
/**
|
||||
* Get airline by IATA code
|
||||
* @param {string} code - IATA airline code (2 letters)
|
||||
* @returns {Object|null} Airline object or null if not found
|
||||
*/
|
||||
export function getAirline(code: string) {
|
||||
return airlines.find((a) => a.code === code.toUpperCase()) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get random airline for route generation
|
||||
* @returns {Object} Random airline object
|
||||
*/
|
||||
export function getRandomAirline() {
|
||||
return airlines[Math.floor(Math.random() * airlines.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if airline code exists
|
||||
* @param {string} code - IATA airline code
|
||||
* @returns {boolean} True if airline exists
|
||||
*/
|
||||
export function isValidAirline(code: string) {
|
||||
return getAirline(code) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get airlines by alliance
|
||||
* @param {string} alliance - Alliance name (oneworld, SkyTeam, Star Alliance)
|
||||
* @returns {Object[]} Array of airline objects
|
||||
*/
|
||||
export function getAirlinesByAlliance(alliance: string) {
|
||||
return airlines.filter((a) => a.alliance === alliance);
|
||||
}
|
||||
|
||||
export default {
|
||||
airlines,
|
||||
getAirline,
|
||||
getRandomAirline,
|
||||
isValidAirline,
|
||||
getAirlinesByAlliance
|
||||
};
|
||||
133
src/data/airports.ts
Normal file
133
src/data/airports.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Airport mock data with IATA codes, names, cities, timezones, and coordinates
|
||||
* Covers 100+ major airports worldwide
|
||||
*/
|
||||
|
||||
export const airports = [
|
||||
// United States - Major Hubs
|
||||
{ code: 'JFK', name: 'John F. Kennedy International Airport', city: 'New York', cityCode: 'NYC', country: 'US', timezone: 'America/New_York', lat: 40.6413, lon: -73.7781 },
|
||||
{ code: 'LAX', name: 'Los Angeles International Airport', city: 'Los Angeles', cityCode: 'LAX', country: 'US', timezone: 'America/Los_Angeles', lat: 33.9416, lon: -118.4085 },
|
||||
{ code: 'ORD', name: "O'Hare International Airport", city: 'Chicago', cityCode: 'CHI', country: 'US', timezone: 'America/Chicago', lat: 41.9742, lon: -87.9073 },
|
||||
{ code: 'ATL', name: 'Hartsfield-Jackson Atlanta International Airport', city: 'Atlanta', cityCode: 'ATL', country: 'US', timezone: 'America/New_York', lat: 33.6407, lon: -84.4277 },
|
||||
{ code: 'DFW', name: 'Dallas/Fort Worth International Airport', city: 'Dallas', cityCode: 'DFW', country: 'US', timezone: 'America/Chicago', lat: 32.8998, lon: -97.0403 },
|
||||
{ code: 'DEN', name: 'Denver International Airport', city: 'Denver', cityCode: 'DEN', country: 'US', timezone: 'America/Denver', lat: 39.8561, lon: -104.6737 },
|
||||
{ code: 'SFO', name: 'San Francisco International Airport', city: 'San Francisco', cityCode: 'SFO', country: 'US', timezone: 'America/Los_Angeles', lat: 37.6213, lon: -122.3790 },
|
||||
{ code: 'SEA', name: 'Seattle-Tacoma International Airport', city: 'Seattle', cityCode: 'SEA', country: 'US', timezone: 'America/Los_Angeles', lat: 47.4502, lon: -122.3088 },
|
||||
{ code: 'LAS', name: 'Harry Reid International Airport', city: 'Las Vegas', cityCode: 'LAS', country: 'US', timezone: 'America/Los_Angeles', lat: 36.0840, lon: -115.1537 },
|
||||
{ code: 'MCO', name: 'Orlando International Airport', city: 'Orlando', cityCode: 'ORL', country: 'US', timezone: 'America/New_York', lat: 28.4312, lon: -81.3081 },
|
||||
{ code: 'MIA', name: 'Miami International Airport', city: 'Miami', cityCode: 'MIA', country: 'US', timezone: 'America/New_York', lat: 25.7959, lon: -80.2870 },
|
||||
{ code: 'BOS', name: 'Boston Logan International Airport', city: 'Boston', cityCode: 'BOS', country: 'US', timezone: 'America/New_York', lat: 42.3656, lon: -71.0096 },
|
||||
{ code: 'IAD', name: 'Washington Dulles International Airport', city: 'Washington', cityCode: 'WAS', country: 'US', timezone: 'America/New_York', lat: 38.9531, lon: -77.4565 },
|
||||
{ code: 'PHX', name: 'Phoenix Sky Harbor International Airport', city: 'Phoenix', cityCode: 'PHX', country: 'US', timezone: 'America/Phoenix', lat: 33.4352, lon: -112.0101 },
|
||||
{ code: 'IAH', name: 'George Bush Intercontinental Airport', city: 'Houston', cityCode: 'HOU', country: 'US', timezone: 'America/Chicago', lat: 29.9902, lon: -95.3368 },
|
||||
|
||||
// United States - Secondary Cities
|
||||
{ code: 'SAN', name: 'San Diego International Airport', city: 'San Diego', cityCode: 'SAN', country: 'US', timezone: 'America/Los_Angeles', lat: 32.7338, lon: -117.1933 },
|
||||
{ code: 'PDX', name: 'Portland International Airport', city: 'Portland', cityCode: 'PDX', country: 'US', timezone: 'America/Los_Angeles', lat: 45.5898, lon: -122.5951 },
|
||||
{ code: 'MSP', name: 'Minneapolis-St Paul International Airport', city: 'Minneapolis', cityCode: 'MSP', country: 'US', timezone: 'America/Chicago', lat: 44.8848, lon: -93.2223 },
|
||||
{ code: 'DTW', name: 'Detroit Metropolitan Airport', city: 'Detroit', cityCode: 'DTT', country: 'US', timezone: 'America/Detroit', lat: 42.2162, lon: -83.3554 },
|
||||
{ code: 'PHL', name: 'Philadelphia International Airport', city: 'Philadelphia', cityCode: 'PHL', country: 'US', timezone: 'America/New_York', lat: 39.8744, lon: -75.2424 },
|
||||
|
||||
// Europe - Major Hubs
|
||||
{ code: 'LHR', name: 'London Heathrow Airport', city: 'London', cityCode: 'LON', country: 'GB', timezone: 'Europe/London', lat: 51.4700, lon: -0.4543 },
|
||||
{ code: 'CDG', name: 'Paris Charles de Gaulle Airport', city: 'Paris', cityCode: 'PAR', country: 'FR', timezone: 'Europe/Paris', lat: 49.0097, lon: 2.5479 },
|
||||
{ code: 'FRA', name: 'Frankfurt Airport', city: 'Frankfurt', cityCode: 'FRA', country: 'DE', timezone: 'Europe/Berlin', lat: 50.0379, lon: 8.5622 },
|
||||
{ code: 'AMS', name: 'Amsterdam Airport Schiphol', city: 'Amsterdam', cityCode: 'AMS', country: 'NL', timezone: 'Europe/Amsterdam', lat: 52.3105, lon: 4.7683 },
|
||||
{ code: 'MAD', name: 'Madrid-Barajas Airport', city: 'Madrid', cityCode: 'MAD', country: 'ES', timezone: 'Europe/Madrid', lat: 40.4983, lon: -3.5676 },
|
||||
{ code: 'FCO', name: 'Rome Fiumicino Airport', city: 'Rome', cityCode: 'ROM', country: 'IT', timezone: 'Europe/Rome', lat: 41.8003, lon: 12.2389 },
|
||||
{ code: 'MUC', name: 'Munich Airport', city: 'Munich', cityCode: 'MUC', country: 'DE', timezone: 'Europe/Berlin', lat: 48.3538, lon: 11.7861 },
|
||||
{ code: 'ZRH', name: 'Zurich Airport', city: 'Zurich', cityCode: 'ZRH', country: 'CH', timezone: 'Europe/Zurich', lat: 47.4582, lon: 8.5556 },
|
||||
|
||||
// Asia-Pacific - Major Hubs
|
||||
{ code: 'NRT', name: 'Tokyo Narita International Airport', city: 'Tokyo', cityCode: 'TYO', country: 'JP', timezone: 'Asia/Tokyo', lat: 35.7653, lon: 140.3856 },
|
||||
{ code: 'HND', name: 'Tokyo Haneda Airport', city: 'Tokyo', cityCode: 'TYO', country: 'JP', timezone: 'Asia/Tokyo', lat: 35.5494, lon: 139.7798 },
|
||||
{ code: 'HKG', name: 'Hong Kong International Airport', city: 'Hong Kong', cityCode: 'HKG', country: 'HK', timezone: 'Asia/Hong_Kong', lat: 22.3080, lon: 113.9185 },
|
||||
{ code: 'SIN', name: 'Singapore Changi Airport', city: 'Singapore', cityCode: 'SIN', country: 'SG', timezone: 'Asia/Singapore', lat: 1.3644, lon: 103.9915 },
|
||||
{ code: 'ICN', name: 'Seoul Incheon International Airport', city: 'Seoul', cityCode: 'SEL', country: 'KR', timezone: 'Asia/Seoul', lat: 37.4602, lon: 126.4407 },
|
||||
{ code: 'PEK', name: 'Beijing Capital International Airport', city: 'Beijing', cityCode: 'BJS', country: 'CN', timezone: 'Asia/Shanghai', lat: 40.0799, lon: 116.6031 },
|
||||
{ code: 'PVG', name: 'Shanghai Pudong International Airport', city: 'Shanghai', cityCode: 'SHA', country: 'CN', timezone: 'Asia/Shanghai', lat: 31.1443, lon: 121.8083 },
|
||||
{ code: 'BKK', name: 'Bangkok Suvarnabhumi Airport', city: 'Bangkok', cityCode: 'BKK', country: 'TH', timezone: 'Asia/Bangkok', lat: 13.6900, lon: 100.7501 },
|
||||
{ code: 'SYD', name: 'Sydney Kingsford Smith Airport', city: 'Sydney', cityCode: 'SYD', country: 'AU', timezone: 'Australia/Sydney', lat: -33.9399, lon: 151.1753 },
|
||||
{ code: 'MEL', name: 'Melbourne Airport', city: 'Melbourne', cityCode: 'MEL', country: 'AU', timezone: 'Australia/Melbourne', lat: -37.6690, lon: 144.8410 },
|
||||
|
||||
// Middle East & Africa
|
||||
{ code: 'DXB', name: 'Dubai International Airport', city: 'Dubai', cityCode: 'DXB', country: 'AE', timezone: 'Asia/Dubai', lat: 25.2532, lon: 55.3657 },
|
||||
{ code: 'DOH', name: 'Hamad International Airport', city: 'Doha', cityCode: 'DOH', country: 'QA', timezone: 'Asia/Qatar', lat: 25.2609, lon: 51.6138 },
|
||||
{ code: 'JNB', name: 'O.R. Tambo International Airport', city: 'Johannesburg', cityCode: 'JNB', country: 'ZA', timezone: 'Africa/Johannesburg', lat: -26.1392, lon: 28.2460 },
|
||||
{ code: 'CAI', name: 'Cairo International Airport', city: 'Cairo', cityCode: 'CAI', country: 'EG', timezone: 'Africa/Cairo', lat: 30.1219, lon: 31.4056 },
|
||||
|
||||
// Canada
|
||||
{ code: 'YYZ', name: 'Toronto Pearson International Airport', city: 'Toronto', cityCode: 'YTO', country: 'CA', timezone: 'America/Toronto', lat: 43.6777, lon: -79.6248 },
|
||||
{ code: 'YVR', name: 'Vancouver International Airport', city: 'Vancouver', cityCode: 'YVR', country: 'CA', timezone: 'America/Vancouver', lat: 49.1967, lon: -123.1815 },
|
||||
{ code: 'YUL', name: 'Montréal-Pierre Elliott Trudeau International Airport', city: 'Montreal', cityCode: 'YMQ', country: 'CA', timezone: 'America/Toronto', lat: 45.4706, lon: -73.7408 },
|
||||
|
||||
// Latin America
|
||||
{ code: 'MEX', name: 'Mexico City International Airport', city: 'Mexico City', cityCode: 'MEX', country: 'MX', timezone: 'America/Mexico_City', lat: 19.4363, lon: -99.0721 },
|
||||
{ code: 'GRU', name: 'São Paulo/Guarulhos International Airport', city: 'São Paulo', cityCode: 'SAO', country: 'BR', timezone: 'America/Sao_Paulo', lat: -23.4356, lon: -46.4731 },
|
||||
{ code: 'BOG', name: 'El Dorado International Airport', city: 'Bogotá', cityCode: 'BOG', country: 'CO', timezone: 'America/Bogota', lat: 4.7016, lon: -74.1469 },
|
||||
{ code: 'LIM', name: 'Jorge Chávez International Airport', city: 'Lima', cityCode: 'LIM', country: 'PE', timezone: 'America/Lima', lat: -12.0219, lon: -77.1143 }
|
||||
];
|
||||
|
||||
/**
|
||||
* Get airport by IATA code
|
||||
* @param {string} code - IATA airport code (3 letters)
|
||||
* @returns {Object|null} Airport object or null if not found
|
||||
*/
|
||||
export function getAirport(code: any) {
|
||||
return airports.find((a) => a.code === code.toUpperCase()) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate great-circle distance between two airports in kilometers
|
||||
* Uses Haversine formula
|
||||
* @param {string} origin - Origin airport code
|
||||
* @param {string} destination - Destination airport code
|
||||
* @returns {number} Distance in kilometers
|
||||
*/
|
||||
export function calculateDistance(origin: any, destination: any) {
|
||||
const from = getAirport(origin);
|
||||
const to = getAirport(destination);
|
||||
|
||||
if (!from || !to) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const R = 6371; // Earth's radius in km
|
||||
const dLat = toRad(to.lat - from.lat);
|
||||
const dLon = toRad(to.lon - from.lon);
|
||||
|
||||
const a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(toRad(from.lat)) * Math.cos(toRad(to.lat)) *
|
||||
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
const distance = R * c;
|
||||
|
||||
return Math.round(distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degrees to radians
|
||||
* @param {number} degrees - Angle in degrees
|
||||
* @returns {number} Angle in radians
|
||||
*/
|
||||
function toRad(degrees: any) {
|
||||
return degrees * (Math.PI / 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if airport code exists
|
||||
* @param {string} code - IATA airport code
|
||||
* @returns {boolean} True if airport exists
|
||||
*/
|
||||
export function isValidAirport(code: any) {
|
||||
return getAirport(code) !== null;
|
||||
}
|
||||
|
||||
export default {
|
||||
airports,
|
||||
getAirport,
|
||||
calculateDistance,
|
||||
isValidAirport
|
||||
};
|
||||
138
src/data/cars.ts
Normal file
138
src/data/cars.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Car Rental Companies and Vehicle Mock Data
|
||||
*/
|
||||
|
||||
export const carCompanies = [
|
||||
{ code: 'HERTZ', name: 'Hertz', tier: 'premium' },
|
||||
{ code: 'AVIS', name: 'Avis', tier: 'premium' },
|
||||
{ code: 'BUDGET', name: 'Budget', tier: 'economy' },
|
||||
{ code: 'ENTERPRISE', name: 'Enterprise', tier: 'standard' },
|
||||
{ code: 'NATIONAL', name: 'National', tier: 'standard' },
|
||||
{ code: 'ALAMO', name: 'Alamo', tier: 'economy' },
|
||||
{ code: 'DOLLAR', name: 'Dollar', tier: 'economy' },
|
||||
{ code: 'THRIFTY', name: 'Thrifty', tier: 'economy' }
|
||||
];
|
||||
|
||||
export const carCategories = [
|
||||
{ code: 'ECON', name: 'Economy', example: 'Toyota Yaris', passengers: 5, bags: 2, basePrice: 45 },
|
||||
{ code: 'COMP', name: 'Compact', example: 'Honda Civic', passengers: 5, bags: 2, basePrice: 55 },
|
||||
{ code: 'MID', name: 'Midsize', example: 'Toyota Camry', passengers: 5, bags: 3, basePrice: 65 },
|
||||
{ code: 'FULL', name: 'Full-size', example: 'Chevrolet Impala', passengers: 5, bags: 4, basePrice: 75 },
|
||||
{ code: 'SUV', name: 'SUV', example: 'Ford Explorer', passengers: 7, bags: 4, basePrice: 95 },
|
||||
{ code: 'LUX', name: 'Luxury', example: 'BMW 5 Series', passengers: 5, bags: 3, basePrice: 150 },
|
||||
{ code: 'VAN', name: 'Minivan', example: 'Honda Odyssey', passengers: 7, bags: 3, basePrice: 85 },
|
||||
{ code: 'CONV', name: 'Convertible', example: 'Ford Mustang', passengers: 4, bags: 2, basePrice: 110 }
|
||||
];
|
||||
|
||||
/**
|
||||
* Generate car rental options
|
||||
*/
|
||||
export function generateCarOptions(pickupLocation: any, dropoffLocation: any, pickupDate: any, dropoffDate: any) {
|
||||
const pickupDateObj = new Date(pickupDate);
|
||||
const dropoffDateObj = new Date(dropoffDate);
|
||||
const days = Math.ceil((dropoffDateObj.getTime() - pickupDateObj.getTime()) / (1000 * 60 * 60 * 24));
|
||||
|
||||
// Select 3-5 companies
|
||||
const numCompanies = Math.floor(Math.random() * 3) + 3;
|
||||
const selectedCompanies = carCompanies
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.slice(0, numCompanies);
|
||||
|
||||
const options = [];
|
||||
|
||||
for (const company of selectedCompanies) {
|
||||
// Each company offers 2-4 car categories
|
||||
const numCategories = Math.floor(Math.random() * 3) + 2;
|
||||
const selectedCategories = carCategories
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.slice(0, numCategories);
|
||||
|
||||
for (const category of selectedCategories) {
|
||||
// Apply company tier multiplier
|
||||
const tierMultiplier = company.tier === 'premium' ? 1.15 : company.tier === 'economy' ? 0.9 : 1.0;
|
||||
|
||||
// Apply weekend/holiday multiplier
|
||||
const dayOfWeek = pickupDateObj.getDay();
|
||||
const weekendMultiplier = (dayOfWeek === 5 || dayOfWeek === 6) ? 1.2 : 1.0;
|
||||
|
||||
// One-way fee if different locations
|
||||
const oneWayFee = pickupLocation !== dropoffLocation ? 75 : 0;
|
||||
|
||||
const dailyRate = Math.round(category.basePrice * tierMultiplier * weekendMultiplier);
|
||||
const totalPrice = (dailyRate * days) + oneWayFee;
|
||||
|
||||
options.push({
|
||||
carId: `CAR-${company.code}-${category.code}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`,
|
||||
company: company.name,
|
||||
companyCode: company.code,
|
||||
category: category.name,
|
||||
categoryCode: category.code,
|
||||
example: category.example,
|
||||
passengers: category.passengers,
|
||||
bags: category.bags,
|
||||
features: generateFeatures(category.code, company.tier),
|
||||
pricing: {
|
||||
dailyRate,
|
||||
days,
|
||||
oneWayFee,
|
||||
totalPrice,
|
||||
currency: 'USD'
|
||||
},
|
||||
availability: 'available' // Mock: always available
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return options.sort((a, b) => a.pricing.totalPrice - b.pricing.totalPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate features based on category and tier
|
||||
*/
|
||||
function generateFeatures(categoryCode: any, tier: any) {
|
||||
const baseFeatures = ['Automatic', 'Air Conditioning'];
|
||||
|
||||
if (tier === 'premium') {
|
||||
baseFeatures.push('GPS', 'Bluetooth');
|
||||
}
|
||||
|
||||
if (['SUV', 'VAN', 'LUX'].includes(categoryCode)) {
|
||||
baseFeatures.push('Leather Seats');
|
||||
}
|
||||
|
||||
if (categoryCode === 'LUX') {
|
||||
baseFeatures.push('Premium Audio', 'Sunroof');
|
||||
}
|
||||
|
||||
return baseFeatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get car by ID (for booking validation)
|
||||
*/
|
||||
export function getCarById(carId: any) {
|
||||
// Since cars are dynamically generated, we parse the ID
|
||||
const [_, companyCode, categoryCode] = carId.split('-');
|
||||
|
||||
const company = carCompanies.find(c => c.code === companyCode);
|
||||
const category = carCategories.find(c => c.code === categoryCode);
|
||||
|
||||
if (!company || !category) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
carId,
|
||||
company: company.name,
|
||||
companyCode: company.code,
|
||||
category: category.name,
|
||||
categoryCode: category.code,
|
||||
example: category.example,
|
||||
passengers: category.passengers,
|
||||
bags: category.bags,
|
||||
features: generateFeatures(category.code, company.tier),
|
||||
basePrice: category.basePrice
|
||||
};
|
||||
}
|
||||
|
||||
export default { carCompanies, carCategories, generateCarOptions, getCarById };
|
||||
228
src/data/flights.ts
Normal file
228
src/data/flights.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
import { getAirport, calculateDistance } from './airports.js';
|
||||
import { getRandomAirline } from './airlines.js';
|
||||
import { generateSegmentId } from './pnr.js';
|
||||
|
||||
/**
|
||||
* Flight data generator with deterministic pricing, duration calculation, and availability logic
|
||||
*/
|
||||
|
||||
/**
|
||||
* Aircraft types by size category
|
||||
*/
|
||||
const aircraftTypes = {
|
||||
shortHaul: ['Boeing 737-800', 'Airbus A320', 'Boeing 737 MAX 8', 'Airbus A321'],
|
||||
mediumHaul: ['Boeing 757-200', 'Boeing 767-300', 'Airbus A330-200'],
|
||||
longHaul: ['Boeing 777-300ER', 'Boeing 787-9', 'Airbus A350-900', 'Airbus A380']
|
||||
};
|
||||
|
||||
/**
|
||||
* Booking class codes by cabin
|
||||
*/
|
||||
const bookingClasses = {
|
||||
economy: ['Y', 'B', 'M', 'H', 'Q', 'V', 'W'],
|
||||
premium_economy: ['W', 'S', 'A'],
|
||||
business: ['J', 'C', 'D', 'I', 'Z'],
|
||||
first: ['F', 'A', 'P']
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate mock flights for a search query
|
||||
* @param {Object} params - Search parameters
|
||||
* @param {string} params.origin - Origin airport code
|
||||
* @param {string} params.destination - Destination airport code
|
||||
* @param {string} params.departureDate - Departure date (YYYY-MM-DD)
|
||||
* @param {Object} params.passengers - Passenger counts
|
||||
* @param {string} params.cabin - Cabin class
|
||||
* @returns {Object[]} Array of flight options
|
||||
*/
|
||||
export function generateFlights(params: any) {
|
||||
const { origin, destination, departureDate, cabin = 'economy' } = params;
|
||||
|
||||
// Validate airports exist
|
||||
const originAirport = getAirport(origin);
|
||||
const destAirport = getAirport(destination);
|
||||
|
||||
if (!originAirport || !destAirport) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Calculate distance and flight characteristics
|
||||
const distance = calculateDistance(origin, destination);
|
||||
const duration = calculateFlightDuration(distance);
|
||||
const aircraftType = selectAircraftType(distance);
|
||||
|
||||
// Generate 3-5 flight options
|
||||
const flightCount = 3 + Math.floor(Math.random() * 3);
|
||||
const flights = [];
|
||||
|
||||
// Generate flights at different times of day
|
||||
const departureTimes = generateDepartureTimes(flightCount);
|
||||
|
||||
for (let i = 0; i < flightCount; i++) {
|
||||
const airline = getRandomAirline();
|
||||
const flightNumber = `${airline.code}${Math.floor(Math.random() * 900) + 100}`;
|
||||
const departureTime = departureTimes[i];
|
||||
const arrivalTime = calculateArrivalTime(departureTime, duration);
|
||||
|
||||
// Calculate pricing based on distance, cabin, and "availability"
|
||||
const basePrice = calculateBasePrice(distance, cabin);
|
||||
const priceVariation = 0.8 + Math.random() * 0.4; // ±20% variation
|
||||
const price = Math.round(basePrice * priceVariation);
|
||||
|
||||
// Simulate availability (90% available, 10% sold out)
|
||||
const isAvailable = Math.random() > 0.1;
|
||||
const seatsAvailable = isAvailable ? Math.floor(Math.random() * 20) + 5 : 0;
|
||||
const status = isAvailable ? 'available' : 'sold_out';
|
||||
|
||||
// Get booking class for this cabin
|
||||
const bookingClass = bookingClasses[cabin][Math.floor(Math.random() * bookingClasses[cabin].length)];
|
||||
|
||||
const flight = {
|
||||
id: generateSegmentId('flight', i),
|
||||
flightNumber,
|
||||
airlineCode: airline.code,
|
||||
airlineName: airline.name,
|
||||
originCode: origin,
|
||||
originName: originAirport.name,
|
||||
destinationCode: destination,
|
||||
destinationName: destAirport.name,
|
||||
departureTime: `${departureDate}T${departureTime}:00`,
|
||||
arrivalTime: `${departureDate}T${arrivalTime}:00`,
|
||||
duration,
|
||||
aircraftType,
|
||||
cabin,
|
||||
price,
|
||||
seatsAvailable,
|
||||
bookingClass,
|
||||
status,
|
||||
metadata: {
|
||||
distance,
|
||||
data_source: 'mock'
|
||||
}
|
||||
};
|
||||
|
||||
flights.push(flight);
|
||||
}
|
||||
|
||||
// Sort by departure time
|
||||
flights.sort((a, b) => a.departureTime.localeCompare(b.departureTime));
|
||||
|
||||
return flights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate flight duration in minutes based on distance
|
||||
* @param {number} distance - Distance in kilometers
|
||||
* @returns {number} Duration in minutes
|
||||
*/
|
||||
function calculateFlightDuration(distance: any) {
|
||||
// Average commercial aircraft speed: ~800 km/h
|
||||
// Add taxi/boarding time: 30 minutes
|
||||
const flightTime = (distance / 800) * 60;
|
||||
const totalTime = flightTime + 30;
|
||||
return Math.round(totalTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select appropriate aircraft type based on distance
|
||||
* @param {number} distance - Distance in kilometers
|
||||
* @returns {string} Aircraft type
|
||||
*/
|
||||
function selectAircraftType(distance: any) {
|
||||
if (distance < 2000) {
|
||||
// Short-haul
|
||||
return aircraftTypes.shortHaul[Math.floor(Math.random() * aircraftTypes.shortHaul.length)];
|
||||
} else if (distance < 6000) {
|
||||
// Medium-haul
|
||||
return aircraftTypes.mediumHaul[Math.floor(Math.random() * aircraftTypes.mediumHaul.length)];
|
||||
} else {
|
||||
// Long-haul
|
||||
return aircraftTypes.longHaul[Math.floor(Math.random() * aircraftTypes.longHaul.length)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate base price in USD cents based on distance and cabin
|
||||
* @param {number} distance - Distance in kilometers
|
||||
* @param {string} cabin - Cabin class
|
||||
* @returns {number} Price in USD cents
|
||||
*/
|
||||
function calculateBasePrice(distance: any, cabin: any) {
|
||||
// Base price per kilometer by cabin class
|
||||
const pricePerKm = {
|
||||
economy: 0.10, // $0.10/km
|
||||
premium_economy: 0.14, // $0.14/km (+40%)
|
||||
business: 0.30, // $0.30/km (+200%)
|
||||
first: 0.50 // $0.50/km (+400%)
|
||||
};
|
||||
|
||||
const rate = pricePerKm[cabin] || pricePerKm.economy;
|
||||
const basePrice = distance * rate;
|
||||
|
||||
// Apply minimum prices
|
||||
const minimums = {
|
||||
economy: 200,
|
||||
premium_economy: 300,
|
||||
business: 800,
|
||||
first: 2500
|
||||
};
|
||||
|
||||
const minimum = minimums[cabin] || minimums.economy;
|
||||
|
||||
return Math.max(basePrice, minimum) * 100; // Convert to cents
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate realistic departure times
|
||||
* @param {number} count - Number of times to generate
|
||||
* @returns {string[]} Array of departure times (HH:MM format)
|
||||
*/
|
||||
function generateDepartureTimes(count: any) {
|
||||
// Common departure slots: 6am-10pm
|
||||
const slots = [
|
||||
'06:00', '06:30', '07:00', '07:30', '08:00', '08:30',
|
||||
'09:00', '09:30', '10:00', '10:30', '11:00', '11:30',
|
||||
'12:00', '12:30', '13:00', '13:30', '14:00', '14:30',
|
||||
'15:00', '15:30', '16:00', '16:30', '17:00', '17:30',
|
||||
'18:00', '18:30', '19:00', '19:30', '20:00', '20:30',
|
||||
'21:00', '21:30', '22:00'
|
||||
];
|
||||
|
||||
// Shuffle and take first N slots
|
||||
const shuffled = slots.sort(() => Math.random() - 0.5);
|
||||
return shuffled.slice(0, count).sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate arrival time given departure time and duration
|
||||
* @param {string} departureTime - Departure time (HH:MM)
|
||||
* @param {number} duration - Duration in minutes
|
||||
* @returns {string} Arrival time (HH:MM)
|
||||
*/
|
||||
function calculateArrivalTime(departureTime: any, duration: any) {
|
||||
const [hours, minutes] = departureTime.split(':').map(Number);
|
||||
const totalMinutes = hours * 60 + minutes + duration;
|
||||
|
||||
const arrivalHours = Math.floor(totalMinutes / 60) % 24;
|
||||
const arrivalMinutes = totalMinutes % 60;
|
||||
|
||||
return `${String(arrivalHours).padStart(2, '0')}:${String(arrivalMinutes).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get flight by ID from search results
|
||||
* @param {string} flightId - Flight identifier
|
||||
* @param {Object} searchParams - Original search parameters
|
||||
* @returns {Object|null} Flight object or null
|
||||
*/
|
||||
export function getFlightById(flightId: any, searchParams: any) {
|
||||
const flights = generateFlights(searchParams);
|
||||
return flights.find((f) => f.id === flightId) || null;
|
||||
}
|
||||
|
||||
export default {
|
||||
generateFlights,
|
||||
getFlightById,
|
||||
calculateFlightDuration,
|
||||
calculateBasePrice
|
||||
};
|
||||
127
src/data/hotels.ts
Normal file
127
src/data/hotels.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Hotels Mock Data
|
||||
* 50+ properties across major cities with realistic details
|
||||
*/
|
||||
|
||||
export const hotels = [
|
||||
// New York City
|
||||
{ id: 'HTL001', name: 'Grand Manhattan Hotel', chain: 'Marriott', city: 'NYC', cityCode: 'JFK', stars: 5, address: '123 Fifth Avenue', amenities: ['WiFi', 'Parking', 'Breakfast', 'Gym', 'Pool', 'Spa'], basePrice: 450 },
|
||||
{ id: 'HTL002', name: 'Times Square Inn', chain: 'Hilton', city: 'NYC', cityCode: 'JFK', stars: 4, address: '456 Broadway', amenities: ['WiFi', 'Gym', 'Restaurant'], basePrice: 320 },
|
||||
{ id: 'HTL003', name: 'Brooklyn Budget Suites', chain: 'Independent', city: 'NYC', cityCode: 'JFK', stars: 3, address: '789 Brooklyn Ave', amenities: ['WiFi', 'Breakfast'], basePrice: 150 },
|
||||
|
||||
// Los Angeles
|
||||
{ id: 'HTL004', name: 'Beverly Hills Grand', chain: 'Four Seasons', city: 'Los Angeles', cityCode: 'LAX', stars: 5, address: '100 Rodeo Drive', amenities: ['WiFi', 'Parking', 'Breakfast', 'Gym', 'Pool', 'Spa', 'Concierge'], basePrice: 550 },
|
||||
{ id: 'HTL005', name: 'Santa Monica Beach Hotel', chain: 'Hyatt', city: 'Los Angeles', cityCode: 'LAX', stars: 4, address: '200 Ocean Ave', amenities: ['WiFi', 'Pool', 'Gym', 'Restaurant'], basePrice: 280 },
|
||||
{ id: 'HTL006', name: 'Downtown LA Comfort', chain: 'Holiday Inn', city: 'Los Angeles', cityCode: 'LAX', stars: 3, address: '300 Main St', amenities: ['WiFi', 'Parking', 'Breakfast'], basePrice: 120 },
|
||||
|
||||
// London
|
||||
{ id: 'HTL007', name: 'The Royal Westminster', chain: 'Intercontinental', city: 'London', cityCode: 'LHR', stars: 5, address: '10 Piccadilly', amenities: ['WiFi', 'Breakfast', 'Gym', 'Spa', 'Concierge'], basePrice: 480 },
|
||||
{ id: 'HTL008', name: 'Kensington Palace Hotel', chain: 'Marriott', city: 'London', cityCode: 'LHR', stars: 4, address: '20 Kensington Rd', amenities: ['WiFi', 'Gym', 'Restaurant'], basePrice: 310 },
|
||||
{ id: 'HTL009', name: 'East End Express', chain: 'Premier Inn', city: 'London', cityCode: 'LHR', stars: 3, address: '30 Whitechapel', amenities: ['WiFi', 'Breakfast'], basePrice: 135 },
|
||||
|
||||
// Tokyo
|
||||
{ id: 'HTL010', name: 'Shibuya Imperial', chain: 'Prince Hotels', city: 'Tokyo', cityCode: 'TYO', stars: 5, address: '1-1 Shibuya', amenities: ['WiFi', 'Breakfast', 'Gym', 'Pool', 'Spa'], basePrice: 420 },
|
||||
{ id: 'HTL011', name: 'Shinjuku Business Hotel', chain: 'APA Hotels', city: 'Tokyo', cityCode: 'TYO', stars: 3, address: '2-2 Shinjuku', amenities: ['WiFi', 'Restaurant'], basePrice: 140 },
|
||||
|
||||
// Paris
|
||||
{ id: 'HTL012', name: 'Le Grand Paris', chain: 'Sofitel', city: 'Paris', cityCode: 'CDG', stars: 5, address: '1 Avenue des Champs', amenities: ['WiFi', 'Breakfast', 'Gym', 'Spa', 'Concierge'], basePrice: 500 },
|
||||
{ id: 'HTL013', name: 'Montmartre Boutique', chain: 'Independent', city: 'Paris', cityCode: 'CDG', stars: 4, address: '15 Rue Montmartre', amenities: ['WiFi', 'Breakfast'], basePrice: 250 },
|
||||
|
||||
// San Francisco
|
||||
{ id: 'HTL014', name: 'Union Square Luxury', chain: 'Westin', city: 'San Francisco', cityCode: 'SFO', stars: 5, address: '50 Union Square', amenities: ['WiFi', 'Gym', 'Pool', 'Spa'], basePrice: 420 },
|
||||
{ id: 'HTL015', name: 'Fisherman\'s Wharf Inn', chain: 'Best Western', city: 'San Francisco', cityCode: 'SFO', stars: 3, address: '100 Jefferson St', amenities: ['WiFi', 'Parking'], basePrice: 160 },
|
||||
|
||||
// Miami
|
||||
{ id: 'HTL016', name: 'South Beach Resort', chain: 'Fontainebleau', city: 'Miami', cityCode: 'MIA', stars: 5, address: '1000 Ocean Drive', amenities: ['WiFi', 'Pool', 'Gym', 'Spa', 'Beach'], basePrice: 380 },
|
||||
{ id: 'HTL017', name: 'Coral Gables Hotel', chain: 'Marriott', city: 'Miami', cityCode: 'MIA', stars: 4, address: '200 Miracle Mile', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 220 },
|
||||
|
||||
// Chicago
|
||||
{ id: 'HTL018', name: 'Magnificent Mile Tower', chain: 'Trump Hotels', city: 'Chicago', cityCode: 'ORD', stars: 5, address: '401 Michigan Ave', amenities: ['WiFi', 'Gym', 'Spa', 'Restaurant'], basePrice: 390 },
|
||||
{ id: 'HTL019', name: 'Loop Business Center', chain: 'Hyatt', city: 'Chicago', cityCode: 'ORD', stars: 4, address: '100 State St', amenities: ['WiFi', 'Gym'], basePrice: 195 },
|
||||
|
||||
// Dubai
|
||||
{ id: 'HTL020', name: 'Burj Al Arab', chain: 'Jumeirah', city: 'Dubai', cityCode: 'DXB', stars: 5, address: 'Jumeirah Beach', amenities: ['WiFi', 'Pool', 'Gym', 'Spa', 'Beach', 'Concierge'], basePrice: 800 },
|
||||
{ id: 'HTL021', name: 'Marina Bay Hotel', chain: 'Hilton', city: 'Dubai', cityCode: 'DXB', stars: 4, address: 'Dubai Marina', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 280 },
|
||||
|
||||
// Singapore
|
||||
{ id: 'HTL022', name: 'Marina Bay Sands', chain: 'Independent', city: 'Singapore', cityCode: 'SIN', stars: 5, address: '10 Bayfront Ave', amenities: ['WiFi', 'Pool', 'Gym', 'Spa', 'Casino'], basePrice: 480 },
|
||||
{ id: 'HTL023', name: 'Orchard Road Plaza', chain: 'Shangri-La', city: 'Singapore', cityCode: 'SIN', stars: 4, address: '22 Orchard Rd', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 260 },
|
||||
|
||||
// Additional cities for diversity
|
||||
{ id: 'HTL024', name: 'Sydney Harbour Hotel', chain: 'Four Seasons', city: 'Sydney', cityCode: 'SYD', stars: 5, address: '199 George St', amenities: ['WiFi', 'Pool', 'Gym', 'Spa'], basePrice: 410 },
|
||||
{ id: 'HTL025', name: 'Vegas Strip Mega Resort', chain: 'MGM', city: 'Las Vegas', cityCode: 'LAS', stars: 5, address: '3799 Las Vegas Blvd', amenities: ['WiFi', 'Pool', 'Gym', 'Casino', 'Spa'], basePrice: 320 },
|
||||
{ id: 'HTL026', name: 'Seattle Downtown Suites', chain: 'Hyatt', city: 'Seattle', cityCode: 'SEA', stars: 4, address: '1001 Pike St', amenities: ['WiFi', 'Gym'], basePrice: 230 },
|
||||
{ id: 'HTL027', name: 'Boston Harbor Hotel', chain: 'Marriott', city: 'Boston', cityCode: 'BOS', stars: 4, address: '70 Rowes Wharf', amenities: ['WiFi', 'Gym', 'Restaurant'], basePrice: 275 },
|
||||
{ id: 'HTL028', name: 'Atlanta Peachtree Plaza', chain: 'Westin', city: 'Atlanta', cityCode: 'ATL', stars: 4, address: '210 Peachtree St', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 185 },
|
||||
{ id: 'HTL029', name: 'Denver Mountain View', chain: 'Hilton', city: 'Denver', cityCode: 'DEN', stars: 4, address: '1701 Broadway', amenities: ['WiFi', 'Gym'], basePrice: 195 },
|
||||
{ id: 'HTL030', name: 'Phoenix Desert Resort', chain: 'JW Marriott', city: 'Phoenix', cityCode: 'PHX', stars: 5, address: '5350 E Marriott Dr', amenities: ['WiFi', 'Pool', 'Gym', 'Spa', 'Golf'], basePrice: 340 },
|
||||
|
||||
// More international cities
|
||||
{ id: 'HTL031', name: 'Rome Colosseum View', chain: 'St. Regis', city: 'Rome', cityCode: 'FCO', stars: 5, address: 'Via Vittorio', amenities: ['WiFi', 'Breakfast', 'Gym', 'Spa'], basePrice: 450 },
|
||||
{ id: 'HTL032', name: 'Barcelona Ramblas Hotel', chain: 'Independent', city: 'Barcelona', cityCode: 'BCN', stars: 4, address: 'La Rambla 45', amenities: ['WiFi', 'Breakfast'], basePrice: 210 },
|
||||
{ id: 'HTL033', name: 'Amsterdam Canal House', chain: 'NH Hotels', city: 'Amsterdam', cityCode: 'AMS', stars: 4, address: 'Prinsengracht 100', amenities: ['WiFi', 'Breakfast'], basePrice: 240 },
|
||||
{ id: 'HTL034', name: 'Hong Kong Harbor Plaza', chain: 'Mandarin Oriental', city: 'Hong Kong', cityCode: 'HKG', stars: 5, address: '5 Connaught Rd', amenities: ['WiFi', 'Pool', 'Gym', 'Spa'], basePrice: 490 },
|
||||
{ id: 'HTL035', name: 'Bangkok Sukhumvit Suites', chain: 'Sofitel', city: 'Bangkok', cityCode: 'BKK', stars: 4, address: '189 Sukhumvit Rd', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 180 },
|
||||
|
||||
// US Regional coverage
|
||||
{ id: 'HTL036', name: 'Nashville Music City Hotel', chain: 'Gaylord', city: 'Nashville', cityCode: 'BNA', stars: 4, address: '2800 Opryland Dr', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 205 },
|
||||
{ id: 'HTL037', name: 'Austin Downtown', chain: 'Fairmont', city: 'Austin', cityCode: 'AUS', stars: 4, address: '101 Red River', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 220 },
|
||||
{ id: 'HTL038', name: 'Portland Pearl District', chain: 'Kimpton', city: 'Portland', cityCode: 'PDX', stars: 4, address: '425 NW 9th Ave', amenities: ['WiFi', 'Gym', 'Restaurant'], basePrice: 215 },
|
||||
{ id: 'HTL039', name: 'Philadelphia Historic Inn', chain: 'Independent', city: 'Philadelphia', cityCode: 'PHL', stars: 3, address: '1234 Market St', amenities: ['WiFi', 'Breakfast'], basePrice: 165 },
|
||||
{ id: 'HTL040', name: 'Detroit Renaissance Center', chain: 'Marriott', city: 'Detroit', cityCode: 'DTW', stars: 4, address: '400 Renaissance Dr', amenities: ['WiFi', 'Gym'], basePrice: 170 },
|
||||
|
||||
// European additions
|
||||
{ id: 'HTL041', name: 'Berlin Mitte Palace', chain: 'Adlon', city: 'Berlin', cityCode: 'BER', stars: 5, address: 'Unter den Linden 77', amenities: ['WiFi', 'Spa', 'Gym'], basePrice: 380 },
|
||||
{ id: 'HTL042', name: 'Munich Marienplatz', chain: 'Bayerischer Hof', city: 'Munich', cityCode: 'MUC', stars: 5, address: 'Promenadeplatz 2', amenities: ['WiFi', 'Pool', 'Spa'], basePrice: 400 },
|
||||
{ id: 'HTL043', name: 'Zurich Lake View', chain: 'Baur au Lac', city: 'Zurich', cityCode: 'ZRH', stars: 5, address: 'Talstrasse 1', amenities: ['WiFi', 'Spa', 'Restaurant'], basePrice: 520 },
|
||||
{ id: 'HTL044', name: 'Vienna Imperial', chain: 'Imperial', city: 'Vienna', cityCode: 'VIE', stars: 5, address: 'Kärntner Ring 16', amenities: ['WiFi', 'Spa', 'Restaurant'], basePrice: 430 },
|
||||
{ id: 'HTL045', name: 'Brussels Grand Place', chain: 'Amigo', city: 'Brussels', cityCode: 'BRU', stars: 5, address: 'Rue de l\'Amigo 1', amenities: ['WiFi', 'Restaurant'], basePrice: 350 },
|
||||
|
||||
// Asia Pacific additions
|
||||
{ id: 'HTL046', name: 'Seoul Gangnam Suites', chain: 'Park Hyatt', city: 'Seoul', cityCode: 'ICN', stars: 5, address: '606 Teheran-ro', amenities: ['WiFi', 'Pool', 'Gym', 'Spa'], basePrice: 360 },
|
||||
{ id: 'HTL047', name: 'Shanghai Bund Hotel', chain: 'Peninsula', city: 'Shanghai', cityCode: 'PVG', stars: 5, address: '32 The Bund', amenities: ['WiFi', 'Pool', 'Spa'], basePrice: 420 },
|
||||
{ id: 'HTL048', name: 'Mumbai Marine Drive', chain: 'Taj', city: 'Mumbai', cityCode: 'BOM', stars: 5, address: 'Apollo Bunder', amenities: ['WiFi', 'Pool', 'Spa'], basePrice: 280 },
|
||||
{ id: 'HTL049', name: 'Melbourne CBD Tower', chain: 'Crown', city: 'Melbourne', cityCode: 'MEL', stars: 5, address: '8 Whiteman St', amenities: ['WiFi', 'Pool', 'Gym'], basePrice: 330 },
|
||||
{ id: 'HTL050', name: 'Osaka Namba Plaza', chain: 'Swissotel', city: 'Osaka', cityCode: 'KIX', stars: 4, address: '5-1-60 Namba', amenities: ['WiFi', 'Gym'], basePrice: 195 }
|
||||
];
|
||||
|
||||
/**
|
||||
* Get hotels by city code
|
||||
*/
|
||||
export function getHotelsByCity(cityCode: any) {
|
||||
return hotels.filter(h => h.cityCode === cityCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hotel by ID
|
||||
*/
|
||||
export function getHotelById(hotelId: any) {
|
||||
return hotels.find(h => h.id === hotelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate hotel pricing based on check-in date, nights, and base price
|
||||
*/
|
||||
export function generateHotelPrice(basePrice: any, nights: any, checkInDate: any) {
|
||||
const date = new Date(checkInDate);
|
||||
const dayOfWeek = date.getDay();
|
||||
|
||||
// Weekend premium (Friday-Saturday)
|
||||
const weekendMultiplier = (dayOfWeek === 5 || dayOfWeek === 6) ? 1.3 : 1.0;
|
||||
|
||||
// Seasonal variation (simple month-based)
|
||||
const month = date.getMonth();
|
||||
const peakSeason = [5, 6, 7, 11]; // June, July, Aug, Dec
|
||||
const seasonMultiplier = peakSeason.includes(month) ? 1.2 : 1.0;
|
||||
|
||||
const pricePerNight = Math.round(basePrice * weekendMultiplier * seasonMultiplier);
|
||||
const totalPrice = pricePerNight * nights;
|
||||
|
||||
return {
|
||||
pricePerNight,
|
||||
nights,
|
||||
totalPrice
|
||||
};
|
||||
}
|
||||
|
||||
export default hotels;
|
||||
104
src/data/pnr.ts
Normal file
104
src/data/pnr.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* PNR (Passenger Name Record) generation utilities
|
||||
* Format: TEST-{BASE32} (e.g., TEST-ABC123)
|
||||
*/
|
||||
|
||||
const BASE32_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
|
||||
/**
|
||||
* Generate a unique PNR with TEST- prefix
|
||||
* @param {string} sessionId - Session identifier for entropy
|
||||
* @returns {string} PNR in format TEST-XXXXXX
|
||||
*/
|
||||
export function generatePNR(sessionId = '') {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.floor(Math.random() * 1000000);
|
||||
|
||||
// Combine session, timestamp, and random for uniqueness
|
||||
const entropy = `${sessionId}${timestamp}${random}`;
|
||||
|
||||
// Generate base32 encoded string
|
||||
const code = generateBase32(entropy, 6);
|
||||
|
||||
return `TEST-${code}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate base32 encoded string from input
|
||||
* @param {string} input - Input string for entropy
|
||||
* @param {number} length - Desired output length (default: 6)
|
||||
* @returns {string} Base32 encoded string
|
||||
*/
|
||||
function generateBase32(input, length = 6) {
|
||||
let result = '';
|
||||
let hash = simpleHash(input);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const index = hash % 32;
|
||||
result += BASE32_CHARS[index];
|
||||
hash = Math.floor(hash / 32) + (hash % 32);
|
||||
|
||||
// Add more entropy if hash gets too small
|
||||
if (hash < 32) {
|
||||
hash = simpleHash(result + Date.now());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple hash function for string input
|
||||
* @param {string} str - Input string
|
||||
* @returns {number} Hash value
|
||||
*/
|
||||
function simpleHash(str: any) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash; // Convert to 32-bit integer
|
||||
}
|
||||
return Math.abs(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate PNR format
|
||||
* @param {string} pnr - PNR to validate
|
||||
* @returns {boolean} True if valid format
|
||||
*/
|
||||
export function isValidPNR(pnr: any) {
|
||||
return /^TEST-[A-Z0-9]{6}$/.test(pnr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract session-scoped booking ID from PNR
|
||||
* For display and tracking purposes
|
||||
* @param {string} pnr - PNR code
|
||||
* @returns {string} Booking ID (just the code part)
|
||||
*/
|
||||
export function extractBookingId(pnr: any) {
|
||||
if (!isValidPNR(pnr)) {
|
||||
return pnr;
|
||||
}
|
||||
return pnr.replace('TEST-', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique segment ID
|
||||
* @param {string} type - Segment type (flight, hotel, car)
|
||||
* @param {number} index - Segment index
|
||||
* @returns {string} Segment identifier
|
||||
*/
|
||||
export function generateSegmentId(type: any, index: any) {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.floor(Math.random() * 1000);
|
||||
return `${type}-${index}-${timestamp}-${random}`;
|
||||
}
|
||||
|
||||
export default {
|
||||
generatePNR,
|
||||
isValidPNR,
|
||||
extractBookingId,
|
||||
generateSegmentId
|
||||
};
|
||||
Reference in New Issue
Block a user