feat(hunt): track walking distance via GPS, show live locations on map
Docker Image CI / test (push) Failing after 41s
Docker Image CI / deploy (push) Skipped
Tests / unit (push) Failing after 36s
Tests / integration (push) Successful in 1m34s

Add foreground-only GPS distance tracking for hunts
This commit is contained in:
2026-09-27 20:55:58 +02:00
parent a0fc836c05
commit 61cc516f47
43 changed files with 2313 additions and 24 deletions
+42
View File
@@ -11,6 +11,7 @@ const { loggedIn, fetch } = useUserSession();
const localePath = useLocalePath();
const validation = useValidation();
const { tKey, tSluggy } = useI18nKey();
const { formatDistance } = useFormatDistance();
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn) {
router.push(localePath('/login'));
@@ -18,6 +19,15 @@ watch(loggedIn, (isLoggedIn) => {
});
const { data, refresh, pending } = await useFetch('/api/auth/profile');
const distanceEntries = computed(() =>
(data.value?.distances ?? []).map((entry) => ({
id: entry.huntId,
name_de: entry.huntName_de,
name_en: entry.huntName_en,
distanceMeters: entry.distanceMeters
}))
);
useHead({
title: t('layouts.title', {
title: t('page.profile.title')
@@ -271,6 +281,38 @@ async function submitPassword() {
</VaCardContent>
<VaCardContent v-else>{{ t('page.profile.no_pictures') }}</VaCardContent>
</VaCard>
<VaCard stripe stripe-color="info">
<VaCardTitle>{{ t('page.profile.distances.title') }}</VaCardTitle>
<VaCardContent v-if="data && data.distances.length > 0">
<p class="mb-4 text-xl font-bold">
{{
t('page.profile.distances.total', {
distance: formatDistance(data.totalDistance)
})
}}
</p>
<ul class="flex flex-col gap-2">
<li
v-for="entry in distanceEntries"
:key="entry.id"
class="flex items-center justify-between gap-2"
>
<NuxtLink
:to="localePath(`/hunt/${tSluggy(entry).value}`)"
class="hover:underline"
>
{{ tKey(entry, 'name') }}
</NuxtLink>
<span class="font-mono">{{
formatDistance(entry.distanceMeters)
}}</span>
</li>
</ul>
</VaCardContent>
<VaCardContent v-else>{{
t('page.profile.distances.no_distances')
}}</VaCardContent>
</VaCard>
<AdminUserRoles />
</div>
</template>