Skip to content

Commit

Permalink
Implemented: logic for job execution timezone management (hotwax#719)
Browse files Browse the repository at this point in the history
  • Loading branch information
amansinghbais committed Aug 14, 2024
1 parent 779f7be commit 260e872
Show file tree
Hide file tree
Showing 11 changed files with 453 additions and 5 deletions.
97 changes: 97 additions & 0 deletions src/components/ExecutionTimeZoneSwitcher.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<template>
<ion-card>
<ion-card-header>
<ion-card-title>
{{ translate("Execution Timezone") }}
</ion-card-title>
</ion-card-header>
<ion-card-content>
{{ translate("Select the timezone that data should be processed in. This should always be the same zone as integrated systems like eCommerce and ERPs.") }}
</ion-card-content>
<ion-item>
<ion-label>
<p class="overline">{{ translate("System TimeZone") }}</p>
{{ browserTimeZone.id }}
<p>{{ getCurrentTime(browserTimeZone.id, dateTimeFormat) }}</p>
</ion-label>
</ion-item>
<ion-item lines="none">
<ion-label>
<p class="overline">{{ translate("Selected TimeZone") }}</p>
{{ currentTimeZoneId }}
<p v-if="currentTimeZoneId">{{ getCurrentTime(currentTimeZoneId, dateTimeFormat) }}</p>
</ion-label>
<ion-button slot="end" fill="outline" color="dark" @click="changeTimeZone()">
{{ translate(currentTimeZoneId ? "Change" : "Add") }}
</ion-button>
</ion-item>
</ion-card>
</template>


<script lang="ts">
import { defineComponent } from "vue";
import {
IonButton,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonItem,
IonLabel,
modalController
} from "@ionic/vue";
import { mapGetters } from "vuex";
import { translate, useUserStore } from "@hotwax/dxp-components";
import { DateTime } from 'luxon';
import TimeZoneModal from "@/components/TimeZoneModal.vue";
export default defineComponent({
name: "ExecutionTimeZoneSwitcher",
components: {
IonButton,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonItem,
IonLabel,
},
data() {
return {
dateTimeFormat: "t ZZZZ",
browserTimeZone: {
label: '',
id: Intl.DateTimeFormat().resolvedOptions().timeZone
}
}
},
computed: {
...mapGetters({
currentTimeZoneId: "util/getJobRecurrenceTimeZone"
})
},
mounted() {
console.log('enter')
},
methods: {
getCurrentTime(zone: string, format = 't ZZZZ') {
return DateTime.now().setZone(zone).toFormat(format)
},
async changeTimeZone() {
const timeZoneModal = await modalController.create({
component: TimeZoneModal,
});
return timeZoneModal.present();
},
},
setup() {
const userStore = useUserStore();
return {
translate,
userStore
};
}
});
</script>
146 changes: 146 additions & 0 deletions src/components/TimeZoneModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<template>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button @click="closeModal">
<ion-icon :icon="close" />
</ion-button>
</ion-buttons>
<ion-title>{{ translate("Select time zone") }}</ion-title>
</ion-toolbar>
<ion-toolbar>
<ion-searchbar @ionFocus="selectSearchBarText($event)" :placeholder="translate('Search time zones')" v-model="queryString" @ionChange="findTimeZone()" @keydown="preventSpecialCharacters($event)" />
</ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
<form @keyup.enter="setUserTimeZone">
<!-- Empty state -->
<div class="empty-state" v-if="isLoading">
<ion-item lines="none">
<ion-spinner color="secondary" name="crescent" slot="start" />
{{ translate("Fetching time zones") }}
</ion-item>
</div>

<div class="empty-state" v-else-if="filteredTimeZones.length === 0">
<p>{{ translate("No time zone found") }}</p>
</div>

<!-- Timezones -->
<div v-else>
<ion-list>
<ion-radio-group value="rd" v-model="timeZoneId">
<ion-item :key="timeZone.id" v-for="timeZone in filteredTimeZones">
<ion-radio label-placement="end" justify="start" :value="timeZone.id">{{ timeZone.label }} ({{ timeZone.id }})</ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</div>
</form>

<!-- Defined ion-fab outside of form element as the fab button losoe its styling when wrapped inside form -->
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button :disabled="!timeZoneId" @click="setUserTimeZone">
<ion-icon :icon="save" />
</ion-fab-button>
</ion-fab>
</ion-content>
</template>

<script lang="ts">
import {
IonButtons,
IonButton,
IonContent,
IonFab,
IonFabButton,
IonHeader,
IonItem,
IonIcon,
IonList,
IonRadioGroup,
IonRadio,
IonSearchbar,
IonSpinner,
IonTitle,
IonToolbar,
modalController
} from "@ionic/vue";
import { defineComponent } from "vue";
import { close, save } from "ionicons/icons";
import { useStore } from "@/store";
import { UserService } from "@/services/UserService";
import { hasError } from '@/utils'
import { DateTime } from 'luxon';
import { translate, useUserStore } from "@hotwax/dxp-components";
export default defineComponent({
name: "TimeZoneModal",
components: {
IonButtons,
IonButton,
IonContent,
IonFab,
IonFabButton,
IonHeader,
IonIcon,
IonItem,
IonList,
IonRadioGroup,
IonRadio,
IonSearchbar,
IonSpinner,
IonTitle,
IonToolbar
},
data() {
return {
queryString: '',
filteredTimeZones: [] as any,
timeZoneId: '',
isLoading: false
}
},
methods: {
closeModal() {
modalController.dismiss({ dismissed: true });
},
preventSpecialCharacters($event: any) {
// Searching special characters fails the API, hence, they must be omitted
if(/[`!@#$%^&*()_+\-=\\|,.<>?~]/.test($event.key)) $event.preventDefault();
},
findTimeZone() {
const queryString = this.queryString.toLowerCase();
this.filteredTimeZones = this.timeZones.filter((timeZone: any) => {
return timeZone.id.toLowerCase().match(queryString) || timeZone.label.toLowerCase().match(queryString);
});
},
async selectSearchBarText(event: any) {
const element = await event.target.getInputElement()
element.select();
},
async setUserTimeZone() {
await this.store.dispatch("util/setJobRecurrenceTimeZone", this.timeZoneId)
this.closeModal()
}
},
beforeMount () {
this.findTimeZone()
},
setup() {
const store = useStore();
const userStore = useUserStore();
const timeZones = userStore.getTimeZones
return {
close,
save,
store,
timeZones,
translate,
userStore
};
}
});
</script>
65 changes: 64 additions & 1 deletion src/services/UtilService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { api } from '@/adapter';
import { hasError } from '@hotwax/oms-api';

const getServiceStatusDesc = async (payload: any): Promise<any> => {
return api({
Expand All @@ -9,6 +10,68 @@ const getServiceStatusDesc = async (payload: any): Promise<any> => {
});
}

const getProductStoreSetting = async (payload: any): Promise<any> => {
return api({
url: "performFind",
method: "post",
data: payload
});
}

const isEnumExists = async (enumId: string): Promise<any> => {
try {
const resp = await api({
url: 'performFind',
method: 'POST',
data: {
entityName: "Enumeration",
inputFields: {
enumId
},
viewSize: 1,
fieldList: ["enumId"],
noConditionFind: 'Y'
}
}) as any

if (!hasError(resp) && resp.data.docs.length) {
return true
}
return false
} catch (err) {
return false
}
}

const createEnumeration = async (payload: any): Promise<any> => {
return api({
url: "/service/createEnumeration",
method: "post",
data: payload
})
}

const createProductStoreSetting = async (payload: any): Promise<any> => {
return api({
url: "service/createProductStoreSetting",
method: "post",
data: payload
});
}

const updateProductStoreSetting = async (payload: any): Promise<any> => {
return api({
url: "service/updateProductStoreSetting",
method: "post",
data: payload
});
}

export const UtilService = {
getServiceStatusDesc
createEnumeration,
createProductStoreSetting,
getProductStoreSetting,
getServiceStatusDesc,
isEnumExists,
updateProductStoreSetting
}
2 changes: 2 additions & 0 deletions src/store/modules/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const actions: ActionTree<UserState, RootState> = {
// Getting service status description
// TODO check if we could move it to logic for fetching jobs
this.dispatch('util/getServiceStatusDesc')
this.dispatch('util/getJobRecurrenceTimeZone', preferredStore.productStoreId);
} catch (err: any) {
// If any of the API call in try block has status code other than 2xx it will be handled in common catch block.
// TODO Check if handling of specific status codes is required.
Expand Down Expand Up @@ -162,6 +163,7 @@ const actions: ActionTree<UserState, RootState> = {
}
commit(types.USER_CURRENT_ECOM_STORE_UPDATED, productStore);
await dispatch('getShopifyConfig', productStore.productStoreId);
this.dispatch('util/getForceScanSetting', productStore.productStoreId)
},
/**
* Update user timeZone
Expand Down
1 change: 1 addition & 0 deletions src/store/modules/util/UtilState.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default interface UtilState {
statusDesc: any;
jobRecurrenceTimeZone: any;
}
Loading

0 comments on commit 260e872

Please sign in to comment.