Skip to content

Commit

Permalink
Merge pull request #537 from R-Sourabh/#531-pagination
Browse files Browse the repository at this point in the history
Implemented: Pagination & searching on the landing pages of Admin side(#531)
  • Loading branch information
ymaheshwari1 authored Dec 20, 2024
2 parents 59bfcdc + a45826e commit 1acf71b
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 48 deletions.
12 changes: 11 additions & 1 deletion src/components/Filters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
<ion-checkbox :value="query.noFacility" @ionChange="updateQuery('noFacility', $event.detail.checked)">{{ translate("No facility") }}</ion-checkbox>
</ion-item>

<ion-item lines="none">
<ion-icon slot="start" :icon="swapVerticalOutline" />
<ion-select :label="translate('Sort by')" :value="query.sortBy" @ionChange="updateQuery('sortBy', $event.detail.value)" interface="popover">
<ion-select-option value="dueDate desc">{{ translate("Farthest due") }}</ion-select-option>
<ion-select-option value="dueDate asc">{{ translate("Nearest due") }}</ion-select-option>
<ion-select-option value="countImportName asc">{{ translate("Name - A to Z") }}</ion-select-option>
<ion-select-option value="countImportName desc">{{ translate("Name - Z to A") }}</ion-select-option>
</ion-select>
</ion-item>

<template v-if="showAdditionalFilters().selectedFacilities">
<ion-item v-for="facilityId in query.facilityIds" :key="facilityId">
<ion-label>{{ getFacilityName(facilityId) }}</ion-label>
Expand Down Expand Up @@ -137,7 +147,7 @@ import {
IonToolbar
} from "@ionic/vue";
import { computed, ref } from "vue";
import { closeCircleOutline, businessOutline, gitBranchOutline, gitPullRequestOutline, locateOutline } from "ionicons/icons";
import { closeCircleOutline, businessOutline, gitBranchOutline, gitPullRequestOutline, locateOutline, swapVerticalOutline } from "ionicons/icons";
import { translate } from '@/i18n'
import store from "@/store";
import router from "@/router";
Expand Down
5 changes: 5 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
"Failed to submit cycle count for review": "Failed to submit cycle count for review",
"Failed to update items": "Failed to update items",
"Failed to update cycle count information": "Failed to update cycle count information",
"Farthest due": "Farthest due",
"Fetching cycle counts...": "Fetching cycle counts...",
"Field mapping name": "Field mapping name",
"File uploaded successfully.": "File uploaded successfully.",
Expand Down Expand Up @@ -161,8 +162,11 @@
"Make sure you've reviewed the products and their counts before uploading them for review": "Make sure you've reviewed the products and their counts before uploading them for review",
"Map all required fields": "Map all required fields",
"Mapping name": "Mapping name",
"Name - A to Z": "Name - A to Z",
"Name - Z to A": "Name - Z to A",
"New Count": "New Count",
"New mapping": "New mapping",
"Nearest due": "Nearest due",
"No cycle counts found": "No cycle counts found",
"No data found": "No data found",
"No items found": "No items found",
Expand Down Expand Up @@ -272,6 +276,7 @@
"Something went wrong": "Something went wrong",
"Something went wrong, please try again": "Something went wrong, please try again",
"Something went wrong while login. Please contact administrator": "Something went wrong while login. Please contact administrator.",
"Sort by": "Sort by",
"Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.": "Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.",
"Status": "Status",
"STAY": "STAY",
Expand Down
5 changes: 4 additions & 1 deletion src/store/modules/count/CountState.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
export default interface CountState {
list: Array<any>,
total: number,
isScrollable: boolean,
query: {
facilityIds: Array<string>,
noFacility: boolean
noFacility: boolean,
queryString: string,
sortBy: string
},
stats: any;
cycleCounts: any;
Expand Down
40 changes: 29 additions & 11 deletions src/store/modules/count/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import CountState from "./CountState"
import * as types from "./mutation-types"
import { CountService } from "@/services/CountService"
import { hasError, showToast } from "@/utils"
import emitter from "@/event-bus"
import { translate } from "@/i18n"
import router from "@/router"
import logger from "@/logger";
import { DateTime } from "luxon"

const actions: ActionTree<CountState, RootState> = {
async fetchCycleCounts({ commit, dispatch, state }, payload) {
emitter.emit("presentLoader", { message: "Fetching cycle counts...", backdropDismiss: false })
let counts: Array<any> = [], total = 0;
let counts = state.list ? JSON.parse(JSON.stringify(state.list)) : [], total = 0;
let isScrollable = true

const params = {
...payload,
pageSize: 200
}
// TODO: Currently, the search functionality works only on the count name. Once the API supports searching across
// multiple fields, we should include the count ID in the search parameters.
if(state.query.queryString.length) {
params["countImportName"] = state.query.queryString
params["countImportName_op"] = "contains"
}

if(state.query.facilityIds.length) {
Expand All @@ -34,22 +38,32 @@ const actions: ActionTree<CountState, RootState> = {
}
}

if(state.query.sortBy) {
params["orderByField"] = state.query.sortBy
}

try {
const resp = await CountService.fetchCycleCounts(params);

if(!hasError(resp) && resp.data.length > 0) {
counts = resp.data
if(payload.pageIndex && payload.pageIndex > 0) {
counts = counts.concat(resp.data)
} else {
counts = resp.data
}
total = resp.data.length

dispatch("fetchCycleCountStats", counts.map((count) => count.inventoryCountImportId))
dispatch("fetchCycleCountStats", counts.map((count: any) => count.inventoryCountImportId))
// Determine if more data can be fetched
isScrollable = resp.data.length >= payload.pageSize
} else {
if (payload.pageIndex > 0) isScrollable = false
throw "Failed to fetch the counts"
}
} catch(err) {
isScrollable = false
if(payload.pageIndex == 0) counts = []
logger.error(err)
}
commit(types.COUNT_LIST_UPDATED, { counts, total })
emitter.emit("dismissLoader")
commit(types.COUNT_LIST_UPDATED, { counts, total , isScrollable })
},

async fetchCycleCountStats({ commit }, inventoryCountImportIds) {
Expand Down Expand Up @@ -116,7 +130,11 @@ const actions: ActionTree<CountState, RootState> = {
} else if(router.currentRoute.value.name === "Closed") {
statusId = "INV_COUNT_COMPLETED"
}
dispatch("fetchCycleCounts", { statusId })
dispatch("fetchCycleCounts", { pageSize: process.env.VUE_APP_VIEW_SIZE, pageIndex: 0, statusId })
},

async updateQueryString({ commit }, payload) {
commit(types.COUNT_QUERY_UPDATED, payload)
},

async clearQuery({ commit }) {
Expand Down
3 changes: 3 additions & 0 deletions src/store/modules/count/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const getters: GetterTree<CountState, RootState> = {
getCycleCountsList(state) {
return state.cycleCounts.list ? JSON.parse(JSON.stringify(state.cycleCounts.list)) : []
},
isCycleCountListScrollable(state) {
return state.isScrollable
},
isCycleCountScrollable(state) {
return state.cycleCounts.isScrollable
},
Expand Down
5 changes: 4 additions & 1 deletion src/store/modules/count/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ const countModule: Module<CountState, RootState> = {
state: {
list: [],
total: 0,
isScrollable: true,
query: {
facilityIds: [],
noFacility: false
noFacility: false,
queryString: '',
sortBy: 'dueDate desc'
},
stats: {},
cycleCountImportSystemMessages:[],
Expand Down
5 changes: 4 additions & 1 deletion src/store/modules/count/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ const mutations: MutationTree <CountState> = {
[types.COUNT_LIST_UPDATED](state, payload) {
state.list = payload.counts
state.total = payload.total
state.isScrollable = payload.isScrollable;
},
[types.COUNT_QUERY_UPDATED](state, payload) {
(state.query as any)[payload.key] = payload.value
},
[types.COUNT_QUERY_CLEARED](state) {
state.query = {
facilityIds: [],
noFacility: false
noFacility: false,
queryString: '',
sortBy: 'dueDate desc'
}
},
[types.COUNT_STATS_UPDATED](state, payload) {
Expand Down
5 changes: 5 additions & 0 deletions src/theme/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ http://ionicframework.com/docs/theming/ */
.list-item {
padding: var(--spacer-sm) 0;
}

ion-searchbar.searchbar {
padding-top: var(--spacer-base);
padding-inline: var(--spacer-sm)
}
}

.empty-state {
Expand Down
62 changes: 56 additions & 6 deletions src/views/Assigned.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
</ion-toolbar>
</ion-header>

<ion-content id="filter">
<ion-content ref="contentRef" :scroll-events="true" @ionScroll="enableScrolling()" id="filter">
<ion-searchbar class="searchbar" v-model="query.queryString" @keyup.enter="updateQueryString('queryString', $event.target.value)" />
<p v-if="!cycleCounts.length" class="empty-state">
{{ translate("No cycle counts found") }}
</p>
Expand Down Expand Up @@ -47,31 +48,80 @@
</ion-item>
</div>
</ion-list>

<ion-infinite-scroll ref="infiniteScrollRef" v-show="isScrollable" threshold="100px" @ionInfinite="loadMoreCycleCounts($event)">
<ion-infinite-scroll-content loading-spinner="crescent" :loading-text="translate('Loading')" />
</ion-infinite-scroll>
</ion-content>
</ion-page>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { computed, ref } from "vue";
import { translate } from '@/i18n'
import { filterOutline, storefrontOutline } from "ionicons/icons";
import { IonBadge, IonButtons, IonChip, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonList, IonMenuButton, IonPage, IonTitle, IonToolbar, onIonViewDidEnter, onIonViewWillLeave } from "@ionic/vue";
import { IonBadge, IonButtons, IonChip, IonContent, IonHeader, IonIcon, IonItem, IonInfiniteScroll, IonInfiniteScrollContent, IonLabel, IonList, IonMenuButton, IonPage, IonSearchbar, IonTitle, IonToolbar, onIonViewDidEnter, onIonViewWillLeave } from "@ionic/vue";
import store from "@/store"
import { getCycleCountStats, getDateWithOrdinalSuffix, getDerivedStatusForCount, getFacilityName } from "@/utils"
import Filters from "@/components/Filters.vue"
import router from "@/router"
const cycleCounts = computed(() => store.getters["count/getCounts"])
const isScrollable = computed(() => store.getters["count/isCycleCountListScrollable"])
const query = computed(() => store.getters["count/getQuery"])
const isScrollingEnabled = ref(false);
const contentRef = ref({}) as any
const infiniteScrollRef = ref({}) as any
onIonViewDidEnter(async () => {
await store.dispatch("count/fetchCycleCounts", {
statusId: "INV_COUNT_ASSIGNED"
})
await fetchAssignedCycleCount();
})
onIonViewWillLeave(async () => {
await store.dispatch("count/clearCycleCountList")
})
function enableScrolling() {
const parentElement = contentRef.value.$el
const scrollEl = parentElement.shadowRoot.querySelector("main[part='scroll']")
let scrollHeight = scrollEl.scrollHeight, infiniteHeight = infiniteScrollRef?.value?.$el?.offsetHeight, scrollTop = scrollEl.scrollTop, threshold = 100, height = scrollEl.offsetHeight
const distanceFromInfinite = scrollHeight - infiniteHeight - scrollTop - threshold - height
if(distanceFromInfinite < 0) {
isScrollingEnabled.value = false;
} else {
isScrollingEnabled.value = true;
}
}
async function updateQueryString(key: string, value: any) {
await store.dispatch("count/updateQueryString", { key, value })
fetchAssignedCycleCount();
}
async function loadMoreCycleCounts(event: any) {
if(!(isScrollingEnabled.value && isScrollable.value)) {
await event.target.complete();
}
fetchAssignedCycleCount(
undefined,
Math.ceil(
cycleCounts.value?.length / (process.env.VUE_APP_VIEW_SIZE as any)
).toString()
).then(async () => {
await event.target.complete()})
}
async function fetchAssignedCycleCount(vSize?: any, vIndex?: any) {
const pageSize = vSize ? vSize : process.env.VUE_APP_VIEW_SIZE;
const pageIndex = vIndex ? vIndex : 0;
const payload = {
pageSize,
pageIndex,
statusId: "INV_COUNT_ASSIGNED"
}
await store.dispatch("count/fetchCycleCounts", payload)
}
</script>

<style scoped>
Expand Down
Loading

0 comments on commit 1acf71b

Please sign in to comment.