Skip to content
Snippets Groups Projects
feature.store.js 14.2 KiB
Newer Older
import axios from '@/axios-client.js';
import router from '../../router';

const feature = {
  namespaced: true,
  state: {
    attachmentFormset: [],
    attachmentsToDelete: [],
    checkedFeatures: [],
    extra_forms: [],
leandro's avatar
leandro committed
    features_count: 0,
Florent Lavelle's avatar
Florent Lavelle committed
    currentFeature: null,
    linkedFormset: [], //* used to edit in feature_edit
    linked_features: [], //* used to display in feature_detail
      state.features = features.sort((a, b) => {
        return new Date(b.created_on) - new Date(a.created_on); // sort features chronologically
      });
leandro's avatar
leandro committed
    SET_FEATURES_COUNT(state, features_count) {
      state.features_count = features_count;
    },
DESPRES Damien's avatar
DESPRES Damien committed
    SET_CURRENT_FEATURE(state, feature) {
Florent Lavelle's avatar
Florent Lavelle committed
      state.currentFeature = feature;
DESPRES Damien's avatar
DESPRES Damien committed
    },
    UPDATE_FORM(state, payload) {
      state.form = payload;
    },
    UPDATE_EXTRA_FORM(state, extra_form) {
      const index = state.extra_forms.findIndex(el => el.label === extra_form.label);
        state.extra_forms[index] = extra_form;
    SET_EXTRA_FORMS(state, extra_forms) {
      state.extra_forms = extra_forms;
    CLEAR_EXTRA_FORM(state) {
      state.extra_forms = [];
    ADD_ATTACHMENT_FORM(state, attachmentFormset) {
      state.attachmentFormset = [...state.attachmentFormset, attachmentFormset];
    },
    UPDATE_ATTACHMENT_FORM(state, payload) {
      const index = state.attachmentFormset.findIndex((el) => el.dataKey === payload.dataKey);
Florent Lavelle's avatar
Florent Lavelle committed
      if (index !== -1) {
        state.attachmentFormset[index] = payload;
      }
    },
    REMOVE_ATTACHMENT_FORM(state, payload) {
      state.attachmentFormset = state.attachmentFormset.filter(form => form.dataKey !== payload);
    },
    CLEAR_ATTACHMENT_FORM(state) {
      state.attachmentFormset = [];
    },
    ADD_LINKED_FORM(state, linkedFormset) {
      state.linkedFormset = [...state.linkedFormset, linkedFormset];
    },
    UPDATE_LINKED_FORM(state, payload) {
      const index = state.linkedFormset.findIndex((el) => el.dataKey === payload.dataKey);
Florent Lavelle's avatar
Florent Lavelle committed
      if (index !== -1) {
        state.linkedFormset[index] = payload;
      }
    },
    REMOVE_LINKED_FORM(state, payload) {
      state.linkedFormset = state.linkedFormset.filter(form => form.dataKey !== payload);
    },
    SET_LINKED_FEATURES(state, payload) {
      state.linked_features = payload;
    },

    ADD_ATTACHMENT_TO_DELETE(state, attachementId) {
      state.attachmentsToDelete.push(attachementId);
    },
    REMOVE_ATTACHMENTS_ID_TO_DELETE(state, attachementId) {
      state.attachmentsToDelete = state.attachmentsToDelete.filter(el => el !== attachementId);
    },
    UPDATE_CHECKED_FEATURES(state, checkedFeatures) {
      state.checkedFeatures = checkedFeatures;
    },
    UPDATE_CLICKED_FEATURES(state, clickedFeatures) {
      state.clickedFeatures = clickedFeatures;
    },
    TOGGLE_MASS_MODE(state, payload) {
      state.massMode = payload;
    },
Florent Lavelle's avatar
Florent Lavelle committed

Timothee P's avatar
Timothee P committed
    async GET_PROJECT_FEATURES({ commit, rootState }, {
      project_slug,
      feature_type__slug,
      ordering,
      search,
      limit,
Florent Lavelle's avatar
Florent Lavelle committed
      geojson = false
Timothee P's avatar
Timothee P committed
    }) {
Florent's avatar
Florent committed
      if (rootState.cancellableSearchRequest.length > 0) {
        const currentRequestCancelToken =
          rootState.cancellableSearchRequest[rootState.cancellableSearchRequest.length - 1];
        currentRequestCancelToken.cancel();
      }
Florent's avatar
Florent committed
      const cancelToken = axios.CancelToken.source();
      commit('SET_CANCELLABLE_SEARCH_REQUEST', cancelToken, { root: true });
      commit('SET_FEATURES', []);
      commit('SET_FEATURES_COUNT', 0);
Florent's avatar
Florent committed
      let url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}projects/${project_slug}/feature/`;
      if (feature_type__slug) {
        url = url.concat('', `${url.includes('?') ? '&' : '?'}feature_type__slug=${feature_type__slug}`);
      }
      if (ordering) {
        url = url.concat('', `${url.includes('?') ? '&' : '?'}ordering=${ordering}`);
      }
Florent's avatar
Florent committed
      if (search) {
Timothee P's avatar
Timothee P committed
        url = url.concat('', `${url.includes('?') ? '&' : '?'}title__icontains=${search}`);
Florent's avatar
Florent committed
      }
      if (limit) {
        url = url.concat('', `${url.includes('?') ? '&' : '?'}limit=${limit}`);
Florent's avatar
Florent committed
      }
Florent Lavelle's avatar
Florent Lavelle committed
      if (geojson) {
        url = url.concat('', '&output=geojson');
      }
Florent Lavelle's avatar
Florent Lavelle committed

      try {
        const response = await axios.get(url, { cancelToken: cancelToken.token });
        if (response.status === 200 && response.data) {
          const features = response.data.features;
          commit('SET_FEATURES', features);
Florent Lavelle's avatar
Florent Lavelle committed
          const features_count = response.data.count;
          commit('SET_FEATURES_COUNT', features_count);
Florent Lavelle's avatar
Florent Lavelle committed
      } catch (error) {
        if (error.message) {
          console.error(error);
        }
    GET_PROJECT_FEATURE({ commit, rootState }, { project_slug, feature_id }) {
DESPRES Damien's avatar
DESPRES Damien committed
      if (rootState.cancellableSearchRequest.length > 0) {
        const currentRequestCancelToken =
          rootState.cancellableSearchRequest[rootState.cancellableSearchRequest.length - 1];
        currentRequestCancelToken.cancel();
      }
DESPRES Damien's avatar
DESPRES Damien committed
      const cancelToken = axios.CancelToken.source();
      commit('SET_CANCELLABLE_SEARCH_REQUEST', cancelToken, { root: true });
      //commit('SET_CURRENT_FEATURE', null); //? Est-ce que c'est nécessaire ? -> fait sauter l'affichage au clic sur un signalement lié (feature_detail)
Florent Lavelle's avatar
Florent Lavelle committed
      const url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}projects/${project_slug}/feature/?id=${feature_id}`;
DESPRES Damien's avatar
DESPRES Damien committed
      return axios
        .get(url, { cancelToken: cancelToken.token })
DESPRES Damien's avatar
DESPRES Damien committed
        .then((response) => {
          if (response.status === 200 && response.data.features) {
            const feature = response.data.features[0];
            commit('SET_CURRENT_FEATURE', feature);
DESPRES Damien's avatar
DESPRES Damien committed
          }
          return response;
        })
        .catch((error) => {
          throw error;
        });
    },
    SEND_FEATURE({ state, rootState, dispatch }, routeName) {
      function redirect(featureId) {
Florent's avatar
Florent committed
        dispatch(
          'GET_PROJECT_FEATURE',
Florent's avatar
Florent committed
          {
            project_slug: rootState.projects.project.slug,
            feature_id: featureId
Florent's avatar
Florent committed
          }
        )
          .then(() => {
            router.push({
              name: 'details-signalement',
Florent's avatar
Florent committed
              params: {
                slug_type_signal: rootState['feature-type'].current_feature_type_slug,
Florent's avatar
Florent committed
                slug_signal: featureId,
                message: routeName === 'ajouter-signalement' ? 'Le signalement a été crée' : 'Le signalement a été mis à jour'
Florent's avatar
Florent committed
              },
            });
Timothee P's avatar
Timothee P committed
            dispatch('projects/GET_ALL_PROJECTS', null, { root:true }); //* & refresh project list
      async function handleOtherForms(featureId) {
        await dispatch('SEND_ATTACHMENTS', featureId);
        await dispatch('PUT_LINKED_FEATURES', featureId);
        redirect(featureId);
      }

      function createGeojson() { //* prepare feature data to send
Florent Lavelle's avatar
Florent Lavelle committed
        const extraFormObject = {}; //* prepare an object to be flatten in properties of geojson
        for (const field of state.extra_forms) {
          extraFormObject[field.name] = field.value;
        }
        return {
Timothee P's avatar
Timothee P committed
          id: state.form.feature_id,
          type: 'Feature',
          geometry: state.form.geometry,
          properties: {
            title: state.form.title,
            description: state.form.description.value,
            status: state.form.status.value,
            project: rootState.projects.project.slug,
            feature_type: rootState['feature-type'].current_feature_type_slug,
Timothee P's avatar
Timothee P committed
        };
Florent Lavelle's avatar
Florent Lavelle committed

Timothee P's avatar
Timothee P committed
      let url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/`;
      if (routeName !== 'ajouter-signalement') {
        feature_type__slug=${rootState['feature-type'].current_feature_type_slug} 
        &project__slug=${rootState.projects.project.slug}`;
      //* postOrPutFeature function from service featureAPI could be used here, but because configuration is in store,
      //* projectBase would need to be sent with each function which imply to modify all function from this service,
      //* which could create regression
        method: routeName === 'ajouter-signalement' ? 'POST' : 'PUT',
        data: geojson
      }).then((response) => {
        if ((response.status === 200 || response.status === 201) && response.data) {
Timothee P's avatar
Timothee P committed
          if (state.attachmentFormset.length > 0 ||
            state.linkedFormset.length > 0 ||
            state.attachmentsToDelete.length > 0) {
            handleOtherForms(response.data.id);
          } else {
            redirect(response.data.id);
          if (error.message === 'Network Error' || !rootState.isOnline) {
            let arraysOffline = [];
Florent Lavelle's avatar
Florent Lavelle committed
            const localStorageArray = localStorage.getItem('geocontrib_offline');
            if (localStorageArray) {
              arraysOffline = JSON.parse(localStorageArray);
Florent Lavelle's avatar
Florent Lavelle committed
            const updateMsg = {
              project: rootState.projects.project.slug,
              type: routeName === 'ajouter-signalement' ? 'post' : 'put',
              featureId: state.form.feature_id,
              geojson: geojson
            };
            arraysOffline.push(updateMsg);
            localStorage.setItem('geocontrib_offline', JSON.stringify(arraysOffline));
              name: 'offline-signalement',
                slug_type_signal: rootState['feature-type'].current_feature_type_slug
            console.error(error);
    async SEND_ATTACHMENTS({ state, rootState, dispatch }, featureId) {
      const DJANGO_API_BASE = rootState.configuration.VUE_APP_DJANGO_API_BASE;
Florent Lavelle's avatar
Florent Lavelle committed

      function addFile(attachment, attchmtId) {
Florent Lavelle's avatar
Florent Lavelle committed
        const formdata = new FormData();
        formdata.append('file', attachment.fileToImport, attachment.fileToImport.name);
        return axios
          .put(`${DJANGO_API_BASE}features/${featureId}/attachments/${attchmtId}/upload-file/`, formdata)
          .then((response) => {
            return response;
          })
          .catch((error) => {
            console.error(error);
            return error;
          });
      }

      function putOrPostAttachement(attachment) {
Florent Lavelle's avatar
Florent Lavelle committed
        const formdata = new FormData();
        formdata.append('title', attachment.title);
        formdata.append('info', attachment.info);
        let url = `${DJANGO_API_BASE}features/${featureId}/attachments/`;
        if (attachment.id) {
          url += `${attachment.id}/`;
Timothee P's avatar
Timothee P committed
        }

        return axios({
          url,
          method: attachment.id ? 'PUT' : 'POST',
          data: formdata
        }).then((response) => {
          if (response && (response.status === 200 || response.status === 201) && attachment.fileToImport) {
            return addFile(attachment, response.data.id);
          }
          return response;
          .catch((error) => {
            console.error(error);
            return error;
          });

      function deleteAttachement(attachmentsId, featureId) {
Florent Lavelle's avatar
Florent Lavelle committed
        const payload = {
          attachmentsId: attachmentsId,
          featureId: featureId
        };
        return dispatch('DELETE_ATTACHMENTS', payload)
          .then((response) => response);
      }
      const promisesResult = await Promise.all([
        ...state.attachmentFormset.map((attachment) => putOrPostAttachement(attachment)),
        ...state.attachmentsToDelete.map((attachmentsId) => deleteAttachement(attachmentsId, featureId))
      state.attachmentsToDelete = [];
      return promisesResult;
    },


    DELETE_ATTACHMENTS({ commit }, payload) {
Florent Lavelle's avatar
Florent Lavelle committed
      const url = `${this.state.configuration.VUE_APP_DJANGO_API_BASE}features/${payload.featureId}/attachments/${payload.attachmentsId}/`;
      return axios
        .delete(url)
        .then((response) => {
          if (response && response.status === 204) {
            commit('REMOVE_ATTACHMENTS_ID_TO_DELETE', payload.attachmentsId);
            return response;
          }
        })
        .catch((error) => {
          console.error(error);
          return error;
    PUT_LINKED_FEATURES({ state, rootState }, featureId) {
      return axios
        .put(`${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/${featureId}/feature-links/`, state.linkedFormset)
        .then((response) => {
          if (response.status === 200 && response.data) {
            return 'La relation a bien été ajouté';
    DELETE_FEATURE({ rootState }, payload) {
      const { feature_id, noFeatureType } = payload;
      let url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/${feature_id}/?` +
      `project__slug=${rootState.projects.project.slug}`;
Florent Lavelle's avatar
Florent Lavelle committed
      if (!noFeatureType) {
        url +=`&feature_type__slug=${rootState['feature-type'].current_feature_type_slug}`;
Florent Lavelle's avatar
Florent Lavelle committed
      }
      return axios
        .delete(url)
        .then((response) => response)
        .catch(() => {
          return false;
        });
leandro's avatar
leandro committed
    },

    INIT_EXTRA_FORMS({ state, rootGetters, commit }) {
      const feature = state.currentFeature;
      function findCurrentValue(label) {
        const field = feature.feature_data.find((el) => el.label === label);
        return field ? field.value : null;
      }
      //* retrieve 'name', 'options', 'position' from current feature_type data to display in the form
      const extraForm = rootGetters['feature-type/feature_type'].customfield_set.map((field) => {
        return {
          ...field,
          //* add value field to extra forms from feature_type and existing values if feature is defined
          value:
            feature && feature.feature_data
              ? findCurrentValue(field.label)
              : null,
        };
      });
      commit('SET_EXTRA_FORMS', extraForm);
    },
export default feature;