central-auth-js-sdk 1.2.8 → 1.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/api.js +12 -0
- package/core/flow.js +2 -0
- package/package.json +1 -1
- package/signup.js +40 -2
- package/ui/screens/index.js +17 -0
- package/ui/screens/org-details.js +104 -0
package/core/api.js
CHANGED
|
@@ -82,6 +82,18 @@ export function createApi(baseUrl = DEFAULT_BASE, options = {}) {
|
|
|
82
82
|
return request('POST', '/signup/mobile/save', { email, mobile });
|
|
83
83
|
},
|
|
84
84
|
|
|
85
|
+
/** POST /signup/org/details — Save team, sub-team, designation for user (including social login) */
|
|
86
|
+
async signupSaveOrgDetails({ loginToken, email, userId, team, sub_team, designation }) {
|
|
87
|
+
const payload = {};
|
|
88
|
+
if (loginToken) payload.login_token = loginToken;
|
|
89
|
+
if (email) payload.email = email;
|
|
90
|
+
if (userId) payload.user_id = userId;
|
|
91
|
+
if (team !== undefined) payload.team = team;
|
|
92
|
+
if (sub_team !== undefined) payload.sub_team = sub_team;
|
|
93
|
+
if (designation !== undefined) payload.designation = designation;
|
|
94
|
+
return request('POST', '/signup/org/details', payload);
|
|
95
|
+
},
|
|
96
|
+
|
|
85
97
|
/** POST /signup/password/set — Password step */
|
|
86
98
|
async signupPasswordSet(email, password) {
|
|
87
99
|
return request('POST', '/signup/password/set', { email, password });
|
package/core/flow.js
CHANGED
|
@@ -8,6 +8,7 @@ export const STEPS = {
|
|
|
8
8
|
EMAIL_VERIFY: 'emailVerify',
|
|
9
9
|
MOBILE: 'mobile',
|
|
10
10
|
MOBILE_VERIFY: 'mobileVerify',
|
|
11
|
+
ORG_DETAILS: 'orgDetails',
|
|
11
12
|
PASSWORD: 'password',
|
|
12
13
|
FACE: 'face',
|
|
13
14
|
SUCCESS: 'success',
|
|
@@ -32,6 +33,7 @@ const STEP_ORDER = {
|
|
|
32
33
|
STEPS.EMAIL,
|
|
33
34
|
STEPS.MOBILE,
|
|
34
35
|
STEPS.MOBILE_VERIFY,
|
|
36
|
+
STEPS.ORG_DETAILS,
|
|
35
37
|
STEPS.FACE,
|
|
36
38
|
STEPS.SUCCESS,
|
|
37
39
|
],
|
package/package.json
CHANGED
package/signup.js
CHANGED
|
@@ -194,9 +194,14 @@ export function mount(container, options = {}) {
|
|
|
194
194
|
);
|
|
195
195
|
|
|
196
196
|
if (shouldSkipOtp) {
|
|
197
|
-
// Skip OTP verification, save mobile directly and advance
|
|
197
|
+
// Skip OTP verification, save mobile directly and advance
|
|
198
198
|
await api.signupMobileSave(state.get('email'), mobile);
|
|
199
|
-
|
|
199
|
+
if (isSocial()) {
|
|
200
|
+
const skipOrg = state.get('collectOrgDetails') === false || state.get('showOrgDetails') === false;
|
|
201
|
+
flow.setStep(skipOrg ? (enableFaceRegistration ? STEPS.FACE : STEPS.SUCCESS) : STEPS.ORG_DETAILS);
|
|
202
|
+
} else {
|
|
203
|
+
flow.setStep(STEPS.PASSWORD);
|
|
204
|
+
}
|
|
200
205
|
return;
|
|
201
206
|
}
|
|
202
207
|
|
|
@@ -246,6 +251,10 @@ export function mount(container, options = {}) {
|
|
|
246
251
|
const mobile = state.get('mobile');
|
|
247
252
|
if (provider === 'microsoft') await api.microsoftMobileVerify(token, mobile, otp, appIdentifier);
|
|
248
253
|
else await api.googleMobileVerify(token, mobile, otp, appIdentifier);
|
|
254
|
+
|
|
255
|
+
const skipOrg = state.get('collectOrgDetails') === false || state.get('showOrgDetails') === false;
|
|
256
|
+
flow.setStep(skipOrg ? (enableFaceRegistration ? STEPS.FACE : STEPS.SUCCESS) : STEPS.ORG_DETAILS);
|
|
257
|
+
return;
|
|
249
258
|
} else {
|
|
250
259
|
await api.signupMobileVerify(state.get('email'), state.get('mobile'), otp);
|
|
251
260
|
}
|
|
@@ -257,6 +266,34 @@ export function mount(container, options = {}) {
|
|
|
257
266
|
}
|
|
258
267
|
}
|
|
259
268
|
|
|
269
|
+
async function handleOrgDetailsSubmit(data) {
|
|
270
|
+
state.clearError();
|
|
271
|
+
state.setMultiple({
|
|
272
|
+
team: data.team,
|
|
273
|
+
subTeam: data.subTeam,
|
|
274
|
+
designation: data.designation,
|
|
275
|
+
});
|
|
276
|
+
try {
|
|
277
|
+
await api.signupSaveOrgDetails({
|
|
278
|
+
loginToken: state.get('loginToken'),
|
|
279
|
+
email: state.get('email'),
|
|
280
|
+
userId: state.get('userId'),
|
|
281
|
+
team: data.team,
|
|
282
|
+
sub_team: data.subTeam,
|
|
283
|
+
designation: data.designation,
|
|
284
|
+
});
|
|
285
|
+
if (enableFaceRegistration) {
|
|
286
|
+
flow.setStep(STEPS.FACE);
|
|
287
|
+
} else {
|
|
288
|
+
flow.setStep(STEPS.SUCCESS);
|
|
289
|
+
}
|
|
290
|
+
} catch (err) {
|
|
291
|
+
const msg = err?.data?.error || err?.message || 'Failed to save organization details';
|
|
292
|
+
state.set('error', msg);
|
|
293
|
+
showError(msg);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
260
297
|
async function handlePasswordSubmit(password) {
|
|
261
298
|
state.clearError();
|
|
262
299
|
state.set('password', password);
|
|
@@ -330,6 +367,7 @@ export function mount(container, options = {}) {
|
|
|
330
367
|
onMobileSubmit: handleMobileSubmit,
|
|
331
368
|
onMobileVerify: handleMobileVerify,
|
|
332
369
|
onMobileResend: handleMobileResend,
|
|
370
|
+
onOrgDetailsSubmit: handleOrgDetailsSubmit,
|
|
333
371
|
onPasswordSubmit: handlePasswordSubmit,
|
|
334
372
|
onFaceSubmit: handleFaceSubmit,
|
|
335
373
|
onBack: () => {
|
package/ui/screens/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createEmailVerifyScreen } from './email-verify.js';
|
|
|
9
9
|
import { createMobileEntryScreen } from './mobile-entry.js';
|
|
10
10
|
import { createMobileVerifyScreen } from './mobile-verify.js';
|
|
11
11
|
import { createPasswordSetupScreen } from './password-setup.js';
|
|
12
|
+
import { createOrgDetailsScreen } from './org-details.js';
|
|
12
13
|
import { createFaceRegistrationScreen } from './face-registration.js';
|
|
13
14
|
import { createSuccessScreen } from './success.js';
|
|
14
15
|
|
|
@@ -19,6 +20,7 @@ export function createScreen(step, state, flow, callbacks) {
|
|
|
19
20
|
onMobileSubmit,
|
|
20
21
|
onMobileVerify,
|
|
21
22
|
onMobileResend,
|
|
23
|
+
onOrgDetailsSubmit,
|
|
22
24
|
onPasswordSubmit,
|
|
23
25
|
onFaceSubmit,
|
|
24
26
|
onBack,
|
|
@@ -68,6 +70,21 @@ export function createScreen(step, state, flow, callbacks) {
|
|
|
68
70
|
}
|
|
69
71
|
);
|
|
70
72
|
|
|
73
|
+
case STEPS.ORG_DETAILS:
|
|
74
|
+
return createOrgDetailsScreen(
|
|
75
|
+
(data) => onOrgDetailsSubmit(data),
|
|
76
|
+
onBack,
|
|
77
|
+
{
|
|
78
|
+
team: state.get('team') || '',
|
|
79
|
+
subTeam: state.get('subTeam') || '',
|
|
80
|
+
designation: state.get('designation') || '',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
collectOrgDetails: state.get('collectOrgDetails'),
|
|
84
|
+
showOrgDetails: state.get('showOrgDetails'),
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
|
|
71
88
|
case STEPS.PASSWORD:
|
|
72
89
|
return createPasswordSetupScreen(onPasswordSubmit, onBack);
|
|
73
90
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Organization Details Screen — Team, Sub-team & Designation
|
|
3
|
+
* v2.0 — warm, modern design for onboarding & social signup
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const BRIEFCASE_ICON = 'M20 7h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v3H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zM10 4h4v3h-4V4zm10 16H4V9h16v11z';
|
|
7
|
+
const ARROW_LEFT = 'M19 12H5m7 7l-7-7 7-7';
|
|
8
|
+
const ARROW_RIGHT = 'M5 12h14m-7-7l7 7-7 7';
|
|
9
|
+
|
|
10
|
+
export function createOrgDetailsScreen(onNext, onBack, prefill = {}, options = {}) {
|
|
11
|
+
const wrap = document.createElement('div');
|
|
12
|
+
wrap.className = 'wf-screen';
|
|
13
|
+
|
|
14
|
+
const orgOpt = options.collectOrgDetails !== undefined ? options.collectOrgDetails : options.showOrgDetails;
|
|
15
|
+
const showTeam = typeof orgOpt === 'object' && orgOpt !== null ? Boolean(orgOpt.team) : orgOpt !== false;
|
|
16
|
+
const showSubTeam = typeof orgOpt === 'object' && orgOpt !== null ? Boolean(orgOpt.subTeam) : orgOpt !== false;
|
|
17
|
+
const showDesignation = typeof orgOpt === 'object' && orgOpt !== null ? Boolean(orgOpt.designation) : orgOpt !== false;
|
|
18
|
+
|
|
19
|
+
let fieldsHtml = '';
|
|
20
|
+
if (showTeam && showSubTeam) {
|
|
21
|
+
fieldsHtml += `
|
|
22
|
+
<div class="wf-row-2">
|
|
23
|
+
<div class="wf-field">
|
|
24
|
+
<label class="wf-label" for="wf-org-team">Team</label>
|
|
25
|
+
<input type="text" id="wf-org-team" placeholder="e.g. Engineering" class="wf-input" autocomplete="organization" />
|
|
26
|
+
</div>
|
|
27
|
+
<div class="wf-field">
|
|
28
|
+
<label class="wf-label" for="wf-org-subteam">Sub-team</label>
|
|
29
|
+
<input type="text" id="wf-org-subteam" placeholder="e.g. Backend" class="wf-input" />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
`;
|
|
33
|
+
} else if (showTeam) {
|
|
34
|
+
fieldsHtml += `
|
|
35
|
+
<div class="wf-field">
|
|
36
|
+
<label class="wf-label" for="wf-org-team">Team</label>
|
|
37
|
+
<input type="text" id="wf-org-team" placeholder="e.g. Engineering" class="wf-input" autocomplete="organization" />
|
|
38
|
+
</div>
|
|
39
|
+
`;
|
|
40
|
+
} else if (showSubTeam) {
|
|
41
|
+
fieldsHtml += `
|
|
42
|
+
<div class="wf-field">
|
|
43
|
+
<label class="wf-label" for="wf-org-subteam">Sub-team</label>
|
|
44
|
+
<input type="text" id="wf-org-subteam" placeholder="e.g. Backend" class="wf-input" />
|
|
45
|
+
</div>
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (showDesignation) {
|
|
50
|
+
fieldsHtml += `
|
|
51
|
+
<div class="wf-field">
|
|
52
|
+
<label class="wf-label" for="wf-org-designation">Designation</label>
|
|
53
|
+
<input type="text" id="wf-org-designation" placeholder="e.g. Software Engineer" class="wf-input" autocomplete="organization-title" />
|
|
54
|
+
</div>
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
wrap.innerHTML = `
|
|
59
|
+
<div class="wf-screen-header">
|
|
60
|
+
<div class="wf-icon-box">
|
|
61
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${BRIEFCASE_ICON}"/></svg>
|
|
62
|
+
</div>
|
|
63
|
+
<h2 class="wf-screen-title">Complete your profile</h2>
|
|
64
|
+
<p class="wf-screen-desc">Add your team and role details to personalize your workspace</p>
|
|
65
|
+
</div>
|
|
66
|
+
<form class="wf-form" id="wf-org-form">
|
|
67
|
+
${fieldsHtml}
|
|
68
|
+
<div class="wf-btn-row">
|
|
69
|
+
<button type="button" class="wf-btn wf-btn-outline wf-btn-lg" data-action="back" aria-label="Go back">
|
|
70
|
+
<svg class="wf-icon-sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${ARROW_LEFT}"/></svg>
|
|
71
|
+
</button>
|
|
72
|
+
<button type="submit" class="wf-btn wf-btn-primary wf-btn-lg wf-btn-flex" id="wf-btn-org-submit">
|
|
73
|
+
Continue
|
|
74
|
+
<svg class="wf-icon-sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="${ARROW_RIGHT}"/></svg>
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
</form>
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
const form = wrap.querySelector('#wf-org-form');
|
|
81
|
+
const teamInput = wrap.querySelector('#wf-org-team');
|
|
82
|
+
const subTeamInput = wrap.querySelector('#wf-org-subteam');
|
|
83
|
+
const designationInput = wrap.querySelector('#wf-org-designation');
|
|
84
|
+
|
|
85
|
+
if (prefill.team && teamInput) teamInput.value = prefill.team;
|
|
86
|
+
if (prefill.subTeam && subTeamInput) subTeamInput.value = prefill.subTeam;
|
|
87
|
+
if (prefill.designation && designationInput) designationInput.value = prefill.designation;
|
|
88
|
+
|
|
89
|
+
form.addEventListener('submit', (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
onNext({
|
|
92
|
+
team: teamInput ? teamInput.value.trim() : '',
|
|
93
|
+
subTeam: subTeamInput ? subTeamInput.value.trim() : '',
|
|
94
|
+
designation: designationInput ? designationInput.value.trim() : '',
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const backBtn = wrap.querySelector('button[data-action="back"]');
|
|
99
|
+
if (backBtn && typeof onBack === 'function') {
|
|
100
|
+
backBtn.addEventListener('click', onBack);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return wrap;
|
|
104
|
+
}
|