mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-05 13:15:18 +02:00
feat: Implement location details page with server-side loading and deletion functionality
- Added +page.server.ts to handle server-side loading of additional location info. - Created +page.svelte for displaying location details, including images, visits, and maps. - Integrated GPX file handling and rendering on the map. - Updated map route to link to locations instead of adventures. - Refactored profile and search routes to use LocationCard instead of AdventureCard.
This commit is contained in:
parent
8a5d7665df
commit
30c1e2deb6
33 changed files with 966 additions and 934 deletions
|
@ -156,9 +156,17 @@
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Bootstrap JS -->
|
<!-- Bootstrap JS -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<script
|
||||||
|
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
<!-- jQuery (optional, used here for legacy script) -->
|
<!-- jQuery (optional, used here for legacy script) -->
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script
|
||||||
|
src="https://code.jquery.com/jquery-3.6.0.min.js"
|
||||||
|
integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const error_response = (data) => {
|
const error_response = (data) => {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
section: 'main'
|
section: 'main'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/adventures',
|
path: '/locations',
|
||||||
icon: MapMarker,
|
icon: MapMarker,
|
||||||
label: 'locations.my_locations',
|
label: 'locations.my_locations',
|
||||||
section: 'main'
|
section: 'main'
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
import Filter from '~icons/mdi/filter-variant';
|
import Filter from '~icons/mdi/filter-variant';
|
||||||
|
|
||||||
// Component imports
|
// Component imports
|
||||||
import AdventureCard from './AdventureCard.svelte';
|
import AdventureCard from './LocationCard.svelte';
|
||||||
import TransportationCard from './TransportationCard.svelte';
|
import TransportationCard from './TransportationCard.svelte';
|
||||||
import LodgingCard from './LodgingCard.svelte';
|
import LodgingCard from './LodgingCard.svelte';
|
||||||
import NoteCard from './NoteCard.svelte';
|
import NoteCard from './NoteCard.svelte';
|
||||||
|
|
|
@ -228,7 +228,7 @@
|
||||||
<!-- Header Section -->
|
<!-- Header Section -->
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<button
|
<button
|
||||||
on:click={() => goto(`/adventures/${adventure.id}`)}
|
on:click={() => goto(`/locations/${adventure.id}`)}
|
||||||
class="text-xl font-bold text-left hover:text-primary transition-colors duration-200 line-clamp-2 group-hover:underline"
|
class="text-xl font-bold text-left hover:text-primary transition-colors duration-200 line-clamp-2 group-hover:underline"
|
||||||
>
|
>
|
||||||
{adventure.name}
|
{adventure.name}
|
||||||
|
@ -274,7 +274,7 @@
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<button
|
<button
|
||||||
class="btn btn-neutral btn-sm flex-1 mr-2"
|
class="btn btn-neutral btn-sm flex-1 mr-2"
|
||||||
on:click={() => goto(`/adventures/${adventure.id}`)}
|
on:click={() => goto(`/locations/${adventure.id}`)}
|
||||||
>
|
>
|
||||||
<Launch class="w-4 h-4" />
|
<Launch class="w-4 h-4" />
|
||||||
{$t('adventures.open_details')}
|
{$t('adventures.open_details')}
|
|
@ -4,7 +4,7 @@
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AdventureCard from './AdventureCard.svelte';
|
import AdventureCard from './LocationCard.svelte';
|
||||||
let modal: HTMLDialogElement;
|
let modal: HTMLDialogElement;
|
||||||
|
|
||||||
// Icons - following the worldtravel pattern
|
// Icons - following the worldtravel pattern
|
||||||
|
@ -252,7 +252,7 @@
|
||||||
</div>
|
</div>
|
||||||
{#if searchQuery || filterOption !== 'all'}
|
{#if searchQuery || filterOption !== 'all'}
|
||||||
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
||||||
{$t('adventures.no_adventures_found')}
|
{$t('adventures.no_locations_found')}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-base-content/50 text-center max-w-md mb-6">
|
<p class="text-base-content/50 text-center max-w-md mb-6">
|
||||||
{$t('collection.try_different_search')}
|
{$t('collection.try_different_search')}
|
|
@ -249,7 +249,7 @@
|
||||||
formData.append('name', attachmentName);
|
formData.append('name', attachmentName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/adventures?/attachment', {
|
const res = await fetch('/locations?/attachment', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
|
@ -326,9 +326,9 @@
|
||||||
async function uploadImage(file: File) {
|
async function uploadImage(file: File) {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('image', file);
|
formData.append('image', file);
|
||||||
formData.append('adventure', adventure.id);
|
formData.append('location', adventure.id);
|
||||||
|
|
||||||
let res = await fetch(`/adventures?/image`, {
|
let res = await fetch(`/locations?/image`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
|
@ -383,8 +383,8 @@
|
||||||
wikiImageError = '';
|
wikiImageError = '';
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('image', file);
|
formData.append('image', file);
|
||||||
formData.append('adventure', adventure.id);
|
formData.append('location', adventure.id);
|
||||||
let res2 = await fetch(`/adventures?/image`, {
|
let res2 = await fetch(`/locations?/image`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
|
@ -922,12 +922,12 @@
|
||||||
<p class=" font-semibold">{$t('adventures.share_location')}</p>
|
<p class=" font-semibold">{$t('adventures.share_location')}</p>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<p class="text-card-foreground font-mono">
|
<p class="text-card-foreground font-mono">
|
||||||
{window.location.origin}/adventures/{adventure.id}
|
{window.location.origin}/locations/{adventure.id}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
navigator.clipboard.writeText(`${window.location.origin}/adventures/${adventure.id}`);
|
navigator.clipboard.writeText(`${window.location.origin}/locations/${adventure.id}`);
|
||||||
}}
|
}}
|
||||||
class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2"
|
class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2"
|
||||||
>
|
>
|
|
@ -103,7 +103,7 @@
|
||||||
|
|
||||||
// Navigation items for better organization
|
// Navigation items for better organization
|
||||||
const navigationItems = [
|
const navigationItems = [
|
||||||
{ path: '/adventures', icon: MapMarker, label: 'locations.locations' },
|
{ path: '/locations', icon: MapMarker, label: 'locations.locations' },
|
||||||
{ path: '/collections', icon: FormatListBulletedSquare, label: 'navbar.collections' },
|
{ path: '/collections', icon: FormatListBulletedSquare, label: 'navbar.collections' },
|
||||||
{ path: '/worldtravel', icon: Earth, label: 'navbar.worldtravel' },
|
{ path: '/worldtravel', icon: Earth, label: 'navbar.worldtravel' },
|
||||||
{ path: '/map', icon: Map, label: 'navbar.map' },
|
{ path: '/map', icon: Map, label: 'navbar.map' },
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<img src={Lost} alt="Lost" class="w-1/2" />
|
<img src={Lost} alt="Lost" class="w-1/2" />
|
||||||
</div>
|
</div>
|
||||||
<h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
|
<h1 class="mt-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
|
||||||
{$t('adventures.no_adventures_found')}
|
{$t('adventures.no_locations_found')}
|
||||||
</h1>
|
</h1>
|
||||||
{#if !error}
|
{#if !error}
|
||||||
<p class="mt-4 text-muted-foreground">
|
<p class="mt-4 text-muted-foreground">
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "Teilen Sie diesen Ort!",
|
"share_location": "Teilen Sie diesen Ort!",
|
||||||
"visit_calendar": "Besuchen Sie den Kalender",
|
"visit_calendar": "Besuchen Sie den Kalender",
|
||||||
"wiki_location_desc": "Zieht Auszug aus dem Wikipedia -Artikel, der dem Namen des Standorts entspricht.",
|
"wiki_location_desc": "Zieht Auszug aus dem Wikipedia -Artikel, der dem Namen des Standorts entspricht.",
|
||||||
"will_be_marked_location": "wird als besucht markiert, sobald der Standort gespeichert ist."
|
"will_be_marked_location": "wird als besucht markiert, sobald der Standort gespeichert ist.",
|
||||||
|
"no_locations_found": "Keine Standorte gefunden"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"desc_1": "Entdecken, planen und erkunden Sie mühelos",
|
"desc_1": "Entdecken, planen und erkunden Sie mühelos",
|
||||||
|
|
|
@ -226,6 +226,7 @@
|
||||||
"adventure_not_found": "There are no adventures to display. Add some using the plus button at the bottom right or try changing filters!",
|
"adventure_not_found": "There are no adventures to display. Add some using the plus button at the bottom right or try changing filters!",
|
||||||
"collection_contents": "Collection Contents",
|
"collection_contents": "Collection Contents",
|
||||||
"no_adventures_found": "No adventures found",
|
"no_adventures_found": "No adventures found",
|
||||||
|
"no_locations_found": "No locations found",
|
||||||
"no_adventures_message": "Start documenting your adventures and planning new ones. Every journey has a story worth telling.",
|
"no_adventures_message": "Start documenting your adventures and planning new ones. Every journey has a story worth telling.",
|
||||||
"mark_visited": "Mark Visited",
|
"mark_visited": "Mark Visited",
|
||||||
"error_updating_regions": "Error updating regions",
|
"error_updating_regions": "Error updating regions",
|
||||||
|
|
|
@ -301,7 +301,8 @@
|
||||||
"share_location": "¡Comparte esta ubicación!",
|
"share_location": "¡Comparte esta ubicación!",
|
||||||
"visit_calendar": "Visitar el calendario",
|
"visit_calendar": "Visitar el calendario",
|
||||||
"wiki_location_desc": "Extrae extracto del artículo de Wikipedia que coincide con el nombre de la ubicación.",
|
"wiki_location_desc": "Extrae extracto del artículo de Wikipedia que coincide con el nombre de la ubicación.",
|
||||||
"will_be_marked_location": "se marcará según lo visitado una vez que se guarde la ubicación."
|
"will_be_marked_location": "se marcará según lo visitado una vez que se guarde la ubicación.",
|
||||||
|
"no_locations_found": "No se encontraron ubicaciones"
|
||||||
},
|
},
|
||||||
"worldtravel": {
|
"worldtravel": {
|
||||||
"all": "Todo",
|
"all": "Todo",
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "Partagez cet emplacement!",
|
"share_location": "Partagez cet emplacement!",
|
||||||
"visit_calendar": "Visiter le calendrier",
|
"visit_calendar": "Visiter le calendrier",
|
||||||
"wiki_location_desc": "Tire un extrait de l'article de Wikipedia correspondant au nom de l'emplacement.",
|
"wiki_location_desc": "Tire un extrait de l'article de Wikipedia correspondant au nom de l'emplacement.",
|
||||||
"will_be_marked_location": "sera marqué comme visité une fois l'emplacement enregistré."
|
"will_be_marked_location": "sera marqué comme visité une fois l'emplacement enregistré.",
|
||||||
|
"no_locations_found": "Aucun emplacement trouvé"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"desc_1": "Découvrez, planifiez et explorez en toute simplicité",
|
"desc_1": "Découvrez, planifiez et explorez en toute simplicité",
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "Condividi questa posizione!",
|
"share_location": "Condividi questa posizione!",
|
||||||
"visit_calendar": "Visita il calendario",
|
"visit_calendar": "Visita il calendario",
|
||||||
"wiki_location_desc": "Estratto dall'articolo di Wikipedia che corrisponde al nome della posizione.",
|
"wiki_location_desc": "Estratto dall'articolo di Wikipedia che corrisponde al nome della posizione.",
|
||||||
"will_be_marked_location": "sarà contrassegnato come visitato una volta salvata la posizione."
|
"will_be_marked_location": "sarà contrassegnato come visitato una volta salvata la posizione.",
|
||||||
|
"no_locations_found": "Nessuna posizione trovata"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"desc_1": "Scopri, pianifica ed esplora con facilità",
|
"desc_1": "Scopri, pianifica ed esplora con facilità",
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "이 위치를 공유하십시오!",
|
"share_location": "이 위치를 공유하십시오!",
|
||||||
"visit_calendar": "캘린더를 방문하십시오",
|
"visit_calendar": "캘린더를 방문하십시오",
|
||||||
"wiki_location_desc": "위치 이름과 일치하는 Wikipedia 기사에서 발췌 한 내용을 가져옵니다.",
|
"wiki_location_desc": "위치 이름과 일치하는 Wikipedia 기사에서 발췌 한 내용을 가져옵니다.",
|
||||||
"will_be_marked_location": "위치가 저장되면 방문한대로 표시됩니다."
|
"will_be_marked_location": "위치가 저장되면 방문한대로 표시됩니다.",
|
||||||
|
"no_locations_found": "발견 된 위치는 없습니다"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"confirm_password": "비밀번호 확인",
|
"confirm_password": "비밀번호 확인",
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "Deel deze locatie!",
|
"share_location": "Deel deze locatie!",
|
||||||
"visit_calendar": "Bezoek de agenda",
|
"visit_calendar": "Bezoek de agenda",
|
||||||
"wiki_location_desc": "Haalt fragment uit het Wikipedia -artikel dat overeenkomt met de naam van de locatie.",
|
"wiki_location_desc": "Haalt fragment uit het Wikipedia -artikel dat overeenkomt met de naam van de locatie.",
|
||||||
"will_be_marked_location": "wordt gemarkeerd als bezocht zodra de locatie is opgeslagen."
|
"will_be_marked_location": "wordt gemarkeerd als bezocht zodra de locatie is opgeslagen.",
|
||||||
|
"no_locations_found": "Geen locaties gevonden"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"desc_1": "Ontdek, plan en verken met gemak",
|
"desc_1": "Ontdek, plan en verken met gemak",
|
||||||
|
|
|
@ -301,7 +301,8 @@
|
||||||
"share_location": "Del dette stedet!",
|
"share_location": "Del dette stedet!",
|
||||||
"visit_calendar": "Besøk kalenderen",
|
"visit_calendar": "Besøk kalenderen",
|
||||||
"wiki_location_desc": "Trekker utdrag fra Wikipedia -artikkelen som samsvarer med navnet på stedet.",
|
"wiki_location_desc": "Trekker utdrag fra Wikipedia -artikkelen som samsvarer med navnet på stedet.",
|
||||||
"will_be_marked_location": "vil bli merket som besøkt når stedet er lagret."
|
"will_be_marked_location": "vil bli merket som besøkt når stedet er lagret.",
|
||||||
|
"no_locations_found": "Ingen steder funnet"
|
||||||
},
|
},
|
||||||
"worldtravel": {
|
"worldtravel": {
|
||||||
"country_list": "Liste over land",
|
"country_list": "Liste over land",
|
||||||
|
|
|
@ -301,7 +301,8 @@
|
||||||
"share_location": "Udostępnij tę lokalizację!",
|
"share_location": "Udostępnij tę lokalizację!",
|
||||||
"visit_calendar": "Odwiedź kalendarz",
|
"visit_calendar": "Odwiedź kalendarz",
|
||||||
"wiki_location_desc": "Wyciąga fragment artykułu Wikipedii pasujący do nazwy lokalizacji.",
|
"wiki_location_desc": "Wyciąga fragment artykułu Wikipedii pasujący do nazwy lokalizacji.",
|
||||||
"will_be_marked_location": "zostanie oznaczone jako odwiedzone po zapisaniu lokalizacji."
|
"will_be_marked_location": "zostanie oznaczone jako odwiedzone po zapisaniu lokalizacji.",
|
||||||
|
"no_locations_found": "Nie znaleziono żadnych lokalizacji"
|
||||||
},
|
},
|
||||||
"worldtravel": {
|
"worldtravel": {
|
||||||
"country_list": "Lista krajów",
|
"country_list": "Lista krajów",
|
||||||
|
|
|
@ -301,7 +301,8 @@
|
||||||
"share_location": "Поделитесь этим расположением!",
|
"share_location": "Поделитесь этим расположением!",
|
||||||
"visit_calendar": "Посетите календарь",
|
"visit_calendar": "Посетите календарь",
|
||||||
"wiki_location_desc": "Вытягивает отрывок из статьи Википедии, соответствующей названию места.",
|
"wiki_location_desc": "Вытягивает отрывок из статьи Википедии, соответствующей названию места.",
|
||||||
"will_be_marked_location": "будет отмечен по посещению после сохранения местоположения."
|
"will_be_marked_location": "будет отмечен по посещению после сохранения местоположения.",
|
||||||
|
"no_locations_found": "Никаких мест не найдено"
|
||||||
},
|
},
|
||||||
"worldtravel": {
|
"worldtravel": {
|
||||||
"country_list": "Список стран",
|
"country_list": "Список стран",
|
||||||
|
|
|
@ -249,7 +249,8 @@
|
||||||
"share_location": "Dela den här platsen!",
|
"share_location": "Dela den här platsen!",
|
||||||
"visit_calendar": "Besök kalendern",
|
"visit_calendar": "Besök kalendern",
|
||||||
"wiki_location_desc": "Drar utdrag från Wikipedia -artikeln som matchar namnet på platsen.",
|
"wiki_location_desc": "Drar utdrag från Wikipedia -artikeln som matchar namnet på platsen.",
|
||||||
"will_be_marked_location": "kommer att markeras som besöks när platsen har sparats."
|
"will_be_marked_location": "kommer att markeras som besöks när platsen har sparats.",
|
||||||
|
"no_locations_found": "Inga platser hittades"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"desc_1": "Upptäck, planera och utforska med lätthet",
|
"desc_1": "Upptäck, planera och utforska med lätthet",
|
||||||
|
|
|
@ -301,7 +301,8 @@
|
||||||
"share_location": "分享这个位置!",
|
"share_location": "分享这个位置!",
|
||||||
"visit_calendar": "访问日历",
|
"visit_calendar": "访问日历",
|
||||||
"wiki_location_desc": "从Wikipedia文章中提取摘录,符合该位置的名称。",
|
"wiki_location_desc": "从Wikipedia文章中提取摘录,符合该位置的名称。",
|
||||||
"will_be_marked_location": "保存位置后,将被标记为访问。"
|
"will_be_marked_location": "保存位置后,将被标记为访问。",
|
||||||
|
"no_locations_found": "找不到位置"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"forgot_password": "忘记密码?",
|
"forgot_password": "忘记密码?",
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
<div class="flex flex-col sm:flex-row gap-4 pt-4">
|
<div class="flex flex-col sm:flex-row gap-4 pt-4">
|
||||||
{#if data.user}
|
{#if data.user}
|
||||||
<button
|
<button
|
||||||
on:click={() => goto('/adventures')}
|
on:click={() => goto('/locations')}
|
||||||
class="btn btn-primary btn-lg gap-3 shadow-lg hover:shadow-xl transition-all duration-300 group"
|
class="btn btn-primary btn-lg gap-3 shadow-lg hover:shadow-xl transition-all duration-300 group"
|
||||||
>
|
>
|
||||||
<PlayIcon class="w-5 h-5 group-hover:scale-110 transition-transform" />
|
<PlayIcon class="w-5 h-5 group-hover:scale-110 transition-transform" />
|
||||||
|
|
|
@ -1,99 +1,5 @@
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
import type { PageServerLoad } from './$types';
|
|
||||||
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
|
|
||||||
import type { Location } from '$lib/types';
|
|
||||||
|
|
||||||
import type { Actions } from '@sveltejs/kit';
|
export const load = (async (_event) => {
|
||||||
import { fetchCSRFToken } from '$lib/index.server';
|
return redirect(301, '/locations');
|
||||||
|
}) satisfies import('./$types').PageServerLoad;
|
||||||
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
|
||||||
|
|
||||||
export const load = (async (event) => {
|
|
||||||
if (!event.locals.user) {
|
|
||||||
return redirect(302, '/login');
|
|
||||||
} else {
|
|
||||||
let count = 0;
|
|
||||||
let adventures: Location[] = [];
|
|
||||||
|
|
||||||
let typeString = event.url.searchParams.get('types');
|
|
||||||
|
|
||||||
// If no type is specified, default to 'all'
|
|
||||||
if (!typeString) {
|
|
||||||
typeString = 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
const include_collections = event.url.searchParams.get('include_collections') || 'false';
|
|
||||||
const order_by = event.url.searchParams.get('order_by') || 'updated_at';
|
|
||||||
const order_direction = event.url.searchParams.get('order_direction') || 'asc';
|
|
||||||
const page = event.url.searchParams.get('page') || '1';
|
|
||||||
const is_visited = event.url.searchParams.get('is_visited') || 'all';
|
|
||||||
|
|
||||||
let initialFetch = await event.fetch(
|
|
||||||
`${serverEndpoint}/api/locations/filtered?types=${typeString}&order_by=${order_by}&order_direction=${order_direction}&include_collections=${include_collections}&page=${page}&is_visited=${is_visited}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Cookie: `sessionid=${event.cookies.get('sessionid')}`
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!initialFetch.ok) {
|
|
||||||
let error_message = await initialFetch.json();
|
|
||||||
console.error(error_message);
|
|
||||||
console.error('Failed to fetch visited adventures');
|
|
||||||
return redirect(302, '/login');
|
|
||||||
} else {
|
|
||||||
let res = await initialFetch.json();
|
|
||||||
let visited = res.results as Location[];
|
|
||||||
|
|
||||||
count = res.count;
|
|
||||||
adventures = [...adventures, ...visited];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
adventures,
|
|
||||||
count
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}) satisfies PageServerLoad;
|
|
||||||
|
|
||||||
export const actions: Actions = {
|
|
||||||
image: async (event) => {
|
|
||||||
let formData = await event.request.formData();
|
|
||||||
let csrfToken = await fetchCSRFToken();
|
|
||||||
let sessionId = event.cookies.get('sessionid');
|
|
||||||
let res = await fetch(`${serverEndpoint}/api/images/`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Cookie: `csrftoken=${csrfToken}; sessionid=${sessionId}`,
|
|
||||||
'X-CSRFToken': csrfToken,
|
|
||||||
Referer: event.url.origin // Include Referer header
|
|
||||||
},
|
|
||||||
body: formData
|
|
||||||
});
|
|
||||||
let data = await res.json();
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
attachment: async (event) => {
|
|
||||||
let formData = await event.request.formData();
|
|
||||||
let csrfToken = await fetchCSRFToken();
|
|
||||||
let sessionId = event.cookies.get('sessionid');
|
|
||||||
let res = await fetch(`${serverEndpoint}/api/attachments/`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Cookie: `csrftoken=${csrfToken}; sessionid=${sessionId}`,
|
|
||||||
'X-CSRFToken': csrfToken,
|
|
||||||
Referer: event.url.origin // Include Referer header
|
|
||||||
},
|
|
||||||
body: formData
|
|
||||||
});
|
|
||||||
let data = await res.json();
|
|
||||||
|
|
||||||
console.log(res);
|
|
||||||
console.log(data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,76 +1,7 @@
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
|
import { redirect } from '@sveltejs/kit';
|
||||||
import type { AdditionalLocation, Location, Collection } from '$lib/types';
|
|
||||||
const endpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
|
||||||
|
|
||||||
export const load = (async (event) => {
|
export const load = (async (event) => {
|
||||||
const id = event.params as { id: string };
|
const id = event.params as { id: string };
|
||||||
let request = await fetch(`${endpoint}/api/locations/${id.id}/additional-info/`, {
|
return redirect(301, `/locations/${id.id}`);
|
||||||
headers: {
|
|
||||||
Cookie: `sessionid=${event.cookies.get('sessionid')}`
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
if (!request.ok) {
|
|
||||||
console.error('Failed to fetch adventure ' + id.id);
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
adventure: null
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
let adventure = (await request.json()) as AdditionalLocation;
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
adventure
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}) satisfies PageServerLoad;
|
}) satisfies PageServerLoad;
|
||||||
|
|
||||||
import { redirect, type Actions } from '@sveltejs/kit';
|
|
||||||
import { fetchCSRFToken } from '$lib/index.server';
|
|
||||||
|
|
||||||
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
|
||||||
|
|
||||||
export const actions: Actions = {
|
|
||||||
delete: async (event) => {
|
|
||||||
const id = event.params as { id: string };
|
|
||||||
const adventureId = id.id;
|
|
||||||
|
|
||||||
if (!event.locals.user) {
|
|
||||||
return redirect(302, '/login');
|
|
||||||
}
|
|
||||||
if (!adventureId) {
|
|
||||||
return {
|
|
||||||
status: 400,
|
|
||||||
error: new Error('Bad request')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let csrfToken = await fetchCSRFToken();
|
|
||||||
|
|
||||||
let res = await fetch(`${serverEndpoint}/api/locations/${event.params.id}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: {
|
|
||||||
Referer: event.url.origin, // Include Referer header
|
|
||||||
Cookie: `sessionid=${event.cookies.get('sessionid')};
|
|
||||||
csrftoken=${csrfToken}`,
|
|
||||||
'X-CSRFToken': csrfToken
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
console.log(res);
|
|
||||||
if (!res.ok) {
|
|
||||||
return {
|
|
||||||
status: res.status,
|
|
||||||
error: new Error('Failed to delete adventure')
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
status: 204
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
return marked(markdown);
|
return marked(markdown);
|
||||||
};
|
};
|
||||||
|
|
||||||
let adventures = data.props.adventures;
|
let locations = data.props.adventures;
|
||||||
let allDates = data.props.dates;
|
let allDates = data.props.dates;
|
||||||
let filteredDates = [...allDates];
|
let filteredDates = [...allDates];
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="stat py-2 px-4">
|
<div class="stat py-2 px-4">
|
||||||
<div class="stat-title text-xs">{$t('locations.locations')}</div>
|
<div class="stat-title text-xs">{$t('locations.locations')}</div>
|
||||||
<div class="stat-value text-lg text-secondary">{adventures.length}</div>
|
<div class="stat-value text-lg text-secondary">{locations.length}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search adventures or locations..."
|
placeholder={$t('adventures.search_for_location')}
|
||||||
class="input input-bordered w-full pl-10 pr-10 bg-base-100/80"
|
class="input input-bordered w-full pl-10 pr-10 bg-base-100/80"
|
||||||
bind:value={searchFilter}
|
bind:value={searchFilter}
|
||||||
/>
|
/>
|
||||||
|
@ -299,7 +299,7 @@
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
<div class="stat p-0">
|
<div class="stat p-0">
|
||||||
<div class="stat-title text-xs">{$t('locations.locations')}</div>
|
<div class="stat-title text-xs">{$t('locations.locations')}</div>
|
||||||
<div class="stat-value text-lg text-primary">{adventures.length}</div>
|
<div class="stat-value text-lg text-primary">{locations.length}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
|
|
||||||
{#if selectedEvent.extendedProps.adventureId}
|
{#if selectedEvent.extendedProps.adventureId}
|
||||||
<a
|
<a
|
||||||
href={`/adventures/${selectedEvent.extendedProps.adventureId}`}
|
href={`/locations/${selectedEvent.extendedProps.adventureId}`}
|
||||||
class="btn btn-neutral btn-block mt-4"
|
class="btn btn-neutral btn-block mt-4"
|
||||||
>
|
>
|
||||||
{$t('map.view_details')}
|
{$t('map.view_details')}
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
import DayGrid from '@event-calendar/day-grid';
|
import DayGrid from '@event-calendar/day-grid';
|
||||||
|
|
||||||
import Plus from '~icons/mdi/plus';
|
import Plus from '~icons/mdi/plus';
|
||||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/LocationCard.svelte';
|
||||||
import AdventureLink from '$lib/components/AdventureLink.svelte';
|
import AdventureLink from '$lib/components/LocationLink.svelte';
|
||||||
import { MapLibre, Marker, Popup, LineLayer, GeoJSON } from 'svelte-maplibre';
|
import { MapLibre, Marker, Popup, LineLayer, GeoJSON } from 'svelte-maplibre';
|
||||||
import TransportationCard from '$lib/components/TransportationCard.svelte';
|
import TransportationCard from '$lib/components/TransportationCard.svelte';
|
||||||
import NoteCard from '$lib/components/NoteCard.svelte';
|
import NoteCard from '$lib/components/NoteCard.svelte';
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
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 AdventureModal from '$lib/components/AdventureModal.svelte';
|
import AdventureModal 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';
|
||||||
|
@ -1323,7 +1323,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="btn btn-neutral btn-wide btn-sm mt-4"
|
class="btn btn-neutral btn-wide btn-sm mt-4"
|
||||||
on:click={() => goto(`/adventures/${adventure.id}`)}
|
on:click={() => goto(`/locations/${adventure.id}`)}
|
||||||
>{$t('map.view_details')}</button
|
>{$t('map.view_details')}</button
|
||||||
>
|
>
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/LocationCard.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<!-- Quick Action -->
|
<!-- Quick Action -->
|
||||||
<div class="flex flex-col sm:flex-row gap-3">
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
<a
|
<a
|
||||||
href="/adventures"
|
href="/locations"
|
||||||
class="btn btn-primary btn-lg gap-2 shadow-lg hover:shadow-xl transition-all duration-300"
|
class="btn btn-primary btn-lg gap-2 shadow-lg hover:shadow-xl transition-all duration-300"
|
||||||
>
|
>
|
||||||
<Plus class="w-5 h-5" />
|
<Plus class="w-5 h-5" />
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
<p class="text-base-content/60">{$t('home.latest_travel_experiences')}</p>
|
<p class="text-base-content/60">{$t('home.latest_travel_experiences')}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="/adventures" class="btn btn-ghost gap-2">
|
<a href="/locations" class="btn btn-ghost gap-2">
|
||||||
{$t('dashboard.view_all')}
|
{$t('dashboard.view_all')}
|
||||||
<span class="badge badge-primary">{stats.adventure_count}</span>
|
<span class="badge badge-primary">{stats.adventure_count}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -208,7 +208,7 @@
|
||||||
|
|
||||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
<a
|
<a
|
||||||
href="/adventures"
|
href="/locations"
|
||||||
class="btn btn-primary btn-lg gap-2 shadow-lg hover:shadow-xl transition-all duration-300"
|
class="btn btn-primary btn-lg gap-2 shadow-lg hover:shadow-xl transition-all duration-300"
|
||||||
>
|
>
|
||||||
<Plus class="w-5 h-5" />
|
<Plus class="w-5 h-5" />
|
||||||
|
|
99
frontend/src/routes/locations/+page.server.ts
Normal file
99
frontend/src/routes/locations/+page.server.ts
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
|
||||||
|
import type { Location } from '$lib/types';
|
||||||
|
|
||||||
|
import type { Actions } from '@sveltejs/kit';
|
||||||
|
import { fetchCSRFToken } from '$lib/index.server';
|
||||||
|
|
||||||
|
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
||||||
|
|
||||||
|
export const load = (async (event) => {
|
||||||
|
if (!event.locals.user) {
|
||||||
|
return redirect(302, '/login');
|
||||||
|
} else {
|
||||||
|
let count = 0;
|
||||||
|
let adventures: Location[] = [];
|
||||||
|
|
||||||
|
let typeString = event.url.searchParams.get('types');
|
||||||
|
|
||||||
|
// If no type is specified, default to 'all'
|
||||||
|
if (!typeString) {
|
||||||
|
typeString = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
const include_collections = event.url.searchParams.get('include_collections') || 'false';
|
||||||
|
const order_by = event.url.searchParams.get('order_by') || 'updated_at';
|
||||||
|
const order_direction = event.url.searchParams.get('order_direction') || 'asc';
|
||||||
|
const page = event.url.searchParams.get('page') || '1';
|
||||||
|
const is_visited = event.url.searchParams.get('is_visited') || 'all';
|
||||||
|
|
||||||
|
let initialFetch = await event.fetch(
|
||||||
|
`${serverEndpoint}/api/locations/filtered?types=${typeString}&order_by=${order_by}&order_direction=${order_direction}&include_collections=${include_collections}&page=${page}&is_visited=${is_visited}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: `sessionid=${event.cookies.get('sessionid')}`
|
||||||
|
},
|
||||||
|
credentials: 'include'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!initialFetch.ok) {
|
||||||
|
let error_message = await initialFetch.json();
|
||||||
|
console.error(error_message);
|
||||||
|
console.error('Failed to fetch visited adventures');
|
||||||
|
return redirect(302, '/login');
|
||||||
|
} else {
|
||||||
|
let res = await initialFetch.json();
|
||||||
|
let visited = res.results as Location[];
|
||||||
|
|
||||||
|
count = res.count;
|
||||||
|
adventures = [...adventures, ...visited];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
adventures,
|
||||||
|
count
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}) satisfies PageServerLoad;
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
image: async (event) => {
|
||||||
|
let formData = await event.request.formData();
|
||||||
|
let csrfToken = await fetchCSRFToken();
|
||||||
|
let sessionId = event.cookies.get('sessionid');
|
||||||
|
let res = await fetch(`${serverEndpoint}/api/images/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Cookie: `csrftoken=${csrfToken}; sessionid=${sessionId}`,
|
||||||
|
'X-CSRFToken': csrfToken,
|
||||||
|
Referer: event.url.origin // Include Referer header
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
let data = await res.json();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
attachment: async (event) => {
|
||||||
|
let formData = await event.request.formData();
|
||||||
|
let csrfToken = await fetchCSRFToken();
|
||||||
|
let sessionId = event.cookies.get('sessionid');
|
||||||
|
let res = await fetch(`${serverEndpoint}/api/attachments/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Cookie: `csrftoken=${csrfToken}; sessionid=${sessionId}`,
|
||||||
|
'X-CSRFToken': csrfToken,
|
||||||
|
Referer: event.url.origin // Include Referer header
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
let data = await res.json();
|
||||||
|
|
||||||
|
console.log(res);
|
||||||
|
console.log(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
|
@ -2,8 +2,8 @@
|
||||||
import { enhance, deserialize } from '$app/forms';
|
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 AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/LocationCard.svelte';
|
||||||
import AdventureModal from '$lib/components/AdventureModal.svelte';
|
import AdventureModal 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 NotFound from '$lib/components/NotFound.svelte';
|
||||||
|
@ -241,7 +241,7 @@
|
||||||
<Compass class="w-16 h-16 text-base-content/30" />
|
<Compass class="w-16 h-16 text-base-content/30" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
<h3 class="text-xl font-semibold text-base-content/70 mb-2">
|
||||||
{$t('adventures.no_adventures_found')}
|
{$t('adventures.no_locations_found')}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-base-content/50 text-center max-w-md">
|
<p class="text-base-content/50 text-center max-w-md">
|
||||||
{$t('adventures.no_adventures_message')}
|
{$t('adventures.no_adventures_message')}
|
76
frontend/src/routes/locations/[id]/+page.server.ts
Normal file
76
frontend/src/routes/locations/[id]/+page.server.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
|
||||||
|
import type { AdditionalLocation, Location, Collection } from '$lib/types';
|
||||||
|
const endpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
||||||
|
|
||||||
|
export const load = (async (event) => {
|
||||||
|
const id = event.params as { id: string };
|
||||||
|
let request = await fetch(`${endpoint}/api/locations/${id.id}/additional-info/`, {
|
||||||
|
headers: {
|
||||||
|
Cookie: `sessionid=${event.cookies.get('sessionid')}`
|
||||||
|
},
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
if (!request.ok) {
|
||||||
|
console.error('Failed to fetch adventure ' + id.id);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
adventure: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let adventure = (await request.json()) as AdditionalLocation;
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
adventure
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}) satisfies PageServerLoad;
|
||||||
|
|
||||||
|
import { redirect, type Actions } from '@sveltejs/kit';
|
||||||
|
import { fetchCSRFToken } from '$lib/index.server';
|
||||||
|
|
||||||
|
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
delete: async (event) => {
|
||||||
|
const id = event.params as { id: string };
|
||||||
|
const adventureId = id.id;
|
||||||
|
|
||||||
|
if (!event.locals.user) {
|
||||||
|
return redirect(302, '/login');
|
||||||
|
}
|
||||||
|
if (!adventureId) {
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
error: new Error('Bad request')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let csrfToken = await fetchCSRFToken();
|
||||||
|
|
||||||
|
let res = await fetch(`${serverEndpoint}/api/locations/${event.params.id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
Referer: event.url.origin, // Include Referer header
|
||||||
|
Cookie: `sessionid=${event.cookies.get('sessionid')};
|
||||||
|
csrftoken=${csrfToken}`,
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
if (!res.ok) {
|
||||||
|
return {
|
||||||
|
status: res.status,
|
||||||
|
error: new Error('Failed to delete adventure')
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: 204
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -16,7 +16,7 @@
|
||||||
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 AdventureModal from '$lib/components/AdventureModal.svelte';
|
import AdventureModal 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';
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AdventureModal from '$lib/components/AdventureModal.svelte';
|
import AdventureModal 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';
|
||||||
|
@ -268,7 +268,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary btn-sm gap-2"
|
class="btn btn-primary btn-sm gap-2"
|
||||||
on:click={() => goto(`/adventures/${adventure.id}`)}
|
on:click={() => goto(`/locations/${adventure.id}`)}
|
||||||
>
|
>
|
||||||
<Eye class="w-4 h-4" />
|
<Eye class="w-4 h-4" />
|
||||||
{$t('map.view_details')}
|
{$t('map.view_details')}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let data;
|
export let data;
|
||||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/LocationCard.svelte';
|
||||||
import CollectionCard from '$lib/components/CollectionCard.svelte';
|
import CollectionCard from '$lib/components/CollectionCard.svelte';
|
||||||
import type { Location, Collection, User } from '$lib/types.js';
|
import type { Location, Collection, User } from '$lib/types.js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/LocationCard.svelte';
|
||||||
import RegionCard from '$lib/components/RegionCard.svelte';
|
import RegionCard from '$lib/components/RegionCard.svelte';
|
||||||
import CityCard from '$lib/components/CityCard.svelte';
|
import CityCard from '$lib/components/CityCard.svelte';
|
||||||
import CountryCard from '$lib/components/CountryCard.svelte';
|
import CountryCard from '$lib/components/CountryCard.svelte';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue