mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-28 17:29:36 +02:00
Refactor date handling components: Replace DateRangeDropdown with DateRangeCollapse
- Introduced DateRangeCollapse.svelte to manage date range selection with timezone support. - Removed DateRangeDropdown.svelte as it was redundant. - Updated LodgingModal and TransportationModal to utilize DateRangeCollapse for date selection. - Enhanced date conversion utilities to handle all-day events correctly. - Adjusted TimezoneSelector for improved accessibility and focus management. - Updated date handling logic in dateUtils.ts to support all-day events. - Modified test page to reflect changes in date range component usage.
This commit is contained in:
parent
827b150965
commit
2c50ca0b1a
8 changed files with 484 additions and 758 deletions
|
@ -92,6 +92,7 @@
|
|||
import Crown from '~icons/mdi/crown';
|
||||
import AttachmentCard from './AttachmentCard.svelte';
|
||||
import LocationDropdown from './LocationDropdown.svelte';
|
||||
import DateRangeCollapse from './DateRangeCollapse.svelte';
|
||||
let modal: HTMLDialogElement;
|
||||
|
||||
let wikiError: string = '';
|
||||
|
@ -684,237 +685,8 @@
|
|||
<ActivityComplete bind:activities={adventure.activity_types} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse collapse-plus bg-base-200 mb-4">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
{$t('adventures.visits')} ({adventure.visits.length})
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<label class="label cursor-pointer flex items-start space-x-2">
|
||||
{#if adventure.collection && collection && collection.start_date && collection.end_date}
|
||||
<span class="label-text">{$t('adventures.date_constrain')}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
id="constrain_dates"
|
||||
name="constrain_dates"
|
||||
on:change={() => (constrainDates = !constrainDates)}
|
||||
/>
|
||||
{/if}
|
||||
<span class="label-text">{$t('adventures.all_day')}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
id="constrain_dates"
|
||||
name="constrain_dates"
|
||||
bind:checked={allDay}
|
||||
/>
|
||||
</label>
|
||||
<div class="flex gap-2 mb-1">
|
||||
{#if !allDay}
|
||||
<input
|
||||
type="datetime-local"
|
||||
class="input input-bordered w-full"
|
||||
placeholder={$t('adventures.start_date')}
|
||||
min={constrainDates ? fullStartDate : ''}
|
||||
max={constrainDates ? fullEndDate : ''}
|
||||
bind:value={new_start_date}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addNewVisit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="datetime-local"
|
||||
class="input input-bordered w-full"
|
||||
placeholder={$t('adventures.end_date')}
|
||||
bind:value={new_end_date}
|
||||
min={constrainDates ? fullStartDate : ''}
|
||||
max={constrainDates ? fullEndDate : ''}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addNewVisit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
type="date"
|
||||
class="input input-bordered w-full"
|
||||
placeholder={$t('adventures.start_date')}
|
||||
min={constrainDates ? fullStartDateOnly : ''}
|
||||
max={constrainDates ? fullEndDateOnly : ''}
|
||||
bind:value={new_start_date}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addNewVisit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="date"
|
||||
class="input input-bordered w-full"
|
||||
placeholder={$t('adventures.end_date')}
|
||||
bind:value={new_end_date}
|
||||
min={constrainDates ? fullStartDateOnly : ''}
|
||||
max={constrainDates ? fullEndDateOnly : ''}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addNewVisit();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex gap-2 mb-1">
|
||||
<!-- textarea for notes -->
|
||||
<textarea
|
||||
class="textarea textarea-bordered w-full"
|
||||
placeholder={$t('adventures.add_notes')}
|
||||
bind:value={new_notes}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addNewVisit();
|
||||
}
|
||||
}}
|
||||
></textarea>
|
||||
</div>
|
||||
{#if !allDay}
|
||||
<div role="alert" class="alert shadow-lg bg-neutral mt-2 mb-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-info h-6 w-6 shrink-0"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<span>
|
||||
{$t('lodging.current_timezone')}:
|
||||
{(() => {
|
||||
const tz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const [continent, city] = tz.split('/');
|
||||
return `${continent} (${city.replace('_', ' ')})`;
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button type="button" class="btn btn-neutral" on:click={addNewVisit}
|
||||
>{$t('adventures.add')}</button
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if adventure.visits.length > 0}
|
||||
<h2 class="font-bold text-xl mt-2">{$t('adventures.my_visits')}</h2>
|
||||
{#each adventure.visits as visit}
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2 items-center">
|
||||
<p>
|
||||
{#if isAllDay(visit.start_date)}
|
||||
<!-- For all-day events, show just the date -->
|
||||
{new Date(visit.start_date).toLocaleDateString(undefined, {
|
||||
timeZone: 'UTC'
|
||||
})}
|
||||
{:else}
|
||||
<!-- For timed events, show date and time -->
|
||||
{new Date(visit.start_date).toLocaleDateString()} ({new Date(
|
||||
visit.start_date
|
||||
).toLocaleTimeString()})
|
||||
{/if}
|
||||
</p>
|
||||
{#if visit.end_date && visit.end_date !== visit.start_date}
|
||||
<p>
|
||||
{#if isAllDay(visit.end_date)}
|
||||
<!-- For all-day events, show just the date -->
|
||||
{new Date(visit.end_date).toLocaleDateString(undefined, {
|
||||
timeZone: 'UTC'
|
||||
})}
|
||||
{:else}
|
||||
<!-- For timed events, show date and time -->
|
||||
{new Date(visit.end_date).toLocaleDateString()} ({new Date(
|
||||
visit.end_date
|
||||
).toLocaleTimeString()})
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-neutral"
|
||||
on:click={() => {
|
||||
// Determine if this is an all-day event
|
||||
const isAllDayEvent = isAllDay(visit.start_date);
|
||||
allDay = isAllDayEvent;
|
||||
|
||||
if (isAllDayEvent) {
|
||||
// For all-day events, use date only
|
||||
new_start_date = visit.start_date.split('T')[0];
|
||||
new_end_date = visit.end_date.split('T')[0];
|
||||
} else {
|
||||
// For timed events, format properly for datetime-local input
|
||||
const startDate = new Date(visit.start_date);
|
||||
const endDate = new Date(visit.end_date);
|
||||
|
||||
// Format as yyyy-MM-ddThh:mm
|
||||
new_start_date =
|
||||
startDate.getFullYear() +
|
||||
'-' +
|
||||
String(startDate.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(startDate.getDate()).padStart(2, '0') +
|
||||
'T' +
|
||||
String(startDate.getHours()).padStart(2, '0') +
|
||||
':' +
|
||||
String(startDate.getMinutes()).padStart(2, '0');
|
||||
|
||||
new_end_date =
|
||||
endDate.getFullYear() +
|
||||
'-' +
|
||||
String(endDate.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(endDate.getDate()).padStart(2, '0') +
|
||||
'T' +
|
||||
String(endDate.getHours()).padStart(2, '0') +
|
||||
':' +
|
||||
String(endDate.getMinutes()).padStart(2, '0');
|
||||
}
|
||||
|
||||
new_notes = visit.notes;
|
||||
adventure.visits = adventure.visits.filter((v) => v !== visit);
|
||||
}}
|
||||
>
|
||||
{$t('lodging.edit')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-error"
|
||||
on:click={() => {
|
||||
adventure.visits = adventure.visits.filter((v) => v !== visit);
|
||||
}}
|
||||
>
|
||||
{$t('adventures.remove')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="whitespace-pre-wrap -mt-2 mb-2">{visit.notes}</p>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<DateRangeCollapse type="adventure" {collection} bind:visits={adventure.visits} />
|
||||
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue