Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 238 additions & 50 deletions assets/js/template-switching.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,43 @@
template_category: '',
stored_templates: {},
confirm_switch: 0,

/*
* Drives visibility of the confirm panel. Set true when
* the customer picks a grid template (template_id watcher
* below) or clicks Reset (reset_template). Set false on
* Cancel and after a successful switch. We track this
* explicitly rather than deriving it from
* (template_id !== original_template_id) because the
* Reset flow needs the panel to appear *while*
* template_id equals original_template_id, which a
* derived check could not express.
*/
confirm_active: false,
ready: false,

/*
* Inline error surface for the confirm panel.
*
* The legacy error path called wu_ajax_error() which
* either shows a SweetAlert modal (when Swal is loaded
* — it isn't on customer-panel pages) or prepends a
* dismissible notice to the very top of #wpbody-content.
* In the customer panel the confirm panel sits well
* below the fold on the typical viewport, so a notice
* placed at the top of the page is invisible to a
* customer who has just clicked "Switch to X". They
* see the spinner clear, the panel close, and nothing
* else — looking like the action silently failed.
*
* Setting this string surfaces the error inline inside
* the confirm panel itself (see views/ui/template-
* switching-confirm.php), right where the customer's
* eye is. We keep the wu_ajax_error() call too for
* users who scroll up, plus belt-and-braces for the
* (rare) case where the panel itself fails to render.
*/
error_message: '',
};

},
Expand Down Expand Up @@ -80,6 +116,85 @@
} // end if;

},

