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
+41 -4
View File
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { sluggy } from '#imports';
import type { DataTableColumnSource } from 'vuestic-ui';
import MemberCard from '~/components/showcase/MemberCard.vue';
import NumberCard from '~/components/showcase/NumberCard.vue';
import { fullDate } from '~~/server/utils/date';
@@ -10,6 +11,7 @@ definePageMeta({
const { t, d } = useI18n();
const localePath = useLocalePath();
const { tKey, hasKey, tSluggy } = useI18nKey();
const { formatDistance } = useFormatDistance();
const app = useNuxtApp();
const { name, id } = app.$slugData.huntSlug!;
@@ -32,11 +34,23 @@ const leaderboardColumns: DataTableColumnSource[] = [
key: 'score',
displayFormatFn: (data: number) => Number(data).toLocaleString('de')
},
'answers'
'answers',
...(data.value?.trackDistance
? ([
{
key: 'distance',
displayFormatFn: (value: number) => formatDistance(value)
}
] as DataTableColumnSource[])
: [])
];
const columns = leaderboardColumns.map((c) =>
typeof c === 'string' ? c : c.key
);
const totalDistance = computed(
() => data.value?.leaderboard?.reduce((ac, l) => ac + l.distance, 0) ?? 0
);
// TODO: colors
</script>
@@ -76,9 +90,9 @@ const columns = leaderboardColumns.map((c) =>
<section id="numbers">
<div class="grid grid-cols-3 gap-4 bg-red-100 p-4">
<NumberCard
:title="t('page.showcase.crew')"
:count="data._count.members + 1"
icon="support_agent"
:title="t('page.showcase.distance')"
:value="formatDistance(totalDistance)"
icon="route"
/>
<NumberCard
:title="t('page.showcase.quests')"
@@ -188,6 +202,12 @@ const columns = leaderboardColumns.map((c) =>
:count="data.leaderboard[2].answers"
icon="question_mark"
/>
<NumberCard
:title="t('page.showcase.distance')"
:value="formatDistance(data.leaderboard[2].distance)"
icon="route"
/>
<MemberCard :members="data.leaderboard[2].members" />
</div>
</div>
</section>
@@ -210,6 +230,12 @@ const columns = leaderboardColumns.map((c) =>
:count="data.leaderboard[1].answers"
icon="question_mark"
/>
<NumberCard
:title="t('page.showcase.distance')"
:value="formatDistance(data.leaderboard[1].distance)"
icon="route"
/>
<MemberCard :members="data.leaderboard[1].members" />
</div>
</div>
</section>
@@ -236,6 +262,11 @@ const columns = leaderboardColumns.map((c) =>
:count="data.leaderboard[0].answers"
icon="question_mark"
/>
<NumberCard
:title="t('page.showcase.distance')"
:value="formatDistance(data.leaderboard[0].distance)"
icon="route"
/>
</div>
</div>
</section>
@@ -258,6 +289,12 @@ const columns = leaderboardColumns.map((c) =>
:count="data.leaderboard[0].answers"
icon="question_mark"
/>
<NumberCard
:title="t('page.showcase.distance')"
:value="formatDistance(data.leaderboard[0].distance)"
icon="route"
/>
<MemberCard :members="data.leaderboard[0].members" />
</div>
</div>
</section>