import inspirationalQuotes from './json/quotes.json'; import randomBackgrounds from './json/backgrounds.json'; import type { Adventure, Background, Checklist, Collection, Note, Transportation, User } from './types'; export function getRandomQuote() { const quotes = inspirationalQuotes.quotes; const randomIndex = Math.floor(Math.random() * quotes.length); let quoteString = quotes[randomIndex].quote; let authorString = quotes[randomIndex].author; return { quote: quoteString, author: authorString }; } export function getFlag(size: number, country: string) { return `https://flagcdn.com/h${size}/${country}.png`; } export function checkLink(link: string) { if (link.startsWith('http://') || (link.startsWith('https://') && link.indexOf('.') !== -1)) { return link; } else { return 'http://' + link + '.com'; } } export async function exportData() { let res = await fetch('/api/adventures/all'); let adventures = (await res.json()) as Adventure[]; res = await fetch('/api/collections/all'); let collections = (await res.json()) as Collection[]; res = await fetch('/api/visitedregion'); let visitedRegions = await res.json(); const data = { adventures, collections, visitedRegions }; const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); return URL.createObjectURL(blob); } export function isValidUrl(url: string) { try { new URL(url); return true; } catch (err) { return false; } } export function groupAdventuresByDate( adventures: Adventure[], startDate: Date, numberOfDays: number ): Record { const groupedAdventures: Record = {}; // Initialize all days in the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; groupedAdventures[dateString] = []; } adventures.forEach((adventure) => { adventure.visits.forEach((visit) => { if (visit.start_date) { const adventureDate = new Date(visit.start_date).toISOString().split('T')[0]; if (visit.end_date) { const endDate = new Date(visit.end_date).toISOString().split('T')[0]; // Loop through all days and include adventure if it falls within the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; // Include the current day if it falls within the adventure date range if (dateString >= adventureDate && dateString <= endDate) { if (groupedAdventures[dateString]) { groupedAdventures[dateString].push(adventure); } } } } else if (groupedAdventures[adventureDate]) { // If there's no end date, add adventure to the start date only groupedAdventures[adventureDate].push(adventure); } } }); }); return groupedAdventures; } export function groupTransportationsByDate( transportations: Transportation[], startDate: Date, numberOfDays: number ): Record { const groupedTransportations: Record = {}; // Initialize all days in the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; groupedTransportations[dateString] = []; } transportations.forEach((transportation) => { if (transportation.date) { const transportationDate = new Date(transportation.date).toISOString().split('T')[0]; if (transportation.end_date) { const endDate = new Date(transportation.end_date).toISOString().split('T')[0]; // Loop through all days and include transportation if it falls within the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; // Include the current day if it falls within the transportation date range if (dateString >= transportationDate && dateString <= endDate) { if (groupedTransportations[dateString]) { groupedTransportations[dateString].push(transportation); } } } } else if (groupedTransportations[transportationDate]) { // If there's no end date, add transportation to the start date only groupedTransportations[transportationDate].push(transportation); } } }); return groupedTransportations; } export function groupNotesByDate( notes: Note[], startDate: Date, numberOfDays: number ): Record { const groupedNotes: Record = {}; // Initialize all days in the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; groupedNotes[dateString] = []; } notes.forEach((note) => { if (note.date) { const noteDate = new Date(note.date).toISOString().split('T')[0]; // Add note to the appropriate date group if it exists if (groupedNotes[noteDate]) { groupedNotes[noteDate].push(note); } } }); return groupedNotes; } export function groupChecklistsByDate( checklists: Checklist[], startDate: Date, numberOfDays: number ): Record { const groupedChecklists: Record = {}; // Initialize all days in the range for (let i = 0; i < numberOfDays; i++) { const currentDate = new Date(startDate); currentDate.setUTCDate(startDate.getUTCDate() + i); const dateString = currentDate.toISOString().split('T')[0]; groupedChecklists[dateString] = []; } checklists.forEach((checklist) => { if (checklist.date) { const checklistDate = new Date(checklist.date).toISOString().split('T')[0]; // Add checklist to the appropriate date group if it exists if (groupedChecklists[checklistDate]) { groupedChecklists[checklistDate].push(checklist); } } }); return groupedChecklists; } export function continentCodeToString(code: string) { switch (code) { case 'AF': return 'Africa'; case 'AN': return 'Antarctica'; case 'AS': return 'Asia'; case 'EU': return 'Europe'; case 'NA': return 'North America'; case 'OC': return 'Oceania'; case 'SA': return 'South America'; default: return 'Unknown'; } } export let ADVENTURE_TYPES = [ { type: 'general', label: 'General 🌍' }, { type: 'outdoor', label: 'Outdoor 🏞️' }, { type: 'lodging', label: 'Lodging πŸ›Œ' }, { type: 'dining', label: 'Dining 🍽️' }, { type: 'activity', label: 'Activity πŸ„' }, { type: 'attraction', label: 'Attraction 🎒' }, { type: 'shopping', label: 'Shopping πŸ›οΈ' }, { type: 'nightlife', label: 'Nightlife πŸŒƒ' }, { type: 'event', label: 'Event πŸŽ‰' }, { type: 'transportation', label: 'Transportation πŸš—' }, { type: 'culture', label: 'Culture 🎭' }, { type: 'water_sports', label: 'Water Sports 🚀' }, { type: 'hiking', label: 'Hiking πŸ₯Ύ' }, { type: 'wildlife', label: 'Wildlife πŸ¦’' }, { type: 'historical_sites', label: 'Historical Sites πŸ›οΈ' }, { type: 'music_concerts', label: 'Music & Concerts 🎢' }, { type: 'fitness', label: 'Fitness πŸ‹οΈ' }, { type: 'art_museums', label: 'Art & Museums 🎨' }, { type: 'festivals', label: 'Festivals πŸŽͺ' }, { type: 'spiritual_journeys', label: 'Spiritual Journeys πŸ§˜β€β™€οΈ' }, { type: 'volunteer_work', label: 'Volunteer Work 🀝' }, { type: 'other', label: 'Other' } ]; // adventure type to icon mapping export let ADVENTURE_TYPE_ICONS = { general: '🌍', outdoor: '🏞️', lodging: 'πŸ›Œ', dining: '🍽️', activity: 'πŸ„', attraction: '🎒', shopping: 'πŸ›οΈ', nightlife: 'πŸŒƒ', event: 'πŸŽ‰', transportation: 'πŸš—', culture: '🎭', water_sports: '🚀', hiking: 'πŸ₯Ύ', wildlife: 'πŸ¦’', historical_sites: 'πŸ›οΈ', music_concerts: '🎢', fitness: 'πŸ‹οΈ', art_museums: '🎨', festivals: 'πŸŽͺ', spiritual_journeys: 'πŸ§˜β€β™€οΈ', volunteer_work: '🀝', other: '❓' }; export function getAdventureTypeLabel(type: string) { // return the emoji ADVENTURE_TYPE_ICONS label for the given type if not found return ? emoji if (type in ADVENTURE_TYPE_ICONS) { return ADVENTURE_TYPE_ICONS[type as keyof typeof ADVENTURE_TYPE_ICONS]; } else { return '❓'; } } export function getRandomBackground() { const today = new Date(); // Special dates for specific backgrounds // New Years week const newYearsStart = new Date(today.getFullYear() - 1, 11, 31); newYearsStart.setHours(0, 0, 0, 0); const newYearsEnd = new Date(today.getFullYear(), 0, 2); newYearsEnd.setHours(23, 59, 59, 999); if (today >= newYearsStart && today <= newYearsEnd) { return { url: 'backgrounds/adventurelog_new_year.webp', author: 'Roven Images', location: "Happy New Year's from the AdventureLog team!" } as Background; } // Christmas 12/24 - 12/25 const christmasStart = new Date(today.getFullYear(), 11, 24); christmasStart.setHours(0, 0, 0, 0); const christmasEnd = new Date(today.getFullYear(), 11, 25); christmasEnd.setHours(23, 59, 59, 999); if (today >= christmasStart && today <= christmasEnd) { return { url: 'backgrounds/adventurelog_christmas.webp', author: 'Annie Spratt', location: 'Merry Christmas from the AdventureLog team!' } as Background; } const randomIndex = Math.floor(Math.random() * randomBackgrounds.backgrounds.length); return randomBackgrounds.backgrounds[randomIndex] as Background; } export function findFirstValue(obj: any): any { for (const key in obj) { if (typeof obj[key] === 'object' && obj[key] !== null) { const value = findFirstValue(obj[key]); if (value !== undefined) { return value; } } else { return obj[key]; } } } export let themes = [ { name: 'light', label: 'Light' }, { name: 'dark', label: 'Dark' }, { name: 'night', label: 'Night' }, { name: 'forest', label: 'Forest' }, { name: 'aqua', label: 'Aqua' }, { name: 'aestheticLight', label: 'Aesthetic Light' }, { name: 'aestheticDark', label: 'Aesthetic Dark' }, { name: 'northernLights', label: 'Northern Lights' } ]; export function osmTagToEmoji(tag: string) { switch (tag) { case 'camp_site': return 'πŸ•οΈ'; case 'slipway': return 'πŸ›³οΈ'; case 'playground': return 'πŸ›'; case 'viewpoint': return 'πŸ‘€'; case 'cape': return '🏞️'; case 'beach': return 'πŸ–οΈ'; case 'park': return '🌳'; case 'museum': return 'πŸ›οΈ'; case 'theme_park': return '🎒'; case 'nature_reserve': return '🌲'; case 'memorial': return 'πŸ•ŠοΈ'; case 'monument': return 'πŸ—Ώ'; case 'wood': return '🌲'; case 'zoo': return '🦁'; case 'attraction': return '🎑'; case 'ruins': return '🏚️'; case 'bay': return '🌊'; case 'hotel': return '🏨'; case 'motel': return '🏩'; case 'pub': return '🍺'; case 'restaurant': return '🍽️'; case 'cafe': return 'β˜•'; case 'bakery': return 'πŸ₯'; case 'archaeological_site': return '🏺'; case 'lighthouse': return 'πŸ—Ό'; case 'tree': return '🌳'; case 'cliff': return '⛰️'; case 'water': return 'πŸ’§'; case 'fishing': return '🎣'; case 'golf_course': return 'β›³'; case 'swimming_pool': return '🏊'; case 'stadium': return '🏟️'; case 'cave_entrance': return 'πŸ•³οΈ'; case 'anchor': return 'βš“'; case 'garden': return '🌼'; case 'disc_golf_course': return 'πŸ₯'; case 'natural': return '🌿'; case 'ice_rink': return '⛸️'; case 'horse_riding': return '🐎'; case 'wreck': return '🚒'; case 'water_park': return 'πŸ’¦'; case 'picnic_site': return '🧺'; case 'axe_throwing': return 'πŸͺ“'; case 'fort': return '🏰'; case 'amusement_arcade': return 'πŸ•ΉοΈ'; case 'tepee': return 'πŸ•οΈ'; case 'track': return 'πŸƒ'; case 'trampoline_park': return '🀸'; case 'dojo': return 'πŸ₯‹'; case 'tree_stump': return 'πŸͺ΅'; case 'peak': return 'πŸ”οΈ'; case 'fitness_centre': return 'πŸ‹οΈ'; case 'artwork': return '🎨'; case 'fast_food': return 'πŸ”'; case 'ice_cream': return '🍦'; default: return 'πŸ“'; // Default placeholder emoji for unknown tags } }