599 lines
30 KiB
HTML
599 lines
30 KiB
HTML
<!--
|
||
@description : Restyled to match the reference HTML wizard mockup's
|
||
"Salesforce-Shopify Configuration" screen. All Apex calls
|
||
and existing @track state/methods in shopifyCredentials.js
|
||
are unchanged — only the template/CSS and a handful of new
|
||
presentation-only getters/methods (appended at the bottom
|
||
of shopifyCredentials.js) were added.
|
||
@author : SME Team (restyle by Claude)
|
||
-->
|
||
<template>
|
||
|
||
<!-- Custom in-component toasts (success = green→teal gradient, error = red). -->
|
||
<template if:true={toasts.length}>
|
||
<div class="sw-toast-container">
|
||
<template for:each={toasts} for:item="t">
|
||
<div key={t.id} class={t.cssClass}>
|
||
<span class="sw-toast-icon">{t.iconLabel}</span>
|
||
<div class="sw-toast-body">
|
||
<div class="sw-toast-title">{t.title}</div>
|
||
<div class="sw-toast-message">{t.message}</div>
|
||
</div>
|
||
<button class="sw-toast-close" data-id={t.id} onclick={handleToastClose} title="Dismiss">×</button>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
|
||
<template lwc:if={showBodyLoading}>
|
||
<div class="sw-loading">
|
||
<img src={pageLoadingGif} class="pageLoading-Gif" alt="Loading">
|
||
</div>
|
||
</template>
|
||
|
||
<template lwc:else>
|
||
<div class="sw-card">
|
||
|
||
<!-- Card header -->
|
||
<div class="sw-card-header">
|
||
<div>
|
||
<h2 class="sw-title">Salesforce–Shopify Configuration</h2>
|
||
<p class="sw-subtitle">Connect your Shopify store and choose which records sync between the two platforms.</p>
|
||
</div>
|
||
<div class="sw-header-right">
|
||
<div class={autoConfigPillClass}>
|
||
<span class="conn-dot"></span>{autoConfigPillLabel}
|
||
</div>
|
||
<div class="sw-divider"></div>
|
||
<span class="sw-auto-label">Auto Configuration</span>
|
||
<c-tooltip title-value="Before enabling Auto Configuration, make sure you have completed the 'Shopify Store Setup' step. This allows you to skip the next steps, as the system automatically handles the remaining object and field configurations. You can disable Auto Configuration at any time to modify the setup based on your business needs."></c-tooltip>
|
||
<button class={autoToggleTrackClass} onclick={changeConfigurationType} type="button" title="Toggle Auto Configuration">
|
||
<span class="obj-toggle-knob"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Connection hero -->
|
||
<div class="sw-hero">
|
||
<div class="hero-side">
|
||
<span class="hero-icon hero-icon_shopify">
|
||
<img src={StoreLogo} alt="Shopify" class="hero-icon-img" />
|
||
</span>
|
||
<div>
|
||
<div class="hero-name">Shopify</div>
|
||
<div class="hero-sub">{storeName}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hero-mid">
|
||
<div class="hero-line-row">
|
||
<span class="hero-line hero-line_left"></span>
|
||
<span class={connectionPillClass}>
|
||
<span class="conn-dot conn-dot_pulse"></span>{connectionLabel}
|
||
</span>
|
||
<span class="hero-line hero-line_right"></span>
|
||
</div>
|
||
<template lwc:if={showLastSynced}>
|
||
<span class="hero-note">{lastSyncedText}</span>
|
||
</template>
|
||
</div>
|
||
|
||
<div class="hero-side hero-side_right">
|
||
<div class="hero-text_right">
|
||
<div class="hero-name">Salesforce</div>
|
||
<div class="hero-sub">{organizationName}</div>
|
||
</div>
|
||
<span class="hero-icon hero-icon_sf">
|
||
<img src={SFLogo} alt="Salesforce" class="hero-icon-img" />
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Form fields -->
|
||
<div class="sw-fields">
|
||
|
||
<template lwc:if={isManual}>
|
||
<template lwc:if={isSiteSupportedOrg}>
|
||
<div class="field-row">
|
||
<div class="field-label">
|
||
<label>Select a Site URL</label>
|
||
<c-tooltip title-value="Salesforce Sites allow you to create public websites or endpoints that integrate directly with your Salesforce org, without requiring user login. These can be accessed through a branded URL to publicly expose selected data or services. Select an existing site or create a new one." link={siteurlHelptext}></c-tooltip>
|
||
</div>
|
||
<lightning-input type="text" value={siteURL} disabled variant="label-hidden" class="field-input field-input_readonly"></lightning-input>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
|
||
<div class="field-row">
|
||
<div class="field-label">
|
||
<label>Shopify Store Name</label>
|
||
<c-tooltip title-value={label.Please_enter_your_store_name}></c-tooltip>
|
||
</div>
|
||
<template lwc:if={storeNameSelected}>
|
||
<lightning-input type="text" value={storeName} disabled variant="label-hidden" class="field-input field-input_readonly"></lightning-input>
|
||
</template>
|
||
<template lwc:else>
|
||
<lightning-input type="text" value={storeName} placeholder={label.Enter_Store_Name}
|
||
onchange={changeStoreUrl} variant="label-hidden" class="field-input"></lightning-input>
|
||
</template>
|
||
</div>
|
||
|
||
<div class="field-row">
|
||
<div class="field-label">
|
||
<label>Shopify Store Access Token</label>
|
||
<c-tooltip title-value={label.Get_your_Shopify_password_from_private_app}></c-tooltip>
|
||
</div>
|
||
<div class="token-wrap">
|
||
<template lwc:if={accessTokenAvailable}>
|
||
<lightning-input type="password" value={apiAccessToken} disabled placeholder={label.Enter_Access_token}
|
||
variant="label-hidden" class="field-input field-input_token field-input_readonly"></lightning-input>
|
||
</template>
|
||
<template lwc:else>
|
||
<lightning-input type="password" value={apiAccessToken} placeholder={label.Enter_Access_token}
|
||
onchange={changeAccessToken} variant="label-hidden" class="field-input field-input_token"></lightning-input>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<template lwc:if={isManual}>
|
||
<template lwc:if={showCredentialActions}>
|
||
<div class="field-row">
|
||
<div></div>
|
||
<div class="field-actions">
|
||
<button class={checkCredButtonClass} onclick={handleCheckCredentialClick} disabled={disableCheckCredential}>Check Credential</button>
|
||
<button class={genTokenButtonClass} onclick={handleGenerateAccessToken} disabled={disableGenerateAccessToken}>Generate Access Token</button>
|
||
<c-tooltip title-value={label.Generate_Access_Token_Info} link="https://support.syncmadeasy.com/support/solutions/articles/1130000047921-steps-to-retrieve-shopify-access-token-from-the-dev-dashboard-using-sync-made-easy"></c-tooltip>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<template lwc:if={remoteSiteForStore}>
|
||
<div class="field-row">
|
||
<div></div>
|
||
<div class="field-actions">
|
||
<button class="sw-btn sw-btn_primary" onclick={createRemoteSiteForStore}>Create Remote Site</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="field-row">
|
||
<div class="field-label">
|
||
<label>Select a Pricebook</label>
|
||
<c-tooltip title-value={label.The_standard_price_book_is_the_master_list}></c-tooltip>
|
||
</div>
|
||
<lightning-combobox value={priceBook} options={priceBookList} onchange={changePriceBook}
|
||
placeholder="Select Pricebook" variant="label-hidden" class="field-input fix-slds-input_faux"></lightning-combobox>
|
||
</div>
|
||
|
||
<div class="field-row">
|
||
<template lwc:if={showCurrencyCode}>
|
||
<div class="field-label">
|
||
<label>Select a Currency</label>
|
||
<c-tooltip title-value={label.Multicurrency}></c-tooltip>
|
||
</div>
|
||
<lightning-combobox value={storeSelectedCurrency} options={currencyCodeList}
|
||
onchange={changeCurrencyISOCode} variant="label-hidden" class="field-input fix-slds-input_faux"></lightning-combobox>
|
||
</template>
|
||
<template lwc:else>
|
||
<div class="field-label">
|
||
<label>Default Currency</label>
|
||
<c-tooltip title-value={label.Default_Organization_Currency_ISO_Code}></c-tooltip>
|
||
</div>
|
||
<lightning-input type="text" value={storeSelectedCurrency} disabled variant="label-hidden" class="field-input"></lightning-input>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
|
||
<!-- Auto Configuration summary -->
|
||
<template lwc:if={isAutomatic}>
|
||
<div class="auto-summary-wrap">
|
||
<div class="auto-summary-card">
|
||
<div class="auto-summary-head">
|
||
<span class="auto-summary-icon">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h7l-1 8 10-12h-7l1-8z"></path></svg>
|
||
</span>
|
||
<div>
|
||
<div class="auto-summary-title">Auto Configuration is on</div>
|
||
<div class="auto-summary-sub">Settings are applied from your most recently added store's configuration.</div>
|
||
</div>
|
||
</div>
|
||
<div class="auto-summary-grid">
|
||
<div class="auto-summary-item">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f8a24" stroke-width="2.4"><path d="M20 6L9 17l-5-5"></path></svg>
|
||
<div><div class="auto-summary-item-title">Pricebook</div><div class="auto-summary-item-sub">{selectedPricebookLabel} — auto-selected</div></div>
|
||
</div>
|
||
<div class="auto-summary-item">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f8a24" stroke-width="2.4"><path d="M20 6L9 17l-5-5"></path></svg>
|
||
<div><div class="auto-summary-item-title">Currency</div><div class="auto-summary-item-sub">{storeSelectedCurrency} — matched to store</div></div>
|
||
</div>
|
||
<div class="auto-summary-item">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f8a24" stroke-width="2.4"><path d="M20 6L9 17l-5-5"></path></svg>
|
||
<div><div class="auto-summary-item-title">Object sync</div><div class="auto-summary-item-sub">Recommended set enabled</div></div>
|
||
</div>
|
||
<div class="auto-summary-item">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f8a24" stroke-width="2.4"><path d="M20 6L9 17l-5-5"></path></svg>
|
||
<div><div class="auto-summary-item-title">Notifications</div><div class="auto-summary-item-sub">Sent to your admin email</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="auto-summary-footnote">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#a0a0a0" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M12 16v-4M12 8h.01"></path></svg>
|
||
<span>Need fine-grained control? Turn off <strong>Auto Configuration</strong> to edit these manually.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Access scope error -->
|
||
<template lwc:if={AccessScope}>
|
||
<div class="scope-error-card">
|
||
<div class="scope-error-title">Access Token Missing Permissions</div>
|
||
<ul class="scope-error-list">
|
||
<template for:each={listAccessScopeError} for:item="scopeError">
|
||
<li key={scopeError} class="scope-error-item">{scopeError}</li>
|
||
</template>
|
||
</ul>
|
||
<p class="scope-error-help">
|
||
These permissions are missing from your store's access token. Enable them in your Shopify
|
||
Custom App, then click <strong>Generate Access Token</strong> again to issue a fresh token
|
||
with the required access.
|
||
</p>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Two panels -->
|
||
<template lwc:if={isManual}>
|
||
<div class="sw-panels">
|
||
<!-- Object sync -->
|
||
<div class="panel-card">
|
||
<div class="panel-head">
|
||
<h3 class="panel-title">Object Sync Settings</h3>
|
||
<span class="obj-count-badge">{objOnCount} of 6 on</span>
|
||
</div>
|
||
|
||
<div class="obj-row">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M21 16V8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
||
<path d="M3.3 7L12 12l8.7-5M12 22V12"></path>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">{label.Product}</span>
|
||
</div>
|
||
<div class="obj-right">
|
||
<!-- <span class="required-tag">Required</span> -->
|
||
<div class="locked-toggle" title="Always enabled"><span class="locked-knob"></span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="obj-row">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||
<circle cx="12" cy="7" r="4"></circle>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">{label.Customer}</span>
|
||
</div>
|
||
<div class="obj-right">
|
||
<!-- <span class="required-tag">Required</span> -->
|
||
<div class="locked-toggle" title="Always enabled"><span class="locked-knob"></span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="obj-row">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
||
<path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"></path>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">{label.Draft_Order}</span>
|
||
</div>
|
||
<button class={draftToggleTrackClass} onclick={handleToggleDraftSync} type="button" title="Toggle Draft Order sync">
|
||
<span class="obj-toggle-knob"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="obj-row">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="9" cy="21" r="1"></circle>
|
||
<circle cx="20" cy="21" r="1"></circle>
|
||
<path d="M1 1h4l2.7 13.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6"></path>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">Paid Order</span>
|
||
</div>
|
||
<button class={orderToggleTrackClass} onclick={handleToggleOrderSync} type="button" title="Toggle Paid Order sync">
|
||
<span class="obj-toggle-knob"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="obj-row">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 2l9 5-9 5-9-5 9-5z"></path>
|
||
<path d="M3 12l9 5 9-5M3 17l9 5 9-5"></path>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">{label.Collection}</span>
|
||
</div>
|
||
<button class={collectionToggleTrackClass} onclick={handleToggleCollectionSync} type="button" title="Toggle Collection sync">
|
||
<span class="obj-toggle-knob"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="obj-row obj-row_last">
|
||
<div class="obj-left">
|
||
<span class="obj-icon">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M21 10c0 6-9 12-9 12s-9-6-9-12a9 9 0 0 1 18 0z"></path>
|
||
<circle cx="12" cy="10" r="3"></circle>
|
||
</svg>
|
||
</span>
|
||
<span class="obj-label">{label.Location}/{label.Inventory}</span>
|
||
</div>
|
||
<button class={inventoryToggleTrackClass} onclick={handleToggleInventorySync} type="button" title="Toggle Location/Inventory sync">
|
||
<span class="obj-toggle-knob"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Emails -->
|
||
<div class="panel-card panel-card_emails">
|
||
<h3 class="panel-title">Sync notification emails</h3>
|
||
<p class="panel-sub">Add up to 3 addresses to receive sync-related alerts.</p>
|
||
<!-- <template if:false={stopEmailError}>
|
||
<div class="email-hint">{emailLimitHintText}</div>
|
||
</template> -->
|
||
|
||
<template for:each={emailList} for:item="email">
|
||
<div key={email.index} class="email-row">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#4f8a24" stroke-width="2.4" class="email-check-icon">
|
||
<path d="M20 6L9 17l-5-5"></path>
|
||
</svg>
|
||
|
||
<template lwc:if={email.isEditable}>
|
||
<input type="email" value={email.value} data-id={email.index}
|
||
onblur={handleEmailBlur} placeholder="name@example.com" class="email-input-native">
|
||
</template>
|
||
<template lwc:else>
|
||
<span class="email-text">{email.value}</span>
|
||
</template>
|
||
|
||
<button class="email-icon-btn" data-id={email.index} onclick={editEmail} title="Edit">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="pointer-events:none">
|
||
<path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"></path>
|
||
</svg>
|
||
</button>
|
||
|
||
<template lwc:if={showDelete}>
|
||
<button class="email-icon-btn email-icon-btn_danger" data-id={email.index} onclick={deleteEmail} title="Remove">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="pointer-events:none">
|
||
<path d="M18 6L6 18M6 6l12 12"></path>
|
||
</svg>
|
||
</button>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
|
||
<template lwc:if={addButtonVisible}>
|
||
<button class="add-email-btn" onclick={handleAddEmailRow}>
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" style="pointer-events:none">
|
||
<path d="M12 5v14M5 12h14"></path>
|
||
</svg>
|
||
Add email address
|
||
</button>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Footer actions -->
|
||
<div class="sw-actions">
|
||
<button class="sw-btn-back" onclick={handleBackStep}>
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M11 6l-6 6 6 6"></path></svg>
|
||
Back
|
||
</button>
|
||
<button class="sw-btn-save" onclick={handleSaveShopifyCredentials}>
|
||
Save & Next
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"></path></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Check Credential result modal -->
|
||
<template lwc:if={credModalOpen}>
|
||
<div class="sw-modal-overlay">
|
||
<div class="sw-modal sw-modal_narrow">
|
||
<div class="sw-modal-accent"></div>
|
||
<div class="sw-modal-body sw-modal-body_center credcheck-modal">
|
||
<template lwc:if={credChecking}>
|
||
<div class="credcheck-spinner-ring"></div>
|
||
<p class="credcheck-title">Checking credential…</p>
|
||
</template>
|
||
<template lwc:else>
|
||
<template lwc:if={credResultSuccess}>
|
||
<div class="credcheck-icon credcheck-icon_success">
|
||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20 6L9 17l-5-5"></path>
|
||
</svg>
|
||
</div>
|
||
<p class="credcheck-title">Credential is valid</p>
|
||
<p class="credcheck-sub">The access token authenticated successfully with Shopify.</p>
|
||
</template>
|
||
<template lwc:else>
|
||
<div class="credcheck-icon credcheck-icon_error">
|
||
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round">
|
||
<path d="M18 6L6 18M6 6l12 12"></path>
|
||
</svg>
|
||
</div>
|
||
<p class="credcheck-title">Credential is not valid</p>
|
||
<p class="credcheck-sub">Please double-check the access token and try again.</p>
|
||
</template>
|
||
<button class="btn-success" onclick={closeCredCheckModal}>Done</button>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Real, untouched multi-store picker (New / Edit / Existing / Delete) -->
|
||
<template lwc:if={multiStoreModel}>
|
||
<c-multi-store-controller onclosemodal={closeMultiStoreModal} onmultistoreenable={multiStoreHandler}>
|
||
</c-multi-store-controller>
|
||
</template>
|
||
|
||
<!-- Pricebook / Currency change confirmation -->
|
||
<template lwc:if={openPricebookCurrencyModal}>
|
||
<div class="sw-modal-overlay">
|
||
<div class="sw-modal sw-modal_narrow">
|
||
<div class="sw-modal-accent"></div>
|
||
<div class="sw-modal-body sw-modal-body_center">
|
||
<h2 class="sw-modal-title">Attention</h2>
|
||
<template lwc:if={isPricebookChanged}>
|
||
<p class="sw-modal-note">{changePricebookMessage}</p>
|
||
</template>
|
||
<template lwc:if={isCurrencyChanged}>
|
||
<p class="sw-modal-note">{changeCurrencyMessage}</p>
|
||
</template>
|
||
<div class="sw-modal-actions" style="justify-content:center">
|
||
<button class="sw-modal-secondary" onclick={closePricebookCurrencyModal}>Close</button>
|
||
<button class="btn-success" onclick={saveShopifyCredentials}>Proceed</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- Generate Access Token modal (real OAuth flow, untouched logic) -->
|
||
<template lwc:if={showGenerateTokenModal}>
|
||
<div class="sw-modal-overlay" lwc:ref="genModalOverlay">
|
||
<div class="sw-modal sw-modal_narrow gen-modal">
|
||
|
||
<!-- Fixed (non-scrolling) header: logo + title -->
|
||
<div class="gen-token-header-fixed">
|
||
<div class="gen-token-header">
|
||
<span class="gen-token-header-icon">
|
||
<img src={generateTokenHeaderLogo} alt="Sync made easy" class="gen-token-header-logo">
|
||
</span>
|
||
</div>
|
||
<template lwc:if={isGeneratingToken}></template>
|
||
<template lwc:else>
|
||
<h2 class="gen-token-fixed-title">Generate Access Token</h2>
|
||
</template>
|
||
</div>
|
||
|
||
<!-- Scrollable middle content -->
|
||
<div class="sw-modal-body gen-token-scroll-body">
|
||
<template lwc:if={isGeneratingToken}>
|
||
<div class="gen-token-generating">
|
||
<h2 class="gen-token-generating-heading">Generate Shopify Access Token</h2>
|
||
<div class="gen-token-spinner-ring">
|
||
<span class="gen-token-spinner-badge">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M5 8h14l-1 12H6L5 8z"></path>
|
||
<path d="M8.5 8V6a3.5 3.5 0 0 1 7 0v2"></path>
|
||
</svg>
|
||
</span>
|
||
</div>
|
||
<p class="gen-token-generating-title">The token is generating…</p>
|
||
<p class="gen-token-generating-sub">Please complete the authorization in the Shopify window. This may take a few moments.</p>
|
||
<div class="gen-token-wait-pill">
|
||
<span class="gen-token-wait-dot"></span>
|
||
<template lwc:if={countdownStarted}>
|
||
<span>Auto-closing in {tokenGenCountdown}s</span>
|
||
</template>
|
||
<template lwc:else>
|
||
<span>Waiting for Shopify authorization…</span>
|
||
</template>
|
||
</div>
|
||
<div class="gen-token-cancel-row">
|
||
<button class="sw-modal-secondary" onclick={closeGenerateTokenModal}>Cancel</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<template lwc:else>
|
||
<div class="gen-token-store-banner">
|
||
<span class="gen-token-store-badge">
|
||
<img src={StoreLogo} alt="Store" class="gen-token-store-badge-img">
|
||
</span>
|
||
<span class="gen-token-store-url">{storeShopifyUrl}</span>
|
||
<button class="token-eye" title="Copy store URL" onclick={copyStoreUrl}>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="gen-token-checklist-box">
|
||
<div class="gen-token-checklist-title">
|
||
<span class="gen-token-check-badge">
|
||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>
|
||
</span>
|
||
Before clicking “Generate Token” button:
|
||
</div>
|
||
<ol class="gen-token-step-list">
|
||
<li>In your Shopify Partner Dashboard or store Admin, create a Custom App.</li>
|
||
<li>Under “API credentials”, copy the <b>Client ID</b> and <b>Client secret</b>.</li>
|
||
<li>Add the Redirect URL below to your app's allowed redirect URLs.</li>
|
||
<li>Enter both values below and click <b>Generate Token</b>.</li>
|
||
</ol>
|
||
<div class="gen-token-guide-row">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#5fa832" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg>
|
||
<span>Need help? Read the full guide: <a href="https://support.syncmadeasy.com/support/solutions/articles/1130000047921-steps-to-retrieve-shopify-access-token-from-the-dev-dashboard-using-sync-made-easy" target="_blank" class="gen-token-guide-link">Steps to Retrieve Shopify Access Token from the Dev Dashboard using Sync Made Easy</a></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sw-modal-field">
|
||
<label class="sw-modal-label">Redirect URL <span class="gen-token-hint">(register this in your Shopify app)</span></label>
|
||
<div class="gen-token-redirect-row" onclick={copyRedirectUri} title="Click to copy">
|
||
<span class="gen-token-redirect-uri">{generatorRedirectUri}</span>
|
||
<button class="token-eye" title="Copy" onclick={copyRedirectUri}>
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<input type="text" name="username" autocomplete="username" tabindex="-1" aria-hidden="true" class="gen-token-decoy">
|
||
<input type="password" name="password" autocomplete="current-password" tabindex="-1" aria-hidden="true" class="gen-token-decoy">
|
||
|
||
<div class="sw-modal-field">
|
||
<label class="sw-modal-label"><span class="req">*</span> Client ID</label>
|
||
<input type="text" value={generatorClientId} oninput={handleGeneratorClientIdChange}
|
||
onfocus={handleCredentialFocus} readonly={clientFieldsReadOnly}
|
||
placeholder="Enter your Shopify app Client ID" class="gen-token-input"
|
||
autocomplete="off" name="shopifyClientId" lwc:ref="clientIdInput">
|
||
</div>
|
||
|
||
<div class="sw-modal-field">
|
||
<label class="sw-modal-label"><span class="req">*</span> Client Secret</label>
|
||
<input type="password" value={generatorClientSecret} oninput={handleGeneratorClientSecretChange}
|
||
onfocus={handleCredentialFocus} readonly={clientFieldsReadOnly}
|
||
placeholder="Enter your Shopify app Client Secret" class="gen-token-input"
|
||
autocomplete="new-password" name="shopifyClientSecret" lwc:ref="clientSecretInput">
|
||
</div>
|
||
|
||
</template>
|
||
</div>
|
||
|
||
<!-- Fixed (non-scrolling) footer: Close / Generate Token -->
|
||
<template lwc:if={isGeneratingToken}></template>
|
||
<template lwc:else>
|
||
<div class="gen-token-footer-fixed">
|
||
<div class="sw-modal-actions">
|
||
<button class="sw-modal-secondary" onclick={closeGenerateTokenModal}>Close</button>
|
||
<button class={generateTokenSubmitClass} disabled={disableGenerateTokenSubmit} onclick={handleGenerateTokenSubmit}>Generate Token</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
</template> |