(transaction) possibility to change location

This commit is contained in:
Julien Calixte
2020-03-15 14:49:16 +01:00
parent 20463fa540
commit cab5a4e46d
6 changed files with 190 additions and 54 deletions

View File

@@ -5,59 +5,115 @@
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import mapboxgl from 'mapbox-gl/dist/mapbox-gl'
interface Location {
name?: string
lat: number
lon: number
}
import { debounce } from 'lodash-es'
import ILocation from '@/models/ILocation'
@Component
export default class EarthMap extends Vue {
@Prop({ type: Array, default: () => [] })
private locations!: Location[]
private locations!: ILocation[]
@Prop({ type: Boolean, default: false })
private defineLocation!: boolean
private earth: any | null = null
private markerLocation: any | null = null
private emit = debounce((earthMap: EarthMap) => {
if (!earthMap.markerLocation) {
return
}
const lnglat = earthMap.markerLocation.getLngLat()
earthMap.$emit('located', {
lat: lnglat.lat,
lon: lnglat.lng
})
}, 150)
private mounted() {
mapboxgl.accessToken = process.env.VUE_APP_MAPBOX_KEY
this.initEarthMap()
if (!this.earth) {
return
}
const markers = this.locations.map((location) => [
location.lon,
location.lat
])
const latitudes = this.locations.map((location: Location) => location.lat)
const longitudes = this.locations.map((location: Location) => location.lon)
const minLat = Math.min(...latitudes)
const maxLat = Math.min(...latitudes)
const minLon = Math.min(...longitudes)
const maxLon = Math.min(...longitudes)
const earth = new mapboxgl.Map({
markers.forEach((marker) => {
const el = document.createElement('i')
el.classList.add('marker', 'gg-pin-alt')
new mapboxgl.Marker(el).setLngLat(marker).addTo(this.earth)
})
}
private initEarthMap() {
mapboxgl.accessToken = process.env.VUE_APP_MAPBOX_KEY
const latitudes = this.locations.map((location: ILocation) => location.lat)
const longitudes = this.locations.map((location: ILocation) => location.lon)
const minLat = Math.min(...latitudes)
const maxLat = Math.max(...latitudes)
const minLon = Math.min(...longitudes)
const maxLon = Math.max(...longitudes)
// [sw, ne]
const bounds = this.locations.length
? [
[minLon, minLat],
[maxLon, maxLat]
]
: undefined
this.earth = new mapboxgl.Map({
container: 'earth',
style: 'mapbox://styles/mapbox/streets-v11',
bounds: [
[minLon, minLat],
[maxLon, maxLat]
],
bounds,
fitBoundsOptions: {
padding: 15,
padding: 30,
maxZoom: 12
}
})
earth.addControl(new mapboxgl.NavigationControl())
this.earth.addControl(new mapboxgl.NavigationControl())
const geolocControl = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
})
markers.forEach((marker) => {
new mapboxgl.Marker().setLngLat(marker).addTo(earth)
this.earth.addControl(geolocControl)
if (!this.defineLocation) {
return
}
geolocControl.trigger()
const el = document.createElement('i')
el.classList.add('gg-pin-alt', 'marker', 'marker-location')
this.markerLocation = new mapboxgl.Marker(el)
.setLngLat(this.earth.getCenter())
.addTo(this.earth)
this.earth.on('move', (evt: any) => {
this.markerLocation.setLngLat(this.earth.getCenter())
this.emit(this)
})
}
}
</script>
<style lang="scss" scoped>
<style lang="scss">
@import '../styles/earth-map.css';
.earth-container {
min-height: 50vh;
height: 100%;
}
.marker-location {
color: var(--primary-color);
z-index: 1;
}
</style>

View File

@@ -94,15 +94,27 @@
<label class="label">Localisation</label>
</div>
<div class="field-body">
<div class="field">
<div class="control" v-if="transaction.location">
<div
class="field"
:class="{ 'has-addons': !!transaction.location }"
>
<div class="control">
<input
type="text"
readonly
class="input"
v-if="transaction.location"
v-model="transaction.location.place"
/>
</div>
<div class="control set-location">
<button
class="button is-primary"
@click="displayLocationModal = true"
>
définir
</button>
</div>
</div>
</div>
</div>
@@ -176,6 +188,33 @@
</div>
</div>
</div>
<div class="modal" :class="{ 'is-active': displayLocationModal }">
<div class="modal-background"></div>
<div class="modal-card">
<section>
<earth-map
v-if="displayLocationModal"
:locations="
transaction.location ? [transaction.location] : undefined
"
:define-location="true"
@located="located"
/>
</section>
<footer class="modal-card-foot">
<button
class="button is-primary"
:class="{ 'is-loading': isSetLocation }"
@click="validLocation"
>
valider
</button>
<button class="button" @click="displayLocationModal = false">
annuler
</button>
</footer>
</div>
</div>
<fab-button
@valid="submitTransaction"
:margin="true"
@@ -203,11 +242,14 @@ import formatDate from '@/utils/format-date'
import notif from '@/utils/notif'
import { money } from '@/utils/filters'
import { confirmation, alertMessage, findContrastColor } from '@/utils'
import ILocation from '@/models/ILocation'
import MapService from '../services/MapService'
const today: Date = new Date()
@Component({
components: {
'earth-map': () => import('@/components/EarthMap.vue'),
'fab-button': () => import('@/components/FabButton.vue'),
'transaction-split': () => import('@/components/TransactionSplit.vue'),
'transaction-tag-update': () =>
@@ -226,13 +268,15 @@ export default class TransactionCreate extends Vue {
public tag: TransactionTag = TransactionTag.None
public today: string = formatDate(today)
public date: string = formatDate(today)
public location: string = ''
public currency: ICurrency | null = null
public payBy: string = ''
public payFor: ISplit[] = []
public maxAmount: number = 1000000
public noTag: string = TransactionTag.None
public transactionTagLabel: typeof TransactionTagLabel = TransactionTagLabel
public displayLocationModal = false
public isSetLocation = false
public location: ILocation | null = null
public async created(): Promise<void> {
this.setData(this.transaction)
@@ -325,6 +369,29 @@ export default class TransactionCreate extends Vue {
this.payFor.forEach((p: ISplit) => (p.weight = p.weight || 1))
}
public located(location: ILocation) {
this.location = location
}
public async validLocation() {
try {
this.isSetLocation = true
if (this.location) {
const place = await MapService.getPlace(this.location)
const location = {
...this.location,
place
}
this.$set<ILocation>(this.transaction, 'location', location)
}
} catch (error) {
this.$set(this.transaction, 'location', this.transaction.location)
} finally {
this.displayLocationModal = false
this.isSetLocation = false
}
}
public get payForUsers(): ISplit[] {
return this.payFor.filter((p, index) => p.weight > 0)
}
@@ -394,4 +461,7 @@ export default class TransactionCreate extends Vue {
.help {
text-align: left;
}
.set-location {
text-align: center;
}
</style>