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: NetSuite Integration Management UI(#37) #38

Open
wants to merge 11 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
16 changes: 13 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
<template>
<ion-app>
<ion-router-outlet />
<IonSplitPane content-id="main-content" when="lg">
<Menu />
<ion-router-outlet id="main-content"></ion-router-outlet>
</IonSplitPane>
</ion-app>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from "vue";
import { IonApp, IonRouterOutlet, loadingController } from "@ionic/vue";
import { IonApp, IonRouterOutlet, IonSplitPane, loadingController } from "@ionic/vue";
import Menu from '@/components/Menu.vue';
import emitter from "@/event-bus"
import { Settings } from 'luxon'
import store from "./store";
Expand Down Expand Up @@ -78,4 +82,10 @@ onUnmounted(() => {

resetConfig()
})
</script>
</script>

<style scoped>
ion-split-pane {
--side-width: 304px;
}
</style>
106 changes: 106 additions & 0 deletions src/components/DiscountsModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<template>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button @click="closeModal()">
<ion-icon slot="icon-only" :icon="closeOutline" />
</ion-button>
</ion-buttons>
<ion-title>{{ translate("Discounts") }}</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-item class="ion-margin-top">
<ion-icon slot="start" :icon="informationCircleOutline" />
<ion-label>
{{ translate("Learn more about discounts in NetSuite") }}
</ion-label>
<ion-icon :icon="openOutline" slot="end" />
</ion-item>

<ion-item lines="full" class="ion-margin-top">
<ion-input v-model="orderLevelDiscount" :label="translate('Order level discount')" :placeholder="translate('NetSuite discount item ID')" />
</ion-item>

<ion-item lines="full">
<ion-input v-model="itemLevelDiscount" :label="translate('Item level discounts')" :placeholder="translate('NetSuite discount item ID')" />
</ion-item>

<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button @click="editNetSuiteDiscountItemIds" :disabled="isDiscountValueChanged()">
<ion-icon :icon="saveOutline" />
</ion-fab-button>
</ion-fab>
</ion-content>
</template>

<script setup lang="ts">
import { IonButton, IonButtons, IonContent, IonFab, IonFabButton, IonHeader, IonIcon, IonInput, IonItem, IonLabel, IonTitle, IonToolbar, modalController } from "@ionic/vue";
import { closeOutline, informationCircleOutline, openOutline, saveOutline } from 'ionicons/icons';
import { translate } from "@/i18n"
import { useStore } from "vuex";
import { computed, onMounted, ref } from "vue";
import { useNetSuiteComposables } from "@/composables/useNetSuiteComposables";

const store = useStore();

const { addNetSuiteId, updateNetSuiteId } = useNetSuiteComposables("NETSUITE_DISC_MTHD")

const integrationTypeMappings = computed(() => store.getters["netSuite/getIntegrationTypeMappings"]("NETSUITE_DISC_MTHD"))

const orderLevelDiscount = ref("");
const itemLevelDiscount = ref("");
const integrationMappingByKey = ref({}) as any
const mappingKeys = {
order: "SHOPIFY_DISC",
item: "SHOPIFY_ITEM_DISC"
}

onMounted(async () => {
await store.dispatch("netSuite/fetchIntegrationTypeMappings", { integrationTypeId: "NETSUITE_DISC_MTHD" })

// Set orderLevelDiscount and itemLevelDiscount based on their corresponding mapping keys in integration type mappings.
integrationTypeMappings.value.map((mapping: any) => {
integrationMappingByKey[mapping.mappingKey] = mapping
if(mapping.mappingKey === mappingKeys.order) {
orderLevelDiscount.value = mapping.mappingValue
} else {
itemLevelDiscount.value = mapping.mappingValue
}
});
})

function closeModal() {
modalController.dismiss({ dismissed: true });
}

function isDiscountValueChanged() {
return !orderLevelDiscount.value?.trim() || !itemLevelDiscount.value?.trim() || (orderLevelDiscount.value === integrationMappingByKey[mappingKeys.order]?.mappingValue) && itemLevelDiscount.value === integrationMappingByKey[mappingKeys.item]?.mappingValue
}

async function editNetSuiteDiscountItemIds() {
if(orderLevelDiscount.value !== integrationMappingByKey[mappingKeys.order].mappingValue) {
await updateMapping(mappingKeys.order, orderLevelDiscount.value)
}
if(!itemLevelDiscount.value !== integrationMappingByKey[mappingKeys.item].mappingValue) {
await updateMapping(mappingKeys.item, itemLevelDiscount.value)
}
closeModal();
}

async function updateMapping(mappingKey: any, mappingValue: any) {

const payload = {
integrationTypeId: "NETSUITE_DISC_MTHD",
mappingKey,
mappingValue
}

if(integrationMappingByKey[mappingKey]?.integrationMappingId) {
await updateNetSuiteId(payload, integrationMappingByKey[mappingKey].integrationMappingId);
} else {
await addNetSuiteId(payload);
}
}
</script>
91 changes: 91 additions & 0 deletions src/components/Facilities.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<template>
<ion-page>
<ion-header :translucent="true">
<ion-toolbar>
<ion-back-button slot="start" default-href="/netsuite" />
<ion-menu-button slot="start" />
<ion-title>{{ translate("Facilities") }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="header ion-margin-top">
<ion-item lines="none">
<ion-icon slot="start" :icon="shieldCheckmarkOutline" />
<ion-label>
Map facilities to NetSuite
<p>For orders and inventory to sync with NetSuite, the facilities in NetSuite must be mapped to facilities in HotWax Commerce</p>
</ion-label>
</ion-item>
</div>
<div class="list-item">
<ion-item lines="none">
<ion-icon slot="start" :icon="storefrontOutline" />
<ion-label>
<p class="overline">Retail</p>
Store 1 name
<p>Facility Id</p>
</ion-label>
</ion-item>

<ion-label>
shopify mapping
<p>Shopify location</p>
</ion-label>

<div>
<ion-chip :outline="true">
<ion-label>15</ion-label>
<ion-icon :icon="closeCircleOutline" />
</ion-chip>
<ion-label>
<p>NetSuite ID</p>
</ion-label>
</div>

<ion-button fill="clear" color="medium">
<ion-icon slot="icon-only" :icon="ellipsisVerticalOutline" />
</ion-button>
</div>
<div class="list-item">
<ion-item lines="none">
<ion-icon slot="start" :icon="storefrontOutline" />
<ion-label>
<p class="overline">Retail</p>
Store 1 name
<p>Facility Id</p>
</ion-label>
</ion-item>

<ion-label>
shopify mapping
<p>Shopify location</p>
</ion-label>

<div>
<ion-chip :outline="true">
<ion-label>15</ion-label>
<ion-icon :icon="closeCircleOutline" />
</ion-chip>
<ion-label>
<p>NetSuite ID</p>
</ion-label>
</div>

<ion-button fill="clear" color="medium">
<ion-icon slot="icon-only" :icon="ellipsisVerticalOutline" />
</ion-button>
</div>
</ion-content>
</ion-page>
</template>
<script setup lang="ts">
import { translate } from "@/i18n"
import { IonBackButton, IonButton, IonChip, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonPage, IonMenuButton, IonTitle, IonToolbar } from "@ionic/vue";
import { closeCircleOutline, ellipsisVerticalOutline, shieldCheckmarkOutline, storefrontOutline } from 'ionicons/icons'

</script>
<style scoped>
.list-item {
--columns-desktop: 4;
}
</style>
116 changes: 116 additions & 0 deletions src/components/Menu.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<template>
<ion-menu content-id="main-content" type="overlay" :disabled="!isUserAuthenticated">
<ion-header>
<ion-toolbar>
<ion-title>{{ translate("Company") }}</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-list id="company-list">
<ion-menu-toggle auto-hide="false" v-for="(p, i) in appPages" :key="i">
<ion-item button router-direction="root" :router-link="p.url" class="hydrated" :class="{ selected: selectedIndex === i }">
<ion-icon slot="start" :ios="p.iosIcon" :md="p.mdIcon" />
<ion-label>{{ p.title }}</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
</template>

<script lang="ts">
import {
IonContent,
IonIcon,
IonHeader,
IonItem,
IonLabel,
IonList,
IonTitle,
IonToolbar,
IonMenu,
IonMenuToggle,
} from "@ionic/vue";
import { computed, defineComponent } from "vue";
import { mapGetters } from "vuex";
import { businessOutline, cartOutline, settingsOutline, walletOutline } from "ionicons/icons";
import { useStore } from "@/store";
import { useRouter } from "vue-router";
import { translate } from "@/i18n";

export default defineComponent({
name: "Menu",
components: {
IonContent,
IonHeader,
IonIcon,
IonItem,
IonTitle,
IonLabel,
IonList,
IonToolbar,
IonMenu,
IonMenuToggle,
},
computed: {
...mapGetters({
isUserAuthenticated: 'user/isUserAuthenticated',
})
},
setup() {
const store = useStore();
const router = useRouter();
const appPages = [
{
title: "Product Store",
url: "/product-store",
childRoutes: ["/product-store/"],
iosIcon: businessOutline,
mdIcon: businessOutline,
},
// {
// title: "Shopify",
// url: "/shopify",
// childRoutes: ["/shopify/"],
// iosIcon: cartOutline,
// mdIcon: cartOutline,
// },
{
title: "NetSuite",
url: "/netsuite",
childRoutes: ["/netsuite/"],
iosIcon: walletOutline,
mdIcon: walletOutline
},
{
title: "Settings",
url: "/settings",
iosIcon: settingsOutline,
mdIcon: settingsOutline,
}
];

const selectedIndex = computed(() => {
const path = router.currentRoute.value.path
return appPages.findIndex((screen) => screen.url === path || screen.childRoutes?.includes(path) || screen.childRoutes?.some((route) => path.includes(route)))
})

return {
selectedIndex,
appPages,
store,
translate
};
}
});
</script>

<style scoped>
ion-item.selected ion-icon {
color: var(--ion-color-secondary);
}
ion-item.selected {
--color: var(--ion-color-secondary);
}
</style>
Loading