1550 lines
57 KiB
JavaScript
1550 lines
57 KiB
JavaScript
/*
|
||
****************************************************************************
|
||
Component Name : Home
|
||
Created Date : 17/4/2024
|
||
@description : This Home page serves as the main entry point for the application.
|
||
* It handles the navigation to all other component pages. This component integrates
|
||
* with various sub-components and manages the overall layout and
|
||
* state of the application.
|
||
@author : SME Team
|
||
Modification Log:
|
||
Ver Date Author
|
||
1.0 23/4/2024 SME Team
|
||
****************************************************************************
|
||
*/
|
||
|
||
|
||
|
||
import { LightningElement, track, api, wire } from "lwc";
|
||
// DISPLAY-ONLY: used to greet the logged-in user by first name (falling
|
||
// back to last name) in the support panel. No functional/business logic.
|
||
import USER_ID from "@salesforce/user/Id";
|
||
import { getRecord } from "lightning/uiRecordApi";
|
||
import FIRST_NAME_FIELD from "@salesforce/schema/User.FirstName";
|
||
import LAST_NAME_FIELD from "@salesforce/schema/User.LastName";
|
||
|
||
// FETCHING RESOURCES FROM THE STATIC RESOURCES
|
||
// import pageLoadingGif from "@salesforce/resourceUrl/SMEPageLoadingGif";
|
||
// import SyncMadeEasy from "@salesforce/resourceUrl/SyncMadeEasy";
|
||
|
||
// NOT USING
|
||
// import ShopifyProcessingGif from "@salesforce/resourceUrl/ShopifyProcessingGif";
|
||
// import AuthenticateConnecting from "@salesforce/resourceUrl/AuthenticateConnecting";
|
||
// import storeulgetinfo from "@salesforce/resourceUrl/storeulgetinfo";
|
||
// import Configuration from "@salesforce/resourceUrl/Configuration";
|
||
// import DataProcessing from "@salesforce/resourceUrl/DataProcessing";
|
||
|
||
// CUSTOM LABELS FOR THE INSERTION
|
||
|
||
import Back from '@salesforce/label/c.Back';
|
||
import Setup from '@salesforce/label/c.Setup';
|
||
import Shopify_Credentials from '@salesforce/label/c.Shopify_Credentials';
|
||
import Object_Setup from '@salesforce/label/c.Object_Setup';
|
||
import Record_Type from '@salesforce/label/c.Record_Type';
|
||
import Field_Mapping from '@salesforce/label/c.Field_Mapping';
|
||
import Finished from '@salesforce/label/c.Finished';
|
||
import Contact_support from '@salesforce/label/c.Contact_support';
|
||
import Reset_Default_Setting from '@salesforce/label/c.Reset_Default_Setting';
|
||
import Having_More_than_One_Store from '@salesforce/label/c.Having_More_than_One_Store';
|
||
import Edit_Mapping_Message from '@salesforce/label/c.Edit_Mapping_Message';
|
||
import Step_Change_Message from '@salesforce/label/c.Step_Change_Message';
|
||
import Store_Change_Lost_Message from '@salesforce/label/c.Store_Change_Lost_Message';
|
||
import Warning from '@salesforce/label/c.Warning';
|
||
import Error from '@salesforce/label/c.Error';
|
||
import Success from '@salesforce/label/c.Success';
|
||
import New from '@salesforce/label/c.New';
|
||
import Batch_Progress_Message from '@salesforce/label/c.Batch_Progress_Message';
|
||
import Go_To_Record_Type from '@salesforce/label/c.Go_To_Record_Type';
|
||
import Follow_Steps_Message from '@salesforce/label/c.Follow_Steps_Message';
|
||
import Page_Loading_Message from '@salesforce/label/c.Page_Loading_Message';
|
||
import Follow_Starting_Steps from '@salesforce/label/c.Follow_Starting_Steps';
|
||
import Field_Complete_Message from '@salesforce/label/c.Field_Complete_Message';
|
||
import A_maximum_of_1000 from '@salesforce/label/c.A_maximum_of_1000';
|
||
import Existing_Store from '@salesforce/label/c.Existing_Store';
|
||
import Default_Store_Reset from '@salesforce/label/c.Default_Store_Reset';
|
||
import Close from '@salesforce/label/c.Close';
|
||
import Thank_You from '@salesforce/label/c.Thank_You';
|
||
import Issue_not_sent from '@salesforce/label/c.Issue_Not_Sent';
|
||
import Try_Again_Or_Contact_Us from '@salesforce/label/c.Try_Again_Or_Contact_Us';
|
||
import Support_Email_Submitted_Message from '@salesforce/label/c.Support_Email_Submitted_Message';
|
||
import Previous_Page_Button from '@salesforce/label/c.Previous_Page_Button';
|
||
import Go_To_Next_Step_Button from '@salesforce/label/c.Go_To_Next_Step_Button';
|
||
import Please_write_your_issue_here from '@salesforce/label/c.Please_write_your_issue_here';
|
||
import Submit from '@salesforce/label/c.Submit';
|
||
import Issue from '@salesforce/label/c.Issue';
|
||
import Cancel from '@salesforce/label/c.Cancel';
|
||
import OK from '@salesforce/label/c.OK';
|
||
|
||
import Shopify_Warning_Modal from "@salesforce/resourceUrl/Shopify_Warning_Modal";
|
||
import ShopifyMadeEasyLogo from "@salesforce/resourceUrl/ShopifyMadeEasyLogo";
|
||
import SendingMailTrue from "@salesforce/resourceUrl/SendingMailTrue";
|
||
import SendingMailFalse from "@salesforce/resourceUrl/SendingMailFalse";
|
||
|
||
import Resources from "@salesforce/resourceUrl/Resources";
|
||
import SMEPageLoadingGIF2 from "@salesforce/resourceUrl/SMEPageLoadingGIF2";
|
||
|
||
// THIS IS THE PREVIOUS PAGE LOADING GIF
|
||
|
||
// CREATING INSTANCES OF APEX METHODS
|
||
import issuePkceForState from '@salesforce/apex/PkceUtil.issuePkceForState';
|
||
import getConfigrations from '@salesforce/apex/ShopifyController.getConfigrationForMultipleStore';
|
||
import updateAutoConfiguration from '@salesforce/apex/ShopifyController.updateAutoConfiguration';
|
||
import getAutoConfigurationStatus from '@salesforce/apex/ShopifyController.getAutoConfigurationStatus';
|
||
import copyFieldMapping from '@salesforce/apex/ShopifyController.copyFieldMapping';
|
||
import remoteSite from '@salesforce/apex/ShopifyController.remoteSite';
|
||
import syncShopify from "@salesforce/apex/ShopifyController.syncShopify";
|
||
import SendingMailtoShopifySupport from "@salesforce/apex/ShopifyController.sendingMailtoShopifySupport";
|
||
import Checkemaildeliverability from "@salesforce/apex/ShopifyController.checkemaildeliverability";
|
||
import checkBatchIsProcessing from '@salesforce/apex/ShopifyController.checkBatchIsProcessing';
|
||
import runPostInstallScript from "@salesforce/apex/ShopifyController.runPostInstallScript";
|
||
|
||
// DISPLAY-ONLY: last synced (paid) order/opportunity timestamp for the
|
||
// shared "Connected & syncing" hero bar shown on every step from Object
|
||
// Setup onward.
|
||
import getLastOrderSyncTime from '@salesforce/apex/ShopifyController.getLastOrderSyncTime';
|
||
|
||
// DISPLAY-ONLY: caps the store-select combobox dropdown to ~3 rows + scroll.
|
||
import { loadStyle } from 'lightning/platformResourceLoader';
|
||
import COMBOBOX_DROPDOWN_SCROLL from '@salesforce/resourceUrl/comboboxDropdownScroll';
|
||
|
||
// SHOW TOAST EVENT
|
||
import { ShowToastEvent } from "lightning/platformShowToastEvent";
|
||
|
||
import Store from "@salesforce/resourceUrl/shopify_store"
|
||
import Sme_png from "@salesforce/resourceUrl/SME_png"
|
||
// import SMELOGO from "@salesforce/resourceUrl/SMELOGO"
|
||
import SMELogoPNG from "@salesforce/resourceUrl/SMELogoPNG"
|
||
import SupportAgent from "@salesforce/resourceUrl/SupportAgent"
|
||
import StoreLogo from "@salesforce/resourceUrl/StoreLogo"
|
||
import SFLogo from "@salesforce/resourceUrl/SFLogo"
|
||
import SMEPRO from "@salesforce/resourceUrl/SMEPRO"
|
||
|
||
|
||
export default class Home extends LightningElement {
|
||
|
||
// Custom in-component toast state (replaces ShowToastEvent) — see showNotification.
|
||
@track toasts = [];
|
||
_toastSeq = 0;
|
||
|
||
|
||
// GLOBAL VARIABLES
|
||
@track storeList = [];
|
||
@track storeOptions = [];
|
||
selectedStore;
|
||
@track isModalOpen = false;
|
||
@api storeName = "";
|
||
@api storeSelectionType = "";
|
||
@api isNewStore = false;
|
||
@track Store = Store;
|
||
@track Sme_png = Sme_png;
|
||
@track SMELogoPNG = SMELogoPNG;
|
||
@track SupportAgent = SupportAgent;
|
||
@track StoreLogo = StoreLogo;
|
||
@track SFLogo = SFLogo;
|
||
@track SMEPRO = SMEPRO;
|
||
|
||
// DISPLAY-ONLY: last synced (paid) order/opportunity time for the shared
|
||
// hero bar's "Last order synced X ago" line. Mirrors the same logic used
|
||
// in shopifyCredentials — null means this store has never synced a paid
|
||
// order/opportunity, in which case the line stays hidden.
|
||
@track _lastSyncedText = '';
|
||
_syncTimerId = null;
|
||
_syncStoreChecked = null;
|
||
|
||
// DISPLAY-ONLY: current user's name for the "Hello, {name}" greeting
|
||
// in the support panel. Purely presentational, no functional impact.
|
||
@wire(getRecord, { recordId: USER_ID, fields: [FIRST_NAME_FIELD, LAST_NAME_FIELD] })
|
||
currentUser;
|
||
|
||
get greetingName() {
|
||
const firstName = this.currentUser?.data?.fields?.FirstName?.value;
|
||
const lastName = this.currentUser?.data?.fields?.LastName?.value;
|
||
return firstName || lastName || '';
|
||
}
|
||
|
||
// LOCAL VARIABLES
|
||
batchTriggered = false;
|
||
isAutomatic = false;
|
||
useAutomatic = true;
|
||
@track autoConfigSaveTimeout;
|
||
@track autoConfigJustEnabled = false;
|
||
@track storeNameFromCredentials = '';
|
||
@track autoJumpInProgress = false;
|
||
@track spinnerClosed = true;
|
||
@track optionList = [];
|
||
@track usercurrentvalue = Setup;
|
||
@track usercurrentpathvalue = "";
|
||
@track userselectedpathvalue = Setup;
|
||
@track hideTopButtons = true;
|
||
@track hideBottomButtons = true;
|
||
@track hideLeftButton = true;
|
||
@track hideRightButton = false;
|
||
@track processing = false;
|
||
@track showStore = false;
|
||
@track contactModel = false;
|
||
@track issueDescription = "";
|
||
@track supportEmailError = false;
|
||
@track supportEmailSent = false;
|
||
@track contactSupport = false;
|
||
@track isSubmit = true;
|
||
@track batchProcessingStatus = false;
|
||
@track batchProcessingObject = {};
|
||
@track setupComponent = false;
|
||
@track shopifyCredentialComponent = false;
|
||
@track objectMappingComponent = false;
|
||
@track fieldMappingComponent = false;
|
||
@track recordyTypeComponent = false;
|
||
@track finishedComponent = false;
|
||
@track multiStoreModel = false;
|
||
@track shopifyCredentialMultiStore = false;
|
||
@track warningModel = false;
|
||
@track reordtypeSync = false;
|
||
@track setupColor = "darkGreenColor";
|
||
@track credentialColor = "grayColor";
|
||
@track objectColor = "grayColor";
|
||
@track fieldColor = "grayColor";
|
||
@track recordColor = "grayColor";
|
||
@track finishColor = "grayColor";
|
||
@track currentvaluecheck = true;
|
||
@track checkpathwithcurrentvalue = true;
|
||
@track checkMultiStoreIsExisting = true;
|
||
@track fieldMappings = "";
|
||
@track multiStoreButtonClicked = false;
|
||
@track label = {
|
||
Back, Contact_support, Go_To_Record_Type, Close,
|
||
Existing_Store, Default_Store_Reset,
|
||
Field_Complete_Message, Follow_Starting_Steps,
|
||
Page_Loading_Message, Follow_Steps_Message,
|
||
Reset_Default_Setting, Having_More_than_One_Store,
|
||
Edit_Mapping_Message, Step_Change_Message, Go_To_Next_Step_Button,
|
||
Store_Change_Lost_Message, Warning, Error, Support_Email_Submitted_Message, Previous_Page_Button,
|
||
Success, New, Batch_Progress_Message, Thank_You, Issue_not_sent, Try_Again_Or_Contact_Us,
|
||
Please_write_your_issue_here, Issue, A_maximum_of_1000, Submit, Cancel, OK
|
||
};
|
||
|
||
//CREATING IMAGE OBJECT TO USE ON HTML
|
||
// @track imageLogo = {SyncMadeEasy,DataProcessing,Configuration,pageLoadingGif,storeulgetinfo,AuthenticateConnecting,ShopifyProcessingGif,SendingMailTrue,SendingMailFalse};
|
||
@track imageLogo = { SendingMailTrue, SendingMailFalse };
|
||
ShopifyMadeEasyLogo = Resources + "/Resources/SyncMadeEasy.png";
|
||
// SyncMadeEasy = Resources + "/Resources/SyncMadeEasy.svg";
|
||
pageLoadingGif = SMEPageLoadingGIF2;
|
||
supportPersonImg = Resources + '/Resources/SupportPersonImage.png';
|
||
upgradeProImg = Resources + '/Resources/Pro.png';
|
||
SyncProImg = Resources + '/Resources/SyncPro.png';
|
||
|
||
|
||
// CONNECTED CALLBACK
|
||
connectedCallback() {
|
||
console.log('SYNC MADE EASY INITIALIZED');
|
||
|
||
this.checkRemoteSiteSettings();
|
||
// let labelList = ["Setup", "Shopify Credentials", "Object Setup", "Field Mapping", "Record Type", "Finished"];
|
||
let labelList = [Setup, Shopify_Credentials, Object_Setup, Field_Mapping, Record_Type, Finished];
|
||
let priority = 1;
|
||
labelList.map((value) => {
|
||
this.optionList.push({ label: value, value: value, selected: false, priority: priority++ });
|
||
});
|
||
this.handleBatchProcessing();
|
||
if (this.storeName) {
|
||
this.fetchAutoConfigurationStatus(this.storeName);
|
||
}
|
||
this.template.addEventListener('autoconfigchange', this.handleAutoConfigChange.bind(this));
|
||
|
||
// Refresh the server-computed "X ago" label every 60s.
|
||
this._syncTimerId = setInterval(() => {
|
||
if (this.storeName) this.loadLastOrderSyncTime();
|
||
}, 60000);
|
||
}
|
||
|
||
disconnectedCallback() {
|
||
if (this._syncTimerId) {
|
||
clearInterval(this._syncTimerId);
|
||
this._syncTimerId = null;
|
||
}
|
||
}
|
||
|
||
// storeName is set from many places across the wizard (credentials step,
|
||
// batch processing, dashboard events, etc.), so rather than hook every
|
||
// assignment site, renderedCallback picks up the change once and fires a
|
||
// single Apex call per new store — cheap and idempotent.
|
||
renderedCallback() {
|
||
if (this.storeName && this.storeName !== this._syncStoreChecked) {
|
||
this._syncStoreChecked = this.storeName;
|
||
this.loadLastOrderSyncTime();
|
||
}
|
||
// Load the combobox dropdown height cap once.
|
||
if (!this._comboScrollLoaded) {
|
||
this._comboScrollLoaded = true;
|
||
loadStyle(this, COMBOBOX_DROPDOWN_SCROLL).catch((error) => {
|
||
console.log('SME: loadStyle combobox scroll error', JSON.stringify(error));
|
||
});
|
||
}
|
||
}
|
||
|
||
// DISPLAY-ONLY: fetches the ready-formatted "Last order synced X ago" text
|
||
// for the current store (time math done server-side in Apex via Datetime.now()).
|
||
loadLastOrderSyncTime() {
|
||
getLastOrderSyncTime({ store: this.storeName })
|
||
.then((text) => {
|
||
this._lastSyncedText = text || '';
|
||
})
|
||
.catch((error) => {
|
||
console.log('SME: getLastOrderSyncTime error', JSON.stringify(error));
|
||
this._lastSyncedText = '';
|
||
});
|
||
}
|
||
|
||
// Show the "Last order synced …" line ONLY when this store has actually
|
||
// synced a paid order/opportunity into this org.
|
||
get showLastSynced() {
|
||
return !!this._lastSyncedText;
|
||
}
|
||
|
||
get lastSyncedText() {
|
||
return this._lastSyncedText || '';
|
||
}
|
||
|
||
handleAutoConfigChange(event) {
|
||
console.log('>>> Auto config change event received: ' + event.detail);
|
||
this.isAutomatic = event.detail;
|
||
|
||
// Update child components if needed
|
||
this.updateChildAutoConfigState(this.isAutomatic);
|
||
}
|
||
|
||
// METHOD IS FOR AUTOMATION OF THE APP
|
||
changeConfigurationType(event) {
|
||
console.log('HOME AUTOMATIION ' + event.detail);
|
||
const newAutoConfigValue = event.detail;
|
||
this.isAutomatic = newAutoConfigValue;
|
||
|
||
if (this.storeName) {
|
||
this.saveAutoConfiguration(newAutoConfigValue);
|
||
}
|
||
|
||
}
|
||
|
||
saveAutoConfiguration(isAuto) {
|
||
clearTimeout(this.autoConfigSaveTimeout);
|
||
|
||
this.autoConfigSaveTimeout = setTimeout(() => {
|
||
updateAutoConfiguration({
|
||
storeName: this.storeName,
|
||
isAuto: isAuto
|
||
})
|
||
.then((result) => {
|
||
console.log('>>> Auto Configuration saved: ' + isAuto + ', Result: ' + result);
|
||
this.autoConfigJustEnabled = isAuto;
|
||
})
|
||
.catch((error) => {
|
||
console.error('>>> Error saving Auto Configuration:', error);
|
||
// Silent fail for auto-save to avoid annoying user
|
||
});
|
||
}, 500);
|
||
}
|
||
fetchAutoConfigurationStatus(storeName) {
|
||
if (!storeName) {
|
||
this.isAutomatic = false;
|
||
return Promise.resolve(false);
|
||
}
|
||
|
||
// Show spinner while checking status
|
||
this.spinnerClosed = false;
|
||
this.processing = true;
|
||
|
||
// Direct call without cache - ensures fresh data from database
|
||
return getAutoConfigurationStatus({ storeName: storeName })
|
||
.then((result) => {
|
||
console.log('>>> FRESH Auto Configuration status for ' + storeName + ': ' + result);
|
||
|
||
// Set auto-config based on LATEST database value
|
||
this.isAutomatic = (result === true);
|
||
|
||
// Update child components
|
||
this.updateChildAutoConfigState(this.isAutomatic);
|
||
|
||
return result;
|
||
})
|
||
.catch((error) => {
|
||
console.error('>>> Error fetching Auto Configuration status:', error);
|
||
this.isAutomatic = false;
|
||
return false;
|
||
})
|
||
.finally(() => {
|
||
this.spinnerClosed = true;
|
||
this.processing = false;
|
||
});
|
||
}
|
||
updateChildAutoConfigState(isAuto) {
|
||
// Try to update child components if they have setter methods
|
||
const credentialsComp = this.template.querySelector('c-shopify-credentials');
|
||
if (credentialsComp && typeof credentialsComp.setAutoConfiguration === 'function') {
|
||
credentialsComp.setAutoConfiguration(isAuto);
|
||
}
|
||
|
||
const setupComp = this.template.querySelector('c-setup');
|
||
if (setupComp && typeof setupComp.setAutoConfiguration === 'function') {
|
||
setupComp.setAutoConfiguration(isAuto);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* This Method is called to create remote site settings
|
||
*/
|
||
checkRemoteSiteSettings() {
|
||
console.log('SYNC MADE EASY CREATING REMOTE SITE');
|
||
remoteSite().then((result) => {
|
||
//Success
|
||
}).catch((error) => {
|
||
//Error occured
|
||
});
|
||
}
|
||
|
||
// CHECK EXISTING STORE IS SELECTED OR EDITED OR CREATING A NEW STORE
|
||
checkExistingStoreHandler(event) {
|
||
this.checkMultiStoreIsExisting = event.detail.subject;
|
||
this.multiStoreModel = false;
|
||
this.storeName = event.detail.storeName;
|
||
this.shopifyCredentialMultiStore = false;
|
||
this.storeSelectionType = event.detail.storeSelectType;
|
||
|
||
// Reset per-session state so stale values from the previous store
|
||
// don't bleed into the new store's credentials / object-setup flow.
|
||
this.batchTriggered = false;
|
||
this.storeNameFromCredentials = '';
|
||
this.autoJumpInProgress = false;
|
||
|
||
// if (this.storeSelectionType.toLowerCase() === this.label.New) {
|
||
if (this.storeSelectionType === this.label.New) {
|
||
this.isNewStore = true;
|
||
this.isAutomatic = false;
|
||
this.resetChildComponent();
|
||
} else {
|
||
this.isNewStore = false;
|
||
this.fetchAutoConfigurationStatus(this.storeName)
|
||
.then(() => {
|
||
// Only reset component after status is confirmed
|
||
this.resetChildComponent();
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
// PATH HANDLER
|
||
pathHandler(event) {
|
||
const selectedStep = event.target.value;
|
||
|
||
if (this.batchProcessingStatus) {
|
||
this.showNotification(
|
||
this.label.Warning,
|
||
'Warning',
|
||
this.label.Batch_Progress_Message
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Prevent navigation to disabled steps in auto mode
|
||
if (this.isAutomatic && (selectedStep === Object_Setup || selectedStep === Field_Mapping)) {
|
||
this.showNotification(
|
||
this.label.Warning,
|
||
'Warning',
|
||
'Object Setup and Field Mapping are Auto Configured'
|
||
);
|
||
return;
|
||
}
|
||
|
||
// CHECKING IF THE PAGE IS STILL LOADING
|
||
if (!this.spinnerClosed) {
|
||
this.showNotification(this.label.Warning, 'Warning', this.label.Page_Loading_Message);
|
||
return;
|
||
}
|
||
// Restrict navigation from Setup if status is not checked
|
||
if (this.usercurrentvalue === Setup && this.refs.setup && !this.refs.setup.isStatusChecked) {
|
||
if (selectedStep !== Setup) {
|
||
this.refs.setup.goNextPage();
|
||
return;
|
||
}
|
||
}
|
||
|
||
// CHAECKING IF IT IS AN EXISTING STORE OR NOT
|
||
if (this.spinnerClosed && this.checkMultiStoreIsExisting) {
|
||
this.childComponentName = [];
|
||
this.userselectedpathvalue = event.target.value;
|
||
let currentPriority = 1;
|
||
let selectedPriority = 1;
|
||
|
||
// HANDLING THE EVENT OCCURES ON PATH HANDLER
|
||
for (let options of this.optionList) {
|
||
if (this.usercurrentvalue !== Record_Type && this.userselectedpathvalue === Finished) {
|
||
this.showNotification(this.label.Error, 'Error', this.label.Go_To_Record_Type);
|
||
this.userselectedpathvalue = this.usercurrentvalue;
|
||
return null;
|
||
}
|
||
if (this.usercurrentvalue == options.label) {
|
||
currentPriority = options.priority;
|
||
}
|
||
if (this.userselectedpathvalue == options.label) {
|
||
selectedPriority = options.priority;
|
||
}
|
||
}
|
||
|
||
// HANDLE AUTO-CONFIG NAVIGATION FROM CREDENTIALS TO RECORD TYPE
|
||
if (this.isAutomatic && this.usercurrentvalue === Shopify_Credentials && selectedStep === Record_Type) {
|
||
// Validate we have store name before allowing direct jump to Record Type
|
||
if (!this.storeName) {
|
||
this.showNotification(this.label.Error, 'Error', 'Please save credentials first');
|
||
return;
|
||
}
|
||
|
||
// Set flags for auto-navigation
|
||
this.autoJumpInProgress = true;
|
||
this.usercurrentvalue = Record_Type;
|
||
this.userselectedpathvalue = Record_Type;
|
||
|
||
for (let option of this.optionList) {
|
||
option.selected = (option.label === Record_Type);
|
||
}
|
||
|
||
this.resetChildComponent();
|
||
return;
|
||
}
|
||
|
||
// HANDLE FINISH FROM RECORD TYPE IN AUTO MODE
|
||
if (selectedPriority === 6 && currentPriority === 5) {
|
||
if (this.isAutomatic) {
|
||
console.log('>>> Auto mode: Finish path - delegating to save flow');
|
||
|
||
// DON'T execute batch here!
|
||
// Just set target and let handleNextButton trigger proper save flow
|
||
this.userselectedpathvalue = Finished;
|
||
this.handleNextButton();
|
||
return;
|
||
}
|
||
this.handleNextButton();
|
||
}
|
||
else {
|
||
this.optionList.map((options) => {
|
||
if (this.userselectedpathvalue == options.label) {
|
||
this.usercurrentvalue = this.userselectedpathvalue;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
});
|
||
}
|
||
|
||
// RESETTING THE PAGE STRUCTURE AND CSS OF THE UI
|
||
this.resetChildComponent();
|
||
} // IF STORE IS NEW IS EDITED BY THE USER
|
||
else if (this.spinnerClosed && !this.checkMultiStoreIsExisting) {
|
||
this.userselectedpathvalue = event.target.value;
|
||
let currentPriority = 1;
|
||
let selectedPriority = 1;
|
||
currentPriority = this.optionList.find(obj => obj.label === this.usercurrentvalue)?.priority;
|
||
selectedPriority = this.optionList.find(obj => obj.label === this.userselectedpathvalue)?.priority;
|
||
|
||
if (currentPriority + 1 === selectedPriority) {
|
||
// Enforce store existence check for Shopify Credentials
|
||
if (this.usercurrentvalue === Shopify_Credentials && !this.storeName) {
|
||
this.showNotification(this.label.Error, 'Error', 'Please save credentials first.');
|
||
return;
|
||
}
|
||
// Just navigate forward the same way backward navigation works.
|
||
for (let options of this.optionList) {
|
||
if (this.userselectedpathvalue == options.label) {
|
||
this.usercurrentvalue = this.userselectedpathvalue;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
} else if (selectedPriority < currentPriority) {
|
||
for (let options of this.optionList) {
|
||
if (this.userselectedpathvalue == options.label) {
|
||
this.usercurrentvalue = this.userselectedpathvalue;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
|
||
} else {
|
||
this.showNotification(this.label.Error, 'Error', this.label.Follow_Steps_Message);
|
||
}
|
||
} else {
|
||
this.showNotification(this.label.Error, 'Error', this.label.Follow_Starting_Steps);
|
||
}
|
||
}
|
||
|
||
navigateToFinish() {
|
||
console.log('>>> navigateToFinish called');
|
||
|
||
// Set current values to Finish
|
||
this.usercurrentvalue = Finished;
|
||
this.userselectedpathvalue = Finished;
|
||
|
||
// Update all option selections
|
||
for (let option of this.optionList) {
|
||
option.selected = (option.label === Finished);
|
||
}
|
||
|
||
// Reset and show finish component
|
||
this.resetChildComponent();
|
||
}
|
||
|
||
// RESETTING VALUE FOR ALL THE COMPONENT BEFORE SETTING THE VALUES AS PER THE CURRENT COMPONENT
|
||
resetChildComponent() {
|
||
console.log('>>> resetChildComponent called for: ' + this.usercurrentvalue);
|
||
|
||
// IMMEDIATE CHECK: If auto-config is ON and trying to show disabled pages, skip immediately
|
||
if (this.isAutomatic && (this.usercurrentvalue === Object_Setup || this.usercurrentvalue === Field_Mapping)) {
|
||
console.log('>>> AUTO CONFIG: Blocking disabled page ' + this.usercurrentvalue);
|
||
|
||
// Show warning notification
|
||
this.showNotification(
|
||
this.label.Warning,
|
||
'Warning',
|
||
'Object Setup and Field Mapping are Auto Configured'
|
||
);
|
||
|
||
// Auto-navigate to next valid page
|
||
setTimeout(() => {
|
||
if (this.usercurrentvalue === Object_Setup) {
|
||
// Skip to Field Mapping (which will also be blocked and skip to Record Type)
|
||
this.usercurrentvalue = Field_Mapping;
|
||
this.resetChildComponent();
|
||
} else if (this.usercurrentvalue === Field_Mapping) {
|
||
// Skip to Record Type
|
||
this.usercurrentvalue = Record_Type;
|
||
this.userselectedpathvalue = Record_Type;
|
||
|
||
// Update selection
|
||
for (let option of this.optionList) {
|
||
option.selected = (option.label === Record_Type);
|
||
}
|
||
|
||
this.autoJumpInProgress = true;
|
||
this.resetChildComponent();
|
||
}
|
||
}, 100);
|
||
|
||
return; // Stop here, don't render the disabled component
|
||
}
|
||
|
||
this.processing = true;
|
||
this.setupComponent = false;
|
||
this.shopifyCredentialComponent = false;
|
||
this.objectMappingComponent = false;
|
||
this.fieldMappingComponent = false;
|
||
this.recordyTypeComponent = false;
|
||
this.finishedComponent = false;
|
||
this.setColors("grayColor", "grayColor", "grayColor", "grayColor", "grayColor", "grayColor");
|
||
this.showChildComponent();
|
||
}
|
||
|
||
// SETTING UP THE COLORS FOR THE COMPONENTS AS PER THE SELECTION
|
||
setColors(setupColor, credentialColor, objectColor, fieldColor, recordColor, finishColor) {
|
||
this.setupColor = setupColor;
|
||
this.credentialColor = credentialColor;
|
||
this.objectColor = objectColor;
|
||
this.fieldColor = fieldColor;
|
||
this.recordColor = recordColor;
|
||
this.finishColor = finishColor;
|
||
}
|
||
|
||
// BUTTON RENDERING CONTROLLER AS PER THE USER SELECTED PAGE
|
||
showButtons(showStore, hideTopButtons, hideBottomButtons, hideLeftButton) {
|
||
this.showStore = showStore;
|
||
this.hideTopButtons = hideTopButtons;
|
||
this.hideBottomButtons = hideBottomButtons;
|
||
this.hideLeftButton = hideLeftButton;
|
||
}
|
||
|
||
// CHILD COMPONENT CONTROLLER TO SHOW OR HIDE THE CHILD COMPONENT
|
||
showChildComponent() {
|
||
for (let option of this.optionList) {
|
||
if (option.selected) {
|
||
if (option.label == Setup) {
|
||
this.setupComponent = true;
|
||
this.setColors("darkGreenColor", "grayColor", "grayColor", "grayColor", "grayColor", "grayColor");
|
||
this.showButtons(false, true, true, true);
|
||
} else if (option.label == Shopify_Credentials) {
|
||
this.shopifyCredentialComponent = true;
|
||
this.setColors("greenColor", "darkGreenColor", "grayColor", "grayColor", "grayColor", "grayColor");
|
||
// hideBottomButtons is now true: shopifyCredentials.html has its own
|
||
// in-card Back / Save & Next footer (added for the reference-mockup
|
||
// restyle), so home's bottom bar would otherwise duplicate it — same
|
||
// pattern already used for the Setup step above.
|
||
this.showButtons(false, true, true, true);
|
||
} else if (option.label == Object_Setup) {
|
||
this.objectMappingComponent = true;
|
||
this.setColors("greenColor", "greenColor", "darkGreenColor", "grayColor", "grayColor", "grayColor");
|
||
this.showButtons(true, true, true, true);
|
||
} else if (option.label == Field_Mapping) {
|
||
this.fieldMappingComponent = true;
|
||
this.setColors("greenColor", "greenColor", "greenColor", "darkGreenColor", "grayColor", "grayColor");
|
||
this.showButtons(true, true, true, true);
|
||
} else if (option.label == Record_Type) {
|
||
this.recordyTypeComponent = true;
|
||
this.setColors("greenColor", "greenColor", "greenColor", "greenColor", "darkGreenColor", "grayColor");
|
||
this.showButtons(true, true, false, false);
|
||
} else if (option.label == Finished) {
|
||
this.finishedComponent = true;
|
||
this.setColors("greenColor", "greenColor", "greenColor", "greenColor", "greenColor", "darkGreenColor");
|
||
this.showButtons(false, true, true, false);
|
||
} else {
|
||
//Error occurs
|
||
}
|
||
}
|
||
}
|
||
this.processing = false;
|
||
}
|
||
|
||
// OPEN SUPPORT MODAL TO EMAIL THE QUERY
|
||
openContactSupport() {
|
||
this.contactModel = true;
|
||
this.lockBodyScroll();
|
||
|
||
if (!this.spinnerClosed) {
|
||
this.contactModel = false;
|
||
this.unlockBodyScroll();
|
||
}
|
||
|
||
// CHECKING THE MAIL DELIVERABILITY IF SUPPORTED BY THE USER PERMISSIONS OR NOT
|
||
Checkemaildeliverability()
|
||
.then((result) => {
|
||
if (result) {
|
||
this.contactSupport = true;
|
||
}
|
||
else {
|
||
this.supportEmailError = true;
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
this.supportEmailError = true;
|
||
});
|
||
}
|
||
|
||
// CLOSE SUPPORT MODAL
|
||
closeModal() {
|
||
this.contactModel = false;
|
||
this.unlockBodyScroll();
|
||
this.supportEmailSent = false;
|
||
this.supportEmailError = false;
|
||
this.contactSupport = false;
|
||
}
|
||
|
||
// CLOSE STORE CHANGE WARNING MODAL
|
||
closeWarningModal() {
|
||
this.warningModel = false;
|
||
this.unlockBodyScroll();
|
||
}
|
||
|
||
// STORE OPERATION HANDLER IF THE USER IS EDITING OR SELECTING THE STORE OR IF THE USER IS CONFIGURING THE NEW STORE
|
||
configureMultiStore() {
|
||
this.warningModel = false;
|
||
this.unlockBodyScroll();
|
||
if (this.usercurrentvalue !== Shopify_Credentials) {
|
||
this.shopifyCredentialMultiStore = true;
|
||
this.usercurrentvalue = Shopify_Credentials;
|
||
this.userselectedpathvalue = Shopify_Credentials;
|
||
for (let option of this.optionList) {
|
||
if (option.label == this.usercurrentvalue) {
|
||
option.selected = true;
|
||
} else {
|
||
option.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
} else {
|
||
this.refs.shopifyCredentials.openMultiStoreController();
|
||
}
|
||
|
||
}
|
||
|
||
// BUTTON IS CALLED FROM THE HTML WHICH IS USED TO SEND THE EMAIL TO THE SUPPORT
|
||
submitDetails() {
|
||
console.log('I m in submit details method');
|
||
// Trim leading and trailing spaces from the issue description
|
||
const trimmedIssueDescription = this.issueDescription.trim();
|
||
|
||
// Check if the trimmed issue description is empty
|
||
if (trimmedIssueDescription === "") {
|
||
console.log('If Block is executed');
|
||
this.contactModel = true;
|
||
this.lockBodyScroll();
|
||
|
||
// Display an error message if the issue description is empty after trimming
|
||
this.showNotification(this.label.Error, 'Error', this.label.Field_Complete_Message);
|
||
} else {
|
||
// If the issue description is not empty after trimming, proceed to submit
|
||
this.contactModel = false;
|
||
this.unlockBodyScroll();
|
||
console.log('Else Block is executed');
|
||
this.contactSupport = false;
|
||
|
||
SendingMailtoShopifySupport({ issue: this.issueDescription })
|
||
.then((result) => {
|
||
this.supportEmailSent = true;
|
||
this.contactModel = false;
|
||
this.unlockBodyScroll();
|
||
this.issueDescription = "";
|
||
setTimeout(() => {
|
||
this.supportEmailSent = false;
|
||
|
||
}, 6000);
|
||
})
|
||
.catch((error) => {
|
||
t
|
||
this.contactModel = true;
|
||
this.lockBodyScroll();
|
||
this.supportEmailError = true;
|
||
|
||
});
|
||
}
|
||
console.log('Submit details method end');
|
||
}
|
||
|
||
|
||
// HANDLING THE ISSUE DESCRIPTION METHOD CALLS FROM THE HTML
|
||
issueHandler(event) {
|
||
this.issueDescription = (event.detail && event.detail.value !== undefined) ? event.detail.value : event.target.value;
|
||
}
|
||
|
||
// METHOD IS CALLED FROM HTML AND IS USED TO OPEN THE WARNING MODAL BEFORE CHANGING THE STORE
|
||
multipleStores() {
|
||
if (this.batchProcessingStatus) {
|
||
this.showNotification(this.label.Warning, 'Warning', this.label.Batch_Progress_Message);
|
||
} else if (!this.spinnerClosed) {
|
||
this.warningModel = false;
|
||
} else if (this.usercurrentvalue === Setup) {
|
||
this.multiStoreButtonClicked = true;
|
||
this.refs.setup.goNextPage();
|
||
} else {
|
||
this.warningModel = true;
|
||
this.lockBodyScroll();
|
||
}
|
||
}
|
||
|
||
// CALLED FROM HTML AND USED TO GO TO THE PREVIOUS COMPONENT
|
||
previousPage() {
|
||
if (this.batchProcessingStatus) {
|
||
this.showNotification(this.label.Warning, 'Warning', this.label.Batch_Progress_Message);
|
||
} else {
|
||
let index = 0;
|
||
for (let option of this.optionList) {
|
||
if (option.label == this.usercurrentvalue) {
|
||
index = this.optionList.indexOf(option);
|
||
option.selected = false;
|
||
}
|
||
}
|
||
|
||
// If auto configuration is ON and current page is Record Type, skip to Shopify Credentials
|
||
if (this.isAutomatic && this.usercurrentvalue === Record_Type) {
|
||
// Find Shopify Credentials index
|
||
const credentialsIndex = this.optionList.findIndex(opt => opt.label === Shopify_Credentials);
|
||
if (credentialsIndex !== -1) {
|
||
this.optionList[credentialsIndex].selected = true;
|
||
this.usercurrentvalue = this.optionList[credentialsIndex].label;
|
||
this.userselectedpathvalue = this.optionList[credentialsIndex].label;
|
||
}
|
||
} else {
|
||
this.optionList[index - 1].selected = true;
|
||
this.usercurrentvalue = this.optionList[index - 1].label;
|
||
this.userselectedpathvalue = this.optionList[index - 1].label;
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
}
|
||
|
||
// CALLED FROM HTML AND USED TO GO TO THE NEXT COMPONENT
|
||
handleNextButton() {
|
||
console.log('>>> handleNextButton');
|
||
this.ensureStoreName();
|
||
|
||
if (this.isAutomatic && (this.usercurrentvalue === Object_Setup || this.usercurrentvalue === Field_Mapping)) {
|
||
this.nextPage();
|
||
return;
|
||
}
|
||
if (this.usercurrentvalue == Shopify_Credentials) {
|
||
console.log('>>> handleNextButton 1 block');
|
||
this.refs.shopifyCredentials.handleSaveShopifyCredentials();
|
||
console.log('>>> handleNextButton creds');
|
||
} else if (this.usercurrentvalue == Object_Setup) {
|
||
console.log('>>> handleNextButton 2 block');
|
||
this.refs.objectMapping.handleSave();
|
||
console.log('>>> handleNextButton object map');
|
||
} else if (this.usercurrentvalue == Field_Mapping) {
|
||
console.log('>>> handleNextButton 3 block');
|
||
console.log('>>> handleNextButton Field Mapping');
|
||
this.refs.fieldMappingParent.handleSaveButton();
|
||
console.log('>>> handleNextButton Field Mapping');
|
||
} else if (this.usercurrentvalue == Record_Type) {
|
||
console.log('>>> handleNextButton 4 block');
|
||
this.refs.recordTypeMapping.handleSaveRecordTypeMapping();
|
||
console.log('>>> handleNextButton Record Type');
|
||
} else if (this.usercurrentvalue == Setup) {
|
||
console.log('>>> handleNextButton 5 block');
|
||
this.refs.setup.goNextPage();
|
||
console.log('>>> handleNextButton setup');
|
||
} else {
|
||
console.log('>>> handleNextButton else and 6 block');
|
||
this.nextPage();
|
||
console.log('>>> handleNextButton else');
|
||
}
|
||
}
|
||
|
||
// THIS METHOD IS USED TO CONTROLLER THE NEXT PAGE RENDERING
|
||
nextPage() {
|
||
console.log('This is executed : ', this.usercurrentvalue);
|
||
let index = 0;
|
||
|
||
for (let option of this.optionList) {
|
||
if (option.label == this.usercurrentvalue) {
|
||
index = this.optionList.indexOf(option);
|
||
console.log('loop block is executed >>>', this.usercurrentvalue, index);
|
||
console.log('loop block is executed >>>', this.usercurrentvalue);
|
||
option.selected = false;
|
||
}
|
||
}
|
||
const previousValue = this.usercurrentvalue;
|
||
const nextOption = this.optionList[index + 1];
|
||
if (!nextOption) {
|
||
console.error('>>> ERROR: No next option found');
|
||
return;
|
||
}
|
||
nextOption.selected = true;
|
||
this.usercurrentvalue = nextOption.label;
|
||
// HANDLE AUTO-CONFIG BATCH TRIGGER BEFORE FINISH
|
||
if (
|
||
this.isAutomatic &&
|
||
previousValue === Record_Type &&
|
||
this.usercurrentvalue === Finished
|
||
) {
|
||
// If batch already triggered from pathHandler, just show finish page
|
||
if (this.batchTriggered) {
|
||
console.log('>>> Batch already triggered from pathHandler, just showing Finish page');
|
||
this.resetChildComponent();
|
||
return;
|
||
}
|
||
|
||
// Otherwise trigger batch (for Save & Next button flow)
|
||
console.log('>>> Auto config: triggering batch before Finish from nextPage');
|
||
const storeToSync = this.storeName || this.storeNameFromCredentials;
|
||
if (!storeToSync) {
|
||
console.error('>>> ERROR: No store name available for batch in nextPage');
|
||
this.showNotification(this.label.Error, 'Error', 'Store name is missing');
|
||
// Revert navigation
|
||
nextOption.selected = false;
|
||
this.optionList[index].selected = true;
|
||
this.usercurrentvalue = previousValue;
|
||
return;
|
||
}
|
||
this.batchTriggered = true;
|
||
syncShopify({ store: storeToSync })
|
||
.then(() => {
|
||
console.log('>>> Batch SUCCESS from nextPage');
|
||
this.resetChildComponent();
|
||
})
|
||
.catch(error => {
|
||
console.error('>>> Batch ERROR from nextPage', error);
|
||
this.batchTriggered = false;
|
||
// Revert navigation on error
|
||
nextOption.selected = false;
|
||
this.optionList[index].selected = true;
|
||
this.usercurrentvalue = previousValue;
|
||
this.showNotification(this.label.Error, 'Error', 'Batch execution failed');
|
||
});
|
||
return; // stop normal flow here
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
|
||
ensureStoreName() {
|
||
if (!this.storeName && this.storeNameFromCredentials) {
|
||
this.storeName = this.storeNameFromCredentials;
|
||
console.log('>>> Restored storeName from backup: ' + this.storeName);
|
||
}
|
||
return this.storeName;
|
||
}
|
||
|
||
// Used in multistore handler
|
||
closeMultiStoreModal(event) {
|
||
this.multiStoreModel = false;
|
||
}
|
||
|
||
// METHOD USED TO CLOSE MULTISTORE MODAL
|
||
closemodal(event) {
|
||
this.multiStoreModel = false;
|
||
}
|
||
|
||
// THIS IS THE MULTISTORE HANDLER OPENING METHOD FOR SHOPIFY CREDENTIAL COMPONENT
|
||
childHandler(event) {
|
||
this.shopifyCredentialComponent = true;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* METHOD USED TO CALL THE CHILD COMPONENT SAVE DETIALS METHOD BEFORE GOING TO NEXT PAGE
|
||
*/
|
||
childSaveEvent(event) {
|
||
console.log('>>> THIS IS this.isAutomatic :: ' + this.isAutomatic);
|
||
console.log('>>> THIS IS this.storeName :: ' + this.storeName);
|
||
console.log('>>> THIS IS CURRENT VALUE :: ' + this.usercurrentvalue);
|
||
|
||
// Capture store name from credentials save
|
||
if (this.usercurrentvalue == Shopify_Credentials && event.detail) {
|
||
this.storeName = event.detail;
|
||
this.storeNameFromCredentials = event.detail; // Backup store name
|
||
console.log('>>> Store name saved: ' + this.storeName);
|
||
if (this.isAutomatic) {
|
||
this.saveAutoConfiguration(true);
|
||
}
|
||
}
|
||
|
||
// Handle auto-config navigation from Credentials
|
||
if (this.isAutomatic && !this.autoJumpInProgress && this.usercurrentvalue === Shopify_Credentials) {
|
||
// Ensure we have the store name
|
||
if (!this.storeName && event.detail) {
|
||
this.storeName = event.detail;
|
||
}
|
||
this.saveAutoConfiguration(true);
|
||
this.autoJumpInProgress = true;
|
||
|
||
this.usercurrentvalue = Record_Type;
|
||
this.userselectedpathvalue = Record_Type;
|
||
|
||
for (let option of this.optionList) {
|
||
option.selected = (option.label === Record_Type);
|
||
}
|
||
|
||
this.resetChildComponent();
|
||
return;
|
||
}
|
||
|
||
// Handle save from Record Type in auto-config mode
|
||
if (this.isAutomatic && this.usercurrentvalue === Record_Type) {
|
||
console.log('>>> REAL RECORD TYPE SAVE → running batch');
|
||
|
||
// Ensure store name is available
|
||
const storeToSync = this.storeName || this.storeNameFromCredentials;
|
||
if (!storeToSync) {
|
||
console.error('>>> ERROR: No store name available for batch');
|
||
this.showNotification(this.label.Error, 'Error', 'Store name is missing');
|
||
return;
|
||
}
|
||
|
||
this.autoJumpInProgress = false;
|
||
this.batchTriggered = true;
|
||
|
||
syncShopify({ store: storeToSync })
|
||
.then(() => {
|
||
console.log('>>> syncShopify SUCCESS');
|
||
this.nextPage();
|
||
})
|
||
.catch(error => {
|
||
console.error('>>> syncShopify ERROR', error);
|
||
this.batchTriggered = false;
|
||
this.showNotification(this.label.Error, 'Error', 'Batch execution failed');
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Handle manual mode Record Type save
|
||
else if (this.usercurrentvalue == Record_Type) {
|
||
console.log('>>> THIS IS INSIDE RECORD TYPE (Manual) :: ' + this.usercurrentvalue);
|
||
|
||
const storeToSync = this.storeName || this.storeNameFromCredentials;
|
||
if (!storeToSync) {
|
||
console.error('>>> ERROR: No store name available for batch');
|
||
this.showNotification(this.label.Error, 'Error', 'Store name is missing');
|
||
return;
|
||
}
|
||
|
||
syncShopify({ store: storeToSync })
|
||
.then((result) => {
|
||
console.log('>>> THIS IS syncShopify Result :: ');
|
||
})
|
||
.catch((error) => {
|
||
console.log('>>> THIS IS syncShopify Error :: ');
|
||
});
|
||
}
|
||
|
||
// Handle Setup page multi-store button
|
||
if (this.usercurrentvalue === Setup && this.multiStoreButtonClicked) {
|
||
this.multiStoreButtonClicked = false;
|
||
this.warningModel = true;
|
||
}
|
||
|
||
// Normal navigation flow
|
||
if (this.usercurrentvalue == this.userselectedpathvalue) {
|
||
this.nextPage();
|
||
this.userselectedpathvalue = this.usercurrentvalue;
|
||
} else if (!this.checkMultiStoreIsExisting && this.usercurrentvalue !== this.userselectedpathvalue) {
|
||
this.nextPage();
|
||
} else {
|
||
if (this.checkMultiStoreIsExisting) {
|
||
for (let option of this.optionList) {
|
||
if (this.userselectedpathvalue == option.label) {
|
||
option.selected = true;
|
||
this.usercurrentvalue = this.userselectedpathvalue;
|
||
} else {
|
||
option.selected = false;
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
} else {
|
||
this.showNotification(this.label.Error, 'Error', this.label.Follow_Starting_Steps);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ??? CHECK WHETHER THIS COMPONENT IS BEING CALLED FROM ANY COMPONENT OR HTML PART
|
||
savePreviousPageValue() {
|
||
console.log('>>> savePreviousPageValue');
|
||
if (this.usercurrentpathvalue !== this.usercurrentvalue) {
|
||
this.handleNextButton();
|
||
console.log('>>> savePreviousPageValuex inside');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* THIS METHOD IS CALLED FROM THE FINISH PAGE IF ANY ERROR OCCURED IN BATCH PROCESSING
|
||
*/
|
||
|
||
finishedSaveEvent(event) {
|
||
for (let options of this.optionList) {
|
||
if (event.detail == options.label) {
|
||
this.usercurrentvalue = options.label;
|
||
this.userselectedpathvalue = options.label;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
|
||
// HANDLE WHETHER THE BATHC IS BEING PROCESSING OF NOT
|
||
handleBatchProcessingEvent(event) {
|
||
for (let options of this.optionList) {
|
||
if (event.detail.pathName == options.label) {
|
||
this.usercurrentvalue = options.label;
|
||
this.userselectedpathvalue = options.label;
|
||
this.storeName = event.detail.store;
|
||
this.batchProcessingStatus = event.detail.batchStatus;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
|
||
// HANDLE WHEN ALL BATCHES ARE COMPLETED IN FINISH PAGE
|
||
handleBatchCompleted(event) {
|
||
if (this.usercurrentvalue === Finished) {
|
||
for (let options of this.optionList) {
|
||
if (event.detail == options.label) {
|
||
this.usercurrentvalue = options.label;
|
||
this.userselectedpathvalue = options.label;
|
||
this.batchProcessingStatus = false;
|
||
options.selected = true;
|
||
this.storeSelectionType = this.label.Existing_Store;
|
||
this.checkMultiStoreIsExisting = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
|
||
}
|
||
|
||
/*
|
||
* THIS METHOD IS USED TO SHOW THE TOAST EVENT
|
||
*/
|
||
// Custom gradient toast (success = green→teal, error = red) instead of
|
||
// ShowToastEvent. Same (title, variant, message) signature/callers.
|
||
showNotification(title, variant, message) {
|
||
const v = (variant || '').toString().toLowerCase();
|
||
const kind = v === 'error' ? 'error' : v === 'success' ? 'success' : v === 'warning' ? 'warning' : 'info';
|
||
const id = 't' + (this._toastSeq++);
|
||
this.toasts = [...this.toasts, {
|
||
id, title, message,
|
||
cssClass: 'sw-toast sw-toast-' + kind,
|
||
iconLabel: kind === 'error' ? '⚠' : kind === 'success' ? '✓' : kind === 'warning' ? '!' : 'ℹ'
|
||
}];
|
||
if (kind !== 'error') {
|
||
// eslint-disable-next-line @lwc/lwc/no-async-operation
|
||
setTimeout(() => this._dismissToast(id), 4000);
|
||
}
|
||
}
|
||
|
||
_dismissToast(id) {
|
||
this.toasts = this.toasts.filter((t) => t.id !== id);
|
||
}
|
||
|
||
handleToastClose(event) {
|
||
this._dismissToast(event.currentTarget.dataset.id);
|
||
}
|
||
|
||
/**
|
||
*
|
||
* THIS METHOD IS USED TO CLOSE THE SPINNER
|
||
*/
|
||
spinnerHandlerTrue() {
|
||
this.spinnerClosed = false;
|
||
this.disablePathHandler = true;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* THIS METHOD IS USED TO OPEN THE SPINNER
|
||
*/
|
||
spinnerHandlerFalse() {
|
||
this.spinnerClosed = true;
|
||
this.disablePathHandler = false;
|
||
}
|
||
|
||
// METHOD TO HANDLE THE BATCH RUNNING STATUS FROM FINISH PAGE
|
||
handleFinishBatchStatus(event) {
|
||
this.batchProcessingStatus = event.detail;
|
||
}
|
||
|
||
get showStoreFromObjectSetupOnward() {
|
||
return this.objectMappingComponent
|
||
|| this.fieldMappingComponent
|
||
|| this.recordyTypeComponent
|
||
// || this.finishedComponent;
|
||
}
|
||
|
||
// METHOD IS USED TO CHECK IF THE BACTH IS ALREADY RUNNING
|
||
handleBatchProcessing() {
|
||
console.log('SYNC MADE EASY: Checking batch details');
|
||
checkBatchIsProcessing().then((result) => {
|
||
this.batchProcessingObject = JSON.parse(result);
|
||
if (this.batchProcessingObject !== null && this.batchProcessingObject?.HIC_ShopifySync__Batch_Is_Processing__c === true) {
|
||
this.storeName = this.batchProcessingObject.HIC_ShopifySync__Store__c;
|
||
this.batchProcessingStatus = this.batchProcessingObject.HIC_ShopifySync__Batch_Is_Processing__c;;
|
||
// Go to the finish page
|
||
for (let options of this.optionList) {
|
||
if (options.label === Finished) {
|
||
this.usercurrentvalue = options.label;
|
||
this.userselectedpathvalue = options.label;
|
||
options.selected = true;
|
||
} else {
|
||
options.selected = false;
|
||
}
|
||
}
|
||
this.resetChildComponent();
|
||
}
|
||
else {
|
||
this.setupComponent = true;
|
||
}
|
||
}).catch((error) => {
|
||
this.showNotification(this.label.Error, 'Error', this.label.Batch_Progress_Message);
|
||
});
|
||
}
|
||
redirectToSalesforce() {
|
||
console.log('>>> URL TO INITIALISE ');
|
||
let clientId = '3MVG9k02hQhyUgQBOt_JP6D3pqjgnrs_fqXqRo3UTb0N952WEZnDenpYrXqh4sFC7vvb6aZQXnD4fURdodCds';
|
||
let redirectUrl = 'https://login.salesforce.com/apex/HIC_ShopifySync__SalesforceAuthentication';
|
||
// PKCE: Apex generates verifier+challenge and packs the verifier into state.
|
||
issuePkceForState({ existingState: '' }).then((pkce) => {
|
||
let urlToOpen = '/services/oauth2/authorize?client_id=' + clientId +
|
||
'&response_type=code&redirect_uri=' + redirectUrl +
|
||
'&code_challenge=' + encodeURIComponent(pkce.codeChallenge) +
|
||
'&code_challenge_method=S256' +
|
||
'&state=' + encodeURIComponent(pkce.state);
|
||
console.log('>>> URL TO INITIALISE 3rd ' + urlToOpen);
|
||
window.open(urlToOpen, '_blank');
|
||
}).catch((error) => {
|
||
console.log('PKCE issuance failed: ' + JSON.stringify(error));
|
||
});
|
||
// var companyId = event.currentTarget.dataset.realmid1;
|
||
// isSandox().then(resp => {
|
||
// //console.log(resp);
|
||
// if (resp) {
|
||
// let urlToOpen = '/services/oauth2/authorize?client_id=' + this.sfClientId_Sand + '&response_type=code&redirect_uri=' + this.sfRedrectUriForSandbox + '&state=sandboxtest_realmid=' + companyId;
|
||
// console.log(urlToOpen);
|
||
// window.open(urlToOpen);
|
||
// // } else {
|
||
// // let urlToOpen = '/services/oauth2/authorize?client_id=' + this.sfClientId_Prod + '&response_type=code&redirect_uri=' + this.sfRedrectUriForProduction + '&state=productionlive_realmid=' + companyId;
|
||
// // console.log(urlToOpen);
|
||
// // window.open(urlToOpen);
|
||
// // }
|
||
// });
|
||
}
|
||
|
||
resetDefaults() {
|
||
console.log('SYNC MADE EASY: Run Post Install');
|
||
if(this.batchProcessingStatus) {
|
||
this.showNotification(this.label.Warning, 'Warning', this.label.Batch_Progress_Message);
|
||
}else if(this.refs.setup && !this.refs.setup.isStatusChecked){
|
||
this.showNotification(this.label.Warning, 'Warning', "Please complete the Salesforce Configuration Step first");
|
||
}else {
|
||
this.isModalOpen = true;
|
||
this.lockBodyScroll();
|
||
this.getStores();
|
||
// runPostInstallScript().then((result) => {
|
||
// if (result === 'Success') {
|
||
// console.log('SYNC MADE EASY: Run Post Install Successfull Ran!');
|
||
// this.showNotification(this.label.Success, 'Success', this.label.Default_Store_Reset);
|
||
// }
|
||
// }).catch((error) => {
|
||
// console.log('SYNC MADE EASY: Run Post Install Script Failed!');
|
||
// this.showNotification(this.label.Error, 'Error', this.label.Error);
|
||
// })
|
||
}
|
||
}
|
||
|
||
closeCertificateModal() {
|
||
this.isModalOpen = false;
|
||
this.unlockBodyScroll();
|
||
this.selectedStore = undefined;
|
||
this.selectedStoreName = null;
|
||
|
||
}
|
||
|
||
getStores() {
|
||
console.log('Fetching stores...');
|
||
console.log('Current working store name:', this.storeName);
|
||
|
||
getConfigrations()
|
||
.then((result) => {
|
||
let data = typeof result === 'string'
|
||
? JSON.parse(result)
|
||
: result;
|
||
|
||
console.log('All stores from Apex:', data);
|
||
|
||
const filteredStores = data.filter(store => {
|
||
const storeLabel = store.Name || store.storeName;
|
||
return storeLabel !== this.storeName;
|
||
});
|
||
|
||
this.storeOptions = filteredStores.map(store => ({
|
||
label: store.Name || store.storeName,
|
||
value: store.Id || store.storeId
|
||
}));
|
||
|
||
console.log('Final combobox options:', this.storeOptions);
|
||
})
|
||
.catch((error) => {
|
||
console.error('Error fetching stores:', error);
|
||
});
|
||
}
|
||
|
||
|
||
|
||
|
||
handleStoreChange(event) {
|
||
const selectedId = event.detail.value;
|
||
this.selectedStore = selectedId;
|
||
|
||
// 🔍 Get store NAME from options
|
||
const selectedOption = this.storeOptions.find(
|
||
option => option.value === selectedId
|
||
);
|
||
|
||
this.selectedStoreName = selectedOption?.label;
|
||
|
||
console.log('Selected Store Id:', this.selectedStore);
|
||
console.log('Selected Store Name:', this.selectedStoreName);
|
||
}
|
||
|
||
|
||
handleCopyMapping() {
|
||
|
||
console.log('setupComponent : ', this.setupComponent);
|
||
console.log('shopifyCredentialComponent : ', this.shopifyCredentialComponent);
|
||
console.log('objectMappingComponent : ', this.objectMappingComponent);
|
||
console.log('fieldMappingComponent : ', this.fieldMappingComponent);
|
||
console.log('recordyTypeComponent : ', this.recordyTypeComponent);
|
||
// 🔒 Safety checks
|
||
if (!this.storeName) {
|
||
this.showNotification('Error', 'Error', 'Current store is missing');
|
||
return;
|
||
}
|
||
|
||
if (!this.selectedStore) {
|
||
this.showNotification('Error', 'Error', 'Please select a store');
|
||
return;
|
||
}
|
||
let pageStatus = '';
|
||
if (this.setupComponent) {
|
||
pageStatus = 'Setup';
|
||
this.setupComponent = false;
|
||
} else if (this.shopifyCredentialComponent) {
|
||
pageStatus = 'Shopify Credentials';
|
||
this.shopifyCredentialComponent = false;
|
||
} else if (this.objectMappingComponent) {
|
||
pageStatus = 'Object Mapping';
|
||
this.objectMappingComponent = false;
|
||
} else if (this.fieldMappingComponent) {
|
||
pageStatus = 'Field Mapping';
|
||
this.fieldMappingComponent = false;
|
||
} else if (this.recordyTypeComponent) {
|
||
pageStatus = 'Record Type';
|
||
this.recordyTypeComponent = false;
|
||
}
|
||
this.isModalOpen = false;
|
||
this.unlockBodyScroll();
|
||
|
||
// Show spinner and hide other content
|
||
this.processing = true;
|
||
this.spinnerClosed = false;
|
||
|
||
console.log('FROM STORE:', this.selectedStoreName);
|
||
console.log('TO STORE:', this.storeName);
|
||
copyFieldMapping({
|
||
fromStore: this.selectedStoreName,
|
||
toStore: this.storeName
|
||
})
|
||
.then(() => {
|
||
this.showNotification(
|
||
'Success',
|
||
'Success',
|
||
'Field mapping copied successfully'
|
||
);
|
||
|
||
// Optional UX cleanup
|
||
this.isModalOpen = false;
|
||
this.unlockBodyScroll();
|
||
this.selectedStore = undefined;
|
||
this.selectedStoreName = null;
|
||
})
|
||
.catch(error => {
|
||
console.error(error);
|
||
|
||
this.showNotification(
|
||
'Error',
|
||
'Error',
|
||
error.body?.message || 'Failed to copy field mapping'
|
||
);
|
||
})
|
||
.finally(() => {
|
||
if (pageStatus === 'Setup' && !this.setupComponent) {
|
||
this.setupComponent = true;
|
||
} else if (pageStatus === 'Shopify Credentials' && !this.shopifyCredentialComponent) {
|
||
this.shopifyCredentialComponent = true;
|
||
} else if (pageStatus === 'Object Mapping' && !this.objectMappingComponent) {
|
||
this.objectMappingComponent = true;
|
||
} else if (pageStatus === 'Field Mapping' && !this.fieldMappingComponent) {
|
||
this.fieldMappingComponent = true;
|
||
} else if (pageStatus === 'Record Type' && !this.recordyTypeComponent) {
|
||
this.recordyTypeComponent = true;
|
||
}
|
||
this.processing = false;
|
||
this.spinnerClosed = true;
|
||
});
|
||
}
|
||
|
||
lockBodyScroll() {
|
||
document.body.style.overflow = 'hidden';
|
||
document.body.style.position = 'fixed';
|
||
document.body.style.width = '100%';
|
||
this.scrollY = window.scrollY;
|
||
}
|
||
|
||
// UNLOCK BODY SCROLL WHEN MODAL CLOSES
|
||
unlockBodyScroll() {
|
||
document.body.style.overflow = '';
|
||
document.body.style.position = '';
|
||
document.body.style.width = '';
|
||
window.scrollTo(0, this.scrollY);
|
||
}
|
||
|
||
// ========================================================================
|
||
// NEW — presentation-only members added for the reference-mockup restyle.
|
||
// Nothing above this line was changed. These replace the two old
|
||
// decorative/functional progress-indicator blocks with a single styled
|
||
// step list, reusing the exact same real state (optionList, the six
|
||
// *Color trackers) and the real, untouched pathHandler(event) navigation
|
||
// method — invoked here via a hand-built { target: { value } } object,
|
||
// the same shape lightning-progress-step's onclick passed.
|
||
// ========================================================================
|
||
// DISPLAY-ONLY: "Setup Progress X / N" label + bar, derived from the
|
||
// existing optionList/usercurrentvalue. No functional impact.
|
||
// DISPLAY-ONLY: current calendar year for the copyright footer.
|
||
get currentYear() {
|
||
return new Date().getFullYear();
|
||
}
|
||
|
||
get setupProgressStepNum() {
|
||
const current = this.optionList.find(o => o.label === this.usercurrentvalue);
|
||
return current ? current.priority : 1;
|
||
}
|
||
get setupProgressTotal() {
|
||
return this.optionList.length || 6;
|
||
}
|
||
get setupProgressLabel() {
|
||
return `${this.setupProgressStepNum} / ${this.setupProgressTotal}`;
|
||
}
|
||
get setupProgressBarStyle() {
|
||
const pct = Math.round((this.setupProgressStepNum / this.setupProgressTotal) * 100);
|
||
return `height:100%;width:${pct}%;border-radius:999px;background:linear-gradient(90deg,#6cb33f,#3f9a86);transition:width .4s;`;
|
||
}
|
||
|
||
get navSteps() {
|
||
const colors = [
|
||
this.setupColor,
|
||
this.credentialColor,
|
||
this.objectColor,
|
||
this.fieldColor,
|
||
this.recordColor,
|
||
this.finishColor
|
||
];
|
||
const descriptions = [
|
||
'Domain & Security',
|
||
'Connect your store',
|
||
'Choose what syncs',
|
||
'Map your data',
|
||
'Assign Record Types',
|
||
'Go Live'
|
||
];
|
||
const icons = ['shield', 'bag', 'layers', 'grid', 'tag', 'check'];
|
||
return this.optionList.map((option, index) => {
|
||
const color = colors[index];
|
||
const done = color === 'greenColor';
|
||
const active = color === 'darkGreenColor';
|
||
const icon = icons[index];
|
||
return {
|
||
key: option.label,
|
||
value: option.value,
|
||
label: 'Step ' + (index + 1),
|
||
title: option.label,
|
||
desc: descriptions[index],
|
||
done,
|
||
active,
|
||
showIcon: !done && !active,
|
||
isShield: icon === 'shield',
|
||
isBag: icon === 'bag',
|
||
isLayers: icon === 'layers',
|
||
isGrid: icon === 'grid',
|
||
isTag: icon === 'tag',
|
||
isCheck: icon === 'check',
|
||
isLast: index === this.optionList.length - 1,
|
||
circleClass: done ? 'nav-circle nav-circle_done' : active ? 'nav-circle nav-circle_active' : 'nav-circle',
|
||
topLineClass: index === 0
|
||
? 'nav-line nav-line_hidden'
|
||
: ((done || active) ? 'nav-line nav-line_done' : 'nav-line'),
|
||
lineClass: index === this.optionList.length - 1
|
||
? 'nav-line nav-line_hidden'
|
||
: (done ? 'nav-line nav-line_done' : 'nav-line'),
|
||
titleClass: done ? 'nav-title nav-title_done' : active ? 'nav-title nav-title_active' : 'nav-title',
|
||
chipClass: done ? 'nav-chip nav-chip_done' : active ? 'nav-chip nav-chip_active' : 'nav-chip',
|
||
labelWrapClass: active ? 'nav-label nav-label_active' : 'nav-label'
|
||
};
|
||
});
|
||
}
|
||
|
||
handleNavClick(event) {
|
||
const value = event.currentTarget.dataset.value;
|
||
this.pathHandler({ target: { value } });
|
||
}
|
||
|
||
} |