Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented: in-app notifications state and UI #279

Merged
merged 21 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
07cfe86
Implemented: static UI and logic
k2maan Aug 25, 2023
4ea5a52
Implemented: logic and functionality to show notifications and manage…
k2maan Sep 12, 2023
6902e3c
Improved: code for utils and added toast when notification is added
k2maan Sep 13, 2023
c8285fe
Merge branch 'main' of https://github.com/hotwax/bopis into bopis/not…
k2maan Sep 13, 2023
ca0df0c
Fixed: URLs and removed logs in firebase-messaging-sw file
k2maan Sep 13, 2023
e3d098f
Improved: used firebase vapid key from env
k2maan Sep 13, 2023
f89b9ec
Improved: cleared notifications state on logout
k2maan Sep 13, 2023
a9e416c
Implemented: in-app notifications state and UI
k2maan Sep 14, 2023
11e2897
Improved: showed toast for foreground notifications only
k2maan Sep 14, 2023
9322e85
Fixed: focus if notifications tab is already open
k2maan Sep 15, 2023
4125372
Improved: indentation and removed unused return from fetchNotificatio…
k2maan Sep 15, 2023
478e5ae
Improved: handled case if no prefs are found
k2maan Sep 15, 2023
9f55058
Improved: handling based on OMS service responses
k2maan Sep 15, 2023
be855f3
Fixed: build failure and updated entries for DXP and OMS API
k2maan Sep 15, 2023
e858969
Merge branch 'main' of https://github.com/hotwax/bopis into bopis/not…
k2maan Sep 18, 2023
5f05518
Improved: code to disable save button in preference update modal if i…
k2maan Sep 18, 2023
8620247
Improved: variable and function naming and removed unused imports
k2maan Sep 20, 2023
c7f73a8
Improved: handling for showing toast if preference update fails and c…
k2maan Sep 21, 2023
7f70348
Improved: code for showing toast and parameter type in isDisabled com…
k2maan Sep 21, 2023
0c57a8d
Improved: removed client registration token directly instead of action
k2maan Sep 22, 2023
45277de
Improved: used getter instead of computed property for changing notif…
k2maan Sep 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ VUE_APP_ALIAS=
VUE_APP_CURRENCY_FORMATS={"en": {"currency": {"style": "currency","currency": "USD"}}, "ja": {"currency": {"style": "currency", "currency": "JPY"}}, "es": {"currency": {"style": "currency","currency": "ESP"}}}
VUE_APP_RF_CNFG_MPNG={ "allowDeliveryMethodUpdate": "CUST_DLVRMTHD_UPDATE", "allowDeliveryAddressUpdate": "CUST_DLVRADR_UPDATE", "allowPickupUpdate": "CUST_PCKUP_UPDATE", "allowCancel": "CUST_ALLOW_CNCL", "shippingMethod": "RF_SHIPPING_METHOD"}
VUE_APP_DEFAULT_LOG_LEVEL="error"
VUE_APP_LOGIN_URL="http://launchpad.hotwax.io/login"
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": "AIzaSyAq-jeG6dy8y2O6p_RYKk_MpkfTZ97GF_Q","authDomain": "hotwax-digital-commerce.firebaseapp.com","databaseURL": "https://hotwax-digital-commerce.firebaseio.com","projectId": "hotwax-digital-commerce","storageBucket": "hotwax-digital-commerce.appspot.com","messagingSenderId": "211268342110","appId": "1:211268342110:web:6fa33f0d16129925c27fcf"}
VUE_APP_FIREBAE_VAPID_KEY="BOUIEOumNzijvdsEaG2x3fCmQIupqlvq0tJS4QQSF7C1xrCYC6fYJ-VQWkKKPCZN4GG1jVIVMtdiUVjvbeOXO6w"
2,293 changes: 2,033 additions & 260 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
"@casl/ability": "^6.0.0",
"@hotwax/app-version-info": "^1.0.0",
"@hotwax/apps-theme": "^1.1.0",
"@hotwax/dxp-components": "^1.3.4",
"@hotwax/dxp-components": "^1.6.0",
"@hotwax/oms-api": "^1.10.0",
"@ionic/core": "6.7.5",
"@ionic/vue": "6.7.5",
"@ionic/vue-router": "6.7.5",
"@shopify/app-bridge-utils": "^2.0.4",
"boon-js": "^2.0.3",
"core-js": "^3.6.5",
"firebase": "^10.3.1",
"luxon": "^3.2.0",
"mitt": "^2.1.0",
"register-service-worker": "^1.7.1",
Expand Down
69 changes: 69 additions & 0 deletions public/firebase-messaging-sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here. Other Firebase libraries
// are not available in the service worker.
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';

const firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
}

// 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 => {
console.log(
'[firebase-messaging-sw.js] Received background message ',
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);

// 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();
}
}

// If the app window is not open, open a new one
if (clients.openWindow) {
return clients.openWindow(deepLink);
}
})
);
});
9 changes: 9 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"An email notification will be sent to that their order is ready for pickup. This order will also be moved to the packed orders tab.": "An email notification will be sent to { customerName } that their order is ready for pickup.{ space } This order will also be moved to the packed orders tab.",
"An email notification will be sent to that their order is ready for pickup.": "An email notification will be sent to { customerName } that their order is ready for pickup.",
"Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to?",
"Are you sure you want to update the notification preferences?": "Are you sure you want to update the notification preferences?",
"Arrived": "Arrived",
"Authenticating": "Authenticating",
"Assign Pickers": "Assign Pickers",
Expand Down Expand Up @@ -56,14 +57,21 @@
"Logout": "Logout",
"Mismatch": "Mismatch",
"More": "More",
"New notification received.": "New notification received.",
"No inventory details found": "No inventory details found",
"Not in stock": "Not in stock",
"Not in Stock": "Not in Stock",
"No products found": "No products found",
"No reason": "No reason",
"No notifications to show": "No notifications to show",
"No picker assigned.": "No picker assigned.",
"No picker found": "No picker found",
"No time zone found": "No time zone found",
"Notifications": "Notifications",
"Notification Preference": "Notification Preference",
"Notification preferences not found.": "Notification preferences not found.",
"Notification preferences updated.": "Notification preferences updated.",
"Notification preferences not updated. Please try again.": "Notification preferences not updated. Please try again.",
"Open": "Open",
"OMS": "OMS",
"OMS instance": "OMS instance",
Expand Down Expand Up @@ -144,6 +152,7 @@
"Warehouse": "Warehouse",
"Worn Display": "Worn Display",
"This order will be removed from your dashboard. This action cannot be undone.": "This order will be removed from your dashboard.{ space } This action cannot be undone.",
"Update notification preferences": "Update notification preferences",
"View shipping orders along with pickup orders.": "View shipping orders along with pickup orders.",
"You do not have permission to access this page": "You do not have permission to access this page",
"Zipcode": "Zipcode"
Expand Down
9 changes: 9 additions & 0 deletions src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"An email notification will be sent to that their order is ready for pickup. This order will also be moved to the packed orders tab.": "Se enviará una notificación por correo electrónico a {customerName} de que su pedido está listo para recoger.{ space } Este pedido también se moverá a la pestaña de pedidos empacados.",
"An email notification will be sent to that their order is ready for pickup.": "Se enviará una notificación por correo electrónico a {customerName} de que su pedido está listo para recoger.",
"Are you sure you want to change the time zone to?": "¿Estás seguro de que quieres cambiar la zona horaria a?",
"Are you sure you want to update the notification preferences?": "Are you sure you want to update the notification preferences?",
"Arrived": "Llegó",
"Authenticating": "Authenticating",
"Assign Pickers": "Asignar recolectores",
Expand Down Expand Up @@ -56,13 +57,20 @@
"Logout": "Cerrar sesión",
"Mismatch": "Desajuste",
"More": "Más",
"New notification received.": "New notification received.",
"No inventory details found": "No se encontraron detalles de inventario",
"Not in stock": "No disponible en el inventario",
"No products found": "No se encontraron productos",
"No reason": "Sin razón",
"No notifications to show": "No notifications to show",
"No picker assigned.": "No picker assigned.",
"No picker found": "No se encontró recolector",
"No time zone found": "No se encontró zona horaria",
"Notifications": "Notifications",
"Notification Preference": "Notification Preference",
"Notification preferences not found.": "Notification preferences not found.",
"Notification preferences updated.": "Notification preferences updated.",
"Notification preferences not updated. Please try again.": "Notification preferences not updated. Please try again.",
"Open": "Abierto",
"OMS": "OMS",
"OMS instance": "Instancia de OMS",
Expand Down Expand Up @@ -143,6 +151,7 @@
"Warehouse": "Almacén",
"Worn Display": "Pantalla desgastada",
"This order will be removed from your dashboard. This action cannot be undone.": "Este pedido será eliminado de tu panel de control.{ space } Esta acción no se puede deshacer.",
"Update notification preferences": "Update notification preferences",
"View shipping orders along with pickup orders.": "Ver órdenes de envío junto con órdenes de recogida.",
"You do not have permission to access this page": "No tienes permiso para acceder a esta página",
"Zipcode": "Código postal",
Expand Down
9 changes: 9 additions & 0 deletions src/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"An email notification will be sent to that their order is ready for pickup. This order will also be moved to the packed orders tab.": "{ customerName }様宛に注文の受け取り準備が完了したことをお知らするメールが送信されます。{ space } この注文は「梱包済み注文」タブに移動されます.",
"An email notification will be sent to that their order is ready for pickup.": "{ customerName }様宛に注文の受け取り準備が完了したことをお知らするメールが送信されます。",
"Are you sure you want to change the time zone to?": "タイムゾーンを変更してもよろしいですか?",
"Are you sure you want to update the notification preferences?": "Are you sure you want to update the notification preferences?",
"Arrived": "到着",
"Authenticating": "Authenticating",
"Assign Pickers": "受け取り人の割当",
Expand Down Expand Up @@ -56,13 +57,20 @@
"Logout": "ログアウト",
"Mismatch": "不一致",
"More": "More",
"New notification received.": "New notification received.",
"No inventory details found": "在庫の詳細が見つかりません",
"Not in Stock": "在庫切れ",
"No products found": "商品が見つかりません",
"No reason": "理由なし",
"No notifications to show": "No notifications to show",
"No picker assigned.": "No picker assigned.",
"No picker found": "受取人が見つかりません",
"No time zone found": "タイムゾーンが見つかりません",
"Notifications": "Notifications",
"Notification Preference": "Notification Preference",
"Notification preferences not found.": "Notification preferences not found.",
"Notification preferences updated.": "Notification preferences updated.",
"Notification preferences not updated. Please try again.": "Notification preferences not updated. Please try again.",
"Open": "オープン",
"OMS": "OMS",
"OMS instance": "OMSインスタンス",
Expand Down Expand Up @@ -143,6 +151,7 @@
"Warehouse": "倉庫",
"Worn Display": "すり切れたディスプレイ",
"This order will be removed from your dashboard. This action cannot be undone.": "この注文はダッシュボードから削除されます。{ space } この操作は元に戻せません。",
"Update notification preferences": "Update notification preferences",
"View shipping orders along with pickup orders.": "店舗受取の注文と一緒に配送注文を表示します",
"You do not have permission to access this page": "このページにアクセスする権限がありません",
"Zipcode": "郵便番号"
Expand Down
19 changes: 16 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,18 @@ import "@hotwax/apps-theme";

import i18n from './i18n'
import store from './store'

import permissionPlugin from '@/authorization';
import permissionRules from '@/authorization/Rules';
import permissionActions from '@/authorization/Actions';

import { dxpComponents } from '@hotwax/dxp-components'
import { login, logout, loader } from './user-utils';
import { login, logout, loader } from '@/utils/user';
import {
addNotification,
storeClientRegistrationToken
} from '@/utils/firebase';
import { getConfig, initialise } from '@hotwax/oms-api';

const app = createApp(App)
.use(IonicVue, {
Expand All @@ -46,11 +53,17 @@ const app = createApp(App)
actions: permissionActions
})
.use(dxpComponents, {
addNotification,
appLoginUrl: process.env.VUE_APP_LOGIN_URL as string,
appFirebaseConfig: JSON.parse(process.env.VUE_APP_FIREBASE_CONFIG),
appFirebaseVapidKey: process.env.VUE_APP_FIREBAE_VAPID_KEY,
defaultImgUrl: require("@/assets/images/defaultImage.png"),
getConfig,
initialise,
loader,
login,
logout,
loader,
appLoginUrl: process.env.VUE_APP_LOGIN_URL as string
storeClientRegistrationToken,
});

// Filters are removed in Vue 3 and global filter introduced https://v3.vuejs.org/guide/migration/filters.html#global-filters
Expand Down
9 changes: 8 additions & 1 deletion src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Tabs from '@/views/Tabs.vue'
import OrderDetail from '@/views/OrderDetail.vue'
import ProductDetail from '@/views/ProductDetail.vue'
import ShipToStoreOrders from '@/views/ShipToStoreOrders.vue'
import Notifications from '@/views/Notifications.vue'
import Shopify from '@/views/Shopify.vue'

import { hasPermission } from '@/authorization';
Expand All @@ -13,7 +14,7 @@ import { translate } from '@/i18n'

import 'vue-router'
import { Login, useAuthStore } from '@hotwax/dxp-components';
import { loader } from '@/user-utils';
import { loader } from '@/utils/user';