/*
* Surface the confirm panel when the customer clicks a Select
* button in the grid. Grid buttons live inside the shared
* checkout/template-selection clean.php view (which we don't
* edit because signup uses it too); they only set
* template_id. Watching that change lets us inject the
* confirm_active = true behaviour without touching the
* shared view.
*
* Guard: don't flip confirm_active on the initial v-init
* assignment (which sets template_id = original_template_id
* before the page is interactive). Picking the customer's
* existing template from the grid is also a no-op — there's
* nothing to confirm.
*/
template_id(new_value, old_value) {

if (old_value === undefined) {

return;

} // end if;

if (new_value === 0 || new_value === '0') {

this.confirm_active = false;
return;

} // end if;

/*
* Defence in depth against directive-ordering races on
* mount. The element output co-locates
* v-init:original_template_id and v-init:template_id on
* the same hidden field, but if anything ever causes the
* template_id directive to bind first (Vue plugin order,
* future markup change, third-party Vue mixin, etc.) we
* would otherwise reach the `confirm_active = true`
* branch below with original_template_id still at its
* data() sentinel of -1. -1 is a value that no real
* template can have, so we treat it as "not yet
* initialised" and bail out — the watcher will fire
* again on the next legitimate template change.
*/
// eslint-disable-next-line eqeqeq
if (this.original_template_id == -1 || this.original_template_id <= 0) {

return;

} // end if;
Comment on lines +165 to +169
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't suppress the confirm flow for first-time template application.

When a site has no current template, original_template_id is 0. This guard returns before confirm_active is set, so picking a template never opens the new confirm panel and there is no way to reach switch_template() for that path. The earlier new_value === 0 branch already covers the initial mount case, so the <= 0 check is too broad here.

💡 Suggested fix
-					if (this.original_template_id == -1 || this.original_template_id <= 0) {
+					if (this.original_template_id == -1) {
 
 						return;
 
 					} // end if;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/js/template-switching.js` around lines 165 - 169, The if guard is
suppressing the confirm flow for first-time template application because it
returns when original_template_id <= 0; change the condition to only detect the
uninitialized sentinel (original_template_id == -1) so that original_template_id
=== 0 will continue and allow confirm_active to be set and switch_template() to
run; update the if from "original_template_id == -1 || original_template_id <=
0" to just "original_template_id == -1" (or equivalent) so the new_value === 0
mount case is still handled.


// eslint-disable-next-line eqeqeq
if (new_value == this.original_template_id) {

// Picking the current template from the grid is a
// no-op; reset_template() handles the deliberate
// "Reset" path and will set confirm_active = true
// itself.
return;

} // end if;

/*
* Clear any error message left over from a previous
* failed switch attempt. If the customer picks a
* different template after seeing an error, they are
* starting a new attempt and the stale message would
* be misleading.
*/
if (this.error_message) {

this.error_message = '';

} // end if;

this.confirm_active = true;

},
},
methods: {
get_template(template, data) {
Expand Down Expand Up @@ -141,55 +256,142 @@

},
/**
* Re-apply the customer's current template, refreshing
* the site from the source template. Triggered by the
* "Reset current template" link in the form.
* Show the confirm panel for re-applying the customer's
* current template. Triggered by the "Reset Current
* Template" button in the current-template card.
*
* Confirms with the customer first because this overwrites
* the site's content. Confirmation text is supplied via
* wu_template_switching_params.i18n.reset_confirm so it
* is translatable.
* Previously this used a native confirm() popup and fired
* the switch immediately. The new flow surfaces the same
* confirmation card used for switching to a different
* template — the customer sees the target thumbnail, name,
* and disclaimer before clicking Confirm. Pairing reset
* and switch under the same confirmation UI makes the
* "you are about to overwrite your site" warning feel
* consistent regardless of which path got the customer
* here.
*
* Setting ready = true triggers the existing watcher which
* calls switch_template() — the same code path used by the
* normal "Process Switch" button.
* The actual switch is then triggered from the Confirm
* button inside the panel (which sets ready = true,
* matching the grid switch flow).
*/
reset_template() {

const params = window.wu_template_switching_params || {};
const message = (params.i18n && params.i18n.reset_confirm)
? params.i18n.reset_confirm
: 'Re-apply your current template? This will overwrite your site content with a fresh copy of the template. This cannot be undone.';

// Native confirm() matches the existing pattern used elsewhere
// in this codebase (edit-placeholders.js, tax-rates.js, dns-management.js)
// for destructive customer-facing actions. Avoiding the no-alert
// rule would mean introducing modal infrastructure that does not
// yet exist on this page.
// eslint-disable-next-line no-alert
if ( ! window.confirm(message)) {
if ( ! this.original_template_id || this.original_template_id <= 0) {

return;

} // end if;

if ( ! this.original_template_id || this.original_template_id <= 0) {
this.template_id = this.original_template_id;
this.confirm_active = true;

Comment on lines 277 to 287
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear stale inline errors when opening the reset flow.

After a failed switch attempt, clicking Reset Current Template keeps the previous error_message because the watcher intentionally no-ops when template_id == original_template_id. That makes the reset panel render with an unrelated old error before the user retries.

💡 Suggested fix
 				reset_template() {
 
 					if ( ! this.original_template_id || this.original_template_id <= 0) {
 
 						return;
 
 					} // end if;
 
+					this.error_message  = '';
 					this.template_id     = this.original_template_id;
 					this.confirm_active  = true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/js/template-switching.js` around lines 277 - 287, The reset_template()
flow leaves a stale error_message showing because the watcher short-circuits
when template_id == original_template_id; update reset_template() (the
reset_template method) to clear any existing inline error state (e.g., set
error_message = '' or null and any related error flags) before or immediately
after restoring this.template_id = this.original_template_id so the reset panel
does not render a previous error; keep existing confirm_active behavior
unchanged.

return;
/*
* Scroll the confirm panel into view. The current-
* template card and the panel can both fit on screen
* together for most viewports, but on shorter windows
* the panel renders below the fold; without this
* scroll, customers reported clicking Reset and seeing
* "nothing happen" until they scrolled.
*/
this.$nextTick(() => {

} // end if;
const panel = document.querySelector('.wu-template-switching-confirm');

this.template_id = this.original_template_id;
if (panel && typeof panel.scrollIntoView === 'function') {

this.confirm_switch = true;
panel.scrollIntoView({ behavior: 'smooth', block: 'center' });

this.ready = true;
} // end if;

});

},

/**
* Dismiss the confirm panel without performing a switch.
* Resets the queued template selection back to the
* customer's active template so the grid no longer shows
* a "Selected" highlight on a template they decided not
* to switch to.
*/
cancel_switch() {

this.confirm_active = false;
this.template_id = this.original_template_id;
this.error_message = '';

},

/**
* Surface an AJAX failure inline in the confirm panel and
* also via the global wu_ajax_error() toast/notice.
*
* Keeping the confirm panel open (confirm_active stays
* true) is deliberate: the previous behaviour closed the
* panel on failure and let wu_ajax_error() prepend a
* notice to the top of #wpbody-content. On the customer
* panel that notice is far above the fold from where the
* customer just clicked Confirm, so they saw nothing —
* the spinner cleared, the panel disappeared, and the
* action looked like a silent no-op. Now the error renders
* directly inside the panel where the click happened.
*
* @param {string|null} message Human-readable failure
* reason. Pass null to delegate copy to wu_ajax_error
* (used for network errors where we do not have a
* server-supplied string).
*/
show_error(message) {

this.unblock();
this.confirm_switch = false;
this.ready = false;

/*
* Keep confirm_active true so the panel — which now
* carries the inline error block — stays visible.
*/
this.confirm_active = true;

this.error_message = message || 'An error occurred while switching templates.';

/*
* Belt-and-braces: also show the global notice in case
* the panel itself fails to render (e.g. third-party
* JS error breaks the Vue update).
*/
wu_ajax_error(message);

/*
* Bring the panel into view if the customer scrolled
* away or it was rendered below the fold. Without
* this, an inline error placed below the visible
* region would still go unnoticed.
*/
this.$nextTick(() => {

const panel = document.querySelector('.wu-template-switching-confirm');

if (panel && typeof panel.scrollIntoView === 'function') {

panel.scrollIntoView({ behavior: 'smooth', block: 'center' });

} // end if;

});

},
switch_template() {

const that = this;

/*
* Clear any error from a previous attempt so the
* panel does not show a stale message while the new
* request is in flight.
*/
that.error_message = '';

that.block();

this.request('wu_switch_template', {
Expand All @@ -205,13 +407,7 @@
*/
if ( ! results || typeof results !== 'object') {

that.unblock();

that.confirm_switch = false;

that.ready = false;

wu_ajax_error('An error occurred while switching templates.');
that.show_error('An error occurred while switching templates.');

return;

Expand All @@ -222,12 +418,6 @@
*/
if (results.success === false) {

that.unblock();

that.confirm_switch = false;

that.ready = false;

let errorMessage = 'An error occurred while switching templates.';

if (results.data && results.data.message) {
Expand All @@ -240,7 +430,7 @@

}

wu_ajax_error(errorMessage);
that.show_error(errorMessage);

return;

Expand Down Expand Up @@ -269,21 +459,19 @@
that.unblock();

that.confirm_switch = false;
that.confirm_active = false;

that.ready = false;

}, function() {

/*
* Handle network errors.
* Handle network errors. wu_ajax_error(null) lets that
* helper fill in its own "network error" copy; mirror it
* inline in the panel so the customer sees the same
* information without scrolling.
*/
that.unblock();

that.confirm_switch = false;

that.ready = false;

wu_ajax_error(null);
that.show_error('A network error occurred. Please check your connection and try again.');

});

Expand Down
2 changes: 1 addition & 1 deletion assets/js/template-switching.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading