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;