Better feedback with connectivity issues when sending reports

This commit is contained in:
Lucas Verney 2018-07-04 18:20:28 +02:00
parent 35851802d0
commit 5c777138f4
9 changed files with 97 additions and 20 deletions

View File

@ -23,6 +23,9 @@
</v-list-tile> </v-list-tile>
</v-list> </v-list>
</v-menu> </v-menu>
<div>
<v-progress-linear v-if="isLoading" :indeterminate="true" class="progressBar"></v-progress-linear>
</div>
</v-toolbar> </v-toolbar>
<v-content> <v-content>
<router-view/> <router-view/>
@ -32,6 +35,11 @@
<script> <script>
export default { export default {
computed: {
isLoading() {
return this.$store.state.isLoading;
},
},
data() { data() {
return { return {
title: 'Cycl\'Assist', title: 'Cycl\'Assist',
@ -61,6 +69,13 @@ export default {
color: rgba(0, 0, 0, .87); color: rgba(0, 0, 0, .87);
text-decoration: none; text-decoration: none;
} }
.progressBar {
margin: 0;
position: absolute;
bottom: 0;
left: 0;
}
</style> </style>
<style> <style>

View File

@ -15,12 +15,18 @@ export function saveReport(type, lat, lng) {
}) })
.then(response => response.json()) .then(response => response.json())
.then(response => response.data) .then(response => response.data)
.catch(exc => console.error(`Unable to post report: ${exc}.`)); .catch((exc) => {
console.error(`Unable to post report: ${exc}.`);
throw exc;
});
} }
export function getReports() { export function getReports() {
return fetch(`${BASE_URL}api/v1/reports`) return fetch(`${BASE_URL}api/v1/reports`)
.then(response => response.json()) .then(response => response.json())
.then(response => response.data) .then(response => response.data)
.catch(exc => console.error(`Unable to fetch reports: ${exc}.`)); .catch((exc) => {
console.error(`Unable to fetch reports: ${exc}.`);
throw exc;
});
} }

View File

@ -1,13 +1,37 @@
<template> <template>
<v-bottom-sheet v-model="isActive"> <div>
<v-card> <v-dialog v-model="error" max-width="290">
<v-container fluid> <v-card>
<v-layout row wrap> <v-card-title class="subheading">{{ $t('reportDialog.unableToSendTitle') }}</v-card-title>
<ReportTile v-for="(item, type) in REPORT_TYPES" :type="type" :imageSrc="item.image" :label="$t(item.label)" :save="saveReport" :key="type"></ReportTile>
</v-layout> <v-card-text>{{ $t('reportDialog.unableToSendDescription') }} </v-card-text>
</v-container>
</v-card> <v-card-actions>
</v-bottom-sheet> <v-spacer></v-spacer>
<v-btn
color="red darken-1"
@click="error = false"
dark
large
>
{{ $t('misc.discard') }}
</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
<v-bottom-sheet v-model="isActive">
<v-card>
<v-container fluid>
<v-layout row wrap>
<ReportTile v-for="(item, type) in REPORT_TYPES" :type="type" :imageSrc="item.image" :label="$t(item.label)" :save="saveReport" :key="type"></ReportTile>
</v-layout>
</v-container>
</v-card>
</v-bottom-sheet>
</div>
</template> </template>
<script> <script>
@ -36,19 +60,20 @@ export default {
}, },
data() { data() {
return { return {
error: false,
REPORT_TYPES, REPORT_TYPES,
}; };
}, },
methods: { methods: {
saveReport(type) { saveReport(type) {
this.isActive = !this.isActive;
return this.$store.dispatch('saveReport', { return this.$store.dispatch('saveReport', {
type, type,
lat: this.lat, lat: this.lat,
lng: this.lng, lng: this.lng,
}) }).catch(() => {
.then(() => { this.error = true;
this.isActive = !this.isActive; });
});
}, },
}, },
}; };

View File

