SyncMadeEasy/force-app/main/default/lwc/setup/setup.js

1096 lines
45 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
****************************************************************************
Component Name : Setup
Created Date : 17/4/2024
@description : This component is used for setting up the application
@author : SME Team
Modification Log:
Ver Date Author
1.0 23/4/2024 SME Team
****************************************************************************
*/
import { LightningElement, track, api, wire } from "lwc";
// FETCHING RESOURCES FROM THE STATIC RESOURCES
// import AuthenticateConnecting from "@salesforce/resourceUrl/AuthenticateConnecting";
// import pageLoadingGif from "@salesforce/resourceUrl/SMEPageLoadingGif";
import Resources from "@salesforce/resourceUrl/Resources";
import SMEPageLoadingGIF2 from "@salesforce/resourceUrl/SMEPageLoadingGIF2";
// MAKING INSTANCE OF APEX CLASS METHODS
import saveSiteUrlOnHicConfig from "@salesforce/apex/ShopifyController.saveSiteUrlOnHicConfig";
import issuePkceForState from "@salesforce/apex/PkceUtil.issuePkceForState";
import getUIThemeDescription from "@salesforce/apex/ShopifyController.getUIThemeDescription";
import returnDomainUrl from "@salesforce/apex/ShopifyController.returnDomainUrl";
import CheckSitefromConfiguration from "@salesforce/apex/ShopifyController.checkSitefromConfiguration";
import savesiteurlconfig from "@salesforce/apex/ShopifyController.savesiteurlconfig";
import getSiteURLs from "@salesforce/apex/ShopifyController.getSiteURLs";
import getAuthenticateURL from "@salesforce/apex/ShopifyController.getAuthenticateURL";
import checkSiteClassandPageAccess from "@salesforce/apex/ShopifyController.checkSiteClassandPageAccess";
import setupAccessCheck from "@salesforce/apex/ShopifyController.setupAccessCheck";
import refreshTokenCheck from "@salesforce/apex/ShopifyController.refreshTokenCheck";
import preAuthSetupCheck from "@salesforce/apex/ShopifyController.preAuthSetupCheck";
// import runPostInstallScript from "@salesforce/apex/ShopifyController.runPostInstallScript";
// SHOW TOAST
import { ShowToastEvent } from "lightning/platformShowToastEvent";
// NAVIGATION — Locker/LWS-safe way to open Salesforce setup pages.
// Raw window.open(url,'_blank') to relative setup URLs is blocked/sanitized in
// installed (managed-package) orgs and throws the opaque "aura_prod.js Script error. null".
import { NavigationMixin } from "lightning/navigation";
//Custom Labels
import click_here from '@salesforce/label/c.click_here';
import Information from '@salesforce/label/c.Information';
import Please from '@salesforce/label/c.Please';
import create_Domain_remote_site from '@salesforce/label/c.create_Domain_remote_site';
import to_create_remote_site_setting from '@salesforce/label/c.to_create_remote_site_setting';
import Attention_required from '@salesforce/label/c.Attention_required';
import create_Authenticate_remote_site from '@salesforce/label/c.create_Authenticate_remote_site';
import self_signed_Certificate_Shopify from '@salesforce/label/c.self_signed_Certificate_Shopify';
import self_signed_Certificate from '@salesforce/label/c.self_signed_Certificate';
import Please_press_the_button_labeled from '@salesforce/label/c.Please_press_the_button_labeled';
import Let_get_started from '@salesforce/label/c.Let_get_started';
import Close from '@salesforce/label/c.Close';
import Site from '@salesforce/label/c.Site';
import SetupLabel from '@salesforce/label/c.Setup';
import How_to from '@salesforce/label/c.How_to';
import Please_create_below_remote from '@salesforce/label/c.Please_create_below_remote';
import No_certificate_found from '@salesforce/label/c.No_certificate_found';
import Create_certificate from '@salesforce/label/c.Create_certificate';
import button_to_create_certificate from '@salesforce/label/c.button_to_create_certificate';
import Please_click_on_the from '@salesforce/label/c.Please_click_on_the';
import If_you_are_a_first_time_visitor from '@salesforce/label/c.If_you_are_a_first_time_visitor';
import Thank_You from '@salesforce/label/c.Thank_You';
import Check_Status from '@salesforce/label/c.Check_Status';
import Next from '@salesforce/label/c.Next';
import Error from '@salesforce/label/c.Error';
import Some_error_occurred_in_theme_description from '@salesforce/label/c.Some_error_occurred_in_theme_description';
import Some_error_occurred_in_site_url from '@salesforce/label/c.Some_error_occurred_in_site_url';
import Some_error_occurred_in_domain_url from '@salesforce/label/c.Some_error_occurred_in_domain_url';
import Some_error_occurred_while_checking_site_configuration from '@salesforce/label/c.Some_error_occurred_while_checking_site_configuration';
import Some_error_occurred_while_checking_site_page_access from '@salesforce/label/c.Some_error_occurred_while_checking_site_page_access';
import Some_error_occurred_while_saving_site_url from '@salesforce/label/c.Some_error_occurred_while_saving_site_url';
import Some_error_occurred_in_refresh_token from '@salesforce/label/c.Some_error_occurred_in_refresh_token';
import Please_create_new_site_or_activate_existing_site from '@salesforce/label/c.Please_create_new_site_or_activate_existing_site';
import Please_configure_site from '@salesforce/label/c.Please_configure_site';
import Please_create_domain_Url_remote_site_setting from '@salesforce/label/c.Please_create_domain_Url_remote_site_setting';
import Please_create_authenticate_Url_remote_site_setting from '@salesforce/label/c.Please_create_authenticate_Url_remote_site_setting';
import Please_create_self_signed_certificate from '@salesforce/label/c.Please_create_self_signed_certificate';
import to_configure_site from '@salesforce/label/c.to_configure_site';
// GO NEXT SITE
import Go_Next from '@salesforce/label/c.Go_Next';
import Cancel from '@salesforce/label/c.Cancel';
import Select_a_Site_URL from '@salesforce/label/c.Select_a_Site_URL';
import Select_Progress from '@salesforce/label/c.Select_Progress';
import Success from '@salesforce/label/c.Success';
import Save from '@salesforce/label/c.Save';
import button from '@salesforce/label/c.button';
import Site_Page from '@salesforce/label/c.Site_Page';
//
import Please_activate_the_site_or_grant_access from '@salesforce/label/c.Please_activate_the_site_or_grant_access';
import site_currently_does_not_have_access_to_the_class from '@salesforce/label/c.site_currently_does_not_have_access_to_the_class';
import Please_Setup_Site from '@salesforce/label/c.Please_Setup_Site';
import There_is_no_activate_site_in_your_org from '@salesforce/label/c.There_is_no_activate_site_in_your_org';
import to_create_a_new_site_or_activate_existing_site from '@salesforce/label/c.to_create_a_new_site_or_activate_existing_site';
import You_Can_Change_Site from '@salesforce/label/c.You_Can_Change_Site';
import Initialize from '@salesforce/label/c.Initialize';
import Create_Remote_site from '@salesforce/label/c.Create_Remote_site';
// ── Module-level flag: tracks whether the "auto-advance to Step 2 on refresh"
// has already run for this page session. Persists across component instances
// (so clicking back to Step 1 in the stepper does NOT re-trigger auto-advance),
// but resets on browser refresh (module re-loads → false again).
let hasAutoAdvancedOnRefresh = false;
export default class Setup extends NavigationMixin(LightningElement) {
// Instance flag distinguishing an automatic page-load/refresh verification
// run from a manual "Check Status" click — see connectedCallback and
// handleCheckStatusClick. Only a run made with this true is allowed to
// auto-advance to Step 2.
_isAutoLoadCheck = false;
// Custom in-component toast state (replaces ShowToastEvent) — see
// showNotification.
@track toasts = [];
_toastSeq = 0;
// GLOBAL VARIABLE
@api storeName = "";
// LOCAL VARIABLE
@track url = "";
@track height = "900px";
@track width = "100%";
@track toolingRemoteSiteSettings = false;
@track error;
@track selectedSite = null;
@track CertificateCreateLink = "/lightning/setup/CertificatesAndKeysManagement/page?address=/0P1/e?MasterLabel=Shopify&DeveloperName=Shopify";
// Org My Domain (e.g. https://mydomain.my.salesforce.com). Prepended to relative setup
// URLs so window.open resolves correctly in installed/managed-package (Locker) orgs.
@track orgDomainUrl = "";
@track viewMode = "";
@track CreateRemotesiteSettingUrl = "";
@track remoteSiteExist = false;
@track remoteSiteError = false;
@track remoteSiteHeaderMsg = "";
@track certificateExist = false;
@track certificateError = false;
@track certificateHeaderMsg = "";
@track isCertificate = false;
@track checkSiteExist = false;
@track checkSiteAccess = false;
@track siteURLList = [];
@track urlSavedSuccess = false;
@track siteModel = false;
@track siteOptions = [];
@track siteValue;
@track siteurl = "";
@track siteSavingNotification = Please_Setup_Site;
// DISPLAY-ONLY: suppress the default "Please Setup Site" placeholder in the
// Salesforce Configuration Site modal. Real notifications (save success,
// access errors, "You can change site") still render normally.
get showSiteNotification() {
const note = this.siteSavingNotification;
return !!note && note !== Please_Setup_Site;
}
@track siteName = "";
@track allSettingCompleted = false;
@track RemotesiteUrl;
@track isRemoteSite = false;
@track noRefreshToken = false;
@track refreshTokenValue = '';
@track accessToken = '';
@track isLoading = false;
@track noAccessToken = false;
@track authenticationUrl = 'https://login.salesforce.com';
@track authenticationRemoteSite = false;
@api isStatusChecked = false;
@track selectedSiteId = null;
@track disableDomainRemoteSite = true;
@track disableAuthenticateRemoteSite = true;
@track disableCertificate = true;
@track isSiteSupportedOrg = true;
checkStatusSpinner = false;
@track showCheckStatusMessage = true;
//Custom Labels
@track label = {
click_here ,Cancel, Please ,Information, create_Domain_remote_site , to_create_remote_site_setting , Attention_required ,
create_Authenticate_remote_site , self_signed_Certificate_Shopify , self_signed_Certificate ,
Please_press_the_button_labeled , Let_get_started , Close , Site , SetupLabel , How_to , Please_create_below_remote ,
No_certificate_found , Create_certificate , button_to_create_certificate , Please_click_on_the , If_you_are_a_first_time_visitor ,
Thank_You , Check_Status , Next , Error , Some_error_occurred_in_theme_description , Some_error_occurred_in_site_url ,
Some_error_occurred_in_domain_url , Some_error_occurred_while_checking_site_configuration , Some_error_occurred_while_checking_site_page_access ,
Some_error_occurred_while_saving_site_url,
Some_error_occurred_in_refresh_token,
Please_create_new_site_or_activate_existing_site,
Please_configure_site,
Please_create_domain_Url_remote_site_setting,
Please_create_authenticate_Url_remote_site_setting,
Please_create_self_signed_certificate ,
to_configure_site , Go_Next , Select_a_Site_URL , Select_Progress , Success , Save , Site_Page ,
Please_activate_the_site_or_grant_access , site_currently_does_not_have_access_to_the_class , Please_Setup_Site ,
There_is_no_activate_site_in_your_org , to_create_a_new_site_or_activate_existing_site , You_Can_Change_Site ,
Initialize , button , Create_Remote_site
};
// AuthenticateConnecting = AuthenticateConnecting;
// pageLoadingGif = pageLoadingGif;
AuthenticateConnecting = Resources + "/Resources/AuthenticateConnecting.gif";
pageLoadingGif = SMEPageLoadingGIF2;
// CONNECTED CALLBACK
connectedCallback() {
console.log('SYNC MADE EASY: Setup Connected Callback');
this.showSpinnerHandler();
// Mark this specific verification run as the automatic one triggered by
// page load/refresh (as opposed to the user manually clicking "Check
// Status" — see handleCheckStatusClick). Only THIS run is allowed to
// auto-advance to Step 2 if everything's already verified.
this._isAutoLoadCheck = true;
this.getSiteUrl();
this.returnDomain();
this.getThemeDescription();
this.getOrganizationAuthenticateUrl();
}
// Manual "Check Status" button click: run the same verification chain as
// the automatic page-load check, but never auto-advance off of it — the
// user should land on Step 2 automatically only via a fresh page load/
// refresh when setup is already verified, not from clicking this button.
handleCheckStatusClick() {
this._isAutoLoadCheck = false;
this.getSiteUrl();
}
//CHECK IF THIS METHOD IS BEING USED ANYWHERE deprecated
getOrganizationAuthenticateUrl() {
getAuthenticateURL().then((result) => {
if (result) {
this.authenticationUrl = result;
}
}).catch((error) => {
//Error occured
})
}
//Check All Settings
checkSettingStatus() {
this.siteConfiguration();
}
//GET TOOLING REMOTE SITE SETTINGS
handleToolingremotesite() {
this.openSetupPage("/lightning/setup/CustomDomain/home");
}
// GET CURRENT UI THEME TO SEND USED IN REDIRECTION
getThemeDescription() {
getUIThemeDescription().then((result) => {
this.viewMode = result;
})
.catch((error) => {
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_in_theme_description);
});
}
// GET ALL SITE URLS
getSiteUrl() {
console.log('SYNC MADE EASY: Setup => Checking Site Existance');
this.checkStatusSpinner = true;
this.checkSiteExist = false;
this.checkSiteAccess = false;
this.remoteSiteExist = false;
this.authenticationRemoteSite = false;
this.certificateExist = false;
this.noRefreshToken = false;
getSiteURLs().then((result) => {
if (result != null) {
if (result == 'No access to site.') {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.isSiteSupportedOrg = false;
this.allSettingCompleted = true;
this.disableCertificate = false;
console.log('SITE NOT SUPPORTED');
// this.getSetupAccessCheck();
this.getRefreshToken();
} else {
console.log('SITE SUPPORTED');
this.allSettingCompleted = false;
this.siteURLList = JSON.parse(result);
this.checkSiteExist = true;
this.siteOptions = JSON.parse(result).map((element) => {
return { label: element.siteUrl, value: element.siteguestid };
});
this.siteValue = this.siteURLList[0].siteguestid;
console.log('@@@ this.siteValue : ' + this.siteValue);
this.selectedSiteId = this.siteURLList[0].Id;
this.siteConfiguration();
}
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.checkSiteExist = false;
this.checkSiteAccess = false;
}
}).catch((error) => {
console.log('@@@ This is the Error Occured in site url ', JSON.stringify(error));
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_in_site_url);
});
}
// RETURNING DOMAIN URL FOR REMOTE SITE SETTING
returnDomain() {
returnDomainUrl().then((result) => {
this.CreateRemotesiteSettingUrl = result;
this.orgDomainUrl = result;
}).catch((error) => {
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_in_domain_url);
});
}
// CHECK IF SITE EXISTS IN CONFIURATION
siteConfiguration() {
console.log('SYNC MADE EASY: Setup => Checking Site Configuration');
CheckSitefromConfiguration().then((result) => {
if (result == true || (result && result.includes && result.includes("http"))) {
// URL already saved before — use that site
this.selectedSite = result;
for (let site of this.siteURLList) {
if (site.siteUrl == this.selectedSite) {
this.selectedSiteId = site.id;
this.siteValue = site.siteguestid;
}
}
this.urlSavedSuccess = true;
this.siteClassAndPageAccess();
} else {
// ✅ FIX: URL not saved yet. Try saving now if access is granted.
// Default to first site and run access check → save flow
if (this.siteURLList && this.siteURLList.length > 0) {
this.siteValue = this.siteURLList[0].siteguestid;
this.siteurl = this.siteURLList[0].siteUrl;
this.siteName = this.siteURLList[0].name;
this.selectedSiteId = this.siteURLList[0].id;
this.siteClassAndPageAccess(); // This will check access + save URL
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
}
}
}).catch((error) => {
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_while_checking_site_configuration);
});
}
// THIS METHOD CHECKS THE ACCESS TO THE SITE FOR THE SPECIFIC USER
siteClassAndPageAccess() {
console.log('SYNC MADE EASY: Setup => Checking Class Access');
for (let site of this.siteURLList) {
if (site.siteguestid == this.siteValue) {
this.siteurl = site.siteUrl;
this.siteName = site.name;
this.selectedSiteId = site.id;
}
}
checkSiteClassandPageAccess({ Guestuserid: this.siteValue })
.then((result) => {
console.log('@@@ checkSiteClassandPageAccess : ' + result);
if (result == true) {
this.checkSiteAccess = true;
// ✅ Save URL to BOTH Configuration objects in parallel
return Promise.all([
savesiteurlconfig({ siteurl: this.siteurl }),
saveSiteUrlOnHicConfig({ siteurl: this.siteurl })
]);
} else {
this.disableDomainRemoteSite = true;
this.disableAuthenticateRemoteSite = true;
this.disableCertificate = true;
this.checkSiteAccess = false;
this.urlSavedSuccess = false;
this.siteSavingNotification = `${this.siteName}${this.label.site_currently_does_not_have_access_to_the_class} 'HIC_ShopifySync.AuthenticateAllApexClass' ${this.label.Please_activate_the_site_or_grant_access}`;
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
return null;
}
})
.then((saveResults) => {
if (saveResults === null) return;
const [customSettingSave, hicConfigSave] = saveResults;
console.log('@@@ savesiteurlconfig (Configuration__c): ' + customSettingSave);
console.log('@@@ saveSiteUrlOnHicConfig (HIC_Configuration__c): ' + hicConfigSave);
// Consider success if at least one saved (Configuration__c is the critical one for auth)
if (customSettingSave == true) {
console.log('@@@ ✅ Site URL saved on both Configuration objects');
this.urlSavedSuccess = true;
this.checkSiteExist = true;
this.disableDomainRemoteSite = false;
this.disableAuthenticateRemoteSite = false;
this.siteSavingNotification = "This site has been saved Successfully!";
this.closeSiteModel();
this.getRefreshToken();
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
}
})
.catch((error) => {
console.log('@@@ Error: ' + JSON.stringify(error));
this.checkStatusSpinner = false;
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_while_checking_site_page_access);
});
}
// THIS METHOD IS USED TO SAVE THE SITE CONFIGURATION USER HAS SELECTED
saveSiteUrlConfiguration() {
savesiteurlconfig({ siteurl: this.siteurl })
.then((result) => {
if (result == true) {
this.getRefreshToken();
this.disableDomainRemoteSite = false;
this.disableAuthenticateRemoteSite = false;
this.checkSiteAccess = true;
this.checkSiteExist = true;
this.urlSavedSuccess = true;
this.siteSavingNotification =
"This site has been saved Successfully!";
this.closeSiteModel();
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
}
})
.catch((error) => {
this.checkStatusSpinner = false;
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_while_saving_site_url);
});
}
//Get Refresh token
getRefreshToken() {
console.log('SYNC MADE EASY: Setup => Checking tokens');
refreshTokenCheck().then((result) => {
if (result === 'No refresh token found') {
console.log('SYNC MADE EASY: Setup => No Refresh Token Found');
this.noRefreshToken = true;
this.runPreAuthChecks();
} else {
this.refreshTokenValue = result;
if (result === 'No access token found') {
console.log('SYNC MADE EASY: Setup => No Access Token Found');
this.noAccessToken = true;
this.noRefreshToken = true;
this.runPreAuthChecks();
} else {
console.log('SYNC MADE EASY: Setup => Access Token Found');
this.noRefreshToken = false;
this.accessToken = result;
this.shopifyCertificateSite();
}
}
}).catch((error) => {
this.checkStatusSpinner = false;
this.showNotification(this.label.Error, 'Error', this.label.Some_error_occurred_in_refresh_token);
});
}
//THIS METHOD IS USED TO CHECK IF THE USER HAS ACCESS TO SHOPIFY CLASS AND PAGE, REMOTE SITE AND CERTIFICATE
getSetupAccessCheck() {
console.log('SYNC MADE EASY: Setup => Checking Final Access ' + this.siteValue + ' this is acccess Token :: ' + this.accessToken);
setupAccessCheck({ guestUserId: this.siteValue, accessToken: this.accessToken }).then((result) => {
console.log('@@@ setupAccessCheck : ' + JSON.stringify(result));
if (result.classAndPageAccess) {
this.disableDomainRemoteSite = false;
this.disableAuthenticateRemoteSite = false;
this.disableCertificate = true;
if (result.remoteSite) {
this.remoteSiteExist = true;
this.authenticationRemoteSite = true;
this.disableDomainRemoteSite = true;
this.disableAuthenticateRemoteSite = true;
this.disableCertificate = false;
if (result.certificate) {
console.log('@@@ result.certificate', result.certificate);
this.disableCertificate = true;
this.remoteSiteExist = true;
this.authenticationRemoteSite = true;
this.certificateExist = true;
this.isCertificate = false;
this.unlockBodyScroll();
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.isStatusChecked = true;
this.showCheckStatusMessage = false;
console.log('@@@ this.storeName : ' + this.storeName);
// Auto-advance to Step 2 ONLY when this verification run came from
// the automatic page-load/refresh check (this._isAutoLoadCheck),
// and only the first time per page load (hasAutoAdvancedOnRefresh).
// A manual "Check Status" button click (handleCheckStatusClick sets
// _isAutoLoadCheck = false) never auto-advances — it just marks the
// step Verified and stays put; moving on then requires an explicit
// Next click.
if (this._isAutoLoadCheck && !hasAutoAdvancedOnRefresh) {
hasAutoAdvancedOnRefresh = true;
this._isAutoLoadCheck = false;
console.log('SYNC MADE EASY: Initial refresh with setup verified — auto-advancing to Step 2');
this.goNextPage();
} else {
hasAutoAdvancedOnRefresh = true;
}
} else {
console.log('@@@ inside else');
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.disableCertificate = false;
this.certificateExist = false;
this.isCertificate = true;
this.lockBodyScroll();
this.certificateHeaderMsg = this.label.Create_certificate;
}
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.isRemoteSite = true;
this.remoteSiteExist = false;
this.authenticationRemoteSite = false;
this.remoteSiteHeaderMsg = this.label.Create_Remote_site;
this.disableDomainRemoteSite = false;
this.disableAuthenticateRemoteSite = false;
}
} else {
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
this.disableDomainRemoteSite = true;
this.disableAuthenticateRemoteSite = true;
this.disableCertificate = true;
this.urlSavedSuccess = false;
}
}).catch((error) => {
console.error('SYNC MADE EASY: Setup => setupAccessCheck failed: ' + JSON.stringify(error));
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
})
}
@api goNextPage() {
console.log('@@@ isSiteSupportedOrg : ' + this.isSiteSupportedOrg);
console.log('@@@ urlSavedSuccess : ' + this.urlSavedSuccess);
console.log('@@@ remoteSiteExist : ' + this.remoteSiteExist);
console.log('@@@ authenticationRemoteSite : ' + this.authenticationRemoteSite);
console.log('@@@ certificateExist : ' + this.certificateExist);
if (!this.checkSiteExist && this.isSiteSupportedOrg) {
this.showNotification(this.label.Error, 'Error', this.label.Please_create_new_site_or_activate_existing_site);
} else if (!this.urlSavedSuccess && this.isSiteSupportedOrg) {
this.showNotification(this.label.Error, 'Error', this.label.Please_configure_site);
} else if (!this.remoteSiteExist) {
this.showNotification(this.label.Error, 'Error', this.label.Please_create_domain_Url_remote_site_setting);
} else if (!this.authenticationRemoteSite) {
this.showNotification(this.label.Error, 'Error', this.label.Please_create_authenticate_Url_remote_site_setting);
} else if (!this.certificateExist) {
this.showNotification(this.label.Error, 'Error', this.label.Please_create_self_signed_certificate);
} else if (this.isStatusChecked) {
const selectStore = new CustomEvent('save', {
detail: 'Saved'
});
this.dispatchEvent(selectStore);
}
// const selectStore = new CustomEvent('save', {
// detail: 'Saved'
// });
// this.dispatchEvent(selectStore);
}
// THIS METHOD IS CALLED FROM THE HOME COMPONENT ON SAVE EVENT AND USED TO CHECK IF THE USER HAS ACCESS TO SITE AND REMOTE SITE SETTING AND CERTIFICATE
@api async shopifyCertificateSite() {
for (let site of this.siteURLList) {
if (site.siteguestid == this.siteValue) {
this.siteurl = site.siteUrl;
this.siteName = site.name;
this.selectedSiteId = site.id;
}
}
this.getSetupAccessCheck();
}
// METHOD USED TO REDIRECT TO REMOTE SITE SETTING PAGE WITH PRE POPULATED VALUES TO CREATE
createRemoteSiteSetting() {
if (
this.RemotesiteUrl != null &&
this.RemotesiteUrl != "" &&
this.RemotesiteUrl !== undefined
) {
this.openSetupPage(
"/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_Shopifymadeeasy_Site_URl%26EndpointUrl=" +
this.RemotesiteUrl
);
} else {
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_Shopifymadeeasy_Site_URl");
}
}
// METHOD USED TO REDIRECT TO REMOTE SITE SETTING PAGE WITH PRE POPULATED VALUES TO CREATE FOR MIDDLEWARE
serverRemoteSite() {
var serverUrlLink = 'https://sfapps.syncmadeasy.com';
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_SME_RealTimeUrl%26EndpointUrl=" + serverUrlLink);
}
// METHOD USED TO REDIRECT TO REMOTE SITE SETTING PAGE WITH PRE POPULATED VALUES TO CREATE
domainUrlRemoteSiteSetting() {
if (
this.CreateRemotesiteSettingUrl != null &&
this.CreateRemotesiteSettingUrl != "" &&
this.CreateRemotesiteSettingUrl !== undefined
) {
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_Shopifymadeeasy_Site_URl%26EndpointUrl=" + this.CreateRemotesiteSettingUrl);
} else {
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_Shopifymadeeasy_Site_URl");
}
}
// METHOD USED TO REDIRECT TO REMOTE SITE SETTING PAGE WITH PRE POPULATED VALUES TO CREATE
authenticateUrlRemoteSiteSetting() {
if (
this.authenticationUrl != null &&
this.authenticationUrl != "" &&
this.authenticationUrl !== undefined
) {
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_SME_AuthenticateUrl%26EndpointUrl=" + this.authenticationUrl);
} else {
this.openSetupPage("/lightning/setup/SecurityRemoteProxy/page?address=/0rp/e?SiteName=HIC_SME_AuthenticateUrl");
}
}
// METHOD USED TO OPEN THE MODEL TO SELECT SITE AND SAVE IT TO CUSTOM SETTINGS
openSiteModel() {
// If the org has no site to choose from, don't open the popup — send the
// user straight to the Salesforce Sites page so they can create/activate
// one. The popup only opens when a site already exists to select.
const hasSiteToSelect =
this.hasSites && Array.isArray(this.siteOptions) && this.siteOptions.length > 0;
if (!hasSiteToSelect) {
this.openSetupPage("/lightning/setup/CustomDomain/home");
return;
}
this.siteModel = true;
if (this.urlSavedSuccess == true) {
this.siteSavingNotification = this.label.You_Can_Change_Site;
} else {
this.siteSavingNotification = this.label.Please_Setup_Site;
}
}
// METHOD USED TO CLOSE THE SITE MODEL
closeSiteModel() {
this.siteModel = false;
}
// METHOD USED TO TRACK THE CHANGE IN SELECTION OF THE SITE
handleSiteChange(event) {
this.siteValue = event.detail.value;
}
// METHOD USED TO CLOSE THE REMOTE SITE SETTING MODAL
closeRemoteSiteModel() {
this.isRemoteSite = false;
}
// METHOD USED TO REDIRECT TO THE CRETIFICATE CREATION SITE
ReDirectCertificateSetting() {
this.isCertificate = false;
this.unlockBodyScroll();
this.openSetupPage(this.CertificateCreateLink);
}
// METHOD USED TO CLOSE THE CERTIFICATE WARNING MODAL
closeCertificateModal() {
this.isCertificate = false;
this.unlockBodyScroll();
}
// THIS METHOD IS USED TO CALL THE VF PAGE FOR LWC APP TO INITIALIZE THE PROCESS
openInitialize() {
if (this.isSiteSupportedOrg) {
console.log('@@@ Initalize SITE SUPPORTED');
var authenticateurl = '/apex/hic_shopifysync__SalesforceAuthentication?viewmode=' + this.viewMode + '&islwcapp=true';
window.open(authenticateurl, '_top');
} else if (!this.isSiteSupportedOrg) {
console.log('@@@ Initalize SITE NOT SUPPORTED');
this.redirectToSalesforce();
}
// var authenticateurl = '/apex/hic_shopifysync__SalesforceAuthentication?viewmode=' + this.viewMode + '&islwcapp=true';
// window.open(authenticateurl, '_top');
}
// This method is used to redirect to site for Public Access
redirectToSite() {
// this.siteValue
for (let site of this.siteURLList) {
if (site.siteguestid == this.siteValue) {
this.siteurl = site.siteUrl;
this.siteName = site.name;
this.selectedSiteId = site.id;
}
}
this.openSetupPage('/lightning/setup/CustomDomain/page?address=/' + this.selectedSiteId);
}
// Open a Salesforce setup page in a new tab, safely for installed (managed-package) orgs.
// A relative URL passed to window.open resolves against the sandboxed Locker base
// (b.static.lightning.force.com) in subscriber orgs and breaks ("Invalid url: https://").
// Prefixing the real org My Domain removes that ambiguity and keeps the new-tab UX.
openSetupPage(relativeUrl) {
if (this.orgDomainUrl) {
const absoluteUrl = this.orgDomainUrl + relativeUrl;
console.log('SYNC MADE EASY: Setup => opening setup page: ' + absoluteUrl);
window.open(absoluteUrl, '_blank');
} else {
// Org domain not loaded yet — fall back to the platform navigation service (same tab).
console.warn('SYNC MADE EASY: Setup => org domain not loaded, using NavigationMixin fallback');
this[NavigationMixin.Navigate]({
type: 'standard__webPage',
attributes: { url: relativeUrl }
});
}
}
//This Method is used to close spinner
closeSpinnerHandler() {
this.isLoading = false;
const stopSpinner = new CustomEvent('closespinner', {
detail: 'Stop Spinner'
});
this.dispatchEvent(stopSpinner);
}
//This Method is used to show spinner
showSpinnerHandler() {
this.isLoading = true;
const startSpinner = new CustomEvent('showspinner', {
detail: 'Start Spinner'
});
this.dispatchEvent(startSpinner);
}
//Helps to Show a Toast Message
// Custom in-component toast instead of ShowToastEvent: success shows the
// brand green→teal gradient, error shows red, matching the reference. Same
// (title, variant, message) signature and callers as before — variant is
// matched case-insensitively ('Success'/'Error'/'Warning' all work).
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++);
const toast = {
id,
title,
message,
cssClass: 'sw-toast sw-toast-' + kind,
iconLabel: kind === 'error' ? '⚠' : kind === 'success' ? '✓' : kind === 'warning' ? '!' : 'ℹ'
};
this.toasts = [...this.toasts, toast];
// Auto-dismiss non-error toasts after 4s; errors stay until closed.
if (kind !== 'error') {
// eslint-disable-next-line @lwc/lwc/no-async-operation
setTimeout(() => this._dismissToast(id), 4000);
}
this.closeSpinnerHandler();
}
_dismissToast(id) {
this.toasts = this.toasts.filter((t) => t.id !== id);
}
handleToastClose(event) {
this._dismissToast(event.currentTarget.dataset.id);
}
get isNextDisabled(){
// SITE CHECKBOXES DO NOT APPLY TO NON SITE SUPPORTED ORGS
if (!this.isSiteSupportedOrg) {
return !(this.remoteSiteExist && this.authenticationRemoteSite && this.certificateExist);
}
return !(this.checkSiteExist && this.urlSavedSuccess && this.remoteSiteExist && this.authenticationRemoteSite && this.certificateExist)
}
// SHOW INITIALIZE BUTTON IN PLACE OF VERIFY WHEN REFRESH TOKEN IS EMPTY (FIRST TIME / RE-AUTH)
get showInitializeButton() {
return this.noRefreshToken;
}
// HIDE CHECK STATUS ONLY IN THE PRE-AUTH CASE — NO REFRESH TOKEN YET, BUT ALL
// 4 CHECKBOXES ARE VERIFIED, SO INITIALIZE IS THE CORRECT NEXT ACTION (NOT
// CHECK STATUS: clicking Check Status here skips straight past "Ready to
// verify" to "Verified" without going through the real OAuth/Initialize
// chain, since setupAccessCheck can confirm site/remote-site/certificate
// without a token). Once isStatusChecked is real/true, Check Status is
// NEVER hidden anymore — it stays visible as "Verified ✓" alongside
// Verify & Next (see checkButtonClass), it just no longer disappears.
get hideCheckStatus() {
return !this.isStatusChecked && this.noRefreshToken && !this.isInitializeDisabled;
}
// INITIALIZE ENABLED ONLY WHEN ALL 4 CHECKBOXES ARE VERIFIED (SAME GATING AS VERIFY)
get isInitializeDisabled() {
if (this.isSiteSupportedOrg) {
return this.isNextDisabled;
}
// NON SITE SUPPORTED ORG HAS NO SITE CHECKBOX
return !(this.remoteSiteExist && this.authenticationRemoteSite && this.certificateExist);
}
// PRE-AUTH (TOKENLESS) VERIFICATION OF RSS + CERTIFICATE, RUNS ON CHECK STATUS WHEN NO TOKEN EXISTS
runPreAuthChecks() {
preAuthSetupCheck().then((result) => {
this.remoteSiteExist = result.domainRemoteSite === true;
this.authenticationRemoteSite = result.authRemoteSite === true;
this.certificateExist = result.certificate === true;
this.disableDomainRemoteSite = this.remoteSiteExist;
this.disableAuthenticateRemoteSite = this.authenticationRemoteSite;
this.disableCertificate = this.certificateExist;
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
}).catch((error) => {
console.log('@@@ preAuthSetupCheck error : ' + JSON.stringify(error));
this.checkStatusSpinner = false;
this.closeSpinnerHandler();
});
}
// INITIALIZE + VERIFY: RUNS OAUTH FLOW; ON RETURN THE COMPONENT RELOADS AND
// connectedCallback => getSiteUrl() RE-RUNS THE FULL VERIFICATION CHAIN AUTOMATICALLY
handleInitializeVerify() {
this.openInitialize();
}
redirectToSalesforce() {
console.log('>>> URL TO INITIALISE ');
let clientId;
let redirectUrl;
if (this.authenticationUrl.includes('login')) {
clientId = '3MVG9G9pzCUSkzZv4NsQV0kOphm0Il0eDJK5e0YicZLcCZKQcDHS0FORFMYHW8LzqJWPeMxzGUxeyshwEBOin'
redirectUrl = 'https://login.salesforce.com/apex/HIC_ShopifySync__SalesforceAuthentication';
} else {
clientId = '3MVG9G9pzCUSkzZv4NsQV0kOphuwhNCDbV2xJ4wazQQkD_nyOa73sUwa0Z0DtHz1t5woA9d9AVNwcHvqbQy45';
redirectUrl = 'https://test.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() {
// this.showSpinnerHandler();
// runPostInstallScript().then((result) => {
// if (result === 'Success') {
// console.log('@@@ Post install script run successfully.');
// this.showNotification('Success', 'Success', 'Field Mapping of Default store has been reset.');
// this.closeSpinnerHandler();
// }
// }).catch((error) => {
// console.log('@@@ Post install script error.' + error);
// this.closeSpinnerHandler();
// })
// }
lockBodyScroll() {
// document.body / window are owned by the host page, not this component.
// Lightning Locker blocks that access for managed-package LWC in subscriber
// orgs and throws (surfaced as the opaque "aura_prod.js Script error. null").
// Scroll-locking is purely cosmetic, so never let it break the setup flow.
try {
document.body.style.overflow = 'hidden';
document.body.style.position = 'fixed';
document.body.style.width = '100%';
this.scrollY = window.scrollY;
} catch (e) {
console.warn('SYNC MADE EASY: lockBodyScroll skipped (restricted DOM): ' + e);
}
}
// UNLOCK BODY SCROLL WHEN MODAL CLOSES
unlockBodyScroll() {
try {
document.body.style.overflow = '';
document.body.style.position = '';
document.body.style.width = '';
if (typeof this.scrollY === 'number') {
window.scrollTo(0, this.scrollY);
}
} catch (e) {
console.warn('SYNC MADE EASY: unlockBodyScroll skipped (restricted DOM): ' + e);
}
}
// ==========================================================================
// NEW — presentation-only getters that drive the reference-mockup template.
// These do not add any new business logic; they simply project the existing
// state above into the checklist-card / status-pill / modal look.
// ==========================================================================
get tasks() {
const list = [];
if (this.isSiteSupportedOrg) {
list.push({
key: 'site',
title: 'Activate a Salesforce site',
desc: this.checkSiteExist
? 'Select and confirm the Salesforce site used to authorize the connection.'
: 'No active site found in your org. Create a new site or activate an existing one.',
done: this.urlSavedSuccess,
clickable: !this.urlSavedSuccess,
handler: 'site'
});
}
list.push({
key: 'domain',
title: 'Domain URL — Remote Site Setting',
desc: 'Allow Salesforce to send requests to your domain URL.',
done: this.remoteSiteExist,
clickable: !this.disableDomainRemoteSite,
handler: 'domain'
});
list.push({
key: 'auth',
title: 'Authenticate URL — Remote Site Setting',
desc: 'Whitelist the authentication endpoint used during login.',
done: this.authenticationRemoteSite,
clickable: !this.disableAuthenticateRemoteSite,
handler: 'auth'
});
list.push({
key: 'cert',
title: 'Self-signed certificate',
desc: 'Generate the certificate used to sign secure requests.',
done: this.certificateExist,
clickable: !this.disableCertificate,
handler: 'cert'
});
return list.map((t, i) => ({
...t,
index: i,
// "Open again" removed everywhere: the action link only renders while
// the step is still pending (not done).
showAction: !t.done,
actionLabel: t.done ? 'Open again' : 'Click here to configure',
tag: t.done ? 'Done' : 'Required',
rowClass: 'task-row',
boxClass: t.done ? 'task-box task-box_done' : 'task-box',
tagClass: t.done ? 'task-tag task-tag_done' : 'task-tag task-tag_required',
// Link always renders (matches setup.html); it's only visually/
// functionally disabled via pointer-events when clickable is false.
actionClass: t.clickable ? 'task-action' : 'task-action task-action_disabled'
}));
}
get doneCount() {
return this.tasks.filter((t) => t.done).length;
}
get totalTasks() {
return this.tasks.length;
}
get verified() {
return this.isStatusChecked || this.hideCheckStatus;
}
get statusLabel() {
if (this.verified) return 'Verified';
return this.doneCount === this.totalTasks ? 'Ready to verify' : 'In progress';
}
get statusPillClass() {
if (this.verified) return 'status-pill status-pill_verified';
return this.doneCount === this.totalTasks ? 'status-pill status-pill_ready' : 'status-pill status-pill_progress';
}
get checkLabel() {
if (this.checkStatusSpinner) return 'Checking…';
return this.verified ? 'Verified ✓' : 'Check status';
}
get checkIconClass() {
return this.checkStatusSpinner ? 'check-icon check-icon_spin' : 'check-icon';
}
// Check Status button now stays visible (alongside Verify & Next) once
// verified instead of disappearing — matches the reference mockup, where
// both "Verified ✓" and "Verify & Next" show together until the user
// clicks Verify & Next. Only styling/disabled state changes here; the
// real isStatusChecked/verified logic driving it is untouched.
get checkButtonClass() {
return this.verified ? 'btn-check btn-check_done' : 'btn-check';
}
get nextButtonClass() {
return !this.isNextDisabled ? 'btn-next btn-next_active' : 'btn-next';
}
get hasSites() {
return this.isSiteSupportedOrg;
}
get noSites() {
return !this.isSiteSupportedOrg;
}
get siteChosen() {
return this.isSiteSupportedOrg && !!this.siteValue && this.urlSavedSuccess;
}
get successButtonDisabled() {
return !this.siteValue;
}
get successButtonClass() {
return this.successButtonDisabled ? 'btn-success btn-success_disabled' : 'btn-success';
}
// Single click dispatcher for the checklist rows — routes to the
// existing, unmodified handler methods above based on which row was clicked.
handleTaskAction(event) {
event.stopPropagation();
const handler = event.currentTarget.dataset.handler;
switch (handler) {
case 'site':
this.openSiteModel();
break;
case 'domain':
this.domainUrlRemoteSiteSetting();
break;
case 'auth':
this.authenticateUrlRemoteSiteSetting();
break;
case 'cert':
this.ReDirectCertificateSetting();
break;
default:
break;
}
}
handleModalContentClick(event) {
event.stopPropagation();
}
}