1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-20 05:19:38 +02:00

Update map filtering

This commit is contained in:
Sean Morley 2024-10-04 09:49:35 -04:00
parent 5ff4f66fdb
commit d0791faad5
5 changed files with 56 additions and 26 deletions

View file

@ -19,7 +19,7 @@
import DotsHorizontal from '~icons/mdi/dots-horizontal'; import DotsHorizontal from '~icons/mdi/dots-horizontal';
import DeleteWarning from './DeleteWarning.svelte'; import DeleteWarning from './DeleteWarning.svelte';
import ImageDisplayModal from './ImageDisplayModal.svelte'; import ImageDisplayModal from './ImageDisplayModal.svelte';
import { typeToString } from '$lib'; import { isAdventureVisited, typeToString } from '$lib';
export let type: string; export let type: string;
export let user: User | null; export let user: User | null;
@ -28,7 +28,6 @@
let isCollectionModalOpen: boolean = false; let isCollectionModalOpen: boolean = false;
let isWarningModalOpen: boolean = false; let isWarningModalOpen: boolean = false;
let keyword: string = '';
let image_url: string | null = null; let image_url: string | null = null;
export let adventure: Adventure; export let adventure: Adventure;
@ -201,7 +200,7 @@
</div> </div>
<div> <div>
<div class="badge badge-primary">{typeToString(adventure.type)}</div> <div class="badge badge-primary">{typeToString(adventure.type)}</div>
<div class="badge badge-success">{adventure.visits.length > 0 ? 'Visited' : 'Planned'}</div> <div class="badge badge-success">{isAdventureVisited(adventure) ? 'Visited' : 'Planned'}</div>
<div class="badge badge-secondary">{adventure.is_public ? 'Public' : 'Private'}</div> <div class="badge badge-secondary">{adventure.is_public ? 'Public' : 'Private'}</div>
</div> </div>
{#if adventure.location && adventure.location !== ''} {#if adventure.location && adventure.location !== ''}

View file

@ -27,13 +27,12 @@
} }
</script> </script>
<div class="collapse collapse-plus bg-base-300 mb-4 overflow-visible"> <div class="collapse collapse-plus mb-4">
<input type="checkbox" /> <input type="checkbox" />
<div class="collapse-title text-xl font-medium">Category Filter</div> <div class="collapse-title text-xl bg-base-300 font-medium">Category Filter</div>
<div class="collapse-content"> <div class="collapse-content bg-base-300">
<button class="btn btn-wide mb-1 btn-neutral-300" on:click={clearTypes}>Clear</button> <button class="btn btn-wide btn-neutral-300" on:click={clearTypes}>Clear</button>
{#each ADVENTURE_TYPES as type} {#each ADVENTURE_TYPES as type}
<!-- checkbox for each -->
<li> <li>
<label class="cursor-pointer"> <label class="cursor-pointer">
<input <input

View file

@ -252,3 +252,22 @@ export function typeToString(type: string) {
return 'Unknown'; return 'Unknown';
} }
} }
/**
* Checks if an adventure has been visited.
*
* This function determines if the `adventure.visits` array contains at least one visit
* with a `start_date` that is before the current date.
*
* @param adventure - The adventure object to check.
* @returns `true` if the adventure has been visited, otherwise `false`.
*/
export function isAdventureVisited(adventure: Adventure) {
const currentTime = Date.now();
// Check if any visit's start_date is before the current time.
return adventure.visits.some((visit) => {
const visitStartTime = new Date(visit.start_date).getTime();
return visit.start_date && visitStartTime <= currentTime;
});
}

View file

