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: Add time zone support and migrated from moment to luxon (#25k8h53) #174

Merged
merged 13 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35,376 changes: 34,361 additions & 1,015 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
"axios-cache-adapter": "^2.7.3",
"core-js": "^3.6.5",
"http-status-codes": "^2.1.4",
"luxon": "^3.2.0",
"mitt": "^2.1.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
"register-service-worker": "^1.7.1",
"vue": "^3.2.26",
"vue-i18n": "~9.1.6",
Expand All @@ -37,6 +36,7 @@
"devDependencies": {
"@capacitor/cli": "^2.4.7",
"@intlify/vue-i18n-loader": "^2.1.0",
"@types/luxon": "^3.2.0",
"@types/jest": "^27.5.0",
"@typescript-eslint/eslint-plugin": "~5.26.0",
"@typescript-eslint/parser": "~5.26.0",
Expand Down
10 changes: 10 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"All items were canceled from the order": "All items were canceled from the order",
"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.",
"Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to?",
"Catalog": "Catalog",
"Cancel": "Cancel",
"canceled from the order": "canceled from the order",
"Change": "Change",
"Choose language": "Choose language",
"City": "City",
"Click the backdrop to dismiss.": "Click the backdrop to dismiss.",
"Color": "Color",
"Confirm": "Confirm",
"Copied": "Copied { text }",
"Copy": "Copy",
"Depending on the reason you select for not fulfulling an item, an inventory variance will be recorded and all sales channels will be updated with new inventory levels. For example, by selecting “Not in stock” HotWax Commerce will stop routing orders for it to your store and customers will not be able to place BOPIS orders for it at your store on Shopify.": "Depending on the reason you select for not fulfulling an item, an inventory variance will be recorded and all sales channels will be updated with new inventory levels.{ space } For example, by selecting “Not in stock” HotWax Commerce will stop routing orders for it to your store and customers will not be able to place BOPIS orders for it at your store on Shopify.",
Expand All @@ -33,6 +36,7 @@
"Not in stock": "Not in stock",
"Not in Stock": "Not in Stock",
"No reason": "No reason",
"No time zone found": "No time zone found",
"Open": "Open",
"OMS": "OMS",
"OMS instance": "OMS instance",
Expand All @@ -56,7 +60,9 @@
"Reason": "Reason",
"Search": "Search",
"Search Orders": "Search Orders",
"Search time zones": "Search time zones",
"Select facility": "Select facility",
"Select time zone": "Select time zone",
"Settings": "Settings",
"Ship": "Ship",
"Shipping method": "Shipping method",
Expand All @@ -70,12 +76,16 @@
"State": "State",
"Street": "Street",
"Store": "Store",
"Timezone": "Timezone",
"Time zone updated successfully": "Time zone updated successfully",
"The timezone you select is used to ensure automations you schedule are always accurate to the time you select.": "The timezone you select is used to ensure automations you schedule are always accurate to the time you select.",
"This is the name of the OMS you are connected to right now. Make sure that you are connected to the right instance before proceeding.": "This is the name of the OMS you are connected to right now. Make sure that you are connected to the right instance before proceeding.",
"eCom Store": "eCom Store",
"This order cannot be split. If you cannot fulfill any item, will be sent an email with alternate fulfillment options and this order will be removed from your dashboard.": "This order cannot be split. If you cannot fulfill any item, { customerName } will be sent an email with alternate fulfillment options and this order will be removed from your dashboard.",
"This order will be rejected from this store with the selected reason and shipped to the address that has been inputed.Please make sure the address you have entered is correct.": "This order will be rejected from this store with the selected reason and shipped to the address that has been inputed. { space } Please make sure the address you have entered is correct.",
"Unfillable Items": "Unfillable Items",
"Update Order": "Update Order",
"Update time zone": "Update time zone",
"Username": "Username",
"Warehouse": "Warehouse",
"Worn Display": "Worn Display",
Expand Down
15 changes: 7 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
import moment from 'moment'
import "moment-timezone";
import { DateTime } from 'luxon';


import { IonicVue } from '@ionic/vue';
Expand Down Expand Up @@ -41,16 +40,16 @@ const app = createApp(App)
// Filters are removed in Vue 3 and global filter introduced https://v3.vuejs.org/guide/migration/filters.html#global-filters
app.config.globalProperties.$filters = {
formatDate(value: any, inFormat?: string, outFormat?: string) {
// TODO Use Loxon instead
// TODO Make default format configurable and from environment variables
return moment(value, inFormat).format(outFormat ? outFormat : 'MM-DD-YYYY');
if(inFormat){
return DateTime.fromFormat(value, inFormat).toFormat(outFormat ? outFormat : 'MM-dd-yyyy');
}
return DateTime.fromISO(value).toFormat(outFormat ? outFormat : 'MM-dd-yyyy');
},
formatUtcDate(value: any, inFormat?: string, outFormat?: string) {
// TODO Use Loxon instead
formatUtcDate(value: any, inFormat?: any, outFormat?: string) {
// TODO Make default format configurable and from environment variables
const userProfile = store.getters['user/getUserProfile'];
// TODO Fix this setDefault should set the default timezone instead of getting it everytiem and setting the tz
return moment.utc(value, inFormat).tz(userProfile.userTimeZone).format(outFormat ? outFormat : 'MM-DD-YYYY');
return DateTime.fromISO(value, { zone: 'utc' }).setZone(userProfile.userTimeZone).toFormat(outFormat ? outFormat : 'MM-dd-yyyy')
},
getIdentificationId(identifications: any, id: string) {
let externalId = ''
Expand Down
12 changes: 5 additions & 7 deletions src/store/modules/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import UserState from './UserState'
import * as types from './mutation-types'
import { hasError, showToast } from '@/utils'
import i18n, { translate } from '@/i18n'
import moment from 'moment';
import emitter from '@/event-bus'
import "moment-timezone";
import { Settings } from 'luxon';

const actions: ActionTree<UserState, RootState> = {

Expand Down Expand Up @@ -82,9 +80,8 @@ const actions: ActionTree<UserState, RootState> = {
async getProfile ( { commit }) {
const resp = await UserService.getProfile()
if (resp.status === 200) {
const localTimeZone = moment.tz.guess();
if (resp.data.userTimeZone !== localTimeZone) {
emitter.emit('timeZoneDifferent', { profileTimeZone: resp.data.userTimeZone, localTimeZone});
if (resp.data.userTimeZone) {
Settings.defaultZone = resp.data.userTimeZone;
}
try {
const userPreferenceResp = await UserService.getUserPreference({
Expand Down Expand Up @@ -126,8 +123,9 @@ const actions: ActionTree<UserState, RootState> = {
const resp = await UserService.setUserTimeZone(payload)
if (resp.status === 200 && !hasError(resp)) {
const current: any = state.current;
current.userTimeZone = payload.tzId;
current.userTimeZone = payload.timeZoneId;
commit(types.USER_INFO_UPDATED, current);
Settings.defaultZone = current.userTimeZone;
showToast(translate("Time zone updated successfully"));
}
},
Expand Down
11 changes: 10 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toastController } from '@ionic/vue';
import { Plugins } from '@capacitor/core';
import { translate } from '@/i18n'
import { DateTime } from "luxon";

// TODO Use separate files for specific utilities

Expand Down Expand Up @@ -29,4 +30,12 @@ const copyToClipboard = async (text: any) => {
});
}

export { copyToClipboard, showToast, hasError }
const handleDateTimeInput = (dateTimeValue: any) => {
// TODO Handle it in a better way
// Remove timezone and then convert to timestamp
// Current date time picker picks browser timezone and there is no supprt to change it
const dateTime = DateTime.fromISO(dateTimeValue, { setZone: true}).toFormat("yyyy-MM-dd'T'HH:mm:ss")
return DateTime.fromISO(dateTime).toMillis()
}

export { copyToClipboard, showToast, hasError, handleDateTimeInput }
9 changes: 6 additions & 3 deletions src/views/OrderDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<h2>{{ order.customer?.name }}</h2>
<p>{{ order.orderName ? order.orderName : order.orderId }}</p>
</ion-label>
<ion-badge v-if="order.placedDate" color="dark" slot="end">{{ moment.utc(order.placedDate).fromNow() }}</ion-badge>
<ion-badge v-if="order.placedDate" color="dark" slot="end">{{ timeFromNow(order.placedDate) }}</ion-badge>
</ion-item>
</ion-list>
<ion-item v-if="order.customer?.phoneNumber">
Expand Down Expand Up @@ -97,7 +97,7 @@ import {
import ProductListItem from '@/components/ProductListItem.vue'
import { copyToClipboard } from '@/utils'
import { useRouter } from 'vue-router'
import * as moment from "moment-timezone";
import { DateTime } from 'luxon';
import ShipToCustomerModal from "@/components/ShipToCustomerModal.vue";

export default defineComponent({
Expand Down Expand Up @@ -136,6 +136,10 @@ export default defineComponent({
if(this.order.items) this.order.items.map((item) => item['reason'] = this.unfillableReason[0].id);
},
methods: {
timeFromNow (time) {
const timeDiff = DateTime.fromISO(time).diff(DateTime.local());
return DateTime.local().plus(timeDiff).toRelative();
},
async shipToCustomer() {
const shipmodal = await modalController.create({
component: ShipToCustomerModal,
Expand Down Expand Up @@ -187,7 +191,6 @@ export default defineComponent({
callOutline,
copyToClipboard,
mailOutline,
moment,
router,
store,
swapVerticalOutline,
Expand Down
11 changes: 7 additions & 4 deletions src/views/Orders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<p>{{ order.orderName ? order.orderName : order.orderId }}</p>
</ion-label>
<div class="metadata">
<ion-badge v-if="order.placedDate" color="dark">{{ moment.utc(order.placedDate).fromNow() }}</ion-badge>
<ion-badge v-if="order.placedDate" color="dark">{{ timeFromNow(order.placedDate) }}</ion-badge>
<ion-badge v-if="order.statusId !== 'ORDER_APPROVED'" color="danger">{{ $t('pending approval') }}</ion-badge>
</div>
<!-- TODO: Display the packed date of the orders, currently not getting the packed date from API-->
Expand Down Expand Up @@ -65,7 +65,7 @@
<h1>{{ order.customer.name }}</h1>
<p>{{ order.orderName ? order.orderName : order.orderId }}</p>
</ion-label>
<ion-badge v-if="order.placedDate" color="dark" slot="end">{{ moment.utc(order.placedDate).fromNow() }}</ion-badge>
<ion-badge v-if="order.placedDate" color="dark" slot="end">{{ timeFromNow(order.placedDate) }}</ion-badge>
</ion-item>

<ProductListItem v-for="item in part.items" :key="item.productId" :item="item" />
Expand Down Expand Up @@ -133,7 +133,7 @@ import { swapVerticalOutline, callOutline, mailOutline, print } from "ionicons/i
import { mapGetters, useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { copyToClipboard, hasError, showToast } from '@/utils'
import * as moment from "moment-timezone";
import { DateTime } from 'luxon';
import emitter from "@/event-bus"
import api from "@/api"
import { translate } from "@/i18n";
Expand Down Expand Up @@ -183,6 +183,10 @@ export default defineComponent({
}
},
methods: {
timeFromNow (time: any) {
const timeDiff = DateTime.fromISO(time).diff(DateTime.local());
return DateTime.local().plus(timeDiff).toRelative();
},
async printPackingSlip(order: any) {

try {
Expand Down Expand Up @@ -326,7 +330,6 @@ export default defineComponent({
callOutline,
copyToClipboard,
mailOutline,
moment,
print,
router,
segmentSelected,
Expand Down
34 changes: 25 additions & 9 deletions src/views/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,34 @@
</ion-item>
</ion-card>
</section>
<!-- TODO Define section and add language Switch -->
<!-- <ion-item>
<ion-icon :icon="languageOutline" slot="start"/>
<ion-label>{{$t("Choose language")}}</ion-label>
<ion-select interface="popover" :value="locale" @ionChange="setLocale($event.detail.value)">
<ion-select-option v-for="locale in Object.keys(locales)" :key="locale" :value="locale" >{{ locales[locale] }}</ion-select-option>
</ion-select>
</ion-item> -->
<hr />
<section>
<ion-card>
<ion-card-header>
<ion-card-title>
{{ $t('Timezone') }}
</ion-card-title>
</ion-card-header>
<ion-card-content>
{{ $t('The timezone you select is used to ensure automations you schedule are always accurate to the time you select.') }}
</ion-card-content>
<ion-item lines="none">
<ion-label> {{ userProfile && userProfile.userTimeZone ? userProfile.userTimeZone : '-' }} </ion-label>
<ion-button @click="changeTimeZone()" slot="end" fill="outline" color="dark">{{ $t("Change") }}</ion-button>
</ion-item>
</ion-card>
</section>
</ion-content>
</ion-page>
</template>

<script lang="ts">
import { IonAvatar, IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonPage, IonSelect, IonSelectOption, IonTitle, IonToggle , IonToolbar } from '@ionic/vue';
import { IonAvatar, IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonPage, IonSelect, IonSelectOption, IonTitle, IonToggle , IonToolbar, modalController } from '@ionic/vue';
import { defineComponent } from 'vue';
import { ellipsisVertical, personCircleOutline, sendOutline , storefrontOutline, codeWorkingOutline, openOutline } from 'ionicons/icons'
import { mapGetters, useStore } from 'vuex';
import { useRouter } from 'vue-router';
import TimeZoneModal from './TimezoneModal.vue';
import Image from '@/components/Image.vue';

export default defineComponent({
Expand Down Expand Up @@ -154,6 +164,12 @@ export default defineComponent({
'facility': this.userProfile.facilities.find((fac: any) => fac.facilityId == facility['detail'].value)
});
},
async changeTimeZone() {
const timeZoneModal = await modalController.create({
component: TimeZoneModal,
});
return timeZoneModal.present();
},
logout () {
this.store.dispatch('user/logout').then(() => {
this.router.push('/login');
Expand Down
Loading