Skip to content

Commit

Permalink
Merge pull request #464 from hotwax/#463
Browse files Browse the repository at this point in the history
Kit UI (#463)
  • Loading branch information
ravilodhi authored Nov 19, 2024
2 parents 90fa26b + f2c1ee8 commit c54ae7d
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 19 deletions.
42 changes: 40 additions & 2 deletions src/components/ProductListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
</ion-label>
<!-- Only show stock if its not a ship to store order -->
<div slot="end" v-if="!isShipToStoreOrder">
<ion-button v-if="isKit(item)" fill="clear" size="small" @click.stop="fetchKitComponents(item)">
<ion-icon v-if="showKitComponents" color="medium" slot="icon-only" :icon="chevronUpOutline"/>
<ion-icon v-else color="medium" slot="icon-only" :icon="listOutline"/>
</ion-button>

<ion-spinner v-if="isFetchingStock" color="medium" name="crescent" />
<div v-else-if="getProductStock(item.productId).quantityOnHandTotal >= 0" class="atp-info">
<ion-note slot="end"> {{ translate("on hand", { count: getProductStock(item.productId).quantityOnHandTotal ?? '0' }) }} </ion-note>
Expand All @@ -21,24 +26,49 @@
</ion-button>
</div>
</ion-item>

<template v-if="showKitComponents && !getProduct(item.productId)?.productComponents">
<ion-item lines="none">
<ion-skeleton-text animated style="height: 80%;"/>
</ion-item>
<ion-item lines="none">
<ion-skeleton-text animated style="height: 80%;"/>
</ion-item>
</template>
<template v-else-if="showKitComponents && getProduct(item.productId)?.productComponents">
<ion-card v-for="(productComponent, index) in getProduct(item.productId).productComponents" :key="index">
<ion-item lines="none">
<ion-thumbnail slot="start">
<DxpShopifyImg :src="getProduct(productComponent.productIdTo).mainImageUrl" size="small"/>
</ion-thumbnail>
<ion-label>
<p class="overline">{{ getProductIdentificationValue(productIdentificationPref.secondaryId, getProduct(productComponent.productIdTo)) }}</p>
{{ getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(productComponent.productIdTo)) ? getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(productComponent.productIdTo)) : productComponent.productIdTo }}
</ion-label>
</ion-item>
</ion-card>
</template>
</template>

