mesauth-angular 1.8.3 → 1.8.4

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.
@@ -10,7 +10,7 @@ import { DomSanitizer } from '@angular/platform-browser';
10
10
  import { DatePipe } from '@angular/common';
11
11
 
12
12
  /** Current installed package version — keep in sync with package.json. */
13
- const PACKAGE_VERSION = '1.8.3';
13
+ const PACKAGE_VERSION = '1.8.4';
14
14
  /**
15
15
  * Provides server-driven UI configuration loaded from the hosted manifest.
16
16
  * Components read `labels()` and `features()` signals instead of hardcoded strings.
@@ -1224,18 +1224,20 @@ class MaArvContainerComponent {
1224
1224
  routingMode = 'template';
1225
1225
  templates = signal([], ...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ []));
1226
1226
  selectedTemplateId = null;
1227
- selectedTemplate = null;
1227
+ selectedTemplate = signal(null, ...(ngDevMode ? [{ debugName: "selectedTemplate" }] : /* istanbul ignore next */ []));
1228
1228
  loadingTemplate = signal(false, ...(ngDevMode ? [{ debugName: "loadingTemplate" }] : /* istanbul ignore next */ []));
1229
1229
  // Per-step role candidates and selected user
1230
- stepCandidates = [];
1231
- stepLoadingCandidates = [];
1232
- stepSelectedUsers = [];
1230
+ stepCandidates = signal([], ...(ngDevMode ? [{ debugName: "stepCandidates" }] : /* istanbul ignore next */ []));
1231
+ stepLoadingCandidates = signal([], ...(ngDevMode ? [{ debugName: "stepLoadingCandidates" }] : /* istanbul ignore next */ []));
1232
+ stepSelectedUsers = signal([], ...(ngDevMode ? [{ debugName: "stepSelectedUsers" }] : /* istanbul ignore next */ []));
1233
1233
  adHocSteps = [];
1234
1234
  referenceUserIds = [];
1235
1235
  refSearchQuery = '';
1236
1236
  refSearchResults = [];
1237
1237
  userSearchQuery = [];
1238
1238
  userSearchResults = [];
1239
+ candidateSearchQuery = [];
1240
+ candidateSearchResults = [];
1239
1241
  submitting = false;
1240
1242
  isSubmitted = false;
1241
1243
  errorMessage = '';
@@ -1271,13 +1273,13 @@ class MaArvContainerComponent {
1271
1273
  }
1272
1274
  loadTemplateDetail(id) {
1273
1275
  this.loadingTemplate.set(true);
1274
- this.selectedTemplate = null;
1275
- this.stepCandidates = [];
1276
- this.stepLoadingCandidates = [];
1277
- this.stepSelectedUsers = [];
1276
+ this.selectedTemplate.set(null);
1277
+ this.stepCandidates.set([]);
1278
+ this.stepLoadingCandidates.set([]);
1279
+ this.stepSelectedUsers.set([]);
1278
1280
  this.approvalSvc.getTemplate(id).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
1279
1281
  next: (t) => {
1280
- this.selectedTemplate = t;
1282
+ this.selectedTemplate.set(t);
1281
1283
  this.loadingTemplate.set(false);
1282
1284
  this.loadStepCandidates(t.steps);
1283
1285
  },
@@ -1285,14 +1287,18 @@ class MaArvContainerComponent {
1285
1287
  });
1286
1288
  }
