@idsoftsource/initial-process 1.4.1 → 1.4.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.
@@ -6,7 +6,7 @@ import * as i8 from '@angular/forms';
6
6
  import { NG_VALUE_ACCESSOR, COMPOSITION_BUFFER_MODE, Validators, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
7
7
  import * as i2 from '@angular/router';
8
8
  import { RouterModule } from '@angular/router';
9
- import { map, of, tap as tap$1, Subscription, switchMap, finalize, catchError, EMPTY, Subject, firstValueFrom, takeUntil } from 'rxjs';
9
+ import { map, of, tap as tap$1, Subscription, switchMap, finalize, catchError, EMPTY, from, concatMap, Subject, firstValueFrom, takeUntil } from 'rxjs';
10
10
  import * as i1 from '@angular/common/http';
11
11
  import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
12
12
  import * as i7 from 'ngx-bootstrap/modal';
@@ -29180,7 +29180,7 @@ class FirstComponent {
29180
29180
  if (!this.resumeName) {
29181
29181
  fileInput.click();
29182
29182
  }
29183
- this.saveAWSFile();
29183
+ // this.saveAWSFile();
29184
29184
  }
29185
29185
  handleAutoNavigation() {
29186
29186
  this.store.nextStep();
@@ -29269,6 +29269,1326 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
29269
29269
  type: Output
29270
29270
  }] } });
29271
29271
 