<script lang="ts">
import { computed, defineComponent } from "vue";
import { IonButton, IonIcon, IonItem, IonLabel, IonNote, IonSpinner, IonThumbnail, popoverController } from "@ionic/vue";
import { IonButton, IonCard, IonIcon, IonItem, IonLabel, IonNote, IonSkeletonText, IonSpinner, IonThumbnail, popoverController } from "@ionic/vue";
import { mapGetters, useStore } from 'vuex';
import { getProductIdentificationValue, DxpShopifyImg, translate, useProductIdentificationStore } from '@hotwax/dxp-components'
import { cubeOutline, informationCircleOutline } from 'ionicons/icons'
import { chevronUpOutline, cubeOutline, informationCircleOutline, listOutline } from 'ionicons/icons'
import InventoryDetailsPopover from '@/components/InventoryDetailsPopover.vue'
import { isKit } from '@/utils/order'
export default defineComponent({
name: "ProductListItem",
components: {
IonButton,
IonCard,
IonIcon,
IonItem,
IonLabel,
IonNote,
IonSkeletonText,
IonSpinner,
IonThumbnail,
DxpShopifyImg
Expand All @@ -47,6 +77,7 @@ export default defineComponent({
return {
goodIdentificationTypeId: process.env.VUE_APP_PRDT_IDENT_TYPE_ID,
isFetchingStock: false,
showKitComponents: false
}
},
props: ['item', 'isShipToStoreOrder'],
Expand All @@ -58,6 +89,10 @@ export default defineComponent({
})
},
methods: {
async fetchKitComponents(orderItem: any) {
this.store.dispatch('product/fetchProductComponents', { productId: orderItem.productId })
this.showKitComponents = !this.showKitComponents
},
async fetchProductStock(productId: string) {
this.isFetchingStock = true
await this.store.dispatch('stock/fetchStock', { productId });
Expand All @@ -81,10 +116,13 @@ export default defineComponent({
const productIdentificationStore = useProductIdentificationStore();
let productIdentificationPref = computed(() => productIdentificationStore.getProductIdentificationPref)
return {
chevronUpOutline,
getProductIdentificationValue,
productIdentificationPref,
cubeOutline,
informationCircleOutline,
isKit,
listOutline,
store,
translate
}
Expand Down
10 changes: 9 additions & 1 deletion src/services/ProductService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ const findProducts = async (query: any): Promise <any> => {
cache: true
});
}
const fetchProductComponents = async (params: any): Promise<any> => {
return await api({
url: "performFind",
method: "get",
params
})
}
export const ProductService = {
fetchProducts,
findProducts
findProducts,
fetchProductComponents
}
43 changes: 29 additions & 14 deletions src/store/modules/order/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { translate } from "@hotwax/dxp-components";
import emitter from '@/event-bus'
import store from "@/store";
import { prepareOrderQuery } from "@/utils/solrHelper";
import { getOrderCategory } from "@/utils/order";
import { getOrderCategory, removeKitComponents } from '@/utils/order'

import logger from "@/logger";


Expand Down Expand Up @@ -126,6 +127,12 @@ const actions: ActionTree<OrderState , RootState> ={
resp = await OrderService.getOpenOrders(orderQueryPayload)
if (resp.status === 200 && !hasError(resp) && resp.data.grouped?.orderId?.ngroups > 0) {

const productIds = [] as any;
resp.data.grouped?.orderId?.groups.forEach((order: any) => {
productIds.push(...order.doclist.docs.map((item: any) => item.productId));
});
await this.dispatch('product/fetchProducts', { productIds });

let orders = resp.data.grouped?.orderId?.groups.map((order: any) => {
const orderItem = order.doclist.docs[0]
return {
Expand All @@ -136,7 +143,7 @@ const actions: ActionTree<OrderState , RootState> ={
name: orderItem.customerName
},
statusId: orderItem.orderStatusId,
parts: order.doclist.docs.reduce((arr: Array<any>, item: any) => {
parts: removeKitComponents(order.doclist.docs.reduce((arr: Array<any>, item: any) => {
const currentOrderPart = arr.find((orderPart: any) => orderPart.orderPartSeqId === item.shipGroupSeqId)
if (!currentOrderPart) {
arr.push({
Expand Down Expand Up @@ -168,7 +175,7 @@ const actions: ActionTree<OrderState , RootState> ={
}

return arr
}, []),
}, [])),
placedDate: orderItem.orderDate,
shippingInstructions: orderItem.shippingInstructions,
shipGroupSeqId: orderItem.shipGroupSeqId,
Expand All @@ -180,8 +187,6 @@ const actions: ActionTree<OrderState , RootState> ={

const total = resp.data.grouped?.orderId?.ngroups;

this.dispatch('product/getProductInformation', { orders })

if(payload.viewIndex && payload.viewIndex > 0) orders = state.open.list.concat(orders)
commit(types.ORDER_OPEN_UPDATED, { orders, total })
emitter.emit("dismissLoader");
Expand Down Expand Up @@ -218,7 +223,7 @@ const actions: ActionTree<OrderState , RootState> ={
const orders = JSON.parse(JSON.stringify(state.open.list)) as any
// As one order can have multiple parts thus checking orderId and partSeq as well before making any api call
if(current.orderId === payload.orderId && current.orderType === orderType && current.part?.orderPartSeqId === payload.orderPartSeqId) {
this.dispatch('product/getProductInformation', { orders: [ current ] })
await this.dispatch('product/getProductInformation', { orders: [ current ] })
await dispatch('fetchShipGroupForOrder');
return current
}
Expand Down Expand Up @@ -254,7 +259,7 @@ const actions: ActionTree<OrderState , RootState> ={
name: orderItem.customerName
},
statusId: orderItem.orderStatusId,
parts: order.doclist.docs.reduce((arr: Array<any>, item: any) => {
parts: removeKitComponents(order.doclist.docs.reduce((arr: Array<any>, item: any) => {
const currentOrderPart = arr.find((orderPart: any) => orderPart.orderPartSeqId === item.shipGroupSeqId)
if (!currentOrderPart) {
arr.push({
Expand All @@ -280,7 +285,7 @@ const actions: ActionTree<OrderState , RootState> ={
}

return arr
}, []),
}, [])),
placedDate: orderItem.orderDate,
shippingInstructions: orderItem.shippingInstructions,
orderType: orderType,
Expand Down Expand Up @@ -345,6 +350,12 @@ const actions: ActionTree<OrderState , RootState> ={
try {
resp = await OrderService.getPackedOrders(orderQueryPayload)
if (resp.status === 200 && resp.data.grouped?.orderId?.ngroups > 0 && !hasError(resp)) {
const productIds = [] as any;
resp.data.grouped?.orderId?.groups.forEach((order: any) => {
productIds.push(...order.doclist.docs.map((item: any) => item.productId));
});
await this.dispatch('product/fetchProducts', { productIds });

let orders = resp?.data?.grouped?.orderId?.groups.map((order: any) => {
const orderItem = order.doclist.docs[0]
return {
Expand All @@ -357,7 +368,7 @@ const actions: ActionTree<OrderState , RootState> ={
name: orderItem.customerName,
},
statusId: orderItem.orderStatusId,
parts: order.doclist.docs.reduce((arr: Array<any>, item: any) => {
parts: removeKitComponents(order.doclist.docs.reduce((arr: Array<any>, item: any) => {
const currentOrderPart = arr.find((orderPart: any) => orderPart.orderPartSeqId === item.shipGroupSeqId)
if (!currentOrderPart) {
arr.push({
Expand All @@ -381,7 +392,7 @@ const actions: ActionTree<OrderState , RootState> ={
}

return arr
}, []),
}, [])),
placedDate: orderItem.orderDate,
shippingInstructions: orderItem.shippingInstructions,
pickers: orderItem.pickers ? (orderItem.pickers.reduce((names: any, picker: string) => {
Expand All @@ -396,7 +407,6 @@ const actions: ActionTree<OrderState , RootState> ={
shipGroupSeqId: orderItem.shipGroupSeqId
}
})
this.dispatch('product/getProductInformation', { orders });

const total = resp.data.grouped?.orderId?.ngroups;

Expand Down Expand Up @@ -431,6 +441,12 @@ const actions: ActionTree<OrderState , RootState> ={
try {
resp = await OrderService.getCompletedOrders(orderQueryPayload)
if (resp.status === 200 && resp.data.grouped?.orderId?.ngroups > 0 && !hasError(resp)) {
const productIds = [] as any;
resp.data.grouped?.orderId?.groups.forEach((order: any) => {
productIds.push(...order.doclist.docs.map((item: any) => item.productId));
});
await this.dispatch('product/fetchProducts', { productIds });

let orders = resp?.data?.grouped?.orderId?.groups.map((order: any) => {
const orderItem = order.doclist.docs[0]
return {
Expand All @@ -441,7 +457,7 @@ const actions: ActionTree<OrderState , RootState> ={
name: orderItem.customerPartyName,
},
statusId: orderItem.orderStatusId,
parts: order.doclist.docs.reduce((arr: Array<any>, item: any) => {
parts: removeKitComponents(order.doclist.docs.reduce((arr: Array<any>, item: any) => {
const currentOrderPart = arr.find((orderPart: any) => orderPart.orderPartSeqId === item.shipGroupSeqId)
if (!currentOrderPart) {
arr.push({
Expand All @@ -461,12 +477,11 @@ const actions: ActionTree<OrderState , RootState> ={
}

return arr
}, []),
}, [])),
placedDate: orderItem.orderDate,
shipGroupSeqId: orderItem.shipGroupSeqId
}
})
this.dispatch('product/getProductInformation', { orders });

const total = resp.data.grouped?.orderId?.ngroups;

Expand Down
44 changes: 44 additions & 0 deletions src/store/modules/product/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,50 @@ const actions: ActionTree<ProductState, RootState> = {

clearProducts ({ commit }) {
commit(types.PRODUCT_LIST_UPDATED, { products: [], total: 0, queryString: '' })
},

async fetchProductComponents ( { commit, dispatch, state }, { productId }) {
// If there are no products skip the API call
if (productId === '') return;

const cachedProductIds = Object.keys(state.cached);
if (!cachedProductIds.includes(productId)) {
await dispatch('fetchProducts', { productIds: [productId] })
}
const product = state.cached[productId]
if (product.productComponents && product.productComponents.length > 0) {
return;
}

let resp;
try {
resp = await ProductService.fetchProductComponents({
"entityName": "ProductAssoc",
"inputFields": {
"productId": productId,
"productTypeId": "PRODUCT_COMPONENT"
},
"fieldList": ["productId", "productIdTo", "productAssocTypeId"],
"viewIndex": 0,
"viewSize": 250, // maximum records we could have
"distinct": "Y",
"noConditionFind": "Y",
"filterByDate": "Y"
})
if (!hasError(resp)) {
const productComponents = resp.data.docs;
const componentProductIds = productComponents.map((productComponent: any) => productComponent.productIdTo);
await dispatch('fetchProducts', { productIds: componentProductIds })

product["productComponents"] = productComponents;
commit(types.PRODUCT_ADD_TO_CACHED_MULTIPLE, { products: [product] });
} else {
throw resp.data
}
} catch(err) {
logger.error('Failed to fetch product components information', err)
}
return resp;
}
}

Expand Down
39 changes: 38 additions & 1 deletion src/utils/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,43 @@ const getOrderCategory = (order: any) => {
return result;
}

const isKit = (item: any) => {
const product = store.getters['product/getProduct'](item.productId);
return product && product.productTypeId === 'MARKETING_PKG_PICK';
}

const removeKitComponents = (parts: any) => {
const kitItemSeqIds = new Set();

// Process and update parts
const updatedParts = parts.map((part: any) => {
const updatedItems = [] as any;

part.items.forEach((item: any) => {
const product = store.getters['product/getProduct'](item.productId);
if (product && product.productTypeId === "MARKETING_PKG_PICK") {
kitItemSeqIds.add(item.orderItemSeqId);
}
});

//In current implementation kit product and component product will have the same orderItemSeqId
part.items.forEach((item: any) => {
const product = store.getters['product/getProduct'](item.productId);
if ((product && product.productTypeId === "MARKETING_PKG_PICK") || !kitItemSeqIds.has(item.orderItemSeqId)) {
item["productTypeId"] = product ? product.productTypeId : null;
updatedItems.push(item);
}
});

return { ...part, items: updatedItems };
});

return updatedParts;
};


export {
getOrderCategory
getOrderCategory,
isKit,
removeKitComponents
}
2 changes: 1 addition & 1 deletion src/views/Orders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
</ion-label>
</ion-item>

<ProductListItem v-for="item in order.part.items" :key="item.productId" :item="item" />
<ProductListItem v-for="item in order.part.items" :key="item.productId" :item="item"/>

<ion-item v-if="order.customer.phoneNumber">
<ion-icon :icon="callOutline" slot="start" />
Expand Down

0 comments on commit c54ae7d

Please sign in to comment.