diff --git a/src/components/Project/FeaturesListAndMap/FeaturesListAndMapFilters.vue b/src/components/Project/FeaturesListAndMap/FeaturesListAndMapFilters.vue index ecefd999458cfbcd174bd6ae9402a7bc5d5b508b..e9cd4eccf262582149aa6b429eb5e6345724a61a 100644 --- a/src/components/Project/FeaturesListAndMap/FeaturesListAndMapFilters.vue +++ b/src/components/Project/FeaturesListAndMap/FeaturesListAndMapFilters.vue @@ -142,13 +142,27 @@ :class="['field column', { 'disabled': !isOnline }]" > <label>Type</label> - <Dropdown - :options="featureTypeTitles" - :selected="form.type.selected" - :selection.sync="form.type.selected" - :search="true" - :clearable="true" - /> + <Multiselect + v-model="form.type.selected" + :options="featureTypeOptions" + :multiple="true" + track-by="slug" + label="title" + :close-on-select="false" + > + <template slot="clear"> + <div + v-if="form.type.selected" + class="multiselect__clear" + @click.prevent.stop="form.type.selected = ''" + > + <i + class="close icon" + aria-hidden="true" + /> + </div> + </template> + </Multiselect> </div> <div id="statut" @@ -200,6 +214,7 @@ <script> import { mapState, mapGetters } from 'vuex'; +import Multiselect from 'vue-multiselect'; import { statusChoices, allowedStatus2change } from '@/utils'; @@ -217,7 +232,8 @@ export default { name: 'FeaturesListAndMapFilters', components: { - Dropdown + Dropdown, + Multiselect }, props: { @@ -295,6 +311,9 @@ export default { featureTypeTitles() { return this.feature_types.map((el) => el.title); }, + featureTypeOptions() { + return this.feature_types.map((el) => ({ title: el.title, slug: el.slug })); + }, filteredStatusChoices() { //* if project is not moderate, remove pending status return statusChoices.filter((el) => diff --git a/src/services/feature-api.js b/src/services/feature-api.js index 04e9400fb61c06eed4e2c6bb6e704c8d8b9a5b40..aa2ba11505e7b567aa9feae4b84ee3deab83d630 100644 --- a/src/services/feature-api.js +++ b/src/services/feature-api.js @@ -3,10 +3,10 @@ import store from '../store'; const featureAPI = { - async getFeaturesBbox(project_slug, queryParams) { + async getFeaturesBbox(project_slug, queryString) { const baseUrl = store.state.configuration.VUE_APP_DJANGO_API_BASE; const response = await axios.get( - `${baseUrl}projects/${project_slug}/feature-bbox/${queryParams ? '?' + queryParams : ''}` + `${baseUrl}projects/${project_slug}/feature-bbox/${queryString ? '?' + queryString : ''}` ); if ( response.status === 200 && diff --git a/src/views/Feature/FeatureDetail.vue b/src/views/Feature/FeatureDetail.vue index 9068857a9ba1f8542588e13f2ecb36970d7da9da..e026674d96e069f8287afa7a1fe9fbb9699c20c5 100644 --- a/src/views/Feature/FeatureDetail.vue +++ b/src/views/Feature/FeatureDetail.vue @@ -508,7 +508,6 @@ export default { project_slug: this.slug, features: [this.currentFeature], featureTypes: this.feature_types, - addToMap: true, }); mapService.fitExtent(buffer(featureGroup.getExtent(),200)); diff --git a/src/views/Project/FeaturesListAndMap.vue b/src/views/Project/FeaturesListAndMap.vue index e25a394279fc71c27cf486a1e6eaccbc0c0a350e..51ff2a5729f55da9fbfed2de212889b932713859 100644 --- a/src/views/Project/FeaturesListAndMap.vue +++ b/src/views/Project/FeaturesListAndMap.vue @@ -241,9 +241,21 @@ export default { resetPagination() { this.pagination = { ...initialPagination }; }, + + /** + * Updates the filters based on the provided key-value pair. + * If the filter is 'title', it updates the form's 'title' property. + * Otherwise, it updates the 'selected' property of the corresponding filter. + * + * @param {Object} e - The key-value pair representing the filter to update. + */ setFilters(e) { const filter = Object.keys(e)[0]; - const value = Object.values(e)[0]; + let value = Object.values(e)[0]; + if (value && Array.isArray(value)) { + value = value.map(el => el.slug); + } + // TODO: REMOVE 'selected' (and simplify method) if (filter === 'title') { this.form[filter] = value; } else { @@ -295,18 +307,19 @@ export default { const promises = this.checkedFeatures.map( (feature_id) => this.DELETE_FEATURE({ feature_id, noFeatureType: true }) ); - Promise.all(promises).then((response) => { - const deletedFeaturesCount = response.reduce((acc, curr) => curr.status === 204 ? acc += 1 : acc, 0); - const newFeaturesCount = initialFeaturesCount - deletedFeaturesCount; - const newPagesArray = this.createPagesArray(newFeaturesCount, this.pagination.pagesize); - const newLastPageNum = newPagesArray[newPagesArray.length - 1]; - this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []); - if (initialCurrentPage > newLastPageNum) { //* if page doesn't exist anymore - this.toPage(newLastPageNum); //* go to new last page - } else { - this.fetchPagedFeatures(); - } - }) + Promise.all(promises) + .then((response) => { + const deletedFeaturesCount = response.reduce((acc, curr) => curr.status === 204 ? acc += 1 : acc, 0); + const newFeaturesCount = initialFeaturesCount - deletedFeaturesCount; + const newPagesArray = this.createPagesArray(newFeaturesCount, this.pagination.pagesize); + const newLastPageNum = newPagesArray[newPagesArray.length - 1]; + this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []); + if (initialCurrentPage > newLastPageNum) { //* if page doesn't exist anymore + this.toPage(newLastPageNum); //* go to new last page + } else { + this.fetchPagedFeatures(); + } + }) .catch((err) => console.error(err)); this.toggleDeleteModal(); }, @@ -361,9 +374,9 @@ export default { this.fetchPagedFeatures(); }, - fetchBboxNfit(queryParams) { + fetchBboxNfit(queryString) { featureAPI - .getFeaturesBbox(this.projectSlug, queryParams) + .getFeaturesBbox(this.projectSlug, queryString) .then((bbox) => { if (bbox) { mapService.fitBounds(bbox); @@ -387,48 +400,39 @@ export default { return result; }, - buildQueryString() { - let queryString = ''; - const typeFilter = this.getFeatureTypeSlug(this.form.type.selected); + updateQueryParams() { + const typeFilter = this.form.type.selected; const statusFilter = this.form.status.selected.value; - this.queryparams['offset'] = this.pagination.start; if (typeFilter) { this.queryparams['feature_type_slug'] = typeFilter; - queryString += `&feature_type_slug=${typeFilter}`; } if (statusFilter) { this.queryparams['status__value'] = statusFilter; - queryString += `&status__value=${statusFilter}`; } if (this.form.title) { this.queryparams['title'] = this.form.title; - queryString += `&title=${this.form.title}`; } if (this.sort.column) { let ordering = `${this.sort.ascending ? '-' : ''}${this.getAvalaibleField(this.sort.column)}`; this.queryparams['ordering'] = ordering; - queryString += `&ordering=${ordering}`; } - return queryString; }, - fetchPagedFeatures(newUrl) { + fetchPagedFeatures() { if (!this.isOnline) { this.DISPLAY_MESSAGE({ comment: 'Les signalements du projet non mis en cache ne sont pas accessibles en mode déconnecté', }); return; } + let url = `${this.API_BASE_URL}projects/${this.projectSlug}/feature-paginated/?limit=${this.pagination.pagesize}&offset=${this.pagination.start}`; - //* if receiving next & previous url (// todo : might be not used anymore, to check) - if (newUrl && typeof newUrl === 'string') { - //newUrl = newUrl.replace("8000", "8010"); //* for dev uncomment when using proxy link - url = newUrl; + this.updateQueryParams(); + const queryString = new URLSearchParams(this.queryparams).toString(); + if (queryString) { + url += queryString; } - const queryString = this.buildQueryString(); - - url += queryString; this.$store.commit( 'DISPLAY_LOADER', 'Récupération des signalements en cours...' @@ -476,10 +480,7 @@ export default { handleSortChange(sort) { this.sort = sort; - this.fetchPagedFeatures({ - filterType: undefined, - filterValue: undefined, - }); + this.fetchPagedFeatures(); }, toPage(pageNumber) {