Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/hotwax/bopis into bopis/hot…
Browse files Browse the repository at this point in the history
…wax#178-productIdentifier
  • Loading branch information
amansinghbais committed Oct 11, 2023
2 parents a02052f + 9a779b9 commit c3144ff
Show file tree
Hide file tree
Showing 30 changed files with 459 additions and 160 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ VUE_APP_LOGIN_URL="http://launchpad.hotwax.io/login"
VUE_APP_NOTIF_APP_ID=BOPIS
VUE_APP_NOTIF_ENUM_TYPE_ID=NOTIF_BOPIS
VUE_APP_FIREBASE_CONFIG={"apiKey": "","authDomain": "","databaseURL": "","projectId": "","storageBucket": "","messagingSenderId": "","appId": ""}
VUE_APP_FIREBAE_VAPID_KEY=""
VUE_APP_FIREBASE_VAPID_KEY=""
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@casl/ability": "^6.0.0",
"@hotwax/app-version-info": "^1.0.0",
"@hotwax/apps-theme": "^1.1.0",
"@hotwax/dxp-components": "^1.7.4",
"@hotwax/dxp-components": "^1.7.5",
"@hotwax/oms-api": "^1.10.0",
"@ionic/core": "6.7.5",
"@ionic/vue": "6.7.5",
Expand Down
101 changes: 48 additions & 53 deletions public/firebase-messaging-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,57 @@
importScripts('https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js');

