@zwayam/apply-experience-library 0.2.1 → 0.2.3

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/README.md CHANGED
@@ -1,28 +1,14 @@
1
1
  # Apply Experience Library
2
2
 
3
- `@zwayam/apply-experience-library` is a host-facing SDK for launching **Add Profile** and **Edit Profile** popups inside recruiter or admin web applications.
3
+ This package is the bundled web entrypoint for `@zwayam/apply-experience-library`.
4
4
 
5
- It is designed for hosts that already own authentication, API orchestration, and business rules, but want a reusable profile collection UI.
5
+ It exposes framework-friendly mount helpers for launching **Add Profile** and **Edit Profile** popups from:
6
6
 
7
- ## What the SDK Handles
8
-
9
- - resume upload and resume parsing flow
10
- - manual profile creation flow
11
- - add profile and edit profile popup UI
12
- - dynamic field rendering from backend `applyFields`
13
- - required validation, pattern validation, dependent field visibility
14
- - country code + phone input handling
15
- - source / source type / sub-source flow
16
- - optional location autosuggestions
17
- - final submit flow and success callbacks
18
-
19
- ## What the Host App Handles
20
-
21
- - authentication and session
22
- - current job and user context
23
- - backend API calls
24
- - route-level state management
25
- - refresh / navigation after success
7
+ - Angular
8
+ - React
9
+ - Vue
10
+ - Vanilla JavaScript
11
+ - Custom elements
26
12
 
27
13
  ## Install
28
14
 
@@ -30,457 +16,42 @@ It is designed for hosts that already own authentication, API orchestration, and
30
16
  npm install @zwayam/apply-experience-library
31
17
  ```
32
18
 
33
- Import styles once in your host app:
19
+ Import styles once:
34
20
 
35
21
  ```ts
36
22
  import "@zwayam/apply-experience-library/styles.css";
37
23
  ```
38
24
 
39
- ## Exported API
40
-
41
- The package exposes:
42
-
43
- - `mountAddProfile(options)`
44
- - `mountEditProfile(options)`
45
- - `registerAddProfileElement(options)`
46
- - `registerEditProfileElement(options)`
47
-
48
- Use `mount*` for direct framework integration. Use `register*Element` if you prefer custom elements.
49
-
50
- ## How It Is Built
51
-
52
- The SDK is made in two layers:
53
-
54
- 1. `packages/react`
55
- - React implementation of Add Profile / Edit Profile
56
- - field rendering, validations, workflow logic
57
-
58
- 2. `packages/web`
59
- - bundled host-facing package
60
- - exports mount helpers that work in Angular, React, Vue, and vanilla JS
61
-
62
- This means host apps do not need to know the internal React implementation details. They only provide `context`, `api`, and a DOM `container`.
63
-
64
- ## Add Profile Context
65
-
66
- ```ts
67
- type AddProfileHostContext = {
68
- job: {
69
- id: string;
70
- companyId: number | string;
71
- departmentId?: number | string;
72
- jobTitle: string;
73
- jobCode: string;
74
- location?: string;
75
- minYearOfExperience?: number;
76
- maxYearOfExperience?: number;
77
- departmentName?: string;
78
- };
79
- user: {
80
- id: string | number;
81
- email: string;
82
- name: string;
83
- uuid?: string;
84
- };
85
- session: {
86
- sessionId: string;
87
- };
88
- environment?: Record<string, string>;
89
- };
90
- ```
91
-
92
- ### Example
25
+ ## Main Exports
93
26
 
94
- ```ts
95
- const addProfileContext = {
96
- job: {
97
- id: "263294",
98
- companyId: 16136,
99
- departmentId: 12,
100
- jobTitle: "Java Developer",
101
- jobCode: "16667",
102
- location: "Pune, Maharashtra, India",
103
- minYearOfExperience: 2,
104
- maxYearOfExperience: 5,
105
- departmentName: "Engineering",
106
- },
107
- user: {
108
- id: 286813,
109
- email: "recruiter@example.com",
110
- name: "Recruiter Name",
111
- uuid: "host-user-uuid",
112
- },
113
- session: {
114
- sessionId: "SESSION_ID",
115
- },
116
- environment: {
117
- tenant: "prod",
118
- },
119
- };
120
- ```
121
-
122
- ## Edit Profile Context
27
+ - `mountAddProfile`
28
+ - `mountEditProfile`
29
+ - `registerAddProfileElement`
30
+ - `registerEditProfileElement`
123
31
 
124
- Edit Profile uses everything from Add Profile, plus:
32
+ ## Quick Example
125
33
 
126
34
  ```ts
