mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-02 19:55:18 +02:00
fix: update RegionCard component to handle undefined visited state and refactor global search API to return structured results
This commit is contained in:
parent
d60945d5b7
commit
f10e171a8e
4 changed files with 129 additions and 224 deletions
|
@ -7,7 +7,7 @@
|
|||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let region: Region;
|
||||
export let visited: boolean;
|
||||
export let visited: boolean | undefined;
|
||||
|
||||
function goToCity() {
|
||||
console.log(region);
|
||||
|
@ -64,12 +64,12 @@
|
|||
</div>
|
||||
<div class="card-actions justify-end">
|
||||
<!-- <button class="btn btn-info" on:click={moreInfo}>More Info</button> -->
|
||||
{#if !visited}
|
||||
{#if !visited && visited !== undefined}
|
||||
<button class="btn btn-primary" on:click={markVisited}
|
||||
>{$t('adventures.mark_visited')}</button
|
||||
>
|
||||
{/if}
|
||||
{#if visited}
|
||||
{#if visited && visited !== undefined}
|
||||
<button class="btn btn-warning" on:click={removeVisit}>{$t('adventures.remove')}</button>
|
||||
{/if}
|
||||
{#if region.num_cities > 0}
|
||||
|
|
|
@ -8,7 +8,6 @@ const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
|||
|
||||
export const load = (async (event) => {
|
||||
const query = event.url.searchParams.get('query');
|
||||
const property = event.url.searchParams.get('property') || 'all';
|
||||
|
||||
if (!query) {
|
||||
return { data: [] };
|
||||
|
@ -16,15 +15,12 @@ export const load = (async (event) => {
|
|||
|
||||
let sessionId = event.cookies.get('sessionid');
|
||||
|
||||
let res = await fetch(
|
||||
`${serverEndpoint}/api/adventures/search/?query=${query}&property=${property}`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: `sessionid=${sessionId}`
|
||||
}
|
||||
let res = await fetch(`${serverEndpoint}/api/search/?query=${query}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: `sessionid=${sessionId}`
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
console.error('Failed to fetch search data');
|
||||
|
@ -32,27 +28,16 @@ export const load = (async (event) => {
|
|||
return { error: error.error };
|
||||
}
|
||||
|
||||
let adventures: Adventure[] = await res.json();
|
||||
|
||||
let osmRes = await fetch(`https://nominatim.openstreetmap.org/search?q=${query}&format=jsonv2`, {
|
||||
headers: {
|
||||
'User-Agent': `AdventureLog / ${appVersion} `
|
||||
}
|
||||
});
|
||||
|
||||
if (!osmRes.ok) {
|
||||
console.error('Failed to fetch OSM data');
|
||||
let error = await res.json();
|
||||
return { error: error.error };
|
||||
}
|
||||
|
||||
let osmData = (await osmRes.json()) as OpenStreetMapPlace[];
|
||||
let data = await res.json();
|
||||
|
||||
return {
|
||||
props: {
|
||||
adventures,
|
||||
query,
|
||||
osmData
|
||||
}
|
||||
adventures: data.adventures,
|
||||
collections: data.collections,
|
||||
users: data.users,
|
||||
countries: data.countries,
|
||||
regions: data.regions,
|
||||
cities: data.cities,
|
||||
visited_cities: data.visited_cities,
|
||||
visited_regions: data.visited_regions
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
|
|
@ -1,184 +1,102 @@
|
|||
<script lang="ts">
|
||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
||||
import NotFound from '$lib/components/NotFound.svelte';
|
||||
import type { Adventure, OpenStreetMapPlace } from '$lib/types';
|
||||
import { onMount } from 'svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { goto } from '$app/navigation';
|
||||
import AdventureModal from '$lib/components/AdventureModal.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
import RegionCard from '$lib/components/RegionCard.svelte';
|
||||
import CityCard from '$lib/components/CityCard.svelte';
|
||||
import CountryCard from '$lib/components/CountryCard.svelte';
|
||||
import CollectionCard from '$lib/components/CollectionCard.svelte';
|
||||
import UserCard from '$lib/components/UserCard.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
function deleteAdventure(event: CustomEvent<string>) {
|
||||
myAdventures = myAdventures.filter((adventure) => adventure.id !== event.detail);
|
||||
}
|
||||
let adventures = data.adventures;
|
||||
let collections = data.collections;
|
||||
let users = data.users;
|
||||
let countries = data.countries;
|
||||
let regions = data.regions;
|
||||
let cities = data.cities;
|
||||
|
||||
let osmResults: OpenStreetMapPlace[] = [];
|
||||
let myAdventures: Adventure[] = [];
|
||||
let publicAdventures: Adventure[] = [];
|
||||
let visited_regions: { region: any }[] = data.visited_regions;
|
||||
let visited_cities: { city: any }[] = data.visited_cities;
|
||||
|
||||
let query: string | null = '';
|
||||
let property: string = 'all';
|
||||
|
||||
// on chage of property, console log the property
|
||||
|
||||
function filterByProperty() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.set('property', property);
|
||||
goto(url.toString(), { invalidateAll: true });
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
query = urlParams.get('query');
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
$: {
|
||||
if (data.props) {
|
||||
myAdventures = data.props.adventures;
|
||||
publicAdventures = data.props.adventures;
|
||||
|
||||
if (data.user?.uuid != null) {
|
||||
myAdventures = myAdventures.filter((adventure) => adventure.user_id === data.user?.uuid);
|
||||
} else {
|
||||
myAdventures = [];
|
||||
}
|
||||
|
||||
publicAdventures = publicAdventures.filter(
|
||||
(adventure) => adventure.user_id !== data.user?.uuid
|
||||
);
|
||||
|
||||
if (data.props.osmData) {
|
||||
osmResults = data.props.osmData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let adventureToEdit: Adventure;
|
||||
let isAdventureModalOpen: boolean = false;
|
||||
|
||||
function editAdventure(event: CustomEvent<Adventure>) {
|
||||
adventureToEdit = event.detail;
|
||||
isAdventureModalOpen = true;
|
||||
}
|
||||
|
||||
function saveEdit(event: CustomEvent<Adventure>) {
|
||||
console.log(event.detail);
|
||||
myAdventures = myAdventures.map((adventure) => {
|
||||
if (adventure.id === event.detail.id) {
|
||||
return event.detail;
|
||||
}
|
||||
return adventure;
|
||||
});
|
||||
isAdventureModalOpen = false;
|
||||
console.log(myAdventures);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isAdventureModalOpen}
|
||||
<AdventureModal
|
||||
{adventureToEdit}
|
||||
on:close={() => (isAdventureModalOpen = false)}
|
||||
on:save={filterByProperty}
|
||||
/>
|
||||
{/if}
|
||||
<h1 class="text-4xl font-bold text-center m-4">Search{query ? `: ${query}` : ''}</h1>
|
||||
|
||||
{#if myAdventures.length === 0 && osmResults.length === 0}
|
||||
<NotFound error={data.error} />
|
||||
{/if}
|
||||
|
||||
{#if myAdventures.length !== 0}
|
||||
<h2 class="text-center font-bold text-2xl mb-4">{$t('search.adventurelog_results')}</h2>
|
||||
<div class="flex items-center justify-center mt-2 mb-2">
|
||||
<div class="join">
|
||||
<input
|
||||
class="join-item btn"
|
||||
type="radio"
|
||||
name="filter"
|
||||
aria-label={$t('adventures.all')}
|
||||
id="all"
|
||||
checked
|
||||
on:change={() => (property = 'all')}
|
||||
/>
|
||||
<input
|
||||
class="join-item btn"
|
||||
type="radio"
|
||||
name="filter"
|
||||
aria-label={$t('adventures.name')}
|
||||
id="name"
|
||||
on:change={() => (property = 'name')}
|
||||
/>
|
||||
<input
|
||||
class="join-item btn"
|
||||
type="radio"
|
||||
name="filter"
|
||||
aria-label={$t('adventures.location')}
|
||||
id="location"
|
||||
on:change={() => (property = 'location')}
|
||||
/>
|
||||
<input
|
||||
class="join-item btn"
|
||||
type="radio"
|
||||
name="filter"
|
||||
aria-label={$t('adventures.description')}
|
||||
id="description"
|
||||
on:change={() => (property = 'description')}
|
||||
/>
|
||||
<input
|
||||
class="join-item btn"
|
||||
type="radio"
|
||||
name="filter"
|
||||
aria-label={$t('adventures.tags')}
|
||||
id="activity_types"
|
||||
on:change={() => (property = 'activity_types')}
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-primary ml-2" type="button" on:click={filterByProperty}
|
||||
>{$t('adventures.filter')}</button
|
||||
>
|
||||
{#if adventures.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Adventures</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each adventures as adventure}
|
||||
<AdventureCard {adventure} user={data.user} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if myAdventures.length > 0}
|
||||
<h2 class="text-center font-bold text-2xl mb-4">{$t('adventures.my_adventures')}</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each myAdventures as adventure}
|
||||
<AdventureCard
|
||||
user={data.user}
|
||||
{adventure}
|
||||
on:delete={deleteAdventure}
|
||||
on:edit={editAdventure}
|
||||
{#if collections.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Collections</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each collections as collection}
|
||||
<CollectionCard {collection} type={''} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if countries.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Countries</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each countries as country}
|
||||
<CountryCard {country} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if regions.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Regions</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each regions as region}
|
||||
<RegionCard
|
||||
{region}
|
||||
visited={visited_regions.some((visitedRegion) => visitedRegion.region === region.id)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if publicAdventures.length > 0}
|
||||
<h2 class="text-center font-bold text-2xl mb-4">{$t('search.public_adventures')}</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each publicAdventures as adventure}
|
||||
<AdventureCard user={null} {adventure} on:delete={deleteAdventure} on:edit={editAdventure} />
|
||||
{#if cities.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Cities</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each cities as city}
|
||||
<CityCard
|
||||
{city}
|
||||
visited={visited_cities.some((visitedCity) => visitedCity.city === city.id)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if myAdventures.length > 0 && osmResults.length > 0 && publicAdventures.length > 0}
|
||||
<div class="divider"></div>
|
||||
{/if}
|
||||
{#if osmResults.length > 0}
|
||||
<h2 class="text-center font-bold mt-2 text-2xl mb-4">{$t('search.online_results')}</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||
{#each osmResults as result}
|
||||
<div class="bg-base-300 rounded-lg shadow-md p-4 w-96 mb-2">
|
||||
<h2 class="text-xl font-bold">{result.display_name}</h2>
|
||||
<p>{result.type}</p>
|
||||
<p>{result.lat}, {result.lon}</p>
|
||||
</div>
|
||||
|
||||
{#if users.length > 0}
|
||||
<h2 class="text-3xl font-bold text-center m-4">Users</h2>
|
||||
<div class="flex flex-wrap gap-4 mr-4 ml-4 justify-center content-center">
|
||||
{#each users as user}
|
||||
<UserCard {user} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if adventures.length === 0 && regions.length === 0 && cities.length === 0 && countries.length === 0 && collections.length === 0 && users.length === 0}
|
||||
<p class="text-center text-lg m-4">
|
||||
{$t('adventures.no_results')}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<svelte:head>
|
||||
<title>Search{query ? `: ${query}` : ''}</title>
|
||||
<meta name="description" content="Search your adventures." />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue