1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-19 21:09:37 +02:00

is visited

This commit is contained in:
Sean Morley 2024-10-31 09:51:04 -04:00
parent 9d42dbac98
commit 727daf0cfd
10 changed files with 284 additions and 281 deletions

View file

@ -1,3 +1,4 @@
from django.utils import timezone
import os
from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit
from rest_framework import serializers
@ -19,6 +20,7 @@ class AdventureImageSerializer(serializers.ModelSerializer):
return representation
class VisitSerializer(serializers.ModelSerializer):
class Meta:
model = Visit
fields = ['id', 'start_date', 'end_date', 'notes']
@ -27,10 +29,19 @@ class VisitSerializer(serializers.ModelSerializer):
class AdventureSerializer(serializers.ModelSerializer):
images = AdventureImageSerializer(many=True, read_only=True)
visits = VisitSerializer(many=True, read_only=False)
is_visited = serializers.SerializerMethodField()
class Meta:
model = Adventure
fields = ['id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location', 'is_public', 'collection', 'created_at', 'updated_at', 'images', 'link', 'type', 'longitude', 'latitude', 'visits']
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
fields = ['id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location', 'is_public', 'collection', 'created_at', 'updated_at', 'images', 'link', 'type', 'longitude', 'latitude', 'visits', 'is_visited']
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'is_visited']
def get_is_visited(self, obj):
current_date = timezone.now().date()
for visit in obj.visits.all():
if visit.start_date and visit.end_date and (visit.start_date <= current_date):
return True
return False
def to_representation(self, instance):
representation = super().to_representation(instance)

View file

@ -16,7 +16,6 @@
import CollectionLink from './CollectionLink.svelte';
import DotsHorizontal from '~icons/mdi/dots-horizontal';
import DeleteWarning from './DeleteWarning.svelte';
import { isAdventureVisited } from '$lib';
import CardCarousel from './CardCarousel.svelte';
import { t } from 'svelte-i18n';
@ -132,7 +131,7 @@
<div>
<div class="badge badge-primary">{$t(`adventures.activities.${adventure.type}`)}</div>
<div class="badge badge-success">
{isAdventureVisited(adventure) ? $t('adventures.visited') : $t('adventures.planned')}
{adventure.is_visited ? $t('adventures.visited') : $t('adventures.planned')}
</div>
<div class="badge badge-secondary">
{adventure.is_public ? $t('adventures.public') : $t('adventures.private')}

View file

@ -28,6 +28,7 @@
import ActivityComplete from './ActivityComplete.svelte';
import { appVersion } from '$lib/config';
import { ADVENTURE_TYPES } from '$lib';
import RegionCard from './RegionCard.svelte';
let wikiError: string = '';
@ -629,7 +630,11 @@ it would also work to just use on:click on the MapLibre component itself. -->
{#if reverseGeocodePlace}
<div class="mt-2">
<p>{reverseGeocodePlace.region}, {reverseGeocodePlace.country}</p>
<p>{reverseGeocodePlace.is_visited ? 'Visited' : 'Not Visited'}</p>
<p>
{reverseGeocodePlace.is_visited
? $t('adventures.visited')
: $t('adventures.not_visited')}
</p>
</div>
{#if !reverseGeocodePlace.is_visited}
<div role="alert" class="alert alert-info mt-2">
@ -647,10 +652,15 @@ it would also work to just use on:click on the MapLibre component itself. -->
></path>
</svg>
<span
>Mark region {reverseGeocodePlace.region}, {reverseGeocodePlace.country} as visited?</span
>{$t('adventures.mark_region_as_visited', {
values: {
region: reverseGeocodePlace.region,
country: reverseGeocodePlace.country
}
})}</span
>
<button type="button" class="btn btn-neutral" on:click={markVisited}>
Mark as Visited
{$t('adventures.mark_visited')}
</button>
</div>
{/if}

View file

@ -253,28 +253,6 @@ export let ADVENTURE_TYPES = [
{ type: 'other', label: 'Other' }
];
/**
* 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 &&
adventure.visits.some((visit) => {
const visitStartTime = new Date(visit.start_date).getTime();
return visit.start_date && visitStartTime <= currentTime;
})
);
}
export function getRandomBackground() {
const randomIndex = Math.floor(Math.random() * randomBackgrounds.backgrounds.length);
return randomBackgrounds.backgrounds[randomIndex] as Background;

View file

@ -37,6 +37,7 @@ export type Adventure = {
is_public: boolean;
created_at?: string | null;
updated_at?: string | null;
is_visited?: boolean;
};
export type Country = {

View file

@ -139,6 +139,7 @@
"unarchive": "Unarchive",
"archive": "Archive",
"no_collections_found": "No collections found to add this adventure to.",
"not_visited": "Not Visited",
"archived_collection_message": "Collection archived successfully!",
"unarchived_collection_message": "Collection unarchived successfully!",
"delete_collection_success": "Collection deleted successfully!",
@ -173,6 +174,8 @@
"basic_information": "Basic Information",
"adventure_not_found": "There are no adventures to display. Add some using the plus button at the bottom right or try changing filters!",
"no_adventures_found": "No adventures found",
"mark_region_as_visited": "Mark region {region}, {country} as visited?",
"mark_visited": "Mark Visited",
"activities": {
"general": "General 🌍",
"outdoor": "Outdoor 🏞️",

View file

@ -196,7 +196,10 @@
"no_adventures_found": "No se encontraron aventuras",
"no_collections_found": "No se encontraron colecciones para agregar esta aventura.",
"my_adventures": "mis aventuras",
"no_linkable_adventures": "No se encontraron aventuras que puedan vincularse a esta colección."
"no_linkable_adventures": "No se encontraron aventuras que puedan vincularse a esta colección.",
"mark_region_as_visited": "¿Marcar región {region}, {country} como visitada?",
"mark_visited": "Marcos visitó",
"not_visited": "No visitado"
},
"worldtravel": {
"all": "Todo",

View file

@ -20,8 +20,7 @@
groupAdventuresByDate,
groupNotesByDate,
groupTransportationsByDate,
groupChecklistsByDate,
isAdventureVisited
groupChecklistsByDate
} from '$lib';
import ChecklistCard from '$lib/components/ChecklistCard.svelte';
import ChecklistModal from '$lib/components/ChecklistModal.svelte';
@ -45,7 +44,7 @@
$: {
numAdventures = adventures.length;
numVisited = adventures.filter(isAdventureVisited).length;
numVisited = adventures.filter((adventure) => adventure.is_visited).length;
}
let notFound: boolean = false;

View file

@ -46,6 +46,7 @@ export const load = (async (event) => {
name: adventure.name,
visits: adventure.visits,
type: adventure.type,
is_visited: adventure.is_visited
};
});

View file

@ -1,7 +1,6 @@
<script>
// @ts-nocheck
import { isAdventureVisited } from '$lib';
import AdventureModal from '$lib/components/AdventureModal.svelte';
import {
DefaultMarker,
@ -25,8 +24,7 @@
let showPlanned = true;
$: filteredMarkers = markers.filter(
(marker) =>
(showVisited && isAdventureVisited(marker)) || (showPlanned && !isAdventureVisited(marker))
(marker) => (showVisited && marker.is_visited) || (showPlanned && !marker.is_visited)
);
let newMarker = [];
@ -145,7 +143,7 @@
standardControls
>
{#each filteredMarkers as marker}
{#if isAdventureVisited(marker)}
{#if marker.is_visited}
<Marker
lngLat={marker.lngLat}
on:click={() => (clickedName = marker.name)}
@ -205,7 +203,7 @@
<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">
{$t(`adventures.activities.${marker.type}`)}}
{$t(`adventures.activities.${marker.type}`)}
</p>
{#if marker.visits && marker.visits.length > 0}
<p class="text-black text-sm">