River cruising is a well known in Europe. But, it also includes floating down the Mekong, among the wilderness of the Amazon, and through the kaleidoscope of colors found on the banks of the Ganges. Let KaliKosmos Travel find the perfect river cruise experience for you!
document.addEventListener("DOMContentLoaded", function() {
const SHEET_URL = "https://api.sheetbest.com/sheets/a1b91312-947f-4689-b10a-1ab876c556af";
function randomPick(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
async function fetchItems() {
const res = await fetch(SHEET_URL);
const data = await res.json();
return data; // array of items
}
function pickItem(items, category, weather, occasion=null, excludeTypes=[]) {
let filtered = items.filter(i => i.Category === category);
if(weather) filtered = filtered.filter(i => i['Suitable Weather']?.includes(weather));
if(occasion) filtered = filtered.filter(i => i['Occasion']?.includes(occasion));
if(excludeTypes.length) filtered = filtered.filter(i => !excludeTypes.includes(i[`${category} Type`] || i.Type));
return filtered.length ? randomPick(filtered) : null;
}
async function generateOutfit() {
const weather = document.getElementById("weatherOption").value;
const items = await fetchItems();
let outfit = [];
// PICK dress OR top+bottom
let dress = pickItem(items, "Dress", weather);
if(dress) {
outfit.push(dress);
} else {
let top = pickItem(items, "Top", weather);
let bottom = pickItem(items, "Pants", weather) || pickItem(items, "Skirt", weather);
if(top) outfit.push(top);
if(bottom) outfit.push(bottom);
}
// Layer rules
let excludeLayers = [];
const topOrDress = outfit.find(i => i.Category === "Top" || i.Category === "Dress");
if(topOrDress?.['Top Type']?.toLowerCase()?.includes("sweater") || topOrDress?.['Dress Type']?.toLowerCase()?.includes("sweater")) {
excludeLayers = ["vest","cardigan","blazer","sweater vest"];
}
let layer = pickItem(items, "Layers", weather, null, excludeLayers);
if(layer) outfit.push(layer);
// Cold / Freezing coat rule
if(["Cold","Freezing"].includes(weather)) {
let coat = items.find(i => i['Layers Type']?.toLowerCase() === "coat");
if(coat) outfit.push(coat);
if(layer && ["blazer","shacket","jacket","puffer vest"].includes(layer['Layers Type']?.toLowerCase())) {
outfit = outfit.filter(i => i !== layer);
}
}
// Shoes
let shoes = pickItem(items, "Shoes", weather);
if(shoes && shoes['Shoes Type']?.toLowerCase().includes("rain boots") && 0 /* skip rain check for now */ < 80) {
shoes = pickItem(items, "Shoes", weather, null, ["rain boots"]);
}
if(shoes) outfit.push(shoes);
// Purse
let purse = pickItem(items, "Purse", weather);
if(purse) outfit.push(purse);
// Accessories (max 3, 2 for loungewear)
const isLoungewear = outfit.some(i => i.Occasion?.toLowerCase()?.includes("loungewear"));
const maxAccessories = isLoungewear ? 2 : 3;
let accessories = [];
const accCandidates = items.filter(i => i.Category === "Accessories");
while(accessories.length < maxAccessories) {
let acc = randomPick(accCandidates);
if(!acc) break;
if(!accessories.find(a=>a['Accessories Type']===acc['Accessories Type'])) {
if(acc['Accessories Type']?.toLowerCase()==="scarf" && accessories.find(a=>a['Accessories Type']?.toLowerCase()==="necklace")) continue;
if(acc['Accessories Type']?.toLowerCase()==="necklace" && accessories.find(a=>a['Accessories Type']?.toLowerCase()==="scarf")) continue;
if(acc['Accessories Type']?.toLowerCase()==="hat" && outfit.some(i=>i.Occasion?.toLowerCase()?.includes("special occasion"))) continue;
accessories.push(acc);
}
}
outfit.push(...accessories);
// Display outfit
const container = document.getElementById("outfit-results");
container.innerHTML = outfit.filter(Boolean).map(i =>
`
${i['Dress Type'] || i['Top Type'] || i['Pants Type'] || i['Layers Type'] || i['Accessories Type'] || i['Purse Type'] || i['Shoes Type'] || i.Type}
${i.Category}
`
).join("");
}
document.getElementById("generate").addEventListener("click", generateOutfit);
});