Skip to content
Snippets Groups Projects
projects.store.js 7.02 KiB
import axios from '@/axios-client.js';
import projectAPI from '@/services/project-api';

const initialFilters = {
  moderation: null,
  access_level: null,
  user_access_level: null,
  accessible: null
};

/**
 * Constructs the URL for the search request, appending search text and any active filters.
 *
 * @param {Object} rootState - The root state to access global configuration settings.
 * @param {Object} filters - The current state of filters applied to the search.
 * @param {String} text - The current search text.
 * @returns {String} The fully constructed URL for the search request.
 */
function constructSearchUrl({ baseUrl, filters, text, page }) {
  let url = `${baseUrl}v2/projects/?`;
  // Append page number if provided.
  if (page) {
    url += `page=${page}`;
  }
  // Append search text if provided.
  if (text) {
    url += `&search=${encodeURIComponent(text)}`;
  }

  // Append each active filter to the URL.
  Object.entries(filters).forEach(([key, value]) => {
    if (value) {
      url += `&${key}=${encodeURIComponent(value)}`;
    }
  });

  return url;
}

const projectsStore = {

  namespaced: true,

  state: {
    count: 0,
    currentPage: 1,
    filters: { ...initialFilters },
    isProjectsListSearched: null,
    last_comments: [],
    projects: [],
    project: null,
    searchProjectsFilter: null,
  },

  mutations: {
    SET_CURRENT_PAGE (state, payload) {
      state.currentPage = payload;
    },

    SET_PROJECTS(state, projects) {
      if (projects.results) {
        state.projects = projects.results;
        state.count = projects.count;
      } else {
        state.projects = projects;
        state.count = projects.length;
      }
    },

    ADD_PROJECT(state, project) {
      state.projects = [project, ...state.projects];
    },

    SET_PROJECT(state, project) {
      state.project = project;
    },

    SET_PROJECTS_FILTER(state, payload) {
      state.filters[payload.filter] = payload.value;
    },

    SET_PROJECTS_SEARCH_STATE(state, payload) {
      state.isProjectsListSearched = payload.isSearched;
      state.searchProjectsFilter = payload.text;
    },

    SET_PROJECT_COMMENTS(state, last_comments) {
      state.last_comments = last_comments;
    },
  },

  actions: {
    async GET_PROJECTS({ state, rootState, commit }, payload) {
      let { page, myaccount, projectSlug } = payload || {};
      if (!page) {
        page = state.currentPage;
      }
      const baseUrl = rootState.configuration.VUE_APP_DJANGO_API_BASE;
      const projects = await projectAPI.getProjects({
        baseUrl,
        filters : state.filters,
        page,
        projectSlug,
        myaccount,
      });
      console.trace('GET_PROJECTS', payload, state.filters.attributes, projects);
      commit('SET_PROJECTS', projects);
      return;
    },

    // async FILTER_PROJECTS({ state, commit, dispatch }, { page, text }) {
    //   if (!page) {
    //     page = state.currentPage;
    //   }
    //   if (text === undefined) {
    //     // if text is undefined it means that user didn't specify the text, we can use the text stored previously
    //     text = state.searchProjectsFilter;
    //     // this allows to replace search by empty string when the user emptied the input field, then we can empty stored text
    //   } else if (text !== state.searchProjectsFilter) {
    //     commit('SET_PROJECTS_SEARCH_STATE', text);
    //   }
    //   await dispatch('HANDLE_PROJECTS_SEARCH_REQUEST', { page, text });
    // },

    async SEARCH_PROJECTS({ commit, dispatch }, text) {
      if (text) {
        await dispatch('HANDLE_PROJECTS_SEARCH_REQUEST', text);
      } else {
        commit('SET_PROJECTS_SEARCH_STATE', {
          isSearched: false,
          text: null
        });
        await dispatch('GET_PROJECTS');
      }
    },

    async GET_PROJECT({ rootState, commit }, slug) { // todo : use GET_PROJECTS instead, with slug
      const baseUrl = rootState.configuration.VUE_APP_DJANGO_API_BASE;
      const project = await projectAPI.getProject(baseUrl, slug);
      commit('SET_PROJECT', project);
      return project;
    },

    async GET_PROJECT_INFO({ dispatch }, slug) {
      const promises = [
        dispatch('GET_PROJECT_LAST_MESSAGES', slug).then(response => response),
        dispatch('feature-type/GET_PROJECT_FEATURE_TYPES', slug, { root: true }).then(response => response),
        dispatch('map/GET_BASEMAPS', slug, { root: true }).then(response => response)
      ];

      const promiseResult = await Promise.all(promises);
      return promiseResult;
    },

    GET_PROJECT_LAST_MESSAGES({ commit }, project_slug) {
      return axios
        .get(`${this.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${project_slug}/comments/`)
        .then((response) => {
          if (response && response.status === 200) {
            commit('SET_PROJECT_COMMENTS', response.data.last_comments);
          }
          return response;
        })
        .catch((error) => {
          throw error;
        });
    },

    /**
     * Asynchronously handles the search request for projects, incorporating search text and applied filters.
     * Cancels any ongoing search request to ensure that only the latest request is processed,
     * which enhances the responsiveness of search functionality.
     *
     * @param {Object} context - Destructured to gain access to Vuex state, rootState, and commit function.
     * @param {String} text - The search text used for filtering projects.
     */
    async HANDLE_PROJECTS_SEARCH_REQUEST({ state, rootState, commit, /* dispatch */ }, { page, text }) {
      // Cancel any ongoing search request.
      if (rootState.cancellableSearchRequest.length > 0) {
        const currentRequestCancelToken =
          rootState.cancellableSearchRequest[rootState.cancellableSearchRequest.length - 1];
        currentRequestCancelToken.cancel();
      }
      //dispatch('CANCEL_CURRENT_SEARCH_REQUEST', null, { root: true });

      // Prepare the cancel token for the new request and store it.
      const cancelToken = axios.CancelToken.source();
      commit('SET_CANCELLABLE_SEARCH_REQUEST', cancelToken, { root: true });

      // Construct the search URL with any applied filters.
      // TODO: Reduce code duplication by merging into GET_PROJECTS/projectAPI.getProjects
      const searchUrl = constructSearchUrl({
        baseUrl: rootState.configuration.VUE_APP_DJANGO_API_BASE,
        filters: state.filters,
        text,
        page
      });
      //console.log('HANDLE_PROJECTS_SEARCH_REQUEST', searchUrl);

      try {
        // Perform the search request.
        const response = await axios.get(searchUrl, { cancelToken: cancelToken.token });

        // Process successful response.
        if (response.status === 200 && response.data) {
          commit('SET_PROJECTS', response.data);
          commit('SET_PROJECTS_SEARCH_STATE', {
            isSearched: true,
            text: text
          });
        }
      } catch (error) {
        // Handle potential errors, such as request cancellation.
        console.error('Search request canceled or failed', error);
      }
    }
  }
};

export default projectsStore;