1
0
Fork 0
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:
Sean Morley 2025-02-15 19:44:11 -05:00
parent 60b5bbb3c8
commit b5d6788c11
21 changed files with 1048 additions and 901 deletions

View file

@ -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;
}

View file

@ -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">

View file

@ -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>

View file

@ -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

View file

@ -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>

View file

@ -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')}

View file

@ -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 />