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

[WIP] Implemented: logic to allow user select execution timezone (#719) #722

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
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";

Check warning on line 73 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'UserService' is defined but never used

Check warning on line 73 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'UserService' is defined but never used
import { hasError } from '@/utils'

Check warning on line 74 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'hasError' is defined but never used

Check warning on line 74 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'hasError' is defined but never used
import { DateTime } from 'luxon';

Check warning on line 75 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'DateTime' is defined but never used

Check warning on line 75 in src/components/TimeZoneModal.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'DateTime' is defined but never used
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
}
10 changes: 5 additions & 5 deletions src/store/modules/job/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@
const payload = {
'jobId': job.jobId,
'systemJobEnumId': job.systemJobEnumId,
'recurrenceTimeZone': this.state.user.current.userTimeZone,
'recurrenceTimeZone': this.state.util.jobRecurrenceTimeZone ? this.state.util.jobRecurrenceTimeZone : this.state.user.current.userTimeZone,
'tempExprId': job.jobStatus,
'statusId': "SERVICE_PENDING",
'runTimeEpoch': '', // when updating a job clearning the epoch time, as job honors epoch time as runTime and the new job created also uses epoch time as runTime
Expand Down Expand Up @@ -567,7 +567,7 @@
'maxRecurrenceCount': '-1',
'parentJobId': job.parentJobId,
'runAsUser': 'system', //default system, but empty in run now. TODO Need to remove this as we are using SERVICE_RUN_AS_SYSTEM, currently kept it for backward compatibility
'recurrenceTimeZone': this.state.user.current.userTimeZone,
'recurrenceTimeZone': this.state.util.jobRecurrenceTimeZone ? this.state.util.jobRecurrenceTimeZone : this.state.user.current.userTimeZone,
'createdByUserLogin': this.state.user.current.userLoginId,
'lastModifiedByUserLogin': this.state.user.current.userLoginId,
},
Expand Down Expand Up @@ -653,7 +653,7 @@
'jobId': job.jobId,
'runTime': updatedRunTime,
'systemJobEnumId': job.systemJobEnumId,
'recurrenceTimeZone': this.state.user.current.userTimeZone,
'recurrenceTimeZone': this.state.util.jobRecurrenceTimeZone ? this.state.util.jobRecurrenceTimeZone : this.state.user.current.userTimeZone,
'statusId': "SERVICE_PENDING",
'runTimeEpoch': ''
} as any
Expand Down Expand Up @@ -681,7 +681,7 @@
return resp;
},

async runServiceNow({ dispatch }, params) {

Check warning on line 684 in src/store/modules/job/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 684 in src/store/modules/job/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
let resp;

const job = params.job
Expand All @@ -696,7 +696,7 @@
'systemJobEnumId': job.systemJobEnumId,
'tempExprId': job.jobStatus, // Need to remove this as we are passing frequency in SERVICE_TEMP_EXPR, currently kept it for backward compatibility
'parentJobId': job.parentJobId,
'recurrenceTimeZone': this.state.user.current.userTimeZone,
'recurrenceTimeZone': this.state.util.jobRecurrenceTimeZone ? this.state.util.jobRecurrenceTimeZone : this.state.user.current.userTimeZone,
'createdByUserLogin': this.state.user.current.userLoginId,
'lastModifiedByUserLogin': this.state.user.current.userLoginId
},
Expand Down Expand Up @@ -897,7 +897,7 @@
'maxRecurrenceCount': '-1',
'parentJobId': job.parentJobId,
'runAsUser': 'system', //default system, but empty in run now. TODO Need to remove this as we are using SERVICE_RUN_AS_SYSTEM, currently kept it for backward compatibility
'recurrenceTimeZone': this.state.user.current.userTimeZone,
'recurrenceTimeZone': this.state.util.jobRecurrenceTimeZone ? this.state.util.jobRecurrenceTimeZone : this.state.user.current.userTimeZone,
'createdByUserLogin': this.state.user.current.userLoginId,
'lastModifiedByUserLogin': this.state.user.current.userLoginId
},
Expand Down
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
Loading