1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-19 12:59:36 +02:00

feat(lodging): add check-in and check-out labels and enhance date handling for lodging events

This commit is contained in:
Sean Morley 2025-06-18 22:21:34 -04:00
parent df24316837
commit 9964398e25
15 changed files with 93 additions and 68 deletions

View file

@ -263,7 +263,9 @@
<label for="date" class="text-sm font-medium"> <label for="date" class="text-sm font-medium">
{type === 'transportation' {type === 'transportation'
? $t('adventures.departure_date') ? $t('adventures.departure_date')
: $t('adventures.start_date')} : type === 'lodging'
? $t('adventures.check_in')
: $t('adventures.start_date')}
</label> </label>
{#if allDay} {#if allDay}
@ -295,7 +297,11 @@
{#if localStartDate} {#if localStartDate}
<div class="space-y-2"> <div class="space-y-2">
<label for="end_date" class="text-sm font-medium"> <label for="end_date" class="text-sm font-medium">
{type === 'transportation' ? $t('adventures.arrival_date') : $t('adventures.end_date')} {type === 'transportation'
? $t('adventures.arrival_date')
: type === 'lodging'
? $t('adventures.check_out')
: $t('adventures.end_date')}
</label> </label>
{#if allDay} {#if allDay}

View file

@ -7,6 +7,8 @@
import LocationDropdown from './LocationDropdown.svelte'; import LocationDropdown from './LocationDropdown.svelte';
import DateRangeCollapse from './DateRangeCollapse.svelte'; import DateRangeCollapse from './DateRangeCollapse.svelte';
import { isAllDay } from '$lib'; import { isAllDay } from '$lib';
// @ts-ignore
import { DateTime } from 'luxon';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -85,19 +87,21 @@
lodging.timezone = lodgingTimezone || null; lodging.timezone = lodgingTimezone || null;
console.log(lodgingTimezone);
// Auto-set end date if missing but start date exists // Auto-set end date if missing but start date exists
if (lodging.check_in && !lodging.check_out) { if (lodging.check_in && !lodging.check_out) {
const startDate = new Date(lodging.check_in);
const nextDay = new Date(startDate);
nextDay.setDate(nextDay.getDate() + 1);
if (isAllDay(lodging.check_in)) { if (isAllDay(lodging.check_in)) {
// For all-day, set to next day at 00:00:00 // For all-day, just add one day and keep at UTC 00:00:00
lodging.check_out = nextDay.toISOString().split('T')[0] + 'T00:00:00'; const start = DateTime.fromISO(lodging.check_in, { zone: 'utc' });
const nextDay = start.plus({ days: 1 });
lodging.check_out = nextDay.toISO();
} else { } else {
// For timed events, set to next day at 9:00 AM // For timed events, set to next day at 9:00 AM in lodging's timezone, then convert to UTC
nextDay.setHours(9, 0, 0, 0); const start = DateTime.fromISO(lodging.check_in, { zone: lodging.timezone || 'utc' });
lodging.check_out = nextDay.toISOString(); const nextDay = start.plus({ days: 1 });
const end = nextDay.set({ hour: 9, minute: 0, second: 0, millisecond: 0 });
lodging.check_out = end.toUTC().toISO();
} }
} }

View file

@ -70,66 +70,57 @@ export function groupAdventuresByDate(
): Record<string, Adventure[]> { ): Record<string, Adventure[]> {
const groupedAdventures: Record<string, Adventure[]> = {}; const groupedAdventures: Record<string, Adventure[]> = {};
// Initialize all days in the range // Initialize all days in the range using DateTime
for (let i = 0; i < numberOfDays; i++) { for (let i = 0; i < numberOfDays; i++) {
const currentDate = new Date(startDate); const currentDate = DateTime.fromJSDate(startDate).plus({ days: i });
currentDate.setDate(startDate.getDate() + i); const dateString = currentDate.toISODate(); // 'YYYY-MM-DD'
const dateString = getLocalDateString(currentDate);
groupedAdventures[dateString] = []; groupedAdventures[dateString] = [];
} }
adventures.forEach((adventure) => { adventures.forEach((adventure) => {
adventure.visits.forEach((visit) => { adventure.visits.forEach((visit) => {
if (visit.start_date) { if (visit.start_date) {
// Check if this is an all-day event (both start and end at midnight) // Check if it's all-day: start has 00:00:00 AND (no end OR end also has 00:00:00)
const isAllDayEvent = const startHasZeros = visit.start_date.includes('T00:00:00');
isAllDay(visit.start_date) && (visit.end_date ? isAllDay(visit.end_date) : false); const endHasZeros = visit.end_date ? visit.end_date.includes('T00:00:00') : true;
const isAllDayEvent = startHasZeros && endHasZeros;
// For all-day events, we need to handle dates differently let startDT: DateTime;
if (isAllDayEvent && visit.end_date) { let endDT: DateTime;
// Extract just the date parts without time
const startDateStr = visit.start_date.split('T')[0];
const endDateStr = visit.end_date.split('T')[0];
// Loop through all days in the range if (isAllDayEvent) {
for (let i = 0; i < numberOfDays; i++) { // For all-day events, extract just the date part and ignore timezone
const currentDate = new Date(startDate); const dateOnly = visit.start_date.split('T')[0]; // Get 'YYYY-MM-DD'
currentDate.setDate(startDate.getDate() + i); startDT = DateTime.fromISO(dateOnly); // This creates a date without time/timezone
const currentDateStr = getLocalDateString(currentDate);
// Include the current day if it falls within the adventure date range endDT = visit.end_date
if (currentDateStr >= startDateStr && currentDateStr <= endDateStr) { ? DateTime.fromISO(visit.end_date.split('T')[0])
if (groupedAdventures[currentDateStr]) { : startDT;
groupedAdventures[currentDateStr].push(adventure);
}
}
}
} else { } else {
// Handle regular events with time components // For timed events, use timezone conversion
const adventureStartDate = new Date(visit.start_date); startDT = DateTime.fromISO(visit.start_date, {
const adventureDateStr = getLocalDateString(adventureStartDate); zone: visit.timezone ?? 'UTC'
});
if (visit.end_date) { endDT = visit.end_date
const adventureEndDate = new Date(visit.end_date); ? DateTime.fromISO(visit.end_date, {
const endDateStr = getLocalDateString(adventureEndDate); zone: visit.timezone ?? 'UTC'
})
: startDT;
}
// Loop through all days and include adventure if it falls within the range const startDateStr = startDT.toISODate();
for (let i = 0; i < numberOfDays; i++) { const endDateStr = endDT.toISODate();
const currentDate = new Date(startDate);
currentDate.setDate(startDate.getDate() + i);
const dateString = getLocalDateString(currentDate);
// Include the current day if it falls within the adventure date range // Loop through all days in range
if (dateString >= adventureDateStr && dateString <= endDateStr) { for (let i = 0; i < numberOfDays; i++) {
if (groupedAdventures[dateString]) { const currentDate = DateTime.fromJSDate(startDate).plus({ days: i });
groupedAdventures[dateString].push(adventure); const currentDateStr = currentDate.toISODate();
}
} // Include the current day if it falls within the adventure date range
} if (currentDateStr >= startDateStr && currentDateStr <= endDateStr) {
} else { if (groupedAdventures[currentDateStr]) {
// If there's no end date, add adventure to the start date only groupedAdventures[currentDateStr].push(adventure);
if (groupedAdventures[adventureDateStr]) {
groupedAdventures[adventureDateStr].push(adventure);
} }
} }
} }

View file

@ -244,7 +244,9 @@
"done": "Erledigt", "done": "Erledigt",
"loading_adventures": "Ladeabenteuer ...", "loading_adventures": "Ladeabenteuer ...",
"name_location": "Name, Ort", "name_location": "Name, Ort",
"collection_contents": "Sammelinhalt" "collection_contents": "Sammelinhalt",
"check_in": "Einchecken",
"check_out": "Kasse"
}, },
"home": { "home": {
"desc_1": "Entdecken, planen und erkunden Sie mühelos", "desc_1": "Entdecken, planen und erkunden Sie mühelos",

View file

@ -98,6 +98,8 @@
"latitude": "Latitude", "latitude": "Latitude",
"visit": "Visit", "visit": "Visit",
"timed": "Timed", "timed": "Timed",
"check_in": "Check In",
"check_out": "Check Out",
"coordinates": "Coordinates", "coordinates": "Coordinates",
"copy_coordinates": "Copy Coordinates", "copy_coordinates": "Copy Coordinates",
"visits": "Visits", "visits": "Visits",

View file

@ -296,7 +296,9 @@
"done": "Hecho", "done": "Hecho",
"loading_adventures": "Cargando aventuras ...", "loading_adventures": "Cargando aventuras ...",
"name_location": "Nombre, ubicación", "name_location": "Nombre, ubicación",
"collection_contents": "Contenido de la colección" "collection_contents": "Contenido de la colección",
"check_in": "Registrarse",
"check_out": "Verificar"
}, },
"worldtravel": { "worldtravel": {
"all": "Todo", "all": "Todo",

View file

@ -244,7 +244,9 @@
"done": "Fait", "done": "Fait",
"loading_adventures": "Chargement des aventures ...", "loading_adventures": "Chargement des aventures ...",
"name_location": "nom, emplacement", "name_location": "nom, emplacement",
"collection_contents": "Contenu de la collection" "collection_contents": "Contenu de la collection",
"check_in": "Enregistrement",
"check_out": "Vérifier"
}, },
"home": { "home": {
"desc_1": "Découvrez, planifiez et explorez en toute simplicité", "desc_1": "Découvrez, planifiez et explorez en toute simplicité",

View file

@ -244,7 +244,9 @@
"done": "Fatto", "done": "Fatto",
"loading_adventures": "Caricamento di avventure ...", "loading_adventures": "Caricamento di avventure ...",
"name_location": "Nome, posizione", "name_location": "Nome, posizione",
"collection_contents": "Contenuto di raccolta" "collection_contents": "Contenuto di raccolta",
"check_in": "Check -in",
"check_out": "Guardare"
}, },
"home": { "home": {
"desc_1": "Scopri, pianifica ed esplora con facilità", "desc_1": "Scopri, pianifica ed esplora con facilità",

View file

@ -244,7 +244,9 @@
"done": "완료", "done": "완료",
"loading_adventures": "적재 모험 ...", "loading_adventures": "적재 모험 ...",
"name_location": "이름, 위치", "name_location": "이름, 위치",
"collection_contents": "수집 내용" "collection_contents": "수집 내용",
"check_in": "체크인",
"check_out": "체크 아웃"
}, },
"auth": { "auth": {
"confirm_password": "비밀번호 확인", "confirm_password": "비밀번호 확인",

View file

@ -244,7 +244,9 @@
"done": "Klaar", "done": "Klaar",
"loading_adventures": "Adventuren laden ...", "loading_adventures": "Adventuren laden ...",
"name_location": "naam, locatie", "name_location": "naam, locatie",
"collection_contents": "Verzamelingsinhoud" "collection_contents": "Verzamelingsinhoud",
"check_in": "Inchecken",
"check_out": "Uitchecken"
}, },
"home": { "home": {
"desc_1": "Ontdek, plan en verken met gemak", "desc_1": "Ontdek, plan en verken met gemak",

View file

@ -296,7 +296,9 @@
"done": "Ferdig", "done": "Ferdig",
"loading_adventures": "Laster opp eventyr ...", "loading_adventures": "Laster opp eventyr ...",
"name_location": "Navn, plassering", "name_location": "Navn, plassering",
"collection_contents": "Samlingsinnhold" "collection_contents": "Samlingsinnhold",
"check_in": "Sjekk inn",
"check_out": "Sjekk ut"
}, },
"worldtravel": { "worldtravel": {
"country_list": "Liste over land", "country_list": "Liste over land",

View file

@ -296,7 +296,9 @@
"loading_adventures": "Ładowanie przygód ...", "loading_adventures": "Ładowanie przygód ...",
"name_location": "Nazwa, lokalizacja", "name_location": "Nazwa, lokalizacja",
"delete_collection_warning": "Czy na pewno chcesz usunąć tę kolekcję? \nTego działania nie można cofnąć.", "delete_collection_warning": "Czy na pewno chcesz usunąć tę kolekcję? \nTego działania nie można cofnąć.",
"collection_contents": "Zawartość kolekcji" "collection_contents": "Zawartość kolekcji",
"check_in": "Zameldować się",
"check_out": "Wymeldować się"
}, },
"worldtravel": { "worldtravel": {
"country_list": "Lista krajów", "country_list": "Lista krajów",

View file

@ -296,7 +296,9 @@
"done": "Сделанный", "done": "Сделанный",
"loading_adventures": "Загрузка приключений ...", "loading_adventures": "Загрузка приключений ...",
"name_location": "имя, местоположение", "name_location": "имя, местоположение",
"collection_contents": "Содержание коллекции" "collection_contents": "Содержание коллекции",
"check_in": "Регистрироваться",
"check_out": "Проверить"
}, },
"worldtravel": { "worldtravel": {
"country_list": "Список стран", "country_list": "Список стран",

View file

@ -244,7 +244,9 @@
"done": "Gjort", "done": "Gjort",
"loading_adventures": "Laddar äventyr ...", "loading_adventures": "Laddar äventyr ...",
"name_location": "namn, plats", "name_location": "namn, plats",
"collection_contents": "Insamlingsinnehåll" "collection_contents": "Insamlingsinnehåll",
"check_in": "Checka in",
"check_out": "Checka ut"
}, },
"home": { "home": {
"desc_1": "Upptäck, planera och utforska med lätthet", "desc_1": "Upptäck, planera och utforska med lätthet",

View file

@ -296,7 +296,9 @@
"done": "完毕", "done": "完毕",
"loading_adventures": "加载冒险...", "loading_adventures": "加载冒险...",
"name_location": "名称,位置", "name_location": "名称,位置",
"collection_contents": "收集内容" "collection_contents": "收集内容",
"check_in": "报到",
"check_out": "查看"
}, },
"auth": { "auth": {
"forgot_password": "忘记密码?", "forgot_password": "忘记密码?",