@ -8,7 +8,7 @@ export const load = (async (event) => {
if (!event.locals.user) { if (!event.locals.user) {
return redirect(302, '/login'); return redirect(302, '/login');
} else { } else {
let visitedFetch = await fetch(`${endpoint}/api/adventures/all/`, { let visitedFetch = await fetch(`${endpoint}/api/adventures/`, {
headers: { headers: {
Cookie: `${event.cookies.get('auth')}` Cookie: `${event.cookies.get('auth')}`
} }
@ -25,16 +25,26 @@ export const load = (async (event) => {
console.error('Failed to fetch visited adventures'); console.error('Failed to fetch visited adventures');
return redirect(302, '/login'); return redirect(302, '/login');
} else { } else {
let visited = (await visitedFetch.json()) as Adventure[]; let visited: Adventure[] = [];
try {
let api_result = await visitedFetch.json();
visited = api_result.results as Adventure[];
if (!Array.isArray(visited) || visited.length === 0 || !visited) {
throw new Error('Visited adventures response is not an array');
}
} catch (error) {
console.error('Error parsing visited adventures:', error);
return redirect(302, '/login');
}
// make a long lat array like this { lngLat: [-20, 0], name: 'Adventure 1' }, // make a long lat array like this { lngLat: [-20, 0], name: 'Adventure 1' },
let markers = visited let markers = visited
.filter((adventure) => adventure.latitude !== null && adventure.longitude !== null) .filter((adventure) => adventure.latitude !== null && adventure.longitude !== null)
.map((adventure) => { .map((adventure) => {
return { return {
lngLat: [adventure.longitude, adventure.latitude] as [number, number], lngLat: [adventure.longitude, adventure.latitude],
name: adventure.name, name: adventure.name,
type: adventure.type, visits: adventure.visits
collection: adventure.collection
}; };
}); });

View file

@ -1,5 +1,7 @@
<script> <script>
// @ts-nocheck // @ts-nocheck
import { isAdventureVisited } from '$lib';
import AdventureModal from '$lib/components/AdventureModal.svelte'; import AdventureModal from '$lib/components/AdventureModal.svelte';
import { import {
DefaultMarker, DefaultMarker,
@ -16,12 +18,14 @@
let clickedName = ''; let clickedName = '';
console.log(data);
let showVisited = true; let showVisited = true;
let showPlanned = true; let showPlanned = true;
$: filteredMarkers = markers.filter( $: filteredMarkers = markers.filter(
(marker) => (marker) =>
(showVisited && marker.type === 'visited') || (showPlanned && marker.type === 'planned') (showVisited && isAdventureVisited(marker)) || (showPlanned && !isAdventureVisited(marker))
); );
let newMarker = []; let newMarker = [];
@ -46,7 +50,8 @@
let newMarker = { let newMarker = {
lngLat: [event.detail.longitude, event.detail.latitude], lngLat: [event.detail.longitude, event.detail.latitude],
name: event.detail.name, name: event.detail.name,
type: event.detail.type type: event.detail.type,
visits: event.detail.visits
}; };
markers = [...markers, newMarker]; markers = [...markers, newMarker];
clearMarkers(); clearMarkers();
@ -138,11 +143,11 @@
class="relative aspect-[9/16] max-h-[70vh] w-full sm:aspect-video sm:max-h-full" class="relative aspect-[9/16] max-h-[70vh] w-full sm:aspect-video sm:max-h-full"
standardControls standardControls
> >
{#each filteredMarkers as { lngLat, name, type }} {#each filteredMarkers as marker}
{#if type == 'visited'} {#if isAdventureVisited(marker)}
<Marker <Marker
{lngLat} lngLat={marker.lngLat}
on:click={() => (clickedName = name)} on:click={() => (clickedName = marker.name)}
class="grid h-8 w-8 place-items-center rounded-full border border-gray-200 bg-red-300 text-black shadow-md" class="grid h-8 w-8 place-items-center rounded-full border border-gray-200 bg-red-300 text-black shadow-md"
> >
<svg <svg
@ -155,16 +160,14 @@
<circle cx="12" cy="12" r="10" stroke="red" stroke-width="2" fill="red" /> <circle cx="12" cy="12" r="10" stroke="red" stroke-width="2" fill="red" />
</svg> </svg>
<Popup openOn="click" offset={[0, -10]}> <Popup openOn="click" offset={[0, -10]}>
<div class="text-lg text-black font-bold">{name}</div> <div class="text-lg text-black font-bold">{marker.name}</div>
<p class="font-semibold text-black text-md">Visited</p> <p class="font-semibold text-black text-md">Visited</p>
</Popup> </Popup>
</Marker> </Marker>
{/if} {:else}
{#if type == 'planned'}
<Marker <Marker
{lngLat} lngLat={marker.lngLat}
on:click={() => (clickedName = name)} on:click={() => (clickedName = marker.name)}
class="grid h-8 w-8 place-items-center rounded-full border border-gray-200 bg-blue-300 text-black shadow-2xl focus:outline-2 focus:outline-black" class="grid h-8 w-8 place-items-center rounded-full border border-gray-200 bg-blue-300 text-black shadow-2xl focus:outline-2 focus:outline-black"
> >
<svg <svg
@ -177,7 +180,7 @@
<circle cx="12" cy="12" r="10" stroke="blue" stroke-width="2" fill="blue" /> <circle cx="12" cy="12" r="10" stroke="blue" stroke-width="2" fill="blue" />
</svg> </svg>
<Popup openOn="click" offset={[0, -10]}> <Popup openOn="click" offset={[0, -10]}>
<div class="text-lg text-black font-bold">{name}</div> <div class="text-lg text-black font-bold">{marker.name}</div>
<p class="font-semibold text-black text-md">Planned</p> <p class="font-semibold text-black text-md">Planned</p>
</Popup> </Popup>
</Marker> </Marker>