127
- type EditProfileHostContext = AddProfileHostContext & {
128
- applyId: string | number;
129
- application?: Record<string, unknown>;
130
- };
131
- ```
132
-
133
- ### Example
134
-
135
- ```ts
136
- const editProfileContext = {
137
- ...addProfileContext,
138
- applyId: 987654,
139
- application: {
140
- applyId: 987654,
141
- candidateId: 12345,
142
- },
143
- };
144
- ```
145
-
146
- ## Add Profile API Contract
147
-
148
- ```ts
149
- type AddProfileApi = {
150
- loadInitialData(
151
- context: AddProfileHostContext,
152
- ): Promise<{
153
- applyFields: AddProfileFieldDefinition[];
154
- supportedFiles: {
155
- addProfile?: {
156
- fileFormat: string[];
157
- fileSize?: number;
158
- };
159
- };
160
- profileSources: Array<{
161
- sourceOfProfile?: string;
162
- profileSource: string;
163
- subSourceValues?: string | null;
164
- }>;
165
- phoneConfiguration: {
166
- countryIsoCode: string | null;
167
- whatsAppEnabled: boolean;
168
- maxCount: number;
169
- };
170
- resumeOptional?: boolean;
171
- }>;
172
-
173
- parseResume(
174
- file: File,
175
- context: AddProfileHostContext,
176
- ): Promise<{
177
- responseCode?: number;
178
- reponseObject?: {
179
- parsedObjectId?: string;
180
- parsedResult?: {
181
- profile?: Record<string, unknown>;
182
- };
183
- jobApplication?: Record<string, unknown>;
184
- };
185
- }>;
186
-
187
- submitProfile(
188
- payload: FormData,
189
- context: AddProfileHostContext,
190
- ): Promise<{
191
- code?: number;
192
- message?: string;
193
- [key: string]: unknown;
194
- }>;
195
-
196
- getLocationSuggestions?(
197
- query: string,
198
- context: AddProfileHostContext,
199
- ): Promise<string[]>;
200
- };
201
- ```
202
-
203
- ## Edit Profile API Contract
204
-
205
- ```ts
206
- type EditProfileApi = {
207
- loadInitialData(
208
- context: EditProfileHostContext,
209
- ): Promise<{
210
- jobApplication: Record<string, unknown>;
211
- applyFieldsObject: Record<string, unknown>;
212
- applyFields: AddProfileFieldDefinition[];
213
- phoneConfiguration: {
214
- countryIsoCode: string | null;
215
- whatsAppEnabled: boolean;
216
- maxCount: number;
217
- };
218
- phoneNumbers?: Array<Record<string, unknown>>;
219
- supportedFiles?: {
220
- addProfile?: {
221
- fileFormat: string[];
222
- fileSize?: number;
223
- };
224
- };
225
- }>;
226
-
227
- submitProfile(
228
- payload: Record<string, unknown>,
229
- context: EditProfileHostContext,
230
- ): Promise<{
231
- code?: number;
232
- message?: string;
233
- [key: string]: unknown;
234
- }>;
235
-
236
- getLocationSuggestions?(
237
- query: string,
238
- context: EditProfileHostContext,
239
- ): Promise<string[]>;
240
- };
241
- ```
242
-
243
- ## Field Definitions
244
-
245
- The SDK renders fields from backend `applyFields`.
246
-
247
- Common field types include:
248
-
249
- - `T` for text-like inputs
250
- - `D` for searchable dropdowns
251
- - `date`
252
- - `phone`
253
- - `checkbox`
254
- - `location`
255
- - `email`
256
- - `consent`
257
-
258
- Notes:
259
-
260
- - `field.errorMessage` is used as first priority for validation messages when present.
261
- - Generated SDK validation messages are used as fallback when API does not provide one.
262
- - Currency formatting follows field metadata type such as `INRCURRENCY` / `CURRENCY`, matching host behavior.
263
-
264
- ## React Usage
265
-
266
- ```tsx
267
- import { useEffect, useRef } from "react";
268
- import {
269
- mountAddProfile,
270
- type MountedAddProfile,
271
- type AddProfileApi,
272
- type AddProfileHostContext,
273
- } from "@zwayam/apply-experience-library";
274
- import "@zwayam/apply-experience-library/styles.css";
35
+ import { mountAddProfile } from "@zwayam/apply-experience-library";
275
36
 
