fix(sidepanel): restore plus settings before auto run

This commit is contained in:
QLHazycoder
2026-05-03 02:57:34 +08:00
parent 2437e6e67d
commit aa2337f9e5
4 changed files with 391 additions and 29 deletions
+9 -4
View File
@@ -284,11 +284,16 @@
} }
if (generator === 'icloud') { if (generator === 'icloud') {
const stateFetchMode = String(mergedState.icloudFetchMode || '').trim().toLowerCase(); const stateFetchMode = String(mergedState.icloudFetchMode || '').trim().toLowerCase();
return fetchIcloudHideMyEmail({ const icloudOptions = {
generateNew: Boolean(options.generateNew) || stateFetchMode === 'always_new', generateNew: Boolean(options.generateNew) || stateFetchMode === 'always_new',
hostPreference: mergedState.icloudHostPreference, };
preferredHost: mergedState.preferredIcloudHost, if (mergedState.icloudHostPreference !== undefined) {
}); icloudOptions.hostPreference = mergedState.icloudHostPreference;
}
if (mergedState.preferredIcloudHost !== undefined) {
icloudOptions.preferredHost = mergedState.preferredIcloudHost;
}
return fetchIcloudHideMyEmail(icloudOptions);
} }
if (generator === 'cloudflare') { if (generator === 'cloudflare') {
return fetchCloudflareEmail(mergedState, options); return fetchCloudflareEmail(mergedState, options);
-1
View File
@@ -70,4 +70,3 @@
- 用户手动停止会中断当前计划;恢复时是否回到步骤 7,取决于当前页面状态与回调是否过期: - 用户手动停止会中断当前计划;恢复时是否回到步骤 7,取决于当前页面状态与回调是否过期:
- 回调未过期且仍在可恢复链路:优先当前链路继续; - 回调未过期且仍在可恢复链路:优先当前链路继续;
- 回调已过期或链路断裂:回步骤 7 重拉授权。 - 回调已过期或链路断裂:回步骤 7 重拉授权。
+208 -18
View File
@@ -162,6 +162,7 @@ const inputCodex2ApiAdminKey = document.getElementById('input-codex2api-admin-ke
const rowCustomPassword = document.getElementById('row-custom-password'); const rowCustomPassword = document.getElementById('row-custom-password');
const rowPlusMode = document.getElementById('row-plus-mode'); const rowPlusMode = document.getElementById('row-plus-mode');
const inputPlusModeEnabled = document.getElementById('input-plus-mode-enabled'); const inputPlusModeEnabled = document.getElementById('input-plus-mode-enabled');
const selectPlusPaymentMethod = document.getElementById('select-plus-payment-method');
const rowPayPalAccount = document.getElementById('row-paypal-account'); const rowPayPalAccount = document.getElementById('row-paypal-account');
const selectPayPalAccount = document.getElementById('select-paypal-account'); const selectPayPalAccount = document.getElementById('select-paypal-account');
const btnAddPayPalAccount = document.getElementById('btn-add-paypal-account'); const btnAddPayPalAccount = document.getElementById('btn-add-paypal-account');
@@ -291,6 +292,7 @@ const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('inpu
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled'); const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes'); const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds'); const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
const inputOAuthFlowTimeoutEnabled = document.getElementById('input-oauth-flow-timeout-enabled');
const inputVerificationResendCount = document.getElementById('input-verification-resend-count'); const inputVerificationResendCount = document.getElementById('input-verification-resend-count');
const rowPhoneVerificationEnabled = document.getElementById('row-phone-verification-enabled'); const rowPhoneVerificationEnabled = document.getElementById('row-phone-verification-enabled');
const btnTogglePhoneVerificationSection = document.getElementById('btn-toggle-phone-verification-section'); const btnTogglePhoneVerificationSection = document.getElementById('btn-toggle-phone-verification-section');
@@ -402,6 +404,7 @@ const btnAutoStartContinue = document.getElementById('btn-auto-start-continue');
const autoHintText = document.querySelector('.auto-hint'); const autoHintText = document.querySelector('.auto-hint');
const stepsList = document.querySelector('.steps-list'); const stepsList = document.querySelector('.steps-list');
let currentPlusModeEnabled = false; let currentPlusModeEnabled = false;
let currentPlusPaymentMethod = 'paypal';
let heroSmsCountrySelectionOrder = []; let heroSmsCountrySelectionOrder = [];
let phoneSmsProviderOrderSelection = []; let phoneSmsProviderOrderSelection = [];
let heroSmsCountryMenuSearchKeyword = ''; let heroSmsCountryMenuSearchKeyword = '';
@@ -417,7 +420,7 @@ const fiveSimCountrySearchTextByCode = new Map();
let nexSmsCountrySelectionOrder = []; let nexSmsCountrySelectionOrder = [];
let nexSmsCountryMenuSearchKeyword = ''; let nexSmsCountryMenuSearchKeyword = '';
const nexSmsCountrySearchTextById = new Map(); const nexSmsCountrySearchTextById = new Map();
let stepDefinitions = getStepDefinitionsForMode(false); let stepDefinitions = getStepDefinitionsForMode(false, currentPlusPaymentMethod);
let STEP_IDS = stepDefinitions.map((step) => Number(step.id)).filter(Number.isFinite); let STEP_IDS = stepDefinitions.map((step) => Number(step.id)).filter(Number.isFinite);
let STEP_DEFAULT_STATUSES = Object.fromEntries(STEP_IDS.map((stepId) => [stepId, 'pending'])); let STEP_DEFAULT_STATUSES = Object.fromEntries(STEP_IDS.map((stepId) => [stepId, 'pending']));
let SKIPPABLE_STEPS = new Set(STEP_IDS); let SKIPPABLE_STEPS = new Set(STEP_IDS);
@@ -538,8 +541,22 @@ const AUTO_RUN_PLUS_RISK_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-run-plus
const PLUS_CONTRIBUTION_PROMPT_LEDGER_STORAGE_KEY = 'multipage-plus-contribution-prompt-ledger'; const PLUS_CONTRIBUTION_PROMPT_LEDGER_STORAGE_KEY = 'multipage-plus-contribution-prompt-ledger';
const PHONE_VERIFICATION_SECTION_EXPANDED_STORAGE_KEY = 'multipage-phone-verification-section-expanded'; const PHONE_VERIFICATION_SECTION_EXPANDED_STORAGE_KEY = 'multipage-phone-verification-section-expanded';
function getStepDefinitionsForMode(plusModeEnabled = false) { function normalizePlusPaymentMethod(value = '') {
return (window.MultiPageStepDefinitions?.getSteps?.({ plusModeEnabled }) || []) return String(value || '').trim().toLowerCase() === 'gopay' ? 'gopay' : 'paypal';
}
function getSelectedPlusPaymentMethod() {
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
return normalizePlusPaymentMethod(selectPlusPaymentMethod.value);
}
return normalizePlusPaymentMethod(latestState?.plusPaymentMethod || currentPlusPaymentMethod);
}
function getStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethod = 'paypal') {
return (window.MultiPageStepDefinitions?.getSteps?.({
plusModeEnabled,
plusPaymentMethod: normalizePlusPaymentMethod(plusPaymentMethod),
}) || [])
.sort((left, right) => { .sort((left, right) => {
const leftOrder = Number.isFinite(left.order) ? left.order : left.id; const leftOrder = Number.isFinite(left.order) ? left.order : left.id;
const rightOrder = Number.isFinite(right.order) ? right.order : right.id; const rightOrder = Number.isFinite(right.order) ? right.order : right.id;
@@ -548,9 +565,10 @@ function getStepDefinitionsForMode(plusModeEnabled = false) {
}); });
} }
function rebuildStepDefinitionState(plusModeEnabled = false) { function rebuildStepDefinitionState(plusModeEnabled = false, plusPaymentMethod = 'paypal') {
currentPlusModeEnabled = Boolean(plusModeEnabled); currentPlusModeEnabled = Boolean(plusModeEnabled);
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled); currentPlusPaymentMethod = normalizePlusPaymentMethod(plusPaymentMethod);
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled, currentPlusPaymentMethod);
STEP_IDS = stepDefinitions.map((step) => Number(step.id)).filter(Number.isFinite); STEP_IDS = stepDefinitions.map((step) => Number(step.id)).filter(Number.isFinite);
STEP_DEFAULT_STATUSES = Object.fromEntries(STEP_IDS.map((stepId) => [stepId, 'pending'])); STEP_DEFAULT_STATUSES = Object.fromEntries(STEP_IDS.map((stepId) => [stepId, 'pending']));
SKIPPABLE_STEPS = new Set(STEP_IDS); SKIPPABLE_STEPS = new Set(STEP_IDS);
@@ -843,6 +861,8 @@ let cloudflareTempEmailDomainEditMode = false;
let modalChoiceResolver = null; let modalChoiceResolver = null;
let currentModalActions = []; let currentModalActions = [];
let modalResultBuilder = null; let modalResultBuilder = null;
let activePlusManualConfirmationRequestId = '';
let plusManualConfirmationDialogInFlight = false;
let scheduledCountdownTimer = null; let scheduledCountdownTimer = null;
let configMenuOpen = false; let configMenuOpen = false;
let configActionInFlight = false; let configActionInFlight = false;
@@ -1279,6 +1299,95 @@ async function openConfirmModalWithOption({
}; };
} }
async function openPlusManualConfirmationDialog(options = {}) {
const method = String(options.method || '').trim().toLowerCase();
const title = String(options.title || '').trim() || (method === 'gopay' ? 'GoPay 订阅确认' : '手动确认');
const message = String(options.message || '').trim()
|| (method === 'gopay'
? '请在当前订阅页中手动完成 GoPay 订阅,完成后点击“我已完成订阅”继续。'
: '请先在页面中完成当前手动操作,完成后点击确认继续。');
return openActionModal({
title,
message,
actions: [
{ id: 'cancel', label: '取消等待', variant: 'btn-ghost' },
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
],
alert: method === 'gopay'
? { text: '确认后流程会直接继续到 Plus 模式第 10 步 OAuth 登录。', tone: 'info' }
: null,
});
}
async function syncPlusManualConfirmationDialog() {
const requestId = String(latestState?.plusManualConfirmationRequestId || '').trim();
const pending = Boolean(latestState?.plusManualConfirmationPending);
if (!pending || !requestId || plusManualConfirmationDialogInFlight || activePlusManualConfirmationRequestId === requestId) {
return;
}
const step = Number(latestState?.plusManualConfirmationStep) || 0;
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
const title = latestState?.plusManualConfirmationTitle;
const message = latestState?.plusManualConfirmationMessage;
activePlusManualConfirmationRequestId = requestId;
plusManualConfirmationDialogInFlight = true;
let shouldReopenDialog = false;
try {
const choice = await openPlusManualConfirmationDialog({
method,
title,
message,
});
const currentRequestId = String(latestState?.plusManualConfirmationRequestId || '').trim();
const stillPending = Boolean(latestState?.plusManualConfirmationPending);
if (!stillPending || currentRequestId !== requestId) {
return;
}
if (choice == null) {
shouldReopenDialog = true;
showToast('当前订阅确认仍在等待中,将重新弹出确认窗口。', 'info', 1800);
return;
}
const confirmed = choice === 'confirm';
const response = await chrome.runtime.sendMessage({
type: 'RESOLVE_PLUS_MANUAL_CONFIRMATION',
source: 'sidepanel',
payload: {
step,
requestId,
confirmed,
},
});
if (response?.error) {
throw new Error(response.error);
}
if (confirmed) {
showToast(method === 'gopay' ? 'GoPay 订阅已确认,正在继续 OAuth 登录...' : '已确认,流程继续执行中...', 'info', 2200);
} else {
showToast(method === 'gopay' ? '已取消 GoPay 订阅等待。' : '已取消当前手动确认。', 'warn', 2200);
}
} catch (error) {
showToast(error?.message || String(error || '未知错误'), 'error');
} finally {
if (activePlusManualConfirmationRequestId === requestId) {
activePlusManualConfirmationRequestId = '';
}
plusManualConfirmationDialogInFlight = false;
if (
shouldReopenDialog
&& latestState?.plusManualConfirmationPending
&& String(latestState?.plusManualConfirmationRequestId || '').trim() === requestId
) {
setTimeout(() => {
void syncPlusManualConfirmationDialog();
}, 0);
}
}
}
function isPromptDismissed(storageKey) { function isPromptDismissed(storageKey) {
return localStorage.getItem(storageKey) === '1'; return localStorage.getItem(storageKey) === '1';
} }
@@ -2707,6 +2816,13 @@ function collectSettingsPayload() {
const currentPayPalAccount = typeof getCurrentPayPalAccount === 'function' const currentPayPalAccount = typeof getCurrentPayPalAccount === 'function'
? getCurrentPayPalAccount(latestState) ? getCurrentPayPalAccount(latestState)
: payPalAccounts.find((account) => account?.id === String(latestState?.currentPayPalAccountId || '').trim()) || null; : payPalAccounts.find((account) => account?.id === String(latestState?.currentPayPalAccountId || '').trim()) || null;
const plusPaymentMethod = typeof getSelectedPlusPaymentMethod === 'function'
? getSelectedPlusPaymentMethod()
: (String(
(typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod
? selectPlusPaymentMethod.value
: latestState?.plusPaymentMethod) || ''
).trim().toLowerCase() === 'gopay' ? 'gopay' : 'paypal');
return { return {
...(contributionModeEnabled ? {} : { ...(contributionModeEnabled ? {} : {
panelMode: selectPanelMode.value, panelMode: selectPanelMode.value,
@@ -2744,6 +2860,7 @@ function collectSettingsPayload() {
plusModeEnabled: typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled plusModeEnabled: typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
? Boolean(inputPlusModeEnabled.checked) ? Boolean(inputPlusModeEnabled.checked)
: Boolean(latestState?.plusModeEnabled), : Boolean(latestState?.plusModeEnabled),
plusPaymentMethod,
paypalEmail: String(currentPayPalAccount?.email || latestState?.paypalEmail || '').trim(), paypalEmail: String(currentPayPalAccount?.email || latestState?.paypalEmail || '').trim(),
paypalPassword: String(currentPayPalAccount?.password || latestState?.paypalPassword || ''), paypalPassword: String(currentPayPalAccount?.password || latestState?.paypalPassword || ''),
currentPayPalAccountId: String(latestState?.currentPayPalAccountId || '').trim(), currentPayPalAccountId: String(latestState?.currentPayPalAccountId || '').trim(),
@@ -2797,6 +2914,9 @@ function collectSettingsPayload() {
autoRunDelayEnabled: inputAutoDelayEnabled.checked, autoRunDelayEnabled: inputAutoDelayEnabled.checked,
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value), autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value), autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
oauthFlowTimeoutEnabled: typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled
? Boolean(inputOAuthFlowTimeoutEnabled.checked)
: true,
phoneVerificationEnabled: Boolean(inputPhoneVerificationEnabled?.checked), phoneVerificationEnabled: Boolean(inputPhoneVerificationEnabled?.checked),
phoneSmsProvider: phoneSmsProviderValue, phoneSmsProvider: phoneSmsProviderValue,
phoneSmsProviderOrder: phoneSmsProviderOrderValue, phoneSmsProviderOrder: phoneSmsProviderOrderValue,
@@ -6361,13 +6481,18 @@ function updatePlusModeUI() {
const enabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled const enabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
? Boolean(inputPlusModeEnabled.checked) ? Boolean(inputPlusModeEnabled.checked)
: false; : false;
const paymentMethod = getSelectedPlusPaymentMethod();
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
selectPlusPaymentMethod.value = paymentMethod;
selectPlusPaymentMethod.style.display = enabled ? '' : 'none';
}
[ [
typeof rowPayPalAccount !== 'undefined' ? rowPayPalAccount : null, typeof rowPayPalAccount !== 'undefined' ? rowPayPalAccount : null,
].forEach((row) => { ].forEach((row) => {
if (!row) { if (!row) {
return; return;
} }
row.style.display = enabled ? '' : 'none'; row.style.display = enabled && paymentMethod === 'paypal' ? '' : 'none';
}); });
} }
@@ -6435,10 +6560,10 @@ function scheduleSettingsAutoSave() {
} }
async function saveSettings(options = {}) { async function saveSettings(options = {}) {
const { silent = false } = options; const { silent = false, force = false } = options;
clearTimeout(settingsAutoSaveTimer); clearTimeout(settingsAutoSaveTimer);
if (!settingsDirty && !settingsSaveInFlight && silent) { if (!force && !settingsDirty && !settingsSaveInFlight && silent) {
return; return;
} }
@@ -6484,6 +6609,12 @@ async function saveSettings(options = {}) {
} }
} }
async function persistCurrentSettingsForAction() {
clearTimeout(settingsAutoSaveTimer);
await waitForSettingsSaveIdle();
await saveSettings({ silent: true, force: true });
}
function applyAutoRunStatus(payload = currentAutoRun) { function applyAutoRunStatus(payload = currentAutoRun) {
syncAutoRunState(payload); syncAutoRunState(payload);
const runLabel = getAutoRunLabel(currentAutoRun); const runLabel = getAutoRunLabel(currentAutoRun);
@@ -6494,7 +6625,13 @@ function applyAutoRunStatus(payload = currentAutoRun) {
setSettingsCardLocked(settingsCardLocked); setSettingsCardLocked(settingsCardLocked);
inputRunCount.disabled = currentAutoRun.autoRunning || shouldLockRunCountToEmailPool(); const lockedRunCount = getLockedRunCountFromEmailPool();
const shouldSyncAutoRunTotalRuns = currentAutoRun.autoRunning
|| locked
|| paused
|| scheduled;
inputRunCount.disabled = currentAutoRun.autoRunning || lockedRunCount > 0;
btnAutoRun.disabled = currentAutoRun.autoRunning; btnAutoRun.disabled = currentAutoRun.autoRunning;
btnFetchEmail.disabled = locked btnFetchEmail.disabled = locked
|| isCustomMailProvider() || isCustomMailProvider()
@@ -6502,7 +6639,9 @@ function applyAutoRunStatus(payload = currentAutoRun) {
inputEmail.disabled = locked; inputEmail.disabled = locked;
inputAutoSkipFailures.disabled = scheduled; inputAutoSkipFailures.disabled = scheduled;
if (currentAutoRun.totalRuns > 0) { if (lockedRunCount > 0) {
inputRunCount.value = String(lockedRunCount);
} else if (shouldSyncAutoRunTotalRuns && currentAutoRun.totalRuns > 0) {
inputRunCount.value = String(currentAutoRun.totalRuns); inputRunCount.value = String(currentAutoRun.totalRuns);
} }
@@ -6603,14 +6742,17 @@ function renderStepsList() {
updateButtonStates(); updateButtonStates();
} }
function syncStepDefinitionsForMode(plusModeEnabled = false, options = {}) { function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethod = 'paypal', options = {}) {
const nextPlusModeEnabled = Boolean(plusModeEnabled); const nextPlusModeEnabled = Boolean(plusModeEnabled);
const shouldRender = Boolean(options.render) || nextPlusModeEnabled !== currentPlusModeEnabled; const nextPlusPaymentMethod = normalizePlusPaymentMethod(plusPaymentMethod);
const shouldRender = Boolean(options.render)
|| nextPlusModeEnabled !== currentPlusModeEnabled
|| nextPlusPaymentMethod !== currentPlusPaymentMethod;
if (!shouldRender) { if (!shouldRender) {
return; return;
} }
rebuildStepDefinitionState(nextPlusModeEnabled); rebuildStepDefinitionState(nextPlusModeEnabled, nextPlusPaymentMethod);
renderStepsList(); renderStepsList();
} }
@@ -6620,7 +6762,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
function applySettingsState(state) { function applySettingsState(state) {
if (typeof syncStepDefinitionsForMode === 'function') { if (typeof syncStepDefinitionsForMode === 'function') {
syncStepDefinitionsForMode(Boolean(state?.plusModeEnabled)); syncStepDefinitionsForMode(Boolean(state?.plusModeEnabled), state?.plusPaymentMethod);
} }
const fallbackIpProxyService = '711proxy'; const fallbackIpProxyService = '711proxy';
const fallbackIpProxyMode = 'account'; const fallbackIpProxyMode = 'account';
@@ -6677,6 +6819,9 @@ function applySettingsState(state) {
if (typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled) { if (typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled) {
inputPlusModeEnabled.checked = Boolean(state?.plusModeEnabled); inputPlusModeEnabled.checked = Boolean(state?.plusModeEnabled);
} }
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(state?.plusPaymentMethod);
}
inputVpsUrl.value = state?.vpsUrl || ''; inputVpsUrl.value = state?.vpsUrl || '';
inputVpsPassword.value = state?.vpsPassword || ''; inputVpsPassword.value = state?.vpsPassword || '';
setLocalCpaStep9Mode(state?.localCpaStep9Mode); setLocalCpaStep9Mode(state?.localCpaStep9Mode);
@@ -6853,6 +6998,11 @@ function applySettingsState(state) {
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled); inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes)); inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds); inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
if (typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) {
inputOAuthFlowTimeoutEnabled.checked = state?.oauthFlowTimeoutEnabled !== undefined
? Boolean(state.oauthFlowTimeoutEnabled)
: true;
}
if (inputVerificationResendCount) { if (inputVerificationResendCount) {
const restoredVerificationResendCount = state?.verificationResendCount !== undefined const restoredVerificationResendCount = state?.verificationResendCount !== undefined
? state.verificationResendCount ? state.verificationResendCount
@@ -6950,7 +7100,12 @@ function applySettingsState(state) {
if (normalized === 'nexsms') return 'nexsms'; if (normalized === 'nexsms') return 'nexsms';
return 'hero-sms'; return 'hero-sms';
}); });
const providerOrderForRestore = resolveNormalizedProviderOrderForRuntime(state || {}); const providerOrderForRestore = typeof resolveNormalizedProviderOrderForRuntime === 'function'
? resolveNormalizedProviderOrderForRuntime(state || {})
: [normalizeProvider(
state?.phoneSmsProvider
|| (typeof DEFAULT_PHONE_SMS_PROVIDER !== 'undefined' ? DEFAULT_PHONE_SMS_PROVIDER : 'hero-sms')
)];
const activeProvider = providerOrderForRestore[0] || normalizeProvider( const activeProvider = providerOrderForRestore[0] || normalizeProvider(
state?.phoneSmsProvider state?.phoneSmsProvider
|| (typeof DEFAULT_PHONE_SMS_PROVIDER !== 'undefined' ? DEFAULT_PHONE_SMS_PROVIDER : 'hero-sms') || (typeof DEFAULT_PHONE_SMS_PROVIDER !== 'undefined' ? DEFAULT_PHONE_SMS_PROVIDER : 'hero-sms')
@@ -7028,6 +7183,9 @@ function applySettingsState(state) {
queueLuckmailPurchaseRefresh(); queueLuckmailPurchaseRefresh();
} }
updateButtonStates(); updateButtonStates();
if (typeof syncPlusManualConfirmationDialog === 'function') {
void syncPlusManualConfirmationDialog();
}
} }
async function restoreState() { async function restoreState() {
@@ -9122,6 +9280,7 @@ stepsList?.addEventListener('click', async (event) => {
if (!(await maybeTakeoverAutoRun(`执行步骤 ${step}`))) { if (!(await maybeTakeoverAutoRun(`执行步骤 ${step}`))) {
return; return;
} }
await persistCurrentSettingsForAction();
if (step === 3) { if (step === 3) {
if (inputPassword.value !== (latestState?.customPassword || '')) { if (inputPassword.value !== (latestState?.customPassword || '')) {
await chrome.runtime.sendMessage({ await chrome.runtime.sendMessage({
@@ -9363,8 +9522,8 @@ async function startAutoRunFromCurrentSettings() {
console.warn('Failed to refresh contribution content hint before auto run:', error); console.warn('Failed to refresh contribution content hint before auto run:', error);
} }
if (typeof settingsDirty !== 'undefined' && settingsDirty && typeof saveSettings === 'function') { if (typeof persistCurrentSettingsForAction === 'function') {
await saveSettings({ silent: true }); await persistCurrentSettingsForAction();
} }
const customEmailPoolEnabled = typeof usesCustomEmailPoolGenerator === 'function' const customEmailPoolEnabled = typeof usesCustomEmailPoolGenerator === 'function'
@@ -9646,7 +9805,15 @@ inputPassword.addEventListener('blur', () => {
inputPlusModeEnabled?.addEventListener('change', () => { inputPlusModeEnabled?.addEventListener('change', () => {
updatePlusModeUI(); updatePlusModeUI();
syncStepDefinitionsForMode(Boolean(inputPlusModeEnabled.checked), { render: true }); syncStepDefinitionsForMode(Boolean(inputPlusModeEnabled.checked), getSelectedPlusPaymentMethod(), { render: true });
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
selectPlusPaymentMethod?.addEventListener('change', () => {
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(selectPlusPaymentMethod.value);
updatePlusModeUI();
syncStepDefinitionsForMode(Boolean(inputPlusModeEnabled?.checked), selectPlusPaymentMethod.value, { render: true });
markSettingsDirty(true); markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { }); saveSettings({ silent: true }).catch(() => { });
}); });
@@ -10504,6 +10671,11 @@ inputAutoDelayMinutes.addEventListener('blur', () => {
saveSettings({ silent: true }).catch(() => { }); saveSettings({ silent: true }).catch(() => { });
}); });
inputOAuthFlowTimeoutEnabled?.addEventListener('change', () => {
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
inputPhoneVerificationEnabled?.addEventListener('change', () => { inputPhoneVerificationEnabled?.addEventListener('change', () => {
if (inputPhoneVerificationEnabled.checked) { if (inputPhoneVerificationEnabled.checked) {
setPhoneVerificationSectionExpanded(true); setPhoneVerificationSectionExpanded(true);
@@ -11224,6 +11396,20 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
) { ) {
updateMailProviderUI(); updateMailProviderUI();
} }
if (message.payload.plusModeEnabled !== undefined && inputPlusModeEnabled) {
inputPlusModeEnabled.checked = Boolean(message.payload.plusModeEnabled);
}
if (message.payload.plusPaymentMethod !== undefined && selectPlusPaymentMethod) {
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(message.payload.plusPaymentMethod);
}
if (message.payload.plusModeEnabled !== undefined || message.payload.plusPaymentMethod !== undefined) {
syncStepDefinitionsForMode(
Boolean(latestState?.plusModeEnabled),
latestState?.plusPaymentMethod,
{ render: true }
);
updatePlusModeUI();
}
if (message.payload.currentHotmailAccountId !== undefined || message.payload.hotmailAccounts !== undefined) { if (message.payload.currentHotmailAccountId !== undefined || message.payload.hotmailAccounts !== undefined) {
renderHotmailAccounts(); renderHotmailAccounts();
if (selectMailProvider.value === 'hotmail-api') { if (selectMailProvider.value === 'hotmail-api') {
@@ -11303,6 +11489,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.payload.autoStepDelaySeconds !== undefined) { if (message.payload.autoStepDelaySeconds !== undefined) {
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(message.payload.autoStepDelaySeconds); inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(message.payload.autoStepDelaySeconds);
} }
if (message.payload.oauthFlowTimeoutEnabled !== undefined && typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) {
inputOAuthFlowTimeoutEnabled.checked = Boolean(message.payload.oauthFlowTimeoutEnabled);
}
if ( if (
( (
message.payload.verificationResendCount !== undefined message.payload.verificationResendCount !== undefined
@@ -11509,6 +11698,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
} }
updateAccountRunHistorySettingsUI(); updateAccountRunHistorySettingsUI();
renderContributionMode(); renderContributionMode();
void syncPlusManualConfirmationDialog();
break; break;
} }
+168
View File
@@ -0,0 +1,168 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const sidepanelSource = fs.readFileSync('sidepanel/sidepanel.js', 'utf8');
function extractFunction(name) {
const asyncStart = sidepanelSource.indexOf(`async function ${name}`);
const normalStart = sidepanelSource.indexOf(`function ${name}`);
const start = asyncStart !== -1
? asyncStart
: normalStart;
if (start === -1) {
throw new Error(`Function ${name} not found`);
}
const signatureEnd = sidepanelSource.indexOf(')', start);
const bodyStart = sidepanelSource.indexOf('{', signatureEnd);
let depth = 0;
let end = bodyStart;
for (; end < sidepanelSource.length; end += 1) {
const char = sidepanelSource[end];
if (char === '{') {
depth += 1;
} else if (char === '}') {
depth -= 1;
if (depth === 0) {
end += 1;
break;
}
}
}
return sidepanelSource.slice(start, end);
}
test('sidepanel step definitions keep the selected Plus payment method', () => {
const bundle = [
extractFunction('normalizePlusPaymentMethod'),
extractFunction('getStepDefinitionsForMode'),
extractFunction('rebuildStepDefinitionState'),
extractFunction('syncStepDefinitionsForMode'),
].join('\n');
const api = new Function(`
const calls = [];
const window = {
MultiPageStepDefinitions: {
getSteps(options) {
calls.push({ type: 'getSteps', options });
return [{ id: options.plusPaymentMethod === 'gopay' ? 7 : 6, order: 1 }];
},
},
};
let currentPlusModeEnabled = false;
let currentPlusPaymentMethod = 'paypal';
let stepDefinitions = [];
let STEP_IDS = [];
let STEP_DEFAULT_STATUSES = {};
let SKIPPABLE_STEPS = new Set();
function renderStepsList() {
calls.push({ type: 'render', stepIds: [...STEP_IDS] });
}
${bundle}
return {
calls,
syncStepDefinitionsForMode,
getCurrentPlusPaymentMethod: () => currentPlusPaymentMethod,
getStepIds: () => [...STEP_IDS],
};
`)();
api.syncStepDefinitionsForMode(true, 'gopay', { render: true });
assert.equal(api.getCurrentPlusPaymentMethod(), 'gopay');
assert.deepEqual(api.getStepIds(), [7]);
assert.deepEqual(api.calls[0], {
type: 'getSteps',
options: { plusModeEnabled: true, plusPaymentMethod: 'gopay' },
});
assert.deepEqual(api.calls[1], { type: 'render', stepIds: [7] });
});
test('sidepanel Plus UI hides PayPal account selector while GoPay is selected', () => {
const bundle = [
extractFunction('normalizePlusPaymentMethod'),
extractFunction('getSelectedPlusPaymentMethod'),
extractFunction('updatePlusModeUI'),
].join('\n');
const api = new Function(`
let latestState = { plusPaymentMethod: 'gopay' };
let currentPlusPaymentMethod = 'paypal';
const inputPlusModeEnabled = { checked: true };
const selectPlusPaymentMethod = { value: 'gopay', style: { display: 'none' } };
const rowPayPalAccount = { style: { display: '' } };
${bundle}
return { updatePlusModeUI, selectPlusPaymentMethod, rowPayPalAccount };
`)();
api.updatePlusModeUI();
assert.equal(api.selectPlusPaymentMethod.style.display, '');
assert.equal(api.rowPayPalAccount.style.display, 'none');
api.selectPlusPaymentMethod.value = 'paypal';
api.updatePlusModeUI();
assert.equal(api.rowPayPalAccount.style.display, '');
});
test('sidepanel resolves pending GoPay manual confirmation from DATA_UPDATED state', async () => {
const bundle = [
extractFunction('openPlusManualConfirmationDialog'),
extractFunction('syncPlusManualConfirmationDialog'),
].join('\n');
const api = new Function(`
const events = [];
let latestState = {
plusManualConfirmationPending: true,
plusManualConfirmationRequestId: 'gopay-request-1',
plusManualConfirmationStep: 7,
plusManualConfirmationMethod: 'gopay',
plusManualConfirmationTitle: 'GoPay 订阅确认',
plusManualConfirmationMessage: '请确认订阅。',
};
let activePlusManualConfirmationRequestId = '';
let plusManualConfirmationDialogInFlight = false;
function openActionModal(options) {
events.push({ type: 'modal', options });
return Promise.resolve('confirm');
}
function showToast(message, tone) {
events.push({ type: 'toast', message, tone });
}
const chrome = {
runtime: {
async sendMessage(message) {
events.push({ type: 'send', message });
latestState = {
...latestState,
plusManualConfirmationPending: false,
};
return { ok: true };
},
},
};
${bundle}
return { events, syncPlusManualConfirmationDialog };
`)();
await api.syncPlusManualConfirmationDialog();
assert.equal(api.events[0].type, 'modal');
assert.equal(api.events[0].options.title, 'GoPay 订阅确认');
assert.deepEqual(api.events[1], {
type: 'send',
message: {
type: 'RESOLVE_PLUS_MANUAL_CONFIRMATION',
source: 'sidepanel',
payload: {
step: 7,
requestId: 'gopay-request-1',
confirmed: true,
},
},
});
assert.match(api.events[2].message, /GoPay/);
assert.equal(api.events[2].tone, 'info');
});