# supportcandy/trunk/includes/admin/onboarding/onboarding.js

SupportCandy – AI Customer Support Ticket System &amp; Live Chatbot Agent, version trunk. 235 lines.

- Page: https://pluginprobe.com/plugins/supportcandy/trunk/code/includes/admin/onboarding/onboarding.js
- Raw: https://pluginprobe.com/plugins/supportcandy/trunk/raw/includes/admin/onboarding/onboarding.js
- Modified: 2026-09-29T05:00:44+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/supportcandy/trunk/code/includes/admin/onboarding/onboarding.js#L10-L20`.

```javascript
/**
 * Setup wizard - step navigation and actions.
 * Follows the same AJAX fragment-loading pattern used throughout wp-admin.js.
 */

/**
 * Load a wizard step's body via AJAX and reflect it in the progress nav.
 */
function wpsc_onboarding_load_step(stepId) {
  jQuery(".wpsc-onboarding-step-nav").removeClass("active");
  jQuery(".wpsc-onboarding-step-nav." + stepId).addClass("active");

  window.history.replaceState(
    {},
    null,
    "admin.php?page=wpsc-onboarding&step=" + stepId
  );

  jQuery(".wpsc-onboarding-body").html(supportcandy.loader_html);
  wpsc_scroll_top();

  var data = { action: "wpsc_get_onboarding_step", step: stepId };
  jQuery.post(supportcandy.ajax_url, data, function (response) {
    jQuery(".wpsc-onboarding-body").html(response);
    wpsc_reset_responsive_style();
  });
}

/**
 * Move to the next step in order, or leave the wizard if this was the last one.
 */
function wpsc_onboarding_next_step(currentStepId) {
  var steps = supportcandy.onboarding_steps || [];
  var idx = steps.indexOf(currentStepId);
  if (idx > -1 && idx < steps.length - 1) {
    wpsc_onboarding_load_step(steps[idx + 1]);
  } else {
    window.location.href = "admin.php?page=wpsc-tickets";
  }
}

/**
 * Reflect a step's completed state in the progress nav without a reload.
 */
function wpsc_onboarding_mark_step(stepId, status) {
  jQuery(".wpsc-onboarding-step-nav." + stepId)
    .removeClass("pending completed")
    .addClass(status);
}

/**
 * Mark a step complete and move on. Setup must be completed, so a step can
 * only be marked done, never skipped - the server enforces the same rule
 * (e.g. the Support Page requirement on step 1) regardless of what the UI did.
 *
 * The progress nav (see wpsc_onboarding_load_step) lets an admin jump straight
 * to any step, so this can be rejected because an earlier step was never
 * completed - the server then sends back which step to go complete first
 * (redirect_step). Not every step has a ".wpsc-onboarding-inline-message" in
 * its markup to show that in, so this is surfaced with an alert instead and
 * the admin is sent back to that step.
 */
function wpsc_onboarding_complete_step(stepId, nonce) {
  var data = { action: "wpsc_onboarding_complete_step", step: stepId, _ajax_nonce: nonce };
  jQuery
    .post(supportcandy.ajax_url, data, function () {
      wpsc_onboarding_mark_step(stepId, "completed");
      wpsc_onboarding_next_step(stepId);
    })
    .fail(function (xhr) {
      var msg = supportcandy.translations.something_wrong;
      var redirectStep = null;
      try {
        var res = JSON.parse(xhr.responseText);
        if (res && res.data) {
          msg = typeof res.data === "string" ? res.data : res.data.message || msg;
          redirectStep = res.data && res.data.redirect_step ? res.data.redirect_step : null;
        }
      } catch (e) {
        // ignore - fall back to generic message.
      }
      if (redirectStep) {
        alert(msg);
        wpsc_onboarding_load_step(redirectStep);
      } else {
        jQuery(".wpsc-onboarding-inline-message").text(msg).addClass("error");
      }
    });
}

/**
 * Step 1: create the Support/Open Ticket page in one click, then reload the step.
 */
function wpsc_onboarding_create_page(type, el, nonce) {
  jQuery(el).text(supportcandy.translations.please_wait);
  var data = { action: "wpsc_onboarding_create_page", type: type, _ajax_nonce: nonce };
  jQuery.post(supportcandy.ajax_url, data, function () {
    wpsc_onboarding_load_step("support-pages");
  });
}

/**
 * Step 1: the Support Page is required - block Continue and show a notice
 * until it's been created, then save guest-ticket / OTP settings and mark
 * the step complete.
 */
function wpsc_onboarding_save_pages_step(el, completeNonce) {
  var configured = jQuery(".wpsc-onboarding-support-page-configured").val() === "1";
  if (!configured) {
    jQuery(".wpsc-onboarding-support-page-notice").show();
    return;
  }
  jQuery(".wpsc-onboarding-support-page-notice").hide();

  var form = jQuery(".wpsc-frm-onboarding-ticket-access")[0];
  var dataform = new FormData(form);
  jQuery(el).text(supportcandy.translations.please_wait);
  jQuery
    .ajax({
      url: supportcandy.ajax_url,
      type: "POST",
      data: dataform,
      processData: false,
      contentType: false,
    })
    .done(function () {
      wpsc_onboarding_complete_step("support-pages", completeNonce);
    });
}

/**
 * Step 2: save the AI provider/API key via the existing save endpoint, then
 * reload the step to reflect the new connected/error state.
 */
function wpsc_onboarding_save_ai(el) {
  var $btn = jQuery(el);
  var originalText = $btn.text();
  var form = jQuery(".wpsc-frm-onboarding-ai")[0];
  var dataform = new FormData(form);

  jQuery(".wpsc-onboarding-inline-message").text("").removeClass("error");
  $btn.prop("disabled", true).text(supportcandy.translations.please_wait);

  jQuery
    .ajax({
      url: supportcandy.ajax_url,
      type: "POST",
      data: dataform,
      processData: false,
      contentType: false,
    })
    .done(function () {
      wpsc_onboarding_load_step("ai-assistant");
    })
    .fail(function (xhr) {
      var msg = supportcandy.translations.something_wrong;
      try {
        var res = JSON.parse(xhr.responseText);
        if (res && res.data) {
          msg = typeof res.data === "string" ? res.data : res.data.message || msg;
        }
      } catch (e) {
        // ignore - fall back to generic message.
      }
      jQuery(".wpsc-onboarding-inline-message").text(msg).addClass("error");
      $btn.prop("disabled", false).text(originalText);
    });
}

/**
 * Step 3: add a category via the existing save endpoint, then reload the step.
 */
function wpsc_onboarding_add_category(el, nonce) {
  var input = jQuery(".wpsc-frm-onboarding-add-category input[name='label']");
  var label = input.val().trim();
  if (!label) {
    return;
  }

  jQuery(el).prop("disabled", true).text(supportcandy.translations.please_wait);
  var data = { action: "wpsc_set_add_category", label: label, _ajax_nonce: nonce };
  jQuery.post(supportcandy.ajax_url, data, function () {
    wpsc_onboarding_load_step("categories");
  });
}

/**
 * Step 7: save From Name / From Email onto the existing email-notifications
 * general settings (merged there server-side, not overwritten - including its
 * From Name / From Email required + valid-email validation), then mark the
 * step complete.
 */
function wpsc_onboarding_save_email_step(el, completeNonce) {
  var $btn = jQuery(el);
  var originalText = $btn.text();
  var form = jQuery(".wpsc-frm-onboarding-email-general")[0];

  // The fields are marked required/type="email" in markup - reportValidity()
  // surfaces the browser's native bubble for those before we even hit the
  // server, which still re-checks everything itself regardless.
  if (!form.reportValidity()) {
    return;
  }

  var dataform = new FormData(form);

  jQuery(".wpsc-onboarding-inline-message").text("").removeClass("error");
  $btn.prop("disabled", true).text(supportcandy.translations.please_wait);

  jQuery
    .ajax({
      url: supportcandy.ajax_url,
      type: "POST",
      data: dataform,
      processData: false,
      contentType: false,
    })
    .done(function () {
      wpsc_onboarding_complete_step("emails", completeNonce);
    })
    .fail(function (xhr) {
      var msg = supportcandy.translations.something_wrong;
      try {
        var res = JSON.parse(xhr.responseText);
        if (res && res.data) {
          msg = typeof res.data === "string" ? res.data : res.data.message || msg;
        }
      } catch (e) {
        // ignore - fall back to generic message.
      }
      jQuery(".wpsc-onboarding-inline-message").text(msg).addClass("error");
      $btn.prop("disabled", false).text(originalText);
    });
}

```
