Merge pull request #30 from tainacan/11-basic-textual-search-on-the-collection-items-list

#11 basic textual search on the collection items list
This commit is contained in:
Mateus Machado Luna 2022-06-30 09:27:51 -03:00 committed by GitHub
commit a27deaa190
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 126 additions and 30 deletions

View File

@ -26,6 +26,8 @@ export const translationStrings = {
label_option_multiple_attachments: 'Single item with document and attachments from file selection',
label_option_single_item: 'Single empty item',
label_cancel: 'Cancel',
label_search: 'Search',
label_no_results_found: 'No results found',
info_application_password: 'This password is not the same of your WordPress admin.',
label_learn_more_here: 'Learn more here'
},
@ -56,6 +58,8 @@ export const translationStrings = {
label_option_multiple_attachments: 'Um item com documento e anexos provenientes de ums seleção de aquivos',
label_option_single_item: 'Um item vazio',
label_cancel: 'Cancelar',
label_search: 'Buscar',
label_no_results_found: 'Nenhum resultado encontrado',
info_application_password: 'Esta senha não é a mesma do seu painel admin do WordPress.',
label_learn_more_here: 'Saiba mais aqui.'
}

View File

@ -5,11 +5,21 @@
<ion-refresher slot="fixed" @ionRefresh="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
<ion-toolbar>
<ion-searchbar debounce="500" :placeholder="$t('label_search')" @ionChange="handleSearch($event)"></ion-searchbar>
</ion-toolbar>
<ion-loading
:is-open="isLoading"
:message="$t('label_loading')"
>
</ion-loading>
<ion-spinner v-if="isSearching"></ion-spinner>
<div
v-if="!isLoading && !isSearching && (!tainacanStore.totalCollectionItems || tainacanStore.totalCollectionItems == '0')"
class="results-not-found"
>
<span> {{$t('label_no_results_found')}} </span>
</div>
<items-list :items="tainacanStore.collectionItems"></items-list>
<ion-infinite-scroll ref="infiniteScroll" threshold="5%" @ionInfinite="loadItemsByCollection">
<ion-infinite-scroll-content>
@ -40,6 +50,9 @@ import {
IonButton,
actionSheetController,
IonInfiniteScroll,
IonToolbar,
IonSearchbar,
IonSpinner,
IonInfiniteScrollContent
} from '@ionic/vue';
import BaseLayout from '@/components/base/BaseLayout.vue';
@ -56,6 +69,9 @@ export default defineComponent({
IonIcon,
IonButton,
IonInfiniteScroll,
IonToolbar,
IonSearchbar,
IonSpinner,
IonInfiniteScrollContent
},
props: {
@ -64,16 +80,37 @@ export default defineComponent({
},
setup(props) {
const isLoading = ref(false);
const isSearching = ref(false)
const search = ref();
const infiniteScroll = ref();
const setIsLoading = (state: boolean) => isLoading.value = state;
const setIsSearching = (state: boolean) => isSearching.value = state;
const setSearch = (value: string) => search.value = value;
const loadItemsByCollection = async (event: any, reset: boolean) => {
let hasMoreCollections = await tainacanStore.fetchItemsByCollection(props.id + '', { perPage: '12', orderBy: 'modified', reset: reset});
await tainacanStore.fetchItemsByCollection(props.id + '', { perPage: '12', orderBy: 'modified', reset: reset, search: search.value});
let hasMoreCollectionsItems = tainacanStore.totalCollectionItems && tainacanStore.totalCollectionItems !== 0;
if (event && event.target)
event.target.complete();
if (!hasMoreCollections){
if (!hasMoreCollectionsItems){
infiniteScroll.value.$el.disabled = true;
}
}
const cancelSearch = async () => {
await loadItemsByCollection(null, true);
}
const handleSearch = async (event: any) => {
let search = event && event.detail && event.detail.value;
setSearch(search);
setIsSearching(true);
if(search !== '') {
await loadItemsByCollection(null, true);
} else {
await cancelSearch();
}
setIsSearching(false);
}
const doRefresh = async (event: any) => {
await loadItemsByCollection({}, true);
if (event && event.target){
@ -146,6 +183,7 @@ export default defineComponent({
let tainacanStore = useTainacanStore();
return {
isLoading,
isSearching,
tainacanStore,
wpStore,
setIsLoading,
@ -156,7 +194,8 @@ export default defineComponent({
actionSheetLabels,
setActionSheetLabels,
collectionObject,
infiniteScroll
infiniteScroll,
handleSearch,
}
},
async created() {
@ -176,15 +215,18 @@ export default defineComponent({
</script>
<style>
.add-items-button {
position: fixed;
bottom: 16px;
right: 16px;
height: 52px;
--padding-start: 24px;
--padding-bottom: 16px;
--padding-top: 16px;
--padding-end: 24px;
--border-radius: 18px;
}
.add-items-button {
position: fixed;
bottom: 16px;
right: 16px;
height: 52px;
--padding-start: 24px;
--padding-bottom: 16px;
--padding-top: 16px;
--padding-end: 24px;
--border-radius: 18px;
}
ion-spinner {
margin-top: 2rem;
}
</style>

View File

@ -5,10 +5,18 @@
:message="$t('label_loading')"
>
</ion-loading>
<ion-toolbar>
<ion-searchbar debounce="500" :placeholder="$t('label_search')" @ionChange="handleSearch($event)"></ion-searchbar>
</ion-toolbar>
<ion-refresher slot="fixed" @ionRefresh="doRefresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
<ion-spinner v-if="isSearching"></ion-spinner>
<div v-if="!isLoading && !isSearching && (!tainacanStore.totalItems || tainacanStore.totalItems == '0')" class="results-not-found">
<span> {{$t('label_no_results_found')}} </span>
</div>
<items-list :items="tainacanStore.items"></items-list>
<ion-infinite-scroll ref="infiniteScroll" threshold="5%" @ionInfinite="loadItems">
<ion-infinite-scroll-content>
</ion-infinite-scroll-content>
@ -25,6 +33,9 @@ import {
IonRefresher,
IonRefresherContent,
IonInfiniteScroll,
IonToolbar,
IonSearchbar,
IonSpinner,
IonInfiniteScrollContent
} from '@ionic/vue';
import BaseLayout from '@/components/base/BaseLayout.vue';
@ -38,20 +49,45 @@ export default {
IonRefresher,
IonRefresherContent,
IonInfiniteScroll,
IonToolbar,
IonSearchbar,
IonSpinner,
IonInfiniteScrollContent
},
setup() {
const isLoading = ref(false);
const isSearching = ref(false)
const search = ref();
const setIsLoading = (state: boolean) => isLoading.value = state;
const setIsSearching = (state: boolean) => isSearching.value = state;
const setSearch = (value: string) => search.value = value;
const infiniteScroll = ref();
const loadItems = async (event: any, reset: boolean) => {
let hasMoreItems = await tainacanStore.fetchItems({ perPage: '12', orderBy: 'modified', reset: reset});
await tainacanStore.fetchItems({ perPage: '12', orderBy: 'modified', reset: reset, search: search.value});
let hasMoreItems = tainacanStore.totalItems && tainacanStore.totalItems !== 0;
if (event && event.target)
event.target.complete();
if (!hasMoreItems){
infiniteScroll.value.$el.disabled = true;
}
}
const cancelSearch = async () => {
await loadItems(null, true);
}
const handleSearch = async (event: any) => {
let search = event && event.detail && event.detail.value;
setSearch(search);
setIsSearching(true);
if(search !== '') {
await loadItems(null, true);
setIsSearching(false);
} else {
await cancelSearch();
}
setIsSearching(false);
}
const doRefresh = async (event: any) => {
await loadItems({}, true);
if (event && event.target){
@ -62,11 +98,13 @@ export default {
let tainacanStore = useTainacanStore();
return {
isLoading,
isSearching,
setIsLoading,
tainacanStore,
doRefresh,
loadItems,
infiniteScroll
infiniteScroll,
handleSearch
}
},
async created(){
@ -76,3 +114,9 @@ export default {
},
}
</script>
<style scoped>
ion-spinner {
margin-top: 2rem;
}
</style>

View File

@ -77,7 +77,7 @@ const useTainacanStore = defineStore("tainacan", {
}
},
async fetchItemsByCollection(collectionId: string, params: { perPage: string, orderBy: string, reset: boolean }) {
async fetchItemsByCollection(collectionId: string, params: { perPage: string, orderBy: string, reset?: boolean, search?: string }) {
try {
const wpStore = useWpStore();
@ -94,6 +94,9 @@ const useTainacanStore = defineStore("tainacan", {
else
endpoint += '&orderby=modified';
if (params && params.search && params.search !== '')
endpoint += '&search=' + params.search
if (params.reset) {
this.collectionItems = [];
this.nextItemsByCollectionPage = 1;
@ -110,13 +113,10 @@ const useTainacanStore = defineStore("tainacan", {
this.collectionItems.push(...response.data.items);
this.totalCollectionItems = response.headers['x-wp-total'];
if (!this.totalCollectionItems ||
this.totalCollectionItems === "0") {
return false;
} else {
this.nextItemsByCollectionPage++;
return true;
if (this.totalCollectionItems && this.totalCollectionItems !== "0") {
this.nextItemsByCollectionPage++;
}
} catch (err) {
this.collectionItems = [];
this.totalCollectionItems = 0;
@ -151,7 +151,7 @@ const useTainacanStore = defineStore("tainacan", {
}
},
async fetchItems(params: { perPage: string, orderBy: string, reset: boolean }) {
async fetchItems(params: { perPage: string, orderBy: string, reset?: boolean, search?: string }) {
try {
const wpStore = useWpStore();
@ -164,6 +164,9 @@ const useTainacanStore = defineStore("tainacan", {
if (params && params.orderBy)
endpoint += '&orderby=' + params.orderBy;
if (params && params.search && params.search !== '')
endpoint += '&search=' + params.search
if (params.reset) {
this.items = [];
this.nextItemsPage = 1;
@ -180,12 +183,8 @@ const useTainacanStore = defineStore("tainacan", {
this.items.push(...response.data.items);
this.totalItems = response.headers['x-wp-total'];
if (!this.totalItems ||
this.totalItems === "0") {
return false;
} else {
if (this.totalItems && this.totalItems !== "0") {
this.nextItemsPage++;
return true;
}
} catch (err) {

View File

@ -0,0 +1,7 @@
ion-spinner {
display: block;
margin: auto;
}
.results-not-found {
text-align: center;
}