ƏMAS step: surface failure reason on intro, clearer 'cached' state
Symptom: after the second phone tap the wizard appeared to drop the
user back to the ƏMAS intro screen with no indication of what
happened — they couldn't tell if employees had been cached, the
import had run, or anything had failed.
Root cause was a UX bug in the JS layer: every error path in the
ƏMAS sub-flow (connect_amas, change_amas_account, get_employees_
report, cache_selected_employees) did
this.$wrap.find(".jey-status").text(error_message);
this.amas_state = "intro";
this.show_current_step();
but show_current_step() unconditionally calls .jey-status.empty()
at the top of the render, so the message was wiped before the user
could read it. They saw a clean intro screen and assumed nothing
ran or that it silently succeeded.
Fix:
- New persistent fields data.amas_last_error / data.asan_last_error
that survive show_current_step re-renders. Every ƏMAS error path
now writes to data.amas_last_error before flipping state.
- intro renderer reads data.amas_last_error and shows a red
"Previous attempt failed: <message>" banner above the usual
copy when set. amas_start_auth clears it on retry.
- Added .error callbacks to the four frappe.call sites that didn't
have one — network errors used to drop the user to intro with no
message at all.
Also rewrote the success "done" screen so it can't be misread:
heading is now "Cached and ready", body explicitly says "Cached on
the server. Actual import into Employee / ƏMAS Employees runs as a
background job right after you click Finish — you can keep working
in /app while it runs." Same data, just unmistakable.
This commit is contained in:
parent
29f277a7bf
commit
8c178524d9
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.21"
|
||||
__version__ = "0.1.22"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ frappe.provide("jey_wizard");
|
|||
// Bump this string in every commit that changes wizard code. Displayed in the badge so
|
||||
// we can tell at a glance which version is actually running on a given machine. Kept in
|
||||
// sync with __version__ in jey_wizard/__init__.py.
|
||||
const JEY_WIZARD_VERSION = "0.1.21";
|
||||
const JEY_WIZARD_VERSION = "0.1.22";
|
||||
|
||||
// Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners
|
||||
// don't try to mutate a wizard that isn't slide-based anymore.
|
||||
|
|
@ -71,6 +71,12 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
amas_selected_employees: [],
|
||||
amas_create_designation: 1,
|
||||
amas_organization_name: "",
|
||||
// Survives show_current_step() re-renders so the user sees what
|
||||
// failed when an error path resets amas_state to "intro" — the
|
||||
// .jey-status helper is cleared by every render and would erase
|
||||
// the message before they could read it.
|
||||
amas_last_error: "",
|
||||
asan_last_error: "",
|
||||
};
|
||||
|
||||
// Sub-state machines per step. `input` / `intro` is the always-safe fallback
|
||||
|
|
@ -314,8 +320,14 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
render_employees($body) {
|
||||
if (this.amas_state === "intro") {
|
||||
const alreadyLoaded = (this.data.amas_selected_employees || []).length;
|
||||
const lastError = this.data.amas_last_error || "";
|
||||
$body.html(`
|
||||
<h3 style="margin-bottom:16px">${__("Load employees from ƏMAS")}</h3>
|
||||
${lastError
|
||||
? `<div style="margin-bottom:12px;padding:12px;background:#fee2e2;border-left:3px solid #dc2626;border-radius:4px;color:#991b1b">
|
||||
<b>${__("Previous attempt failed:")}</b> ${frappe.utils.escape_html(lastError)}
|
||||
</div>`
|
||||
: ""}
|
||||
<p>${__("ƏMAS (e-social.gov.az) stores employment contracts. If your company has employees registered there, we can import them now.")}</p>
|
||||
<div style="margin-top:12px;padding:12px;background:#fff8e1;border-left:3px solid #e0a800;border-radius:4px">
|
||||
<b>${__("Heads up:")}</b> ${__("You will receive a second confirmation request on your phone from ASAN Sign / MyGovID. This is separate from the one you just approved for the tax portal.")}
|
||||
|
|
@ -400,12 +412,13 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
} else if (this.amas_state === "done") {
|
||||
const n = (this.data.amas_selected_employees || []).length;
|
||||
$body.html(`
|
||||
<h3 style="margin-bottom:16px;color:#080">✓ ${__("Employees ready to import")}</h3>
|
||||
<h3 style="margin-bottom:16px;color:#080">✓ ${__("Cached and ready")}</h3>
|
||||
<div style="padding:12px;background:#e8f5e9;border-radius:4px;margin-bottom:12px">
|
||||
${__("Organization:")} <b>${frappe.utils.escape_html(this.data.amas_organization_name || "")}</b><br>
|
||||
${__("Employees found:")} <b>${n}</b>
|
||||
${__("Employees cached:")} <b>${n}</b>
|
||||
</div>
|
||||
<p style="color:#666">${__("All employees will be imported into ƏMAS Employees and the standard Employee doctype after the wizard finishes.")}</p>
|
||||
<p style="color:#666">${__("Cached on the server. Actual import into Employee / ƏMAS Employees runs as a background job right after you click Finish — you can keep working in /app while it runs.")}</p>
|
||||
<p style="color:#888;font-size:12px;margin-top:8px">${__("Click Next to continue, or Back to re-select.")}</p>
|
||||
`);
|
||||
// No extra buttons here — Back/Next in nav cover everything.
|
||||
}
|
||||
|
|
@ -1157,6 +1170,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
return;
|
||||
}
|
||||
this.data.amas_skipped = false;
|
||||
this.data.amas_last_error = "";
|
||||
this.amas_verification_code = "";
|
||||
this.amas_state = "auth";
|
||||
this.show_current_step();
|
||||
|
|
@ -1170,7 +1184,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
if (this.amas_state !== "auth") return;
|
||||
const m = r.message || {};
|
||||
if (!m.success) {
|
||||
this.$wrap.find(".jey-status").text(m.message || __("MyGovID authentication failed."));
|
||||
this.data.amas_last_error = m.message || __("MyGovID authentication failed.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1179,7 +1193,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
},
|
||||
error: () => {
|
||||
if (this.amas_state !== "auth") return;
|
||||
this.$wrap.find(".jey-status").text(__("MyGovID request timed out."));
|
||||
this.data.amas_last_error = __("MyGovID request timed out.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
},
|
||||
|
|
@ -1213,7 +1227,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
callback: (r) => {
|
||||
const m = r.message || {};
|
||||
if (!m.success) {
|
||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to connect to ƏMAS."));
|
||||
this.data.amas_last_error = m.message || __("Failed to connect to ƏMAS.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1233,7 +1247,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
} else if (this.amas_accounts.length === 1) {
|
||||
this.amas_pick_account(0);
|
||||
} else if (this.amas_accounts.length === 0) {
|
||||
this.$wrap.find(".jey-status").text(__("No organizations found in ƏMAS for this account."));
|
||||
this.data.amas_last_error = __("No organizations found in ƏMAS for this account.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
} else {
|
||||
|
|
@ -1241,6 +1255,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
this.show_current_step();
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.data.amas_last_error = __("Network error while connecting to ƏMAS.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1267,7 +1286,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
callback: (r) => {
|
||||
const m = r.message || {};
|
||||
if (!m.success) {
|
||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to select organization."));
|
||||
this.data.amas_last_error = m.message || __("Failed to select organization.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1275,6 +1294,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
this.data.amas_organization_name = name;
|
||||
this.amas_load_employees();
|
||||
},
|
||||
error: () => {
|
||||
this.data.amas_last_error = __("Network error while selecting organization.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1292,14 +1316,14 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
callback: (r) => {
|
||||
const m = r.message || {};
|
||||
if (!m.success) {
|
||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to fetch employees."));
|
||||
this.data.amas_last_error = m.message || __("Failed to fetch employees.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
}
|
||||
const employees = m.employees || [];
|
||||
if (employees.length === 0) {
|
||||
this.$wrap.find(".jey-status").text(__("No employees found in ƏMAS for this organization."));
|
||||
this.data.amas_last_error = __("No employees found in ƏMAS for this organization.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1315,6 +1339,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
amas_commit_selection() {
|
||||
const all = this.amas_employees || [];
|
||||
if (all.length === 0) {
|
||||
this.data.amas_last_error = __("Got empty employee list from ƏMAS.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1331,7 +1356,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
callback: (r) => {
|
||||
const m = r.message || {};
|
||||
if (!m.ok) {
|
||||
this.$wrap.find(".jey-status").text(__("Failed to cache selection."));
|
||||
this.data.amas_last_error = __("Failed to cache employee selection on the server.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
return;
|
||||
|
|
@ -1341,6 +1366,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
this.amas_state = "done";
|
||||
this.show_current_step();
|
||||
},
|
||||
error: () => {
|
||||
this.data.amas_last_error = __("Network error while caching the employee selection.");
|
||||
this.amas_state = "intro";
|
||||
this.show_current_step();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue