Skip to content

Commit

Permalink
feat: added location questions
Browse files Browse the repository at this point in the history
  • Loading branch information
ymarcon committed Feb 10, 2025
1 parent 99b9181 commit 98a1492
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 14 deletions.
8 changes: 7 additions & 1 deletion backend/api/views/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ async def get(token: str, session: AsyncSession = Depends(get_session)) -> Parti
if campaign.end_date is not None and campaign.end_date < datetime.now():
raise HTTPException(
status_code=400, detail="Campaign has already ended")
return ParticipantData(data=participant.data)
data = participant.data
data["workplace"] = {
"address": campaign.address,
"lon": campaign.lon,
"lat": campaign.lat
}
return ParticipantData(data=data)
128 changes: 128 additions & 0 deletions collect/src/components/form/LocationItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<template>
<div>
<div class="text-h4 q-mb-md">{{ label }}</div>
<div v-if="hint" class="text-h6">{{ hint }}</div>
<div class="q-mt-lg q-mb-lg">
<q-input
v-model="addressLocation.address"
type="text"
class="text-h4 q-mb-md"
bg-color="green-3"
filled
debounce="300"
@keyup.enter="onSuggestAddress"
@update:model-value="onUpdate"
:loading="loading"
lazy-rules
>
<q-menu v-model="showSuggestions" no-parent-event no-focus auto-close>
<q-list style="min-width: 100px">
<q-item
clickable
v-close-popup
v-for="sugg in suggestions"
:key="sugg.value"
@click="onSuggestionSelected(sugg)"
>
<q-item-section>{{ sugg.value }}</q-item-section>
</q-item>
<q-item v-if="suggestions.length === 0">
<q-item-section class="text-grey">
{{ t('no_results') }}
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-input>
<div v-if="addressLocation.lat && addressLocation.lon" class="q-pl-sm q-mb-lg">
<a
:href="`https://www.google.com/maps/search/?api=1&query=${addressLocation.lat},${addressLocation.lon}`"
target="_blank"
class="text-h6 text-white"
>
<q-icon name="location_on" color="white" />
{{ formatCoordinates(addressLocation.lat, addressLocation.lon) }}
</a>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { geocoderApi, toAddress } from 'src/utils/geocoder'
import type { Feature, Point } from 'geojson'
import type { AddressLocation } from 'src/models'
import { formatCoordinates } from 'src/utils/numbers'
const { t } = useI18n()
interface Props {
modelValue: AddressLocation | undefined
label?: string
hint?: string
}
const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue', 'feature'])
interface Suggestion {
value: string
feature: Feature
}
const addressLocation = ref<AddressLocation>({ address: '' })
const suggestions = ref<Suggestion[]>([])
const showSuggestions = ref(false)
const loading = ref(false)
onMounted(() => {
if (props.modelValue === undefined) {
emit('update:modelValue', { address: '' })
} else {
onInit()
}
})
function onInit() {
addressLocation.value = props.modelValue || { address: '' }
suggestions.value = []
}
function onUpdate() {
emit('update:modelValue', addressLocation.value)
}
function onSuggestAddress() {
if (addressLocation.value?.address === undefined || addressLocation.value.address.length < 3) {
return
}
loading.value = true
showSuggestions.value = false
geocoderApi
.forwardGeocode({ query: addressLocation.value.address, limit: 5 })
.then((collection) => {
if (collection && collection.features && collection.features.length) {
suggestions.value = collection.features
.filter((feature) => feature.properties?.address)
.map((feature) => ({ value: toAddress(feature), feature }))
}
})
.catch((error) => {
console.error(error)
})
.finally(() => {
showSuggestions.value = true
loading.value = false
})
}
function onSuggestionSelected(suggestion: Suggestion) {
addressLocation.value.address = suggestion.value
showSuggestions.value = false
addressLocation.value.lat = (suggestion.feature.geometry as Point).coordinates[1]
addressLocation.value.lon = (suggestion.feature.geometry as Point).coordinates[0]
emit('feature', suggestion.feature)
onUpdate()
}
</script>
38 changes: 25 additions & 13 deletions collect/src/components/form/SurveyPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@
/>
</div>
<div v-if="step === 3">
<LocationItem
:label="t('form.workplace')"
v-model="collector.caseReport.data.workplace"
class="q-mb-xl"
/>
<LocationItem
:label="t('form.origin')"
:hint="t('form.origin_hint')"
v-model="collector.caseReport.data.origin"
/>
</div>
<div v-if="step === 4">
<NumberItem
:label="t('form.travel_time')"
v-model="collector.caseReport.data.travel_time"
Expand All @@ -45,7 +57,7 @@
:unit-hint="t('form.travel_time_minutes')"
/>
</div>
<div v-if="step === 4">
<div v-if="step === 5">
<ChoiceItem
:label="t('form.constraints')"
:options="constraintsOptions"
Expand All @@ -54,7 +66,7 @@
:option-label-class="q.screen.lt.sm ? 'text-h5' : ''"
/>
</div>
<div v-if="step === 5">
<div v-if="step === 6">
<ChoiceItem
:label="t('form.equipments')"
:options="equipmentsOptions"
Expand All @@ -63,7 +75,7 @@
:option-label-class="q.screen.lt.sm ? 'text-h5' : ''"
/>
</div>
<div v-if="step === 6">
<div v-if="step === 7">
<SectionItem :label="t('form.freq_mod')" :hint="t('form.freq_mod_hint')" class="q-mb-lg" />
<SliderItem
:label="t('form.mode.walking')"
Expand Down Expand Up @@ -108,7 +120,7 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 7">
<div v-if="step === 8">
<SectionItem :label="t('form.freq_trav_pro')" class="q-mb-lg" />
<NumberItem
:label="t('form.freq_trav_pro_local')"
Expand Down Expand Up @@ -144,7 +156,7 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 8">
<div v-if="step === 9">
<SectionItem :label="t('form.freq_mod_pro')" class="q-mb-lg" />
<NumberItem
:label="t('form.mode.walking')"
Expand Down Expand Up @@ -224,7 +236,7 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 9">
<div v-if="step === 10">
<SectionItem
:label="t('form.importance')"
:hint="t('form.importance_hint')"
Expand Down Expand Up @@ -273,7 +285,7 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 10">
<div v-if="step === 11">
<SectionItem :label="t('form.needs')" :hint="t('form.needs_hint')" class="q-mb-lg" />
<RatingItem
:label="t('form.mode.walking')"
Expand Down Expand Up @@ -312,7 +324,7 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 11">
<div v-if="step === 12">
<SectionItem
:label="t('form.adjectives')"
:hint="t('form.adjectives_hint')"
Expand Down Expand Up @@ -349,18 +361,17 @@
class="q-mb-lg"
/>
</div>
<div v-if="step === 12">
<div v-if="step === 13">
<SectionItem :label="t('form.recommendations')" class="q-mb-lg" />
<pre>{{ collector.caseReport.data }}</pre>
</div>
<div v-if="step === 13">
<div v-if="step === 14">
<SectionItem :label="t('form.comments')" class="q-mb-lg" />
<q-input
v-model="collector.caseReport.data.comments"
type="textarea"
class="q-mb-lg text-h4"
bg-color="green-3"
rounded
filled
/>
</div>
Expand All @@ -376,7 +387,7 @@
/>
<q-btn
rounded
v-if="step < 13"
v-if="step < 14"
color="accent"
icon="keyboard_arrow_right"
size="lg"
Expand All @@ -385,7 +396,7 @@
/>
<q-btn
rounded
v-if="step === 13"
v-if="step === 14"
color="primary"
:label="t('send')"
icon-right="send"
Expand All @@ -405,6 +416,7 @@ import ToggleItem from 'src/components/form/ToggleItem.vue'
import SectionItem from 'src/components/form/SectionItem.vue'
import SliderItem from 'src/components/form/SliderItem.vue'
import RatingItem from 'src/components/form/RatingItem.vue'
import LocationItem from 'src/components/form/LocationItem.vue'
const { t } = useI18n()
const collector = useCollector()
Expand Down
5 changes: 5 additions & 0 deletions collect/src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export default {
company_vehicle: 'Do you have a company vehicle?',
yes: 'Yes',
no: 'No',
workplace: 'Address of usual place of work',
origin: 'Where do you usually leave from to reach your workplace?',
origin_hint:
'This confidential information will only be used to calculate your mobility options for your home-work journey.',
travel_time:
'What is your average travel time from home to work, with the mode of transport you use most often?',
travel_time_minutes: 'minutes (one way)',
Expand Down Expand Up @@ -106,4 +110,5 @@ export default {
token: 'Token',
welcome: 'Welcome to {brand}',
welcome_intro: 'Please fill out the survey to help us improve your daily commute.',
no_results: 'No results',
}
8 changes: 8 additions & 0 deletions collect/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export interface ParticipantData {
}
}

export interface AddressLocation {
address: string
lat?: number | undefined
lon?: number | undefined
}

export interface CaseReport {
data: {
age_class: string
Expand Down Expand Up @@ -49,5 +55,7 @@ export interface CaseReport {
adjectives_pubs: string[]
adjectives_motors: string[]
comments: string
workplace: AddressLocation
origin: AddressLocation
}
}

0 comments on commit 98a1492

Please # to comment.