mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-25 15:59:38 +02:00
feat: Add location_name to ReverseGeocode type and implement location fetching in stats view
This commit is contained in:
parent
60b5bbb3c8
commit
b5d6788c11
21 changed files with 1048 additions and 901 deletions
|
@ -18,9 +18,7 @@
|
|||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
console.log(res);
|
||||
let data = await res.json();
|
||||
console.log('ACTIVITIES' + data.activities);
|
||||
if (data && data.activities) {
|
||||
allActivities = data.activities;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
let categories: Category[] = [];
|
||||
|
||||
export let initialLatLng: { lat: number; lng: number } | null = null; // Used to pass the location from the map selection to the modal
|
||||
|
||||
let fileInput: HTMLInputElement;
|
||||
let immichIntegration: boolean = false;
|
||||
|
||||
|
@ -87,7 +89,6 @@
|
|||
onMount(async () => {
|
||||
modal = document.getElementById('my_modal_1') as HTMLDialogElement;
|
||||
modal.showModal();
|
||||
console.log('open');
|
||||
});
|
||||
|
||||
let url: string = '';
|
||||
|
@ -142,14 +143,11 @@
|
|||
const input = event.target as HTMLInputElement;
|
||||
if (input.files && input.files.length) {
|
||||
selectedFile = input.files[0];
|
||||
console.log('Selected file:', selectedFile);
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadAttachment(event: Event) {
|
||||
event.preventDefault();
|
||||
console.log('UPLOAD');
|
||||
console.log(selectedFile);
|
||||
|
||||
if (!selectedFile) {
|
||||
console.error('No files selected');
|
||||
|
@ -157,23 +155,18 @@
|
|||
}
|
||||
|
||||
const file = selectedFile;
|
||||
console.log(file);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('adventure', adventure.id);
|
||||
formData.append('name', attachmentName);
|
||||
|
||||
console.log(formData);
|
||||
|
||||
try {
|
||||
const res = await fetch('/adventures?/attachment', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
|
||||
if (res.ok) {
|
||||
const newData = deserialize(await res.text()) as { data: Attachment };
|
||||
adventure.attachments = [...adventure.attachments, newData.data];
|
||||
|
@ -202,7 +195,6 @@
|
|||
if (res.status === 204) {
|
||||
images = images.filter((image) => image.id !== id);
|
||||
adventure.images = images;
|
||||
console.log(images);
|
||||
addToast('success', $t('adventures.image_removed_success'));
|
||||
} else {
|
||||
addToast('error', $t('adventures.image_removed_error'));
|
||||
|
@ -255,9 +247,7 @@
|
|||
});
|
||||
if (res.ok) {
|
||||
let newData = deserialize(await res.text()) as { data: { id: string; image: string } };
|
||||
console.log(newData);
|
||||
let newImage = { id: newData.data.id, image: newData.data.image, is_primary: false };
|
||||
console.log(newImage);
|
||||
images = [...images, newImage];
|
||||
adventure.images = images;
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
|
@ -308,9 +298,7 @@
|
|||
});
|
||||
if (res2.ok) {
|
||||
let newData = deserialize(await res2.text()) as { data: { id: string; image: string } };
|
||||
console.log(newData);
|
||||
let newImage = { id: newData.data.id, image: newData.data.image, is_primary: false };
|
||||
console.log(newImage);
|
||||
images = [...images, newImage];
|
||||
adventure.images = images;
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
|
@ -371,30 +359,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
function imageSubmit() {
|
||||
return async ({ result }: any) => {
|
||||
if (result.type === 'success') {
|
||||
if (result.data.id && result.data.image) {
|
||||
adventure.images = [...adventure.images, result.data];
|
||||
images = [...images, result.data];
|
||||
addToast('success', $t('adventures.image_upload_success'));
|
||||
|
||||
fileInput.value = '';
|
||||
console.log(adventure);
|
||||
} else {
|
||||
addToast('error', result.data.error || $t('adventures.image_upload_error'));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function handleSubmit(event: Event) {
|
||||
event.preventDefault();
|
||||
triggerMarkVisted = true;
|
||||
|
||||
console.log(adventure);
|
||||
if (adventure.id === '') {
|
||||
console.log(categories);
|
||||
if (adventure.category?.display_name == '') {
|
||||
if (categories.some((category) => category.name === 'general')) {
|
||||
adventure.category = categories.find(
|
||||
|
@ -597,7 +566,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<LocationDropdown bind:item={adventure} bind:triggerMarkVisted />
|
||||
<LocationDropdown bind:item={adventure} bind:triggerMarkVisted {initialLatLng} />
|
||||
|
||||
<div class="collapse collapse-plus bg-base-200 mb-4 overflow-visible">
|
||||
<input type="checkbox" />
|
||||
|
@ -958,7 +927,7 @@
|
|||
{/if}
|
||||
|
||||
{#if adventure.is_public && adventure.id}
|
||||
<div class="bg-neutral p-4 mt-2 rounded-md shadow-sm">
|
||||
<div class="bg-neutral p-4 mt-2 rounded-md shadow-sm text-neutral-content">
|
||||
<p class=" font-semibold">{$t('adventures.share_adventure')}</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="text-card-foreground font-mono">
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
<li><button on:click={() => goto('/adventures')}>{$t('navbar.my_adventures')}</button></li>
|
||||
<li><button on:click={() => goto('/shared')}>{$t('navbar.shared_with_me')}</button></li>
|
||||
<li><button on:click={() => goto('/settings')}>{$t('navbar.settings')}</button></li>
|
||||
{#if user.is_staff}
|
||||
<li><button on:click={() => goto('/admin')}>{$t('navbar.admin_panel')}</button></li>
|
||||
{/if}
|
||||
<form method="post">
|
||||
<li><button formaction="/?/logout">{$t('navbar.logout')}</button></li>
|
||||
</form>
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
import { appVersion } from '$lib/config';
|
||||
import { addToast } from '$lib/toasts';
|
||||
import type { Adventure, Lodging, OpenStreetMapPlace, Point, ReverseGeocode } from '$lib/types';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { DefaultMarker, MapEvents, MapLibre } from 'svelte-maplibre';
|
||||
|
||||
export let item: Adventure | Lodging;
|
||||
export let triggerMarkVisted: boolean = false;
|
||||
|
||||
export let initialLatLng: { lat: number; lng: number } | null = null; // Used to pass the location from the map selection to the modal
|
||||
|
||||
let reverseGeocodePlace: ReverseGeocode | null = null;
|
||||
let markers: Point[] = [];
|
||||
|
||||
|
@ -19,6 +22,22 @@
|
|||
let places: OpenStreetMapPlace[] = [];
|
||||
let noPlaces: boolean = false;
|
||||
|
||||
onMount(() => {
|
||||
if (initialLatLng) {
|
||||
markers = [
|
||||
{
|
||||
lngLat: { lng: initialLatLng.lng, lat: initialLatLng.lat },
|
||||
name: '',
|
||||
location: '',
|
||||
activity_type: ''
|
||||
}
|
||||
];
|
||||
item.latitude = initialLatLng.lat;
|
||||
item.longitude = initialLatLng.lng;
|
||||
reverseGeocode();
|
||||
}
|
||||
});
|
||||
|
||||
$: if (markers.length > 0) {
|
||||
const newLat = Math.round(markers[0].lngLat.lat * 1e6) / 1e6;
|
||||
const newLng = Math.round(markers[0].lngLat.lng * 1e6) / 1e6;
|
||||
|
@ -35,10 +54,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
console.log(triggerMarkVisted);
|
||||
}
|
||||
|
||||
$: if (triggerMarkVisted && willBeMarkedVisited) {
|
||||
markVisited();
|
||||
triggerMarkVisted = false;
|
||||
|
@ -84,8 +99,6 @@
|
|||
break; // Exit the loop since we've determined the result
|
||||
}
|
||||
}
|
||||
|
||||
console.log('WMBV:', willBeMarkedVisited);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +193,9 @@
|
|||
) {
|
||||
old_display_name = reverseGeocodePlace.display_name;
|
||||
item.location = reverseGeocodePlace.display_name;
|
||||
if (reverseGeocodePlace.location_name) {
|
||||
item.name = reverseGeocodePlace.location_name;
|
||||
}
|
||||
}
|
||||
console.log(data);
|
||||
}
|
||||
|
@ -187,6 +203,8 @@
|
|||
function clearMap() {
|
||||
console.log('CLEAR');
|
||||
markers = [];
|
||||
item.latitude = null;
|
||||
item.longitude = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -268,6 +286,8 @@
|
|||
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
|
||||
class="relative aspect-[9/16] max-h-[70vh] w-full sm:aspect-video sm:max-h-full rounded-lg"
|
||||
standardControls
|
||||
zoom={item.latitude && item.longitude ? 12 : 1}
|
||||
center={{ lng: item.longitude || 0, lat: item.latitude || 0 }}
|
||||
>
|
||||
<!-- MapEvents gives you access to map events even from other components inside the map,
|
||||
where you might not have access to the top-level `MapLibre` component. In this case
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
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();
|
||||
|
||||
|
@ -36,20 +35,6 @@
|
|||
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 &&
|
||||
|
@ -88,9 +73,9 @@
|
|||
|
||||
{#if isWarningModalOpen}
|
||||
<DeleteWarning
|
||||
title={$t('adventures.delete_transportation')}
|
||||
title={$t('adventures.delete_lodging')}
|
||||
button_text="Delete"
|
||||
description={$t('adventures.transportation_delete_confirm')}
|
||||
description={$t('adventures.lodging_delete_confirm')}
|
||||
is_warning={false}
|
||||
on:close={() => (isWarningModalOpen = false)}
|
||||
on:confirm={deleteTransportation}
|
||||
|
@ -106,7 +91,7 @@
|
|||
<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}
|
||||
{$t(`lodging.${lodging.type}`)}
|
||||
</div>
|
||||
<!-- {#if hotel.type == 'plane' && hotel.flight_number}
|
||||
<div class="badge badge-neutral-200">{hotel.flight_number}</div>
|
||||
|
@ -117,36 +102,35 @@
|
|||
<div class="badge badge-error">{$t('adventures.out_of_range')}</div>
|
||||
{/if}
|
||||
|
||||
<!-- Locations -->
|
||||
<!-- Location -->
|
||||
<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>
|
||||
<span class="font-medium text-sm">{$t('adventures.location')}:</span>
|
||||
<p>{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>
|
||||
<span class="font-medium text-sm">{$t('adventures.dates')}:</span>
|
||||
<p>
|
||||
{new Date(lodging.check_in).toLocaleString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
})}
|
||||
-
|
||||
{new Date(lodging.check_out).toLocaleString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -53,8 +53,8 @@
|
|||
description: hotelToEdit?.description || '',
|
||||
rating: hotelToEdit?.rating || NaN,
|
||||
link: hotelToEdit?.link || '',
|
||||
check_in: hotelToEdit?.check_in || null,
|
||||
check_out: hotelToEdit?.check_out || null,
|
||||
check_in: hotelToEdit?.check_in ? toLocalDatetime(hotelToEdit.check_in) : null,
|
||||
check_out: hotelToEdit?.check_out ? toLocalDatetime(hotelToEdit.check_out) : null,
|
||||
reservation_number: hotelToEdit?.reservation_number || '',
|
||||
price: hotelToEdit?.price || null,
|
||||
latitude: hotelToEdit?.latitude || null,
|
||||
|
@ -166,6 +166,32 @@
|
|||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="type">
|
||||
{$t('transportation.type')}<span class="text-red-500">*</span>
|
||||
</label>
|
||||
<div>
|
||||
<select
|
||||
class="select select-bordered w-full max-w-xs"
|
||||
name="type"
|
||||
id="type"
|
||||
bind:value={lodging.type}
|
||||
>
|
||||
<option disabled selected>{$t('transportation.type')}</option>
|
||||
<option value="hotel">{$t('lodging.hotel')}</option>
|
||||
<option value="hostel">{$t('lodging.hostel')}</option>
|
||||
<option value="resort">{$t('lodging.resort')}</option>
|
||||
<option value="bnb">{$t('lodging.bnb')}</option>
|
||||
<option value="campground">{$t('lodging.campground')}</option>
|
||||
<option value="cabin">{$t('lodging.cabin')}</option>
|
||||
<option value="apartment">{$t('lodging.apartment')}</option>
|
||||
<option value="house">{$t('lodging.house')}</option>
|
||||
<option value="villa">{$t('lodging.villa')}</option>
|
||||
<option value="motel">{$t('lodging.motel')}</option>
|
||||
<option value="other">{$t('lodging.other')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label for="description">{$t('adventures.description')}</label><br />
|
||||
|
@ -250,13 +276,53 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse collapse-plus bg-base-200 mb-4">
|
||||
<input type="checkbox" checked />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
{$t('adventures.lodging_information')}
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<!-- Reservation Number -->
|
||||
<div>
|
||||
<label for="date">
|
||||
{$t('lodging.reservation_number')}
|
||||
</label>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="reservation_number"
|
||||
name="reservation_number"
|
||||
bind:value={lodging.reservation_number}
|
||||
class="input input-bordered w-full max-w-xs mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Price -->
|
||||
<div>
|
||||
<label for="price">
|
||||
{$t('adventures.price')}
|
||||
</label>
|
||||
<div>
|
||||
<input
|
||||
type="number"
|
||||
id="price"
|
||||
name="price"
|
||||
bind:value={lodging.price}
|
||||
class="input input-bordered w-full max-w-xs mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse collapse-plus bg-base-200 mb-4">
|
||||
<input type="checkbox" checked />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
{$t('adventures.date_information')}
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<!-- Start Date -->
|
||||
<!-- Check In -->
|
||||
<div>
|
||||
<label for="date">
|
||||
{$t('lodging.check_in')}
|
||||
|
|
|
@ -243,6 +243,20 @@
|
|||
{$t('adventures.basic_information')}
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<label for="name">
|
||||
{$t('adventures.name')}<span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
bind:value={transportation.name}
|
||||
class="input input-bordered w-full"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- Type selection -->
|
||||
<div>
|
||||
<label for="type">
|
||||
|
@ -267,20 +281,6 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<label for="name">
|
||||
{$t('adventures.name')}<span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
bind:value={transportation.name}
|
||||
class="input input-bordered w-full"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label for="description">{$t('adventures.description')}</label><br />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue