1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-23 14:59:36 +02:00

Fix adventure grouping in collections

This commit is contained in:
Sean Morley 2024-10-01 09:32:02 -04:00
parent 1eadac90f1
commit b9cae8a687
4 changed files with 176 additions and 157 deletions

View file

@ -1,10 +1,10 @@
{% extends "base.html" %} {% extends "base.html" %} {% block content %}
<!-- Main jumbotron for a primary marketing message or call to action -->
{% block content %} <div class="jumbotron">
<!-- Main jumbotron for a primary marketing message or call to action --> <h1>AdventureLog API Server</h1>
<div class="jumbotron"> <p>
<h1>AdventureLog API Server</h1> <a class="btn btn-primary btn-lg" href="/admin" role="button">Admin Site</a>
<p>Welcome to the server side of AdventureLog!</p> <a class="btn btn-secondary btn-lg" href="/docs" role="button">API Docs</a>
<p>This site is only ment for administrative users</p> </p>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { Adventure, OpenStreetMapPlace, Point } from '$lib/types'; import type { Adventure, Collection, OpenStreetMapPlace, Point } from '$lib/types';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { enhance } from '$app/forms'; import { enhance } from '$app/forms';
import { addToast } from '$lib/toasts'; import { addToast } from '$lib/toasts';
@ -8,9 +8,7 @@
export let longitude: number | null = null; export let longitude: number | null = null;
export let latitude: number | null = null; export let latitude: number | null = null;
export let collection_id: string | null = null; export let collection: Collection | null = null;
export let is_collection: boolean = false;
import { DefaultMarker, MapEvents, MapLibre } from 'svelte-maplibre'; import { DefaultMarker, MapEvents, MapLibre } from 'svelte-maplibre';
@ -19,21 +17,14 @@
let images: { id: string; image: string }[] = []; let images: { id: string; image: string }[] = [];
let warningMessage: string = ''; let warningMessage: string = '';
import Earth from '~icons/mdi/earth';
import ActivityComplete from './ActivityComplete.svelte'; import ActivityComplete from './ActivityComplete.svelte';
import { appVersion } from '$lib/config'; import { appVersion } from '$lib/config';
import { ADVENTURE_TYPES } from '$lib'; import { ADVENTURE_TYPES } from '$lib';
export let startDate: string | null = null;
export let endDate: string | null = null;
let wikiError: string = ''; let wikiError: string = '';
let noPlaces: boolean = false; let noPlaces: boolean = false;
let region_name: string | null = null;
let region_id: string | null = null;
let adventure: Adventure = { let adventure: Adventure = {
id: '', id: '',
name: '', name: '',
@ -49,7 +40,7 @@
location: null, location: null,
images: [], images: [],
user_id: null, user_id: null,
collection: collection_id || null collection: collection?.id || null
}; };
export let adventureToEdit: Adventure | null = null; export let adventureToEdit: Adventure | null = null;
@ -68,9 +59,8 @@
location: adventureToEdit?.location || null, location: adventureToEdit?.location || null,
images: adventureToEdit?.images || [], images: adventureToEdit?.images || [],
user_id: adventureToEdit?.user_id || null, user_id: adventureToEdit?.user_id || null,
collection: adventureToEdit?.collection || collection_id || null, collection: adventureToEdit?.collection || collection?.id || null,
visits: adventureToEdit?.visits || [] visits: adventureToEdit?.visits || []
//visits: []
}; };
let markers: Point[] = []; let markers: Point[] = [];
@ -91,7 +81,6 @@
activity_type: '' activity_type: ''
} }
]; ];
checkPointInRegion();
} }
if (longitude && latitude) { if (longitude && latitude) {
@ -109,8 +98,6 @@
function clearMap() { function clearMap() {
console.log('CLEAR'); console.log('CLEAR');
markers = []; markers = [];
region_id = null;
region_name = null;
} }
let imageSearch: string = adventure.name || ''; let imageSearch: string = adventure.name || '';
@ -147,13 +134,6 @@
} }
} }
$: {
if (adventure.type != 'visited') {
region_id = null;
region_name = null;
}
}
async function fetchImage() { async function fetchImage() {
let res = await fetch(url); let res = await fetch(url);
let data = await res.blob(); let data = await res.blob();
@ -236,6 +216,37 @@
} }
} }
let new_start_date: string = '';
let new_end_date: string = '';
let new_notes: string = '';
function addNewVisit() {
// check if start date is before end date
if (new_start_date > new_end_date) {
addToast('error', 'Start date must be before end date');
return;
}
if (new_start_date === '' || new_end_date === '') {
addToast('error', 'Please enter a start and end date');
return;
}
if (new_end_date && !new_start_date) {
addToast('error', 'Please enter a start date');
return;
}
adventure.visits = [
...adventure.visits,
{
start_date: new_start_date,
end_date: new_end_date,
notes: new_notes,
id: ''
}
];
new_start_date = '';
new_end_date = '';
new_notes = '';
}
async function reverseGeocode() { async function reverseGeocode() {
let res = await fetch( let res = await fetch(
`https://nominatim.openstreetmap.org/search?q=${adventure.latitude},${adventure.longitude}&format=jsonv2`, `https://nominatim.openstreetmap.org/search?q=${adventure.latitude},${adventure.longitude}&format=jsonv2`,
@ -259,7 +270,6 @@
activity_type: data[0]?.type || '' activity_type: data[0]?.type || ''
} }
]; ];
checkPointInRegion();
} }
} }
console.log(data); console.log(data);
@ -297,29 +307,6 @@
} }
} }
async function checkPointInRegion() {
if (adventure.type == 'visited') {
let lat = markers[0].lngLat.lat;
let lon = markers[0].lngLat.lng;
let res = await fetch(`/api/countries/check_point_in_region/?lat=${lat}&lon=${lon}`);
let data = await res.json();
if (data.error) {
addToast('error', data.error);
} else {
if (data.in_region) {
region_name = data.region_name;
region_id = data.region_id;
} else {
region_id = null;
region_name = null;
}
}
} else {
region_id = null;
region_name = null;
}
}
async function addMarker(e: CustomEvent<any>) { async function addMarker(e: CustomEvent<any>) {
markers = []; markers = [];
markers = [ markers = [
@ -331,8 +318,6 @@
activity_type: '' activity_type: ''
} }
]; ];
checkPointInRegion();
console.log(markers); console.log(markers);
} }
@ -355,20 +340,6 @@
async function handleSubmit(event: Event) { async function handleSubmit(event: Event) {
event.preventDefault(); event.preventDefault();
if (region_id && region_name) {
let res = await fetch(`/api/visitedregion/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ region: region_id })
});
if (res.ok) {
addToast('success', `Region ${region_name} marked as visited`);
}
}
console.log(adventure); console.log(adventure);
if (adventure.id === '') { if (adventure.id === '') {
let res = await fetch('/api/adventures', { let res = await fetch('/api/adventures', {
@ -544,7 +515,7 @@
<p class="text-red-500">{wikiError}</p> <p class="text-red-500">{wikiError}</p>
</div> </div>
</div> </div>
{#if !collection_id} {#if !collection?.id}
<div> <div>
<div class="form-control flex items-start mt-1"> <div class="form-control flex items-start mt-1">
<label class="label cursor-pointer flex items-start space-x-2"> <label class="label cursor-pointer flex items-start space-x-2">
@ -563,34 +534,6 @@
</div> </div>
</div> </div>
<div class="collapse collapse-plus bg-base-200 mb-4 overflow-visible">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">
Activity Types ({adventure.activity_types?.length || 0})
</div>
<div class="collapse-content">
<input
type="text"
id="activity_types"
name="activity_types"
hidden
bind:value={adventure.activity_types}
class="input input-bordered w-full"
/>
<ActivityComplete bind:activities={adventure.activity_types} />
</div>
</div>
<div class="collapse collapse-plus bg-base-200 mb-4">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">
Visits ({adventure.visits.length})
</div>
<div class="collapse-content">
<p>Coming soon!</p>
</div>
</div>
<div class="collapse collapse-plus bg-base-200 mb-4"> <div class="collapse collapse-plus bg-base-200 mb-4">
<input type="checkbox" /> <input type="checkbox" />
<div class="collapse-title text-xl font-medium">Location Information</div> <div class="collapse-title text-xl font-medium">Location Information</div>
@ -640,7 +583,6 @@
activity_type: place.type activity_type: place.type
} }
]; ];
checkPointInRegion();
}} }}
> >
{place.display_name} {place.display_name}
@ -668,13 +610,117 @@ it would also work to just use on:click on the MapLibre component itself. -->
{/each} {/each}
</MapLibre> </MapLibre>
</div> </div>
{#if region_name}
<p class="text-lg font-semibold mt-2">Region: {region_name} ({region_id})</p>
{/if}
</div> </div>
</div> </div>
<!-- ---OLD--- --> <div class="collapse collapse-plus bg-base-200 mb-4 overflow-visible">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">
Activity Types ({adventure.activity_types?.length || 0})
</div>
<div class="collapse-content">
<input
type="text"
id="activity_types"
name="activity_types"
hidden
bind:value={adventure.activity_types}
class="input input-bordered w-full"
/>
<ActivityComplete bind:activities={adventure.activity_types} />
</div>
</div>
<div class="collapse collapse-plus bg-base-200 mb-4">
<input type="checkbox" />
<div class="collapse-title text-xl font-medium">
Visits ({adventure.visits.length})
</div>
<div class="collapse-content">
<label class="label cursor-pointer flex items-start space-x-2">
<span class="label-text">Constrain to collection dates</span>
<input
type="checkbox"
class="toggle toggle-primary"
id="is_public"
name="is_public"
/>
<!-- TODO: implement this constrain -->
</label>
<div class="flex gap-2 mb-1">
<input
type="date"
class="input input-bordered w-full"
placeholder="Start Date"
bind:value={new_start_date}
on:keydown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
addNewVisit();
}
}}
/>
<input
type="date"
class="input input-bordered w-full"
placeholder="End Date"
bind:value={new_end_date}
on:keydown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
addNewVisit();
}
}}
/>
</div>
<div class="flex gap-2 mb-1">
<!-- textarea for notes -->
<textarea
class="textarea textarea-bordered w-full"
placeholder="Add notes"
bind:value={new_notes}
on:keydown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
addNewVisit();
}
}}
></textarea>
</div>
<div class="flex gap-2">
<button type="button" class="btn btn-neutral" on:click={addNewVisit}>Add</button>
</div>
{#if adventure.visits.length > 0}
<h2 class=" font-bold text-xl mt-2">My Visits</h2>
{#each adventure.visits as visit}
<div class="flex gap-2">
<p>
{new Date(visit.start_date).toLocaleDateString(undefined, {
timeZone: 'UTC'
})}
</p>
<p>
{new Date(visit.end_date).toLocaleDateString(undefined, { timeZone: 'UTC' })}
</p>
<p>{visit.notes}</p>
<div>
<button
type="button"
class="btn btn-sm btn-error mb-1"
on:click={() => {
adventure.visits = adventure.visits.filter((v) => v !== visit);
}}
>
Remove
</button>
</div>
</div>
{/each}
{/if}
</div>
</div>
<div> <div>
<div class="mt-4"> <div class="mt-4">
@ -798,29 +844,3 @@ it would also work to just use on:click on the MapLibre component itself. -->
{/if} {/if}
</div> </div>
</dialog> </dialog>
<!-- {#each adventure.visits as visit}
<div class="flex flex-row">
<p>
{new Date(visit.start_date).toLocaleDateString(undefined, { timeZone: 'UTC' })}
{#if visit.end_date}
- {new Date(visit.end_date).toLocaleDateString(undefined, {
timeZone: 'UTC'
})}
{/if}
</p>
<button
type="button"
class="btn btn-sm btn-error absolute right-0 mt-2.5 mr-4"
on:click={() => {
adventure.visits = adventure.visits.filter((v) => v.id !== visit.id);
}}
>
Remove
</button>
</div>
{/each}
{#if adventure.visits.length == 0}
<p>No visits</p>
{/if} -->

View file

@ -66,29 +66,31 @@ export function groupAdventuresByDate(
} }
adventures.forEach((adventure) => { adventures.forEach((adventure) => {
if (adventure.date) { adventure.visits.forEach((visit) => {
const adventureDate = new Date(adventure.date).toISOString().split('T')[0]; if (visit.start_date) {
if (adventure.end_date) { const adventureDate = new Date(visit.start_date).toISOString().split('T')[0];
const endDate = new Date(adventure.end_date).toISOString().split('T')[0]; if (visit.end_date) {
const endDate = new Date(visit.end_date).toISOString().split('T')[0];
// Loop through all days and include adventure if it falls within the range // Loop through all days and include adventure if it falls within the range
for (let i = 0; i < numberOfDays; i++) { for (let i = 0; i < numberOfDays; i++) {
const currentDate = new Date(startDate); const currentDate = new Date(startDate);
currentDate.setUTCDate(startDate.getUTCDate() + i); currentDate.setUTCDate(startDate.getUTCDate() + i);
const dateString = currentDate.toISOString().split('T')[0]; const dateString = currentDate.toISOString().split('T')[0];
// Include the current day if it falls within the adventure date range // Include the current day if it falls within the adventure date range
if (dateString >= adventureDate && dateString <= endDate) { if (dateString >= adventureDate && dateString <= endDate) {
if (groupedAdventures[dateString]) { if (groupedAdventures[dateString]) {
groupedAdventures[dateString].push(adventure); groupedAdventures[dateString].push(adventure);
}
} }
} }
} else if (groupedAdventures[adventureDate]) {
// If there's no end date, add adventure to the start date only
groupedAdventures[adventureDate].push(adventure);
} }
} else if (groupedAdventures[adventureDate]) {
// If there's no end date, add adventure to the start date only
groupedAdventures[adventureDate].push(adventure);
} }
} });
}); });
return groupedAdventures; return groupedAdventures;

View file

@ -185,10 +185,7 @@
{adventureToEdit} {adventureToEdit}
on:close={() => (isAdventureModalOpen = false)} on:close={() => (isAdventureModalOpen = false)}
on:save={saveOrCreate} on:save={saveOrCreate}
collection_id={collection.id} {collection}
startDate={collection.start_date}
endDate={collection.end_date}
is_collection={true}
/> />
{/if} {/if}
@ -598,11 +595,11 @@
<p class="font-semibold text-black text-md"> <p class="font-semibold text-black text-md">
{adventure.type.charAt(0).toUpperCase() + adventure.type.slice(1)} {adventure.type.charAt(0).toUpperCase() + adventure.type.slice(1)}
</p> </p>
<p> <!-- <p>
{adventure.date {adventure.
? new Date(adventure.date).toLocaleDateString(undefined, { timeZone: 'UTC' }) ? new Date(adventure.date).toLocaleDateString(undefined, { timeZone: 'UTC' })
: ''} : ''}
</p> </p> -->
</Popup> </Popup>
</DefaultMarker> </DefaultMarker>
{/if} {/if}