1287
1289
  loadStepCandidates(steps) {
1288
- this.stepCandidates = steps.map(() => []);
1289
- this.stepLoadingCandidates = steps.map(() => false);
1290
- this.stepSelectedUsers = steps.map(() => '');
1290
+ this.stepCandidates.set(steps.map(() => []));
1291
+ this.stepLoadingCandidates.set(steps.map(() => false));
1292
+ this.stepSelectedUsers.set(steps.map(() => ''));
1291
1293
  const config = this.mesAuth.getConfig();
1292
1294
  steps.forEach((step, i) => {
1293
1295
  if (step.roles && step.roles.length > 0) {
1294
1296
  // Role-based: fetch candidates via role preview
1295
- this.stepLoadingCandidates[i] = true;
1297
+ this.stepLoadingCandidates.update(c => {
1298
+ const next = [...c];
1299
+ next[i] = true;
1300
+ return next;
1301
+ });
1296
1302
  const calls = step.roles.map(r => this.approvalSvc.previewRole(r.orgCode, r.positionLevel));
1297
1303
  forkJoin(calls.length > 0 ? calls : [of([])])
1298
1304
  .pipe(takeUntilDestroyed(this.destroyRef))
@@ -1300,19 +1306,41 @@ class MaArvContainerComponent {
1300
1306
  next: results => {
1301
1307
  const merged = new Map();
1302
1308
  results.forEach(list => list.forEach(u => merged.set(u.userId, u)));
1303
- this.stepCandidates[i] = Array.from(merged.values());
1309
+ this.stepCandidates.update(c => {
1310
+ const next = [...c];
1311
+ next[i] = Array.from(merged.values());
1312
+ return next;
1313
+ });
1304
1314
  // Single candidate — pre-select automatically
1305
- if (this.stepCandidates[i].length === 1) {
1306
- this.stepSelectedUsers[i] = this.stepCandidates[i][0].userId;
1315
+ if (this.stepCandidates()[i].length === 1) {
1316
+ this.stepSelectedUsers.update(u => {
1317
+ const next = [...u];
1318
+ next[i] = this.stepCandidates()[i][0].userId;
1319
+ return next;
1320
+ });
1307
1321
  }
1308
- this.stepLoadingCandidates[i] = false;
1322
+ this.stepLoadingCandidates.update(c => {
1323
+ const next = [...c];
1324
+ next[i] = false;
1325
+ return next;
1326
+ });
1309
1327
  },
1310
- error: () => { this.stepLoadingCandidates[i] = false; }
1328
+ error: () => {
1329
+ this.stepLoadingCandidates.update(c => {
1330
+ const next = [...c];
1331
+ next[i] = false;
1332
+ return next;
1333
+ });
1334
+ }
1311
1335
  });
1312
1336
  }
1313
1337
  else if (step.assigneeUserIds && step.assigneeUserIds.length > 0 && config) {
1314
1338
  // Search-selected employees: resolve IDs to display names
1315
- this.stepLoadingCandidates[i] = true;
1339
+ this.stepLoadingCandidates.update(c => {
1340
+ const next = [...c];
1341
+ next[i] = true;
1342
+ return next;
1343
+ });
1316
1344
  const base = config.apiBaseUrl.replace(/\/$/, '');
1317
1345
  const opts = { withCredentials: config.withCredentials ?? true };
1318
1346
  const calls = step.assigneeUserIds.map(uid => this.http.get(`${base}/urs/users/${encodeURIComponent(uid)}`, opts));
@@ -1320,31 +1348,67 @@ class MaArvContainerComponent {
1320
1348
  .pipe(takeUntilDestroyed(this.destroyRef))
1321
1349
  .subscribe({
1322
1350
  next: results => {
1323
- this.stepCandidates[i] = results.map((u) => ({
1324
- userId: u.id || u.Id,
1325
- fullName: u.fullName || u.FullName || u.userName || u.UserName,
1326
- department: u.department || u.Department,
1327
- position: u.position || u.Position,
1328
- employeeCode: u.employeeCode || u.EmployeeCode
1329
- }));
1351
+ this.stepCandidates.update(candidates => {
1352
+ candidates[i] = results.map((u) => ({
1353
+ userId: u.id || u.Id,
1354
+ fullName: u.fullName || u.FullName || u.userName || u.UserName,
1355
+ department: u.department || u.Department,
1356
+ position: u.position || u.Position,
1357
+ employeeCode: u.employeeCode || u.EmployeeCode
1358
+ }));
1359
+ return candidates;
1360
+ });
1330
1361
  // Single assignee — pre-select automatically
1331
- if (this.stepCandidates[i].length === 1) {
1332
- this.stepSelectedUsers[i] = this.stepCandidates[i][0].userId;
1362
+ if (this.stepCandidates()[i].length === 1) {
1363
+ this.stepSelectedUsers.update(users => {
1364
+ users[i] = this.stepCandidates()[i][0].userId;
1365
+ return users;
1366
+ });
1333
1367
  }
1334
- this.stepLoadingCandidates[i] = false;
1368
+ this.stepLoadingCandidates.update(c => {
1369
+ const next = [...c];
1370
+ next[i] = false;
1371
+ return next;
1372
+ });
1335
1373
  },
1336
- error: () => { this.stepLoadingCandidates[i] = false; }
1374
+ error: () => {
1375
+ this.stepLoadingCandidates.update(c => {
1376
+ const next = [...c];
1377
+ next[i] = false;
1378
+ return next;
1379
+ });
1380
+ }
1337
1381
  });
1338
1382
  }
1339
1383
  });
1340
1384
  }
1341
1385
  onStepUserChange(stepIndex, event) {
1342
- this.stepSelectedUsers[stepIndex] = event.target.value;
1386
+ this.stepSelectedUsers.update(users => {
1387
+ users[stepIndex] = event.target.value;
1388
+ return users;
1389
+ });
1390
+ }
1391
+ onStepUserChangeInput(stepIndex, userId) {
1392
+ this.stepSelectedUsers.update(users => {
1393
+ users[stepIndex] = userId;
1394
+ return users;
1395
+ });
1396
+ this.storeLabelFromCandidates(userId, this.stepCandidates()[stepIndex]);
1397
+ this.candidateSearchQuery[stepIndex] = '';
1398
+ this.candidateSearchResults[stepIndex] = [];
1399
+ }
1400
+ onCandidateSearchInput(stepIndex, query) {
1401
+ this.candidateSearchQuery[stepIndex] = query;
1402
+ if (!query || query.length < 2) {
1403
+ this.candidateSearchResults[stepIndex] = this.stepCandidates()[stepIndex];
1404
+ return;
1405
+ }
1406
+ this.candidateSearchResults[stepIndex] = this.stepCandidates()[stepIndex].filter(u => u.fullName?.toLowerCase().includes(query.toLowerCase()) || u.userId.toLowerCase().includes(query.toLowerCase()));
1343
1407
  }
1344
1408
  onTemplateChange(event) {
1345
1409
  const val = event.target.value;
1346
1410
  this.selectedTemplateId = val ? parseInt(val, 10) : null;
1347
- this.selectedTemplate = null;
1411
+ this.selectedTemplate.set(null);
1348
1412
  if (this.selectedTemplateId) {
1349
1413
  this.loadTemplateDetail(this.selectedTemplateId);
1350
1414
  }
@@ -1383,10 +1447,17 @@ class MaArvContainerComponent {
1383
1447
  storeLabelFromResults(userId, results) {
1384
1448
  const user = results.find((u) => u.id === userId);
1385
1449
  if (user) {
1386
- const parts = [user.department, user.position, user.fullName].filter(Boolean);
1450
+ const parts = [user.department, user.position, user.fullName, user.employeeCode].filter(Boolean);
1387
1451
  this.userLabelMap[userId] = parts.length > 0 ? parts.join(' - ') : (user.userName || userId);
1388
1452
  }
1389
1453
  }
1454
+ storeLabelFromCandidates(userId, candidates) {
1455
+ const user = candidates.find((u) => u.userId === userId);
1456
+ if (user) {
1457
+ const parts = [user.department, user.position, user.fullName, user.employeeCode].filter(Boolean);
1458
+ this.userLabelMap[userId] = parts.length > 0 ? parts.join(' - ') : (user.employeeCode || userId);
1459
+ }
1460
+ }
1390
1461
  removeReference(j) {
1391
1462
  this.referenceUserIds.splice(j, 1);
1392
1463
  }
@@ -1419,7 +1490,8 @@ class MaArvContainerComponent {
1419
1490
  fullName: u.fullName || u.FullName,
1420
1491
  email: u.email || u.Email,
1421
1492
  department: u.department || u.Department,
1422
- position: u.position || u.Position
1493
+ position: u.position || u.Position,
1494
+ employeeCode: u.employeeCode || u.EmployeeCode
1423
1495
  }));
1424
1496
  }).catch(() => []);
