mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-25 15:59:38 +02:00
feat: Refactor hotel terminology to lodging and update related components
This commit is contained in:
parent
d2cb862103
commit
68924d7ecc
17 changed files with 510 additions and 135 deletions
|
@ -1,11 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { appVersion } from '$lib/config';
|
||||
import { addToast } from '$lib/toasts';
|
||||
import type { Adventure, Hotel, OpenStreetMapPlace, Point, ReverseGeocode } from '$lib/types';
|
||||
import type { Adventure, Lodging, OpenStreetMapPlace, Point, ReverseGeocode } from '$lib/types';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { DefaultMarker, MapEvents, MapLibre } from 'svelte-maplibre';
|
||||
|
||||
export let item: Adventure | Hotel;
|
||||
export let item: Adventure | Lodging;
|
||||
export let triggerMarkVisted: boolean = false;
|
||||
|
||||
let reverseGeocodePlace: ReverseGeocode | null = null;
|
||||
|
@ -279,40 +279,39 @@ it would also work to just use on:click on the MapLibre component itself. -->
|
|||
{/each}
|
||||
</MapLibre>
|
||||
{#if reverseGeocodePlace}
|
||||
<div class="mt-2">
|
||||
<p>
|
||||
<div class="mt-2 p-4 bg-neutral rounded-lg shadow-md">
|
||||
<h3 class="text-lg font-bold mb-2">{$t('adventures.location_details')}</h3>
|
||||
<p class="mb-1">
|
||||
<span class="font-semibold">{$t('adventures.display_name')}:</span>
|
||||
{reverseGeocodePlace.city
|
||||
? reverseGeocodePlace.city + ', '
|
||||
: ''}{reverseGeocodePlace.region},
|
||||
{reverseGeocodePlace.country}
|
||||
? reverseGeocodePlace.city + ', '
|
||||
: ''}{reverseGeocodePlace.region}, {reverseGeocodePlace.country}
|
||||
</p>
|
||||
<p>
|
||||
{reverseGeocodePlace.region}:
|
||||
{reverseGeocodePlace.region_visited
|
||||
? $t('adventures.visited')
|
||||
: $t('adventures.not_visited')}
|
||||
<p class="mb-1">
|
||||
<span class="font-semibold">{$t('adventures.region')}:</span>
|
||||
{reverseGeocodePlace.region}
|
||||
{reverseGeocodePlace.region_visited ? '✅' : '❌'}
|
||||
</p>
|
||||
{#if reverseGeocodePlace.city}
|
||||
<p>
|
||||
{reverseGeocodePlace.city}:
|
||||
{reverseGeocodePlace.city_visited
|
||||
? $t('adventures.visited')
|
||||
: $t('adventures.not_visited')}
|
||||
<p class="mb-1">
|
||||
<span class="font-semibold">{$t('adventures.city')}:</span>
|
||||
{reverseGeocodePlace.city}
|
||||
{reverseGeocodePlace.city_visited ? '✅' : '❌'}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !reverseGeocodePlace.region_visited || (!reverseGeocodePlace.city_visited && !willBeMarkedVisited)}
|
||||
<button type="button" class="btn btn-neutral" on:click={markVisited}>
|
||||
<button type="button" class="btn btn-primary mt-2" on:click={markVisited}>
|
||||
{$t('adventures.mark_visited')}
|
||||
</button>
|
||||
{/if}
|
||||
{#if (willBeMarkedVisited && !reverseGeocodePlace.region_visited && reverseGeocodePlace.region_id) || (!reverseGeocodePlace.city_visited && willBeMarkedVisited && reverseGeocodePlace.city_id)}
|
||||
<div role="alert" class="alert alert-info mt-2">
|
||||
<div role="alert" class="alert alert-info mt-2 flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
class="h-6 w-6 shrink-0 stroke-current mr-2"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -321,13 +320,12 @@ it would also work to just use on:click on the MapLibre component itself. -->
|
|||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<span
|
||||
>{reverseGeocodePlace.city
|
||||
? reverseGeocodePlace.city + ', '
|
||||
: ''}{reverseGeocodePlace.region},
|
||||
{reverseGeocodePlace.country}
|
||||
{$t('adventures.will_be_marked')}</span
|
||||
>
|
||||
<span>
|
||||
{reverseGeocodePlace.city
|
||||
? reverseGeocodePlace.city + ', '
|
||||
: ''}{reverseGeocodePlace.region}, {reverseGeocodePlace.country}
|
||||
{$t('adventures.will_be_marked')}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
176
frontend/src/lib/components/LodgingCard.svelte
Normal file
176
frontend/src/lib/components/LodgingCard.svelte
Normal file
|
@ -0,0 +1,176 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import TrashCanOutline from '~icons/mdi/trash-can-outline';
|
||||
import FileDocumentEdit from '~icons/mdi/file-document-edit';
|
||||
import type { Collection, Lodging, User } from '$lib/types';
|
||||
import { addToast } from '$lib/toasts';
|
||||
import { t } from 'svelte-i18n';
|
||||
import DeleteWarning from './DeleteWarning.svelte';
|
||||
// import ArrowDownThick from '~icons/mdi/arrow-down-thick';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let lodging: Lodging;
|
||||
export let user: User | null = null;
|
||||
export let collection: Collection | null = null;
|
||||
|
||||
let isWarningModalOpen: boolean = false;
|
||||
|
||||
function editTransportation() {
|
||||
dispatch('edit', lodging);
|
||||
}
|
||||
|
||||
let unlinked: boolean = false;
|
||||
|
||||
$: {
|
||||
if (collection?.start_date && collection.end_date) {
|
||||
// Parse transportation dates
|
||||
let transportationStartDate = lodging.check_in
|
||||
? new Date(lodging.check_in.split('T')[0]) // Ensure proper date parsing
|
||||
: null;
|
||||
let transportationEndDate = lodging.check_out
|
||||
? new Date(lodging.check_out.split('T')[0])
|
||||
: null;
|
||||
|
||||
// Parse collection dates
|
||||
let collectionStartDate = new Date(collection.start_date);
|
||||
let collectionEndDate = new Date(collection.end_date);
|
||||
|
||||
// // Debugging outputs
|
||||
// console.log(
|
||||
// 'Transportation Start Date:',
|
||||
// transportationStartDate,
|
||||
// 'Transportation End Date:',
|
||||
// transportationEndDate
|
||||
// );
|
||||
// console.log(
|
||||
// 'Collection Start Date:',
|
||||
// collectionStartDate,
|
||||
// 'Collection End Date:',
|
||||
// collectionEndDate
|
||||
// );
|
||||
|
||||
// Check if the collection range is outside the transportation range
|
||||
const startOutsideRange =
|
||||
transportationStartDate &&
|
||||
collectionStartDate < transportationStartDate &&
|
||||
collectionEndDate < transportationStartDate;
|
||||
|
||||
const endOutsideRange =
|
||||
transportationEndDate &&
|
||||
collectionStartDate > transportationEndDate &&
|
||||
collectionEndDate > transportationEndDate;
|
||||
|
||||
unlinked = !!(
|
||||
startOutsideRange ||
|
||||
endOutsideRange ||
|
||||
(!transportationStartDate && !transportationEndDate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTransportation() {
|
||||
let res = await fetch(`/api/lodging/${lodging.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!res.ok) {
|
||||
console.log($t('transportation.transportation_delete_error'));
|
||||
} else {
|
||||
addToast('info', $t('transportation.transportation_deleted'));
|
||||
isWarningModalOpen = false;
|
||||
dispatch('delete', lodging.id);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isWarningModalOpen}
|
||||
<DeleteWarning
|
||||
title={$t('adventures.delete_transportation')}
|
||||
button_text="Delete"
|
||||
description={$t('adventures.transportation_delete_confirm')}
|
||||
is_warning={false}
|
||||
on:close={() => (isWarningModalOpen = false)}
|
||||
on:confirm={deleteTransportation}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl"
|
||||
>
|
||||
<div class="card-body space-y-4">
|
||||
<!-- Title and Type -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="card-title text-lg font-semibold truncate">{lodging.name}</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="badge badge-secondary">
|
||||
{lodging.type}
|
||||
</div>
|
||||
<!-- {#if hotel.type == 'plane' && hotel.flight_number}
|
||||
<div class="badge badge-neutral-200">{hotel.flight_number}</div>
|
||||
{/if} -->
|
||||
</div>
|
||||
</div>
|
||||
{#if unlinked}
|
||||
<div class="badge badge-error">{$t('adventures.out_of_range')}</div>
|
||||
{/if}
|
||||
|
||||
<!-- Locations -->
|
||||
<div class="space-y-2">
|
||||
{#if lodging.location}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm">{$t('adventures.from')}:</span>
|
||||
<p class="break-words">{lodging.location}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if lodging.check_in && lodging.check_out}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm">{$t('adventures.start')}:</span>
|
||||
<p>{new Date(lodging.check_in).toLocaleDateString(undefined, { timeZone: 'UTC' })}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Dates -->
|
||||
<div class="space-y-2">
|
||||
{#if lodging.location}
|
||||
<!-- <ArrowDownThick class="w-4 h-4" /> -->
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm">{$t('adventures.to')}:</span>
|
||||
|
||||
<p class="break-words">{lodging.location}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if lodging.check_out}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-medium text-sm">{$t('adventures.end')}:</span>
|
||||
<p>{new Date(lodging.check_out).toLocaleDateString(undefined, { timeZone: 'UTC' })}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
{#if lodging.user_id == user?.uuid || (collection && user && collection.shared_with && collection.shared_with.includes(user.uuid))}
|
||||
<div class="card-actions justify-end">
|
||||
<button
|
||||
class="btn btn-primary btn-sm flex items-center gap-1"
|
||||
on:click={editTransportation}
|
||||
title="Edit"
|
||||
>
|
||||
<FileDocumentEdit class="w-5 h-5" />
|
||||
<span>{$t('transportation.edit')}</span>
|
||||
</button>
|
||||
<button
|
||||
on:click={() => (isWarningModalOpen = true)}
|
||||
class="btn btn-secondary btn-sm flex items-center gap-1"
|
||||
title="Delete"
|
||||
>
|
||||
<TrashCanOutline class="w-5 h-5" />
|
||||
<span>{$t('adventures.delete')}</span>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
|
@ -3,27 +3,19 @@
|
|||
import { addToast } from '$lib/toasts';
|
||||
import { t } from 'svelte-i18n';
|
||||
import MarkdownEditor from './MarkdownEditor.svelte';
|
||||
import { appVersion } from '$lib/config';
|
||||
import { DefaultMarker, MapEvents, MapLibre } from 'svelte-maplibre';
|
||||
import type { Collection, Hotel, ReverseGeocode, OpenStreetMapPlace, Point } from '$lib/types';
|
||||
import type { Collection, Lodging } from '$lib/types';
|
||||
import LocationDropdown from './LocationDropdown.svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let collection: Collection;
|
||||
export let hotelToEdit: Hotel | null = null;
|
||||
export let lodgingToEdit: Lodging | null = null;
|
||||
|
||||
let modal: HTMLDialogElement;
|
||||
let constrainDates: boolean = false;
|
||||
let hotel: Hotel = { ...initializeHotel(hotelToEdit) };
|
||||
let lodging: Lodging = { ...initializeLodging(lodgingToEdit) };
|
||||
let fullStartDate: string = '';
|
||||
let fullEndDate: string = '';
|
||||
let reverseGeocodePlace: any | null = null;
|
||||
let query: string = '';
|
||||
let places: OpenStreetMapPlace[] = [];
|
||||
let noPlaces: boolean = false;
|
||||
let is_custom_location: boolean = false;
|
||||
let markers: Point[] = [];
|
||||
|
||||
// Format date as local datetime
|
||||
function toLocalDatetime(value: string | null): string {
|
||||
|
@ -32,12 +24,32 @@
|
|||
return date.toISOString().slice(0, 16); // Format: YYYY-MM-DDTHH:mm
|
||||
}
|
||||
|
||||
type LodgingType = {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
const LODGING_TYPES: LodgingType[] = [
|
||||
{ value: 'hotel', label: 'Hotel' },
|
||||
{ value: 'hostel', label: 'Hostel' },
|
||||
{ value: 'resort', label: 'Resort' },
|
||||
{ value: 'bnb', label: 'Bed & Breakfast' },
|
||||
{ value: 'campground', label: 'Campground' },
|
||||
{ value: 'cabin', label: 'Cabin' },
|
||||
{ value: 'apartment', label: 'Apartment' },
|
||||
{ value: 'house', label: 'House' },
|
||||
{ value: 'villa', label: 'Villa' },
|
||||
{ value: 'motel', label: 'Motel' },
|
||||
{ value: 'other', label: 'Other' }
|
||||
];
|
||||
|
||||
// Initialize hotel with values from hotelToEdit or default values
|
||||
function initializeHotel(hotelToEdit: Hotel | null): Hotel {
|
||||
function initializeLodging(hotelToEdit: Lodging | null): Lodging {
|
||||
return {
|
||||
id: hotelToEdit?.id || '',
|
||||
user_id: hotelToEdit?.user_id || '',
|
||||
name: hotelToEdit?.name || '',
|
||||
type: hotelToEdit?.type || 'other',
|
||||
description: hotelToEdit?.description || '',
|
||||
rating: hotelToEdit?.rating || NaN,
|
||||
link: hotelToEdit?.link || '',
|
||||
|
@ -49,7 +61,7 @@
|
|||
longitude: hotelToEdit?.longitude || null,
|
||||
location: hotelToEdit?.location || '',
|
||||
is_public: hotelToEdit?.is_public || false,
|
||||
collection: hotelToEdit?.collection || '',
|
||||
collection: hotelToEdit?.collection || collection.id,
|
||||
created_at: hotelToEdit?.created_at || '',
|
||||
updated_at: hotelToEdit?.updated_at || ''
|
||||
};
|
||||
|
@ -63,8 +75,8 @@
|
|||
|
||||
// Handle rating change
|
||||
$: {
|
||||
if (!hotel.rating) {
|
||||
hotel.rating = NaN;
|
||||
if (!lodging.rating) {
|
||||
lodging.rating = NaN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,35 +100,37 @@
|
|||
async function handleSubmit(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (hotel.check_in && !hotel.check_out) {
|
||||
const checkInDate = new Date(hotel.check_in);
|
||||
if (lodging.check_in && !lodging.check_out) {
|
||||
const checkInDate = new Date(lodging.check_in);
|
||||
checkInDate.setDate(checkInDate.getDate() + 1);
|
||||
hotel.check_out = checkInDate.toISOString();
|
||||
lodging.check_out = checkInDate.toISOString();
|
||||
}
|
||||
|
||||
if (hotel.check_in && hotel.check_out && hotel.check_in > hotel.check_out) {
|
||||
if (lodging.check_in && lodging.check_out && lodging.check_in > lodging.check_out) {
|
||||
addToast('error', $t('adventures.start_before_end_error'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create or update hotel
|
||||
const url = hotel.id === '' ? '/api/hotels' : `/api/hotels/${hotel.id}`;
|
||||
const method = hotel.id === '' ? 'POST' : 'PATCH';
|
||||
const url = lodging.id === '' ? '/api/lodging' : `/api/lodging/${lodging.id}`;
|
||||
const method = lodging.id === '' ? 'POST' : 'PATCH';
|
||||
const res = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(hotel)
|
||||
body: JSON.stringify(lodging)
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.id) {
|
||||
hotel = data as Hotel;
|
||||
lodging = data as Lodging;
|
||||
const toastMessage =
|
||||
hotel.id === '' ? 'adventures.adventure_created' : 'adventures.adventure_updated';
|
||||
lodging.id === '' ? 'adventures.adventure_created' : 'adventures.adventure_updated';
|
||||
addToast('success', $t(toastMessage));
|
||||
dispatch('save', hotel);
|
||||
dispatch('save', lodging);
|
||||
} else {
|
||||
const errorMessage =
|
||||
hotel.id === '' ? 'adventures.adventure_create_error' : 'adventures.adventure_update_error';
|
||||
lodging.id === ''
|
||||
? 'adventures.adventure_create_error'
|
||||
: 'adventures.adventure_update_error';
|
||||
addToast('error', $t(errorMessage));
|
||||
}
|
||||
}
|
||||
|
@ -127,9 +141,7 @@
|
|||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<div class="modal-box w-11/12 max-w-3xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
||||
<h3 class="font-bold text-2xl">
|
||||
{hotelToEdit
|
||||
? $t('transportation.edit_transportation')
|
||||
: $t('transportation.new_transportation')}
|
||||
{lodgingToEdit ? $t('lodging.edit_lodging') : $t('lodging.new_lodging')}
|
||||
</h3>
|
||||
<div class="modal-action items-center">
|
||||
<form method="post" style="width: 100%;" on:submit={handleSubmit}>
|
||||
|
@ -149,7 +161,7 @@
|
|||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
bind:value={hotel.name}
|
||||
bind:value={lodging.name}
|
||||
class="input input-bordered w-full"
|
||||
required
|
||||
/>
|
||||
|
@ -157,7 +169,7 @@
|
|||
<!-- Description -->
|
||||
<div>
|
||||
<label for="description">{$t('adventures.description')}</label><br />
|
||||
<MarkdownEditor bind:text={hotel.description} editor_height={'h-32'} />
|
||||
<MarkdownEditor bind:text={lodging.description} editor_height={'h-32'} />
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div>
|
||||
|
@ -167,7 +179,7 @@
|
|||
min="0"
|
||||
max="5"
|
||||
hidden
|
||||
bind:value={hotel.rating}
|
||||
bind:value={lodging.rating}
|
||||
id="rating"
|
||||
name="rating"
|
||||
class="input input-bordered w-full max-w-xs mt-1"
|
||||
|
@ -177,48 +189,48 @@
|
|||
type="radio"
|
||||
name="rating-2"
|
||||
class="rating-hidden"
|
||||
checked={Number.isNaN(hotel.rating)}
|
||||
checked={Number.isNaN(lodging.rating)}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-2"
|
||||
class="mask mask-star-2 bg-orange-400"
|
||||
on:click={() => (hotel.rating = 1)}
|
||||
checked={hotel.rating === 1}
|
||||
on:click={() => (lodging.rating = 1)}
|
||||
checked={lodging.rating === 1}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-2"
|
||||
class="mask mask-star-2 bg-orange-400"
|
||||
on:click={() => (hotel.rating = 2)}
|
||||
checked={hotel.rating === 2}
|
||||
on:click={() => (lodging.rating = 2)}
|
||||
checked={lodging.rating === 2}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-2"
|
||||
class="mask mask-star-2 bg-orange-400"
|
||||
on:click={() => (hotel.rating = 3)}
|
||||
checked={hotel.rating === 3}
|
||||
on:click={() => (lodging.rating = 3)}
|
||||
checked={lodging.rating === 3}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-2"
|
||||
class="mask mask-star-2 bg-orange-400"
|
||||
on:click={() => (hotel.rating = 4)}
|
||||
checked={hotel.rating === 4}
|
||||
on:click={() => (lodging.rating = 4)}
|
||||
checked={lodging.rating === 4}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-2"
|
||||
class="mask mask-star-2 bg-orange-400"
|
||||
on:click={() => (hotel.rating = 5)}
|
||||
checked={hotel.rating === 5}
|
||||
on:click={() => (lodging.rating = 5)}
|
||||
checked={lodging.rating === 5}
|
||||
/>
|
||||
{#if hotel.rating}
|
||||
{#if lodging.rating}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-error ml-2"
|
||||
on:click={() => (hotel.rating = NaN)}
|
||||
on:click={() => (lodging.rating = NaN)}
|
||||
>
|
||||
{$t('adventures.remove')}
|
||||
</button>
|
||||
|
@ -232,7 +244,7 @@
|
|||
type="url"
|
||||
id="link"
|
||||
name="link"
|
||||
bind:value={hotel.link}
|
||||
bind:value={lodging.link}
|
||||
class="input input-bordered w-full"
|
||||
/>
|
||||
</div>
|
||||
|
@ -247,7 +259,7 @@
|
|||
<!-- Start Date -->
|
||||
<div>
|
||||
<label for="date">
|
||||
{$t('adventures.start_date')}
|
||||
{$t('lodging.check_in')}
|
||||
</label>
|
||||
|
||||
{#if collection && collection.start_date && collection.end_date}<label
|
||||
|
@ -268,7 +280,7 @@
|
|||
type="datetime-local"
|
||||
id="date"
|
||||
name="date"
|
||||
bind:value={hotel.check_in}
|
||||
bind:value={lodging.check_in}
|
||||
min={constrainDates ? fullStartDate : ''}
|
||||
max={constrainDates ? fullEndDate : ''}
|
||||
class="input input-bordered w-full max-w-xs mt-1"
|
||||
|
@ -276,19 +288,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- End Date -->
|
||||
{#if hotel.check_in}
|
||||
{#if lodging.check_out}
|
||||
<div>
|
||||
<label for="end_date">
|
||||
{$t('adventures.end_date')}
|
||||
{$t('lodging.check_out')}
|
||||
</label>
|
||||
<div>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="end_date"
|
||||
name="end_date"
|
||||
min={constrainDates ? hotel.check_in : ''}
|
||||
min={constrainDates ? lodging.check_in : ''}
|
||||
max={constrainDates ? fullEndDate : ''}
|
||||
bind:value={hotel.check_out}
|
||||
bind:value={lodging.check_out}
|
||||
class="input input-bordered w-full max-w-xs mt-1"
|
||||
/>
|
||||
</div>
|
||||
|
@ -298,7 +310,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Location Information -->
|
||||
<LocationDropdown bind:item={hotel} />
|
||||
<LocationDropdown bind:item={lodging} />
|
||||
|
||||
<!-- Form Actions -->
|
||||
<div class="mt-4">
|
Loading…
Add table
Add a link
Reference in a new issue