feat(hunt): track walking distance via GPS, show live locations on map
Add foreground-only GPS distance tracking for hunts
This commit is contained in:
@@ -74,6 +74,14 @@ const answer = ref(data.value?.answer?.text);
|
||||
const final = ref(data.value?.answer?.final || false);
|
||||
const privateImage = ref(data.value?.answer?.picture?.private ?? false);
|
||||
|
||||
const trackableHunt = data.value?.hunt ?? null;
|
||||
const geo = trackableHunt ? useGeoTracking(trackableHunt) : null;
|
||||
|
||||
// Submit-location slice: independent of the tracking watch loop. The checkbox
|
||||
// is offered only when the user consented and the hunt is tracking-eligible.
|
||||
const sendLocation = ref(unref(geo?.consented?.value ?? false));
|
||||
const locationNotice = ref('');
|
||||
|
||||
const privateChanged = computed(
|
||||
() => (data.value?.answer?.picture?.private ?? false) !== privateImage.value
|
||||
);
|
||||
@@ -105,6 +113,7 @@ useEventListener(window, 'beforeunload', (ev) => {
|
||||
async function submit() {
|
||||
uploading.value = true;
|
||||
submitError.value = '';
|
||||
locationNotice.value = '';
|
||||
uploadProgress.value = 0;
|
||||
|
||||
const body = new FormData();
|
||||
@@ -127,6 +136,16 @@ async function submit() {
|
||||
compressing.value = false;
|
||||
body.set('image', compressedImage);
|
||||
}
|
||||
if (sendLocation.value && geo) {
|
||||
try {
|
||||
const pos = await geo.getPosition();
|
||||
body.set('lat', String(pos.lat));
|
||||
body.set('lon', String(pos.lon));
|
||||
} catch {
|
||||
// Non-blocking: submit without the location and tell the user.
|
||||
locationNotice.value = t('page.quest.location_unavailable');
|
||||
}
|
||||
}
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
try {
|
||||
@@ -149,6 +168,7 @@ async function submit() {
|
||||
answer.value = data.value?.answer?.text;
|
||||
privateImage.value = data.value?.answer?.picture?.private ?? false;
|
||||
newImage.value = undefined;
|
||||
sendLocation.value = false;
|
||||
} catch (e) {
|
||||
if (xhr.status === 418) {
|
||||
submitError.value = t('page.quest.already_finalized');
|
||||
@@ -353,7 +373,20 @@ async function submit() {
|
||||
:label="t('page.quest.finalize')"
|
||||
:messages="t('page.quest.finalize_explain')"
|
||||
/>
|
||||
<VaCheckbox
|
||||
v-if="geo?.gate"
|
||||
v-model="sendLocation"
|
||||
:disabled="uploading || data.answer?.final"
|
||||
:label="t('page.quest.send_location')"
|
||||
:messages="t('page.quest.send_location_explain')"
|
||||
/>
|
||||
|
||||
<VaAlert
|
||||
v-if="locationNotice.length > 0"
|
||||
color="warning"
|
||||
class="w-full text-center"
|
||||
>{{ locationNotice }}</VaAlert
|
||||
>
|
||||
<VaAlert
|
||||
v-if="submitError.length > 0"
|
||||
color="danger"
|
||||
@@ -367,7 +400,8 @@ async function submit() {
|
||||
newImage ||
|
||||
data.answer?.text !== answer ||
|
||||
data.answer?.final !== final ||
|
||||
privateChanged
|
||||
privateChanged ||
|
||||
sendLocation
|
||||
) || uploading
|
||||
"
|
||||
:loading="uploading"
|
||||
|
||||
Reference in New Issue
Block a user