1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-08-08 14:45:17 +02:00

feat: integrate NewLocationModal across various components; update location handling and state management

This commit is contained in:
Sean Morley 2025-08-06 20:17:17 -04:00
parent 2da568dcc1
commit b7b7f9d26d
6 changed files with 107 additions and 65 deletions

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'; import { createEventDispatcher, onMount } from 'svelte';
import type { Location, User } from '$lib/types'; import type { Collection, Location, User } from '$lib/types';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import LocationQuickStart from './locations/LocationQuickStart.svelte'; import LocationQuickStart from './locations/LocationQuickStart.svelte';
import LocationDetails from './locations/LocationDetails.svelte'; import LocationDetails from './locations/LocationDetails.svelte';
import LocationMedia from './locations/LocationMedia.svelte'; import LocationMedia from './locations/LocationMedia.svelte';
import LocationVisits from './locations/LocationVisits.svelte'; import LocationVisits from './locations/LocationVisits.svelte';
export let user: User | null = null; export let user: User | null = null;
export let collection: Collection | null = null;
export let initialLatLng: { lat: number; lng: number } | null = null; // Used to pass the location from the map selection to the modal
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -96,6 +99,12 @@
steps[0].selected = false; steps[0].selected = false;
steps[1].selected = true; steps[1].selected = true;
} }
if (initialLatLng) {
location.latitude = initialLatLng.lat;
location.longitude = initialLatLng.lng;
steps[1].selected = true;
steps[0].selected = false;
}
}); });
function close() { function close() {
@ -296,6 +305,7 @@
}} }}
on:close={() => close()} on:close={() => close()}
measurementSystem={user?.measurement_system || 'metric'} measurementSystem={user?.measurement_system || 'metric'}
{collection}
/> />
{/if} {/if}
</div> </div>

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'; import { createEventDispatcher, onMount } from 'svelte';
import { MapLibre, Marker, MapEvents } from 'svelte-maplibre'; import { MapLibre, Marker, MapEvents } from 'svelte-maplibre';
import { t } from 'svelte-i18n'; import { number, t } from 'svelte-i18n';
import { getBasemapUrl } from '$lib'; import { getBasemapUrl } from '$lib';
import CategoryDropdown from '../CategoryDropdown.svelte'; import CategoryDropdown from '../CategoryDropdown.svelte';
import type { Collection, Location } from '$lib/types'; import type { Collection, Location } from '$lib/types';
@ -210,6 +210,7 @@
async function performDetailedReverseGeocode(lat: number, lng: number) { async function performDetailedReverseGeocode(lat: number, lng: number) {
try { try {
console.log('Performing detailed reverse geocoding for:', lat, lng);
const response = await fetch( const response = await fetch(
`/api/reverse-geocode/reverse_geocode/?lat=${lat}&lon=${lng}&format=json` `/api/reverse-geocode/reverse_geocode/?lat=${lat}&lon=${lng}&format=json`
); );
@ -349,6 +350,33 @@
dispatch('back'); dispatch('back');
} }
onMount(async () => {
if (initialLocation.latitude && initialLocation.longitude) {
selectedMarker = {
lng: initialLocation.longitude,
lat: initialLocation.latitude
};
location.latitude = initialLocation.latitude;
location.longitude = initialLocation.longitude;
mapCenter = [initialLocation.longitude, initialLocation.latitude];
mapZoom = 14;
selectedLocation = {
name: initialLocation.name || '',
lat: initialLocation.latitude,
lng: initialLocation.longitude,
location: initialLocation.location || '',
type: 'point',
category: initialLocation.category || null
};
selectedMarker = {
lng: Number(initialLocation.longitude),
lat: Number(initialLocation.latitude)
};
// trigger reverse geocoding to populate location data
await performDetailedReverseGeocode(initialLocation.latitude, initialLocation.longitude);
}
});
onMount(() => { onMount(() => {
if (initialLocation && typeof initialLocation === 'object') { if (initialLocation && typeof initialLocation === 'object') {
// Only update location properties if they don't already have values // Only update location properties if they don't already have values
@ -366,17 +394,6 @@
} }
} }
if (initialLocation.latitude && initialLocation.longitude) {
selectedMarker = {
lng: initialLocation.longitude,
lat: initialLocation.latitude
};
location.latitude = initialLocation.latitude;
location.longitude = initialLocation.longitude;
mapCenter = [initialLocation.longitude, initialLocation.latitude];
mapZoom = 14;
}
if (initialLocation.tags && Array.isArray(initialLocation.tags)) { if (initialLocation.tags && Array.isArray(initialLocation.tags)) {
location.tags = initialLocation.tags; location.tags = initialLocation.tags;
} }
@ -397,7 +414,7 @@
}); });
</script> </script>
<div class="min-h-screen bg-gradient-to-br from-base-200/30 via-base-100 to-primary/5 pl-6 pr-6"> <div class="min-h-screen bg-gradient-to-br from-base-200/30 via-base-100 to-primary/5 p-6">
<div class="max-w-full mx-auto space-y-6"> <div class="max-w-full mx-auto space-y-6">
<!-- Basic Information Section --> <!-- Basic Information Section -->
<div class="card bg-base-100 border border-base-300 shadow-lg"> <div class="card bg-base-100 border border-base-300 shadow-lg">
@ -454,7 +471,7 @@
<!-- Rating Field --> <!-- Rating Field -->
<div class="form-control"> <div class="form-control">
<label class="label"> <label class="label" for="rating">
<span class="label-text font-medium">Rating</span> <span class="label-text font-medium">Rating</span>
</label> </label>
<div <div
@ -464,6 +481,7 @@
<input <input
type="radio" type="radio"
name="rating" name="rating"
id="rating"
class="rating-hidden" class="rating-hidden"
checked={Number.isNaN(location.rating)} checked={Number.isNaN(location.rating)}
/> />
@ -615,7 +633,7 @@
<!-- Search Input --> <!-- Search Input -->
<div class="form-control"> <div class="form-control">
<label class="label"> <label class="label" for="search-location">
<span class="label-text font-medium">Search Location</span> <span class="label-text font-medium">Search Location</span>
</label> </label>
<div class="relative"> <div class="relative">
@ -624,6 +642,7 @@
</div> </div>
<input <input
type="text" type="text"
id="search-location"
bind:value={searchQuery} bind:value={searchQuery}
on:input={handleSearchInput} on:input={handleSearchInput}
placeholder="Enter city, location, or landmark..." placeholder="Enter city, location, or landmark..."
@ -649,9 +668,9 @@
</div> </div>
{:else if searchResults.length > 0} {:else if searchResults.length > 0}
<div class="space-y-2"> <div class="space-y-2">
<label class="label"> <div class="label">
<span class="label-text text-sm font-medium">Search Results</span> <span class="label-text text-sm font-medium">Search Results</span>
</label> </div>
<div class="max-h-48 overflow-y-auto space-y-1"> <div class="max-h-48 overflow-y-auto space-y-1">
{#each searchResults as result} {#each searchResults as result}
<button <button
@ -732,9 +751,9 @@
<!-- Map --> <!-- Map -->
<div class="space-y-4"> <div class="space-y-4">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<label class="label"> <div class="label">
<span class="label-text font-medium">Interactive Map</span> <span class="label-text font-medium">Interactive Map</span>
</label> </div>
{#if isReverseGeocoding} {#if isReverseGeocoding}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="loading loading-spinner loading-sm"></span> <span class="loading loading-spinner loading-sm"></span>

View file

@ -39,13 +39,13 @@
import ChecklistCard from '$lib/components/ChecklistCard.svelte'; import ChecklistCard from '$lib/components/ChecklistCard.svelte';
import ChecklistModal from '$lib/components/ChecklistModal.svelte'; import ChecklistModal from '$lib/components/ChecklistModal.svelte';
import LocationModal from '$lib/components/LocationModal.svelte';
import TransportationModal from '$lib/components/TransportationModal.svelte'; import TransportationModal from '$lib/components/TransportationModal.svelte';
import CardCarousel from '$lib/components/CardCarousel.svelte'; import CardCarousel from '$lib/components/CardCarousel.svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import LodgingModal from '$lib/components/LodgingModal.svelte'; import LodgingModal from '$lib/components/LodgingModal.svelte';
import LodgingCard from '$lib/components/LodgingCard.svelte'; import LodgingCard from '$lib/components/LodgingCard.svelte';
import CollectionAllView from '$lib/components/CollectionAllView.svelte'; import CollectionAllView from '$lib/components/CollectionAllView.svelte';
import NewLocationModal from '$lib/components/NewLocationModal.svelte';
export let data: PageData; export let data: PageData;
console.log(data); console.log(data);
@ -530,7 +530,24 @@
let noteToEdit: Note | null; let noteToEdit: Note | null;
let checklistToEdit: Checklist | null; let checklistToEdit: Checklist | null;
let newType: string; let locationBeingUpdated: Location | undefined = undefined;
// Sync the locationBeingUpdated with the adventures array
$: {
if (locationBeingUpdated && locationBeingUpdated.id) {
const index = adventures.findIndex((adventure) => adventure.id === locationBeingUpdated?.id);
if (index !== -1) {
adventures[index] = { ...locationBeingUpdated };
adventures = adventures; // Trigger reactivity
} else {
adventures = [{ ...locationBeingUpdated }, ...adventures];
if (data.props.adventure) {
data.props.adventure.locations = adventures; // Update data.props.adventure.locations as well
}
}
}
}
function editAdventure(event: CustomEvent<Location>) { function editAdventure(event: CustomEvent<Location>) {
adventureToEdit = event.detail; adventureToEdit = event.detail;
@ -690,12 +707,13 @@
{/if} {/if}
{#if isLocationModalOpen} {#if isLocationModalOpen}
<LocationModal <NewLocationModal
locationToEdit={adventureToEdit}
on:close={() => (isLocationModalOpen = false)} on:close={() => (isLocationModalOpen = false)}
on:save={saveOrCreateAdventure} on:save={saveOrCreateAdventure}
{collection}
user={data.user} user={data.user}
locationToEdit={adventureToEdit}
bind:location={locationBeingUpdated}
{collection}
/> />
{/if} {/if}
@ -790,7 +808,6 @@
// Reset the transportation object for creating a new one // Reset the transportation object for creating a new one
transportationToEdit = null; transportationToEdit = null;
isShowingTransportationModal = true; isShowingTransportationModal = true;
newType = '';
}} }}
> >
{$t('adventures.transportation')}</button {$t('adventures.transportation')}</button
@ -799,7 +816,7 @@
class="btn btn-primary" class="btn btn-primary"
on:click={() => { on:click={() => {
isNoteModalOpen = true; isNoteModalOpen = true;
newType = '';
noteToEdit = null; noteToEdit = null;
}} }}
> >
@ -809,7 +826,7 @@
class="btn btn-primary" class="btn btn-primary"
on:click={() => { on:click={() => {
isShowingChecklistModal = true; isShowingChecklistModal = true;
newType = '';
checklistToEdit = null; checklistToEdit = null;
}} }}
> >
@ -819,7 +836,7 @@
class="btn btn-primary" class="btn btn-primary"
on:click={() => { on:click={() => {
isShowingLodgingModal = true; isShowingLodgingModal = true;
newType = '';
lodgingToEdit = null; lodgingToEdit = null;
}} }}
> >

View file

@ -1,13 +1,10 @@
<script lang="ts"> <script lang="ts">
import { enhance, deserialize } from '$app/forms';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import LocationCard from '$lib/components/LocationCard.svelte'; import LocationCard from '$lib/components/LocationCard.svelte';
import LocationModal from '$lib/components/LocationModal.svelte';
import CategoryFilterDropdown from '$lib/components/CategoryFilterDropdown.svelte'; import CategoryFilterDropdown from '$lib/components/CategoryFilterDropdown.svelte';
import CategoryModal from '$lib/components/CategoryModal.svelte'; import CategoryModal from '$lib/components/CategoryModal.svelte';
import NotFound from '$lib/components/NotFound.svelte'; import type { Location } from '$lib/types';
import type { Location, Category } from '$lib/types';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import Plus from '~icons/mdi/plus'; import Plus from '~icons/mdi/plus';
@ -15,9 +12,7 @@
import Sort from '~icons/mdi/sort'; import Sort from '~icons/mdi/sort';
import MapMarker from '~icons/mdi/map-marker'; import MapMarker from '~icons/mdi/map-marker';
import Eye from '~icons/mdi/eye'; import Eye from '~icons/mdi/eye';
import EyeOff from '~icons/mdi/eye-off';
import Calendar from '~icons/mdi/calendar'; import Calendar from '~icons/mdi/calendar';
import Star from '~icons/mdi/star';
import Tag from '~icons/mdi/tag'; import Tag from '~icons/mdi/tag';
import Compass from '~icons/mdi/compass'; import Compass from '~icons/mdi/compass';
import NewLocationModal from '$lib/components/NewLocationModal.svelte'; import NewLocationModal from '$lib/components/NewLocationModal.svelte';
@ -40,10 +35,14 @@
// Sync the locationBeingUpdated with the adventures array // Sync the locationBeingUpdated with the adventures array
$: { $: {
if (locationBeingUpdated && locationBeingUpdated.id) { if (locationBeingUpdated && locationBeingUpdated.id) {
const index = adventures.findIndex((adventure) => adventure.id === locationBeingUpdated!.id); const index = adventures.findIndex((adventure) => adventure.id === locationBeingUpdated?.id);
if (index !== -1) { if (index !== -1) {
adventures[index] = { ...locationBeingUpdated }; adventures[index] = { ...locationBeingUpdated };
adventures = adventures; // Trigger reactivity adventures = adventures; // Trigger reactivity
} else {
adventures = [{ ...locationBeingUpdated }, ...adventures];
data.props.adventures = adventures; // Update data.props.adventures as well
} }
} }
} }
@ -144,19 +143,6 @@
adventures = adventures.filter((adventure) => adventure.id !== event.detail); adventures = adventures.filter((adventure) => adventure.id !== event.detail);
} }
function saveOrCreate(event: CustomEvent<Location>) {
if (adventures.find((adventure) => adventure.id === event.detail.id)) {
adventures = adventures.map((adventure) => {
if (adventure.id === event.detail.id) {
return event.detail;
}
return adventure;
});
} else {
adventures = [event.detail, ...adventures];
}
}
function editAdventure(event: CustomEvent<Location>) { function editAdventure(event: CustomEvent<Location>) {
adventureToEdit = event.detail; adventureToEdit = event.detail;
isLocationModalOpen = true; isLocationModalOpen = true;
@ -181,15 +167,8 @@
</svelte:head> </svelte:head>
{#if isLocationModalOpen} {#if isLocationModalOpen}
<!-- <LocationModal
locationToEdit={adventureToEdit}
on:close={() => (isLocationModalOpen = false)}
on:save={saveOrCreate}
user={data.user}
/> -->
<NewLocationModal <NewLocationModal
on:close={() => (isLocationModalOpen = false)} on:close={() => (isLocationModalOpen = false)}
on:save={saveOrCreate}
user={data.user} user={data.user}
locationToEdit={adventureToEdit} locationToEdit={adventureToEdit}
bind:location={locationBeingUpdated} bind:location={locationBeingUpdated}

View file

@ -16,12 +16,12 @@
import LightbulbOn from '~icons/mdi/lightbulb-on'; import LightbulbOn from '~icons/mdi/lightbulb-on';
import WeatherSunset from '~icons/mdi/weather-sunset'; import WeatherSunset from '~icons/mdi/weather-sunset';
import ClipboardList from '~icons/mdi/clipboard-list'; import ClipboardList from '~icons/mdi/clipboard-list';
import LocationModal from '$lib/components/LocationModal.svelte';
import ImageDisplayModal from '$lib/components/ImageDisplayModal.svelte'; import ImageDisplayModal from '$lib/components/ImageDisplayModal.svelte';
import AttachmentCard from '$lib/components/AttachmentCard.svelte'; import AttachmentCard from '$lib/components/AttachmentCard.svelte';
import { getBasemapUrl, isAllDay } from '$lib'; import { getBasemapUrl, isAllDay } from '$lib';
import ActivityCard from '$lib/components/ActivityCard.svelte'; import ActivityCard from '$lib/components/ActivityCard.svelte';
import TrailCard from '$lib/components/TrailCard.svelte'; import TrailCard from '$lib/components/TrailCard.svelte';
import NewLocationModal from '$lib/components/NewLocationModal.svelte';
let geojson: any; let geojson: any;
@ -241,11 +241,11 @@
{/if} {/if}
{#if isEditModalOpen} {#if isEditModalOpen}
<LocationModal <NewLocationModal
locationToEdit={adventure}
on:close={() => (isEditModalOpen = false)} on:close={() => (isEditModalOpen = false)}
on:save={saveEdit}
user={data.user} user={data.user}
locationToEdit={adventure}
bind:location={adventure}
/> />
{/if} {/if}

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import LocationModal from '$lib/components/LocationModal.svelte';
import { DefaultMarker, MapEvents, MapLibre, Popup, Marker } from 'svelte-maplibre'; import { DefaultMarker, MapEvents, MapLibre, Popup, Marker } from 'svelte-maplibre';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import type { Location, VisitedRegion } from '$lib/types.js'; import type { Location, VisitedRegion } from '$lib/types.js';
@ -13,11 +12,10 @@
import Plus from '~icons/mdi/plus'; import Plus from '~icons/mdi/plus';
import Clear from '~icons/mdi/close'; import Clear from '~icons/mdi/close';
import Eye from '~icons/mdi/eye'; import Eye from '~icons/mdi/eye';
import EyeOff from '~icons/mdi/eye-off';
import Pin from '~icons/mdi/map-marker'; import Pin from '~icons/mdi/map-marker';
import Calendar from '~icons/mdi/calendar'; import Calendar from '~icons/mdi/calendar';
import Category from '~icons/mdi/shape';
import LocationIcon from '~icons/mdi/crosshairs-gps'; import LocationIcon from '~icons/mdi/crosshairs-gps';
import NewLocationModal from '$lib/components/NewLocationModal.svelte';
export let data; export let data;
@ -39,7 +37,6 @@
let newLongitude: number | null = null; let newLongitude: number | null = null;
let newLatitude: number | null = null; let newLatitude: number | null = null;
let openPopupId: string | null = null;
let isPopupOpen = false; let isPopupOpen = false;
// Statistics // Statistics
@ -68,6 +65,25 @@
} }
} }
let locationBeingUpdated: Location | undefined = undefined;
// Sync the locationBeingUpdated with the adventures array
$: {
if (locationBeingUpdated && locationBeingUpdated.id) {
const index = adventures.findIndex((adventure) => adventure.id === locationBeingUpdated?.id);
if (index !== -1) {
adventures[index] = { ...locationBeingUpdated };
adventures = adventures; // Trigger reactivity
} else {
adventures = [{ ...locationBeingUpdated }, ...adventures];
if (data.props.adventures) {
data.props.adventures = adventures; // Update data.props.adventure.locations as well
}
}
}
}
function addMarker(e: { detail: { lngLat: { lng: any; lat: any } } }) { function addMarker(e: { detail: { lngLat: { lng: any; lat: any } } }) {
newMarker = null; newMarker = null;
newMarker = { lngLat: e.detail.lngLat }; newMarker = { lngLat: e.detail.lngLat };
@ -461,11 +477,12 @@
</div> </div>
{#if createModalOpen} {#if createModalOpen}
<LocationModal <NewLocationModal
on:close={() => (createModalOpen = false)} on:close={() => (createModalOpen = false)}
on:save={createNewAdventure} on:save={createNewAdventure}
{initialLatLng} {initialLatLng}
user={data.user} user={data.user}
bind:location={locationBeingUpdated}
/> />
{/if} {/if}