1425
1497
  }
@@ -1448,11 +1520,11 @@ class MaArvContainerComponent {
1448
1520
  return;
1449
1521
  }
1450
1522
  // Validate selectable steps (role-based or multi-assignee) have a selected approver
1451
- if (this.routingMode === 'template' && this.selectedTemplate) {
1452
- for (let i = 0; i < this.selectedTemplate.steps.length; i++) {
1453
- const step = this.selectedTemplate.steps[i];
1523
+ if (this.routingMode === 'template' && this.selectedTemplate()) {
1524
+ for (let i = 0; i < this.selectedTemplate().steps.length; i++) {
1525
+ const step = this.selectedTemplate().steps[i];
1454
1526
  const isSelectable = (this.stepCandidates[i]?.length ?? 0) > 1;
1455
- if (isSelectable && !this.stepSelectedUsers[i]) {
1527
+ if (isSelectable && !this.stepSelectedUsers()[i]) {
1456
1528
  this.errorMessage = `Please select an approver for step "${step.stepName}".`;
1457
1529
  return;
1458
1530
  }
@@ -1479,15 +1551,15 @@ class MaArvContainerComponent {
1479
1551
  if (this.routingMode === 'template') {
1480
1552
  request.templateId = this.selectedTemplateId ?? this.templateIds()?.[0];
1481
1553
  // If template has role-based steps with selected approvers, pass explicit steps
1482
- if (this.selectedTemplate) {
1483
- const hasSelectableSteps = this.selectedTemplate.steps.some((s, i) => (this.stepCandidates[i]?.length ?? 0) > 0);
1554
+ if (this.selectedTemplate()) {
1555
+ const hasSelectableSteps = this.selectedTemplate().steps.some((s, i) => (this.stepCandidates[i]?.length ?? 0) > 0);
1484
1556
  if (hasSelectableSteps) {
1485
- request.steps = this.selectedTemplate.steps.map((s, i) => ({
1557
+ request.steps = this.selectedTemplate().steps.map((s, i) => ({
1486
1558
  stepOrder: s.stepOrder,
1487
1559
  stepName: s.stepName,
1488
1560
  mode: s.mode,
1489
- approverUserIds: this.stepSelectedUsers[i]
1490
- ? [this.stepSelectedUsers[i]]
1561
+ approverUserIds: this.stepSelectedUsers()[i]
1562
+ ? [this.stepSelectedUsers()[i]]
1491
1563
  : (this.stepCandidates[i] && this.stepCandidates[i].length > 0
1492
1564
  ? this.stepCandidates[i].map(u => u.userId)
1493
1565
  : s.assigneeUserIds)
@@ -1660,11 +1732,11 @@ ${clone.outerHTML}
1660
1732
  ];
1661
1733
  }
1662
1734
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: MaArvContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1663
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, referenceId: { classPropertyName: "referenceId", publicName: "referenceId", isSignal: true, isRequired: false, transformFunction: null }, templateIds: { classPropertyName: "templateIds", publicName: "templateIds", isSignal: true, isRequired: false, transformFunction: null }, callbackUrl: { classPropertyName: "callbackUrl", publicName: "callbackUrl", isSignal: true, isRequired: false, transformFunction: null }, deadlineHours: { classPropertyName: "deadlineHours", publicName: "deadlineHours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalSubmitted: "approvalSubmitted", approvalSubmitting: "approvalSubmitting", cancelled: "cancelled" }, host: { properties: { "class": "this.themeClass" } }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["contentBody"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode === 'template'\" (change)=\"routingMode = 'template'\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode === 'adhoc'\" (change)=\"routingMode = 'adhoc'\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate) {\n <div class=\"arv-template-steps\">\n @for (s of selectedTemplate.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step-card\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n {{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' \u00B7 ' + s.roles[0].orgName : '' }}\n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates[i]?.length > 1 || stepLoadingCandidates[i]) {\n <div class=\"arv-step-picker\">\n @if (stepLoadingCandidates[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates[i]) {\n <select class=\"arv-select arv-select-sm\" (change)=\"onStepUserChange(i, $event)\">\n <option value=\"\">-- Select approver --</option>\n @for (u of stepCandidates[i]; track u.userId) {\n <option [value]=\"u.userId\" [selected]=\"u.userId === stepSelectedUsers[i]\">\n {{ u.fullName || u.userId }}{{ u.department ? ' \u00B7 ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}{{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </option>\n }\n </select>\n }\n </div>\n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates[i] && stepCandidates[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates[i][0].fullName || stepCandidates[i][0].userId }}{{ stepCandidates[i][0].department ? ' \u00B7 ' + stepCandidates[i][0].department : '' }}{{ stepCandidates[i][0].position ? ' (' + stepCandidates[i][0].position + ')' : '' }}{{ stepCandidates[i][0].employeeCode ? ' (' + stepCandidates[i][0].employeeCode + ')' : '' }} \n </div>\n }\n </div>\n }\n @if (selectedTemplate.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps; track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"step.stepName = $any($event.target).value\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults?.length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting\" (click)=\"submit()\">\n @if (submitting) {\n <span class=\"arv-spinner\"></span>\n }\n {{ submitting ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage) {\n <div class=\"arv-error\">{{ errorMessage }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] });
1735
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, referenceId: { classPropertyName: "referenceId", publicName: "referenceId", isSignal: true, isRequired: false, transformFunction: null }, templateIds: { classPropertyName: "templateIds", publicName: "templateIds", isSignal: true, isRequired: false, transformFunction: null }, callbackUrl: { classPropertyName: "callbackUrl", publicName: "callbackUrl", isSignal: true, isRequired: false, transformFunction: null }, deadlineHours: { classPropertyName: "deadlineHours", publicName: "deadlineHours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalSubmitted: "approvalSubmitted", approvalSubmitting: "approvalSubmitting", cancelled: "cancelled" }, host: { properties: { "class": "this.themeClass" } }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["contentBody"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode === 'template'\" (change)=\"routingMode = 'template'\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode === 'adhoc'\" (change)=\"routingMode = 'adhoc'\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate() && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate()) {\n <!-- arv-template-steps -->\n <div class=\"arv-steps\"> \n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n {{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' \u00B7 ' + s.roles[0].orgName : '' }}\n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\n <!-- <div class=\"arv-step-picker\">\n @if (stepLoadingCandidates[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates[i]) {\n <select class=\"arv-select arv-select-sm\" (change)=\"onStepUserChange(i, $event)\">\n <option value=\"\">-- Select approver --</option>\n @for (u of stepCandidates[i]; track u.userId) {\n <option [value]=\"u.userId\" [selected]=\"u.userId === stepSelectedUsers[i]\">\n {{ u.fullName || u.userId }}{{ u.department ? ' \u00B7 ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}{{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </option>\n }\n </select>\n }\n </div> -->\n @if (stepLoadingCandidates()[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates()[i]) {\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @if (stepSelectedUsers()[i]) {\n <span class=\"arv-tag\">\n {{ userLabelMap[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\n </span>\n }\n </div>\n @if (!stepSelectedUsers()[i]) {\n <div class=\"arv-user-search arv-step-picker\">\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery[i] || ''\"\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (candidateSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of candidateSearchResults[i]; track u.userId) {\n <div class=\"arv-search-item\" (click)=\"onStepUserChangeInput(i, u.userId)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n } \n </div>\n }\n \n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }} \n </div>\n }\n </div>\n }\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps; track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"step.stepName = $any($event.target).value\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n @if (step.approverUserIds.length === 0) {\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n } \n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults?.length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting\" (click)=\"submit()\">\n @if (submitting) {\n <span class=\"arv-spinner\"></span>\n }\n {{ submitting ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage) {\n <div class=\"arv-error\">{{ errorMessage }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] });
1664
1736
  }
1665
1737
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: MaArvContainerComponent, decorators: [{
1666
1738
  type: Component,
1667
- args: [{ selector: 'ma-arv-container', imports: [], template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode === 'template'\" (change)=\"routingMode = 'template'\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode === 'adhoc'\" (change)=\"routingMode = 'adhoc'\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate) {\n <div class=\"arv-template-steps\">\n @for (s of selectedTemplate.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step-card\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n {{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' \u00B7 ' + s.roles[0].orgName : '' }}\n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates[i]?.length > 1 || stepLoadingCandidates[i]) {\n <div class=\"arv-step-picker\">\n @if (stepLoadingCandidates[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates[i]) {\n <select class=\"arv-select arv-select-sm\" (change)=\"onStepUserChange(i, $event)\">\n <option value=\"\">-- Select approver --</option>\n @for (u of stepCandidates[i]; track u.userId) {\n <option [value]=\"u.userId\" [selected]=\"u.userId === stepSelectedUsers[i]\">\n {{ u.fullName || u.userId }}{{ u.department ? ' \u00B7 ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}{{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </option>\n }\n </select>\n }\n </div>\n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates[i] && stepCandidates[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates[i][0].fullName || stepCandidates[i][0].userId }}{{ stepCandidates[i][0].department ? ' \u00B7 ' + stepCandidates[i][0].department : '' }}{{ stepCandidates[i][0].position ? ' (' + stepCandidates[i][0].position + ')' : '' }}{{ stepCandidates[i][0].employeeCode ? ' (' + stepCandidates[i][0].employeeCode + ')' : '' }} \n </div>\n }\n </div>\n }\n @if (selectedTemplate.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps; track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"step.stepName = $any($event.target).value\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults?.length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting\" (click)=\"submit()\">\n @if (submitting) {\n <span class=\"arv-spinner\"></span>\n }\n {{ submitting ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage) {\n <div class=\"arv-error\">{{ errorMessage }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] }]
1739
+ args: [{ selector: 'ma-arv-container', imports: [], template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode === 'template'\" (change)=\"routingMode = 'template'\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode === 'adhoc'\" (change)=\"routingMode = 'adhoc'\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate() && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate()) {\n <!-- arv-template-steps -->\n <div class=\"arv-steps\"> \n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n {{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' \u00B7 ' + s.roles[0].orgName : '' }}\n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\n <!-- <div class=\"arv-step-picker\">\n @if (stepLoadingCandidates[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates[i]) {\n <select class=\"arv-select arv-select-sm\" (change)=\"onStepUserChange(i, $event)\">\n <option value=\"\">-- Select approver --</option>\n @for (u of stepCandidates[i]; track u.userId) {\n <option [value]=\"u.userId\" [selected]=\"u.userId === stepSelectedUsers[i]\">\n {{ u.fullName || u.userId }}{{ u.department ? ' \u00B7 ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}{{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </option>\n }\n </select>\n }\n </div> -->\n @if (stepLoadingCandidates()[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates()[i]) {\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @if (stepSelectedUsers()[i]) {\n <span class=\"arv-tag\">\n {{ userLabelMap[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\n </span>\n }\n </div>\n @if (!stepSelectedUsers()[i]) {\n <div class=\"arv-user-search arv-step-picker\">\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery[i] || ''\"\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (candidateSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of candidateSearchResults[i]; track u.userId) {\n <div class=\"arv-search-item\" (click)=\"onStepUserChangeInput(i, u.userId)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n } \n </div>\n }\n \n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }} \n </div>\n }\n </div>\n }\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps; track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"step.stepName = $any($event.target).value\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n @if (step.approverUserIds.length === 0) {\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n } \n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults?.length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting\" (click)=\"submit()\">\n @if (submitting) {\n <span class=\"arv-spinner\"></span>\n }\n {{ submitting ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage) {\n <div class=\"arv-error\">{{ errorMessage }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] }]
1668
1740
  }], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], referenceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "referenceId", required: false }] }], templateIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateIds", required: false }] }], callbackUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "callbackUrl", required: false }] }], deadlineHours: [{ type: i0.Input, args: [{ isSignal: true, alias: "deadlineHours", required: false }] }], approvalSubmitted: [{ type: i0.Output, args: ["approvalSubmitted"] }], approvalSubmitting: [{ type: i0.Output, args: ["approvalSubmitting"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }], contentBody: [{
1669
1741
  type: ViewChild,
1670
1742
  args: ['contentBody', { static: true }]