Skip to content

Commit

Permalink
Contrib Mode (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
wazolab authored Feb 26, 2024
1 parent 92eec27 commit 205220a
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 22 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,6 @@ Special formatting support:
| Action on details page | details_event | favorite | details_event | action, title, poiId | trackEvent | event, action, title, poiId |

Note on Matomo. `Origin` is a set as dimension `1` and should be configured as is on Matomo.

## Contributor Mode
Enable/Disable: Add the following query parameter in the URL: `?contrib=true|false`
42 changes: 42 additions & 0 deletions components/Fields/ContribFieldGroup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
/* eslint-disable vue/prop-name-casing */
import { pickBy } from 'lodash'
import type { ContribFields, Link } from '~/middleware/contrib-mode.global'
import ExternalLink from '~/components/UI/ExternalLink.vue'
const props = defineProps<{
editor_id: ContribFields['editor_id']
mapillary_link: ContribFields['mapillary_link']
osm_note: ContribFields['osm_note']
}>()
const onlyDefinedProps = computed(() => {
return pickBy(props, p => !!p)
}) as ComputedRef<Record<string, Link>>
</script>

<template>
<div>
<ExternalLink
v-for="(field, key, index) in onlyDefinedProps"
:key="key"
:class="{ 'mt-2': index > 0 }"
:icon="field.icon"
:href="field.url"
>
{{ $t(`fields.contrib.${key}`) }}
</ExternalLink>
</div>
</template>

<style scoped>
div {
margin: 1rem 0;
}
@media print {
div {
display: none;
}
}
</style>
8 changes: 6 additions & 2 deletions components/PoisCard/PoiCardContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { mapState } from 'pinia'
import type { PropType } from 'vue'
import { defineNuxtComponent } from '#app'
import Fields from '~/components/PoisCard/Fields.vue'
import FavoriteIcon from '~/components/UI/FavoriteIcon.vue'
Expand All @@ -12,6 +11,7 @@ import { coordinatesHref } from '~/lib/coordinates'
import { favoritesStore } from '~/stores/favorite'
import { mapStore } from '~/stores/map'
import { isIOS } from '~/utils/isIOS'
import ContributionMixin from '~/mixins/contribution'
export default defineNuxtComponent({
components: {
Expand All @@ -20,7 +20,7 @@ export default defineNuxtComponent({
FavoriteIcon,
Fields,
},
mixins: [ContributionMixin],
props: {
poi: {
type: Object as PropType<ApiPoi>,
Expand Down Expand Up @@ -217,6 +217,10 @@ export default defineNuxtComponent({
{{ description }}
</p>

<ClientOnly v-if="contribMode && isContribEligible(poi.properties)">
<ContribFieldGroup v-bind="getContributorFields(poi)" />
</ClientOnly>

<div v-else class="tw-h-auto tw-flex-grow tw-shrink-0">
<Fields
:fields="
Expand Down
22 changes: 11 additions & 11 deletions components/PoisDetails/PoiDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ import type { Settings } from '~/lib/apiSettings'
import { PropertyTranslationsContextEnum } from '~/plugins/property-translations'
import { favoritesStore } from '~/stores/favorite'
import { OriginEnum } from '~/utils/types'
import ContributionMixin from '~/mixins/contribution'
import FieldsHeader from '~/components/UI/FieldsHeader.vue'
export default defineNuxtComponent({
components: {
PoiLayout,
IconButton,
FavoriteIcon,
FieldsHeader,
TeritorioIcon,
Share,
Carousel,
Expand All @@ -36,7 +39,7 @@ export default defineNuxtComponent({
FieldsGroup,
RelativeDate,
},
mixins: [ContributionMixin],
props: {
settings: {
type: Object as PropType<Settings>,
Expand Down Expand Up @@ -210,6 +213,12 @@ export default defineNuxtComponent({
<template #body>
<div class="detail-wrapper">
<div class="detail-left">
<ClientOnly v-if="contribMode && isContribEligible(poi.properties)">
<FieldsHeader :recursion-stack="[]">
{{ $t('fields.contrib.heading') }}
</FieldsHeader>
<ContribFieldGroup v-bind="getContributorFields(poi)" />
</ClientOnly>
<FieldsGroup
v-if="detailsFields"
:group="{
Expand Down Expand Up @@ -280,16 +289,7 @@ export default defineNuxtComponent({
<template #footer>
<span v-if="poi.properties.metadata.updated_at">
{{ $t('poiDetails.lastUpdate') }}
<a
v-if="
poi.properties.metadata.osm_type && poi.properties.metadata.osm_id
"
:href="`https://www.openstreetmap.org/${poi.properties.metadata.osm_type}/${poi.properties.metadata.osm_id}`"
target="_blank"
>
<RelativeDate :date="poi.properties.metadata.updated_at" />
</a>
<RelativeDate v-else :date="poi.properties.metadata.updated_at" />
<RelativeDate :date="poi.properties.metadata.updated_at" />
</span>
</template>
</PoiLayout>
Expand Down
4 changes: 1 addition & 3 deletions components/PoisList/PoisList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ export default defineNuxtComponent({
geometry_as: 'point',
short_description: true,
},
).then((pois) => {
this.pois = pois
})
).then(pois => this.pois = pois)
},
},
Expand Down
11 changes: 9 additions & 2 deletions components/PoisList/PoisTable.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<script lang="ts">
import type { PropType } from 'vue'
import { defineNuxtComponent } from '#app'
import Field from '~/components/Fields/Field.vue'
import type { ApiPois, FieldsListItem } from '~/lib/apiPois'
import { PropertyTranslationsContextEnum } from '~/plugins/property-translations'
import ContributionMixin from '~/mixins/contribution'
export default defineNuxtComponent({
components: {
Field,
},
mixins: [ContributionMixin],
props: {
fields: {
type: Array as PropType<FieldsListItem[]>,
Expand All @@ -32,6 +32,8 @@ export default defineNuxtComponent({
),
}))
h.push({ value: '', text: '' })
if (this.contribMode)
h.push({ value: 'contrib', text: this.$t('fields.contrib.heading') })
return h
},
Expand Down Expand Up @@ -68,6 +70,11 @@ export default defineNuxtComponent({
{{ $t('poisTable.details') }}
</NuxtLink>
</td>
<ClientOnly v-if="contribMode && isContribEligible(feature.properties)">
<td class="tw-align-top">
<ContribFieldGroup v-bind="getContributorFields(feature)" />
</td>
</ClientOnly>
</tr>
</tbody>
<tbody v-else>
Expand Down
2 changes: 1 addition & 1 deletion lib/apiPois.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface FieldsListGroup {
fields: FieldsList

display_mode: 'standard' | 'card'
icon: string
icon?: string
}

export type FieldsList = (FieldsListItem | FieldsListGroup)[]
Expand Down
6 changes: 6 additions & 0 deletions locales/en-GB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ export default defineI18nLocale(() => {
label: 'Search or add a value',
},
fields: {
contrib: {
editor_id: 'Edit in iD Editor',
heading: 'Contribution',
osm_note: 'Add an OSM note',
mapillary_link: 'Explore on Mapillary',
},
phone: {
callNumber: 'Call this number',
},
Expand Down
6 changes: 6 additions & 0 deletions locales/es-ES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ export default defineI18nLocale(() => {
label: 'Busca o añade un valor',
},
fields: {
contrib: {
editor_id: 'Editar en iD editor',
heading: 'Contribución',
osm_note: 'Añadir una nota en OSM',
mapillary_link: 'Explorar en Mapillary',
},
phone: {
callNumber: 'Llama a este número',
},
Expand Down
6 changes: 6 additions & 0 deletions locales/fr-FR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ export default defineI18nLocale(() => {
label: 'Recherchez ou ajoutez une valeur',
},
fields: {
contrib: {
editor_id: 'Éditer dans l\'éditeur iD',
heading: 'Contribution',
osm_note: 'Ajouter une note à OSM',
mapillary_link: 'Explorer sur Mapillary',
},
phone: {
callNumber: 'Appeler ce numéro',
},
Expand Down
58 changes: 58 additions & 0 deletions middleware/contrib-mode.global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { ApiPoi, ApiPoiProperties } from '~/lib/apiPois'
import { STORE_NAME, useContribStore } from '~/stores/contrib'

export interface Link {
icon: string
url: string
}

export interface ContribFields {
editor_id: Link
mapillary_link?: Link
osm_note: Link
}

export default defineNuxtRouteMiddleware((to) => {
if (process.server)
return

if (process.client) {
const { setEnabled } = useContribStore()
const contribLocalStorage = localStorage.getItem(STORE_NAME)

if (to.query.contrib !== undefined) {
setEnabled(to.query.contrib === 'true')
return
}

if (contribLocalStorage)
setEnabled(contribLocalStorage === 'true')
}
})

export function getContributorFields(feature: ApiPoi): ContribFields {
const { mapillary } = feature.properties
const { osm_id, osm_type } = feature.properties.metadata
const { coordinates } = feature.geometry as GeoJSON.Point

return {
editor_id: {
icon: 'pen-to-square',
url: `https://www.openstreetmap.org/edit?${osm_type}=${osm_id}`,
},
mapillary_link: mapillary
? {
icon: 'external-link-alt',
url: `https://www.mapillary.com/app/?pKey=${mapillary}&focus=photo`,
}
: undefined,
osm_note: {
icon: 'note-sticky',
url: `https://www.openstreetmap.org/note/new#map=19/${coordinates[1]}/${coordinates[0]}&layers=N`,
},
}
}

export function isContribEligible(properties: ApiPoiProperties): boolean {
return !!(properties.metadata.osm_id && properties.metadata.osm_type && properties.editorial)
}
25 changes: 25 additions & 0 deletions mixins/contribution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { mapState } from 'pinia'
import type { ApiPoi, ApiPoiProperties } from '~/lib/apiPois'
import { useContribStore } from '~/stores/contrib'
import type { ContribFields } from '~/middleware/contrib-mode.global'
import { getContributorFields, isContribEligible } from '~/middleware/contrib-mode.global'
import ContribFieldGroup from '~/components/Fields/ContribFieldGroup.vue'

export default {
components: {
ContribFieldGroup,
},
computed: {
...mapState(useContribStore, {
contribMode: 'enabled',
}),
},
methods: {
isContribEligible(properties: ApiPoiProperties): boolean {
return isContribEligible(properties)
},
getContributorFields(feature: ApiPoi): ContribFields {
return getContributorFields(feature)
},
},
}
4 changes: 4 additions & 0 deletions plugins/fontawesome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import {
faMap,
faMapMarkerAlt,
faMinus,
faNoteSticky,
faPenToSquare,
faPhone,
faPlus,
faPrint,
Expand Down Expand Up @@ -115,6 +117,8 @@ library.add(
faCopy,
faCog,
faEnvelope,
faPenToSquare,
faNoteSticky,
)

export default defineNuxtPlugin(_nuxtApp => undefined)
19 changes: 19 additions & 0 deletions stores/contrib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineStore } from 'pinia'

export const STORE_NAME = 'contrib'

interface State {
enabled: boolean
}

export const useContribStore = defineStore(STORE_NAME, {
state: (): State => ({
enabled: false,
}),
actions: {
setEnabled(state: boolean) {
this.enabled = state
localStorage.setItem(STORE_NAME, JSON.stringify(state))
},
},
})
6 changes: 3 additions & 3 deletions stores/map.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { defineStore } from 'pinia'

import type { ApiPoi, ApiPoiProperties } from '~/lib/apiPois'
import type { LatLng, Pitch } from '~/utils/types'
import { Mode } from '~/utils/types'
Expand Down Expand Up @@ -59,14 +58,15 @@ export const mapStore = defineStore('map', {
}

if (feature?.properties) {
const cleanProperties: { [key: string]: any } = {}
const cleanProperties: ApiPoiProperties = {} as ApiPoiProperties

Object.keys(feature.properties).forEach((key) => {
if (isJsonObject(feature.properties[key]))
cleanProperties[key] = JSON.parse(feature.properties[key])
else cleanProperties[key] = feature.properties[key]
})
goodFeature.properties = cleanProperties as ApiPoiProperties

goodFeature.properties = cleanProperties
}

this.selectedFeature = goodFeature
Expand Down

0 comments on commit 205220a

Please sign in to comment.