// Defining types for the meta values
declare module 'vue-router' {
Expand Down Expand Up @@ -110,6 +111,12 @@ const routes: Array<RouteRecordRaw> = [
component: ShipToStoreOrders,
beforeEnter: authGuard,
},
{
path: '/notifications',
name: "Notifications",
component: Notifications,
beforeEnter: authGuard,
},
{
path: '/shopify',
name: 'Shopify',
Expand Down
3 changes: 3 additions & 0 deletions src/store/modules/user/UserState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ export default interface UserState {
locale: string;
permissions: any;
currentEComStore: any;
notifications: any;
notificationPrefs: any;
firebaseDeviceId: string;
}
70 changes: 69 additions & 1 deletion src/store/modules/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UserState from './UserState'
import * as types from './mutation-types'
import { showToast } from '@/utils'
import i18n, { translate } from '@/i18n'
import { Settings } from 'luxon';
import { DateTime, Settings } from 'luxon';
import { hasError, updateInstanceUrl, updateToken, resetConfig, getUserFacilities } from '@/adapter'
import {
getServerPermissionsFromRules,
Expand All @@ -15,6 +15,13 @@ import {
setPermissions
} from '@/authorization'
import { useAuthStore } from '@hotwax/dxp-components'
import {
getNotificationEnumIds,
getNotificationUserPrefTypeIds,
storeClientRegistrationToken,
removeClientRegistrationToken,
} from '@hotwax/oms-api';
import { generateDeviceId, generateTopicName } from '@/utils/firebase'

const actions: ActionTree<UserState, RootState> = {

Expand Down Expand Up @@ -103,6 +110,7 @@ const actions: ActionTree<UserState, RootState> = {
const authStore = useAuthStore()
// TODO add any other tasks if need
dispatch("product/clearProducts", null, { root: true })
dispatch('clearNotificaionsState')
alsoK2maan marked this conversation as resolved.
Show resolved Hide resolved
commit(types.USER_END_SESSION)
resetPermissions();
resetConfig();
Expand Down Expand Up @@ -160,5 +168,65 @@ const actions: ActionTree<UserState, RootState> = {
i18n.global.locale = payload
commit(types.USER_LOCALE_UPDATED, payload)
},

addNotification({ state, commit }, payload) {
const notifications = JSON.parse(JSON.stringify(state.notifications))
notifications.push({ ...payload.notification, time: DateTime.now().toMillis() })
if (payload.isForeground) {
showToast(translate("New notification received."));
}
commit(types.USER_NOTIFICATIONS_UPDATED, notifications)
},

async fetchNotificationPreferences({ commit, state }) {
let resp = {} as any
const oms = state.instanceUrl
const facilityId = (state.currentFacility as any).facilityId
let notificationPreferences = [], enumerationResp = [], userPrefIds = [] as any
try {
resp = await getNotificationEnumIds(process.env.VUE_APP_NOTIF_ENUM_TYPE_ID)
enumerationResp = resp.docs
resp = await getNotificationUserPrefTypeIds(process.env.VUE_APP_NOTIF_APP_ID)
userPrefIds = resp.docs.map((userPref: any) => userPref.userPrefTypeId)
} catch (error) {
console.error(error)
} finally {
// checking enumerationResp as we want to show disbaled prefs if only getNotificationEnumIds returns
// data and getNotificationUserPrefTypeIds fails or returns empty response (all disbaled)
if (enumerationResp.length) {
notificationPreferences = enumerationResp.reduce((notifactionPref: any, pref: any) => {
const userPrefTypeIdToSearch = generateTopicName(oms, facilityId, pref.enumId)
notifactionPref.push({ ...pref, isEnabled: userPrefIds.includes(userPrefTypeIdToSearch) })
return notifactionPref
}, [])
}
commit(types.USER_NOTIFICATIONS_PREFERENCES_UPDATED, notificationPreferences)
}
},

async storeClientRegistrationToken({ commit }, registrationToken) {
const firebaseDeviceId = generateDeviceId()
commit(types.USER_FIREBASE_DEVICEID_UPDATED, firebaseDeviceId)

try {
await storeClientRegistrationToken(registrationToken, firebaseDeviceId, process.env.VUE_APP_NOTIF_APP_ID)
} catch (error) {
console.error(error)
}
},

async removeClientRegistrationToken({ state }) {
try {
await removeClientRegistrationToken(state.firebaseDeviceId, process.env.VUE_APP_NOTIF_APP_ID)
} catch (error) {
console.error(error)
}
},

clearNotificaionsState({ commit }) {
commit(types.USER_NOTIFICATIONS_UPDATED, [])
commit(types.USER_NOTIFICATIONS_PREFERENCES_UPDATED, [])
commit(types.USER_FIREBASE_DEVICEID_UPDATED, '')
}
}
export default actions;
Loading
Loading