@ -21,8 +21,14 @@ export default {
Settings: 'Settings', Settings: 'Settings',
}, },
misc: { misc: {
discard: 'Discard',
retry: 'Retry',
spaceBeforeDoublePunctuations: '', spaceBeforeDoublePunctuations: '',
}, },
reportDialog: {
unableToSendDescription: 'There was a network issue preventing from sending the latest report.',
unableToSendTitle: 'Unable to send latest report',
},
reportLabels: { reportLabels: {
gcum: 'GCUM', gcum: 'GCUM',
gcumDescription: 'A car poorly parked on a bike lane. Such reports are automatically deleted after one hour, as they are by nature temporary.', gcumDescription: 'A car poorly parked on a bike lane. Such reports are automatically deleted after one hour, as they are by nature temporary.',

View File

@ -21,8 +21,14 @@ export default {
Settings: 'Préférences', Settings: 'Préférences',
}, },
misc: { misc: {
discard: 'Annuler',
retry: 'Réessayer',
spaceBeforeDoublePunctuations: ' ', spaceBeforeDoublePunctuations: ' ',
}, },
reportDialog: {
unableToSendDescription: "Une erreur de réseau empêche l'envoi du dernier signalement.",
unableToSendTitle: "Impossible d'envoyer le dernier signalement",
},
reportLabels: { reportLabels: {
gcum: 'GCUM', gcum: 'GCUM',
gcumDescription: "Une voiture (mal) garée sur la piste cyclable. Ces signalements sont automatiquement supprimés au bout d'une heure car ils sont par essence temporaires.", gcumDescription: "Une voiture (mal) garée sur la piste cyclable. Ces signalements sont automatiquement supprimés au bout d'une heure car ils sont par essence temporaires.",

View File

@ -1,13 +1,16 @@
import * as api from '@/api'; import * as api from '@/api';
import { PUSH_REPORT, STORE_REPORTS } from './mutations-types'; import { IS_LOADING, IS_DONE_LOADING, PUSH_REPORT, STORE_REPORTS } from './mutations-types';
export function fetchReports({ commit }) { export function fetchReports({ commit }) {
return api.getReports().then( commit(IS_LOADING);
reports => commit(STORE_REPORTS, { reports }), return api.getReports()
); .then(reports => commit(STORE_REPORTS, { reports }))
.finally(() => commit(IS_DONE_LOADING));
} }
export function saveReport({ commit }, { type, lat, lng }) { export function saveReport({ commit }, { type, lat, lng }) {
commit(IS_LOADING);
return api.saveReport(type, lat, lng) return api.saveReport(type, lat, lng)
.then(report => commit(PUSH_REPORT, { report })); .then(report => commit(PUSH_REPORT, { report }))
.finally(() => commit(IS_DONE_LOADING));
} }

View File

@ -4,10 +4,17 @@ import Vuex from 'vuex';
import * as actions from './actions'; import * as actions from './actions';
import { initialState as state, mutations } from './mutations'; import { initialState as state, mutations } from './mutations';
const plugins = [];
if (process.NODE_ENV !== 'production') {
const createLogger = require('vuex/dist/logger');
plugins.push(createLogger());
}
Vue.use(Vuex); Vue.use(Vuex);
export default new Vuex.Store({ export default new Vuex.Store({
actions, actions,
state, state,
mutations, mutations,
plugins,
}); });

View File

@ -1,2 +1,4 @@
export const IS_LOADING = 'IS_LOADING';
export const IS_DONE_LOADING = 'IS_DONE_LOADING';
export const PUSH_REPORT = 'PUSH_REPORT'; export const PUSH_REPORT = 'PUSH_REPORT';
export const STORE_REPORTS = 'STORE_REPORTS'; export const STORE_REPORTS = 'STORE_REPORTS';

View File

@ -1,10 +1,17 @@
import * as types from './mutations-types'; import * as types from './mutations-types';
export const initialState = { export const initialState = {
isLoading: false,
reports: [], reports: [],
}; };
export const mutations = { export const mutations = {
[types.IS_LOADING](state) {
state.isLoading = true;
},
[types.IS_DONE_LOADING](state) {
state.isLoading = false;
},
[types.STORE_REPORTS](state, { reports }) { [types.STORE_REPORTS](state, { reports }) {
state.reports = reports; state.reports = reports;
}, },