// Initialize a default click_action URL
const clickActionURL = '/notifications';
const iconURL = 'img/icons/msapplication-icon-144x144.png';
// wrapping the logic inside function and calling it as an IIFE
// to provide return statement support
(function () {
const firebaseConfig = { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "" }

const firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
}
if (Object.values(firebaseConfig).some(value => !value)) {
return
}
// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
firebase.initializeApp(firebaseConfig);

// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
firebase.initializeApp(firebaseConfig);

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.onBackgroundMessage(payload => {
// Customize notification here
const notificationTitle = payload.data.title;
const notificationOptions = {
body: payload.data.body,
icon: iconURL,
data: {
click_action: clickActionURL
}
};
self.registration.showNotification(notificationTitle, notificationOptions);
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.onBackgroundMessage(payload => {
// Customize notification here
const notificationTitle = payload.data.title;
const notificationOptions = {
body: payload.data.body,
icon: "/img/icons/msapplication-icon-144x144.png",
data: {
click_action: "/notifications"
}
};
self.registration.showNotification(notificationTitle, notificationOptions);

// broadcast background message on FB_BG_MESSAGES so that app can receive that message
const broadcast = new BroadcastChannel('FB_BG_MESSAGES');
broadcast.postMessage(payload);
});
// broadcast background message on FB_BG_MESSAGES so that app can receive that message
const broadcast = new BroadcastChannel('FB_BG_MESSAGES');
broadcast.postMessage(payload);
});

self.addEventListener('notificationclick', event => {
event.notification.close();
const deepLink = event.notification.data.click_action;
event.waitUntil(
clients.matchAll({ includeUncontrolled: true, type: 'window' }).then(windowClients => {
// Check if the app window is already open
for (let client of windowClients) {
const clientPath = (new URL(client.url)).pathname;
if (clientPath === deepLink && 'focus' in client) {
return client.focus();
self.addEventListener('notificationclick', event => {
event.notification.close();
const deepLink = event.notification.data.click_action;
event.waitUntil(
clients.matchAll({ includeUncontrolled: true, type: 'window' }).then(windowClients => {
// Check if the app window is already open
for (let client of windowClients) {
const clientPath = (new URL(client.url)).pathname;
if (clientPath === deepLink && 'focus' in client) {
return client.focus();
}
}
}

// If the app window is not open, open a new one
if (clients.openWindow) {
return clients.openWindow(deepLink);
}
})
);
});
// If the app window is not open, open a new one
if (clients.openWindow) {
return clients.openWindow(deepLink);
}
})
);
});
})()
12 changes: 8 additions & 4 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ export default defineComponent({
}
},
methods: {
async presentLoader() {
async presentLoader(options = { message: '', backdropDismiss: true }) {
// When having a custom message remove already existing loader
if(options.message && this.loader) this.dismissLoader();
// if currently loader is not present then creating a new loader
if (!this.loader) {
this.loader = await loadingController
.create({
message: this.$t("Click the backdrop to dismiss."),
message: options.message ? this.$t(options.message) : this.$t("Click the backdrop to dismiss."),
translucent: true,
backdropDismiss: true
backdropDismiss: options.backdropDismiss
});
}
this.loader.present();
Expand All @@ -46,7 +49,8 @@ export default defineComponent({
}
},
async unauthorised() {
this.store.dispatch("user/logout");
// Mark the user as unauthorised, this will help in not making the logout api call in actions
this.store.dispatch("user/logout", { isUserUnauthorised: true });
const redirectUrl = window.location.origin + '/login'
window.location.href = `${process.env.VUE_APP_LOGIN_URL}?redirectUrl=${redirectUrl}`
}
Expand Down
4 changes: 4 additions & 0 deletions src/adapter/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
api,
client,
getConfig,
getProductIdentificationPref,
hasError,
getUserFacilities,
getNotificationEnumIds,
getNotificationUserPrefTypeIds,
initialise,
logout,
resetConfig,
removeClientRegistrationToken,
setProductIdentificationPref,
Expand All @@ -20,12 +22,14 @@ import {
export {
api,
client,
getConfig,
getProductIdentificationPref,
hasError,
getUserFacilities,
getNotificationEnumIds,
getNotificationUserPrefTypeIds,
initialise,
logout,
resetConfig,
removeClientRegistrationToken,
setProductIdentificationPref,
Expand Down
1 change: 1 addition & 0 deletions src/authorization/Actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
'APP_ORDER_UPDATE': 'APP_ORDER_UPDATE',
'APP_RF_CONFIG_UPDATE': 'APP_RF_CONFIG_UPDATE',
'APP_PARTIAL_ORDER_REJECTION_CONFIG_UPDATE': 'APP_PARTIAL_ORDER_REJECTION_CONFIG_UPDATE',
}
1 change: 1 addition & 0 deletions src/authorization/Rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export default {
"APP_PRODUCT_DETAIL_VIEW": "",
"APP_ORDER_UPDATE": "COMMON_ADMIN",
"APP_RF_CONFIG_UPDATE": "COMMON_ADMIN",
"APP_PARTIAL_ORDER_REJECTION_CONFIG_UPDATE": "COMMON_ADMIN",
"APP_STOREFULFILLMENT_ADMIN": "STOREFULFILLMENT_ADMIN"
} as any
29 changes: 13 additions & 16 deletions src/components/NotificationPreferenceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@ import { translate } from "@/i18n";
import { showToast } from "@/utils";
import emitter from "@/event-bus"
import { generateTopicName } from "@/utils/firebase";
import {
subscribeTopic,
unsubscribeTopic
} from '@/adapter';
import { subscribeTopic, unsubscribeTopic } from '@/adapter'
export default defineComponent({
name: "NotificationPreferenceModal",
Expand All @@ -78,7 +75,7 @@ export default defineComponent({
data() {
return {
notificationPrefState: {} as any,
notificationPrefToUpate: {
notificationPrefToUpdate: {
subscribe: [],
unsubscribe: []
} as any,
Expand All @@ -87,6 +84,7 @@ export default defineComponent({
},
computed: {
...mapGetters({
userProfile: 'user/getUserProfile',
currentFacility: 'user/getCurrentFacility',
instanceUrl: 'user/getInstanceUrl',
notificationPrefs: 'user/getNotificationPrefs'
Expand Down Expand Up @@ -114,16 +112,16 @@ export default defineComponent({
// running when the ion-toggle hydrates and hence, updated the
// initialNotificationPrefState here
const value = !event.target.checked
// updates the notificationPrefToUpate to check which pref
// updates the notificationPrefToUpdate to check which pref
// values were updated from their initial values
if (value !== this.initialNotificationPrefState[enumId]) {
value
? this.notificationPrefToUpate.subscribe.push(enumId)
: this.notificationPrefToUpate.unsubscribe.push(enumId)
? this.notificationPrefToUpdate.subscribe.push(enumId)
: this.notificationPrefToUpdate.unsubscribe.push(enumId)
} else {
!value
? this.notificationPrefToUpate.subscribe.splice(this.notificationPrefToUpate.subscribe.indexOf(enumId), 1)
: this.notificationPrefToUpate.unsubscribe.splice(this.notificationPrefToUpate.subscribe.indexOf(enumId), 1)
? this.notificationPrefToUpdate.subscribe.splice(this.notificationPrefToUpdate.subscribe.indexOf(enumId), 1)
: this.notificationPrefToUpdate.unsubscribe.splice(this.notificationPrefToUpdate.subscribe.indexOf(enumId), 1)
}
// updating this.notificationPrefState as it is used to
Expand All @@ -132,7 +130,6 @@ export default defineComponent({
this.notificationPrefState[enumId] = value
},
async updateNotificationPref() {
// TODO disbale button if initial and final are same
// added loader as the API call is in pending state for too long, blocking the flow
emitter.emit("presentLoader");
try {
Expand All @@ -144,17 +141,17 @@ export default defineComponent({
}
},
async handleTopicSubscription() {
const oms = this.instanceUrl
const ofbizInstanceName = this.userProfile.ofbizInstanceName
const facilityId = (this.currentFacility as any).facilityId
const subscribeRequests = [] as any
this.notificationPrefToUpate.subscribe.map(async (enumId: string) => {
const topicName = generateTopicName(oms, facilityId, enumId)
this.notificationPrefToUpdate.subscribe.map(async (enumId: string) => {
const topicName = generateTopicName(ofbizInstanceName, facilityId, enumId)
await subscribeRequests.push(subscribeTopic(topicName, process.env.VUE_APP_NOTIF_APP_ID))
})
const unsubscribeRequests = [] as any
this.notificationPrefToUpate.unsubscribe.map(async (enumId: string) => {
const topicName = generateTopicName(oms, facilityId, enumId)
this.notificationPrefToUpdate.unsubscribe.map(async (enumId: string) => {
const topicName = generateTopicName(ofbizInstanceName, facilityId, enumId)
await unsubscribeRequests.push(unsubscribeTopic(topicName, process.env.VUE_APP_NOTIF_APP_ID))
})
Expand Down
40 changes: 34 additions & 6 deletions src/components/ProductListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,40 @@
<p v-if="$filters.getFeature(getProduct(item.productId).featureHierarchy, '1/SIZE/')">{{ $t("Size") }}: {{ $filters.getFeature(getProduct(item.productId).featureHierarchy, '1/SIZE/') }}</p>
</ion-label>
<!-- Only show stock if its not a ship to store order -->
<ion-note v-if="!isShipToStoreOrder" slot="end">{{ getProductStock(item.productId) }} {{ $t("in stock") }}</ion-note>
<div v-if="!isShipToStoreOrder">
<ion-note v-if="getProductStock(item.productId).quantityOnHandTotal >= 0">
{{ getProductStock(item.productId).quantityOnHandTotal }} {{ $t('pieces in stock') }}
</ion-note>
<ion-spinner v-else-if="isFetchingStock" color="medium" name="crescent" />
<ion-button v-else fill="clear" @click.stop="fetchProductStock(item.productId)">
<ion-icon color="medium" slot="icon-only" :icon="cubeOutline"/>
</ion-button>
</div>
</ion-item>
</template>

<script lang="ts">
import { IonItem, IonLabel, IonNote, IonThumbnail } from "@ionic/vue";
import { mapGetters } from 'vuex';
import { defineComponent } from "vue";
import { IonIcon, IonItem, IonLabel, IonNote, IonSpinner, IonThumbnail } from "@ionic/vue";
import { mapGetters, useStore } from 'vuex';
import { ShopifyImg } from '@hotwax/dxp-components'
import { cubeOutline } from 'ionicons/icons'
export default {
export default defineComponent({
name: "ProductListItem",
components: {
IonIcon,
IonItem,
IonLabel,
IonNote,
IonSpinner,
IonThumbnail,
ShopifyImg
},
data () {
return {
goodIdentificationTypeId: process.env.VUE_APP_PRDT_IDENT_TYPE_ID
goodIdentificationTypeId: process.env.VUE_APP_PRDT_IDENT_TYPE_ID,
isFetchingStock: false
}
},
props: {
Expand All @@ -46,8 +60,22 @@ export default {
getProduct: 'product/getProduct',
getProductStock: 'stock/getProductStock'
})
},
methods: {
async fetchProductStock(productId: string) {
this.isFetchingStock = true
await this.store.dispatch('stock/fetchStock', { productId })
this.isFetchingStock = false
}
},
setup() {
const store = useStore();
return {
cubeOutline,
store
}
}
}
})
</script>

<style>
Expand Down
Loading

0 comments on commit c3144ff

Please sign in to comment.