29272
+ class PreviewComponent {
29273
+ store;
29274
+ userSkillSetService;
29275
+ userToolService;
29276
+ userDocumentService;
29277
+ userEducation;
29278
+ userDetailService;
29279
+ userExperienceService;
29280
+ router;
29281
+ tokenService;
29282
+ backToParent = new EventEmitter();
29283
+ payloadUserId;
29284
+ payloadUserName;
29285
+ resumeData;
29286
+ statusList = [];
29287
+ showPopup = false;
29288
+ showBackConfirmPopup = false;
29289
+ userId;
29290
+ userName;
29291
+ constructor(store, userSkillSetService, userToolService, userDocumentService, userEducation, userDetailService, userExperienceService, router, tokenService) {
29292
+ this.store = store;
29293
+ this.userSkillSetService = userSkillSetService;
29294
+ this.userToolService = userToolService;
29295
+ this.userDocumentService = userDocumentService;
29296
+ this.userEducation = userEducation;
29297
+ this.userDetailService = userDetailService;
29298
+ this.userExperienceService = userExperienceService;
29299
+ this.router = router;
29300
+ this.tokenService = tokenService;
29301
+ this.resumeData = this.store.profileSignal();
29302
+ }
29303
+ email;
29304
+ expYears = [];
29305
+ details = signal(undefined, ...(ngDevMode ? [{ debugName: "details" }] : []));
29306
+ async ngOnInit() {
29307
+ this.payloadUserId = await this.tokenService.getUserId();
29308
+ this.payloadUserName = await this.tokenService.getUserFullName();
29309
+ const initialData = this.store.profileSignal()?.basicDetails;
29310
+ if (initialData) {
29311
+ this.details.set(initialData);
29312
+ }
29313
+ this.prefillSectionFieldsFromBasicDetails();
29314
+ // Use 1..30 years of experience.
29315
+ this.expYears = Array.from({ length: 30 }, (_, i) => i + 1);
29316
+ }
29317
+ experience = computed(() => this.store.profileSignal()?.workExperience || [], ...(ngDevMode ? [{ debugName: "experience" }] : []));
29318
+ educationList = computed(() => {
29319
+ const list = this.store.profileSignal()?.education || [];
29320
+ return [...list].sort((a, b) => b.endDate.localeCompare(a.endDate));
29321
+ }, ...(ngDevMode ? [{ debugName: "educationList" }] : []));
29322
+ certs = computed(() => this.store.profileSignal()?.certifications || [], ...(ngDevMode ? [{ debugName: "certs" }] : []));
29323
+ licenses = computed(() => this.store.profileSignal()?.licenses || [], ...(ngDevMode ? [{ debugName: "licenses" }] : []));
29324
+ skills = computed(() => this.store.profileSignal()?.skills || [], ...(ngDevMode ? [{ debugName: "skills" }] : []));
29325
+ tools = computed(() => this.store.profileSignal()?.tools || [], ...(ngDevMode ? [{ debugName: "tools" }] : []));
29326
+ isBlank(value) {
29327
+ return typeof value !== 'string' || value.trim().length === 0;
29328
+ }
29329
+ isBlankOrNull(value) {
29330
+ if (value === null || value === undefined)
29331
+ return true;
29332
+ return this.isBlank(value);
29333
+ }
29334
+ sanitizePhone(value) {
29335
+ const digits = (value ?? '').toString().replace(/\D/g, '');
29336
+ return digits.slice(0, 10);
29337
+ }
29338
+ isMonthRangeInvalid(start, end) {
29339
+ if (this.isBlankOrNull(start) || this.isBlankOrNull(end))
29340
+ return false;
29341
+ const cmp = this.compareMonth(start ?? null, end ?? null);
29342
+ return cmp !== null && cmp >= 0;
29343
+ }
29344
+ compareMonth(a, b) {
29345
+ // Compares YYYY-MM (or YYYY-MM-DD...) values
29346
+ const am = this.toMonthInput(a ?? '');
29347
+ const bm = this.toMonthInput(b ?? '');
29348
+ const matchA = am.match(/^(\d{4})-(\d{2})$/);
29349
+ const matchB = bm.match(/^(\d{4})-(\d{2})$/);
29350
+ if (!matchA || !matchB)
29351
+ return null;
29352
+ const ay = Number(matchA[1]);
29353
+ const amn = Number(matchA[2]);
29354
+ const by = Number(matchB[1]);
29355
+ const bmn = Number(matchB[2]);
29356
+ if (Number.isNaN(ay) || Number.isNaN(amn) || Number.isNaN(by) || Number.isNaN(bmn))
29357
+ return null;
29358
+ return (ay - by) || (amn - bmn);
29359
+ }
29360
+ prefillSectionFieldsFromBasicDetails() {
29361
+ const current = this.store.profileSignal();
29362
+ const basic = current?.basicDetails;
29363
+ if (!current || !basic)
29364
+ return;
29365
+ const fallbackCity = (basic.city ?? '').trim();
29366
+ const fallbackState = (basic.state ?? '').trim();
29367
+ const fallbackCountry = (basic.country ?? '').trim();
29368
+ let changed = false;
29369
+ const nextWork = (current.workExperience ?? []).map((w) => {
29370
+ const next = { ...w };
29371
+ if (this.isBlank(next.city) && fallbackCity) {
29372
+ next.city = fallbackCity;
29373
+ changed = true;
29374
+ }
29375
+ if (this.isBlank(next.state) && fallbackState) {
29376
+ next.state = fallbackState;
29377
+ changed = true;
29378
+ }
29379
+ if (this.isBlank(next.country) && fallbackCountry) {
29380
+ next.country = fallbackCountry;
29381
+ changed = true;
29382
+ }
29383
+ return next;
29384
+ });
29385
+ const nextEdu = (current.education ?? []).map((e) => {
29386
+ const next = { ...e };
29387
+ if (this.isBlank(next.city) && fallbackCity) {
29388
+ next.city = fallbackCity;
29389
+ changed = true;
29390
+ }
29391
+ if (this.isBlank(next.state) && fallbackState) {
29392
+ next.state = fallbackState;
29393
+ changed = true;
29394
+ }
29395
+ if (this.isBlank(next.country) && fallbackCountry) {
29396
+ next.country = fallbackCountry;
29397
+ changed = true;
29398
+ }
29399
+ return next;
29400
+ });
29401
+ const nextCerts = (current.certifications ?? []).map((c) => {
29402
+ const next = { ...c };
29403
+ if ((next.state === null || this.isBlank(next.state)) && fallbackState) {
29404
+ next.state = fallbackState;
29405
+ changed = true;
29406
+ }
29407
+ return next;
29408
+ });
29409
+ if (!changed)
29410
+ return;
29411
+ this.commitProfile({
29412
+ ...current,
29413
+ workExperience: nextWork,
29414
+ education: nextEdu,
29415
+ certifications: nextCerts,
29416
+ });
29417
+ }
29418
+ basicDetailsIssues(item) {
29419
+ const issues = [];
29420
+ if (!item) {
29421
+ issues.push('Basic details are missing');
29422
+ return issues;
29423
+ }
29424
+ if (this.isBlank(item.firstName))
29425
+ issues.push('First name is required');
29426
+ if (this.isBlank(item.lastName))
29427
+ issues.push('Last name is required');
29428
+ if (this.isBlank(item.email))
29429
+ issues.push('Email is required');
29430
+ if (!this.isBlank(item.email)) {
29431
+ const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(item.email.trim());
29432
+ if (!emailOk)
29433
+ issues.push('Email format is invalid');
29434
+ }
29435
+ if (this.isBlank(item.address))
29436
+ issues.push('Home address is required');
29437
+ if (this.isBlank(item.city))
29438
+ issues.push('City is required');
29439
+ if (this.isBlank(item.state))
29440
+ issues.push('State is required');
29441
+ if (this.isBlank(item.zipCode))
29442
+ issues.push('Zip code is required');
29443
+ if (this.isBlank(item.country))
29444
+ issues.push('Country is required');
29445
+ if (this.isBlank(item.phone))
29446
+ issues.push('Phone number is required');
29447
+ if (!this.isBlank(item.phone)) {
29448
+ const digitsOnly = item.phone.replace(/\D/g, '');
29449
+ if (digitsOnly.length !== 10)
29450
+ issues.push('Phone number must be 10 digits');
29451
+ }
29452
+ const yoe = item.yearsOfExperience;
29453
+ if (yoe === null || yoe === undefined || Number.isNaN(Number(yoe)) || Number(yoe) <= 0)
29454
+ issues.push('Years of experience is required');
29455
+ if (this.isBlank(item.jobTitle))
29456
+ issues.push('Job title is required');
29457
+ return issues;
29458
+ }
29459
+ workItemIssues(item) {
29460
+ const issues = [];
29461
+ // Mandatory: company name, job title, city, start date, to date (unless current)
29462
+ if (this.isBlank(item.company))
29463
+ issues.push('Company name is required');
29464
+ if (this.isBlank(item.jobTitle))
29465
+ issues.push('Job title is required');
29466
+ if (this.isBlank(item.city))
29467
+ issues.push('City is required');
29468
+ if (this.isBlank(item.startDate))
29469
+ issues.push('Start date is required');
29470
+ if (!item.isCurrent) {
29471
+ if (this.isBlank(item.endDate))
29472
+ issues.push('End date is required');
29473
+ const cmp = this.compareMonth(item.startDate, item.endDate ?? null);
29474
+ if (cmp !== null && cmp >= 0)
29475
+ issues.push('Start date must be less than end date');
29476
+ }
29477
+ return issues;
29478
+ }
29479
+ educationItemIssues(item) {
29480
+ const issues = [];
29481
+ // Mandatory: degree/course name, degree/course type, institution, start date, end date
29482
+ if (this.isBlank(item.degree))
29483
+ issues.push('Degree / Course name is required');
29484
+ if (this.isBlank(item.degreeType))
29485
+ issues.push('Degree / Course type is required');
29486
+ if (this.isBlank(item.institution))
29487
+ issues.push('Institution name is required');
29488
+ if (this.isBlank(item.startDate))
29489
+ issues.push('Start date is required');
29490
+ if (this.isBlank(item.endDate))
29491
+ issues.push('End date is required');
29492
+ const cmp = this.compareMonth(item.startDate, item.endDate);
29493
+ if (cmp !== null && cmp >= 0)
29494
+ issues.push('Start date must be less than end date');
29495
+ return issues;
29496
+ }
29497
+ certificationItemIssues(item) {
29498
+ const issues = [];
29499
+ // Mandatory: certificate name only
29500
+ if (this.isBlank(item.name))
29501
+ issues.push('Certificate name is required');
29502
+ // Optional date sanity check if both provided
29503
+ const issueDate = item.issueDate;
29504
+ const expiryDate = item.expiryDate;
29505
+ if (!this.isBlankOrNull(issueDate) && !this.isBlankOrNull(expiryDate)) {
29506
+ const cmp = this.compareMonth(issueDate ?? null, expiryDate ?? null);
29507
+ if (cmp !== null && cmp >= 0)
29508
+ issues.push('Issued date must be less than expiry date');
29509
+ }
29510
+ return issues;
29511
+ }
29512
+ licenseItemIssues(item) {
29513
+ const issues = [];
29514
+ // Mandatory: license name only
29515
+ const name = item.name;
29516
+ if (this.isBlankOrNull(name))
29517
+ issues.push('License name is required');
29518
+ // Optional date sanity check if both provided
29519
+ const issueDate = item.issueDate;
29520
+ const expiryDate = item.expiryDate;
29521
+ if (!this.isBlankOrNull(issueDate) && !this.isBlankOrNull(expiryDate)) {
29522
+ const cmp = this.compareMonth(issueDate ?? null, expiryDate ?? null);
29523
+ if (cmp !== null && cmp >= 0)
29524
+ issues.push('Issued date must be less than expiry date');
29525
+ }
29526
+ return issues;
29527
+ }
29528
+ skillItemIssues(name, index) {
29529
+ const issues = [];
29530
+ if (this.isBlank(name))
29531
+ issues.push('Skill name is required');
29532
+ const meta = this.store.resumeSkillMeta()?.[index] ?? {};
29533
+ const stars = Math.round((meta.starRating ?? 0) / 2);
29534
+ if (!stars || stars <= 0)
29535
+ issues.push('Star rating is required');
29536
+ if (meta.year === null || meta.year === undefined)
29537
+ issues.push('Years of experience is required');
29538
+ return issues;
29539
+ }
29540
+ toolItemIssues(name, index) {
29541
+ const issues = [];
29542
+ if (this.isBlank(name))
29543
+ issues.push('Tool name is required');
29544
+ const meta = this.store.resumeToolMeta()?.[index] ?? {};
29545
+ const stars = Math.round((meta.starRating ?? 0) / 2);
29546
+ if (!stars || stars <= 0)
29547
+ issues.push('Star rating is required');
29548
+ if (meta.year === null || meta.year === undefined)
29549
+ issues.push('Years of experience is required');
29550
+ return issues;
29551
+ }
29552
+ basicIssues = computed(() => this.basicDetailsIssues(this.details()), ...(ngDevMode ? [{ debugName: "basicIssues" }] : []));
29553
+ basicSectionHasIssues = computed(() => this.basicIssues().length > 0, ...(ngDevMode ? [{ debugName: "basicSectionHasIssues" }] : []));
29554
+ workIssuesByIndex = computed(() => this.experience().map((w) => this.workItemIssues(w)), ...(ngDevMode ? [{ debugName: "workIssuesByIndex" }] : []));
29555
+ educationIssuesByIndex = computed(() => this.educationList().map((e) => this.educationItemIssues(e)), ...(ngDevMode ? [{ debugName: "educationIssuesByIndex" }] : []));
29556
+ certIssuesByIndex = computed(() => this.certs().map((c) => this.certificationItemIssues(c)), ...(ngDevMode ? [{ debugName: "certIssuesByIndex" }] : []));
29557
+ licenseIssuesByIndex = computed(() => this.licenses().map((l) => this.licenseItemIssues(l)), ...(ngDevMode ? [{ debugName: "licenseIssuesByIndex" }] : []));
29558
+ skillIssuesByIndex = computed(() => this.skills().map((s, i) => this.skillItemIssues(s, i)), ...(ngDevMode ? [{ debugName: "skillIssuesByIndex" }] : []));
29559
+ toolIssuesByIndex = computed(() => this.tools().map((t, i) => this.toolItemIssues(t, i)), ...(ngDevMode ? [{ debugName: "toolIssuesByIndex" }] : []));
29560
+ // Editor overlay validation based on temporary editor values (so it shows immediately on "Edit")
29561
+ skillFormIssues = computed(() => {
29562
+ const form = this.skillForm();
29563
+ if (!form)
29564
+ return [];
29565
+ const issues = [];
29566
+ if (this.isBlank(form.name))
29567
+ issues.push('Skillset name is required');
29568
+ if (!form.stars || form.stars <= 0)
29569
+ issues.push('Star rating is required');
29570
+ if (form.year === null || form.year === undefined)
29571
+ issues.push('Years of experience is required');
29572
+ return issues;
29573
+ }, ...(ngDevMode ? [{ debugName: "skillFormIssues" }] : []));
29574
+ toolFormIssues = computed(() => {
29575
+ const form = this.toolForm();
29576
+ if (!form)
29577
+ return [];
29578
+ const issues = [];
29579
+ if (this.isBlank(form.name))
29580
+ issues.push('Tool name is required');
29581
+ if (!form.stars || form.stars <= 0)
29582
+ issues.push('Star rating is required');
29583
+ if (form.year === null || form.year === undefined)
29584
+ issues.push('Years of experience is required');
29585
+ return issues;
29586
+ }, ...(ngDevMode ? [{ debugName: "toolFormIssues" }] : []));
29587
+ workSectionHasIssues = computed(() => {
29588
+ return this.workIssuesByIndex().some((x) => x.length > 0);
29589
+ }, ...(ngDevMode ? [{ debugName: "workSectionHasIssues" }] : []));
29590
+ educationSectionHasIssues = computed(() => {
29591
+ return this.educationIssuesByIndex().some((x) => x.length > 0);
29592
+ }, ...(ngDevMode ? [{ debugName: "educationSectionHasIssues" }] : []));
29593
+ certificationsSectionHasIssues = computed(() => {
29594
+ return this.certIssuesByIndex().some((x) => x.length > 0);
29595
+ }, ...(ngDevMode ? [{ debugName: "certificationsSectionHasIssues" }] : []));
29596
+ licensesSectionHasIssues = computed(() => this.licenses().some((_, i) => (this.licenseIssuesByIndex()[i] || []).length > 0), ...(ngDevMode ? [{ debugName: "licensesSectionHasIssues" }] : []));
29597
+ skillsSectionHasIssues = computed(() => this.skillIssuesByIndex().some((x) => x.length > 0), ...(ngDevMode ? [{ debugName: "skillsSectionHasIssues" }] : []));
29598
+ toolsSectionHasIssues = computed(() => this.toolIssuesByIndex().some((x) => x.length > 0), ...(ngDevMode ? [{ debugName: "toolsSectionHasIssues" }] : []));
29599
+ canConfirmAndContinue = computed(() => {
29600
+ return !this.basicSectionHasIssues()
29601
+ && !this.workSectionHasIssues()
29602
+ && !this.educationSectionHasIssues()
29603
+ && !this.certificationsSectionHasIssues()
29604
+ && !this.licensesSectionHasIssues()
29605
+ && !this.skillsSectionHasIssues()
29606
+ && !this.toolsSectionHasIssues();
29607
+ }, ...(ngDevMode ? [{ debugName: "canConfirmAndContinue" }] : []));
29608
+ expandedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "expandedIndex" }] : []));
29609
+ toggleJob(index) {
29610
+ this.expandedIndex.update(current => current === index ? -1 : index);
29611
+ }
29612
+ commitProfile(next) {
29613
+ this.store.setProfile(next);
29614
+ this.resumeData = next;
29615
+ }
29616
+ appendToMainModel(key, value) {
29617
+ const current = this.store.profileSignal();
29618
+ if (!current)
29619
+ return;
29620
+ const list = current[key] ?? [];
29621
+ this.commitProfile({ ...current, [key]: [...list, value] });
29622
+ }
29623
+ updateInMainModel(key, index, value) {
29624
+ const current = this.store.profileSignal();
29625
+ if (!current)
29626
+ return;
29627
+ const list = (current[key] ?? []).map((item, i) => (i === index ? value : item));
29628
+ this.commitProfile({ ...current, [key]: list });
29629
+ }
29630
+ toMonthInput(value) {
29631
+ if (!value)
29632
+ return '';
29633
+ if (typeof value !== 'string')
29634
+ return '';
29635
+ const match = value.match(/^(\d{4})-(\d{2})/);
29636
+ if (match)
29637
+ return value.slice(0, 7); // YYYY-MM
29638
+ // Handle full ISO/date strings
29639
+ const d = new Date(value);
29640
+ if (!isNaN(d.getTime())) {
29641
+ return d.toISOString().slice(0, 7);
29642
+ }
29643
+ return value;
29644
+ }
29645
+ formatMonthYear(value) {
29646
+ if (!value)
29647
+ return '';
29648
+ const match = value.match(/^(\d{4})-(\d{2})/);
29649
+ if (!match)
29650
+ return value;
29651
+ const year = Number(match[1]);
29652
+ const monthIndex = Number(match[2]) - 1;
29653
+ const d = new Date(year, monthIndex, 1);
29654
+ if (isNaN(d.getTime()))
29655
+ return value;
29656
+ return new Intl.DateTimeFormat('en-US', { month: 'long', year: 'numeric' }).format(d);
29657
+ }
29658
+ confirmDelete(message) {
29659
+ return typeof window !== 'undefined' ? window.confirm(message) : true;
29660
+ }
29661
+ // Job
29662
+ jobEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "jobEditor" }] : []));
29663
+ isAddingJob() { return this.jobEditor().mode === 'add'; }
29664
+ editingJobIndex() { return this.jobEditor().mode === 'edit' ? this.jobEditor().index : null; }
29665
+ tempJob() { return this.jobEditor().data; }
29666
+ addJob() {
29667
+ this.jobEditor.set({
29668
+ mode: 'add', index: null, data: {
29669
+ company: '',
29670
+ jobTitle: '',
29671
+ country: '',
29672
+ state: '',
29673
+ city: '',
29674
+ startDate: '',
29675
+ endDate: null,
29676
+ isCurrent: false,
29677
+ responsibilities: [],
29678
+ }
29679
+ });
29680
+ this.expandedIndex.set(-1);
29681
+ }
29682
+ startEditJob(jobIndex) {
29683
+ const current = this.store.profileSignal();
29684
+ const job = current?.workExperience?.[jobIndex];
29685
+ if (!current || !job)
29686
+ return;
29687
+ this.jobEditor.set({
29688
+ mode: 'edit', index: jobIndex, data: {
29689
+ ...job,
29690
+ startDate: this.toMonthInput(job.startDate),
29691
+ endDate: job.endDate ? this.toMonthInput(job.endDate) : null,
29692
+ responsibilities: Array.isArray(job.responsibilities) ? [...job.responsibilities] : []
29693
+ }
29694
+ });
29695
+ this.expandedIndex.set(jobIndex);
29696
+ }
29697
+ cancelEditJob() {
29698
+ this.jobEditor.set({ mode: 'closed', index: null, data: null });
29699
+ }
29700
+ saveEditJob() {
29701
+ const current = this.store.profileSignal();
29702
+ const jobIndex = this.editingJobIndex();
29703
+ const nextJob = this.tempJob();
29704
+ if (!current || !nextJob)
29705
+ return;
29706
+ const next = this.isAddingJob()
29707
+ ? { ...current, workExperience: [...(current.workExperience ?? []), nextJob] }
29708
+ : {
29709
+ ...current,
29710
+ workExperience: current.workExperience.map((j, idx) => (idx === jobIndex ? nextJob : j))
29711
+ };
29712
+ this.commitProfile(next);
29713
+ this.cancelEditJob();
29714
+ }
29715
+ deleteJob(index) {
29716
+ const current = this.store.profileSignal();
29717
+ if (!current?.workExperience?.length)
29718
+ return;
29719
+ if (index < 0 || index >= current.workExperience.length)
29720
+ return;
29721
+ if (!this.confirmDelete('Delete this work experience item?'))
29722
+ return;
29723
+ this.commitProfile({
29724
+ ...current,
29725
+ workExperience: current.workExperience.filter((_, i) => i !== index),
29726
+ });
29727
+ if (this.editingJobIndex() === index)
29728
+ this.cancelEditJob();
29729
+ if (this.expandedIndex() === index)
29730
+ this.expandedIndex.set(-1);
29731
+ }
29732
+ updateTempResponsibilities(value) {
29733
+ const job = this.tempJob();
29734
+ if (!job)
29735
+ return;
29736
+ const responsibilities = value
29737
+ .split('\n')
29738
+ .map(x => x.trim())
29739
+ .filter(Boolean);
29740
+ this.jobEditor.update((e) => ({ ...e, data: { ...job, responsibilities } }));
29741
+ }
29742
+ patchTempJob(patch) {
29743
+ const job = this.tempJob();
29744
+ if (!job)
29745
+ return;
29746
+ this.jobEditor.update((e) => ({ ...e, data: { ...job, ...patch } }));
29747
+ }
29748
+ setTempJobIsCurrent(isCurrent) {
29749
+ const job = this.tempJob();
29750
+ if (!job)
29751
+ return;
29752
+ this.jobEditor.update((e) => ({
29753
+ ...e, data: {
29754
+ ...job,
29755
+ isCurrent,
29756
+ endDate: isCurrent ? null : (job.endDate ?? null)
29757
+ }
29758
+ }));
29759
+ }
29760
+ // Skills editing (per-skill edit panel)
29761
+ skillEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "skillEditor" }] : []));
29762
+ isSkillEditorOpen() { return this.skillEditor().mode !== 'closed'; }
29763
+ isAddingSkill() { return this.skillEditor().mode === 'add'; }
29764
+ editingSkillIndex() { return this.skillEditor().mode === 'edit' ? this.skillEditor().index : null; }
29765
+ skillForm() { return this.skillEditor().data; }
29766
+ patchSkillForm(patch) {
29767
+ const curr = this.skillForm();
29768
+ if (!curr)
29769
+ return;
29770
+ this.skillEditor.update((e) => ({ ...e, data: { ...curr, ...patch } }));
29771
+ }
29772
+ openSkillEditor(index) {
29773
+ const current = this.store.profileSignal();
29774
+ if (!current || !current.skills?.length || index < 0 || index >= current.skills.length)
29775
+ return;
29776
+ const meta = this.store.resumeSkillMeta()?.[index] ?? {};
29777
+ this.skillEditor.set({
29778
+ mode: 'edit',
29779
+ index,
29780
+ data: {
29781
+ name: current.skills[index] ?? '',
29782
+ providerName: meta.providerName ?? '',
29783
+ stars: Math.round((meta.starRating ?? 0) / 2),
29784
+ year: meta.year ?? null,
29785
+ profileVisibility: !!meta.profileVisibility,
29786
+ notes: meta.notes ?? '',
29787
+ }
29788
+ });
29789
+ }
29790
+ addSkill() {
29791
+ this.skillEditor.set({
29792
+ mode: 'add',
29793
+ index: null,
29794
+ data: { name: '', providerName: '', stars: 0, year: null, profileVisibility: false, notes: '' }
29795
+ });
29796
+ }
29797
+ closeSkillEditor() {
29798
+ this.skillEditor.set({ mode: 'closed', index: null, data: null });
29799
+ }
29800
+ setTempSkillStars(stars) {
29801
+ this.patchSkillForm({ stars });
29802
+ }
29803
+ saveSkillEditor() {
29804
+ const current = this.store.profileSignal();
29805
+ const idx = this.editingSkillIndex();
29806
+ if (!current)
29807
+ return;
29808
+ const form = this.skillForm();
29809
+ if (!form)
29810
+ return;
29811
+ const nextName = (form.name || '').trim();
29812
+ if (!nextName)
29813
+ return;
29814
+ if (!form.stars || form.stars <= 0)
29815
+ return;
29816
+ if (form.year === null || form.year === undefined)
29817
+ return;
29818
+ const nextSkills = [...(current.skills ?? [])];
29819
+ if (this.isAddingSkill()) {
29820
+ nextSkills.push(nextName);
29821
+ }
29822
+ else if (idx !== null) {
29823
+ nextSkills[idx] = nextName;
29824
+ }
29825
+ else {
29826
+ return;
29827
+ }
29828
+ if (this.isAddingSkill()) {
29829
+ this.appendToMainModel('skills', nextName);
29830
+ }
29831
+ else if (idx !== null) {
29832
+ this.updateInMainModel('skills', idx, nextName);
29833
+ }
29834
+ const metaIndex = this.isAddingSkill() ? nextSkills.length - 1 : idx;
29835
+ if (metaIndex !== null) {
29836
+ this.store.setResumeSkillMeta(metaIndex, {
29837
+ providerName: (form.providerName || '').trim() || undefined,
29838
+ starRating: (form.stars || 0) * 2,
29839
+ year: form.year,
29840
+ profileVisibility: form.profileVisibility,
29841
+ notes: form.notes,
29842
+ });
29843
+ }
29844
+ this.closeSkillEditor();
29845
+ }
29846
+ reindexSkillMetaAfterDelete(deletedIndex) {
29847
+ const meta = this.store.resumeSkillMeta() ?? {};
29848
+ const next = {};
29849
+ Object.keys(meta).forEach((k) => {
29850
+ const idx = Number(k);
29851
+ if (Number.isNaN(idx))
29852
+ return;
29853
+ if (idx < deletedIndex)
29854
+ next[idx] = meta[idx];
29855
+ else if (idx > deletedIndex)
29856
+ next[idx - 1] = meta[idx];
29857
+ });
29858
+ this.store.resumeSkillMeta.set(next);
29859
+ }
29860
+ deleteSkill(index) {
29861
+ const current = this.store.profileSignal();
29862
+ if (!current?.skills?.length)
29863
+ return;
29864
+ if (index < 0 || index >= current.skills.length)
29865
+ return;
29866
+ if (!this.confirmDelete('Delete this skill?'))
29867
+ return;
29868
+ const nextSkills = current.skills.filter((_, i) => i !== index);
29869
+ this.commitProfile({ ...current, skills: nextSkills });
29870
+ this.reindexSkillMetaAfterDelete(index);
29871
+ if (this.editingSkillIndex() === index)
29872
+ this.closeSkillEditor();
29873
+ }
29874
+ // Tools editing (same popup UX as skills)
29875
+ toolEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "toolEditor" }] : []));
29876
+ isToolEditorOpen() { return this.toolEditor().mode !== 'closed'; }
29877
+ isAddingTool() { return this.toolEditor().mode === 'add'; }
29878
+ editingToolIndex() { return this.toolEditor().mode === 'edit' ? this.toolEditor().index : null; }
29879
+ toolForm() { return this.toolEditor().data; }
29880
+ patchToolForm(patch) {
29881
+ const curr = this.toolForm();
29882
+ if (!curr)
29883
+ return;
29884
+ this.toolEditor.update((e) => ({ ...e, data: { ...curr, ...patch } }));
29885
+ }
29886
+ openToolEditor(index) {
29887
+ const current = this.store.profileSignal();
29888
+ if (!current || !current.tools?.length || index < 0 || index >= current.tools.length)
29889
+ return;
29890
+ const meta = this.store.resumeToolMeta()?.[index] ?? {};
29891
+ this.toolEditor.set({
29892
+ mode: 'edit',
29893
+ index,
29894
+ data: {
29895
+ name: current.tools[index] ?? '',
29896
+ providerName: meta.providerName ?? '',
29897
+ stars: Math.round((meta.starRating ?? 0) / 2),
29898
+ year: meta.year ?? null,
29899
+ profileVisibility: !!meta.profileVisibility,
29900
+ notes: meta.notes ?? '',
29901
+ }
29902
+ });
29903
+ }
29904
+ addTool() {
29905
+ this.toolEditor.set({
29906
+ mode: 'add',
29907
+ index: null,
29908
+ data: { name: '', providerName: '', stars: 0, year: null, profileVisibility: false, notes: '' }
29909
+ });
29910
+ }
29911
+ closeToolEditor() {
29912
+ this.toolEditor.set({ mode: 'closed', index: null, data: null });
29913
+ }
29914
+ setTempToolStars(stars) {
29915
+ this.patchToolForm({ stars });
29916
+ }
29917
+ saveToolEditor() {
29918
+ const current = this.store.profileSignal();
29919
+ const idx = this.editingToolIndex();
29920
+ if (!current)
29921
+ return;
29922
+ const form = this.toolForm();
29923
+ if (!form)
29924
+ return;
29925
+ const nextName = (form.name || '').trim();
29926
+ if (!nextName)
29927
+ return;
29928
+ if (!form.stars || form.stars <= 0)
29929
+ return;
29930
+ if (form.year === null || form.year === undefined)
29931
+ return;
29932
+ const nextTools = [...(current.tools ?? [])];
29933
+ if (this.isAddingTool()) {
29934
+ nextTools.push(nextName);
29935
+ }
29936
+ else if (idx !== null) {
29937
+ nextTools[idx] = nextName;
29938
+ }
29939
+ else {
29940
+ return;
29941
+ }
29942
+ if (this.isAddingTool()) {
29943
+ this.appendToMainModel('tools', nextName);
29944
+ }
29945
+ else if (idx !== null) {
29946
+ this.updateInMainModel('tools', idx, nextName);
29947
+ }
29948
+ const metaIndex = this.isAddingTool() ? nextTools.length - 1 : idx;
29949
+ if (metaIndex !== null) {
29950
+ this.store.setResumeToolMeta(metaIndex, {
29951
+ providerName: (form.providerName || '').trim() || undefined,
29952
+ starRating: (form.stars || 0) * 2,
29953
+ year: form.year,
29954
+ profileVisibility: form.profileVisibility,
29955
+ notes: form.notes,
29956
+ });
29957
+ }
29958
+ this.closeToolEditor();
29959
+ }
29960
+ reindexToolMetaAfterDelete(deletedIndex) {
29961
+ const meta = this.store.resumeToolMeta() ?? {};
29962
+ const next = {};
29963
+ Object.keys(meta).forEach((k) => {
29964
+ const idx = Number(k);
29965
+ if (Number.isNaN(idx))
29966
+ return;
29967
+ if (idx < deletedIndex)
29968
+ next[idx] = meta[idx];
29969
+ else if (idx > deletedIndex)
29970
+ next[idx - 1] = meta[idx];
29971
+ });
29972
+ this.store.resumeToolMeta.set(next);
29973
+ }
29974
+ deleteTool(index) {
29975
+ const current = this.store.profileSignal();
29976
+ if (!current?.tools?.length)
29977
+ return;
29978
+ if (index < 0 || index >= current.tools.length)
29979
+ return;
29980
+ if (!this.confirmDelete('Delete this tool?'))
29981
+ return;
29982
+ const nextTools = current.tools.filter((_, i) => i !== index);
29983
+ this.commitProfile({ ...current, tools: nextTools });
29984
+ this.reindexToolMetaAfterDelete(index);
29985
+ if (this.editingToolIndex() === index)
29986
+ this.closeToolEditor();
29987
+ }
29988
+ // Certifications editing
29989
+ certificationEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "certificationEditor" }] : []));
29990
+ isAddingCertification() { return this.certificationEditor().mode === 'add'; }
29991
+ editingCertificationIndex() { return this.certificationEditor().mode === 'edit' ? this.certificationEditor().index : null; }
29992
+ tempCertification() { return this.certificationEditor().data; }
29993
+ normalizeNullableString(value) {
29994
+ const v = value?.trim();
29995
+ return v ? v : null;
29996
+ }
29997
+ normalizeMonthInput(value) {
29998
+ const v = value?.trim();
29999
+ if (!v)
30000
+ return null;
30001
+ return this.toMonthInput(v) || null;
30002
+ }
30003
+ addCertification() {
30004
+ this.certificationEditor.set({
30005
+ mode: 'add', index: null, data: {
30006
+ name: '',
30007
+ issuingOrganization: null,
30008
+ state: null,
30009
+ issueDate: null,
30010
+ expiryDate: null,
30011
+ credentialId: null,
30012
+ }
30013
+ });
30014
+ }
30015
+ startEditCertification(index) {
30016
+ const current = this.store.profileSignal();
30017
+ const cert = current?.certifications?.[index];
30018
+ if (!current || !cert)
30019
+ return;
30020
+ this.certificationEditor.set({
30021
+ mode: 'edit', index, data: {
30022
+ ...cert,
30023
+ issueDate: this.normalizeMonthInput(cert.issueDate),
30024
+ expiryDate: this.normalizeMonthInput(cert.expiryDate),
30025
+ }
30026
+ });
30027
+ }
30028
+ cancelEditCertification() {
30029
+ this.certificationEditor.set({ mode: 'closed', index: null, data: null });
30030
+ }
30031
+ patchTempCertification(patch) {
30032
+ const cert = this.tempCertification();
30033
+ if (!cert)
30034
+ return;
30035
+ this.certificationEditor.update((e) => ({ ...e, data: { ...cert, ...patch } }));
30036
+ }
30037
+ saveCertificationEditor() {
30038
+ const current = this.store.profileSignal();
30039
+ const idx = this.editingCertificationIndex();
30040
+ const nextCert = this.tempCertification();
30041
+ if (!current || !nextCert)
30042
+ return;
30043
+ const name = this.normalizeNullableString(nextCert.name);
30044
+ if (!name)
30045
+ return;
30046
+ const normalized = {
30047
+ ...nextCert,
30048
+ name,
30049
+ issuingOrganization: this.normalizeNullableString(nextCert.issuingOrganization),
30050
+ state: this.normalizeNullableString(nextCert.state),
30051
+ credentialId: this.normalizeNullableString(nextCert.credentialId),
30052
+ issueDate: this.normalizeMonthInput(nextCert.issueDate),
30053
+ expiryDate: this.normalizeMonthInput(nextCert.expiryDate),
30054
+ };
30055
+ if (this.isAddingCertification())
30056
+ this.appendToMainModel('certifications', normalized);
30057
+ else if (idx !== null)
30058
+ this.updateInMainModel('certifications', idx, normalized);
30059
+ this.cancelEditCertification();
30060
+ }
30061
+ deleteCertification(index) {
30062
+ const current = this.store.profileSignal();
30063
+ if (!current?.certifications?.length)
30064
+ return;
30065
+ if (index < 0 || index >= current.certifications.length)
30066
+ return;
30067
+ if (!this.confirmDelete('Delete this certification?'))
30068
+ return;
30069
+ this.commitProfile({
30070
+ ...current,
30071
+ certifications: current.certifications.filter((_, i) => i !== index),
30072
+ });
30073
+ if (this.editingCertificationIndex() === index)
30074
+ this.cancelEditCertification();
30075
+ }
30076
+ // Licenses editing
30077
+ licenseEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "licenseEditor" }] : []));
30078
+ isAddingLicense() { return this.licenseEditor().mode === 'add'; }
30079
+ editingLicenseIndex() { return this.licenseEditor().mode === 'edit' ? this.licenseEditor().index : null; }
30080
+ tempLicense() { return this.licenseEditor().data; }
30081
+ addLicense() {
30082
+ this.licenseEditor.set({
30083
+ mode: 'add', index: null, data: {
30084
+ name: '',
30085
+ issuingAuthority: null,
30086
+ licenseNumber: null,
30087
+ state: null,
30088
+ issueDate: null,
30089
+ expiryDate: null,
30090
+ }
30091
+ });
30092
+ }
30093
+ startEditLicense(index) {
30094
+ const current = this.store.profileSignal();
30095
+ const lic = current?.licenses?.[index];
30096
+ if (!current || !lic)
30097
+ return;
30098
+ this.licenseEditor.set({
30099
+ mode: 'edit', index, data: {
30100
+ ...lic,
30101
+ issueDate: this.normalizeMonthInput(lic.issueDate),
30102
+ expiryDate: this.normalizeMonthInput(lic.expiryDate),
30103
+ }
30104
+ });
30105
+ }
30106
+ cancelEditLicense() {
30107
+ this.licenseEditor.set({ mode: 'closed', index: null, data: null });
30108
+ }
30109
+ patchTempLicense(patch) {
30110
+ const lic = this.tempLicense();
30111
+ if (!lic)
30112
+ return;
30113
+ this.licenseEditor.update((e) => ({ ...e, data: { ...lic, ...patch } }));
30114
+ }
30115
+ saveLicenseEditor() {
30116
+ const current = this.store.profileSignal();
30117
+ const idx = this.editingLicenseIndex();
30118
+ const nextLic = this.tempLicense();
30119
+ if (!current || !nextLic)
30120
+ return;
30121
+ const name = this.normalizeNullableString(nextLic.name);
30122
+ if (!name)
30123
+ return;
30124
+ const normalized = {
30125
+ ...nextLic,
30126
+ name,
30127
+ issuingAuthority: this.normalizeNullableString(nextLic.issuingAuthority),
30128
+ licenseNumber: this.normalizeNullableString(nextLic.licenseNumber),
30129
+ state: this.normalizeNullableString(nextLic.state),
30130
+ issueDate: this.normalizeMonthInput(nextLic.issueDate),
30131
+ expiryDate: this.normalizeMonthInput(nextLic.expiryDate),
30132
+ };
30133
+ if (this.isAddingLicense())
30134
+ this.appendToMainModel('licenses', normalized);
30135
+ else if (idx !== null)
30136
+ this.updateInMainModel('licenses', idx, normalized);
30137
+ this.cancelEditLicense();
30138
+ }
30139
+ deleteLicense(index) {
30140
+ const current = this.store.profileSignal();
30141
+ if (!current?.licenses?.length)
30142
+ return;
30143
+ if (index < 0 || index >= current.licenses.length)
30144
+ return;
30145
+ if (!this.confirmDelete('Delete this license?'))
30146
+ return;
30147
+ this.commitProfile({
30148
+ ...current,
30149
+ licenses: current.licenses.filter((_, i) => i !== index),
30150
+ });
30151
+ if (this.editingLicenseIndex() === index)
30152
+ this.cancelEditLicense();
30153
+ }
30154
+ // Education editing
30155
+ educationEditor = signal({ mode: 'closed', index: null, data: null }, ...(ngDevMode ? [{ debugName: "educationEditor" }] : []));
30156
+ isAddingEducation() { return this.educationEditor().mode === 'add'; }
30157
+ editingEducationIndex() { return this.educationEditor().mode === 'edit' ? this.educationEditor().index : null; }
30158
+ tempEducation() { return this.educationEditor().data; }
30159
+ addEducation() {
30160
+ this.educationEditor.set({
30161
+ mode: 'add', index: null, data: {
30162
+ degree: '',
30163
+ degreeType: '',
30164
+ institution: '',
30165
+ country: '',
30166
+ state: '',
30167
+ city: '',
30168
+ startDate: '',
30169
+ endDate: '',
30170
+ achievements: [],
30171
+ }
30172
+ });
30173
+ }
30174
+ startEditEducation(index) {
30175
+ const current = this.store.profileSignal();
30176
+ const edu = current?.education?.[index];
30177
+ if (!current || !edu)
30178
+ return;
30179
+ this.educationEditor.set({
30180
+ mode: 'edit', index, data: {
30181
+ ...edu,
30182
+ startDate: this.toMonthInput(edu.startDate),
30183
+ endDate: this.toMonthInput(edu.endDate),
30184
+ achievements: Array.isArray(edu.achievements) ? [...edu.achievements] : [],
30185
+ }
30186
+ });
30187
+ }
30188
+ cancelEditEducation() {
30189
+ this.educationEditor.set({ mode: 'closed', index: null, data: null });
30190
+ }
30191
+ patchTempEducation(patch) {
30192
+ const edu = this.tempEducation();
30193
+ if (!edu)
30194
+ return;
30195
+ this.educationEditor.update((e) => ({ ...e, data: { ...edu, ...patch } }));
30196
+ }
30197
+ saveEducation() {
30198
+ const current = this.store.profileSignal();
30199
+ const idx = this.editingEducationIndex();
30200
+ const nextEdu = this.tempEducation();
30201
+ if (!current || !nextEdu)
30202
+ return;
30203
+ if (this.isAddingEducation())
30204
+ this.appendToMainModel('education', nextEdu);
30205
+ else if (idx !== null)
30206
+ this.updateInMainModel('education', idx, nextEdu);
30207
+ else
30208
+ return;
30209
+ this.cancelEditEducation();
30210
+ }
30211
+ deleteEducation(index) {
30212
+ const current = this.store.profileSignal();
30213
+ if (!current?.education?.length)
30214
+ return;
30215
+ if (index < 0 || index >= current.education.length)
30216
+ return;
30217
+ if (!this.confirmDelete('Delete this education item?'))
30218
+ return;
30219
+ this.commitProfile({
30220
+ ...current,
30221
+ education: current.education.filter((_, i) => i !== index),
30222
+ });
30223
+ if (this.editingEducationIndex() === index)
30224
+ this.cancelEditEducation();
30225
+ }
30226
+ onBackClick() {
30227
+ this.showBackConfirmPopup = true;
30228
+ }
30229
+ stayOnPreview() {
30230
+ this.showBackConfirmPopup = false;
30231
+ }
30232
+ closeSavePopup() {
30233
+ this.showPopup = false;
30234
+ }
30235
+ allSaveStepsSucceeded() {
30236
+ return this.statusList.length > 0 && this.statusList.every((x) => x.status === 'success');
30237
+ }
30238
+ goToDashboard() {
30239
+ this.showPopup = false;
30240
+ this.router.navigateByUrl('/dashboard');
30241
+ }
30242
+ proceedBack() {
30243
+ this.showBackConfirmPopup = false;
30244
+ this.backToParent.emit();
30245
+ this.store.currentStep.set(1);
30246
+ }
30247
+ tempProfile;
30248
+ isEditMode = signal(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
30249
+ toggleEdit() {
30250
+ const currentDetails = this.details();
30251
+ if (currentDetails) {
30252
+ this.tempProfile = { ...currentDetails }; // Deep copy for editing
30253
+ this.isEditMode.set(true);
30254
+ }
30255
+ }
30256
+ cancel() {
30257
+ this.isEditMode.set(false);
30258
+ }
30259
+ save() {
30260
+ this.details.update(() => ({ ...this.tempProfile }));
30261
+ this.isEditMode.set(false);
30262
+ const current = this.store.profileSignal();
30263
+ if (!current)
30264
+ return;
30265
+ this.commitProfile({ ...current, basicDetails: { ...this.tempProfile } });
30266
+ }
30267
+ saveResumedetails() {
30268
+ this.showPopup = true;
30269
+ const rawSteps = [
30270
+ {
30271
+ name: 'Basic Details',
30272
+ type: 'single',
30273
+ call: () => {
30274
+ const payload = this.mapBasicDetailsToUserDetail(this.resumeData);
30275
+ return this.userDetailService.initialSetUpCreateUserDetail(payload);
30276
+ }
30277
+ },
30278
+ {
30279
+ name: 'Work Experience',
30280
+ type: 'multiple',
30281
+ data: this.mapWorkExperience(this.resumeData),
30282
+ call: (item) => this.userExperienceService.createUserExperience(item)
30283
+ },
30284
+ {
30285
+ name: 'Education',
30286
+ type: 'multiple',
30287
+ data: this.mapEducation(this.resumeData),
30288
+ call: (item) => this.userEducation.createUserEducation(item)
30289
+ },
30290
+ {
30291
+ name: 'Certification',
30292
+ type: 'multiple',
30293
+ data: this.mapCertifications(this.resumeData),
30294
+ call: (item) => this.userDocumentService.createUserDocument(item)
30295
+ },
30296
+ {
30297
+ name: 'License',
30298
+ type: 'multiple',
30299
+ data: this.mapLicenses(this.resumeData),
30300
+ call: (item) => this.userDocumentService.createUserDocument(item)
30301
+ },
30302
+ {
30303
+ name: 'Skills',
30304
+ type: 'batch',
30305
+ data: this.mapSkills(this.resumeData),
30306
+ call: (items) => this.userSkillSetService.createUserSkillSet(items)
30307
+ },
30308
+ {
30309
+ name: 'Tools',
30310
+ type: 'batch',
30311
+ data: this.mapTools(this.resumeData),
30312
+ call: (items) => this.userToolService.createUserTool(items)
30313
+ }
30314
+ ];
30315
+ // Skip empty sections and continue with available ones.
30316
+ const steps = rawSteps.filter((step) => {
30317
+ if (step.type === 'multiple' || step.type === 'batch') {
30318
+ return Array.isArray(step.data) && step.data.length > 0;
30319
+ }
30320
+ return true;
30321
+ });
30322
+ this.statusList = [];
30323
+ from(steps)
30324
+ .pipe(concatMap((step) => {
30325
+ const stepStatus = {
30326
+ name: step.name,
30327
+ status: 'pending',
30328
+ successCount: 0,
30329
+ failCount: 0
30330
+ };
30331
+ this.statusList.push(stepStatus);
30332
+ // ✅ SINGLE API
30333
+ if (step.type === 'single') {
30334
+ return step.call(null).pipe(tap$1((res) => {
30335
+ if (res?.failed) {
30336
+ stepStatus.status = 'error';
30337
+ stepStatus.error = res.message;
30338
+ }
30339
+ else {
30340
+ stepStatus.status = 'success';
30341
+ }
30342
+ }), catchError((err) => {
30343
+ stepStatus.status = 'error';
30344
+ stepStatus.error = err.message;
30345
+ return of(null); // 🔥 continue flow
30346
+ }));
30347
+ }
30348
+ if (step.type === 'batch') {
30349
+ return step.call(step.data).pipe(tap$1((res) => {
30350
+ if (res?.failed) {
30351
+ stepStatus.status = 'error';
30352
+ stepStatus.error = res.message;
30353
+ }
30354
+ else {
30355
+ stepStatus.status = 'success';
30356
+ stepStatus.successCount = step.data?.length ?? 0;
30357
+ }
30358
+ }), catchError((err) => {
30359
+ stepStatus.status = 'error';
30360
+ stepStatus.error = err.message;
30361
+ return of(null);
30362
+ }));
30363
+ }
30364
+ // ✅ MULTIPLE LOOP (like 2 work experiences)
30365
+ return from(step.data).pipe(concatMap((item) => step.call(item).pipe(tap$1((res) => {
30366
+ if (res?.failed) {
30367
+ stepStatus.failCount++;
30368
+ }
30369
+ else {
30370
+ stepStatus.successCount++;
30371
+ }
30372
+ }), catchError(() => {
30373
+ stepStatus.failCount++;
30374
+ return of(null); // 🔥 continue next item
30375
+ }))), tap$1(() => {
30376
+ // final step status
30377
+ if (stepStatus.failCount > 0) {
30378
+ stepStatus.status = 'partial'; // 🔥 mixed result
30379
+ }
30380
+ else {
30381
+ stepStatus.status = 'success';
30382
+ }
30383
+ }), catchError(() => of(null)) // 🔥 safety
30384
+ );
30385
+ }))
30386
+ .subscribe({
30387
+ complete: () => {
30388
+ console.log('All steps completed (with possible errors)');
30389
+ }
30390
+ });
30391
+ }
30392
+ mapBasicDetailsToUserDetail(data) {
30393
+ const basic = data.basicDetails;
30394
+ this.email = data.email;
30395
+ const jobTitle = (basic?.jobTitle ?? '').toString().trim() || 'Drone Pilot';
30396
+ return {
30397
+ providerName: "AdjusterMatch",
30398
+ providerId: "00000000-0000-0000-0000-000000000000",
30399
+ UserRoleId: "673eacad-8447-4004-8e59-0d5a21f0838b",
30400
+ userDetail: {
30401
+ userBio: basic.summary || "",
30402
+ firstName: basic.firstName,
30403
+ lastName: basic.lastName,
30404
+ email: basic.email,
30405
+ address1: basic.address,
30406
+ address2: "",
30407
+ city: basic.city,
30408
+ state: basic.state,
30409
+ zipcode: basic.zipCode,
30410
+ county: "", // you don’t have this → keep empty or derive
30411
+ country: basic.country,
30412
+ latitude: null, // optional (if using Google API later)
30413
+ longitude: null,
30414
+ yearsActive: 0,
30415
+ isInitialSetupCompleted: false,
30416
+ id: this.payloadUserId,
30417
+ phoneNumber: basic.phone,
30418
+ yearsOfExperince: basic.yearsOfExperience,
30419
+ userJobTitle: [jobTitle],
30420
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
30421
+ datePattern: new Date().toLocaleDateString(),
30422
+ dateTimePattern: new Date().toLocaleString(),
30423
+ timePattern: new Date().toLocaleTimeString()
30424
+ }
30425
+ };
30426
+ }
30427
+ mapWorkExperience(data) {
30428
+ return data.workExperience.map((exp) => {
30429
+ return {
30430
+ id: "00000000-0000-0000-0000-000000000000",
30431
+ providerName: "AdjusterMatch",
30432
+ providerId: "00000000-0000-0000-0000-000000000000",
30433
+ userId: this.payloadUserId,
30434
+ userName: this.payloadUserName,
30435
+ companyName: exp.company,
30436
+ jobTitle: exp.jobTitle,
30437
+ country: exp.country,
30438
+ state: exp.state,
30439
+ city: exp.city,
30440
+ fromDate: this.formatDate(exp.startDate),
30441
+ toDate: exp.isCurrent ? null : this.formatDate(exp.endDate),
30442
+ jobDescription: exp.responsibilities?.join(', ') || "",
30443
+ fileId: null,
30444
+ fileUrl: null,
30445
+ fileName: null,
30446
+ reviewStatus: 2
30447
+ };
30448
+ });
30449
+ }
30450
+ mapEducation(data) {
30451
+ return data.education.map((exp) => {
30452
+ return {
30453
+ id: "00000000-0000-0000-0000-000000000000",
30454
+ providerName: "AdjusterMatch",
30455
+ providerId: "00000000-0000-0000-0000-000000000000",
30456
+ userId: this.payloadUserId,
30457
+ userName: this.payloadUserName,
30458
+ courseName: exp.degree,
30459
+ courseType: exp.degreeType,
30460
+ instituteName: exp.institution,
30461
+ country: exp.country,
30462
+ reviewComments: "N/A",
30463
+ state: exp.state,
30464
+ city: exp.city,
30465
+ startDate: this.formatDate(exp.startDate),
30466
+ endDate: this.formatDate(exp.endDate),
30467
+ comments: exp.achievements[0],
30468
+ reviewStatus: 2
30469
+ };
30470
+ });
30471
+ }
30472
+ mapCertifications(data) {
30473
+ const emailId = data?.basicDetails?.email ?? null;
30474
+ return data.certifications.map((exp) => {
30475
+ return {
30476
+ id: "00000000-0000-0000-0000-000000000000",
30477
+ providerName: "InspectorMatch",
30478
+ userId: this.payloadUserId,
30479
+ userName: this.payloadUserName,
30480
+ issuedState: exp.state,
30481
+ number: "Certificate",
30482
+ issuedBy: exp.issuingOrganization,
30483
+ documentTypeName: exp.name,
30484
+ issueDate: this.formatDate(exp.issueDate),
30485
+ expiryDate: this.formatDate(exp.expiryDate),
30486
+ status: 2,
30487
+ mainType: 2,
30488
+ emailId,
30489
+ forUser: 2,
30490
+ isPrimary: false,
30491
+ profileVisibility: true,
30492
+ notify: true,
30493
+ nationwide: false
30494
+ };
30495
+ });
30496
+ }
30497
+ mapLicenses(data) {
30498
+ const emailId = data?.basicDetails?.email ?? null;
30499
+ return data.licenses.map((exp) => {
30500
+ return {
30501
+ id: "00000000-0000-0000-0000-000000000000",
30502
+ providerName: "InspectorMatch",
30503
+ userId: this.payloadUserId,
30504
+ userName: this.payloadUserName,
30505
+ number: "License",
30506
+ issuedState: exp.state,
30507
+ emailId,
30508
+ issuedBy: exp.issuingAuthority,
30509
+ documentTypeName: exp.name,
30510
+ issueDate: this.formatDate(exp.issueDate),
30511
+ expiryDate: this.formatDate(exp.expiryDate),
30512
+ status: 2,
30513
+ mainType: 1,
30514
+ forUser: 2,
30515
+ isPrimary: false,
30516
+ profileVisibility: true,
30517
+ notify: true,
30518
+ nationwide: false
30519
+ };
30520
+ });
30521
+ }
30522
+ mapSkills(data) {
30523
+ const emailId = data?.basicDetails?.email ?? null;
30524
+ const phoneNumber = data?.basicDetails?.phone ?? '';
30525
+ const meta = this.store.resumeSkillMeta?.() ?? {};
30526
+ return (data?.skills ?? []).map((exp, index) => {
30527
+ const m = meta[index] ?? {};
30528
+ return {
30529
+ forUser: 2,
30530
+ providerId: "00000000-0000-0000-0000-000000000000",
30531
+ providerName: "AdjusterMatch",
30532
+ userId: this.payloadUserId,
30533
+ userName: this.payloadUserName,
30534
+ skillSetId: null,
30535
+ skillSetName: exp,
30536
+ notes: m.notes ?? "",
30537
+ year: m.year ?? null,
30538
+ starRating: m.starRating ?? null,
30539
+ profileVisibility: !!m.profileVisibility,
30540
+ status: 2,
30541
+ emailId,
30542
+ phoneNumber,
30543
+ userHeadShotUrl: ""
30544
+ };
30545
+ });
30546
+ }
30547
+ mapTools(data) {
30548
+ const emailId = data?.basicDetails?.email ?? null;
30549
+ const meta = this.store.resumeToolMeta?.() ?? {};
30550
+ return (data?.tools ?? []).map((exp, index) => {
30551
+ const m = meta[index] ?? {};
30552
+ return {
30553
+ forUser: 2,
30554
+ providerId: "00000000-0000-0000-0000-000000000000",
30555
+ providerName: "AdjusterMatch",
30556
+ userId: this.payloadUserId,
30557
+ userName: this.payloadUserName,
30558
+ toolId: null,
30559
+ toolName: exp,
30560
+ starRating: m.starRating ?? null,
30561
+ year: m.year ?? null,
30562
+ make: null,
30563
+ model: null,
30564
+ serialNumber: null,
30565
+ reviewBy: null,
30566
+ reviewByName: null,
30567
+ reviewDateTime: "",
30568
+ notes: m.notes ?? "",
30569
+ profileVisibility: !!m.profileVisibility,
30570
+ status: 2,
30571
+ emailId,
30572
+ };
30573
+ });
30574
+ }
30575
+ formatDate(date) {
30576
+ if (!date)
30577
+ return null;
30578
+ // input: "2021-01"
30579
+ const d = new Date(date + "-01"); // add day
30580
+ return d.toISOString();
30581
+ }
30582
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PreviewComponent, deps: [{ token: CredentialingStore }, { token: UserSkillSetService }, { token: UserToolService }, { token: UserDocumentService }, { token: UserEducationService }, { token: UserDetailService }, { token: UserExperienceService }, { token: i2.Router }, { token: i6.TokenService }], target: i0.ɵɵFactoryTarget.Component });
30583
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: PreviewComponent, isStandalone: false, selector: "app-preview", outputs: { backToParent: "backToParent" }, ngImport: i0, template: "\r\n<div class=\"preview-page-header\">\r\n <h2 class=\"preview-title\">Confirm based on your resume</h2>\r\n <p class=\"preview-subtitle\">Please confirm everything is accurate. It is based on your resume</p>\r\n</div>\r\n\r\n\r\n<div class=\"container py-4\">\r\n <div class=\"section mb-5\">\r\n <div *ngIf=\"details() as data; else loading\">\r\n <div class=\"card shadow-sm border-0\" *ngIf=\"!isEditMode()\">\r\n <div class=\"card-body p-4\">\r\n <div class=\"d-flex justify-content-between align-items-start mb-4\">\r\n <div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h2 class=\"fw-bold mb-1\">{{ data.firstName }} {{ data.lastName }}</h2>\r\n <span *ngIf=\"basicSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <p class=\"text-muted\">{{ data.jobTitle }} \u2022 {{ data.yearsOfExperience }} Years Exp.</p>\r\n <div *ngIf=\"basicIssues().length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ basicIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n <span class=\"badge bg-primary-subtle text-primary border p-2\">ID: Verified</span>\r\n </div>\r\n\r\n <div class=\"row g-4\">\r\n <div class=\"col-12 border-bottom pb-2\">\r\n <h6 class=\"text-uppercase small fw-bold text-muted\">Summary</h6>\r\n <p class=\"text-secondary small mb-0\">{{ data.summary }}</p>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">EMAIL</label>\r\n <span class=\"fw-bold small\">{{ data.email }}</span>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">PHONE</label>\r\n <span class=\"fw-bold small\">{{ data.phone }}</span>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">LOCATION</label>\r\n <span class=\"small\">{{ data.address }},{{ data.city }},{{ data.state }},{{ data.zipCode }}, {{\r\n data.country }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-light text-end\">\r\n <button class=\"btn btn-sm btn-primary px-4\" (click)=\"toggleEdit()\">Edit Details</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card shadow-sm border-0\" *ngIf=\"isEditMode()\">\r\n <div class=\"card-header bg-white fw-bold\">Update Profile</div>\r\n <div class=\"card-body p-4\">\r\n <form class=\"row g-3\" #basicForm=\"ngForm\" novalidate>\r\n <div *ngIf=\"basicIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ basicIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">First Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.firstName\"\r\n name=\"fName\"\r\n placeholder=\"First Name\"\r\n required\r\n #fName=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"fName.invalid && (fName.dirty || fName.touched)\">First name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Last Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.lastName\"\r\n name=\"lName\"\r\n placeholder=\"Last Name\"\r\n required\r\n #lName=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"lName.invalid && (lName.dirty || lName.touched)\">Last name is required</div>\r\n </div>\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Summary</label>\r\n <textarea class=\"form-control\" rows=\"3\" [(ngModel)]=\"tempProfile.summary\" name=\"sum\"\r\n placeholder=\"Summary\"></textarea>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Email <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"email\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.email\"\r\n name=\"email\"\r\n placeholder=\"Email\"\r\n required\r\n email\r\n #email=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"email.invalid && (email.dirty || email.touched)\">\r\n <span *ngIf=\"email.errors?.['required']\">Email is required</span>\r\n <span *ngIf=\"email.errors?.['email']\">Email format is invalid</span>\r\n </div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Phone Number <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"tempProfile.phone\"\r\n (ngModelChange)=\"tempProfile.phone = sanitizePhone($event)\"\r\n name=\"phone\"\r\n placeholder=\"Phone (10 digits)\"\r\n required\r\n pattern=\"^\\d{10}$\"\r\n maxlength=\"10\"\r\n inputmode=\"numeric\"\r\n #phone=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"phone.invalid && (phone.dirty || phone.touched)\">\r\n <span *ngIf=\"phone.errors?.['required']\">Phone number is required</span>\r\n <span *ngIf=\"phone.errors?.['pattern']\">Phone number must be 10 digits</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-md-3\">\r\n <label class=\"small text-muted d-block\">Home Address <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.address\"\r\n name=\"address\"\r\n placeholder=\"Home Address\"\r\n required\r\n #address=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"address.invalid && (address.dirty || address.touched)\">Home address is required</div>\r\n </div>\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">City <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.city\"\r\n name=\"city\"\r\n placeholder=\"City\"\r\n required\r\n #city=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"city.invalid && (city.dirty || city.touched)\">City is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">State <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.state\"\r\n name=\"state\"\r\n placeholder=\"State\"\r\n required\r\n #state=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"state.invalid && (state.dirty || state.touched)\">State is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">Zip Code <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.zipCode\"\r\n name=\"zipCode\"\r\n placeholder=\"Zip Code\"\r\n required\r\n #zipCode=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"zipCode.invalid && (zipCode.dirty || zipCode.touched)\">Zip code is required</div>\r\n </div>\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">Country <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.country\"\r\n name=\"country\"\r\n placeholder=\"Country\"\r\n required\r\n #country=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"country.invalid && (country.dirty || country.touched)\">Country is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Job Title <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.jobTitle\"\r\n name=\"jobTitle\"\r\n placeholder=\"Job Title\"\r\n required\r\n #jobTitle=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"jobTitle.invalid && (jobTitle.dirty || jobTitle.touched)\">Job title is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.yearsOfExperience\"\r\n name=\"yearsOfExperience\"\r\n placeholder=\"Years of Experience\"\r\n required\r\n min=\"0\"\r\n #yearsOfExperience=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"yearsOfExperience.invalid && (yearsOfExperience.dirty || yearsOfExperience.touched)\">\r\n Years of experience is required\r\n </div>\r\n </div>\r\n\r\n\r\n </form>\r\n </div>\r\n <div class=\"card-footer bg-light text-end gap-2 d-flex justify-content-end\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancel()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"save()\">Save Changes</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Work Experience</h5>\r\n <span *ngIf=\"workSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add work experience\"\r\n (click)=\"addJob()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"experience().length === 0 && !isAddingJob()\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one work experience.</div>\r\n </div>\r\n <div class=\"list-group list-group-flush shadow-sm rounded\">\r\n <div *ngIf=\"isAddingJob() && tempJob()\" class=\"list-group-item p-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">JOB TITLE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.jobTitle\"\r\n (ngModelChange)=\"patchTempJob({ jobTitle: $event })\"\r\n name=\"newJobTitle\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">COMPANY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.company\"\r\n (ngModelChange)=\"patchTempJob({ company: $event })\"\r\n name=\"newCompany\"\r\n />\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">CITY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.city\"\r\n (ngModelChange)=\"patchTempJob({ city: $event })\"\r\n name=\"newCity\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.city)\">City is required</div>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.startDate\"\r\n (ngModelChange)=\"patchTempJob({ startDate: $event })\"\r\n name=\"newStartDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [disabled]=\"tempJob()?.isCurrent\"\r\n [ngModel]=\"tempJob()?.endDate\"\r\n (ngModelChange)=\"patchTempJob({ endDate: $event })\"\r\n name=\"newEndDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isBlank(tempJob()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isMonthRangeInvalid(tempJob()?.startDate, tempJob()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n <div class=\"col-md-4 d-flex align-items-end\">\r\n <div class=\"form-check\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"tempJob()?.isCurrent\"\r\n (ngModelChange)=\"setTempJobIsCurrent($event)\"\r\n name=\"newIsCurrent\"\r\n id=\"newIsCurrent\"\r\n />\r\n <label class=\"form-check-label\" for=\"newIsCurrent\">Current</label>\r\n </div>\r\n </div>\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">RESPONSIBILITIES (one per line)</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"(tempJob()?.responsibilities || []).join('\\n')\"\r\n (ngModelChange)=\"updateTempResponsibilities($event)\"\r\n name=\"newResponsibilities\"\r\n ></textarea>\r\n </div>\r\n </form>\r\n <div class=\"card-footer bg-light text-end mt-3\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditJob(); $event.stopPropagation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEditJob(); $event.stopPropagation()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let job of experience(); let i = index\" class=\"list-group-item p-3\">\r\n\r\n <div class=\"d-flex justify-content-between align-items-center\">\r\n <div class=\"d-flex align-items-center cursor-pointer flex-grow-1\" (click)=\"toggleJob(i)\">\r\n <i class=\"bi bi-briefcase text-primary me-3 fs-4\"></i>\r\n <div>\r\n <h6 class=\"mb-0 fw-bold\">{{ job.jobTitle }}</h6>\r\n <small class=\"text-muted\">\r\n {{ job.company }} \u2022 {{ formatMonthYear(job.startDate) }} - {{ job.isCurrent ? 'Present' : formatMonthYear(job.endDate) }}\r\n </small>\r\n <div\r\n *ngIf=\"editingJobIndex() !== i && (workIssuesByIndex()[i] || []).length > 0\"\r\n class=\"alert alert-warning py-1 px-2 mt-2\"\r\n >\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (workIssuesByIndex()[i] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"d-flex align-items-center gap-2\">\r\n \r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditJob(i)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteJob(i);\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n \r\n\r\n <!-- <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-light p-0\"\r\n style=\"width: 34px; height: 34px;\"\r\n (click)=\"toggleJob(i)\"\r\n title=\"Expand\"\r\n >\r\n <i class=\"bi cursor-pointer\" [ngClass]=\"expandedIndex() === i ? 'bi-chevron-up' : 'bi-chevron-down'\"></i>\r\n </button> -->\r\n </div>\r\n </div>\r\n\r\n <div class=\"mt-3 bg-light p-3 rounded small\" *ngIf=\"expandedIndex() === i\">\r\n <ng-container *ngIf=\"editingJobIndex() !== i; else editJobForm\">\r\n <ul class=\"mb-0\">\r\n <li *ngFor=\"let res of job.responsibilities\">{{ res }}</li>\r\n </ul>\r\n </ng-container>\r\n\r\n <ng-template #editJobForm>\r\n <div *ngIf=\"(workIssuesByIndex()[i] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (workIssuesByIndex()[i] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">JOB TITLE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.jobTitle\"\r\n (ngModelChange)=\"patchTempJob({ jobTitle: $event })\"\r\n name=\"jobTitle{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.jobTitle)\">Job title is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">COMPANY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.company\"\r\n (ngModelChange)=\"patchTempJob({ company: $event })\"\r\n name=\"company{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.company)\">Company name is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">CITY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.city\"\r\n (ngModelChange)=\"patchTempJob({ city: $event })\"\r\n name=\"city{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.city)\">City is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.startDate\"\r\n (ngModelChange)=\"patchTempJob({ startDate: $event })\"\r\n name=\"startDate{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.startDate)\">Start date is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [disabled]=\"tempJob()?.isCurrent\"\r\n [ngModel]=\"tempJob()?.endDate\"\r\n (ngModelChange)=\"patchTempJob({ endDate: $event })\"\r\n name=\"endDate{{ i }}\"\r\n />\r\n <div\r\n class=\"small text-danger mt-1\"\r\n *ngIf=\"!tempJob()?.isCurrent && isBlank(tempJob()?.endDate)\"\r\n >\r\n End date is required\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isMonthRangeInvalid(tempJob()?.startDate, tempJob()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-md-4 d-flex align-items-end\">\r\n <div class=\"form-check\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"tempJob()?.isCurrent\"\r\n (ngModelChange)=\"setTempJobIsCurrent($event)\"\r\n name=\"isCurrent{{ i }}\"\r\n id=\"isCurrent{{ i }}\"\r\n />\r\n <label class=\"form-check-label\" for=\"isCurrent{{ i }}\">Current</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">RESPONSIBILITIES (one per line)</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"(tempJob()?.responsibilities || []).join('\\n')\"\r\n (ngModelChange)=\"updateTempResponsibilities($event)\"\r\n name=\"responsibilities{{ i }}\"\r\n ></textarea>\r\n </div>\r\n </form>\r\n </ng-template>\r\n </div>\r\n\r\n <div class=\"card-footer bg-light text-end\" *ngIf=\"editingJobIndex() === i\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditJob(); $event.stopPropagation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEditJob(); $event.stopPropagation()\">Save</button>\r\n </div>\r\n \r\n\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Certifications</h5>\r\n <span *ngIf=\"certificationsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add certification\"\r\n (click)=\"addCertification()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"certs().length === 0 && !isAddingCertification() && editingCertificationIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one certification.</div>\r\n </div>\r\n\r\n <div class=\"list-group list-group-flush shadow-sm rounded border\">\r\n <div *ngIf=\"isAddingCertification() && tempCertification()\" class=\"list-group-item py-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.name\"\r\n (ngModelChange)=\"patchTempCertification({ name: $event })\"\r\n name=\"newCertName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempCertification()?.name)\">Certificate name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Organization</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issuingOrganization || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issuingOrganization: $event || null })\"\r\n name=\"newCertOrg\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.state || ''\"\r\n (ngModelChange)=\"patchTempCertification({ state: $event || null })\"\r\n name=\"newCertState\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Credential ID</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.credentialId || ''\"\r\n (ngModelChange)=\"patchTempCertification({ credentialId: $event || null })\"\r\n name=\"newCertCredentialId\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issueDate: $event || null })\"\r\n name=\"newCertIssueDate\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ expiryDate: $event || null })\"\r\n name=\"newCertExpiryDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempCertification()?.issueDate || null, tempCertification()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditCertification()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveCertificationEditor()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let cert of certs(); let ci = index\" class=\"list-group-item py-3\">\r\n <ng-container *ngIf=\"editingCertificationIndex() !== ci; else editCert\">\r\n <div class=\"d-flex justify-content-between align-items-start gap-3\">\r\n <div>\r\n <div class=\"fw-semibold\">{{ cert.name }}</div>\r\n <div *ngIf=\"(certIssuesByIndex()[ci] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (certIssuesByIndex()[ci] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"small text-muted\">\r\n {{ cert.issuingOrganization || '\u2014' }}\r\n <span *ngIf=\"cert.state\"> \u2022 {{ cert.state }}</span>\r\n </div>\r\n <div class=\"small text-muted\">\r\n Issue: {{ cert.issueDate ? formatMonthYear(cert.issueDate) : '\u2014' }}\r\n <span class=\"mx-1\">|</span>\r\n Expiry: {{ cert.expiryDate ? formatMonthYear(cert.expiryDate) : '\u2014' }}\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditCertification(ci)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteCertification(ci)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #editCert>\r\n <div *ngIf=\"(certIssuesByIndex()[ci] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (certIssuesByIndex()[ci] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.name\"\r\n (ngModelChange)=\"patchTempCertification({ name: $event })\"\r\n name=\"certName{{ ci }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempCertification()?.name)\">Certificate name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Organization</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issuingOrganization || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issuingOrganization: $event || null })\"\r\n name=\"certOrg{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.state || ''\"\r\n (ngModelChange)=\"patchTempCertification({ state: $event || null })\"\r\n name=\"certState{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Credential ID</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.credentialId || ''\"\r\n (ngModelChange)=\"patchTempCertification({ credentialId: $event || null })\"\r\n name=\"certCredentialId{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issueDate: $event || null })\"\r\n name=\"certIssue{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ expiryDate: $event || null })\"\r\n name=\"certExpiry{{ ci }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempCertification()?.issueDate || null, tempCertification()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditCertification()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveCertificationEditor()\">Save</button>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Licenses</h5>\r\n <span *ngIf=\"licensesSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add license\"\r\n (click)=\"addLicense()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"licenses().length === 0 && !isAddingLicense() && editingLicenseIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one license.</div>\r\n </div>\r\n\r\n <div class=\"list-group list-group-flush shadow-sm rounded border\">\r\n <div *ngIf=\"isAddingLicense() && tempLicense()\" class=\"list-group-item py-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.name\"\r\n (ngModelChange)=\"patchTempLicense({ name: $event })\"\r\n name=\"newLicName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempLicense()?.name)\">License name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Authority</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issuingAuthority || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issuingAuthority: $event || null })\"\r\n name=\"newLicAuthority\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">License Number</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.licenseNumber || ''\"\r\n (ngModelChange)=\"patchTempLicense({ licenseNumber: $event || null })\"\r\n name=\"newLicNumber\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.state || ''\"\r\n (ngModelChange)=\"patchTempLicense({ state: $event || null })\"\r\n name=\"newLicState\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issueDate: $event || null })\"\r\n name=\"newLicIssueDate\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ expiryDate: $event || null })\"\r\n name=\"newLicExpiryDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempLicense()?.issueDate || null, tempLicense()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditLicense()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveLicenseEditor()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let lic of licenses(); let li = index\" class=\"list-group-item py-3\">\r\n <ng-container *ngIf=\"editingLicenseIndex() !== li; else editLic\">\r\n <div class=\"d-flex justify-content-between align-items-start gap-3\">\r\n <div>\r\n <div class=\"fw-semibold\">{{ lic.name }}</div>\r\n <div *ngIf=\"(licenseIssuesByIndex()[li] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (licenseIssuesByIndex()[li] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"small text-muted\">\r\n {{ lic.issuingAuthority || '\u2014' }}\r\n <span *ngIf=\"lic.state\"> \u2022 {{ lic.state }}</span>\r\n </div>\r\n <div class=\"small text-muted\">\r\n Issue: {{ lic.issueDate ? formatMonthYear(lic.issueDate) : '\u2014' }}\r\n <span class=\"mx-1\">|</span>\r\n Expiry: {{ lic.expiryDate ? formatMonthYear(lic.expiryDate) : '\u2014' }}\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditLicense(li)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteLicense(li)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #editLic>\r\n <div *ngIf=\"(licenseIssuesByIndex()[li] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (licenseIssuesByIndex()[li] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.name\"\r\n (ngModelChange)=\"patchTempLicense({ name: $event })\"\r\n name=\"licName{{ li }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempLicense()?.name)\">License name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Authority</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issuingAuthority || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issuingAuthority: $event || null })\"\r\n name=\"licAuthority{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">License Number</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.licenseNumber || ''\"\r\n (ngModelChange)=\"patchTempLicense({ licenseNumber: $event || null })\"\r\n name=\"licNumber{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.state || ''\"\r\n (ngModelChange)=\"patchTempLicense({ state: $event || null })\"\r\n name=\"licState{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issueDate: $event || null })\"\r\n name=\"licIssue{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ expiryDate: $event || null })\"\r\n name=\"licExpiry{{ li }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempLicense()?.issueDate || null, tempLicense()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditLicense()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveLicenseEditor()\">Save</button>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Tools</h5>\r\n <span *ngIf=\"toolsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add tool\"\r\n (click)=\"addTool()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"d-flex flex-wrap gap-2 p-3 bg-white border rounded shadow-sm\">\r\n <div *ngFor=\"let tool of tools(); let ti = index\" class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-light border rounded-pill d-inline-flex align-items-center gap-2 px-3 py-2\"\r\n (click)=\"openToolEditor(ti)\"\r\n title=\"Edit\"\r\n >\r\n <span class=\"fw-normal text-dark\">{{ tool }}</span>\r\n <span\r\n *ngIf=\"(toolIssuesByIndex()[ti] || []).length > 0\"\r\n class=\"badge bg-warning-subtle text-warning border ms-1\"\r\n >\r\n Missing info\r\n </span>\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Delete tool\"\r\n (click)=\"deleteTool(ti)\"\r\n >\r\n <span class=\"fw-bold\">\u00D7</span>\r\n </button>\r\n </div>\r\n\r\n <span *ngIf=\"tools().length === 0\" class=\"text-muted small\">No tools added.</span>\r\n </div>\r\n\r\n <!-- Tool edit panel (overlay) -->\r\n <div\r\n *ngIf=\"isToolEditorOpen()\"\r\n class=\"position-fixed top-0 start-0 w-100 h-100\"\r\n style=\"background: rgba(0,0,0,0.35); z-index: 2000;\"\r\n (click)=\"closeToolEditor()\"\r\n >\r\n <div class=\"container h-100 d-flex align-items-start justify-content-center pt-4\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"card shadow border-0 w-100\" style=\"max-width: 900px;\">\r\n <div class=\"card-header bg-white d-flex align-items-center gap-3\">\r\n <button type=\"button\" class=\"btn btn-link p-0 text-decoration-none\" (click)=\"closeToolEditor()\">\r\n <i class=\"bi bi-arrow-left fs-5\"></i>\r\n </button>\r\n <div class=\"fw-bold\">{{ isAddingTool() ? 'Add Tool' : ('Edit ' + (toolForm()?.name || '') + ' Tool') }}</div>\r\n </div>\r\n <div class=\"card-body p-4\">\r\n <div *ngIf=\"toolFormIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ toolFormIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"row g-3\">\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Tool Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.name\"\r\n (ngModelChange)=\"patchToolForm({ name: $event })\"\r\n name=\"toolName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(toolForm()?.name)\">Tool name is required</div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Service Provider</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.providerName\"\r\n (ngModelChange)=\"patchToolForm({ providerName: $event })\"\r\n name=\"toolProvider\"\r\n placeholder=\"Service Provider\"\r\n />\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block mb-1\">Self-ability Rating <span class=\"text-danger\">*</span></label>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n *ngFor=\"let s of [1,2,3,4,5]\"\r\n type=\"button\"\r\n class=\"btn btn-link p-0 text-decoration-none\"\r\n (click)=\"setTempToolStars(s)\"\r\n [attr.aria-label]=\"'Set rating ' + s\"\r\n >\r\n <span [class]=\"(toolForm()?.stars || 0) >= s ? 'text-warning fs-5' : 'text-muted fs-5'\">\r\n {{ (toolForm()?.stars || 0) >= s ? '\u2605' : '\u2606' }}\r\n </span>\r\n </button>\r\n <span class=\"small text-muted\">{{ toolForm()?.stars || 0 }}/5</span>\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"(toolForm()?.stars || 0) <= 0\">Star rating is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.year\"\r\n (ngModelChange)=\"patchToolForm({ year: $event === '' ? null : +$event })\"\r\n name=\"toolYear\"\r\n min=\"1\"\r\n max=\"30\"\r\n placeholder=\"Years of Experience\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"toolForm()?.year === null || toolForm()?.year === undefined\">Years of experience is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Profile Visibility</label>\r\n <div class=\"form-check form-switch mt-2\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"toolForm()?.profileVisibility\"\r\n (ngModelChange)=\"patchToolForm({ profileVisibility: $event })\"\r\n name=\"toolVisible\"\r\n id=\"toolVisible\"\r\n />\r\n <label class=\"form-check-label\" for=\"toolVisible\">Visible</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Comment</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.notes\"\r\n (ngModelChange)=\"patchToolForm({ notes: $event })\"\r\n name=\"toolNotes\"\r\n placeholder=\"Comment your tool here...\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-white d-flex justify-content-end gap-2\">\r\n <button\r\n *ngIf=\"!isAddingTool() && editingToolIndex() !== null\"\r\n type=\"button\"\r\n class=\"btn btn-link text-danger me-auto\"\r\n (click)=\"deleteTool(editingToolIndex()!)\"\r\n >\r\n Delete\r\n </button>\r\n <button type=\"button\" class=\"btn btn-link text-secondary\" (click)=\"closeToolEditor()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" (click)=\"saveToolEditor()\">\r\n {{ isAddingTool() ? 'Save' : 'Update' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"row g-4 mb-5\">\r\n <div class=\"col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Skills</h5>\r\n <span *ngIf=\"skillsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add skill\"\r\n (click)=\"addSkill()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"d-flex flex-wrap gap-2 p-3 bg-white border rounded shadow-sm\">\r\n <div *ngFor=\"let skill of skills(); let si = index\" class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-light border rounded-pill d-inline-flex align-items-center gap-2 px-3 py-2\"\r\n (click)=\"openSkillEditor(si)\"\r\n title=\"Edit\"\r\n >\r\n <span class=\"fw-normal text-dark\">{{ skill }}</span>\r\n <span\r\n *ngIf=\"(skillIssuesByIndex()[si] || []).length > 0\"\r\n class=\"badge bg-warning-subtle text-warning border ms-1\"\r\n >\r\n Missing info\r\n </span>\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Delete skill\"\r\n (click)=\"deleteSkill(si); $event.stopPropagation()\"\r\n >\r\n <span class=\"fw-bold\">\u00D7</span>\r\n </button>\r\n </div>\r\n\r\n <span *ngIf=\"skills().length === 0\" class=\"text-muted small\">No skills added.</span>\r\n </div>\r\n\r\n <!-- Skill edit panel (overlay) -->\r\n <div\r\n *ngIf=\"isSkillEditorOpen()\"\r\n class=\"position-fixed top-0 start-0 w-100 h-100\"\r\n style=\"background: rgba(0,0,0,0.35); z-index: 2000;\"\r\n (click)=\"closeSkillEditor()\"\r\n >\r\n <div class=\"container h-100 d-flex align-items-start justify-content-center pt-4\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"card shadow border-0 w-100\" style=\"max-width: 900px;\">\r\n <div class=\"card-header bg-white d-flex align-items-center gap-3\">\r\n <button type=\"button\" class=\"btn btn-link p-0 text-decoration-none\" (click)=\"closeSkillEditor()\">\r\n <i class=\"bi bi-arrow-left fs-5\"></i>\r\n </button>\r\n <div class=\"fw-bold\">{{ isAddingSkill() ? 'Add Skill' : ('Edit ' + (skillForm()?.name || '') + ' Skill') }}</div>\r\n </div>\r\n <div class=\"card-body p-4\">\r\n <div *ngIf=\"skillFormIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ skillFormIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"row g-3\">\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Skills Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.name\"\r\n (ngModelChange)=\"patchSkillForm({ name: $event })\"\r\n name=\"skillName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(skillForm()?.name)\">Skillset name is required</div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Service Provider</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.providerName\"\r\n (ngModelChange)=\"patchSkillForm({ providerName: $event })\"\r\n name=\"skillProvider\"\r\n placeholder=\"Service Provider\"\r\n />\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block mb-1\">Self-ability Rating <span class=\"text-danger\">*</span></label>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n *ngFor=\"let s of [1,2,3,4,5]\"\r\n type=\"button\"\r\n class=\"btn btn-link p-0 text-decoration-none\"\r\n (click)=\"setTempSkillStars(s)\"\r\n [attr.aria-label]=\"'Set rating ' + s\"\r\n >\r\n <span [class]=\"(skillForm()?.stars || 0) >= s ? 'text-warning fs-5' : 'text-muted fs-5'\">\r\n {{ (skillForm()?.stars || 0) >= s ? '\u2605' : '\u2606' }}\r\n </span>\r\n </button>\r\n <span class=\"small text-muted\">{{ skillForm()?.stars || 0 }}/5</span>\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"(skillForm()?.stars || 0) <= 0\">Star rating is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.year\"\r\n (ngModelChange)=\"patchSkillForm({ year: $event === '' ? null : +$event })\"\r\n name=\"skillYear\"\r\n min=\"1\"\r\n max=\"30\"\r\n placeholder=\"Years of Experience\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"skillForm()?.year === null || skillForm()?.year === undefined\">Years of experience is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Profile Visibility</label>\r\n <div class=\"form-check form-switch mt-2\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"skillForm()?.profileVisibility\"\r\n (ngModelChange)=\"patchSkillForm({ profileVisibility: $event })\"\r\n name=\"skillVisible\"\r\n id=\"skillVisible\"\r\n />\r\n <label class=\"form-check-label\" for=\"skillVisible\">Visible</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Comment</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.notes\"\r\n (ngModelChange)=\"patchSkillForm({ notes: $event })\"\r\n name=\"skillNotes\"\r\n placeholder=\"Comment your skill here...\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-white d-flex justify-content-end gap-2\">\r\n <button\r\n *ngIf=\"!isAddingSkill() && editingSkillIndex() !== null\"\r\n type=\"button\"\r\n class=\"btn btn-link text-danger me-auto\"\r\n (click)=\"deleteSkill(editingSkillIndex()!)\"\r\n >\r\n Delete\r\n </button>\r\n <button type=\"button\" class=\"btn btn-link text-secondary\" (click)=\"closeSkillEditor()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" (click)=\"saveSkillEditor()\">\r\n {{ isAddingSkill() ? 'Save' : 'Update' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n <div class=\"row g-4 mb-5\">\r\n <div class=\"col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Education</h5>\r\n <span *ngIf=\"educationSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add education\"\r\n (click)=\"addEducation()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"educationList().length === 0 && !isAddingEducation() && editingEducationIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one education.</div>\r\n </div>\r\n\r\n <div *ngIf=\"isAddingEducation() && tempEducation()\" class=\"p-3 bg-white border rounded shadow-sm mb-2\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degree\"\r\n (ngModelChange)=\"patchTempEducation({ degree: $event })\"\r\n name=\"newEduDegree\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degree)\">Degree / Course name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">INSTITUTION <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.institution\"\r\n (ngModelChange)=\"patchTempEducation({ institution: $event })\"\r\n name=\"newEduInstitution\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE / COURSE TYPE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degreeType\"\r\n (ngModelChange)=\"patchTempEducation({ degreeType: $event })\"\r\n name=\"newEduDegreeType\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degreeType)\">Degree / Course type is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.startDate\"\r\n (ngModelChange)=\"patchTempEducation({ startDate: $event })\"\r\n name=\"newEduStartDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.endDate\"\r\n (ngModelChange)=\"patchTempEducation({ endDate: $event })\"\r\n name=\"newEduEndDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempEducation()?.startDate, tempEducation()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n </form>\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditEducation()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveEducation()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let edu of educationList(); let ei = index\" class=\"p-3 bg-white border rounded shadow-sm mb-2\">\r\n <div class=\"d-flex justify-content-between align-items-start\">\r\n <div>\r\n <h6 class=\"fw-bold mb-1\">{{ edu.degree }}</h6>\r\n <p class=\"small text-primary mb-0\">{{ edu.institution }}</p>\r\n <div *ngIf=\"(educationIssuesByIndex()[ei] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (educationIssuesByIndex()[ei] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\" *ngIf=\"editingEducationIndex() !== ei\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditEducation(ei)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteEducation(ei)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"editingEducationIndex() === ei\" class=\"mt-3\">\r\n <div *ngIf=\"(educationIssuesByIndex()[ei] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (educationIssuesByIndex()[ei] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degree\"\r\n (ngModelChange)=\"patchTempEducation({ degree: $event })\"\r\n name=\"eduDegree{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degree)\">Degree / Course name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">INSTITUTION <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.institution\"\r\n (ngModelChange)=\"patchTempEducation({ institution: $event })\"\r\n name=\"eduInstitution{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.institution)\">Institution name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE / COURSE TYPE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degreeType\"\r\n (ngModelChange)=\"patchTempEducation({ degreeType: $event })\"\r\n name=\"eduDegreeType{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degreeType)\">Degree / Course type is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">City</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.city\"\r\n (ngModelChange)=\"patchTempEducation({ city: $event })\"\r\n name=\"eduCity{{ ei }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.startDate\"\r\n (ngModelChange)=\"patchTempEducation({ startDate: $event })\"\r\n name=\"eduStartDate{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.endDate\"\r\n (ngModelChange)=\"patchTempEducation({ endDate: $event })\"\r\n name=\"eduEndDate{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempEducation()?.startDate, tempEducation()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditEducation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEducation()\">Save</button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"educationList().length === 0\" class=\"text-muted small\">No education added.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"d-flex gap-2 justify-content-center mt-5\">\r\n <button class=\"btn btn-outline-secondary px-5\" (click)=\"onBackClick()\">Back</button>\r\n <button\r\n class=\"btn btn-primary px-5 shadow\"\r\n [disabled]=\"!canConfirmAndContinue()\"\r\n [title]=\"canConfirmAndContinue() ? '' : 'Please fill all required fields in all mandatory sections.'\"\r\n (click)=\"saveResumedetails()\"\r\n >\r\n Confirm & Continue\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #loading>\r\n <div class=\"text-center p-5\">\r\n <div class=\"spinner-border text-primary\"></div>\r\n <p class=\"text-muted mt-2\">Loading data...</p>\r\n </div>\r\n</ng-template>\r\n\r\n<div class=\"modal-overlay\" *ngIf=\"showPopup\" (click)=\"closeSavePopup()\">\r\n <div class=\"status-modal-card\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"status-modal-header\">\r\n <h3 class=\"mb-1\">Saving Resume Details</h3>\r\n <p class=\"text-muted mb-0\">Please wait while we process each section.</p>\r\n </div>\r\n\r\n <div class=\"status-modal-body\">\r\n <div class=\"status-modal-row\" *ngFor=\"let item of statusList\">\r\n <div class=\"status-modal-name\">{{ item.name }}</div>\r\n\r\n <div class=\"status-modal-state pending\" *ngIf=\"item.status === 'pending'\">\r\n <span class=\"spinner-border spinner-border-sm me-2\"></span> In progress\r\n </div>\r\n\r\n <div class=\"status-modal-state success\" *ngIf=\"item.status === 'success'\">\r\n <span class=\"me-1\">\u2713</span> Success\r\n </div>\r\n\r\n <div class=\"status-modal-state partial\" *ngIf=\"item.status === 'partial'\">\r\n <span class=\"me-1\">!</span> {{ item.successCount }} Success / {{ item.failCount }} Failed\r\n </div>\r\n\r\n <div class=\"status-modal-state error\" *ngIf=\"item.status === 'error'\">\r\n <span class=\"me-1\">\u2716</span> {{ item.error || 'Failed' }}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"status-modal-footer\">\r\n <button type=\"button\" class=\"btn btn-outline-secondary\" (click)=\"closeSavePopup()\">Back to Preview</button>\r\n <div class=\"d-flex justify-content-end\">\r\n <button\r\n *ngIf=\"allSaveStepsSucceeded()\"\r\n type=\"button\"\r\n class=\"btn btn-primary\"\r\n (click)=\"goToDashboard()\"\r\n >\r\n Go to Dashboard\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"modal-overlay\" *ngIf=\"showBackConfirmPopup\">\r\n <div class=\"confirm-modal-card\">\r\n <h4 class=\"mb-2\">Leave this page?</h4>\r\n <p class=\"text-muted mb-4\">Your data might be lost if you go back now.</p>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n <button type=\"button\" class=\"btn btn-outline-secondary\" (click)=\"stayOnPreview()\">Stay</button>\r\n <button type=\"button\" class=\"btn btn-danger\" (click)=\"proceedBack()\">Proceed Back</button>\r\n </div>\r\n </div>\r\n</div>", styles: [".container{max-width:900px;margin:30px auto;font-family:Arial,sans-serif;color:#333}.preview-page-header{max-width:900px;margin:50px auto 10px;padding:0 12px}.preview-title{font-weight:600;margin:0}.preview-subtitle{margin-top:7px;font-size:16px}.section{margin-bottom:25px}.section-title{font-weight:600;display:block;margin-bottom:8px}.section-title .sub{font-weight:400;color:#777;font-size:13px}.dropdown-box{border:1px solid #ddd;border-radius:8px;padding:12px 15px;display:flex;justify-content:space-between;align-items:center}.icons{display:flex;gap:10px}.icon{cursor:pointer;font-size:14px;color:#777}.card{border:1px solid #ddd;border-radius:10px;padding:20px;background:#fff}.category{border-bottom:1px solid #eee;padding:15px 0}.category:last-child{border-bottom:none}.category-header{display:flex;justify-content:space-between;font-weight:600;margin-bottom:10px}.tags{display:flex;flex-wrap:wrap;gap:10px}.tag{background:#f2f4f7;padding:6px 12px;border-radius:6px;font-size:13px}.footer{text-align:center;margin-top:15px;color:#777;cursor:pointer}.actions{display:flex;justify-content:space-between;margin:50px 0 27px}.text-secondary{white-space:pre-line;font-size:.95rem}.extra-small{font-size:.8rem}.card{transition:transform .2s ease,box-shadow .2s ease}.card:hover{transform:translateY(-3px);box-shadow:0 .5rem 1rem #0000001a!important}.achievement-section .badge{font-size:.75rem;white-space:normal;text-align:left}.skill-tag .badge{font-weight:500;font-size:.9rem;transition:all .2s ease;cursor:default}.skill-tag .badge:hover{transform:translateY(-2px);box-shadow:0 4px 8px #0000001a}.skill-tag .btn-close{opacity:.5}.skill-tag .btn-close:hover{opacity:1}.bg-light.text-dark.border{background-color:#f8f9fa!important;border-color:#dee2e6!important}.card{transition:all .3s cubic-bezier(.25,.8,.25,1)}.card:hover{box-shadow:0 10px 20px #0000001a!important}.card:hover .bg-light{background-color:#e8f5e9!important}.position-fixed .card:hover{transform:none!important}code{background-color:#f8f9fa;padding:2px 6px;border-radius:4px}.list-group-item{transition:all .2s ease-in-out}.list-group-item:hover{background-color:#fcfcfc;transform:translate(5px);box-shadow:-5px 0 15px #0000000d}.border-dashed{border-style:dashed!important}.tool-card{transition:all .2s ease-in-out;border-radius:12px}.tool-card:hover{transform:translateY(-5px);border-color:var(--bs-primary)!important;box-shadow:0 10px 15px #0000001a!important}.tool-card:hover .icon-box{background-color:var(--bs-primary-subtle)!important}.tool-card .icon-box{width:60px;height:60px;transition:background-color .2s ease}.border-dashed{border:2px dashed #dee2e6!important}.border-dashed:hover{border-color:var(--bs-primary)!important;background-color:#fff!important}.popup{position:fixed;top:20%;right:20px;width:320px;background:#fff;border-radius:10px;padding:16px;box-shadow:0 4px 12px #0003}.status-row{display:flex;justify-content:space-between;margin:10px 0}.success{color:#2e7d32;font-weight:700}.error{color:#d32f2f}.pending{color:#f9a825}.section-flag{font-weight:600}button.btn.btn-sm.btn-outline-primary{background-color:#4077ad;border-color:#4077ad;color:#fff;border-radius:10px}button.btn.btn-sm.btn-outline-primary:hover{background-color:#356895;border-color:#356895;color:#fff}button.btn.btn-sm.btn-outline-danger{border-color:#dc3545;color:#dc3545;border-radius:10px}button.btn.btn-sm.btn-outline-danger:hover{background-color:#bb2d3b;border-color:#bb2d3b;color:#fff}button.btn.btn-sm.btn-outline-primary.rounded-circle{background-color:#4077ad;border-color:#4077ad;color:#fff;border-radius:50%!important}button.action-icon-btn{min-width:22px;width:22px;height:22px;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0!important;background:transparent!important;border:none!important;box-shadow:none!important;line-height:1}button.action-icon-btn.btn-outline-primary{color:#4077ad!important;border-color:#4077ad!important}button.action-icon-btn.btn-outline-danger{color:#dc3545!important}.action-icon-image{width:20px;height:20px;object-fit:contain;display:inline-block}.action-icon-image.edit-icon{filter:brightness(0) saturate(100%) invert(41%) sepia(39%) saturate(774%) hue-rotate(170deg) brightness(91%) contrast(89%)}.action-icon-image.delete-icon{filter:brightness(0) saturate(100%) invert(24%) sepia(79%) saturate(4008%) hue-rotate(344deg) brightness(91%) contrast(90%)}.modal-overlay{position:fixed;inset:0;background:#11182773;display:flex;align-items:center;justify-content:center;z-index:2500;padding:20px}.status-modal-card{width:min(760px,96vw);max-height:85vh;overflow:auto;background:#fff;border-radius:16px;box-shadow:0 20px 40px #0f172a40;border:1px solid #e5e7eb}.status-modal-header{padding:20px 24px 14px;border-bottom:1px solid #eef2f7}.status-modal-body{padding:12px 20px 20px}.status-modal-footer{padding:12px 20px 20px;border-top:1px solid #eef2f7;display:flex;justify-content:space-between;align-items:center;gap:12px}.status-modal-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 10px;border-bottom:1px solid #f1f5f9}.status-modal-row:last-child{border-bottom:0}.status-modal-name{font-weight:600;color:#1f2937}.status-modal-state{font-size:.92rem;font-weight:600}.status-modal-state.pending{color:#a16207}.status-modal-state.success{color:#166534}.status-modal-state.partial{color:#b45309}.status-modal-state.error{color:#b91c1c}.confirm-modal-card{width:min(520px,96vw);background:#fff;border-radius:14px;box-shadow:0 20px 35px #0f172a38;border:1px solid #e5e7eb;padding:24px}.year-experience-select{max-height:150px}\n"], dependencies: [{ kind: "directive", type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i8.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i8.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i8.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i8.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i8.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i8.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i8.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { kind: "directive", type: i8.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i8.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i8.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
30584
+ }
30585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PreviewComponent, decorators: [{
30586
+ type: Component,
30587
+ args: [{ selector: 'app-preview', standalone: false, template: "\r\n<div class=\"preview-page-header\">\r\n <h2 class=\"preview-title\">Confirm based on your resume</h2>\r\n <p class=\"preview-subtitle\">Please confirm everything is accurate. It is based on your resume</p>\r\n</div>\r\n\r\n\r\n<div class=\"container py-4\">\r\n <div class=\"section mb-5\">\r\n <div *ngIf=\"details() as data; else loading\">\r\n <div class=\"card shadow-sm border-0\" *ngIf=\"!isEditMode()\">\r\n <div class=\"card-body p-4\">\r\n <div class=\"d-flex justify-content-between align-items-start mb-4\">\r\n <div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h2 class=\"fw-bold mb-1\">{{ data.firstName }} {{ data.lastName }}</h2>\r\n <span *ngIf=\"basicSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <p class=\"text-muted\">{{ data.jobTitle }} \u2022 {{ data.yearsOfExperience }} Years Exp.</p>\r\n <div *ngIf=\"basicIssues().length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ basicIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n <span class=\"badge bg-primary-subtle text-primary border p-2\">ID: Verified</span>\r\n </div>\r\n\r\n <div class=\"row g-4\">\r\n <div class=\"col-12 border-bottom pb-2\">\r\n <h6 class=\"text-uppercase small fw-bold text-muted\">Summary</h6>\r\n <p class=\"text-secondary small mb-0\">{{ data.summary }}</p>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">EMAIL</label>\r\n <span class=\"fw-bold small\">{{ data.email }}</span>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">PHONE</label>\r\n <span class=\"fw-bold small\">{{ data.phone }}</span>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">LOCATION</label>\r\n <span class=\"small\">{{ data.address }},{{ data.city }},{{ data.state }},{{ data.zipCode }}, {{\r\n data.country }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-light text-end\">\r\n <button class=\"btn btn-sm btn-primary px-4\" (click)=\"toggleEdit()\">Edit Details</button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card shadow-sm border-0\" *ngIf=\"isEditMode()\">\r\n <div class=\"card-header bg-white fw-bold\">Update Profile</div>\r\n <div class=\"card-body p-4\">\r\n <form class=\"row g-3\" #basicForm=\"ngForm\" novalidate>\r\n <div *ngIf=\"basicIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ basicIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">First Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.firstName\"\r\n name=\"fName\"\r\n placeholder=\"First Name\"\r\n required\r\n #fName=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"fName.invalid && (fName.dirty || fName.touched)\">First name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Last Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.lastName\"\r\n name=\"lName\"\r\n placeholder=\"Last Name\"\r\n required\r\n #lName=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"lName.invalid && (lName.dirty || lName.touched)\">Last name is required</div>\r\n </div>\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Summary</label>\r\n <textarea class=\"form-control\" rows=\"3\" [(ngModel)]=\"tempProfile.summary\" name=\"sum\"\r\n placeholder=\"Summary\"></textarea>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Email <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"email\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.email\"\r\n name=\"email\"\r\n placeholder=\"Email\"\r\n required\r\n email\r\n #email=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"email.invalid && (email.dirty || email.touched)\">\r\n <span *ngIf=\"email.errors?.['required']\">Email is required</span>\r\n <span *ngIf=\"email.errors?.['email']\">Email format is invalid</span>\r\n </div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Phone Number <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"tempProfile.phone\"\r\n (ngModelChange)=\"tempProfile.phone = sanitizePhone($event)\"\r\n name=\"phone\"\r\n placeholder=\"Phone (10 digits)\"\r\n required\r\n pattern=\"^\\d{10}$\"\r\n maxlength=\"10\"\r\n inputmode=\"numeric\"\r\n #phone=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"phone.invalid && (phone.dirty || phone.touched)\">\r\n <span *ngIf=\"phone.errors?.['required']\">Phone number is required</span>\r\n <span *ngIf=\"phone.errors?.['pattern']\">Phone number must be 10 digits</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-md-3\">\r\n <label class=\"small text-muted d-block\">Home Address <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.address\"\r\n name=\"address\"\r\n placeholder=\"Home Address\"\r\n required\r\n #address=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"address.invalid && (address.dirty || address.touched)\">Home address is required</div>\r\n </div>\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">City <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.city\"\r\n name=\"city\"\r\n placeholder=\"City\"\r\n required\r\n #city=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"city.invalid && (city.dirty || city.touched)\">City is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">State <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.state\"\r\n name=\"state\"\r\n placeholder=\"State\"\r\n required\r\n #state=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"state.invalid && (state.dirty || state.touched)\">State is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">Zip Code <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.zipCode\"\r\n name=\"zipCode\"\r\n placeholder=\"Zip Code\"\r\n required\r\n #zipCode=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"zipCode.invalid && (zipCode.dirty || zipCode.touched)\">Zip code is required</div>\r\n </div>\r\n <div class=\"col-md-2\">\r\n <label class=\"small text-muted d-block\">Country <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.country\"\r\n name=\"country\"\r\n placeholder=\"Country\"\r\n required\r\n #country=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"country.invalid && (country.dirty || country.touched)\">Country is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Job Title <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.jobTitle\"\r\n name=\"jobTitle\"\r\n placeholder=\"Job Title\"\r\n required\r\n #jobTitle=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"jobTitle.invalid && (jobTitle.dirty || jobTitle.touched)\">Job title is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [(ngModel)]=\"tempProfile.yearsOfExperience\"\r\n name=\"yearsOfExperience\"\r\n placeholder=\"Years of Experience\"\r\n required\r\n min=\"0\"\r\n #yearsOfExperience=\"ngModel\"\r\n >\r\n <div class=\"small text-danger mt-1\" *ngIf=\"yearsOfExperience.invalid && (yearsOfExperience.dirty || yearsOfExperience.touched)\">\r\n Years of experience is required\r\n </div>\r\n </div>\r\n\r\n\r\n </form>\r\n </div>\r\n <div class=\"card-footer bg-light text-end gap-2 d-flex justify-content-end\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancel()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"save()\">Save Changes</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Work Experience</h5>\r\n <span *ngIf=\"workSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add work experience\"\r\n (click)=\"addJob()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"experience().length === 0 && !isAddingJob()\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one work experience.</div>\r\n </div>\r\n <div class=\"list-group list-group-flush shadow-sm rounded\">\r\n <div *ngIf=\"isAddingJob() && tempJob()\" class=\"list-group-item p-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">JOB TITLE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.jobTitle\"\r\n (ngModelChange)=\"patchTempJob({ jobTitle: $event })\"\r\n name=\"newJobTitle\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">COMPANY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.company\"\r\n (ngModelChange)=\"patchTempJob({ company: $event })\"\r\n name=\"newCompany\"\r\n />\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">CITY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.city\"\r\n (ngModelChange)=\"patchTempJob({ city: $event })\"\r\n name=\"newCity\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.city)\">City is required</div>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.startDate\"\r\n (ngModelChange)=\"patchTempJob({ startDate: $event })\"\r\n name=\"newStartDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [disabled]=\"tempJob()?.isCurrent\"\r\n [ngModel]=\"tempJob()?.endDate\"\r\n (ngModelChange)=\"patchTempJob({ endDate: $event })\"\r\n name=\"newEndDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isBlank(tempJob()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isMonthRangeInvalid(tempJob()?.startDate, tempJob()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n <div class=\"col-md-4 d-flex align-items-end\">\r\n <div class=\"form-check\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"tempJob()?.isCurrent\"\r\n (ngModelChange)=\"setTempJobIsCurrent($event)\"\r\n name=\"newIsCurrent\"\r\n id=\"newIsCurrent\"\r\n />\r\n <label class=\"form-check-label\" for=\"newIsCurrent\">Current</label>\r\n </div>\r\n </div>\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">RESPONSIBILITIES (one per line)</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"(tempJob()?.responsibilities || []).join('\\n')\"\r\n (ngModelChange)=\"updateTempResponsibilities($event)\"\r\n name=\"newResponsibilities\"\r\n ></textarea>\r\n </div>\r\n </form>\r\n <div class=\"card-footer bg-light text-end mt-3\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditJob(); $event.stopPropagation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEditJob(); $event.stopPropagation()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let job of experience(); let i = index\" class=\"list-group-item p-3\">\r\n\r\n <div class=\"d-flex justify-content-between align-items-center\">\r\n <div class=\"d-flex align-items-center cursor-pointer flex-grow-1\" (click)=\"toggleJob(i)\">\r\n <i class=\"bi bi-briefcase text-primary me-3 fs-4\"></i>\r\n <div>\r\n <h6 class=\"mb-0 fw-bold\">{{ job.jobTitle }}</h6>\r\n <small class=\"text-muted\">\r\n {{ job.company }} \u2022 {{ formatMonthYear(job.startDate) }} - {{ job.isCurrent ? 'Present' : formatMonthYear(job.endDate) }}\r\n </small>\r\n <div\r\n *ngIf=\"editingJobIndex() !== i && (workIssuesByIndex()[i] || []).length > 0\"\r\n class=\"alert alert-warning py-1 px-2 mt-2\"\r\n >\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (workIssuesByIndex()[i] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"d-flex align-items-center gap-2\">\r\n \r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditJob(i)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteJob(i);\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n \r\n\r\n <!-- <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-light p-0\"\r\n style=\"width: 34px; height: 34px;\"\r\n (click)=\"toggleJob(i)\"\r\n title=\"Expand\"\r\n >\r\n <i class=\"bi cursor-pointer\" [ngClass]=\"expandedIndex() === i ? 'bi-chevron-up' : 'bi-chevron-down'\"></i>\r\n </button> -->\r\n </div>\r\n </div>\r\n\r\n <div class=\"mt-3 bg-light p-3 rounded small\" *ngIf=\"expandedIndex() === i\">\r\n <ng-container *ngIf=\"editingJobIndex() !== i; else editJobForm\">\r\n <ul class=\"mb-0\">\r\n <li *ngFor=\"let res of job.responsibilities\">{{ res }}</li>\r\n </ul>\r\n </ng-container>\r\n\r\n <ng-template #editJobForm>\r\n <div *ngIf=\"(workIssuesByIndex()[i] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (workIssuesByIndex()[i] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">JOB TITLE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.jobTitle\"\r\n (ngModelChange)=\"patchTempJob({ jobTitle: $event })\"\r\n name=\"jobTitle{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.jobTitle)\">Job title is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">COMPANY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.company\"\r\n (ngModelChange)=\"patchTempJob({ company: $event })\"\r\n name=\"company{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.company)\">Company name is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">CITY <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.city\"\r\n (ngModelChange)=\"patchTempJob({ city: $event })\"\r\n name=\"city{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.city)\">City is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempJob()?.startDate\"\r\n (ngModelChange)=\"patchTempJob({ startDate: $event })\"\r\n name=\"startDate{{ i }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempJob()?.startDate)\">Start date is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [disabled]=\"tempJob()?.isCurrent\"\r\n [ngModel]=\"tempJob()?.endDate\"\r\n (ngModelChange)=\"patchTempJob({ endDate: $event })\"\r\n name=\"endDate{{ i }}\"\r\n />\r\n <div\r\n class=\"small text-danger mt-1\"\r\n *ngIf=\"!tempJob()?.isCurrent && isBlank(tempJob()?.endDate)\"\r\n >\r\n End date is required\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"!tempJob()?.isCurrent && isMonthRangeInvalid(tempJob()?.startDate, tempJob()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-md-4 d-flex align-items-end\">\r\n <div class=\"form-check\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"tempJob()?.isCurrent\"\r\n (ngModelChange)=\"setTempJobIsCurrent($event)\"\r\n name=\"isCurrent{{ i }}\"\r\n id=\"isCurrent{{ i }}\"\r\n />\r\n <label class=\"form-check-label\" for=\"isCurrent{{ i }}\">Current</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">RESPONSIBILITIES (one per line)</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"(tempJob()?.responsibilities || []).join('\\n')\"\r\n (ngModelChange)=\"updateTempResponsibilities($event)\"\r\n name=\"responsibilities{{ i }}\"\r\n ></textarea>\r\n </div>\r\n </form>\r\n </ng-template>\r\n </div>\r\n\r\n <div class=\"card-footer bg-light text-end\" *ngIf=\"editingJobIndex() === i\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditJob(); $event.stopPropagation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEditJob(); $event.stopPropagation()\">Save</button>\r\n </div>\r\n \r\n\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Certifications</h5>\r\n <span *ngIf=\"certificationsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add certification\"\r\n (click)=\"addCertification()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"certs().length === 0 && !isAddingCertification() && editingCertificationIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one certification.</div>\r\n </div>\r\n\r\n <div class=\"list-group list-group-flush shadow-sm rounded border\">\r\n <div *ngIf=\"isAddingCertification() && tempCertification()\" class=\"list-group-item py-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.name\"\r\n (ngModelChange)=\"patchTempCertification({ name: $event })\"\r\n name=\"newCertName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempCertification()?.name)\">Certificate name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Organization</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issuingOrganization || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issuingOrganization: $event || null })\"\r\n name=\"newCertOrg\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.state || ''\"\r\n (ngModelChange)=\"patchTempCertification({ state: $event || null })\"\r\n name=\"newCertState\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Credential ID</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.credentialId || ''\"\r\n (ngModelChange)=\"patchTempCertification({ credentialId: $event || null })\"\r\n name=\"newCertCredentialId\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issueDate: $event || null })\"\r\n name=\"newCertIssueDate\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ expiryDate: $event || null })\"\r\n name=\"newCertExpiryDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempCertification()?.issueDate || null, tempCertification()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditCertification()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveCertificationEditor()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let cert of certs(); let ci = index\" class=\"list-group-item py-3\">\r\n <ng-container *ngIf=\"editingCertificationIndex() !== ci; else editCert\">\r\n <div class=\"d-flex justify-content-between align-items-start gap-3\">\r\n <div>\r\n <div class=\"fw-semibold\">{{ cert.name }}</div>\r\n <div *ngIf=\"(certIssuesByIndex()[ci] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (certIssuesByIndex()[ci] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"small text-muted\">\r\n {{ cert.issuingOrganization || '\u2014' }}\r\n <span *ngIf=\"cert.state\"> \u2022 {{ cert.state }}</span>\r\n </div>\r\n <div class=\"small text-muted\">\r\n Issue: {{ cert.issueDate ? formatMonthYear(cert.issueDate) : '\u2014' }}\r\n <span class=\"mx-1\">|</span>\r\n Expiry: {{ cert.expiryDate ? formatMonthYear(cert.expiryDate) : '\u2014' }}\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditCertification(ci)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteCertification(ci)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #editCert>\r\n <div *ngIf=\"(certIssuesByIndex()[ci] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (certIssuesByIndex()[ci] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.name\"\r\n (ngModelChange)=\"patchTempCertification({ name: $event })\"\r\n name=\"certName{{ ci }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempCertification()?.name)\">Certificate name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Organization</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issuingOrganization || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issuingOrganization: $event || null })\"\r\n name=\"certOrg{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.state || ''\"\r\n (ngModelChange)=\"patchTempCertification({ state: $event || null })\"\r\n name=\"certState{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Credential ID</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.credentialId || ''\"\r\n (ngModelChange)=\"patchTempCertification({ credentialId: $event || null })\"\r\n name=\"certCredentialId{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ issueDate: $event || null })\"\r\n name=\"certIssue{{ ci }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempCertification()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempCertification({ expiryDate: $event || null })\"\r\n name=\"certExpiry{{ ci }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempCertification()?.issueDate || null, tempCertification()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditCertification()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveCertificationEditor()\">Save</button>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Licenses</h5>\r\n <span *ngIf=\"licensesSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add license\"\r\n (click)=\"addLicense()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n <div *ngIf=\"licenses().length === 0 && !isAddingLicense() && editingLicenseIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one license.</div>\r\n </div>\r\n\r\n <div class=\"list-group list-group-flush shadow-sm rounded border\">\r\n <div *ngIf=\"isAddingLicense() && tempLicense()\" class=\"list-group-item py-3\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.name\"\r\n (ngModelChange)=\"patchTempLicense({ name: $event })\"\r\n name=\"newLicName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempLicense()?.name)\">License name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Authority</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issuingAuthority || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issuingAuthority: $event || null })\"\r\n name=\"newLicAuthority\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">License Number</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.licenseNumber || ''\"\r\n (ngModelChange)=\"patchTempLicense({ licenseNumber: $event || null })\"\r\n name=\"newLicNumber\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.state || ''\"\r\n (ngModelChange)=\"patchTempLicense({ state: $event || null })\"\r\n name=\"newLicState\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issueDate: $event || null })\"\r\n name=\"newLicIssueDate\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ expiryDate: $event || null })\"\r\n name=\"newLicExpiryDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempLicense()?.issueDate || null, tempLicense()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditLicense()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveLicenseEditor()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let lic of licenses(); let li = index\" class=\"list-group-item py-3\">\r\n <ng-container *ngIf=\"editingLicenseIndex() !== li; else editLic\">\r\n <div class=\"d-flex justify-content-between align-items-start gap-3\">\r\n <div>\r\n <div class=\"fw-semibold\">{{ lic.name }}</div>\r\n <div *ngIf=\"(licenseIssuesByIndex()[li] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (licenseIssuesByIndex()[li] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"small text-muted\">\r\n {{ lic.issuingAuthority || '\u2014' }}\r\n <span *ngIf=\"lic.state\"> \u2022 {{ lic.state }}</span>\r\n </div>\r\n <div class=\"small text-muted\">\r\n Issue: {{ lic.issueDate ? formatMonthYear(lic.issueDate) : '\u2014' }}\r\n <span class=\"mx-1\">|</span>\r\n Expiry: {{ lic.expiryDate ? formatMonthYear(lic.expiryDate) : '\u2014' }}\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditLicense(li)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteLicense(li)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template #editLic>\r\n <div *ngIf=\"(licenseIssuesByIndex()[li] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (licenseIssuesByIndex()[li] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.name\"\r\n (ngModelChange)=\"patchTempLicense({ name: $event })\"\r\n name=\"licName{{ li }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempLicense()?.name)\">License name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issuing Authority</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issuingAuthority || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issuingAuthority: $event || null })\"\r\n name=\"licAuthority{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">License Number</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.licenseNumber || ''\"\r\n (ngModelChange)=\"patchTempLicense({ licenseNumber: $event || null })\"\r\n name=\"licNumber{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">State</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.state || ''\"\r\n (ngModelChange)=\"patchTempLicense({ state: $event || null })\"\r\n name=\"licState{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Issue Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.issueDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ issueDate: $event || null })\"\r\n name=\"licIssue{{ li }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">Expiry Date</label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempLicense()?.expiryDate || ''\"\r\n (ngModelChange)=\"patchTempLicense({ expiryDate: $event || null })\"\r\n name=\"licExpiry{{ li }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempLicense()?.issueDate || null, tempLicense()?.expiryDate || null)\">\r\n Issued date must be less than expiry date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditLicense()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveLicenseEditor()\">Save</button>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"section mb-5\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Tools</h5>\r\n <span *ngIf=\"toolsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add tool\"\r\n (click)=\"addTool()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"d-flex flex-wrap gap-2 p-3 bg-white border rounded shadow-sm\">\r\n <div *ngFor=\"let tool of tools(); let ti = index\" class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-light border rounded-pill d-inline-flex align-items-center gap-2 px-3 py-2\"\r\n (click)=\"openToolEditor(ti)\"\r\n title=\"Edit\"\r\n >\r\n <span class=\"fw-normal text-dark\">{{ tool }}</span>\r\n <span\r\n *ngIf=\"(toolIssuesByIndex()[ti] || []).length > 0\"\r\n class=\"badge bg-warning-subtle text-warning border ms-1\"\r\n >\r\n Missing info\r\n </span>\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Delete tool\"\r\n (click)=\"deleteTool(ti)\"\r\n >\r\n <span class=\"fw-bold\">\u00D7</span>\r\n </button>\r\n </div>\r\n\r\n <span *ngIf=\"tools().length === 0\" class=\"text-muted small\">No tools added.</span>\r\n </div>\r\n\r\n <!-- Tool edit panel (overlay) -->\r\n <div\r\n *ngIf=\"isToolEditorOpen()\"\r\n class=\"position-fixed top-0 start-0 w-100 h-100\"\r\n style=\"background: rgba(0,0,0,0.35); z-index: 2000;\"\r\n (click)=\"closeToolEditor()\"\r\n >\r\n <div class=\"container h-100 d-flex align-items-start justify-content-center pt-4\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"card shadow border-0 w-100\" style=\"max-width: 900px;\">\r\n <div class=\"card-header bg-white d-flex align-items-center gap-3\">\r\n <button type=\"button\" class=\"btn btn-link p-0 text-decoration-none\" (click)=\"closeToolEditor()\">\r\n <i class=\"bi bi-arrow-left fs-5\"></i>\r\n </button>\r\n <div class=\"fw-bold\">{{ isAddingTool() ? 'Add Tool' : ('Edit ' + (toolForm()?.name || '') + ' Tool') }}</div>\r\n </div>\r\n <div class=\"card-body p-4\">\r\n <div *ngIf=\"toolFormIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ toolFormIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"row g-3\">\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Tool Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.name\"\r\n (ngModelChange)=\"patchToolForm({ name: $event })\"\r\n name=\"toolName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(toolForm()?.name)\">Tool name is required</div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Service Provider</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.providerName\"\r\n (ngModelChange)=\"patchToolForm({ providerName: $event })\"\r\n name=\"toolProvider\"\r\n placeholder=\"Service Provider\"\r\n />\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block mb-1\">Self-ability Rating <span class=\"text-danger\">*</span></label>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n *ngFor=\"let s of [1,2,3,4,5]\"\r\n type=\"button\"\r\n class=\"btn btn-link p-0 text-decoration-none\"\r\n (click)=\"setTempToolStars(s)\"\r\n [attr.aria-label]=\"'Set rating ' + s\"\r\n >\r\n <span [class]=\"(toolForm()?.stars || 0) >= s ? 'text-warning fs-5' : 'text-muted fs-5'\">\r\n {{ (toolForm()?.stars || 0) >= s ? '\u2605' : '\u2606' }}\r\n </span>\r\n </button>\r\n <span class=\"small text-muted\">{{ toolForm()?.stars || 0 }}/5</span>\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"(toolForm()?.stars || 0) <= 0\">Star rating is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.year\"\r\n (ngModelChange)=\"patchToolForm({ year: $event === '' ? null : +$event })\"\r\n name=\"toolYear\"\r\n min=\"1\"\r\n max=\"30\"\r\n placeholder=\"Years of Experience\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"toolForm()?.year === null || toolForm()?.year === undefined\">Years of experience is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Profile Visibility</label>\r\n <div class=\"form-check form-switch mt-2\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"toolForm()?.profileVisibility\"\r\n (ngModelChange)=\"patchToolForm({ profileVisibility: $event })\"\r\n name=\"toolVisible\"\r\n id=\"toolVisible\"\r\n />\r\n <label class=\"form-check-label\" for=\"toolVisible\">Visible</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Comment</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control\"\r\n [ngModel]=\"toolForm()?.notes\"\r\n (ngModelChange)=\"patchToolForm({ notes: $event })\"\r\n name=\"toolNotes\"\r\n placeholder=\"Comment your tool here...\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-white d-flex justify-content-end gap-2\">\r\n <button\r\n *ngIf=\"!isAddingTool() && editingToolIndex() !== null\"\r\n type=\"button\"\r\n class=\"btn btn-link text-danger me-auto\"\r\n (click)=\"deleteTool(editingToolIndex()!)\"\r\n >\r\n Delete\r\n </button>\r\n <button type=\"button\" class=\"btn btn-link text-secondary\" (click)=\"closeToolEditor()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" (click)=\"saveToolEditor()\">\r\n {{ isAddingTool() ? 'Save' : 'Update' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"row g-4 mb-5\">\r\n <div class=\"col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Skills</h5>\r\n <span *ngIf=\"skillsSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add skill\"\r\n (click)=\"addSkill()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"d-flex flex-wrap gap-2 p-3 bg-white border rounded shadow-sm\">\r\n <div *ngFor=\"let skill of skills(); let si = index\" class=\"d-flex align-items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-light border rounded-pill d-inline-flex align-items-center gap-2 px-3 py-2\"\r\n (click)=\"openSkillEditor(si)\"\r\n title=\"Edit\"\r\n >\r\n <span class=\"fw-normal text-dark\">{{ skill }}</span>\r\n <span\r\n *ngIf=\"(skillIssuesByIndex()[si] || []).length > 0\"\r\n class=\"badge bg-warning-subtle text-warning border ms-1\"\r\n >\r\n Missing info\r\n </span>\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Delete skill\"\r\n (click)=\"deleteSkill(si); $event.stopPropagation()\"\r\n >\r\n <span class=\"fw-bold\">\u00D7</span>\r\n </button>\r\n </div>\r\n\r\n <span *ngIf=\"skills().length === 0\" class=\"text-muted small\">No skills added.</span>\r\n </div>\r\n\r\n <!-- Skill edit panel (overlay) -->\r\n <div\r\n *ngIf=\"isSkillEditorOpen()\"\r\n class=\"position-fixed top-0 start-0 w-100 h-100\"\r\n style=\"background: rgba(0,0,0,0.35); z-index: 2000;\"\r\n (click)=\"closeSkillEditor()\"\r\n >\r\n <div class=\"container h-100 d-flex align-items-start justify-content-center pt-4\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"card shadow border-0 w-100\" style=\"max-width: 900px;\">\r\n <div class=\"card-header bg-white d-flex align-items-center gap-3\">\r\n <button type=\"button\" class=\"btn btn-link p-0 text-decoration-none\" (click)=\"closeSkillEditor()\">\r\n <i class=\"bi bi-arrow-left fs-5\"></i>\r\n </button>\r\n <div class=\"fw-bold\">{{ isAddingSkill() ? 'Add Skill' : ('Edit ' + (skillForm()?.name || '') + ' Skill') }}</div>\r\n </div>\r\n <div class=\"card-body p-4\">\r\n <div *ngIf=\"skillFormIssues().length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ skillFormIssues().join(' \u2022 ') }}</div>\r\n </div>\r\n <div class=\"row g-3\">\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Skills Name <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.name\"\r\n (ngModelChange)=\"patchSkillForm({ name: $event })\"\r\n name=\"skillName\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(skillForm()?.name)\">Skillset name is required</div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Service Provider</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.providerName\"\r\n (ngModelChange)=\"patchSkillForm({ providerName: $event })\"\r\n name=\"skillProvider\"\r\n placeholder=\"Service Provider\"\r\n />\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block mb-1\">Self-ability Rating <span class=\"text-danger\">*</span></label>\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <button\r\n *ngFor=\"let s of [1,2,3,4,5]\"\r\n type=\"button\"\r\n class=\"btn btn-link p-0 text-decoration-none\"\r\n (click)=\"setTempSkillStars(s)\"\r\n [attr.aria-label]=\"'Set rating ' + s\"\r\n >\r\n <span [class]=\"(skillForm()?.stars || 0) >= s ? 'text-warning fs-5' : 'text-muted fs-5'\">\r\n {{ (skillForm()?.stars || 0) >= s ? '\u2605' : '\u2606' }}\r\n </span>\r\n </button>\r\n <span class=\"small text-muted\">{{ skillForm()?.stars || 0 }}/5</span>\r\n </div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"(skillForm()?.stars || 0) <= 0\">Star rating is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Years of Experience <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"number\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.year\"\r\n (ngModelChange)=\"patchSkillForm({ year: $event === '' ? null : +$event })\"\r\n name=\"skillYear\"\r\n min=\"1\"\r\n max=\"30\"\r\n placeholder=\"Years of Experience\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"skillForm()?.year === null || skillForm()?.year === undefined\">Years of experience is required</div>\r\n </div>\r\n\r\n <div class=\"col-md-4\">\r\n <label class=\"small text-muted d-block\">Profile Visibility</label>\r\n <div class=\"form-check form-switch mt-2\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [ngModel]=\"skillForm()?.profileVisibility\"\r\n (ngModelChange)=\"patchSkillForm({ profileVisibility: $event })\"\r\n name=\"skillVisible\"\r\n id=\"skillVisible\"\r\n />\r\n <label class=\"form-check-label\" for=\"skillVisible\">Visible</label>\r\n </div>\r\n </div>\r\n\r\n <div class=\"col-12\">\r\n <label class=\"small text-muted d-block\">Comment</label>\r\n <textarea\r\n rows=\"4\"\r\n class=\"form-control\"\r\n [ngModel]=\"skillForm()?.notes\"\r\n (ngModelChange)=\"patchSkillForm({ notes: $event })\"\r\n name=\"skillNotes\"\r\n placeholder=\"Comment your skill here...\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-footer bg-white d-flex justify-content-end gap-2\">\r\n <button\r\n *ngIf=\"!isAddingSkill() && editingSkillIndex() !== null\"\r\n type=\"button\"\r\n class=\"btn btn-link text-danger me-auto\"\r\n (click)=\"deleteSkill(editingSkillIndex()!)\"\r\n >\r\n Delete\r\n </button>\r\n <button type=\"button\" class=\"btn btn-link text-secondary\" (click)=\"closeSkillEditor()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary px-4\" (click)=\"saveSkillEditor()\">\r\n {{ isAddingSkill() ? 'Save' : 'Update' }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n <div class=\"row g-4 mb-5\">\r\n <div class=\"col-md-12\">\r\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <h5 class=\"fw-bold mb-0\">Education</h5>\r\n <span *ngIf=\"educationSectionHasIssues()\" class=\"badge bg-warning-subtle text-warning border section-flag\">\r\n Missing info\r\n </span>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary rounded-circle d-inline-flex align-items-center justify-content-center\"\r\n style=\"width: 32px; height: 32px; line-height: 1;\"\r\n title=\"Add education\"\r\n (click)=\"addEducation()\"\r\n >\r\n <span class=\"fw-bold fs-5\">+</span>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"educationList().length === 0 && !isAddingEducation() && editingEducationIndex() === null\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">Add at least one education.</div>\r\n </div>\r\n\r\n <div *ngIf=\"isAddingEducation() && tempEducation()\" class=\"p-3 bg-white border rounded shadow-sm mb-2\">\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degree\"\r\n (ngModelChange)=\"patchTempEducation({ degree: $event })\"\r\n name=\"newEduDegree\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degree)\">Degree / Course name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">INSTITUTION <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.institution\"\r\n (ngModelChange)=\"patchTempEducation({ institution: $event })\"\r\n name=\"newEduInstitution\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE / COURSE TYPE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degreeType\"\r\n (ngModelChange)=\"patchTempEducation({ degreeType: $event })\"\r\n name=\"newEduDegreeType\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degreeType)\">Degree / Course type is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.startDate\"\r\n (ngModelChange)=\"patchTempEducation({ startDate: $event })\"\r\n name=\"newEduStartDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.endDate\"\r\n (ngModelChange)=\"patchTempEducation({ endDate: $event })\"\r\n name=\"newEduEndDate\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempEducation()?.startDate, tempEducation()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n </form>\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditEducation()\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-sm btn-success px-4\" (click)=\"saveEducation()\">Save</button>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let edu of educationList(); let ei = index\" class=\"p-3 bg-white border rounded shadow-sm mb-2\">\r\n <div class=\"d-flex justify-content-between align-items-start\">\r\n <div>\r\n <h6 class=\"fw-bold mb-1\">{{ edu.degree }}</h6>\r\n <p class=\"small text-primary mb-0\">{{ edu.institution }}</p>\r\n <div *ngIf=\"(educationIssuesByIndex()[ei] || []).length > 0\" class=\"alert alert-warning py-1 px-2 mt-2\">\r\n <div class=\"fw-semibold small\">Missing required fields</div>\r\n <div class=\"small\">{{ (educationIssuesByIndex()[ei] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n </div>\r\n <div class=\"d-flex align-items-center gap-2\" *ngIf=\"editingEducationIndex() !== ei\">\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-primary action-icon-btn\"\r\n (click)=\"startEditEducation(ei)\"\r\n title=\"Edit\"\r\n >\r\n <img class=\"action-icon-image edit-icon\" src=\"/assets/images/icons/edit-text.png\" alt=\"Edit\" />\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-sm btn-outline-danger action-icon-btn\"\r\n (click)=\"deleteEducation(ei)\"\r\n title=\"Delete\"\r\n >\r\n <img class=\"action-icon-image delete-icon\" src=\"/assets/images/icons/delete.png\" alt=\"Delete\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"editingEducationIndex() === ei\" class=\"mt-3\">\r\n <div *ngIf=\"(educationIssuesByIndex()[ei] || []).length > 0\" class=\"alert alert-warning py-2 px-3 mb-3\">\r\n <div class=\"fw-semibold\">Missing required fields</div>\r\n <div class=\"small\">{{ (educationIssuesByIndex()[ei] || []).join(' \u2022 ') }}</div>\r\n </div>\r\n <form class=\"row g-2\">\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degree\"\r\n (ngModelChange)=\"patchTempEducation({ degree: $event })\"\r\n name=\"eduDegree{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degree)\">Degree / Course name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">INSTITUTION <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.institution\"\r\n (ngModelChange)=\"patchTempEducation({ institution: $event })\"\r\n name=\"eduInstitution{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.institution)\">Institution name is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">DEGREE / COURSE TYPE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.degreeType\"\r\n (ngModelChange)=\"patchTempEducation({ degreeType: $event })\"\r\n name=\"eduDegreeType{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.degreeType)\">Degree / Course type is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">City</label>\r\n <input\r\n type=\"text\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.city\"\r\n (ngModelChange)=\"patchTempEducation({ city: $event })\"\r\n name=\"eduCity{{ ei }}\"\r\n />\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">START DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.startDate\"\r\n (ngModelChange)=\"patchTempEducation({ startDate: $event })\"\r\n name=\"eduStartDate{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.startDate)\">Start date is required</div>\r\n </div>\r\n <div class=\"col-md-6\">\r\n <label class=\"small text-muted d-block\">END DATE <span class=\"text-danger\">*</span></label>\r\n <input\r\n type=\"month\"\r\n class=\"form-control form-control-sm\"\r\n [ngModel]=\"tempEducation()?.endDate\"\r\n (ngModelChange)=\"patchTempEducation({ endDate: $event })\"\r\n name=\"eduEndDate{{ ei }}\"\r\n />\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isBlank(tempEducation()?.endDate)\">End date is required</div>\r\n <div class=\"small text-danger mt-1\" *ngIf=\"isMonthRangeInvalid(tempEducation()?.startDate, tempEducation()?.endDate)\">\r\n Start date must be less than end date\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"d-flex justify-content-end gap-2 mt-2\">\r\n <button class=\"btn btn-sm btn-link text-secondary\" (click)=\"cancelEditEducation()\">Cancel</button>\r\n <button class=\"btn btn-sm btn-success px-4\" (click)=\"saveEducation()\">Save</button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"educationList().length === 0\" class=\"text-muted small\">No education added.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"d-flex gap-2 justify-content-center mt-5\">\r\n <button class=\"btn btn-outline-secondary px-5\" (click)=\"onBackClick()\">Back</button>\r\n <button\r\n class=\"btn btn-primary px-5 shadow\"\r\n [disabled]=\"!canConfirmAndContinue()\"\r\n [title]=\"canConfirmAndContinue() ? '' : 'Please fill all required fields in all mandatory sections.'\"\r\n (click)=\"saveResumedetails()\"\r\n >\r\n Confirm & Continue\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #loading>\r\n <div class=\"text-center p-5\">\r\n <div class=\"spinner-border text-primary\"></div>\r\n <p class=\"text-muted mt-2\">Loading data...</p>\r\n </div>\r\n</ng-template>\r\n\r\n<div class=\"modal-overlay\" *ngIf=\"showPopup\" (click)=\"closeSavePopup()\">\r\n <div class=\"status-modal-card\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"status-modal-header\">\r\n <h3 class=\"mb-1\">Saving Resume Details</h3>\r\n <p class=\"text-muted mb-0\">Please wait while we process each section.</p>\r\n </div>\r\n\r\n <div class=\"status-modal-body\">\r\n <div class=\"status-modal-row\" *ngFor=\"let item of statusList\">\r\n <div class=\"status-modal-name\">{{ item.name }}</div>\r\n\r\n <div class=\"status-modal-state pending\" *ngIf=\"item.status === 'pending'\">\r\n <span class=\"spinner-border spinner-border-sm me-2\"></span> In progress\r\n </div>\r\n\r\n <div class=\"status-modal-state success\" *ngIf=\"item.status === 'success'\">\r\n <span class=\"me-1\">\u2713</span> Success\r\n </div>\r\n\r\n <div class=\"status-modal-state partial\" *ngIf=\"item.status === 'partial'\">\r\n <span class=\"me-1\">!</span> {{ item.successCount }} Success / {{ item.failCount }} Failed\r\n </div>\r\n\r\n <div class=\"status-modal-state error\" *ngIf=\"item.status === 'error'\">\r\n <span class=\"me-1\">\u2716</span> {{ item.error || 'Failed' }}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"status-modal-footer\">\r\n <button type=\"button\" class=\"btn btn-outline-secondary\" (click)=\"closeSavePopup()\">Back to Preview</button>\r\n <div class=\"d-flex justify-content-end\">\r\n <button\r\n *ngIf=\"allSaveStepsSucceeded()\"\r\n type=\"button\"\r\n class=\"btn btn-primary\"\r\n (click)=\"goToDashboard()\"\r\n >\r\n Go to Dashboard\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"modal-overlay\" *ngIf=\"showBackConfirmPopup\">\r\n <div class=\"confirm-modal-card\">\r\n <h4 class=\"mb-2\">Leave this page?</h4>\r\n <p class=\"text-muted mb-4\">Your data might be lost if you go back now.</p>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n <button type=\"button\" class=\"btn btn-outline-secondary\" (click)=\"stayOnPreview()\">Stay</button>\r\n <button type=\"button\" class=\"btn btn-danger\" (click)=\"proceedBack()\">Proceed Back</button>\r\n </div>\r\n </div>\r\n</div>", styles: [".container{max-width:900px;margin:30px auto;font-family:Arial,sans-serif;color:#333}.preview-page-header{max-width:900px;margin:50px auto 10px;padding:0 12px}.preview-title{font-weight:600;margin:0}.preview-subtitle{margin-top:7px;font-size:16px}.section{margin-bottom:25px}.section-title{font-weight:600;display:block;margin-bottom:8px}.section-title .sub{font-weight:400;color:#777;font-size:13px}.dropdown-box{border:1px solid #ddd;border-radius:8px;padding:12px 15px;display:flex;justify-content:space-between;align-items:center}.icons{display:flex;gap:10px}.icon{cursor:pointer;font-size:14px;color:#777}.card{border:1px solid #ddd;border-radius:10px;padding:20px;background:#fff}.category{border-bottom:1px solid #eee;padding:15px 0}.category:last-child{border-bottom:none}.category-header{display:flex;justify-content:space-between;font-weight:600;margin-bottom:10px}.tags{display:flex;flex-wrap:wrap;gap:10px}.tag{background:#f2f4f7;padding:6px 12px;border-radius:6px;font-size:13px}.footer{text-align:center;margin-top:15px;color:#777;cursor:pointer}.actions{display:flex;justify-content:space-between;margin:50px 0 27px}.text-secondary{white-space:pre-line;font-size:.95rem}.extra-small{font-size:.8rem}.card{transition:transform .2s ease,box-shadow .2s ease}.card:hover{transform:translateY(-3px);box-shadow:0 .5rem 1rem #0000001a!important}.achievement-section .badge{font-size:.75rem;white-space:normal;text-align:left}.skill-tag .badge{font-weight:500;font-size:.9rem;transition:all .2s ease;cursor:default}.skill-tag .badge:hover{transform:translateY(-2px);box-shadow:0 4px 8px #0000001a}.skill-tag .btn-close{opacity:.5}.skill-tag .btn-close:hover{opacity:1}.bg-light.text-dark.border{background-color:#f8f9fa!important;border-color:#dee2e6!important}.card{transition:all .3s cubic-bezier(.25,.8,.25,1)}.card:hover{box-shadow:0 10px 20px #0000001a!important}.card:hover .bg-light{background-color:#e8f5e9!important}.position-fixed .card:hover{transform:none!important}code{background-color:#f8f9fa;padding:2px 6px;border-radius:4px}.list-group-item{transition:all .2s ease-in-out}.list-group-item:hover{background-color:#fcfcfc;transform:translate(5px);box-shadow:-5px 0 15px #0000000d}.border-dashed{border-style:dashed!important}.tool-card{transition:all .2s ease-in-out;border-radius:12px}.tool-card:hover{transform:translateY(-5px);border-color:var(--bs-primary)!important;box-shadow:0 10px 15px #0000001a!important}.tool-card:hover .icon-box{background-color:var(--bs-primary-subtle)!important}.tool-card .icon-box{width:60px;height:60px;transition:background-color .2s ease}.border-dashed{border:2px dashed #dee2e6!important}.border-dashed:hover{border-color:var(--bs-primary)!important;background-color:#fff!important}.popup{position:fixed;top:20%;right:20px;width:320px;background:#fff;border-radius:10px;padding:16px;box-shadow:0 4px 12px #0003}.status-row{display:flex;justify-content:space-between;margin:10px 0}.success{color:#2e7d32;font-weight:700}.error{color:#d32f2f}.pending{color:#f9a825}.section-flag{font-weight:600}button.btn.btn-sm.btn-outline-primary{background-color:#4077ad;border-color:#4077ad;color:#fff;border-radius:10px}button.btn.btn-sm.btn-outline-primary:hover{background-color:#356895;border-color:#356895;color:#fff}button.btn.btn-sm.btn-outline-danger{border-color:#dc3545;color:#dc3545;border-radius:10px}button.btn.btn-sm.btn-outline-danger:hover{background-color:#bb2d3b;border-color:#bb2d3b;color:#fff}button.btn.btn-sm.btn-outline-primary.rounded-circle{background-color:#4077ad;border-color:#4077ad;color:#fff;border-radius:50%!important}button.action-icon-btn{min-width:22px;width:22px;height:22px;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0!important;background:transparent!important;border:none!important;box-shadow:none!important;line-height:1}button.action-icon-btn.btn-outline-primary{color:#4077ad!important;border-color:#4077ad!important}button.action-icon-btn.btn-outline-danger{color:#dc3545!important}.action-icon-image{width:20px;height:20px;object-fit:contain;display:inline-block}.action-icon-image.edit-icon{filter:brightness(0) saturate(100%) invert(41%) sepia(39%) saturate(774%) hue-rotate(170deg) brightness(91%) contrast(89%)}.action-icon-image.delete-icon{filter:brightness(0) saturate(100%) invert(24%) sepia(79%) saturate(4008%) hue-rotate(344deg) brightness(91%) contrast(90%)}.modal-overlay{position:fixed;inset:0;background:#11182773;display:flex;align-items:center;justify-content:center;z-index:2500;padding:20px}.status-modal-card{width:min(760px,96vw);max-height:85vh;overflow:auto;background:#fff;border-radius:16px;box-shadow:0 20px 40px #0f172a40;border:1px solid #e5e7eb}.status-modal-header{padding:20px 24px 14px;border-bottom:1px solid #eef2f7}.status-modal-body{padding:12px 20px 20px}.status-modal-footer{padding:12px 20px 20px;border-top:1px solid #eef2f7;display:flex;justify-content:space-between;align-items:center;gap:12px}.status-modal-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 10px;border-bottom:1px solid #f1f5f9}.status-modal-row:last-child{border-bottom:0}.status-modal-name{font-weight:600;color:#1f2937}.status-modal-state{font-size:.92rem;font-weight:600}.status-modal-state.pending{color:#a16207}.status-modal-state.success{color:#166534}.status-modal-state.partial{color:#b45309}.status-modal-state.error{color:#b91c1c}.confirm-modal-card{width:min(520px,96vw);background:#fff;border-radius:14px;box-shadow:0 20px 35px #0f172a38;border:1px solid #e5e7eb;padding:24px}.year-experience-select{max-height:150px}\n"] }]
30588
+ }], ctorParameters: () => [{ type: CredentialingStore }, { type: UserSkillSetService }, { type: UserToolService }, { type: UserDocumentService }, { type: UserEducationService }, { type: UserDetailService }, { type: UserExperienceService }, { type: i2.Router }, { type: i6.TokenService }], propDecorators: { backToParent: [{
30589
+ type: Output
30590
+ }] } });
30591
+
29272
30592
  class CredentialingComponent {
29273
30593
  store;
29274
30594
  postalCodeService;
@@ -29319,7 +30639,7 @@ class CredentialingComponent {
29319
30639
  console.log(this.states);
29320
30640
  }
29321
30641
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CredentialingComponent, deps: [{ token: CredentialingStore }, { token: PostalCodeServices }, { token: LIBRARY_CONFIG }, { token: i11.ViewportScroller }], target: i0.ɵɵFactoryTarget.Component });
29322
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CredentialingComponent, isStandalone: false, selector: "app-credentialing", inputs: { data: "data" }, outputs: { back: "back" }, ngImport: i0, template: "<div class=\"credentialing-container\">\r\n <app-stepper *ngIf=\"!store.isUploadSuccess()\"></app-stepper>\r\n <div class=\"step-content\" [@stepTransition]=\"store.currentStep()\">\r\n <app-first *ngIf=\"store.currentStep() === 1\" (backToParent)=\"goBackToInitialProcess()\" [roleData]=\"data\">\r\n </app-first>\r\n <ng-container *ngIf=\"store.isUploadSuccess()\">\r\n <app-preview *ngIf=\"store.currentStep() === 2\"></app-preview>\r\n </ng-container>\r\n <ng-container *ngIf=\"!store.isUploadSuccess()\">\r\n <app-role-select [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n [cloudfrontUrl]=\"cloudfrontUrl\" [roleData]=\"data\" *ngIf=\"store.currentStep() === 1\"></app-role-select>\r\n <app-coverage [states]=\"states\" [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 2\"></app-coverage>\r\n <app-workexperience [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 3\"></app-workexperience>\r\n <app-education [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 4\"></app-education>\r\n <app-certification [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 5\"></app-certification>\r\n <app-licenses [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 6\"></app-licenses>\r\n <app-skills [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 7\"></app-skills>\r\n <app-tools [providerName]=\"providerName\" [providerId]=\"providerId\" [roleData]=\"data\"\r\n *ngIf=\"store.currentStep() === 8\"></app-tools>\r\n </ng-container>\r\n </div>\r\n</div>", styles: ["::ng-deep .ng-select.ng-select-single .ng-select-container{height:45px!important;border:1px solid #dee2e6}.step-content{position:relative;min-height:400px}\n"], dependencies: [{ kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: StepperComponent, selector: "app-stepper" }, { kind: "component", type: EducationComponent, selector: "app-education", inputs: ["providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: CertificationComponent, selector: "app-certification", inputs: ["states", "providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: SkillsComponent, selector: "app-skills", inputs: ["providerId", "providerName"] }, { kind: "component", type: LicensesComponent, selector: "app-licenses", inputs: ["providerId", "providerName", "cloudfrontUrl", "states"] }, { kind: "component", type: ToolsComponent, selector: "app-tools", inputs: ["roleData", "providerId", "providerName"] }, { kind: "component", type: RoleSelectComponent, selector: "app-role-select", inputs: ["roleData", "cloudfrontUrl", "providerId", "providerName"], outputs: ["backToParent"] }, { kind: "component", type: Step2CoverageComponent, selector: "app-coverage", inputs: ["providerId", "providerName", "states"] }, { kind: "component", type: WorkexperienceComponent, selector: "app-workexperience", inputs: ["providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: FirstComponent, selector: "app-first", outputs: ["backToParent", "nextStep"] }], animations: [
30642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CredentialingComponent, isStandalone: false, selector: "app-credentialing", inputs: { data: "data" }, outputs: { back: "back" }, ngImport: i0, template: "<div class=\"credentialing-container\">\r\n <app-stepper *ngIf=\"!store.isUploadSuccess()\"></app-stepper>\r\n <div class=\"step-content\" [@stepTransition]=\"store.currentStep()\">\r\n <app-first *ngIf=\"store.currentStep() === 1\" (backToParent)=\"goBackToInitialProcess()\" [roleData]=\"data\">\r\n </app-first>\r\n <ng-container *ngIf=\"store.isUploadSuccess()\">\r\n <app-preview *ngIf=\"store.currentStep() === 2\"></app-preview>\r\n </ng-container>\r\n <ng-container *ngIf=\"!store.isUploadSuccess()\">\r\n <app-role-select [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n [cloudfrontUrl]=\"cloudfrontUrl\" [roleData]=\"data\" *ngIf=\"store.currentStep() === 2\"></app-role-select>\r\n <app-coverage [states]=\"states\" [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 3\"></app-coverage>\r\n <app-workexperience [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 4\"></app-workexperience>\r\n <app-education [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 5\"></app-education>\r\n <app-certification [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 6\"></app-certification>\r\n <app-licenses [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 7\"></app-licenses>\r\n <app-skills [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 8\"></app-skills>\r\n <app-tools [providerName]=\"providerName\" [providerId]=\"providerId\" [roleData]=\"data\"\r\n *ngIf=\"store.currentStep() === 9\"></app-tools>\r\n </ng-container>\r\n </div>\r\n</div>", styles: ["::ng-deep .ng-select.ng-select-single .ng-select-container{height:45px!important;border:1px solid #dee2e6}.step-content{position:relative;min-height:400px}\n"], dependencies: [{ kind: "directive", type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: StepperComponent, selector: "app-stepper" }, { kind: "component", type: EducationComponent, selector: "app-education", inputs: ["providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: CertificationComponent, selector: "app-certification", inputs: ["states", "providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: SkillsComponent, selector: "app-skills", inputs: ["providerId", "providerName"] }, { kind: "component", type: LicensesComponent, selector: "app-licenses", inputs: ["providerId", "providerName", "cloudfrontUrl", "states"] }, { kind: "component", type: ToolsComponent, selector: "app-tools", inputs: ["roleData", "providerId", "providerName"] }, { kind: "component", type: RoleSelectComponent, selector: "app-role-select", inputs: ["roleData", "cloudfrontUrl", "providerId", "providerName"], outputs: ["backToParent"] }, { kind: "component", type: Step2CoverageComponent, selector: "app-coverage", inputs: ["providerId", "providerName", "states"] }, { kind: "component", type: WorkexperienceComponent, selector: "app-workexperience", inputs: ["providerId", "providerName", "cloudfrontUrl"] }, { kind: "component", type: FirstComponent, selector: "app-first", outputs: ["backToParent", "nextStep"] }, { kind: "component", type: PreviewComponent, selector: "app-preview", outputs: ["backToParent"] }], animations: [
29323
30643
  trigger('stepTransition', [
29324
30644
  transition('* <=> *', [
29325
30645
  style({
@@ -29349,7 +30669,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
29349
30669
  }))
29350
30670
  ])
29351
30671
  ])
29352
- ], template: "<div class=\"credentialing-container\">\r\n <app-stepper *ngIf=\"!store.isUploadSuccess()\"></app-stepper>\r\n <div class=\"step-content\" [@stepTransition]=\"store.currentStep()\">\r\n <app-first *ngIf=\"store.currentStep() === 1\" (backToParent)=\"goBackToInitialProcess()\" [roleData]=\"data\">\r\n </app-first>\r\n <ng-container *ngIf=\"store.isUploadSuccess()\">\r\n <app-preview *ngIf=\"store.currentStep() === 2\"></app-preview>\r\n </ng-container>\r\n <ng-container *ngIf=\"!store.isUploadSuccess()\">\r\n <app-role-select [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n [cloudfrontUrl]=\"cloudfrontUrl\" [roleData]=\"data\" *ngIf=\"store.currentStep() === 1\"></app-role-select>\r\n <app-coverage [states]=\"states\" [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 2\"></app-coverage>\r\n <app-workexperience [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 3\"></app-workexperience>\r\n <app-education [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 4\"></app-education>\r\n <app-certification [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 5\"></app-certification>\r\n <app-licenses [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 6\"></app-licenses>\r\n <app-skills [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 7\"></app-skills>\r\n <app-tools [providerName]=\"providerName\" [providerId]=\"providerId\" [roleData]=\"data\"\r\n *ngIf=\"store.currentStep() === 8\"></app-tools>\r\n </ng-container>\r\n </div>\r\n</div>", styles: ["::ng-deep .ng-select.ng-select-single .ng-select-container{height:45px!important;border:1px solid #dee2e6}.step-content{position:relative;min-height:400px}\n"] }]
30672
+ ], template: "<div class=\"credentialing-container\">\r\n <app-stepper *ngIf=\"!store.isUploadSuccess()\"></app-stepper>\r\n <div class=\"step-content\" [@stepTransition]=\"store.currentStep()\">\r\n <app-first *ngIf=\"store.currentStep() === 1\" (backToParent)=\"goBackToInitialProcess()\" [roleData]=\"data\">\r\n </app-first>\r\n <ng-container *ngIf=\"store.isUploadSuccess()\">\r\n <app-preview *ngIf=\"store.currentStep() === 2\"></app-preview>\r\n </ng-container>\r\n <ng-container *ngIf=\"!store.isUploadSuccess()\">\r\n <app-role-select [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n [cloudfrontUrl]=\"cloudfrontUrl\" [roleData]=\"data\" *ngIf=\"store.currentStep() === 2\"></app-role-select>\r\n <app-coverage [states]=\"states\" [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 3\"></app-coverage>\r\n <app-workexperience [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 4\"></app-workexperience>\r\n <app-education [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 5\"></app-education>\r\n <app-certification [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 6\"></app-certification>\r\n <app-licenses [states]=\"states\" [cloudfrontUrl]=\"cloudfrontUrl\" [providerName]=\"providerName\"\r\n [providerId]=\"providerId\" *ngIf=\"store.currentStep() === 7\"></app-licenses>\r\n <app-skills [providerName]=\"providerName\" [providerId]=\"providerId\"\r\n *ngIf=\"store.currentStep() === 8\"></app-skills>\r\n <app-tools [providerName]=\"providerName\" [providerId]=\"providerId\" [roleData]=\"data\"\r\n *ngIf=\"store.currentStep() === 9\"></app-tools>\r\n </ng-container>\r\n </div>\r\n</div>", styles: ["::ng-deep .ng-select.ng-select-single .ng-select-container{height:45px!important;border:1px solid #dee2e6}.step-content{position:relative;min-height:400px}\n"] }]
29353
30673
  }], ctorParameters: () => [{ type: CredentialingStore }, { type: PostalCodeServices }, { type: undefined, decorators: [{
29354
30674
  type: Inject,
29355
30675
  args: [LIBRARY_CONFIG]
@@ -31202,7 +32522,8 @@ const INTERNAL_COMPONENTS = [
31202
32522
  RoleSelectComponent,
31203
32523
  Step2CoverageComponent,
31204
32524
  WorkexperienceComponent,
31205
- FirstComponent
32525
+ FirstComponent,
32526
+ PreviewComponent
31206
32527
  ];
31207
32528
  class InitialProcessModule {
31208
32529
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InitialProcessModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -31218,7 +32539,8 @@ class InitialProcessModule {
31218
32539
  RoleSelectComponent,
31219
32540
  Step2CoverageComponent,
31220
32541
  WorkexperienceComponent,
31221
- FirstComponent], imports: [CommonModule,
32542
+ FirstComponent,
32543
+ PreviewComponent], imports: [CommonModule,
31222
32544
  FormsModule,
31223
32545
  ReactiveFormsModule,
31224
32546
  RouterModule,