|
1781 | 1781 | return document.getElementById('aeo-header-content-suggestions'); |
1782 | 1782 | } |
1783 | 1783 |
|
| 1784 | + function getHeaderTrialOfferMount() { |
| 1785 | + return document.getElementById('aeo-header-trial-offer'); |
| 1786 | + } |
| 1787 | + |
1784 | 1788 | function buildHeaderRewritePriorityItems(audit) { |
1785 | 1789 | var items = buildRewriteCandidates(audit).map(function (candidate) { |
1786 | 1790 | return { |
|
1805 | 1809 |
|
1806 | 1810 | function renderHeaderRewritePriorityCard(audit) { |
1807 | 1811 | if (!audit || !audit.pages_reviewed || !audit.pages_reviewed.length) { |
| 1812 | + if (auditUiState.phase === 'error') { |
| 1813 | + return '' |
| 1814 | + + '<div class="aeo-header-priority-empty">' |
| 1815 | + + '<strong>Rewrite priorities are not ready yet.</strong>' |
| 1816 | + + '<p>' + esc(auditUiState.message || 'The latest audit could not be loaded. Refresh the page or rerun the audit to try again.') + '</p>' |
| 1817 | + + '</div>'; |
| 1818 | + } |
| 1819 | + |
| 1820 | + if (auditUiState.phase === 'pending') { |
| 1821 | + return '' |
| 1822 | + + '<div class="aeo-header-priority-empty">' |
| 1823 | + + '<strong>The latest audit is still running…</strong>' |
| 1824 | + + '<p>' + esc(auditUiState.message || 'Rewrite priorities appear after the next completed audit snapshot lands.') + '</p>' |
| 1825 | + + '</div>'; |
| 1826 | + } |
| 1827 | + |
1808 | 1828 | return '' |
1809 | 1829 | + '<div class="aeo-header-priority-empty">' |
1810 | 1830 | + '<strong>Loading rewrite priorities…</strong>' |
|
2017 | 2037 | mount.innerHTML = renderHeaderContentSuggestionsCard(); |
2018 | 2038 | } |
2019 | 2039 |
|
| 2040 | + function renderHeaderTrialOfferCard() { |
| 2041 | + var data = getRewriteAvailabilityData() || {}; |
| 2042 | + var available = typeof data.available === 'number' ? data.available : 0; |
| 2043 | + var limit = typeof data.limit === 'number' ? data.limit : 0; |
| 2044 | + var starterArticles = data.starterArticles > 0 ? data.starterArticles : 5; |
| 2045 | + var starterPrice = data.starterPriceCents > 0 ? formatMoneyCents(data.starterPriceCents) : '$1'; |
| 2046 | + var planLabel = formatRewritePlanLabel(data.plan, data.planLabel); |
| 2047 | + var upgradeUrl = getRewriteUpgradeUrl(); |
| 2048 | + var cardClass = 'aeo-header-trial-offer'; |
| 2049 | + var kicker = '$1 Starter Trial'; |
| 2050 | + var title = 'Checking article trial availability...'; |
| 2051 | + var body = 'A one-time Stripe Checkout charge can unlock ' + starterArticles + ' AEO article credits for rewrites or new articles in Studio.'; |
| 2052 | + var note = ''; |
| 2053 | + var actionHtml = ''; |
| 2054 | + |
| 2055 | + if (rewriteAvailabilityState.phase === 'error') { |
| 2056 | + cardClass += ' is-error'; |
| 2057 | + title = 'Starter trial is temporarily unavailable'; |
| 2058 | + body = rewriteAvailabilityState.message || 'The plugin could not load article trial availability right now.'; |
| 2059 | + note = 'You can still open Studio to manage billing directly.'; |
| 2060 | + if (upgradeUrl) { |
| 2061 | + actionHtml = '<a href="' + esc(upgradeUrl) + '" class="button button-secondary" target="_blank" rel="noopener">Manage in Studio</a>'; |
| 2062 | + } |
| 2063 | + } else if (available > 0) { |
| 2064 | + cardClass += ' is-active'; |
| 2065 | + kicker = planLabel || 'AEO Article Credits'; |
| 2066 | + title = available + ' of ' + (limit > 0 ? limit : starterArticles) + ' article credits remaining'; |
| 2067 | + body = 'Use these credits on full AEO rewrites or brand-new article runs in Studio.'; |
| 2068 | + note = 'The ' + (planLabel || 'active plan') + ' balance is attached to this connected account.'; |
| 2069 | + if (upgradeUrl) { |
| 2070 | + actionHtml = '<a href="' + esc(upgradeUrl) + '" class="button button-secondary" target="_blank" rel="noopener">Manage in Studio</a>'; |
| 2071 | + } |
| 2072 | + } else if (data.checkoutEnabled && data.starterEligible) { |
| 2073 | + title = 'Upgrade for ' + starterPrice + ' and unlock ' + starterArticles + ' AEO articles'; |
| 2074 | + body = 'Use them on full rewrites or new article creation in Studio. Stripe Checkout securely collects card details for a one-time ' + starterPrice + ' charge.'; |
| 2075 | + note = 'This starter trial is designed as a fast path out of the free plan.'; |
| 2076 | + actionHtml = '<button type="button" class="button button-primary aeo-start-rewrite-checkout"' + (rewriteCheckoutState.loading ? ' disabled aria-disabled="true"' : '') + '>' + esc(rewriteCheckoutState.loading ? 'Opening Stripe checkout...' : ('Upgrade for ' + starterPrice)) + '</button>'; |
| 2077 | + } else { |
| 2078 | + cardClass += ' is-exhausted'; |
| 2079 | + kicker = planLabel || 'Starter Trial'; |
| 2080 | + title = planLabel === '$1 Trial Plan' ? 'Your $1 trial is exhausted' : 'Starter trial unavailable'; |
| 2081 | + body = 'Upgrade in Studio to keep generating AEO rewrites and new articles after the trial credits are spent.'; |
| 2082 | + note = 'Billing runs through Stripe Checkout as a one-time payment for the starter trial.'; |
| 2083 | + if (upgradeUrl) { |
| 2084 | + actionHtml = '<a href="' + esc(upgradeUrl) + '" class="button button-secondary" target="_blank" rel="noopener">Upgrade in Studio</a>'; |
| 2085 | + } |
| 2086 | + } |
| 2087 | + |
| 2088 | + return '' |
| 2089 | + + '<div id="aeo-header-trial-offer" class="' + esc(cardClass) + '">' |
| 2090 | + + '<span class="aeo-header-trial-kicker">' + esc(kicker) + '</span>' |
| 2091 | + + '<h2 class="aeo-header-trial-title">' + esc(title) + '</h2>' |
| 2092 | + + '<p class="aeo-header-trial-body">' + esc(body) + '</p>' |
| 2093 | + + (note ? '<p class="aeo-header-trial-note"><strong>Billing:</strong> ' + esc(note) + '</p>' : '') |
| 2094 | + + (actionHtml ? '<div class="aeo-header-trial-actions">' + actionHtml + '</div>' : '') |
| 2095 | + + '</div>'; |
| 2096 | + } |
| 2097 | + |
| 2098 | + function renderHeaderTrialOffer() { |
| 2099 | + var mount = getHeaderTrialOfferMount(); |
| 2100 | + if (!mount) return; |
| 2101 | + mount.outerHTML = renderHeaderTrialOfferCard(); |
| 2102 | + } |
| 2103 | + |
2020 | 2104 | function refreshHeaderInsights() { |
| 2105 | + renderHeaderTrialOffer(); |
2021 | 2106 | renderHeaderRewritePriority(currentAuditData); |
2022 | 2107 | renderHeaderContentSuggestions(); |
2023 | 2108 | } |
|
2034 | 2119 | var currentAuditData = null; |
2035 | 2120 | var currentDiscoveryPayload = null; |
2036 | 2121 | var currentVisibilityPayload = null; |
| 2122 | + var auditUiState = { |
| 2123 | + phase: 'idle', |
| 2124 | + message: '' |
| 2125 | + }; |
2037 | 2126 | var visibilityUiState = { |
2038 | 2127 | phase: 'idle', |
2039 | 2128 | message: '' |
|
2205 | 2294 | actionHtml = '<a href="' + esc(upgradeUrl) + '" class="button button-secondary" target="_blank" rel="noopener">Manage account</a>'; |
2206 | 2295 | } |
2207 | 2296 | } else if (available > 0) { |
2208 | | - body = (planLabel ? planLabel + ' active. ' : '') + available + ' rewrite' + (available === 1 ? '' : 's') + ' remaining'; |
| 2297 | + body = (planLabel ? planLabel + ' active. ' : '') + available + ' AEO article credit' + (available === 1 ? '' : 's') + ' remaining'; |
2209 | 2298 | if (limit > 0) body += ' out of ' + limit + '.'; |
2210 | 2299 | else body += '.'; |
2211 | 2300 | } else if (data.checkoutEnabled && data.starterEligible) { |
2212 | | - body = 'Unlock ' + starterArticles + ' full-article rewrites for ' + starterPrice + '.'; |
2213 | | - actionHtml = '<button type="button" class="button button-primary aeo-start-rewrite-checkout"' + (rewriteCheckoutState.loading ? ' disabled aria-disabled="true"' : '') + '>' + esc(rewriteCheckoutState.loading ? 'Opening checkout...' : ('Unlock ' + starterArticles + ' rewrites for ' + starterPrice)) + '</button>'; |
| 2301 | + body = 'Unlock ' + starterArticles + ' AEO article credits for ' + starterPrice + '. Use them on rewrites or new articles in Studio.'; |
| 2302 | + actionHtml = '<button type="button" class="button button-primary aeo-start-rewrite-checkout"' + (rewriteCheckoutState.loading ? ' disabled aria-disabled="true"' : '') + '>' + esc(rewriteCheckoutState.loading ? 'Opening checkout...' : ('Upgrade for ' + starterPrice)) + '</button>'; |
2214 | 2303 | } else { |
2215 | | - body = (planLabel ? planLabel + '. ' : '') + 'No rewrite tokens remain on this account.'; |
| 2304 | + body = (planLabel ? planLabel + '. ' : '') + 'No AEO article credits remain on this account.'; |
2216 | 2305 | if (upgradeUrl) { |
2217 | 2306 | actionHtml = '<a href="' + esc(upgradeUrl) + '" class="button button-secondary" target="_blank" rel="noopener">Upgrade in Studio</a>'; |
2218 | 2307 | } |
|
4812 | 4901 |
|
4813 | 4902 | function loadAudit(refresh) { |
4814 | 4903 | if (!currentAuditData) { |
| 4904 | + auditUiState.phase = refresh ? 'refreshing' : 'loading'; |
| 4905 | + auditUiState.message = ''; |
| 4906 | + refreshHeaderInsights(); |
4815 | 4907 | setAuditTabsLoading(); |
4816 | 4908 | setSiteAuditPending(); |
4817 | 4909 | } |
|
4826 | 4918 | .then(function (r) { return r.json(); }) |
4827 | 4919 | .then(function (res) { |
4828 | 4920 | if (res.success) { |
| 4921 | + auditUiState.phase = 'ready'; |
| 4922 | + auditUiState.message = ''; |
4829 | 4923 | stopAuditRetry(); |
4830 | 4924 | renderAudit(res.data); |
4831 | 4925 | } else { |
|
4846 | 4940 | } else { |
4847 | 4941 | showError(msg + ' Showing the last completed audit snapshot.'); |
4848 | 4942 | } |
| 4943 | + auditUiState.phase = 'ready'; |
| 4944 | + auditUiState.message = ''; |
4849 | 4945 | refreshWorkflowChrome(); |
4850 | 4946 | return; |
4851 | 4947 | } |
4852 | 4948 |
|
| 4949 | + auditUiState.phase = code === 'aeocas_no_audit' ? 'pending' : 'error'; |
| 4950 | + auditUiState.message = msg; |
4853 | 4951 | AUDIT_TAB_IDS.forEach(function (id) { |
4854 | 4952 | var el = document.getElementById('tab-' + id); |
4855 | 4953 | if (!el) return; |
|
4860 | 4958 | } |
4861 | 4959 | }); |
4862 | 4960 | startAuditRetry(); |
| 4961 | + refreshHeaderInsights(); |
4863 | 4962 | refreshWorkflowChrome(); |
4864 | 4963 | } |
4865 | 4964 | }) |
4866 | 4965 | .catch(function (err) { |
| 4966 | + var msg = 'Network error: ' + (err.message || 'Please try again.'); |
4867 | 4967 | if (currentAuditData) { |
4868 | | - showError('Network error: ' + (err.message || 'Please try again.') + ' Showing the last completed audit snapshot.'); |
| 4968 | + showError(msg + ' Showing the last completed audit snapshot.'); |
| 4969 | + auditUiState.phase = 'ready'; |
| 4970 | + auditUiState.message = ''; |
4869 | 4971 | refreshWorkflowChrome(); |
4870 | 4972 | return; |
4871 | 4973 | } |
| 4974 | + auditUiState.phase = 'error'; |
| 4975 | + auditUiState.message = msg; |
4872 | 4976 | AUDIT_TAB_IDS.forEach(function (id) { |
4873 | 4977 | var el = document.getElementById('tab-' + id); |
4874 | 4978 | if (!el) return; |
4875 | 4979 | if (id === 'site-audit') { |
4876 | 4980 | el.innerHTML = renderSiteAuditPending(); |
4877 | 4981 | } else { |
4878 | | - el.innerHTML = renderAuditEmpty('Network error: ' + (err.message || 'Please try again.')); |
| 4982 | + el.innerHTML = renderAuditEmpty(msg); |
4879 | 4983 | } |
4880 | 4984 | }); |
4881 | 4985 | startAuditRetry(); |
| 4986 | + refreshHeaderInsights(); |
4882 | 4987 | refreshWorkflowChrome(); |
4883 | 4988 | }); |
4884 | 4989 | } |
|
4931 | 5036 | if (!refresh && !tab.innerHTML.trim()) { |
4932 | 5037 | discoveryUiState.phase = 'loading'; |
4933 | 5038 | tab.innerHTML = renderDiscoveryLoading(); |
| 5039 | + refreshHeaderInsights(); |
4934 | 5040 | } |
4935 | 5041 |
|
4936 | 5042 | var data = new FormData(); |
|
5008 | 5114 | refreshWorkflowChrome(); |
5009 | 5115 | } |
5010 | 5116 | }) |
5011 | | - .catch(function () { |
5012 | | - // Network error — keep polling silently; the ticker keeps ticking |
5013 | | - // and "Last checked" will drift, making the stall visible. |
| 5117 | + .catch(function (err) { |
| 5118 | + if (!currentDiscoveryPayload) { |
| 5119 | + var msg = 'Network error: ' + ((err && err.message) || 'Please try again.'); |
| 5120 | + stopDiscoveryPolling(); |
| 5121 | + stopDiscoveryTicker(); |
| 5122 | + discoveryUiState.phase = 'error'; |
| 5123 | + discoveryUiState.status = 'failed'; |
| 5124 | + discoveryUiState.currentStage = msg; |
| 5125 | + currentDiscoveryPayload = { status: 'failed', current_stage: msg }; |
| 5126 | + tab.innerHTML = '<div class="notice notice-error" style="padding:12px 16px;"><p>' + esc(msg) + '</p></div>'; |
| 5127 | + } |
| 5128 | + refreshHeaderInsights(); |
| 5129 | + refreshWorkflowChrome(); |
5014 | 5130 | }); |
5015 | 5131 | } |
5016 | 5132 |
|
|
0 commit comments