276
- export function AddProfileLauncher({
277
- open,
37
+ const mounted = mountAddProfile({
38
+ container: document.getElementById("add-profile-root"),
278
39
  context,
279
40
  api,
280
- onClose,
281
- }: {
282
- open: boolean;
283
- context: AddProfileHostContext;
284
- api: AddProfileApi;
285
- onClose(): void;
286
- }) {
287
- const rootRef = useRef<HTMLDivElement | null>(null);
288
- const mountedRef = useRef<MountedAddProfile | null>(null);
289
-
290
- useEffect(() => {
291
- if (!open || !rootRef.current) return;
292
-
293
- mountedRef.current = mountAddProfile({
294
- container: rootRef.current,
295
- context,
296
- api,
297
- title: "Add Profile",
298
- onClose,
299
- onSuccess: () => {
300
- mountedRef.current?.unmount();
301
- onClose();
302
- },
303
- });
304
-
305
- return () => mountedRef.current?.unmount();
306
- }, [open, context, api, onClose]);
307
-
308
- return <div ref={rootRef} />;
309
- }
310
- ```
311
-
312
- ## Angular Usage
313
-
314
- Import styles once in a global stylesheet:
315
-
316
- ```scss
317
- @import "@zwayam/apply-experience-library/styles.css";
318
- ```
319
-
320
- Mount from a component or service:
321
-
322
- ```ts
323
- import {
324
- mountAddProfile,
325
- type MountedAddProfile,
326
- type AddProfileApi,
327
- type AddProfileHostContext,
328
- } from "@zwayam/apply-experience-library";
329
-
330
- private mountedAddProfile?: MountedAddProfile;
331
-
332
- openAddProfile(container: Element, context: AddProfileHostContext, api: AddProfileApi) {
333
- this.mountedAddProfile = mountAddProfile({
334
- container,
335
- context,
336
- api,
337
- title: "Add Profile",
338
- onClose: () => this.mountedAddProfile?.unmount(),
339
- onSuccess: () => {
340
- this.mountedAddProfile?.unmount();
341
- // refresh host data here
342
- },
343
- });
344
- }
345
- ```
346
-
347
- ## Vue Usage
348
-
349
- ```vue
350
- <script setup lang="ts">
351
- import { onBeforeUnmount, watch, ref } from "vue";
352
- import { mountAddProfile } from "@zwayam/apply-experience-library";
353
- import "@zwayam/apply-experience-library/styles.css";
354
-
355
- const props = defineProps<{
356
- open: boolean;
357
- context: any;
358
- api: any;
359
- }>();
360
-
361
- const root = ref<HTMLElement | null>(null);
362
- let mounted: ReturnType<typeof mountAddProfile> | null = null;
363
-
364
- watch(
365
- () => props.open,
366
- (open) => {
367
- if (!open || !root.value) return;
368
-
369
- mounted = mountAddProfile({
370
- container: root.value,
371
- context: props.context,
372
- api: props.api,
373
- onClose: () => mounted?.unmount(),
374
- onSuccess: () => mounted?.unmount(),
375
- });
376
- },
377
- );
378
-
379
- onBeforeUnmount(() => mounted?.unmount());
380
- </script>
381
-
382
- <template>
383
- <div ref="root"></div>
384
- </template>
385
- ```
386
-
387
- ## Vanilla JavaScript Usage
388
-
389
- ```html
390
- <button id="open-add-profile">Add Profile</button>
391
- <div id="add-profile-root"></div>
392
- ```
393
-
394
- ```js
395
- import { mountAddProfile } from "@zwayam/apply-experience-library";
396
- import "@zwayam/apply-experience-library/styles.css";
397
-
398
- document.getElementById("open-add-profile").addEventListener("click", () => {
399
- const mounted = mountAddProfile({
400
- container: document.getElementById("add-profile-root"),
401
- context: addProfileContext,
402
- api: addProfileApi,
403
- onClose: () => mounted.unmount(),
404
- onSuccess: () => mounted.unmount(),
405
- });
41
+ onClose: () => mounted.unmount(),
42
+ onSuccess: () => mounted.unmount(),
406
43
  });
407
44
  ```
408
45
 
409
- ## Custom Element Usage
46
+ ## Context and API
410
47
 
411
- ```ts
412
- import {
413
- registerAddProfileElement,
414
- registerEditProfileElement,
415
- } from "@zwayam/apply-experience-library";
48
+ The host must provide:
416
49
 
417
- registerAddProfileElement({
418
- getApi: () => addProfileApi,
419
- getContext: () => addProfileContext,
420
- });
50
+ - job context
51
+ - logged-in user context
52
+ - session context
53
+ - host-owned API functions for loading fields, parsing resume, submitting profile, and optionally fetching location suggestions
421
54
 
422
- registerEditProfileElement({
423
- getApi: () => editProfileApi,
424
- getContext: () => editProfileContext,
425
- });
426
- ```
427
-
428
- Then use:
429
-
430
- ```html
431
- <apply-experience-add-profile></apply-experience-add-profile>
432
- <apply-experience-edit-profile></apply-experience-edit-profile>
433
- ```
434
-
435
- ## Example API Object
55
+ For the full API contract and framework-specific examples, see:
436
56
 
437
- ```ts
438
- const addProfileApi = {
439
- loadInitialData: async (context) => {
440
- const response = await fetch(`/api/apply-fields?jobId=${context.job.id}`);
441
- return response.json();
442
- },
443
-
444
- parseResume: async (file, context) => {
445
- const formData = new FormData();
446
- formData.append("file", file);
447
- formData.append("sessionId", context.session.sessionId);
448
- const response = await fetch("/api/parse-resume", {
449
- method: "POST",
450
- body: formData,
451
- });
452
- return response.json();
453
- },
454
-
455
- submitProfile: async (payload, context) => {
456
- payload.append("sessionId", context.session.sessionId);
457
- const response = await fetch("/api/add-profile", {
458
- method: "POST",
459
- body: payload,
460
- });
461
- return response.json();
462
- },
463
-
464
- getLocationSuggestions: async (query) => {
465
- if (!query.trim()) return [];
466
- const response = await fetch(`/api/location-suggestions?q=${encodeURIComponent(query)}`);
467
- const data = await response.json();
468
- return data.suggestions || [];
469
- },
470
- };
471
- ```
472
-
473
- ## Development
474
-
475
- ```bash
476
- npm install
477
- npm run build
478
- npm run playground
479
- ```
480
-
481
- ## Publish
482
-
483
- ```bash
484
- npm run build
485
- npm publish --access public
486
- ```
57
+ - [../../README.md](../../README.md)
@@ -28,6 +28,7 @@ export interface MountEditProfileOptions {
28
28
  api: EditProfileApi;
29
29
  context: EditProfileHostContext;
30
30
  title?: string;
31
+ candidateSettingsUrl?: string;
31
32
  onClose?(): void;
32
33
  onSuccess?(result: unknown): void;
33
34
  showSubmitToast?: boolean;