tango-app-ui-analyse-trax 4.0.48 → 4.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/audit-v2/configure/audit-v2-configure.component.mjs +120 -4
- package/esm2022/lib/components/audit-v2/reports/audit-v2-reports.component.mjs +103 -50
- package/esm2022/lib/components/audit-v2/schedule/audit-v2-schedule-detail.component.mjs +12 -6
- package/esm2022/lib/components/audit-v2/schedule/audit-v2-schedule-editor.component.mjs +14 -6
- package/fesm2022/{tango-app-ui-analyse-trax-audit-v2.module-D2O6kj8t.mjs → tango-app-ui-analyse-trax-audit-v2.module-Bpm0GYMw.mjs} +250 -68
- package/fesm2022/tango-app-ui-analyse-trax-audit-v2.module-Bpm0GYMw.mjs.map +1 -0
- package/fesm2022/{tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-C4oOKSEZ.mjs → tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-Cuk5lK5L.mjs} +2 -2
- package/fesm2022/{tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-C4oOKSEZ.mjs.map → tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-Cuk5lK5L.mjs.map} +1 -1
- package/fesm2022/tango-app-ui-analyse-trax.mjs +1 -1
- package/lib/components/audit-v2/configure/audit-v2-configure.component.d.ts +17 -1
- package/lib/components/audit-v2/reports/audit-v2-reports.component.d.ts +10 -6
- package/lib/components/audit-v2/schedule/audit-v2-schedule-detail.component.d.ts +4 -1
- package/lib/components/audit-v2/schedule/audit-v2-schedule-editor.component.d.ts +3 -1
- package/package.json +1 -1
- package/fesm2022/tango-app-ui-analyse-trax-audit-v2.module-D2O6kj8t.mjs.map +0 -1
|
@@ -20,7 +20,7 @@ import * as i2 from 'tango-app-ui-global';
|
|
|
20
20
|
import dayjs from 'dayjs';
|
|
21
21
|
import dayjsEsm from 'dayjs/esm';
|
|
22
22
|
import utcEsm from 'dayjs/esm/plugin/utc';
|
|
23
|
-
import { T as TraxService, D as DateRangePickerComponent, A as AddTaskComponent, E as ExportGalleryComponent, C as ChecklistPopupComponent, n as noWhitespaceValidator, r as rangeValidator, u as uniqueStringValidator, a as TraxpopupComponent, b as AutoTaskPopupComponent, c as TraxRunAIPopupComponent, d as CreateTaskComponent, e as TaskConfigureComponent } from './tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-
|
|
23
|
+
import { T as TraxService, D as DateRangePickerComponent, A as AddTaskComponent, E as ExportGalleryComponent, C as ChecklistPopupComponent, n as noWhitespaceValidator, r as rangeValidator, u as uniqueStringValidator, a as TraxpopupComponent, b as AutoTaskPopupComponent, c as TraxRunAIPopupComponent, d as CreateTaskComponent, e as TaskConfigureComponent } from './tango-app-ui-analyse-trax-tango-app-ui-analyse-trax-Cuk5lK5L.mjs';
|
|
24
24
|
import utc from 'dayjs/plugin/utc';
|
|
25
25
|
import * as XLSX from 'xlsx';
|
|
26
26
|
import timezone from 'dayjs/plugin/timezone';
|
|
@@ -2969,7 +2969,7 @@ const DISPUTE_REJECT_REASONS = [
|
|
|
2969
2969
|
/** Export pages through the answers API this many submissions at a time, up to EXPORT_MAX. */
|
|
2970
2970
|
/** userEmail filter value no real user has (see resolveScope). */
|
|
2971
2971
|
const NO_MATCH_EMAIL = 'no-team-user@invalid';
|
|
2972
|
-
const EXPORT_PAGE = 100;
|
|
2972
|
+
const EXPORT_PAGE$1 = 100;
|
|
2973
2973
|
const EXPORT_MAX = 3000;
|
|
2974
2974
|
const DEFAULTS = {
|
|
2975
2975
|
type: 'Audit',
|
|
@@ -4960,16 +4960,16 @@ class AuditV2GalleryComponent {
|
|
|
4960
4960
|
return;
|
|
4961
4961
|
}
|
|
4962
4962
|
const wanted = Math.min(this.total, EXPORT_MAX);
|
|
4963
|
-
const pages = Math.ceil(wanted / EXPORT_PAGE);
|
|
4963
|
+
const pages = Math.ceil(wanted / EXPORT_PAGE$1);
|
|
4964
4964
|
const records = [];
|
|
4965
4965
|
const scopeName = [this.fName, this.fStart + ' to ' + (this.fEnd || this.fStart)].join(' - ');
|
|
4966
4966
|
this.exporting = true;
|
|
4967
4967
|
const fetch = (page) => {
|
|
4968
|
-
this.answersRequest(page, EXPORT_PAGE).pipe(takeUntil$1(this.destroy$)).subscribe({
|
|
4968
|
+
this.answersRequest(page, EXPORT_PAGE$1).pipe(takeUntil$1(this.destroy$)).subscribe({
|
|
4969
4969
|
next: (res) => {
|
|
4970
4970
|
const batch = res?.code === 200 ? res.data?.checklistAnswers || [] : [];
|
|
4971
4971
|
records.push(...batch);
|
|
4972
|
-
if (batch.length === EXPORT_PAGE && page + 1 < pages) {
|
|
4972
|
+
if (batch.length === EXPORT_PAGE$1 && page + 1 < pages) {
|
|
4973
4973
|
fetch(page + 1);
|
|
4974
4974
|
return;
|
|
4975
4975
|
}
|
|
@@ -6050,15 +6050,23 @@ class AuditV2ScheduleEditorComponent {
|
|
|
6050
6050
|
? n + ' of ' + total + ' rows selected'
|
|
6051
6051
|
: total + (total === 1 ? ' row' : ' rows') + ' in this schedule';
|
|
6052
6052
|
}
|
|
6053
|
+
/** Rows the header checkbox acts on: past (locked) rows cannot be selected. */
|
|
6054
|
+
get selectableRows() {
|
|
6055
|
+
return this.shownRows.filter(r => !this.isLocked(r));
|
|
6056
|
+
}
|
|
6053
6057
|
get allRowsSelected() {
|
|
6054
|
-
|
|
6058
|
+
const rows = this.selectableRows;
|
|
6059
|
+
return rows.length > 0 && rows.every(r => r.selected);
|
|
6055
6060
|
}
|
|
6056
6061
|
toggleAllRows() {
|
|
6057
6062
|
const on = !this.allRowsSelected;
|
|
6058
|
-
this.
|
|
6063
|
+
this.selectableRows.forEach(r => this.groupRows(r).forEach(m => m.selected = on));
|
|
6059
6064
|
}
|
|
6060
|
-
/** A shown row's checkbox selects every audit of its group. */
|
|
6065
|
+
/** A shown row's checkbox selects every audit of its group; a past (locked) row cannot be selected. */
|
|
6061
6066
|
toggleRow(row) {
|
|
6067
|
+
if (this.isLocked(row)) {
|
|
6068
|
+
return;
|
|
6069
|
+
}
|
|
6062
6070
|
const on = !row.selected;
|
|
6063
6071
|
this.groupRows(row).forEach(m => m.selected = on);
|
|
6064
6072
|
}
|
|
@@ -6639,11 +6647,11 @@ class AuditV2ScheduleEditorComponent {
|
|
|
6639
6647
|
URL.revokeObjectURL(url);
|
|
6640
6648
|
}
|
|
6641
6649
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ScheduleEditorComponent, deps: [{ token: TraxService }, { token: i3.ToastService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
6642
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ScheduleEditorComponent, selector: "lib-audit-v2-schedule-editor", inputs: { clientId: "clientId", audits: "audits", preselect: "preselect", lockAudits: "lockAudits", backLabel: "backLabel", scheduleId: "scheduleId" }, outputs: { closed: "closed" }, host: { listeners: { "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, viewQueries: [{ propertyName: "csvInput", first: true, predicate: ["csvInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<input #csvInput type=\"file\" accept=\".xlsx,.csv,text/csv\" class=\"se-hidden\" (change)=\"onCsvPicked($event)\">\n\n<!-- Editing opens on the Rows step, so its skeleton mirrors that screen. -->\n<ng-container *ngIf=\"loadingEdit\">\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <span class=\"av2-sk se-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title se-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<!-- ============ Create schedule ============ -->\n<ng-container *ngIf=\"step === 'create' && !loadingEdit\">\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\"><a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A {{ scheduleId ? name || 'Schedule' : 'Create schedule' }}</div>\n </div>\n\n <div class=\"se-create\">\n <div class=\"se-card se-card--form\">\n <span class=\"se-badge\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"></circle><path d=\"M12 8v8M8 12h8\"></path></svg>\n </span>\n <div class=\"se-head\">\n <div class=\"se-title\">{{ scheduleId ? 'Edit schedule' : 'Create schedule' }}</div>\n <div class=\"se-sub\">{{ scheduleId ? 'Rename the schedule, or add rows from the template.' : (locked ? 'Name the schedule, then add rows for this audit.' : 'Name the schedule, then add rows.') }}</div>\n </div>\n\n <!-- Opened from an audit's Configure page: that audit is the schedule's audit, named once here\n instead of an audit picker card (QA: the card is not needed when the audit is already chosen). -->\n <div class=\"se-fixed-audit\" *ngIf=\"locked\">\n <span class=\"se-label\">{{ pickedAudits.length > 1 ? 'Audits' : 'Audit' }}</span>\n <span class=\"se-fixed-audit-name\">{{ lockedAuditNames || 'Loading audit\u2026' }}</span>\n </div>\n\n <label class=\"se-field\">\n <span class=\"se-label\">Schedule name</span>\n <input type=\"text\" class=\"se-input\" [(ngModel)]=\"name\" placeholder=\"e.g. February hygiene round\">\n </label>\n\n <!-- Every audit, with the ones picked on the previous page (Not scheduled) already ticked.\n Create only: Edit schedule keeps the schedule's audits and does not ask for them (QA).\n Hidden for now on both (showAuditPicker). -->\n <div class=\"se-field\" *ngIf=\"showAuditPicker && !locked && !scheduleId\">\n <div class=\"se-row\">\n <span class=\"se-label se-grow\">Audits to schedule</span>\n <span class=\"se-count\">{{ pickCount }}</span>\n </div>\n <label class=\"se-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"pickQuery\" placeholder=\"Search audits\">\n <a class=\"se-clear\" *ngIf=\"pickQuery.trim()\" title=\"Clear search\" (click)=\"pickQuery = ''\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </a>\n </label>\n <div class=\"se-picklist\">\n <div class=\"se-pickrow se-pickrow--all\" (click)=\"toggleAllPicks()\">\n <span class=\"se-box\" [class.is-on]=\"allPicked\">\n <svg *ngIf=\"allPicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">{{ allLabel }}</span>\n </div>\n <div class=\"se-empty-sm\" *ngIf=\"!pickables.length\">No audits match that search.</div>\n <div class=\"se-pickrow\" *ngFor=\"let a of pickables; trackBy: trackByAudit\" [class.is-on]=\"isPicked(a)\" (click)=\"togglePick(a)\">\n <span class=\"se-box\" [class.is-on]=\"isPicked(a)\">\n <svg *ngIf=\"isPicked(a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\">\n <span class=\"se-ellipsis\">{{ a.name }}</span>\n <span class=\"se-meta\">{{ a.meta }}{{ a.questions ? ' \u00B7 ' + a.questions + ' questions' : '' }}</span>\n </span>\n </div>\n </div>\n </div>\n\n <ol class=\"se-steps\">\n <li>Use the template to schedule multiple users at once.</li>\n <li>Download the template here \u2014 <a href=\"#\" (click)=\"downloadTemplate($event)\">{{ templateLoading || templateWaiting ? 'Preparing\u2026' : 'Download template' }}</a></li>\n <li>Add your data, then upload it below.</li>\n </ol>\n\n <div class=\"se-actions\">\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--primary\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"importCsv()\">Import from CSV</button>\n <span class=\"se-or\">or</span>\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--ghost\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"addSingle()\">Add a single row</button>\n </div>\n </div>\n\n <!-- Hidden for now on both Create and Edit (showTemplatePreview). -->\n <div class=\"se-card se-card--side\" *ngIf=\"showTemplatePreview\">\n <div class=\"se-head\">\n <div class=\"se-side-title\">What the template expects</div>\n <div class=\"se-sub\">One row per user, store and date. These are the rows the downloaded template will hold for the selected\n {{ picks.length === 1 ? 'audit' : 'audits' }} \u2014 edit or add rows in the file, then import it.</div>\n </div>\n <div class=\"se-sample\">\n <div class=\"se-sample-row se-sample-row--head\">\n <span>Date</span><span>User email</span><span>Assign store</span><span>Assign audit</span>\n </div>\n <lib-audit-v2-shimmer *ngIf=\"templateLoading\" [rows]=\"3\"></lib-audit-v2-shimmer>\n <ng-container *ngIf=\"!templateLoading\">\n <!-- The selected audits' assigned stores / users: the same rows Download template writes. -->\n <div class=\"se-sample-row\" *ngFor=\"let r of previewRows\">\n <span [title]=\"r.date\">{{ r.date }}</span><span [title]=\"r.email\">{{ r.email }}</span>\n <span [title]=\"r.store\">{{ r.store }}</span><span [title]=\"r.audit\">{{ r.audit }}</span>\n </div>\n <div class=\"se-sample-more\" *ngIf=\"previewMore\">+ {{ previewMore }} more {{ previewMore === 1 ? 'row' : 'rows' }} in the file</div>\n <div class=\"se-sample-more\" *ngIf=\"!previewRows.length\">Pick an audit to see its template rows.</div>\n </ng-container>\n </div>\n <span class=\"se-note se-note--warn\" *ngIf=\"!templateLoading && unassignedAudits.length\">\n {{ unassignedAudits.join(', ') }} {{ unassignedAudits.length === 1 ? 'has' : 'have' }} no store assigned yet \u2014 fill in Date, User email\n and Store name for {{ unassignedAudits.length === 1 ? 'its row' : 'their rows' }}.</span>\n <span class=\"se-note\">Visit start and Visit end (HH:mm) are optional \u2014 leave them blank to use the store's open and close time (10:00 to 22:00 when the store has none).</span>\n <span class=\"se-note\">Rows with an unknown store, email or audit are reported before anything is saved. Draft audits\n are published when the schedule is published.</span>\n </div>\n </div>\n</ng-container>\n\n<!-- ============ Rows ============ -->\n<ng-container *ngIf=\"step === 'rows' && !loadingEdit\">\n <!-- Back + crumb on one line, as on the Create step; the name and actions below, left edges aligned.\n Edit has no \"Edit schedule\" step in the crumb (QA 9 Oct): it opens on, and stays on, the rows. -->\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\">\n <a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A\n <ng-container *ngIf=\"!scheduleId\"><a href=\"#\" (click)=\"backToCreate($event)\">Create schedule</a> \u203A</ng-container>\n Rows\n </div>\n </div>\n\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <div class=\"se-name\">{{ name.trim() || 'Untitled schedule' }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"saving\" (click)=\"saveDraft()\">Save as draft</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm se-publish\" [class.is-off]=\"!canPublish\" (click)=\"publish()\">\n {{ saving ? 'Saving\u2026' : (published ? 'Save & publish' : 'Publish schedule') }}\n </button>\n </div>\n\n <div class=\"se-ready\" [class.is-ok]=\"readyOk\">\n <svg *ngIf=\"readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z\"></path><path d=\"M8 12.5l2.7 2.7L16 9.5\"></path></svg>\n <svg *ngIf=\"!readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 4l9 16H3z\"></path><path d=\"M12 10v4M12 17h.01\"></path></svg>\n <span>{{ readyLabel }}</span>\n </div>\n\n <div class=\"se-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of metrics\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <div class=\"se-tablehead\">\n <div class=\"se-titletext\">\n <div class=\"se-side-title\">Schedule rows</div>\n <div class=\"se-sub\">Every row is one user, at one store, on one date.</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"addRow()\">Add row</button>\n <label class=\"se-search se-search--sm\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"rowQuery\" placeholder=\"Search rows\">\n </label>\n </div>\n\n <div class=\"se-scroll\" (scroll)=\"onViewportChange()\">\n <div class=\"se-grid se-grid--head\">\n <div class=\"se-center\" (click)=\"toggleAllRows()\" title=\"Select all rows\">\n <span class=\"se-box\" [class.is-on]=\"allRowsSelected\">\n <svg *ngIf=\"allRowsSelected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n <div>Schedule date</div><div>User email</div><div>Assigned store</div><div>Audit assigned</div><div>Visit window</div><div></div>\n </div>\n\n <div class=\"se-grid se-grid--row\" *ngFor=\"let r of shownRows; trackBy: trackByRow\" [class.is-selected]=\"r.selected\">\n <div class=\"se-center\" (click)=\"toggleRow(r)\">\n <span class=\"se-box\" [class.is-on]=\"r.selected\">\n <svg *ngIf=\"r.selected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n\n <input type=\"date\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'date')\" [attr.title]=\"cellError(r, 'date') || null\" [attr.min]=\"today\"\n [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.date\" (ngModelChange)=\"touch(r, 'date')\">\n\n <!-- User: search by name or email -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'userEmail')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\" [class.is-bad]=\"cellError(r, 'userEmail')\" [attr.title]=\"cellError(r, 'userEmail') || null\"\n placeholder=\"Search user\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.userEmail\" (ngModelChange)=\"onPickerInput(r, 'userEmail')\"\n (focus)=\"openPicker(r, 'userEmail', $event)\" (click)=\"openPicker(r, 'userEmail', $event)\" (keydown)=\"onPickerKey(r, 'userEmail', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'userEmail')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let u of userSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"u.email === r.userEmail.trim().toLowerCase()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickUser(r, u, $event)\">\n <span class=\"se-opt-avatar\">{{ initials(u.name || u.email) }}</span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ u.name || u.email }}</span>\n <span class=\"se-opt-sub\">{{ u.email }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"u.email === r.userEmail.trim().toLowerCase()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!userSuggestions(r).length\">{{ users.length ? 'No user matches \u201C' + r.userEmail + '\u201D' : 'Loading users\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(userSuggestions(r).length, userMatches(r).length, 'users')\">\n {{ moreLabel(userSuggestions(r).length, userMatches(r).length, 'users') }}\n </div>\n </div>\n </div>\n\n <!-- Store: search and show by store name (or city); the store code is never shown or asked for -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'storeId')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\"\n [class.is-bad]=\"cellError(r, 'storeId')\" [attr.title]=\"cellError(r, 'storeId') || null\"\n placeholder=\"Search store\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [ngModel]=\"r.storeText\" (ngModelChange)=\"onStoreTyped(r, $event)\"\n (focus)=\"openPicker(r, 'storeId', $event)\" (click)=\"openPicker(r, 'storeId', $event)\" (keydown)=\"onPickerKey(r, 'storeId', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'storeId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let s of storeSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"s.storeId === r.storeId.trim()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickStore(r, s, $event)\">\n <span class=\"se-opt-icon\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 9l1.5-5h15L21 9\"></path><path d=\"M4 9v11h16V9\"></path><path d=\"M9 20v-6h6v6\"></path></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ s.storeName || s.storeId }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"s.city\">{{ s.city }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"s.storeId === r.storeId.trim()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!storeSuggestions(r).length\">{{ stores.length ? 'No store matches \u201C' + r.storeText + '\u201D' : 'Loading stores\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores')\">\n {{ moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores') }}\n </div>\n </div>\n </div>\n\n <!-- Audit assigned: multi-select with search over the published audits (rowAuditOptions). Ticking another audit\n adds a row for it with the same date, user, store and window; unticking removes that row. No column when\n the schedule has one fixed audit. -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'checkListId')\">\n <button type=\"button\" class=\"se-cell se-select\" [class.is-bad]=\"cellError(r, 'checkListId')\" [attr.title]=\"cellError(r, 'checkListId') || null\"\n [disabled]=\"isLocked(r)\" (click)=\"openPicker(r, 'checkListId', $event)\" (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n <span class=\"se-ellipsis\" [class.se-placeholder]=\"!groupAuditFirst(r)\" [attr.title]=\"groupAuditLabel(r) || null\">{{ groupAuditFirst(r) || 'Select audits' }}</span>\n <span class=\"se-more\" *ngIf=\"groupAuditMore(r)\" [attr.title]=\"groupAuditLabel(r)\">+{{ groupAuditMore(r) }}</span>\n <svg class=\"se-chev\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\n </button>\n <div class=\"se-menu se-menu--multi\" *ngIf=\"isOpen(r, 'checkListId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <label class=\"se-menu-search\" (mousedown)=\"$event.stopPropagation()\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search audits\" autocomplete=\"off\" [(ngModel)]=\"auditQuery\" (ngModelChange)=\"activeIndex = 0\"\n (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n </label>\n <div class=\"se-opt\" *ngFor=\"let a of auditMatches(); let i = index; trackBy: trackByAudit\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"auditTicked(r, a)\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"toggleAudit(r, a, $event)\">\n <span class=\"se-box\" [class.is-on]=\"auditTicked(r, a)\">\n <svg *ngIf=\"auditTicked(r, a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ a.name }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"a.questions\">{{ a.questions }} {{ a.questions === 1 ? 'question' : 'questions' }}</span>\n </span>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!auditMatches().length\">{{ rowAuditOptions.length ? 'No audit matches \u201C' + auditQuery + '\u201D' : 'No published audits yet' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"auditTickCount(r) > 1\">{{ auditTickCount(r) }} audits on this row \u00B7 same user, store, date and window</div>\n </div>\n </div>\n\n <div class=\"se-window\" [attr.title]=\"cellError(r, 'window') || null\">\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.start\" (ngModelChange)=\"touch(r, 'window')\">\n <span class=\"se-dash\">\u2013</span>\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.end\" (ngModelChange)=\"touch(r, 'window')\">\n </div>\n\n <div class=\"se-center\">\n <span class=\"se-lock\" *ngIf=\"isLocked(r)\" title=\"Past visit: already raised, so it cannot be edited or deleted\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"></rect><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"></path></svg>\n </span>\n <a class=\"se-del\" *ngIf=\"!isLocked(r)\" title=\"Delete row\" (click)=\"deleteRow(r)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 7h16\"></path><path d=\"M7 7l1 13h8l1-13M9 7V4h6v3\"></path></svg>\n </a>\n </div>\n\n <!-- Why the row is red, in words. -->\n <ng-container *ngIf=\"rowMessages(r) as msgs\">\n <div class=\"se-rowerr\" *ngIf=\"msgs.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n <span>{{ msgs.join(' \u00B7 ') }}</span>\n <a class=\"se-invite-link\" *ngIf=\"inviteable(r)\" (click)=\"openInvite(newUserEmails(groupRows(r)))\">Invite user</a>\n </div>\n </ng-container>\n <!-- Hints: allowed (Publish is not blocked), e.g. the same visit in another schedule. -->\n <ng-container *ngIf=\"rowHints(r) as hints\">\n <div class=\"se-rowerr se-rowhint\" *ngIf=\"hints.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\n <span>{{ hints.join(' \u00B7 ') }}</span>\n </div>\n </ng-container>\n </div>\n\n <div *ngIf=\"!shownRows.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No rows match this search.' : 'No rows yet. Add a row or import the template.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-foot\">\n <!-- Row count + visit-window hint removed (user, 11 Oct); the count shows only while rows are selected. -->\n <span class=\"se-foot-text\" *ngIf=\"selectedCount\">{{ selectionLabel }}</span>\n <span class=\"se-foot-actions\">\n <button type=\"button\" class=\"se-bulk\" [class.is-off]=\"!selectedCount\" (click)=\"duplicateSelected()\">Duplicate</button>\n <button type=\"button\" class=\"se-bulk se-bulk--danger\" [class.is-off]=\"!selectedCount\" (click)=\"deleteSelected()\">Delete</button>\n </span>\n </div>\n </div>\n</ng-container>\n\n<!-- New User found (as the v1 checklist upload): emails with no user yet, after an import or from a row's Invite user. -->\n<ng-container *ngIf=\"inviteOpen\">\n <div class=\"se-inv-backdrop\" (click)=\"closeInvite()\"></div>\n <div class=\"se-inv\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"se-inv-title\">\n <span class=\"se-inv-icon\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\"></path><path d=\"M12 9v4M12 17h.01\"></path></svg>\n </span>\n <div class=\"se-inv-title\" id=\"se-inv-title\">{{ inviteEmails.length === 1 ? 'New user found' : 'New users found' }}</div>\n <div class=\"se-inv-text\">\n {{ inviteEmails.length === 1 ? 'This email is not a user yet.' : 'These emails are not users yet.' }}\n Invite them to add them as users of this client, or add them in User Management under the Manage menu.\n </div>\n\n <div class=\"se-inv-list\">\n <div class=\"se-pickrow se-pickrow--all\" *ngIf=\"inviteEmails.length > 1\" (click)=\"toggleAllInvite()\">\n <span class=\"se-box\" [class.is-on]=\"allInvitePicked\">\n <svg *ngIf=\"allInvitePicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">Select all ({{ inviteEmails.length }})</span>\n </div>\n <div class=\"se-pickrow\" *ngFor=\"let e of inviteEmails\" [class.is-on]=\"invitePicked.has(e)\" (click)=\"toggleInvite(e)\">\n <span class=\"se-box\" [class.is-on]=\"invitePicked.has(e)\">\n <svg *ngIf=\"invitePicked.has(e)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\"><span class=\"se-ellipsis\">{{ e }}</span></span>\n </div>\n </div>\n\n <div class=\"se-inv-foot\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"inviting\" (click)=\"closeInvite()\">Skip</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" [disabled]=\"inviting || !invitePicked.size\" (click)=\"inviteSelected()\">\n {{ inviting ? 'Inviting\u2026' : 'Invite selected' + (invitePicked.size ? ' (' + invitePicked.size + ')' : '') }}\n </button>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}:host{display:flex;flex-direction:column;gap:20px}.se-hidden{display:none}.se-grow{flex:1;min-width:0}.se-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sk-crumb{width:180px;height:12px;margin:4px 0}.se-sk-name{height:22px;margin:4px 0}.se-crumb{font-size:13px;line-height:20px;color:#667085}.se-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.se-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.se-fixed-audit{display:flex;flex-direction:column;gap:4px;padding:12px 14px;border-radius:8px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0}.se-fixed-audit-name{font-size:14px;line-height:20px;font-weight:600;color:#101828}.se-create{display:flex;flex-wrap:wrap;gap:20px;max-width:1180px}.se-card{min-width:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.se-card--form{flex:1 1 420px;padding:28px;gap:20px}.se-card--side{flex:1 1 380px;padding:28px;gap:16px}.se-badge{width:44px;height:44px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.se-head{display:flex;flex-direction:column;gap:4px}.se-title{font-size:24px;line-height:32px;font-weight:700;color:#101828}.se-side-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-sub{font-size:14px;line-height:20px;color:#667085}.se-field{display:flex;flex-direction:column;gap:6px;margin:0}.se-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.se-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.se-count{font-size:12px;line-height:18px;color:#667085;white-space:nowrap}.se-input{height:44px;padding:0 14px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:14px;color:#101828;outline:none}.se-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #ccedff}.se-search{display:flex;align-items:center;gap:8px;height:40px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.se-search input{flex:1;min-width:0;height:38px;border:none;outline:none;background:transparent;font-size:14px;font-family:inherit;color:#101828}.se-search--sm{flex:0 1 240px;min-width:180px;height:36px}.se-search--sm input{height:34px;font-size:13px}.se-clear{display:flex;cursor:pointer;color:#98a2b3}.se-picklist{display:flex;flex-direction:column;gap:2px;max-height:220px;overflow-y:auto;padding:8px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd}.se-pickrow{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-pickrow:hover{background:#f9fafb}.se-pickrow.is-on{background:#f5fbff}.se-pickrow--all{border-bottom:1px solid #F2F4F7}.se-pickrow--fixed{cursor:default;background:#f9fafb}.se-pickrow--fixed:hover{background:#f9fafb}.se-pickall{font-size:14px;line-height:20px;font-weight:600;color:#344054}.se-pickname{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-pickname .se-ellipsis{font-size:14px;line-height:20px;font-weight:500;color:#101828}.se-meta{font-size:12px;line-height:18px;color:#667085}.se-empty-sm{padding:14px 10px;font-size:13px;line-height:20px;color:#667085}.se-box{width:16px;height:16px;flex-shrink:0;border-radius:4px;display:flex;align-items:center;justify-content:center;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#00a3ff}.se-box.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #00a3ff}.se-steps{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.se-steps a{font-weight:600;color:#00a3ff;cursor:pointer}.se-actions{display:flex;flex-direction:column;gap:12px}.se-or{text-align:center;font-size:14px;color:#98a2b3}.se-btn-lg{height:44px;border:none;border-radius:8px;font-family:inherit;font-size:15px;font-weight:600;cursor:pointer}.se-btn-lg--primary{background:#00a3ff;color:#fff}.se-btn-lg--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054}.se-btn-lg--ghost:hover{background:#f9fafb}.se-btn-lg.is-off{cursor:not-allowed}.se-btn-lg--primary.is-off{background:#f2f4f7;color:#98a2b3}.se-btn-lg--ghost.is-off{color:#98a2b3}.se-btn-lg--ghost.is-off:hover{background:#fff}.se-sample{display:flex;flex-direction:column;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden}.se-sample-row{display:grid;grid-template-columns:.8fr 1.4fr 1fr 1.3fr;gap:8px;padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#344054}.se-sample-row span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sample-row--head{border-top:none;background:#f9fafb;font-weight:600;color:#475467}.se-note{font-size:12px;line-height:18px;color:#667085;text-wrap:pretty}.se-note--warn{color:#b54708}.se-sample-more{padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#667085}.se-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-backbar+.se-titlebar{margin-top:-8px}.se-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.se-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.se-publish.is-off{background:#f2f4f7;color:#98a2b3;cursor:not-allowed;box-shadow:none}.se-ready{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:12px 20px;border-radius:8px;background:#fffcf5;box-shadow:inset 0 0 0 1px #fedf89;color:#b54708;font-size:14px;line-height:20px;font-weight:600}.se-ready svg{flex-shrink:0}.se-ready span{flex:1;min-width:0}.se-ready.is-ok{background:#f6fef9;box-shadow:inset 0 0 0 1px #a6f4c5;color:#027a48}.se-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.se-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.se-scroll{overflow-x:auto}.se-grid{min-width:1120px;display:grid;grid-template-columns:36px 1fr 1.5fr 1fr 1.5fr 1.6fr 40px;gap:12px;align-items:center;padding:10px 24px}.se-grid--head{background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.se-grid--row{border-bottom:1px solid #F2F4F7}.se-grid--row.is-selected{background:#f5fbff}.se-center{display:flex;justify-content:center;cursor:pointer}.se-rowerr{grid-column:2/-1;margin-top:-4px;display:flex;align-items:flex-start;gap:6px;font-size:12px;line-height:18px;color:#d92d20}.se-rowerr svg{flex-shrink:0;margin-top:2px}.se-rowhint{color:#667085}.se-invite-link{flex-shrink:0;font-weight:600;color:#00a3ff;cursor:pointer;text-decoration:none}.se-invite-link:hover{text-decoration:underline}.se-inv-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.se-inv{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:480px;max-width:calc(100vw - 32px);max-height:90vh;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.se-inv-icon{width:48px;height:48px;border-radius:9999px;background:#fef0c7;box-shadow:0 0 0 8px #fffaeb;color:#dc6803;display:flex;align-items:center;justify-content:center;margin:4px 0 8px 4px}.se-inv-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-inv-text{font-size:14px;line-height:20px;color:#475467}.se-inv-list{max-height:260px;overflow-y:auto;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:4px}.se-inv-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:8px}.se-cell{width:100%;height:36px;min-width:0;padding:0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;color:#101828;outline:none}.se-cell:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-cell.is-bad{box-shadow:inset 0 0 0 1px #fda29b}.se-select{display:flex;align-items:center;justify-content:space-between;gap:6px;text-align:left;cursor:pointer}.se-select svg{flex-shrink:0;color:#667085}.se-placeholder{color:#98a2b3}.se-pick{position:relative;min-width:0}.se-cell--pick{padding-right:10px;text-overflow:ellipsis}.se-cell--tagged{padding-right:88px}.se-pick.is-open .se-cell{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-pick.is-open .se-chev{transform:rotate(180deg)}.se-chev{transition:transform .15s ease}.se-tag{position:absolute;top:50%;right:8px;transform:translateY(-50%);max-width:76px;padding:2px 8px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:11px;line-height:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.se-menu{position:fixed;z-index:1060;width:max-content;max-width:380px;max-height:288px;overflow-y:auto;padding:6px;border-radius:10px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 12px 16px -4px #10182814,0 4px 6px -2px #10182808}.se-opt{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-opt.is-active{background:#f9fafb}.se-opt.is-on{background:#f5fbff}.se-opt.is-on.is-active{background:#eaf8ff}.se-opt-avatar{width:28px;height:28px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.se-opt-icon{width:28px;height:28px;flex-shrink:0;border-radius:8px;background:#f2f4f7;color:#475467;display:flex;align-items:center;justify-content:center}.se-opt-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-opt-main{font-size:13px;line-height:18px;font-weight:500;color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-sub{font-size:12px;line-height:16px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-check{flex-shrink:0;color:#00a3ff}.se-menu-empty{padding:12px 10px;font-size:13px;color:#667085}.se-menu--multi{min-width:260px}.se-menu-search{position:sticky;top:-6px;z-index:1;margin:-6px -6px 4px;padding:8px 10px;display:flex;align-items:center;gap:8px;background:#fff;border-bottom:1px solid #F2F4F7;color:#667085;cursor:text}.se-menu-search input{flex:1;min-width:0;border:0;outline:none;background:transparent;font-size:13px;line-height:18px;color:#101828}.se-menu-note{margin:4px -6px -6px;padding:8px 16px;border-top:1px solid #F2F4F7;background:#fcfcfd;font-size:12px;line-height:16px;color:#667085;position:sticky;bottom:-6px}.se-window{display:flex;align-items:center;gap:6px;min-width:0}.se-window .se-cell{flex:1;padding:0 6px}.se-dash{color:#98a2b3;font-size:13px}.se-lock{width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:#98a2b3;cursor:help}.se-del{width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#667085;cursor:pointer}.se-del:hover{background:#fffbfa;color:#d92d20}.se-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.se-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px}.se-foot-text{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:20px;color:#667085}.se-foot-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.se-bulk{height:36px;padding:0 14px;border:none;border-radius:8px;background:transparent;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.se-bulk:hover{background:#f9fafb}.se-bulk--danger{color:#d92d20}.se-bulk--danger:hover{background:#fffbfa}.se-bulk.is-off{color:#98a2b3;cursor:not-allowed}.se-bulk.is-off:hover{background:transparent}.se-select .se-ellipsis{flex:0 1 auto;min-width:0}.se-select .se-chev{margin-left:auto}.se-more{flex-shrink:0;min-width:24px;height:20px;padding:0 7px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:12px;font-weight:600;line-height:20px;text-align:center}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }] });
|
|
6650
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ScheduleEditorComponent, selector: "lib-audit-v2-schedule-editor", inputs: { clientId: "clientId", audits: "audits", preselect: "preselect", lockAudits: "lockAudits", backLabel: "backLabel", scheduleId: "scheduleId" }, outputs: { closed: "closed" }, host: { listeners: { "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" } }, viewQueries: [{ propertyName: "csvInput", first: true, predicate: ["csvInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<input #csvInput type=\"file\" accept=\".xlsx,.csv,text/csv\" class=\"se-hidden\" (change)=\"onCsvPicked($event)\">\n\n<!-- Editing opens on the Rows step, so its skeleton mirrors that screen. -->\n<ng-container *ngIf=\"loadingEdit\">\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <span class=\"av2-sk se-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title se-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<!-- ============ Create schedule ============ -->\n<ng-container *ngIf=\"step === 'create' && !loadingEdit\">\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\"><a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A {{ scheduleId ? name || 'Schedule' : 'Create schedule' }}</div>\n </div>\n\n <div class=\"se-create\">\n <div class=\"se-card se-card--form\">\n <span class=\"se-badge\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"></circle><path d=\"M12 8v8M8 12h8\"></path></svg>\n </span>\n <div class=\"se-head\">\n <div class=\"se-title\">{{ scheduleId ? 'Edit schedule' : 'Create schedule' }}</div>\n <div class=\"se-sub\">{{ scheduleId ? 'Rename the schedule, or add rows from the template.' : (locked ? 'Name the schedule, then add rows for this audit.' : 'Name the schedule, then add rows.') }}</div>\n </div>\n\n <!-- Opened from an audit's Configure page: that audit is the schedule's audit, named once here\n instead of an audit picker card (QA: the card is not needed when the audit is already chosen). -->\n <div class=\"se-fixed-audit\" *ngIf=\"locked\">\n <span class=\"se-label\">{{ pickedAudits.length > 1 ? 'Audits' : 'Audit' }}</span>\n <span class=\"se-fixed-audit-name\">{{ lockedAuditNames || 'Loading audit\u2026' }}</span>\n </div>\n\n <label class=\"se-field\">\n <span class=\"se-label\">Schedule name</span>\n <input type=\"text\" class=\"se-input\" [(ngModel)]=\"name\" placeholder=\"e.g. February hygiene round\">\n </label>\n\n <!-- Every audit, with the ones picked on the previous page (Not scheduled) already ticked.\n Create only: Edit schedule keeps the schedule's audits and does not ask for them (QA).\n Hidden for now on both (showAuditPicker). -->\n <div class=\"se-field\" *ngIf=\"showAuditPicker && !locked && !scheduleId\">\n <div class=\"se-row\">\n <span class=\"se-label se-grow\">Audits to schedule</span>\n <span class=\"se-count\">{{ pickCount }}</span>\n </div>\n <label class=\"se-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"pickQuery\" placeholder=\"Search audits\">\n <a class=\"se-clear\" *ngIf=\"pickQuery.trim()\" title=\"Clear search\" (click)=\"pickQuery = ''\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </a>\n </label>\n <div class=\"se-picklist\">\n <div class=\"se-pickrow se-pickrow--all\" (click)=\"toggleAllPicks()\">\n <span class=\"se-box\" [class.is-on]=\"allPicked\">\n <svg *ngIf=\"allPicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">{{ allLabel }}</span>\n </div>\n <div class=\"se-empty-sm\" *ngIf=\"!pickables.length\">No audits match that search.</div>\n <div class=\"se-pickrow\" *ngFor=\"let a of pickables; trackBy: trackByAudit\" [class.is-on]=\"isPicked(a)\" (click)=\"togglePick(a)\">\n <span class=\"se-box\" [class.is-on]=\"isPicked(a)\">\n <svg *ngIf=\"isPicked(a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\">\n <span class=\"se-ellipsis\">{{ a.name }}</span>\n <span class=\"se-meta\">{{ a.meta }}{{ a.questions ? ' \u00B7 ' + a.questions + ' questions' : '' }}</span>\n </span>\n </div>\n </div>\n </div>\n\n <ol class=\"se-steps\">\n <li>Use the template to schedule multiple users at once.</li>\n <li>Download the template here \u2014 <a href=\"#\" (click)=\"downloadTemplate($event)\">{{ templateLoading || templateWaiting ? 'Preparing\u2026' : 'Download template' }}</a></li>\n <li>Add your data, then upload it below.</li>\n </ol>\n\n <div class=\"se-actions\">\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--primary\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"importCsv()\">Import from CSV</button>\n <span class=\"se-or\">or</span>\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--ghost\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"addSingle()\">Add a single row</button>\n </div>\n </div>\n\n <!-- Hidden for now on both Create and Edit (showTemplatePreview). -->\n <div class=\"se-card se-card--side\" *ngIf=\"showTemplatePreview\">\n <div class=\"se-head\">\n <div class=\"se-side-title\">What the template expects</div>\n <div class=\"se-sub\">One row per user, store and date. These are the rows the downloaded template will hold for the selected\n {{ picks.length === 1 ? 'audit' : 'audits' }} \u2014 edit or add rows in the file, then import it.</div>\n </div>\n <div class=\"se-sample\">\n <div class=\"se-sample-row se-sample-row--head\">\n <span>Date</span><span>User email</span><span>Assign store</span><span>Assign audit</span>\n </div>\n <lib-audit-v2-shimmer *ngIf=\"templateLoading\" [rows]=\"3\"></lib-audit-v2-shimmer>\n <ng-container *ngIf=\"!templateLoading\">\n <!-- The selected audits' assigned stores / users: the same rows Download template writes. -->\n <div class=\"se-sample-row\" *ngFor=\"let r of previewRows\">\n <span [title]=\"r.date\">{{ r.date }}</span><span [title]=\"r.email\">{{ r.email }}</span>\n <span [title]=\"r.store\">{{ r.store }}</span><span [title]=\"r.audit\">{{ r.audit }}</span>\n </div>\n <div class=\"se-sample-more\" *ngIf=\"previewMore\">+ {{ previewMore }} more {{ previewMore === 1 ? 'row' : 'rows' }} in the file</div>\n <div class=\"se-sample-more\" *ngIf=\"!previewRows.length\">Pick an audit to see its template rows.</div>\n </ng-container>\n </div>\n <span class=\"se-note se-note--warn\" *ngIf=\"!templateLoading && unassignedAudits.length\">\n {{ unassignedAudits.join(', ') }} {{ unassignedAudits.length === 1 ? 'has' : 'have' }} no store assigned yet \u2014 fill in Date, User email\n and Store name for {{ unassignedAudits.length === 1 ? 'its row' : 'their rows' }}.</span>\n <span class=\"se-note\">Visit start and Visit end (HH:mm) are optional \u2014 leave them blank to use the store's open and close time (10:00 to 22:00 when the store has none).</span>\n <span class=\"se-note\">Rows with an unknown store, email or audit are reported before anything is saved. Draft audits\n are published when the schedule is published.</span>\n </div>\n </div>\n</ng-container>\n\n<!-- ============ Rows ============ -->\n<ng-container *ngIf=\"step === 'rows' && !loadingEdit\">\n <!-- Back + crumb on one line, as on the Create step; the name and actions below, left edges aligned.\n Edit has no \"Edit schedule\" step in the crumb (QA 9 Oct): it opens on, and stays on, the rows. -->\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\">\n <a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A\n <ng-container *ngIf=\"!scheduleId\"><a href=\"#\" (click)=\"backToCreate($event)\">Create schedule</a> \u203A</ng-container>\n Rows\n </div>\n </div>\n\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <div class=\"se-name\">{{ name.trim() || 'Untitled schedule' }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"saving\" (click)=\"saveDraft()\">Save as draft</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm se-publish\" [class.is-off]=\"!canPublish\" (click)=\"publish()\">\n {{ saving ? 'Saving\u2026' : (published ? 'Save & publish' : 'Publish schedule') }}\n </button>\n </div>\n\n <div class=\"se-ready\" [class.is-ok]=\"readyOk\">\n <svg *ngIf=\"readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z\"></path><path d=\"M8 12.5l2.7 2.7L16 9.5\"></path></svg>\n <svg *ngIf=\"!readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 4l9 16H3z\"></path><path d=\"M12 10v4M12 17h.01\"></path></svg>\n <span>{{ readyLabel }}</span>\n </div>\n\n <div class=\"se-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of metrics\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <div class=\"se-tablehead\">\n <div class=\"se-titletext\">\n <div class=\"se-side-title\">Schedule rows</div>\n <div class=\"se-sub\">Every row is one user, at one store, on one date.</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"addRow()\">Add row</button>\n <label class=\"se-search se-search--sm\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"rowQuery\" placeholder=\"Search rows\">\n </label>\n </div>\n\n <div class=\"se-scroll\" (scroll)=\"onViewportChange()\">\n <div class=\"se-grid se-grid--head\">\n <div class=\"se-center\" (click)=\"toggleAllRows()\" title=\"Select all rows\">\n <span class=\"se-box\" [class.is-on]=\"allRowsSelected\">\n <svg *ngIf=\"allRowsSelected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n <div>Schedule date</div><div>User email</div><div>Assigned store</div><div>Audit assigned</div><div>Visit window</div><div></div>\n </div>\n\n <div class=\"se-grid se-grid--row\" *ngFor=\"let r of shownRows; trackBy: trackByRow\" [class.is-selected]=\"r.selected\" [class.is-locked]=\"isLocked(r)\">\n <div class=\"se-center\" [class.is-off]=\"isLocked(r)\" [attr.title]=\"isLocked(r) ? 'Past visit: already raised, so it cannot be selected' : null\" (click)=\"toggleRow(r)\">\n <span class=\"se-box\" [class.is-on]=\"r.selected\">\n <svg *ngIf=\"r.selected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n\n <input type=\"date\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'date')\" [attr.title]=\"cellError(r, 'date') || null\" [attr.min]=\"today\"\n [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.date\" (ngModelChange)=\"touch(r, 'date')\">\n\n <!-- User: search by name or email -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'userEmail')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\" [class.is-bad]=\"cellError(r, 'userEmail')\" [attr.title]=\"cellError(r, 'userEmail') || null\"\n placeholder=\"Search user\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.userEmail\" (ngModelChange)=\"onPickerInput(r, 'userEmail')\"\n (focus)=\"openPicker(r, 'userEmail', $event)\" (click)=\"openPicker(r, 'userEmail', $event)\" (keydown)=\"onPickerKey(r, 'userEmail', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'userEmail')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let u of userSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"u.email === r.userEmail.trim().toLowerCase()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickUser(r, u, $event)\">\n <span class=\"se-opt-avatar\">{{ initials(u.name || u.email) }}</span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ u.name || u.email }}</span>\n <span class=\"se-opt-sub\">{{ u.email }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"u.email === r.userEmail.trim().toLowerCase()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!userSuggestions(r).length\">{{ users.length ? 'No user matches \u201C' + r.userEmail + '\u201D' : 'Loading users\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(userSuggestions(r).length, userMatches(r).length, 'users')\">\n {{ moreLabel(userSuggestions(r).length, userMatches(r).length, 'users') }}\n </div>\n </div>\n </div>\n\n <!-- Store: search and show by store name (or city); the store code is never shown or asked for -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'storeId')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\"\n [class.is-bad]=\"cellError(r, 'storeId')\" [attr.title]=\"cellError(r, 'storeId') || null\"\n placeholder=\"Search store\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [ngModel]=\"r.storeText\" (ngModelChange)=\"onStoreTyped(r, $event)\"\n (focus)=\"openPicker(r, 'storeId', $event)\" (click)=\"openPicker(r, 'storeId', $event)\" (keydown)=\"onPickerKey(r, 'storeId', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'storeId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let s of storeSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"s.storeId === r.storeId.trim()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickStore(r, s, $event)\">\n <span class=\"se-opt-icon\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 9l1.5-5h15L21 9\"></path><path d=\"M4 9v11h16V9\"></path><path d=\"M9 20v-6h6v6\"></path></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ s.storeName || s.storeId }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"s.city\">{{ s.city }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"s.storeId === r.storeId.trim()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!storeSuggestions(r).length\">{{ stores.length ? 'No store matches \u201C' + r.storeText + '\u201D' : 'Loading stores\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores')\">\n {{ moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores') }}\n </div>\n </div>\n </div>\n\n <!-- Audit assigned: multi-select with search over the published audits (rowAuditOptions). Ticking another audit\n adds a row for it with the same date, user, store and window; unticking removes that row. No column when\n the schedule has one fixed audit. -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'checkListId')\">\n <button type=\"button\" class=\"se-cell se-select\" [class.is-bad]=\"cellError(r, 'checkListId')\" [attr.title]=\"cellError(r, 'checkListId') || null\"\n [disabled]=\"isLocked(r)\" (click)=\"openPicker(r, 'checkListId', $event)\" (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n <span class=\"se-ellipsis\" [class.se-placeholder]=\"!groupAuditFirst(r)\" [attr.title]=\"groupAuditLabel(r) || null\">{{ groupAuditFirst(r) || 'Select audits' }}</span>\n <span class=\"se-more\" *ngIf=\"groupAuditMore(r)\" [attr.title]=\"groupAuditLabel(r)\">+{{ groupAuditMore(r) }}</span>\n <svg class=\"se-chev\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\n </button>\n <div class=\"se-menu se-menu--multi\" *ngIf=\"isOpen(r, 'checkListId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <label class=\"se-menu-search\" (mousedown)=\"$event.stopPropagation()\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search audits\" autocomplete=\"off\" [(ngModel)]=\"auditQuery\" (ngModelChange)=\"activeIndex = 0\"\n (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n </label>\n <div class=\"se-opt\" *ngFor=\"let a of auditMatches(); let i = index; trackBy: trackByAudit\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"auditTicked(r, a)\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"toggleAudit(r, a, $event)\">\n <span class=\"se-box\" [class.is-on]=\"auditTicked(r, a)\">\n <svg *ngIf=\"auditTicked(r, a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ a.name }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"a.questions\">{{ a.questions }} {{ a.questions === 1 ? 'question' : 'questions' }}</span>\n </span>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!auditMatches().length\">{{ rowAuditOptions.length ? 'No audit matches \u201C' + auditQuery + '\u201D' : 'No published audits yet' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"auditTickCount(r) > 1\">{{ auditTickCount(r) }} audits on this row \u00B7 same user, store, date and window</div>\n </div>\n </div>\n\n <div class=\"se-window\" [attr.title]=\"cellError(r, 'window') || null\">\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.start\" (ngModelChange)=\"touch(r, 'window')\">\n <span class=\"se-dash\">\u2013</span>\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.end\" (ngModelChange)=\"touch(r, 'window')\">\n </div>\n\n <div class=\"se-center\">\n <span class=\"se-lock\" *ngIf=\"isLocked(r)\" title=\"Past visit: already raised, so it cannot be edited or deleted\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"></rect><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"></path></svg>\n </span>\n <a class=\"se-del\" *ngIf=\"!isLocked(r)\" title=\"Delete row\" (click)=\"deleteRow(r)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 7h16\"></path><path d=\"M7 7l1 13h8l1-13M9 7V4h6v3\"></path></svg>\n </a>\n </div>\n\n <!-- Why the row is red, in words. -->\n <ng-container *ngIf=\"rowMessages(r) as msgs\">\n <div class=\"se-rowerr\" *ngIf=\"msgs.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n <span>{{ msgs.join(' \u00B7 ') }}</span>\n <a class=\"se-invite-link\" *ngIf=\"inviteable(r)\" (click)=\"openInvite(newUserEmails(groupRows(r)))\">Invite user</a>\n </div>\n </ng-container>\n <!-- Hints: allowed (Publish is not blocked), e.g. the same visit in another schedule. -->\n <ng-container *ngIf=\"rowHints(r) as hints\">\n <div class=\"se-rowerr se-rowhint\" *ngIf=\"hints.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\n <span>{{ hints.join(' \u00B7 ') }}</span>\n </div>\n </ng-container>\n </div>\n\n <div *ngIf=\"!shownRows.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No rows match this search.' : 'No rows yet. Add a row or import the template.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-foot\">\n <!-- Row count + visit-window hint removed (user, 11 Oct); the count shows only while rows are selected. -->\n <span class=\"se-foot-text\" *ngIf=\"selectedCount\">{{ selectionLabel }}</span>\n <span class=\"se-foot-actions\">\n <button type=\"button\" class=\"se-bulk\" [class.is-off]=\"!selectedCount\" (click)=\"duplicateSelected()\">Duplicate</button>\n <button type=\"button\" class=\"se-bulk se-bulk--danger\" [class.is-off]=\"!selectedCount\" (click)=\"deleteSelected()\">Delete</button>\n </span>\n </div>\n </div>\n</ng-container>\n\n<!-- New User found (as the v1 checklist upload): emails with no user yet, after an import or from a row's Invite user. -->\n<ng-container *ngIf=\"inviteOpen\">\n <div class=\"se-inv-backdrop\" (click)=\"closeInvite()\"></div>\n <div class=\"se-inv\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"se-inv-title\">\n <span class=\"se-inv-icon\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\"></path><path d=\"M12 9v4M12 17h.01\"></path></svg>\n </span>\n <div class=\"se-inv-title\" id=\"se-inv-title\">{{ inviteEmails.length === 1 ? 'New user found' : 'New users found' }}</div>\n <div class=\"se-inv-text\">\n {{ inviteEmails.length === 1 ? 'This email is not a user yet.' : 'These emails are not users yet.' }}\n Invite them to add them as users of this client, or add them in User Management under the Manage menu.\n </div>\n\n <div class=\"se-inv-list\">\n <div class=\"se-pickrow se-pickrow--all\" *ngIf=\"inviteEmails.length > 1\" (click)=\"toggleAllInvite()\">\n <span class=\"se-box\" [class.is-on]=\"allInvitePicked\">\n <svg *ngIf=\"allInvitePicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">Select all ({{ inviteEmails.length }})</span>\n </div>\n <div class=\"se-pickrow\" *ngFor=\"let e of inviteEmails\" [class.is-on]=\"invitePicked.has(e)\" (click)=\"toggleInvite(e)\">\n <span class=\"se-box\" [class.is-on]=\"invitePicked.has(e)\">\n <svg *ngIf=\"invitePicked.has(e)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\"><span class=\"se-ellipsis\">{{ e }}</span></span>\n </div>\n </div>\n\n <div class=\"se-inv-foot\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"inviting\" (click)=\"closeInvite()\">Skip</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" [disabled]=\"inviting || !invitePicked.size\" (click)=\"inviteSelected()\">\n {{ inviting ? 'Inviting\u2026' : 'Invite selected' + (invitePicked.size ? ' (' + invitePicked.size + ')' : '') }}\n </button>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}:host{display:flex;flex-direction:column;gap:20px}.se-hidden{display:none}.se-grow{flex:1;min-width:0}.se-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sk-crumb{width:180px;height:12px;margin:4px 0}.se-sk-name{height:22px;margin:4px 0}.se-crumb{font-size:13px;line-height:20px;color:#667085}.se-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.se-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.se-fixed-audit{display:flex;flex-direction:column;gap:4px;padding:12px 14px;border-radius:8px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0}.se-fixed-audit-name{font-size:14px;line-height:20px;font-weight:600;color:#101828}.se-create{display:flex;flex-wrap:wrap;gap:20px;max-width:1180px}.se-card{min-width:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.se-card--form{flex:1 1 420px;padding:28px;gap:20px}.se-card--side{flex:1 1 380px;padding:28px;gap:16px}.se-badge{width:44px;height:44px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.se-head{display:flex;flex-direction:column;gap:4px}.se-title{font-size:24px;line-height:32px;font-weight:700;color:#101828}.se-side-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-sub{font-size:14px;line-height:20px;color:#667085}.se-field{display:flex;flex-direction:column;gap:6px;margin:0}.se-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.se-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.se-count{font-size:12px;line-height:18px;color:#667085;white-space:nowrap}.se-input{height:44px;padding:0 14px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:14px;color:#101828;outline:none}.se-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #ccedff}.se-search{display:flex;align-items:center;gap:8px;height:40px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.se-search input{flex:1;min-width:0;height:38px;border:none;outline:none;background:transparent;font-size:14px;font-family:inherit;color:#101828}.se-search--sm{flex:0 1 240px;min-width:180px;height:36px}.se-search--sm input{height:34px;font-size:13px}.se-clear{display:flex;cursor:pointer;color:#98a2b3}.se-picklist{display:flex;flex-direction:column;gap:2px;max-height:220px;overflow-y:auto;padding:8px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd}.se-pickrow{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-pickrow:hover{background:#f9fafb}.se-pickrow.is-on{background:#f5fbff}.se-pickrow--all{border-bottom:1px solid #F2F4F7}.se-pickrow--fixed{cursor:default;background:#f9fafb}.se-pickrow--fixed:hover{background:#f9fafb}.se-pickall{font-size:14px;line-height:20px;font-weight:600;color:#344054}.se-pickname{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-pickname .se-ellipsis{font-size:14px;line-height:20px;font-weight:500;color:#101828}.se-meta{font-size:12px;line-height:18px;color:#667085}.se-empty-sm{padding:14px 10px;font-size:13px;line-height:20px;color:#667085}.se-box{width:16px;height:16px;flex-shrink:0;border-radius:4px;display:flex;align-items:center;justify-content:center;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#00a3ff}.se-box.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #00a3ff}.se-steps{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.se-steps a{font-weight:600;color:#00a3ff;cursor:pointer}.se-actions{display:flex;flex-direction:column;gap:12px}.se-or{text-align:center;font-size:14px;color:#98a2b3}.se-btn-lg{height:44px;border:none;border-radius:8px;font-family:inherit;font-size:15px;font-weight:600;cursor:pointer}.se-btn-lg--primary{background:#00a3ff;color:#fff}.se-btn-lg--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054}.se-btn-lg--ghost:hover{background:#f9fafb}.se-btn-lg.is-off{cursor:not-allowed}.se-btn-lg--primary.is-off{background:#f2f4f7;color:#98a2b3}.se-btn-lg--ghost.is-off{color:#98a2b3}.se-btn-lg--ghost.is-off:hover{background:#fff}.se-sample{display:flex;flex-direction:column;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden}.se-sample-row{display:grid;grid-template-columns:.8fr 1.4fr 1fr 1.3fr;gap:8px;padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#344054}.se-sample-row span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sample-row--head{border-top:none;background:#f9fafb;font-weight:600;color:#475467}.se-note{font-size:12px;line-height:18px;color:#667085;text-wrap:pretty}.se-note--warn{color:#b54708}.se-sample-more{padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#667085}.se-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-backbar+.se-titlebar{margin-top:-8px}.se-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.se-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.se-publish.is-off{background:#f2f4f7;color:#98a2b3;cursor:not-allowed;box-shadow:none}.se-ready{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:12px 20px;border-radius:8px;background:#fffcf5;box-shadow:inset 0 0 0 1px #fedf89;color:#b54708;font-size:14px;line-height:20px;font-weight:600}.se-ready svg{flex-shrink:0}.se-ready span{flex:1;min-width:0}.se-ready.is-ok{background:#f6fef9;box-shadow:inset 0 0 0 1px #a6f4c5;color:#027a48}.se-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.se-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.se-scroll{overflow-x:auto}.se-grid{min-width:1120px;display:grid;grid-template-columns:36px 1fr 1.5fr 1fr 1.5fr 1.6fr 40px;gap:12px;align-items:center;padding:10px 24px}.se-grid--head{background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.se-grid--row{border-bottom:1px solid #F2F4F7}.se-grid--row.is-selected{background:#f5fbff}.se-center{display:flex;justify-content:center;cursor:pointer}.se-grid--row.is-locked .se-cell{background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;color:#667085;-webkit-text-fill-color:#667085;opacity:1;cursor:not-allowed}.se-grid--row.is-locked .se-chev{display:none}.se-grid--row.is-locked .se-center.is-off{cursor:not-allowed}.se-grid--row.is-locked .se-center.is-off .se-box{background:#f2f4f7;box-shadow:inset 0 0 0 1px #eaecf0}.se-rowerr{grid-column:2/-1;margin-top:-4px;display:flex;align-items:flex-start;gap:6px;font-size:12px;line-height:18px;color:#d92d20}.se-rowerr svg{flex-shrink:0;margin-top:2px}.se-rowhint{color:#667085}.se-invite-link{flex-shrink:0;font-weight:600;color:#00a3ff;cursor:pointer;text-decoration:none}.se-invite-link:hover{text-decoration:underline}.se-inv-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.se-inv{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:480px;max-width:calc(100vw - 32px);max-height:90vh;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.se-inv-icon{width:48px;height:48px;border-radius:9999px;background:#fef0c7;box-shadow:0 0 0 8px #fffaeb;color:#dc6803;display:flex;align-items:center;justify-content:center;margin:4px 0 8px 4px}.se-inv-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-inv-text{font-size:14px;line-height:20px;color:#475467}.se-inv-list{max-height:260px;overflow-y:auto;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:4px}.se-inv-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:8px}.se-cell{width:100%;height:36px;min-width:0;padding:0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;color:#101828;outline:none}.se-cell:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-cell.is-bad{box-shadow:inset 0 0 0 1px #fda29b}.se-select{display:flex;align-items:center;justify-content:space-between;gap:6px;text-align:left;cursor:pointer}.se-select svg{flex-shrink:0;color:#667085}.se-placeholder{color:#98a2b3}.se-pick{position:relative;min-width:0}.se-cell--pick{padding-right:10px;text-overflow:ellipsis}.se-cell--tagged{padding-right:88px}.se-pick.is-open .se-cell{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-pick.is-open .se-chev{transform:rotate(180deg)}.se-chev{transition:transform .15s ease}.se-tag{position:absolute;top:50%;right:8px;transform:translateY(-50%);max-width:76px;padding:2px 8px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:11px;line-height:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.se-menu{position:fixed;z-index:1060;width:max-content;max-width:380px;max-height:288px;overflow-y:auto;padding:6px;border-radius:10px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 12px 16px -4px #10182814,0 4px 6px -2px #10182808}.se-opt{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-opt.is-active{background:#f9fafb}.se-opt.is-on{background:#f5fbff}.se-opt.is-on.is-active{background:#eaf8ff}.se-opt-avatar{width:28px;height:28px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.se-opt-icon{width:28px;height:28px;flex-shrink:0;border-radius:8px;background:#f2f4f7;color:#475467;display:flex;align-items:center;justify-content:center}.se-opt-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-opt-main{font-size:13px;line-height:18px;font-weight:500;color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-sub{font-size:12px;line-height:16px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-check{flex-shrink:0;color:#00a3ff}.se-menu-empty{padding:12px 10px;font-size:13px;color:#667085}.se-menu--multi{min-width:260px}.se-menu-search{position:sticky;top:-6px;z-index:1;margin:-6px -6px 4px;padding:8px 10px;display:flex;align-items:center;gap:8px;background:#fff;border-bottom:1px solid #F2F4F7;color:#667085;cursor:text}.se-menu-search input{flex:1;min-width:0;border:0;outline:none;background:transparent;font-size:13px;line-height:18px;color:#101828}.se-menu-note{margin:4px -6px -6px;padding:8px 16px;border-top:1px solid #F2F4F7;background:#fcfcfd;font-size:12px;line-height:16px;color:#667085;position:sticky;bottom:-6px}.se-window{display:flex;align-items:center;gap:6px;min-width:0}.se-window .se-cell{flex:1;padding:0 6px}.se-dash{color:#98a2b3;font-size:13px}.se-lock{width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:#98a2b3;cursor:help}.se-del{width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#667085;cursor:pointer}.se-del:hover{background:#fffbfa;color:#d92d20}.se-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.se-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px}.se-foot-text{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:20px;color:#667085}.se-foot-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.se-bulk{height:36px;padding:0 14px;border:none;border-radius:8px;background:transparent;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.se-bulk:hover{background:#f9fafb}.se-bulk--danger{color:#d92d20}.se-bulk--danger:hover{background:#fffbfa}.se-bulk.is-off{color:#98a2b3;cursor:not-allowed}.se-bulk.is-off:hover{background:transparent}.se-select .se-ellipsis{flex:0 1 auto;min-width:0}.se-select .se-chev{margin-left:auto}.se-more{flex-shrink:0;min-width:24px;height:20px;padding:0 7px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:12px;font-weight:600;line-height:20px;text-align:center}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }] });
|
|
6643
6651
|
}
|
|
6644
6652
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ScheduleEditorComponent, decorators: [{
|
|
6645
6653
|
type: Component,
|
|
6646
|
-
args: [{ selector: 'lib-audit-v2-schedule-editor', template: "<input #csvInput type=\"file\" accept=\".xlsx,.csv,text/csv\" class=\"se-hidden\" (change)=\"onCsvPicked($event)\">\n\n<!-- Editing opens on the Rows step, so its skeleton mirrors that screen. -->\n<ng-container *ngIf=\"loadingEdit\">\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <span class=\"av2-sk se-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title se-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<!-- ============ Create schedule ============ -->\n<ng-container *ngIf=\"step === 'create' && !loadingEdit\">\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\"><a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A {{ scheduleId ? name || 'Schedule' : 'Create schedule' }}</div>\n </div>\n\n <div class=\"se-create\">\n <div class=\"se-card se-card--form\">\n <span class=\"se-badge\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"></circle><path d=\"M12 8v8M8 12h8\"></path></svg>\n </span>\n <div class=\"se-head\">\n <div class=\"se-title\">{{ scheduleId ? 'Edit schedule' : 'Create schedule' }}</div>\n <div class=\"se-sub\">{{ scheduleId ? 'Rename the schedule, or add rows from the template.' : (locked ? 'Name the schedule, then add rows for this audit.' : 'Name the schedule, then add rows.') }}</div>\n </div>\n\n <!-- Opened from an audit's Configure page: that audit is the schedule's audit, named once here\n instead of an audit picker card (QA: the card is not needed when the audit is already chosen). -->\n <div class=\"se-fixed-audit\" *ngIf=\"locked\">\n <span class=\"se-label\">{{ pickedAudits.length > 1 ? 'Audits' : 'Audit' }}</span>\n <span class=\"se-fixed-audit-name\">{{ lockedAuditNames || 'Loading audit\u2026' }}</span>\n </div>\n\n <label class=\"se-field\">\n <span class=\"se-label\">Schedule name</span>\n <input type=\"text\" class=\"se-input\" [(ngModel)]=\"name\" placeholder=\"e.g. February hygiene round\">\n </label>\n\n <!-- Every audit, with the ones picked on the previous page (Not scheduled) already ticked.\n Create only: Edit schedule keeps the schedule's audits and does not ask for them (QA).\n Hidden for now on both (showAuditPicker). -->\n <div class=\"se-field\" *ngIf=\"showAuditPicker && !locked && !scheduleId\">\n <div class=\"se-row\">\n <span class=\"se-label se-grow\">Audits to schedule</span>\n <span class=\"se-count\">{{ pickCount }}</span>\n </div>\n <label class=\"se-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"pickQuery\" placeholder=\"Search audits\">\n <a class=\"se-clear\" *ngIf=\"pickQuery.trim()\" title=\"Clear search\" (click)=\"pickQuery = ''\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </a>\n </label>\n <div class=\"se-picklist\">\n <div class=\"se-pickrow se-pickrow--all\" (click)=\"toggleAllPicks()\">\n <span class=\"se-box\" [class.is-on]=\"allPicked\">\n <svg *ngIf=\"allPicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">{{ allLabel }}</span>\n </div>\n <div class=\"se-empty-sm\" *ngIf=\"!pickables.length\">No audits match that search.</div>\n <div class=\"se-pickrow\" *ngFor=\"let a of pickables; trackBy: trackByAudit\" [class.is-on]=\"isPicked(a)\" (click)=\"togglePick(a)\">\n <span class=\"se-box\" [class.is-on]=\"isPicked(a)\">\n <svg *ngIf=\"isPicked(a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\">\n <span class=\"se-ellipsis\">{{ a.name }}</span>\n <span class=\"se-meta\">{{ a.meta }}{{ a.questions ? ' \u00B7 ' + a.questions + ' questions' : '' }}</span>\n </span>\n </div>\n </div>\n </div>\n\n <ol class=\"se-steps\">\n <li>Use the template to schedule multiple users at once.</li>\n <li>Download the template here \u2014 <a href=\"#\" (click)=\"downloadTemplate($event)\">{{ templateLoading || templateWaiting ? 'Preparing\u2026' : 'Download template' }}</a></li>\n <li>Add your data, then upload it below.</li>\n </ol>\n\n <div class=\"se-actions\">\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--primary\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"importCsv()\">Import from CSV</button>\n <span class=\"se-or\">or</span>\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--ghost\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"addSingle()\">Add a single row</button>\n </div>\n </div>\n\n <!-- Hidden for now on both Create and Edit (showTemplatePreview). -->\n <div class=\"se-card se-card--side\" *ngIf=\"showTemplatePreview\">\n <div class=\"se-head\">\n <div class=\"se-side-title\">What the template expects</div>\n <div class=\"se-sub\">One row per user, store and date. These are the rows the downloaded template will hold for the selected\n {{ picks.length === 1 ? 'audit' : 'audits' }} \u2014 edit or add rows in the file, then import it.</div>\n </div>\n <div class=\"se-sample\">\n <div class=\"se-sample-row se-sample-row--head\">\n <span>Date</span><span>User email</span><span>Assign store</span><span>Assign audit</span>\n </div>\n <lib-audit-v2-shimmer *ngIf=\"templateLoading\" [rows]=\"3\"></lib-audit-v2-shimmer>\n <ng-container *ngIf=\"!templateLoading\">\n <!-- The selected audits' assigned stores / users: the same rows Download template writes. -->\n <div class=\"se-sample-row\" *ngFor=\"let r of previewRows\">\n <span [title]=\"r.date\">{{ r.date }}</span><span [title]=\"r.email\">{{ r.email }}</span>\n <span [title]=\"r.store\">{{ r.store }}</span><span [title]=\"r.audit\">{{ r.audit }}</span>\n </div>\n <div class=\"se-sample-more\" *ngIf=\"previewMore\">+ {{ previewMore }} more {{ previewMore === 1 ? 'row' : 'rows' }} in the file</div>\n <div class=\"se-sample-more\" *ngIf=\"!previewRows.length\">Pick an audit to see its template rows.</div>\n </ng-container>\n </div>\n <span class=\"se-note se-note--warn\" *ngIf=\"!templateLoading && unassignedAudits.length\">\n {{ unassignedAudits.join(', ') }} {{ unassignedAudits.length === 1 ? 'has' : 'have' }} no store assigned yet \u2014 fill in Date, User email\n and Store name for {{ unassignedAudits.length === 1 ? 'its row' : 'their rows' }}.</span>\n <span class=\"se-note\">Visit start and Visit end (HH:mm) are optional \u2014 leave them blank to use the store's open and close time (10:00 to 22:00 when the store has none).</span>\n <span class=\"se-note\">Rows with an unknown store, email or audit are reported before anything is saved. Draft audits\n are published when the schedule is published.</span>\n </div>\n </div>\n</ng-container>\n\n<!-- ============ Rows ============ -->\n<ng-container *ngIf=\"step === 'rows' && !loadingEdit\">\n <!-- Back + crumb on one line, as on the Create step; the name and actions below, left edges aligned.\n Edit has no \"Edit schedule\" step in the crumb (QA 9 Oct): it opens on, and stays on, the rows. -->\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\">\n <a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A\n <ng-container *ngIf=\"!scheduleId\"><a href=\"#\" (click)=\"backToCreate($event)\">Create schedule</a> \u203A</ng-container>\n Rows\n </div>\n </div>\n\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <div class=\"se-name\">{{ name.trim() || 'Untitled schedule' }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"saving\" (click)=\"saveDraft()\">Save as draft</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm se-publish\" [class.is-off]=\"!canPublish\" (click)=\"publish()\">\n {{ saving ? 'Saving\u2026' : (published ? 'Save & publish' : 'Publish schedule') }}\n </button>\n </div>\n\n <div class=\"se-ready\" [class.is-ok]=\"readyOk\">\n <svg *ngIf=\"readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z\"></path><path d=\"M8 12.5l2.7 2.7L16 9.5\"></path></svg>\n <svg *ngIf=\"!readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 4l9 16H3z\"></path><path d=\"M12 10v4M12 17h.01\"></path></svg>\n <span>{{ readyLabel }}</span>\n </div>\n\n <div class=\"se-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of metrics\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <div class=\"se-tablehead\">\n <div class=\"se-titletext\">\n <div class=\"se-side-title\">Schedule rows</div>\n <div class=\"se-sub\">Every row is one user, at one store, on one date.</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"addRow()\">Add row</button>\n <label class=\"se-search se-search--sm\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"rowQuery\" placeholder=\"Search rows\">\n </label>\n </div>\n\n <div class=\"se-scroll\" (scroll)=\"onViewportChange()\">\n <div class=\"se-grid se-grid--head\">\n <div class=\"se-center\" (click)=\"toggleAllRows()\" title=\"Select all rows\">\n <span class=\"se-box\" [class.is-on]=\"allRowsSelected\">\n <svg *ngIf=\"allRowsSelected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n <div>Schedule date</div><div>User email</div><div>Assigned store</div><div>Audit assigned</div><div>Visit window</div><div></div>\n </div>\n\n <div class=\"se-grid se-grid--row\" *ngFor=\"let r of shownRows; trackBy: trackByRow\" [class.is-selected]=\"r.selected\">\n <div class=\"se-center\" (click)=\"toggleRow(r)\">\n <span class=\"se-box\" [class.is-on]=\"r.selected\">\n <svg *ngIf=\"r.selected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n\n <input type=\"date\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'date')\" [attr.title]=\"cellError(r, 'date') || null\" [attr.min]=\"today\"\n [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.date\" (ngModelChange)=\"touch(r, 'date')\">\n\n <!-- User: search by name or email -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'userEmail')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\" [class.is-bad]=\"cellError(r, 'userEmail')\" [attr.title]=\"cellError(r, 'userEmail') || null\"\n placeholder=\"Search user\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.userEmail\" (ngModelChange)=\"onPickerInput(r, 'userEmail')\"\n (focus)=\"openPicker(r, 'userEmail', $event)\" (click)=\"openPicker(r, 'userEmail', $event)\" (keydown)=\"onPickerKey(r, 'userEmail', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'userEmail')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let u of userSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"u.email === r.userEmail.trim().toLowerCase()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickUser(r, u, $event)\">\n <span class=\"se-opt-avatar\">{{ initials(u.name || u.email) }}</span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ u.name || u.email }}</span>\n <span class=\"se-opt-sub\">{{ u.email }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"u.email === r.userEmail.trim().toLowerCase()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!userSuggestions(r).length\">{{ users.length ? 'No user matches \u201C' + r.userEmail + '\u201D' : 'Loading users\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(userSuggestions(r).length, userMatches(r).length, 'users')\">\n {{ moreLabel(userSuggestions(r).length, userMatches(r).length, 'users') }}\n </div>\n </div>\n </div>\n\n <!-- Store: search and show by store name (or city); the store code is never shown or asked for -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'storeId')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\"\n [class.is-bad]=\"cellError(r, 'storeId')\" [attr.title]=\"cellError(r, 'storeId') || null\"\n placeholder=\"Search store\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [ngModel]=\"r.storeText\" (ngModelChange)=\"onStoreTyped(r, $event)\"\n (focus)=\"openPicker(r, 'storeId', $event)\" (click)=\"openPicker(r, 'storeId', $event)\" (keydown)=\"onPickerKey(r, 'storeId', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'storeId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let s of storeSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"s.storeId === r.storeId.trim()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickStore(r, s, $event)\">\n <span class=\"se-opt-icon\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 9l1.5-5h15L21 9\"></path><path d=\"M4 9v11h16V9\"></path><path d=\"M9 20v-6h6v6\"></path></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ s.storeName || s.storeId }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"s.city\">{{ s.city }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"s.storeId === r.storeId.trim()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!storeSuggestions(r).length\">{{ stores.length ? 'No store matches \u201C' + r.storeText + '\u201D' : 'Loading stores\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores')\">\n {{ moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores') }}\n </div>\n </div>\n </div>\n\n <!-- Audit assigned: multi-select with search over the published audits (rowAuditOptions). Ticking another audit\n adds a row for it with the same date, user, store and window; unticking removes that row. No column when\n the schedule has one fixed audit. -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'checkListId')\">\n <button type=\"button\" class=\"se-cell se-select\" [class.is-bad]=\"cellError(r, 'checkListId')\" [attr.title]=\"cellError(r, 'checkListId') || null\"\n [disabled]=\"isLocked(r)\" (click)=\"openPicker(r, 'checkListId', $event)\" (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n <span class=\"se-ellipsis\" [class.se-placeholder]=\"!groupAuditFirst(r)\" [attr.title]=\"groupAuditLabel(r) || null\">{{ groupAuditFirst(r) || 'Select audits' }}</span>\n <span class=\"se-more\" *ngIf=\"groupAuditMore(r)\" [attr.title]=\"groupAuditLabel(r)\">+{{ groupAuditMore(r) }}</span>\n <svg class=\"se-chev\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\n </button>\n <div class=\"se-menu se-menu--multi\" *ngIf=\"isOpen(r, 'checkListId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <label class=\"se-menu-search\" (mousedown)=\"$event.stopPropagation()\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search audits\" autocomplete=\"off\" [(ngModel)]=\"auditQuery\" (ngModelChange)=\"activeIndex = 0\"\n (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n </label>\n <div class=\"se-opt\" *ngFor=\"let a of auditMatches(); let i = index; trackBy: trackByAudit\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"auditTicked(r, a)\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"toggleAudit(r, a, $event)\">\n <span class=\"se-box\" [class.is-on]=\"auditTicked(r, a)\">\n <svg *ngIf=\"auditTicked(r, a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ a.name }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"a.questions\">{{ a.questions }} {{ a.questions === 1 ? 'question' : 'questions' }}</span>\n </span>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!auditMatches().length\">{{ rowAuditOptions.length ? 'No audit matches \u201C' + auditQuery + '\u201D' : 'No published audits yet' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"auditTickCount(r) > 1\">{{ auditTickCount(r) }} audits on this row \u00B7 same user, store, date and window</div>\n </div>\n </div>\n\n <div class=\"se-window\" [attr.title]=\"cellError(r, 'window') || null\">\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.start\" (ngModelChange)=\"touch(r, 'window')\">\n <span class=\"se-dash\">\u2013</span>\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.end\" (ngModelChange)=\"touch(r, 'window')\">\n </div>\n\n <div class=\"se-center\">\n <span class=\"se-lock\" *ngIf=\"isLocked(r)\" title=\"Past visit: already raised, so it cannot be edited or deleted\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"></rect><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"></path></svg>\n </span>\n <a class=\"se-del\" *ngIf=\"!isLocked(r)\" title=\"Delete row\" (click)=\"deleteRow(r)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 7h16\"></path><path d=\"M7 7l1 13h8l1-13M9 7V4h6v3\"></path></svg>\n </a>\n </div>\n\n <!-- Why the row is red, in words. -->\n <ng-container *ngIf=\"rowMessages(r) as msgs\">\n <div class=\"se-rowerr\" *ngIf=\"msgs.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n <span>{{ msgs.join(' \u00B7 ') }}</span>\n <a class=\"se-invite-link\" *ngIf=\"inviteable(r)\" (click)=\"openInvite(newUserEmails(groupRows(r)))\">Invite user</a>\n </div>\n </ng-container>\n <!-- Hints: allowed (Publish is not blocked), e.g. the same visit in another schedule. -->\n <ng-container *ngIf=\"rowHints(r) as hints\">\n <div class=\"se-rowerr se-rowhint\" *ngIf=\"hints.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\n <span>{{ hints.join(' \u00B7 ') }}</span>\n </div>\n </ng-container>\n </div>\n\n <div *ngIf=\"!shownRows.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No rows match this search.' : 'No rows yet. Add a row or import the template.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-foot\">\n <!-- Row count + visit-window hint removed (user, 11 Oct); the count shows only while rows are selected. -->\n <span class=\"se-foot-text\" *ngIf=\"selectedCount\">{{ selectionLabel }}</span>\n <span class=\"se-foot-actions\">\n <button type=\"button\" class=\"se-bulk\" [class.is-off]=\"!selectedCount\" (click)=\"duplicateSelected()\">Duplicate</button>\n <button type=\"button\" class=\"se-bulk se-bulk--danger\" [class.is-off]=\"!selectedCount\" (click)=\"deleteSelected()\">Delete</button>\n </span>\n </div>\n </div>\n</ng-container>\n\n<!-- New User found (as the v1 checklist upload): emails with no user yet, after an import or from a row's Invite user. -->\n<ng-container *ngIf=\"inviteOpen\">\n <div class=\"se-inv-backdrop\" (click)=\"closeInvite()\"></div>\n <div class=\"se-inv\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"se-inv-title\">\n <span class=\"se-inv-icon\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\"></path><path d=\"M12 9v4M12 17h.01\"></path></svg>\n </span>\n <div class=\"se-inv-title\" id=\"se-inv-title\">{{ inviteEmails.length === 1 ? 'New user found' : 'New users found' }}</div>\n <div class=\"se-inv-text\">\n {{ inviteEmails.length === 1 ? 'This email is not a user yet.' : 'These emails are not users yet.' }}\n Invite them to add them as users of this client, or add them in User Management under the Manage menu.\n </div>\n\n <div class=\"se-inv-list\">\n <div class=\"se-pickrow se-pickrow--all\" *ngIf=\"inviteEmails.length > 1\" (click)=\"toggleAllInvite()\">\n <span class=\"se-box\" [class.is-on]=\"allInvitePicked\">\n <svg *ngIf=\"allInvitePicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">Select all ({{ inviteEmails.length }})</span>\n </div>\n <div class=\"se-pickrow\" *ngFor=\"let e of inviteEmails\" [class.is-on]=\"invitePicked.has(e)\" (click)=\"toggleInvite(e)\">\n <span class=\"se-box\" [class.is-on]=\"invitePicked.has(e)\">\n <svg *ngIf=\"invitePicked.has(e)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\"><span class=\"se-ellipsis\">{{ e }}</span></span>\n </div>\n </div>\n\n <div class=\"se-inv-foot\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"inviting\" (click)=\"closeInvite()\">Skip</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" [disabled]=\"inviting || !invitePicked.size\" (click)=\"inviteSelected()\">\n {{ inviting ? 'Inviting\u2026' : 'Invite selected' + (invitePicked.size ? ' (' + invitePicked.size + ')' : '') }}\n </button>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}:host{display:flex;flex-direction:column;gap:20px}.se-hidden{display:none}.se-grow{flex:1;min-width:0}.se-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sk-crumb{width:180px;height:12px;margin:4px 0}.se-sk-name{height:22px;margin:4px 0}.se-crumb{font-size:13px;line-height:20px;color:#667085}.se-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.se-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.se-fixed-audit{display:flex;flex-direction:column;gap:4px;padding:12px 14px;border-radius:8px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0}.se-fixed-audit-name{font-size:14px;line-height:20px;font-weight:600;color:#101828}.se-create{display:flex;flex-wrap:wrap;gap:20px;max-width:1180px}.se-card{min-width:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.se-card--form{flex:1 1 420px;padding:28px;gap:20px}.se-card--side{flex:1 1 380px;padding:28px;gap:16px}.se-badge{width:44px;height:44px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.se-head{display:flex;flex-direction:column;gap:4px}.se-title{font-size:24px;line-height:32px;font-weight:700;color:#101828}.se-side-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-sub{font-size:14px;line-height:20px;color:#667085}.se-field{display:flex;flex-direction:column;gap:6px;margin:0}.se-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.se-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.se-count{font-size:12px;line-height:18px;color:#667085;white-space:nowrap}.se-input{height:44px;padding:0 14px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:14px;color:#101828;outline:none}.se-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #ccedff}.se-search{display:flex;align-items:center;gap:8px;height:40px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.se-search input{flex:1;min-width:0;height:38px;border:none;outline:none;background:transparent;font-size:14px;font-family:inherit;color:#101828}.se-search--sm{flex:0 1 240px;min-width:180px;height:36px}.se-search--sm input{height:34px;font-size:13px}.se-clear{display:flex;cursor:pointer;color:#98a2b3}.se-picklist{display:flex;flex-direction:column;gap:2px;max-height:220px;overflow-y:auto;padding:8px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd}.se-pickrow{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-pickrow:hover{background:#f9fafb}.se-pickrow.is-on{background:#f5fbff}.se-pickrow--all{border-bottom:1px solid #F2F4F7}.se-pickrow--fixed{cursor:default;background:#f9fafb}.se-pickrow--fixed:hover{background:#f9fafb}.se-pickall{font-size:14px;line-height:20px;font-weight:600;color:#344054}.se-pickname{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-pickname .se-ellipsis{font-size:14px;line-height:20px;font-weight:500;color:#101828}.se-meta{font-size:12px;line-height:18px;color:#667085}.se-empty-sm{padding:14px 10px;font-size:13px;line-height:20px;color:#667085}.se-box{width:16px;height:16px;flex-shrink:0;border-radius:4px;display:flex;align-items:center;justify-content:center;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#00a3ff}.se-box.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #00a3ff}.se-steps{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.se-steps a{font-weight:600;color:#00a3ff;cursor:pointer}.se-actions{display:flex;flex-direction:column;gap:12px}.se-or{text-align:center;font-size:14px;color:#98a2b3}.se-btn-lg{height:44px;border:none;border-radius:8px;font-family:inherit;font-size:15px;font-weight:600;cursor:pointer}.se-btn-lg--primary{background:#00a3ff;color:#fff}.se-btn-lg--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054}.se-btn-lg--ghost:hover{background:#f9fafb}.se-btn-lg.is-off{cursor:not-allowed}.se-btn-lg--primary.is-off{background:#f2f4f7;color:#98a2b3}.se-btn-lg--ghost.is-off{color:#98a2b3}.se-btn-lg--ghost.is-off:hover{background:#fff}.se-sample{display:flex;flex-direction:column;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden}.se-sample-row{display:grid;grid-template-columns:.8fr 1.4fr 1fr 1.3fr;gap:8px;padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#344054}.se-sample-row span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sample-row--head{border-top:none;background:#f9fafb;font-weight:600;color:#475467}.se-note{font-size:12px;line-height:18px;color:#667085;text-wrap:pretty}.se-note--warn{color:#b54708}.se-sample-more{padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#667085}.se-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-backbar+.se-titlebar{margin-top:-8px}.se-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.se-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.se-publish.is-off{background:#f2f4f7;color:#98a2b3;cursor:not-allowed;box-shadow:none}.se-ready{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:12px 20px;border-radius:8px;background:#fffcf5;box-shadow:inset 0 0 0 1px #fedf89;color:#b54708;font-size:14px;line-height:20px;font-weight:600}.se-ready svg{flex-shrink:0}.se-ready span{flex:1;min-width:0}.se-ready.is-ok{background:#f6fef9;box-shadow:inset 0 0 0 1px #a6f4c5;color:#027a48}.se-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.se-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.se-scroll{overflow-x:auto}.se-grid{min-width:1120px;display:grid;grid-template-columns:36px 1fr 1.5fr 1fr 1.5fr 1.6fr 40px;gap:12px;align-items:center;padding:10px 24px}.se-grid--head{background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.se-grid--row{border-bottom:1px solid #F2F4F7}.se-grid--row.is-selected{background:#f5fbff}.se-center{display:flex;justify-content:center;cursor:pointer}.se-rowerr{grid-column:2/-1;margin-top:-4px;display:flex;align-items:flex-start;gap:6px;font-size:12px;line-height:18px;color:#d92d20}.se-rowerr svg{flex-shrink:0;margin-top:2px}.se-rowhint{color:#667085}.se-invite-link{flex-shrink:0;font-weight:600;color:#00a3ff;cursor:pointer;text-decoration:none}.se-invite-link:hover{text-decoration:underline}.se-inv-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.se-inv{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:480px;max-width:calc(100vw - 32px);max-height:90vh;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.se-inv-icon{width:48px;height:48px;border-radius:9999px;background:#fef0c7;box-shadow:0 0 0 8px #fffaeb;color:#dc6803;display:flex;align-items:center;justify-content:center;margin:4px 0 8px 4px}.se-inv-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-inv-text{font-size:14px;line-height:20px;color:#475467}.se-inv-list{max-height:260px;overflow-y:auto;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:4px}.se-inv-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:8px}.se-cell{width:100%;height:36px;min-width:0;padding:0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;color:#101828;outline:none}.se-cell:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-cell.is-bad{box-shadow:inset 0 0 0 1px #fda29b}.se-select{display:flex;align-items:center;justify-content:space-between;gap:6px;text-align:left;cursor:pointer}.se-select svg{flex-shrink:0;color:#667085}.se-placeholder{color:#98a2b3}.se-pick{position:relative;min-width:0}.se-cell--pick{padding-right:10px;text-overflow:ellipsis}.se-cell--tagged{padding-right:88px}.se-pick.is-open .se-cell{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-pick.is-open .se-chev{transform:rotate(180deg)}.se-chev{transition:transform .15s ease}.se-tag{position:absolute;top:50%;right:8px;transform:translateY(-50%);max-width:76px;padding:2px 8px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:11px;line-height:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.se-menu{position:fixed;z-index:1060;width:max-content;max-width:380px;max-height:288px;overflow-y:auto;padding:6px;border-radius:10px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 12px 16px -4px #10182814,0 4px 6px -2px #10182808}.se-opt{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-opt.is-active{background:#f9fafb}.se-opt.is-on{background:#f5fbff}.se-opt.is-on.is-active{background:#eaf8ff}.se-opt-avatar{width:28px;height:28px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.se-opt-icon{width:28px;height:28px;flex-shrink:0;border-radius:8px;background:#f2f4f7;color:#475467;display:flex;align-items:center;justify-content:center}.se-opt-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-opt-main{font-size:13px;line-height:18px;font-weight:500;color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-sub{font-size:12px;line-height:16px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-check{flex-shrink:0;color:#00a3ff}.se-menu-empty{padding:12px 10px;font-size:13px;color:#667085}.se-menu--multi{min-width:260px}.se-menu-search{position:sticky;top:-6px;z-index:1;margin:-6px -6px 4px;padding:8px 10px;display:flex;align-items:center;gap:8px;background:#fff;border-bottom:1px solid #F2F4F7;color:#667085;cursor:text}.se-menu-search input{flex:1;min-width:0;border:0;outline:none;background:transparent;font-size:13px;line-height:18px;color:#101828}.se-menu-note{margin:4px -6px -6px;padding:8px 16px;border-top:1px solid #F2F4F7;background:#fcfcfd;font-size:12px;line-height:16px;color:#667085;position:sticky;bottom:-6px}.se-window{display:flex;align-items:center;gap:6px;min-width:0}.se-window .se-cell{flex:1;padding:0 6px}.se-dash{color:#98a2b3;font-size:13px}.se-lock{width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:#98a2b3;cursor:help}.se-del{width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#667085;cursor:pointer}.se-del:hover{background:#fffbfa;color:#d92d20}.se-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.se-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px}.se-foot-text{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:20px;color:#667085}.se-foot-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.se-bulk{height:36px;padding:0 14px;border:none;border-radius:8px;background:transparent;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.se-bulk:hover{background:#f9fafb}.se-bulk--danger{color:#d92d20}.se-bulk--danger:hover{background:#fffbfa}.se-bulk.is-off{color:#98a2b3;cursor:not-allowed}.se-bulk.is-off:hover{background:transparent}.se-select .se-ellipsis{flex:0 1 auto;min-width:0}.se-select .se-chev{margin-left:auto}.se-more{flex-shrink:0;min-width:24px;height:20px;padding:0 7px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:12px;font-weight:600;line-height:20px;text-align:center}\n"] }]
|
|
6654
|
+
args: [{ selector: 'lib-audit-v2-schedule-editor', template: "<input #csvInput type=\"file\" accept=\".xlsx,.csv,text/csv\" class=\"se-hidden\" (change)=\"onCsvPicked($event)\">\n\n<!-- Editing opens on the Rows step, so its skeleton mirrors that screen. -->\n<ng-container *ngIf=\"loadingEdit\">\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <span class=\"av2-sk se-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title se-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<!-- ============ Create schedule ============ -->\n<ng-container *ngIf=\"step === 'create' && !loadingEdit\">\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\"><a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A {{ scheduleId ? name || 'Schedule' : 'Create schedule' }}</div>\n </div>\n\n <div class=\"se-create\">\n <div class=\"se-card se-card--form\">\n <span class=\"se-badge\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"></circle><path d=\"M12 8v8M8 12h8\"></path></svg>\n </span>\n <div class=\"se-head\">\n <div class=\"se-title\">{{ scheduleId ? 'Edit schedule' : 'Create schedule' }}</div>\n <div class=\"se-sub\">{{ scheduleId ? 'Rename the schedule, or add rows from the template.' : (locked ? 'Name the schedule, then add rows for this audit.' : 'Name the schedule, then add rows.') }}</div>\n </div>\n\n <!-- Opened from an audit's Configure page: that audit is the schedule's audit, named once here\n instead of an audit picker card (QA: the card is not needed when the audit is already chosen). -->\n <div class=\"se-fixed-audit\" *ngIf=\"locked\">\n <span class=\"se-label\">{{ pickedAudits.length > 1 ? 'Audits' : 'Audit' }}</span>\n <span class=\"se-fixed-audit-name\">{{ lockedAuditNames || 'Loading audit\u2026' }}</span>\n </div>\n\n <label class=\"se-field\">\n <span class=\"se-label\">Schedule name</span>\n <input type=\"text\" class=\"se-input\" [(ngModel)]=\"name\" placeholder=\"e.g. February hygiene round\">\n </label>\n\n <!-- Every audit, with the ones picked on the previous page (Not scheduled) already ticked.\n Create only: Edit schedule keeps the schedule's audits and does not ask for them (QA).\n Hidden for now on both (showAuditPicker). -->\n <div class=\"se-field\" *ngIf=\"showAuditPicker && !locked && !scheduleId\">\n <div class=\"se-row\">\n <span class=\"se-label se-grow\">Audits to schedule</span>\n <span class=\"se-count\">{{ pickCount }}</span>\n </div>\n <label class=\"se-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"pickQuery\" placeholder=\"Search audits\">\n <a class=\"se-clear\" *ngIf=\"pickQuery.trim()\" title=\"Clear search\" (click)=\"pickQuery = ''\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </a>\n </label>\n <div class=\"se-picklist\">\n <div class=\"se-pickrow se-pickrow--all\" (click)=\"toggleAllPicks()\">\n <span class=\"se-box\" [class.is-on]=\"allPicked\">\n <svg *ngIf=\"allPicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">{{ allLabel }}</span>\n </div>\n <div class=\"se-empty-sm\" *ngIf=\"!pickables.length\">No audits match that search.</div>\n <div class=\"se-pickrow\" *ngFor=\"let a of pickables; trackBy: trackByAudit\" [class.is-on]=\"isPicked(a)\" (click)=\"togglePick(a)\">\n <span class=\"se-box\" [class.is-on]=\"isPicked(a)\">\n <svg *ngIf=\"isPicked(a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\">\n <span class=\"se-ellipsis\">{{ a.name }}</span>\n <span class=\"se-meta\">{{ a.meta }}{{ a.questions ? ' \u00B7 ' + a.questions + ' questions' : '' }}</span>\n </span>\n </div>\n </div>\n </div>\n\n <ol class=\"se-steps\">\n <li>Use the template to schedule multiple users at once.</li>\n <li>Download the template here \u2014 <a href=\"#\" (click)=\"downloadTemplate($event)\">{{ templateLoading || templateWaiting ? 'Preparing\u2026' : 'Download template' }}</a></li>\n <li>Add your data, then upload it below.</li>\n </ol>\n\n <div class=\"se-actions\">\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--primary\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"importCsv()\">Import from CSV</button>\n <span class=\"se-or\">or</span>\n <button type=\"button\" class=\"se-btn-lg se-btn-lg--ghost\" [class.is-off]=\"!ready\" [attr.aria-disabled]=\"!ready\"\n [ngbTooltip]=\"notReadyReason\" [disableTooltip]=\"ready\" placement=\"top\" (click)=\"addSingle()\">Add a single row</button>\n </div>\n </div>\n\n <!-- Hidden for now on both Create and Edit (showTemplatePreview). -->\n <div class=\"se-card se-card--side\" *ngIf=\"showTemplatePreview\">\n <div class=\"se-head\">\n <div class=\"se-side-title\">What the template expects</div>\n <div class=\"se-sub\">One row per user, store and date. These are the rows the downloaded template will hold for the selected\n {{ picks.length === 1 ? 'audit' : 'audits' }} \u2014 edit or add rows in the file, then import it.</div>\n </div>\n <div class=\"se-sample\">\n <div class=\"se-sample-row se-sample-row--head\">\n <span>Date</span><span>User email</span><span>Assign store</span><span>Assign audit</span>\n </div>\n <lib-audit-v2-shimmer *ngIf=\"templateLoading\" [rows]=\"3\"></lib-audit-v2-shimmer>\n <ng-container *ngIf=\"!templateLoading\">\n <!-- The selected audits' assigned stores / users: the same rows Download template writes. -->\n <div class=\"se-sample-row\" *ngFor=\"let r of previewRows\">\n <span [title]=\"r.date\">{{ r.date }}</span><span [title]=\"r.email\">{{ r.email }}</span>\n <span [title]=\"r.store\">{{ r.store }}</span><span [title]=\"r.audit\">{{ r.audit }}</span>\n </div>\n <div class=\"se-sample-more\" *ngIf=\"previewMore\">+ {{ previewMore }} more {{ previewMore === 1 ? 'row' : 'rows' }} in the file</div>\n <div class=\"se-sample-more\" *ngIf=\"!previewRows.length\">Pick an audit to see its template rows.</div>\n </ng-container>\n </div>\n <span class=\"se-note se-note--warn\" *ngIf=\"!templateLoading && unassignedAudits.length\">\n {{ unassignedAudits.join(', ') }} {{ unassignedAudits.length === 1 ? 'has' : 'have' }} no store assigned yet \u2014 fill in Date, User email\n and Store name for {{ unassignedAudits.length === 1 ? 'its row' : 'their rows' }}.</span>\n <span class=\"se-note\">Visit start and Visit end (HH:mm) are optional \u2014 leave them blank to use the store's open and close time (10:00 to 22:00 when the store has none).</span>\n <span class=\"se-note\">Rows with an unknown store, email or audit are reported before anything is saved. Draft audits\n are published when the schedule is published.</span>\n </div>\n </div>\n</ng-container>\n\n<!-- ============ Rows ============ -->\n<ng-container *ngIf=\"step === 'rows' && !loadingEdit\">\n <!-- Back + crumb on one line, as on the Create step; the name and actions below, left edges aligned.\n Edit has no \"Edit schedule\" step in the crumb (QA 9 Oct): it opens on, and stays on, the rows. -->\n <div class=\"se-backbar\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm se-back\" (click)=\"back()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\n {{ backLabel }}\n </button>\n <div class=\"se-crumb\">\n <a href=\"#\" (click)=\"back($event)\">Schedule</a> \u203A\n <ng-container *ngIf=\"!scheduleId\"><a href=\"#\" (click)=\"backToCreate($event)\">Create schedule</a> \u203A</ng-container>\n Rows\n </div>\n </div>\n\n <div class=\"se-titlebar\">\n <div class=\"se-titletext\">\n <div class=\"se-name\">{{ name.trim() || 'Untitled schedule' }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"saving\" (click)=\"saveDraft()\">Save as draft</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm se-publish\" [class.is-off]=\"!canPublish\" (click)=\"publish()\">\n {{ saving ? 'Saving\u2026' : (published ? 'Save & publish' : 'Publish schedule') }}\n </button>\n </div>\n\n <div class=\"se-ready\" [class.is-ok]=\"readyOk\">\n <svg *ngIf=\"readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z\"></path><path d=\"M8 12.5l2.7 2.7L16 9.5\"></path></svg>\n <svg *ngIf=\"!readyOk\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 4l9 16H3z\"></path><path d=\"M12 10v4M12 17h.01\"></path></svg>\n <span>{{ readyLabel }}</span>\n </div>\n\n <div class=\"se-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of metrics\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-card se-card--table\">\n <div class=\"se-tablehead\">\n <div class=\"se-titletext\">\n <div class=\"se-side-title\">Schedule rows</div>\n <div class=\"se-sub\">Every row is one user, at one store, on one date.</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"addRow()\">Add row</button>\n <label class=\"se-search se-search--sm\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"rowQuery\" placeholder=\"Search rows\">\n </label>\n </div>\n\n <div class=\"se-scroll\" (scroll)=\"onViewportChange()\">\n <div class=\"se-grid se-grid--head\">\n <div class=\"se-center\" (click)=\"toggleAllRows()\" title=\"Select all rows\">\n <span class=\"se-box\" [class.is-on]=\"allRowsSelected\">\n <svg *ngIf=\"allRowsSelected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n <div>Schedule date</div><div>User email</div><div>Assigned store</div><div>Audit assigned</div><div>Visit window</div><div></div>\n </div>\n\n <div class=\"se-grid se-grid--row\" *ngFor=\"let r of shownRows; trackBy: trackByRow\" [class.is-selected]=\"r.selected\" [class.is-locked]=\"isLocked(r)\">\n <div class=\"se-center\" [class.is-off]=\"isLocked(r)\" [attr.title]=\"isLocked(r) ? 'Past visit: already raised, so it cannot be selected' : null\" (click)=\"toggleRow(r)\">\n <span class=\"se-box\" [class.is-on]=\"r.selected\">\n <svg *ngIf=\"r.selected\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n </div>\n\n <input type=\"date\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'date')\" [attr.title]=\"cellError(r, 'date') || null\" [attr.min]=\"today\"\n [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.date\" (ngModelChange)=\"touch(r, 'date')\">\n\n <!-- User: search by name or email -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'userEmail')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\" [class.is-bad]=\"cellError(r, 'userEmail')\" [attr.title]=\"cellError(r, 'userEmail') || null\"\n placeholder=\"Search user\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.userEmail\" (ngModelChange)=\"onPickerInput(r, 'userEmail')\"\n (focus)=\"openPicker(r, 'userEmail', $event)\" (click)=\"openPicker(r, 'userEmail', $event)\" (keydown)=\"onPickerKey(r, 'userEmail', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'userEmail')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let u of userSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"u.email === r.userEmail.trim().toLowerCase()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickUser(r, u, $event)\">\n <span class=\"se-opt-avatar\">{{ initials(u.name || u.email) }}</span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ u.name || u.email }}</span>\n <span class=\"se-opt-sub\">{{ u.email }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"u.email === r.userEmail.trim().toLowerCase()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!userSuggestions(r).length\">{{ users.length ? 'No user matches \u201C' + r.userEmail + '\u201D' : 'Loading users\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(userSuggestions(r).length, userMatches(r).length, 'users')\">\n {{ moreLabel(userSuggestions(r).length, userMatches(r).length, 'users') }}\n </div>\n </div>\n </div>\n\n <!-- Store: search and show by store name (or city); the store code is never shown or asked for -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'storeId')\">\n <input type=\"text\" class=\"se-cell se-cell--pick\"\n [class.is-bad]=\"cellError(r, 'storeId')\" [attr.title]=\"cellError(r, 'storeId') || null\"\n placeholder=\"Search store\" autocomplete=\"off\" [disabled]=\"isLocked(r)\" [ngModel]=\"r.storeText\" (ngModelChange)=\"onStoreTyped(r, $event)\"\n (focus)=\"openPicker(r, 'storeId', $event)\" (click)=\"openPicker(r, 'storeId', $event)\" (keydown)=\"onPickerKey(r, 'storeId', $event)\">\n <div class=\"se-menu\" *ngIf=\"isOpen(r, 'storeId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <div class=\"se-opt\" *ngFor=\"let s of storeSuggestions(r); let i = index\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"s.storeId === r.storeId.trim()\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pickStore(r, s, $event)\">\n <span class=\"se-opt-icon\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 9l1.5-5h15L21 9\"></path><path d=\"M4 9v11h16V9\"></path><path d=\"M9 20v-6h6v6\"></path></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ s.storeName || s.storeId }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"s.city\">{{ s.city }}</span>\n </span>\n <svg class=\"se-opt-check\" *ngIf=\"s.storeId === r.storeId.trim()\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!storeSuggestions(r).length\">{{ stores.length ? 'No store matches \u201C' + r.storeText + '\u201D' : 'Loading stores\u2026' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores')\">\n {{ moreLabel(storeSuggestions(r).length, storeMatches(r).length, 'stores') }}\n </div>\n </div>\n </div>\n\n <!-- Audit assigned: multi-select with search over the published audits (rowAuditOptions). Ticking another audit\n adds a row for it with the same date, user, store and window; unticking removes that row. No column when\n the schedule has one fixed audit. -->\n <div class=\"se-pick\" [class.is-open]=\"isOpen(r, 'checkListId')\">\n <button type=\"button\" class=\"se-cell se-select\" [class.is-bad]=\"cellError(r, 'checkListId')\" [attr.title]=\"cellError(r, 'checkListId') || null\"\n [disabled]=\"isLocked(r)\" (click)=\"openPicker(r, 'checkListId', $event)\" (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n <span class=\"se-ellipsis\" [class.se-placeholder]=\"!groupAuditFirst(r)\" [attr.title]=\"groupAuditLabel(r) || null\">{{ groupAuditFirst(r) || 'Select audits' }}</span>\n <span class=\"se-more\" *ngIf=\"groupAuditMore(r)\" [attr.title]=\"groupAuditLabel(r)\">+{{ groupAuditMore(r) }}</span>\n <svg class=\"se-chev\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\n </button>\n <div class=\"se-menu se-menu--multi\" *ngIf=\"isOpen(r, 'checkListId')\" [style.top.px]=\"menuPos.top\" [style.bottom.px]=\"menuPos.bottom\"\n [style.left.px]=\"menuPos.left\" [style.min-width.px]=\"menuPos.width\">\n <label class=\"se-menu-search\" (mousedown)=\"$event.stopPropagation()\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search audits\" autocomplete=\"off\" [(ngModel)]=\"auditQuery\" (ngModelChange)=\"activeIndex = 0\"\n (keydown)=\"onPickerKey(r, 'checkListId', $event)\">\n </label>\n <div class=\"se-opt\" *ngFor=\"let a of auditMatches(); let i = index; trackBy: trackByAudit\" [class.is-active]=\"i === activeIndex\"\n [class.is-on]=\"auditTicked(r, a)\" (mouseenter)=\"activeIndex = i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"toggleAudit(r, a, $event)\">\n <span class=\"se-box\" [class.is-on]=\"auditTicked(r, a)\">\n <svg *ngIf=\"auditTicked(r, a)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-opt-text\">\n <span class=\"se-opt-main\">{{ a.name }}</span>\n <span class=\"se-opt-sub\" *ngIf=\"a.questions\">{{ a.questions }} {{ a.questions === 1 ? 'question' : 'questions' }}</span>\n </span>\n </div>\n <div class=\"se-menu-empty\" *ngIf=\"!auditMatches().length\">{{ rowAuditOptions.length ? 'No audit matches \u201C' + auditQuery + '\u201D' : 'No published audits yet' }}</div>\n <div class=\"se-menu-note\" *ngIf=\"auditTickCount(r) > 1\">{{ auditTickCount(r) }} audits on this row \u00B7 same user, store, date and window</div>\n </div>\n </div>\n\n <div class=\"se-window\" [attr.title]=\"cellError(r, 'window') || null\">\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.start\" (ngModelChange)=\"touch(r, 'window')\">\n <span class=\"se-dash\">\u2013</span>\n <input type=\"time\" class=\"se-cell\" [class.is-bad]=\"cellError(r, 'window')\" [disabled]=\"isLocked(r)\" [(ngModel)]=\"r.end\" (ngModelChange)=\"touch(r, 'window')\">\n </div>\n\n <div class=\"se-center\">\n <span class=\"se-lock\" *ngIf=\"isLocked(r)\" title=\"Past visit: already raised, so it cannot be edited or deleted\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\"></rect><path d=\"M8 11V7a4 4 0 0 1 8 0v4\"></path></svg>\n </span>\n <a class=\"se-del\" *ngIf=\"!isLocked(r)\" title=\"Delete row\" (click)=\"deleteRow(r)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 7h16\"></path><path d=\"M7 7l1 13h8l1-13M9 7V4h6v3\"></path></svg>\n </a>\n </div>\n\n <!-- Why the row is red, in words. -->\n <ng-container *ngIf=\"rowMessages(r) as msgs\">\n <div class=\"se-rowerr\" *ngIf=\"msgs.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n <span>{{ msgs.join(' \u00B7 ') }}</span>\n <a class=\"se-invite-link\" *ngIf=\"inviteable(r)\" (click)=\"openInvite(newUserEmails(groupRows(r)))\">Invite user</a>\n </div>\n </ng-container>\n <!-- Hints: allowed (Publish is not blocked), e.g. the same visit in another schedule. -->\n <ng-container *ngIf=\"rowHints(r) as hints\">\n <div class=\"se-rowerr se-rowhint\" *ngIf=\"hints.length\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\n <span>{{ hints.join(' \u00B7 ') }}</span>\n </div>\n </ng-container>\n </div>\n\n <div *ngIf=\"!shownRows.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No rows match this search.' : 'No rows yet. Add a row or import the template.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"se-foot\">\n <!-- Row count + visit-window hint removed (user, 11 Oct); the count shows only while rows are selected. -->\n <span class=\"se-foot-text\" *ngIf=\"selectedCount\">{{ selectionLabel }}</span>\n <span class=\"se-foot-actions\">\n <button type=\"button\" class=\"se-bulk\" [class.is-off]=\"!selectedCount\" (click)=\"duplicateSelected()\">Duplicate</button>\n <button type=\"button\" class=\"se-bulk se-bulk--danger\" [class.is-off]=\"!selectedCount\" (click)=\"deleteSelected()\">Delete</button>\n </span>\n </div>\n </div>\n</ng-container>\n\n<!-- New User found (as the v1 checklist upload): emails with no user yet, after an import or from a row's Invite user. -->\n<ng-container *ngIf=\"inviteOpen\">\n <div class=\"se-inv-backdrop\" (click)=\"closeInvite()\"></div>\n <div class=\"se-inv\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"se-inv-title\">\n <span class=\"se-inv-icon\">\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\"></path><path d=\"M12 9v4M12 17h.01\"></path></svg>\n </span>\n <div class=\"se-inv-title\" id=\"se-inv-title\">{{ inviteEmails.length === 1 ? 'New user found' : 'New users found' }}</div>\n <div class=\"se-inv-text\">\n {{ inviteEmails.length === 1 ? 'This email is not a user yet.' : 'These emails are not users yet.' }}\n Invite them to add them as users of this client, or add them in User Management under the Manage menu.\n </div>\n\n <div class=\"se-inv-list\">\n <div class=\"se-pickrow se-pickrow--all\" *ngIf=\"inviteEmails.length > 1\" (click)=\"toggleAllInvite()\">\n <span class=\"se-box\" [class.is-on]=\"allInvitePicked\">\n <svg *ngIf=\"allInvitePicked\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickall\">Select all ({{ inviteEmails.length }})</span>\n </div>\n <div class=\"se-pickrow\" *ngFor=\"let e of inviteEmails\" [class.is-on]=\"invitePicked.has(e)\" (click)=\"toggleInvite(e)\">\n <span class=\"se-box\" [class.is-on]=\"invitePicked.has(e)\">\n <svg *ngIf=\"invitePicked.has(e)\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <span class=\"se-pickname\"><span class=\"se-ellipsis\">{{ e }}</span></span>\n </div>\n </div>\n\n <div class=\"se-inv-foot\">\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" [disabled]=\"inviting\" (click)=\"closeInvite()\">Skip</button>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" [disabled]=\"inviting || !invitePicked.size\" (click)=\"inviteSelected()\">\n {{ inviting ? 'Inviting\u2026' : 'Invite selected' + (invitePicked.size ? ' (' + invitePicked.size + ')' : '') }}\n </button>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}:host{display:flex;flex-direction:column;gap:20px}.se-hidden{display:none}.se-grow{flex:1;min-width:0}.se-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sk-crumb{width:180px;height:12px;margin:4px 0}.se-sk-name{height:22px;margin:4px 0}.se-crumb{font-size:13px;line-height:20px;color:#667085}.se-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.se-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.se-fixed-audit{display:flex;flex-direction:column;gap:4px;padding:12px 14px;border-radius:8px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0}.se-fixed-audit-name{font-size:14px;line-height:20px;font-weight:600;color:#101828}.se-create{display:flex;flex-wrap:wrap;gap:20px;max-width:1180px}.se-card{min-width:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.se-card--form{flex:1 1 420px;padding:28px;gap:20px}.se-card--side{flex:1 1 380px;padding:28px;gap:16px}.se-badge{width:44px;height:44px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.se-head{display:flex;flex-direction:column;gap:4px}.se-title{font-size:24px;line-height:32px;font-weight:700;color:#101828}.se-side-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-sub{font-size:14px;line-height:20px;color:#667085}.se-field{display:flex;flex-direction:column;gap:6px;margin:0}.se-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.se-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.se-count{font-size:12px;line-height:18px;color:#667085;white-space:nowrap}.se-input{height:44px;padding:0 14px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:14px;color:#101828;outline:none}.se-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #ccedff}.se-search{display:flex;align-items:center;gap:8px;height:40px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.se-search input{flex:1;min-width:0;height:38px;border:none;outline:none;background:transparent;font-size:14px;font-family:inherit;color:#101828}.se-search--sm{flex:0 1 240px;min-width:180px;height:36px}.se-search--sm input{height:34px;font-size:13px}.se-clear{display:flex;cursor:pointer;color:#98a2b3}.se-picklist{display:flex;flex-direction:column;gap:2px;max-height:220px;overflow-y:auto;padding:8px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd}.se-pickrow{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-pickrow:hover{background:#f9fafb}.se-pickrow.is-on{background:#f5fbff}.se-pickrow--all{border-bottom:1px solid #F2F4F7}.se-pickrow--fixed{cursor:default;background:#f9fafb}.se-pickrow--fixed:hover{background:#f9fafb}.se-pickall{font-size:14px;line-height:20px;font-weight:600;color:#344054}.se-pickname{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-pickname .se-ellipsis{font-size:14px;line-height:20px;font-weight:500;color:#101828}.se-meta{font-size:12px;line-height:18px;color:#667085}.se-empty-sm{padding:14px 10px;font-size:13px;line-height:20px;color:#667085}.se-box{width:16px;height:16px;flex-shrink:0;border-radius:4px;display:flex;align-items:center;justify-content:center;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#00a3ff}.se-box.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #00a3ff}.se-steps{margin:0;padding-left:20px;display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.se-steps a{font-weight:600;color:#00a3ff;cursor:pointer}.se-actions{display:flex;flex-direction:column;gap:12px}.se-or{text-align:center;font-size:14px;color:#98a2b3}.se-btn-lg{height:44px;border:none;border-radius:8px;font-family:inherit;font-size:15px;font-weight:600;cursor:pointer}.se-btn-lg--primary{background:#00a3ff;color:#fff}.se-btn-lg--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054}.se-btn-lg--ghost:hover{background:#f9fafb}.se-btn-lg.is-off{cursor:not-allowed}.se-btn-lg--primary.is-off{background:#f2f4f7;color:#98a2b3}.se-btn-lg--ghost.is-off{color:#98a2b3}.se-btn-lg--ghost.is-off:hover{background:#fff}.se-sample{display:flex;flex-direction:column;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden}.se-sample-row{display:grid;grid-template-columns:.8fr 1.4fr 1fr 1.3fr;gap:8px;padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#344054}.se-sample-row span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-sample-row--head{border-top:none;background:#f9fafb;font-weight:600;color:#475467}.se-note{font-size:12px;line-height:18px;color:#667085;text-wrap:pretty}.se-note--warn{color:#b54708}.se-sample-more{padding:10px 12px;border-top:1px solid #EAECF0;font-size:12px;line-height:18px;color:#667085}.se-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.se-backbar+.se-titlebar{margin-top:-8px}.se-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.se-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.se-publish.is-off{background:#f2f4f7;color:#98a2b3;cursor:not-allowed;box-shadow:none}.se-ready{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:12px 20px;border-radius:8px;background:#fffcf5;box-shadow:inset 0 0 0 1px #fedf89;color:#b54708;font-size:14px;line-height:20px;font-weight:600}.se-ready svg{flex-shrink:0}.se-ready span{flex:1;min-width:0}.se-ready.is-ok{background:#f6fef9;box-shadow:inset 0 0 0 1px #a6f4c5;color:#027a48}.se-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.se-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.se-scroll{overflow-x:auto}.se-grid{min-width:1120px;display:grid;grid-template-columns:36px 1fr 1.5fr 1fr 1.5fr 1.6fr 40px;gap:12px;align-items:center;padding:10px 24px}.se-grid--head{background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.se-grid--row{border-bottom:1px solid #F2F4F7}.se-grid--row.is-selected{background:#f5fbff}.se-center{display:flex;justify-content:center;cursor:pointer}.se-grid--row.is-locked .se-cell{background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;color:#667085;-webkit-text-fill-color:#667085;opacity:1;cursor:not-allowed}.se-grid--row.is-locked .se-chev{display:none}.se-grid--row.is-locked .se-center.is-off{cursor:not-allowed}.se-grid--row.is-locked .se-center.is-off .se-box{background:#f2f4f7;box-shadow:inset 0 0 0 1px #eaecf0}.se-rowerr{grid-column:2/-1;margin-top:-4px;display:flex;align-items:flex-start;gap:6px;font-size:12px;line-height:18px;color:#d92d20}.se-rowerr svg{flex-shrink:0;margin-top:2px}.se-rowhint{color:#667085}.se-invite-link{flex-shrink:0;font-weight:600;color:#00a3ff;cursor:pointer;text-decoration:none}.se-invite-link:hover{text-decoration:underline}.se-inv-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.se-inv{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:480px;max-width:calc(100vw - 32px);max-height:90vh;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.se-inv-icon{width:48px;height:48px;border-radius:9999px;background:#fef0c7;box-shadow:0 0 0 8px #fffaeb;color:#dc6803;display:flex;align-items:center;justify-content:center;margin:4px 0 8px 4px}.se-inv-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.se-inv-text{font-size:14px;line-height:20px;color:#475467}.se-inv-list{max-height:260px;overflow-y:auto;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:4px}.se-inv-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:8px}.se-cell{width:100%;height:36px;min-width:0;padding:0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;color:#101828;outline:none}.se-cell:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-cell.is-bad{box-shadow:inset 0 0 0 1px #fda29b}.se-select{display:flex;align-items:center;justify-content:space-between;gap:6px;text-align:left;cursor:pointer}.se-select svg{flex-shrink:0;color:#667085}.se-placeholder{color:#98a2b3}.se-pick{position:relative;min-width:0}.se-cell--pick{padding-right:10px;text-overflow:ellipsis}.se-cell--tagged{padding-right:88px}.se-pick.is-open .se-cell{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 3px #ccedff}.se-pick.is-open .se-chev{transform:rotate(180deg)}.se-chev{transition:transform .15s ease}.se-tag{position:absolute;top:50%;right:8px;transform:translateY(-50%);max-width:76px;padding:2px 8px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:11px;line-height:16px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;pointer-events:none}.se-menu{position:fixed;z-index:1060;width:max-content;max-width:380px;max-height:288px;overflow-y:auto;padding:6px;border-radius:10px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 12px 16px -4px #10182814,0 4px 6px -2px #10182808}.se-opt{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer}.se-opt.is-active{background:#f9fafb}.se-opt.is-on{background:#f5fbff}.se-opt.is-on.is-active{background:#eaf8ff}.se-opt-avatar{width:28px;height:28px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.se-opt-icon{width:28px;height:28px;flex-shrink:0;border-radius:8px;background:#f2f4f7;color:#475467;display:flex;align-items:center;justify-content:center}.se-opt-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.se-opt-main{font-size:13px;line-height:18px;font-weight:500;color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-sub{font-size:12px;line-height:16px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.se-opt-check{flex-shrink:0;color:#00a3ff}.se-menu-empty{padding:12px 10px;font-size:13px;color:#667085}.se-menu--multi{min-width:260px}.se-menu-search{position:sticky;top:-6px;z-index:1;margin:-6px -6px 4px;padding:8px 10px;display:flex;align-items:center;gap:8px;background:#fff;border-bottom:1px solid #F2F4F7;color:#667085;cursor:text}.se-menu-search input{flex:1;min-width:0;border:0;outline:none;background:transparent;font-size:13px;line-height:18px;color:#101828}.se-menu-note{margin:4px -6px -6px;padding:8px 16px;border-top:1px solid #F2F4F7;background:#fcfcfd;font-size:12px;line-height:16px;color:#667085;position:sticky;bottom:-6px}.se-window{display:flex;align-items:center;gap:6px;min-width:0}.se-window .se-cell{flex:1;padding:0 6px}.se-dash{color:#98a2b3;font-size:13px}.se-lock{width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:#98a2b3;cursor:help}.se-del{width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#667085;cursor:pointer}.se-del:hover{background:#fffbfa;color:#d92d20}.se-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.se-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px}.se-foot-text{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:20px;color:#667085}.se-foot-actions{display:flex;align-items:center;gap:8px;margin-left:auto}.se-bulk{height:36px;padding:0 14px;border:none;border-radius:8px;background:transparent;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.se-bulk:hover{background:#f9fafb}.se-bulk--danger{color:#d92d20}.se-bulk--danger:hover{background:#fffbfa}.se-bulk.is-off{color:#98a2b3;cursor:not-allowed}.se-bulk.is-off:hover{background:transparent}.se-select .se-ellipsis{flex:0 1 auto;min-width:0}.se-select .se-chev{margin-left:auto}.se-more{flex-shrink:0;min-width:24px;height:20px;padding:0 7px;border-radius:9999px;background:#f2f4f7;color:#344054;font-size:12px;font-weight:600;line-height:20px;text-align:center}\n"] }]
|
|
6647
6655
|
}], ctorParameters: () => [{ type: TraxService }, { type: i3.ToastService }, { type: i0.ChangeDetectorRef }], propDecorators: { clientId: [{
|
|
6648
6656
|
type: Input
|
|
6649
6657
|
}], audits: [{
|
|
@@ -6848,7 +6856,8 @@ class AuditV2ScheduleDetailComponent {
|
|
|
6848
6856
|
edit = new EventEmitter();
|
|
6849
6857
|
loading = true;
|
|
6850
6858
|
name = '';
|
|
6851
|
-
audits
|
|
6859
|
+
/** The schedule's audits by name; the summary line shows a count when there are several (names in its tooltip). */
|
|
6860
|
+
auditNames = [];
|
|
6852
6861
|
published = false;
|
|
6853
6862
|
metrics = { visits: 0, users: 0, completed: 0, pending: 0 };
|
|
6854
6863
|
rows = [];
|
|
@@ -6875,7 +6884,7 @@ class AuditV2ScheduleDetailComponent {
|
|
|
6875
6884
|
}
|
|
6876
6885
|
this.name = d.schedule?.name || 'Schedule';
|
|
6877
6886
|
this.published = !!d.schedule?.publish;
|
|
6878
|
-
this.
|
|
6887
|
+
this.auditNames = (d.schedule?.checkLists || []).map((c) => c.checkListName).filter(Boolean);
|
|
6879
6888
|
this.metrics = { ...this.metrics, ...(d.metrics || {}) };
|
|
6880
6889
|
this.rows = (d.rows || []).map((r) => {
|
|
6881
6890
|
const email = String(r.userEmail || '');
|
|
@@ -6971,8 +6980,13 @@ class AuditV2ScheduleDetailComponent {
|
|
|
6971
6980
|
}
|
|
6972
6981
|
get rangeLabel() {
|
|
6973
6982
|
const m = this.shownMetrics;
|
|
6983
|
+
const n = this.auditNames.length;
|
|
6974
6984
|
return m.visits + (m.visits === 1 ? ' visit' : ' visits') + ' · ' + m.users + (m.users === 1 ? ' user' : ' users')
|
|
6975
|
-
+ (this.
|
|
6985
|
+
+ (n === 1 ? ' · ' + this.auditNames[0] : n > 1 ? ' · ' + n + ' audits' : '');
|
|
6986
|
+
}
|
|
6987
|
+
/** Every audit name, as the summary line's tooltip when it shows only the count. */
|
|
6988
|
+
get auditsTip() {
|
|
6989
|
+
return this.auditNames.length > 1 ? this.auditNames.join(', ') : null;
|
|
6976
6990
|
}
|
|
6977
6991
|
/** Column sort ('' = the schedule's order); a header click toggles ascending / descending (QA 10 Oct). */
|
|
6978
6992
|
sortKey = '';
|
|
@@ -7034,11 +7048,11 @@ class AuditV2ScheduleDetailComponent {
|
|
|
7034
7048
|
fg(s) { return STATUS$1[s].fg; }
|
|
7035
7049
|
dot(s) { return STATUS$1[s].dot; }
|
|
7036
7050
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ScheduleDetailComponent, deps: [{ token: TraxService }, { token: i3.ToastService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
7037
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ScheduleDetailComponent, selector: "lib-audit-v2-schedule-detail", inputs: { clientId: "clientId", scheduleId: "scheduleId", canEdit: "canEdit", fromDate: "fromDate", toDate: "toDate" }, outputs: { back: "back", edit: "edit" }, ngImport: i0, template: "<ng-container *ngIf=\"loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <span class=\"av2-sk sd-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title sd-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\"><span class=\"av2-sk av2-sk--value sd-sk-value\"></span></div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"!loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <div class=\"sd-crumb\"><a href=\"#\" (click)=\"goBack($event)\">Schedule</a> \u203A {{ name }}</div>\n <div class=\"sd-name\">{{ name }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" *ngIf=\"canEdit\" (click)=\"edit.emit(scheduleId)\">Edit rows</button>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <div class=\"sd-tablehead\">\n <div class=\"sd-titletext\">\n <div class=\"sd-card-title\">Scheduled info</div>\n <div class=\"sd-sub\">\n {{ rangeLabel }}\n <ng-container *ngIf=\"rangeText\">\n \u00B7 {{ rangeOn ? 'Visits on ' + rangeText : 'All dates' }}\n <a class=\"sd-range-link\" (click)=\"toggleShowAll()\">{{ rangeOn ? 'Show all dates' : 'Show ' + rangeText + ' only' }}</a>\n </ng-container>\n </div>\n </div>\n <label class=\"sd-search\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"query\" (ngModelChange)=\"onQuery()\" placeholder=\"Search users or stores\">\n </label>\n </div>\n\n <div class=\"sd-scroll\">\n <div class=\"sd-grid sd-grid--head\">\n <div class=\"av2-sortable\" (click)=\"sortBy('date')\">Schedule date <lib-audit-v2-sort-icon [active]=\"sortKey === 'date'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('email')\">User email <lib-audit-v2-sort-icon [active]=\"sortKey === 'email'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('store')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'store'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('window')\">Visit window <lib-audit-v2-sort-icon [active]=\"sortKey === 'window'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('audit')\">Audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'audit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('status')\">Status <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n </div>\n <div class=\"sd-grid sd-grid--row\" *ngFor=\"let r of paged\">\n <div>{{ r.date }}</div>\n <div class=\"sd-user\">\n <span class=\"sd-avatar\">{{ r.initials }}</span>\n <span class=\"sd-ellipsis\" [av2Tip]=\"r.email\">{{ r.email }}</span>\n </div>\n <!-- Store name (QA: the store code was shown); the id only for a row without a name. -->\n <div class=\"sd-store sd-ellipsis\" [av2Tip]=\"r.storeName || ''\">{{ r.storeName || '\u2014' }}</div>\n <div [class.sd-muted]=\"!r.hasWindow\" [class.sd-missed]=\"r.status === 'missed' && r.hasWindow\" [attr.title]=\"r.windowTip || null\">{{ r.window }}</div>\n <div class=\"sd-ellipsis\" [av2Tip]=\"r.audit\">{{ r.audit }}</div>\n <div>\n <span class=\"sd-pill\" [style.background]=\"bg(r.status)\" [style.color]=\"fg(r.status)\" [title]=\"r.note\">\n <span class=\"sd-dot\" [style.background]=\"dot(r.status)\"></span>{{ label(r.status) }}\n </span>\n </div>\n </div>\n <div *ngIf=\"!filtered.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No visits match this search.' : 'No rows yet. Use Edit rows to add users, stores and dates.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-foot\">\n <span>{{ countLabel }}</span>\n <lib-pagination *ngIf=\"filtered.length\" [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\"\n [paginationSizes]=\"pageSizes\" [currentPage]=\"page\" [totalItems]=\"filtered.length\"\n (pageChange)=\"onPage($event)\" (pageSizeChange)=\"onPageSize($event)\"></lib-pagination>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}:host{display:flex;flex-direction:column;gap:20px}.sd-sk-crumb{width:140px;height:12px;margin:4px 0}.sd-sk-name{height:22px;margin:4px 0}.sd-sk-value{height:32px;margin:3px 0}.sd-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.sd-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.sd-crumb{font-size:13px;line-height:20px;color:#667085}.sd-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.sd-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.sd-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px}.sd-card{border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.sd-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.sd-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.sd-sub{font-size:14px;line-height:20px;color:#667085}.sd-search{flex:0 1 260px;min-width:180px;display:flex;align-items:center;gap:8px;height:36px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.sd-search input{flex:1;min-width:0;height:34px;border:none;outline:none;background:transparent;font-size:13px;font-family:inherit;color:#101828}.sd-scroll{overflow-x:auto}.sd-grid{min-width:1180px;display:grid;grid-template-columns:1fr 1.6fr .9fr 1.1fr 1.5fr 1fr;gap:12px;align-items:center;padding:14px 24px}.sd-grid--head{padding:10px 24px;background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.sd-grid--row{border-bottom:1px solid #F2F4F7;font-size:13px;color:#344054}.sd-user{display:flex;align-items:center;gap:8px;min-width:0}.sd-avatar{width:24px;height:24px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700}.sd-ellipsis{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-store{font-weight:600;color:#101828}.sd-muted{color:#98a2b3}.sd-missed{color:#d92d20}.sd-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:9999px;font-size:12px;font-weight:600}.sd-dot{width:6px;height:6px;border-radius:9999px;display:block}.sd-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.sd-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px;font-size:14px;color:#667085}.sd-range-link{margin-left:6px;color:#00a3ff;font-weight:500;cursor:pointer}.sd-range-link:hover{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.PaginationComponent, selector: "lib-pagination", inputs: ["collection", "itemsPerPage", "currentPage", "totalItems", "directionLinks", "pageSize", "paginationSizes"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AuditV2TipDirective, selector: "[av2Tip]", inputs: ["av2Tip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SortIconComponent, selector: "lib-audit-v2-sort-icon", inputs: ["active", "dir"] }] });
|
|
7051
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ScheduleDetailComponent, selector: "lib-audit-v2-schedule-detail", inputs: { clientId: "clientId", scheduleId: "scheduleId", canEdit: "canEdit", fromDate: "fromDate", toDate: "toDate" }, outputs: { back: "back", edit: "edit" }, ngImport: i0, template: "<ng-container *ngIf=\"loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <span class=\"av2-sk sd-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title sd-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\"><span class=\"av2-sk av2-sk--value sd-sk-value\"></span></div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"!loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <div class=\"sd-crumb\"><a href=\"#\" (click)=\"goBack($event)\">Schedule</a> \u203A {{ name }}</div>\n <div class=\"sd-name\">{{ name }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" *ngIf=\"canEdit\" (click)=\"edit.emit(scheduleId)\">Edit rows</button>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <div class=\"sd-tablehead\">\n <div class=\"sd-titletext\">\n <div class=\"sd-card-title\">Scheduled info</div>\n <div class=\"sd-sub\">\n <span [attr.title]=\"auditsTip\">{{ rangeLabel }}</span>\n <ng-container *ngIf=\"rangeText\">\n \u00B7 {{ rangeOn ? 'Visits on ' + rangeText : 'All dates' }}\n <a class=\"sd-range-link\" (click)=\"toggleShowAll()\">{{ rangeOn ? 'Show all dates' : 'Show ' + rangeText + ' only' }}</a>\n </ng-container>\n </div>\n </div>\n <label class=\"sd-search\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"query\" (ngModelChange)=\"onQuery()\" placeholder=\"Search users or stores\">\n </label>\n </div>\n\n <div class=\"sd-scroll\">\n <div class=\"sd-grid sd-grid--head\">\n <div class=\"av2-sortable\" (click)=\"sortBy('date')\">Schedule date <lib-audit-v2-sort-icon [active]=\"sortKey === 'date'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('email')\">User email <lib-audit-v2-sort-icon [active]=\"sortKey === 'email'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('store')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'store'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('window')\">Visit window <lib-audit-v2-sort-icon [active]=\"sortKey === 'window'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('audit')\">Audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'audit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('status')\">Status <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n </div>\n <div class=\"sd-grid sd-grid--row\" *ngFor=\"let r of paged\">\n <div>{{ r.date }}</div>\n <div class=\"sd-user\">\n <span class=\"sd-avatar\">{{ r.initials }}</span>\n <span class=\"sd-ellipsis\" [av2Tip]=\"r.email\">{{ r.email }}</span>\n </div>\n <!-- Store name (QA: the store code was shown); the id only for a row without a name. -->\n <div class=\"sd-store sd-ellipsis\" [av2Tip]=\"r.storeName || ''\">{{ r.storeName || '\u2014' }}</div>\n <div [class.sd-muted]=\"!r.hasWindow\" [class.sd-missed]=\"r.status === 'missed' && r.hasWindow\" [attr.title]=\"r.windowTip || null\">{{ r.window }}</div>\n <div class=\"sd-ellipsis\" [av2Tip]=\"r.audit\">{{ r.audit }}</div>\n <div>\n <span class=\"sd-pill\" [style.background]=\"bg(r.status)\" [style.color]=\"fg(r.status)\" [title]=\"r.note\">\n <span class=\"sd-dot\" [style.background]=\"dot(r.status)\"></span>{{ label(r.status) }}\n </span>\n </div>\n </div>\n <div *ngIf=\"!filtered.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No visits match this search.' : 'No rows yet. Use Edit rows to add users, stores and dates.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-foot\">\n <span>{{ countLabel }}</span>\n <lib-pagination *ngIf=\"filtered.length\" [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\"\n [paginationSizes]=\"pageSizes\" [currentPage]=\"page\" [totalItems]=\"filtered.length\"\n (pageChange)=\"onPage($event)\" (pageSizeChange)=\"onPageSize($event)\"></lib-pagination>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}:host{display:flex;flex-direction:column;gap:20px}.sd-sk-crumb{width:140px;height:12px;margin:4px 0}.sd-sk-name{height:22px;margin:4px 0}.sd-sk-value{height:32px;margin:3px 0}.sd-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.sd-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.sd-crumb{font-size:13px;line-height:20px;color:#667085}.sd-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.sd-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.sd-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px}.sd-card{border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.sd-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.sd-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.sd-sub{font-size:14px;line-height:20px;color:#667085}.sd-search{flex:0 1 260px;min-width:180px;display:flex;align-items:center;gap:8px;height:36px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.sd-search input{flex:1;min-width:0;height:34px;border:none;outline:none;background:transparent;font-size:13px;font-family:inherit;color:#101828}.sd-scroll{overflow-x:auto}.sd-grid{min-width:1180px;display:grid;grid-template-columns:1fr 1.6fr .9fr 1.1fr 1.5fr 1fr;gap:12px;align-items:center;padding:14px 24px}.sd-grid--head{padding:10px 24px;background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.sd-grid--row{border-bottom:1px solid #F2F4F7;font-size:13px;color:#344054}.sd-user{display:flex;align-items:center;gap:8px;min-width:0}.sd-avatar{width:24px;height:24px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700}.sd-ellipsis{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-store{font-weight:600;color:#101828}.sd-muted{color:#98a2b3}.sd-missed{color:#d92d20}.sd-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:9999px;font-size:12px;font-weight:600}.sd-dot{width:6px;height:6px;border-radius:9999px;display:block}.sd-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.sd-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px;font-size:14px;color:#667085}.sd-range-link{margin-left:6px;color:#00a3ff;font-weight:500;cursor:pointer}.sd-range-link:hover{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.PaginationComponent, selector: "lib-pagination", inputs: ["collection", "itemsPerPage", "currentPage", "totalItems", "directionLinks", "pageSize", "paginationSizes"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AuditV2TipDirective, selector: "[av2Tip]", inputs: ["av2Tip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SortIconComponent, selector: "lib-audit-v2-sort-icon", inputs: ["active", "dir"] }] });
|
|
7038
7052
|
}
|
|
7039
7053
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ScheduleDetailComponent, decorators: [{
|
|
7040
7054
|
type: Component,
|
|
7041
|
-
args: [{ selector: 'lib-audit-v2-schedule-detail', template: "<ng-container *ngIf=\"loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <span class=\"av2-sk sd-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title sd-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\"><span class=\"av2-sk av2-sk--value sd-sk-value\"></span></div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"!loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <div class=\"sd-crumb\"><a href=\"#\" (click)=\"goBack($event)\">Schedule</a> \u203A {{ name }}</div>\n <div class=\"sd-name\">{{ name }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" *ngIf=\"canEdit\" (click)=\"edit.emit(scheduleId)\">Edit rows</button>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <div class=\"sd-tablehead\">\n <div class=\"sd-titletext\">\n <div class=\"sd-card-title\">Scheduled info</div>\n <div class=\"sd-sub\">\n {{ rangeLabel }}\n <ng-container *ngIf=\"rangeText\">\n \u00B7 {{ rangeOn ? 'Visits on ' + rangeText : 'All dates' }}\n <a class=\"sd-range-link\" (click)=\"toggleShowAll()\">{{ rangeOn ? 'Show all dates' : 'Show ' + rangeText + ' only' }}</a>\n </ng-container>\n </div>\n </div>\n <label class=\"sd-search\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"query\" (ngModelChange)=\"onQuery()\" placeholder=\"Search users or stores\">\n </label>\n </div>\n\n <div class=\"sd-scroll\">\n <div class=\"sd-grid sd-grid--head\">\n <div class=\"av2-sortable\" (click)=\"sortBy('date')\">Schedule date <lib-audit-v2-sort-icon [active]=\"sortKey === 'date'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('email')\">User email <lib-audit-v2-sort-icon [active]=\"sortKey === 'email'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('store')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'store'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('window')\">Visit window <lib-audit-v2-sort-icon [active]=\"sortKey === 'window'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('audit')\">Audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'audit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('status')\">Status <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n </div>\n <div class=\"sd-grid sd-grid--row\" *ngFor=\"let r of paged\">\n <div>{{ r.date }}</div>\n <div class=\"sd-user\">\n <span class=\"sd-avatar\">{{ r.initials }}</span>\n <span class=\"sd-ellipsis\" [av2Tip]=\"r.email\">{{ r.email }}</span>\n </div>\n <!-- Store name (QA: the store code was shown); the id only for a row without a name. -->\n <div class=\"sd-store sd-ellipsis\" [av2Tip]=\"r.storeName || ''\">{{ r.storeName || '\u2014' }}</div>\n <div [class.sd-muted]=\"!r.hasWindow\" [class.sd-missed]=\"r.status === 'missed' && r.hasWindow\" [attr.title]=\"r.windowTip || null\">{{ r.window }}</div>\n <div class=\"sd-ellipsis\" [av2Tip]=\"r.audit\">{{ r.audit }}</div>\n <div>\n <span class=\"sd-pill\" [style.background]=\"bg(r.status)\" [style.color]=\"fg(r.status)\" [title]=\"r.note\">\n <span class=\"sd-dot\" [style.background]=\"dot(r.status)\"></span>{{ label(r.status) }}\n </span>\n </div>\n </div>\n <div *ngIf=\"!filtered.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No visits match this search.' : 'No rows yet. Use Edit rows to add users, stores and dates.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-foot\">\n <span>{{ countLabel }}</span>\n <lib-pagination *ngIf=\"filtered.length\" [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\"\n [paginationSizes]=\"pageSizes\" [currentPage]=\"page\" [totalItems]=\"filtered.length\"\n (pageChange)=\"onPage($event)\" (pageSizeChange)=\"onPageSize($event)\"></lib-pagination>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}:host{display:flex;flex-direction:column;gap:20px}.sd-sk-crumb{width:140px;height:12px;margin:4px 0}.sd-sk-name{height:22px;margin:4px 0}.sd-sk-value{height:32px;margin:3px 0}.sd-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.sd-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.sd-crumb{font-size:13px;line-height:20px;color:#667085}.sd-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.sd-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.sd-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px}.sd-card{border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.sd-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.sd-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.sd-sub{font-size:14px;line-height:20px;color:#667085}.sd-search{flex:0 1 260px;min-width:180px;display:flex;align-items:center;gap:8px;height:36px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.sd-search input{flex:1;min-width:0;height:34px;border:none;outline:none;background:transparent;font-size:13px;font-family:inherit;color:#101828}.sd-scroll{overflow-x:auto}.sd-grid{min-width:1180px;display:grid;grid-template-columns:1fr 1.6fr .9fr 1.1fr 1.5fr 1fr;gap:12px;align-items:center;padding:14px 24px}.sd-grid--head{padding:10px 24px;background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.sd-grid--row{border-bottom:1px solid #F2F4F7;font-size:13px;color:#344054}.sd-user{display:flex;align-items:center;gap:8px;min-width:0}.sd-avatar{width:24px;height:24px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700}.sd-ellipsis{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-store{font-weight:600;color:#101828}.sd-muted{color:#98a2b3}.sd-missed{color:#d92d20}.sd-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:9999px;font-size:12px;font-weight:600}.sd-dot{width:6px;height:6px;border-radius:9999px;display:block}.sd-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.sd-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px;font-size:14px;color:#667085}.sd-range-link{margin-left:6px;color:#00a3ff;font-weight:500;cursor:pointer}.sd-range-link:hover{text-decoration:underline}\n"] }]
|
|
7055
|
+
args: [{ selector: 'lib-audit-v2-schedule-detail', template: "<ng-container *ngIf=\"loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <span class=\"av2-sk sd-sk-crumb\"></span>\n <span class=\"av2-sk av2-sk--title sd-sk-name\"></span>\n </div>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\"><span class=\"av2-sk av2-sk--value sd-sk-value\"></span></div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <lib-audit-v2-shimmer></lib-audit-v2-shimmer>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"!loading\">\n <div class=\"sd-titlebar\">\n <div class=\"sd-titletext\">\n <div class=\"sd-crumb\"><a href=\"#\" (click)=\"goBack($event)\">Schedule</a> \u203A {{ name }}</div>\n <div class=\"sd-name\">{{ name }}</div>\n </div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" *ngIf=\"canEdit\" (click)=\"edit.emit(scheduleId)\">Edit rows</button>\n </div>\n\n <div class=\"sd-metrics\">\n <div class=\"av2-ocard\" *ngFor=\"let m of cards\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count\">{{ m.value }}</div>\n <div class=\"av2-ocard-text\">{{ m.label }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-card\">\n <div class=\"sd-tablehead\">\n <div class=\"sd-titletext\">\n <div class=\"sd-card-title\">Scheduled info</div>\n <div class=\"sd-sub\">\n <span [attr.title]=\"auditsTip\">{{ rangeLabel }}</span>\n <ng-container *ngIf=\"rangeText\">\n \u00B7 {{ rangeOn ? 'Visits on ' + rangeText : 'All dates' }}\n <a class=\"sd-range-link\" (click)=\"toggleShowAll()\">{{ rangeOn ? 'Show all dates' : 'Show ' + rangeText + ' only' }}</a>\n </ng-container>\n </div>\n </div>\n <label class=\"sd-search\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" [(ngModel)]=\"query\" (ngModelChange)=\"onQuery()\" placeholder=\"Search users or stores\">\n </label>\n </div>\n\n <div class=\"sd-scroll\">\n <div class=\"sd-grid sd-grid--head\">\n <div class=\"av2-sortable\" (click)=\"sortBy('date')\">Schedule date <lib-audit-v2-sort-icon [active]=\"sortKey === 'date'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('email')\">User email <lib-audit-v2-sort-icon [active]=\"sortKey === 'email'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('store')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'store'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('window')\">Visit window <lib-audit-v2-sort-icon [active]=\"sortKey === 'window'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('audit')\">Audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'audit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n <div class=\"av2-sortable\" (click)=\"sortBy('status')\">Status <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></div>\n </div>\n <div class=\"sd-grid sd-grid--row\" *ngFor=\"let r of paged\">\n <div>{{ r.date }}</div>\n <div class=\"sd-user\">\n <span class=\"sd-avatar\">{{ r.initials }}</span>\n <span class=\"sd-ellipsis\" [av2Tip]=\"r.email\">{{ r.email }}</span>\n </div>\n <!-- Store name (QA: the store code was shown); the id only for a row without a name. -->\n <div class=\"sd-store sd-ellipsis\" [av2Tip]=\"r.storeName || ''\">{{ r.storeName || '\u2014' }}</div>\n <div [class.sd-muted]=\"!r.hasWindow\" [class.sd-missed]=\"r.status === 'missed' && r.hasWindow\" [attr.title]=\"r.windowTip || null\">{{ r.window }}</div>\n <div class=\"sd-ellipsis\" [av2Tip]=\"r.audit\">{{ r.audit }}</div>\n <div>\n <span class=\"sd-pill\" [style.background]=\"bg(r.status)\" [style.color]=\"fg(r.status)\" [title]=\"r.note\">\n <span class=\"sd-dot\" [style.background]=\"dot(r.status)\"></span>{{ label(r.status) }}\n </span>\n </div>\n </div>\n <div *ngIf=\"!filtered.length\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ rows.length ? 'No visits match this search.' : 'No rows yet. Use Edit rows to add users, stores and dates.' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"sd-foot\">\n <span>{{ countLabel }}</span>\n <lib-pagination *ngIf=\"filtered.length\" [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\"\n [paginationSizes]=\"pageSizes\" [currentPage]=\"page\" [totalItems]=\"filtered.length\"\n (pageChange)=\"onPage($event)\" (pageSizeChange)=\"onPageSize($event)\"></lib-pagination>\n </div>\n </div>\n</ng-container>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}:host{display:flex;flex-direction:column;gap:20px}.sd-sk-crumb{width:140px;height:12px;margin:4px 0}.sd-sk-name{height:22px;margin:4px 0}.sd-sk-value{height:32px;margin:3px 0}.sd-titlebar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.sd-titletext{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:2px}.sd-crumb{font-size:13px;line-height:20px;color:#667085}.sd-crumb a{font-weight:600;color:#00a3ff;text-decoration:none;cursor:pointer}.sd-name{font-size:20px;line-height:30px;font-weight:700;color:#101828}.sd-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px}.sd-card{border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;display:flex;flex-direction:column}.sd-tablehead{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:20px 24px}.sd-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.sd-sub{font-size:14px;line-height:20px;color:#667085}.sd-search{flex:0 1 260px;min-width:180px;display:flex;align-items:center;gap:8px;height:36px;padding:0 12px;margin:0;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;color:#667085}.sd-search input{flex:1;min-width:0;height:34px;border:none;outline:none;background:transparent;font-size:13px;font-family:inherit;color:#101828}.sd-scroll{overflow-x:auto}.sd-grid{min-width:1180px;display:grid;grid-template-columns:1fr 1.6fr .9fr 1.1fr 1.5fr 1fr;gap:12px;align-items:center;padding:14px 24px}.sd-grid--head{padding:10px 24px;background:#f9fafb;border-top:1px solid #EAECF0;border-bottom:1px solid #EAECF0;font-size:12px;font-weight:600;color:#475467}.sd-grid--row{border-bottom:1px solid #F2F4F7;font-size:13px;color:#344054}.sd-user{display:flex;align-items:center;gap:8px;min-width:0}.sd-avatar{width:24px;height:24px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700}.sd-ellipsis{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-store{font-weight:600;color:#101828}.sd-muted{color:#98a2b3}.sd-missed{color:#d92d20}.sd-pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:9999px;font-size:12px;font-weight:600}.sd-dot{width:6px;height:6px;border-radius:9999px;display:block}.sd-empty{padding:36px 24px;text-align:center;font-size:13px;color:#667085}.sd-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;padding:16px 24px;font-size:14px;color:#667085}.sd-range-link{margin-left:6px;color:#00a3ff;font-weight:500;cursor:pointer}.sd-range-link:hover{text-decoration:underline}\n"] }]
|
|
7042
7056
|
}], ctorParameters: () => [{ type: TraxService }, { type: i3.ToastService }, { type: i0.ChangeDetectorRef }], propDecorators: { clientId: [{
|
|
7043
7057
|
type: Input
|
|
7044
7058
|
}], scheduleId: [{
|
|
@@ -8217,6 +8231,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
8217
8231
|
const PASS_MARK = 75;
|
|
8218
8232
|
/** Rows without a circle head in the store hierarchy are grouped under this key. */
|
|
8219
8233
|
const UNASSIGNED = '__unassigned';
|
|
8234
|
+
/** Visits per /audit/dashboard/detail call when exporting (the API's max limit). */
|
|
8235
|
+
const EXPORT_PAGE = 5000;
|
|
8220
8236
|
/**
|
|
8221
8237
|
* Reports ("Reports — Store audit report" prototype), read from POST /trax/audit/reports: one call returns every
|
|
8222
8238
|
* store of the header scope with its score, result, last audit, cluster and hierarchy line, plus the circle head /
|
|
@@ -8385,6 +8401,9 @@ class AuditV2ReportsComponent {
|
|
|
8385
8401
|
return this.pageOf(this.storeRows);
|
|
8386
8402
|
}
|
|
8387
8403
|
get storeLabel() {
|
|
8404
|
+
if (this.storeSel && !this.storeSel.size) {
|
|
8405
|
+
return 'No stores selected';
|
|
8406
|
+
}
|
|
8388
8407
|
return this.storeSel
|
|
8389
8408
|
? this.storeSel.size + (this.storeSel.size === 1 ? ' store' : ' stores') + ' selected'
|
|
8390
8409
|
: 'All stores (' + this.allStores.length + ')';
|
|
@@ -8817,6 +8836,11 @@ class AuditV2ReportsComponent {
|
|
|
8817
8836
|
/** Apply: the draft's filters become the page's; a new date range refetches. */
|
|
8818
8837
|
applyFilters() {
|
|
8819
8838
|
const d = this.draft;
|
|
8839
|
+
if (d && d.mode === 'store' && d.storeSel && !d.storeSel.size) {
|
|
8840
|
+
this.activeCat = 'scope';
|
|
8841
|
+
this.toast.getErrorToast('Select at least one store');
|
|
8842
|
+
return;
|
|
8843
|
+
}
|
|
8820
8844
|
if (d) {
|
|
8821
8845
|
const datesChanged = d.from !== this.from || d.to !== this.to;
|
|
8822
8846
|
this.from = d.from;
|
|
@@ -8895,9 +8919,10 @@ class AuditV2ReportsComponent {
|
|
|
8895
8919
|
const n = this.storeScope.length;
|
|
8896
8920
|
return this.storeLabel + ' · ' + n + (n === 1 ? ' store' : ' stores') + ' in scope';
|
|
8897
8921
|
}
|
|
8922
|
+
/** null = every store; an empty set = none ticked (Select All unticked), which Apply does not accept. */
|
|
8898
8923
|
applyPick(ids) {
|
|
8899
8924
|
const uniq = [...new Set(ids)];
|
|
8900
|
-
this.storeSel =
|
|
8925
|
+
this.storeSel = uniq.length >= this.allStores.length ? null : new Set(uniq);
|
|
8901
8926
|
this.page = 1;
|
|
8902
8927
|
}
|
|
8903
8928
|
get pickedIds() {
|
|
@@ -9009,52 +9034,35 @@ class AuditV2ReportsComponent {
|
|
|
9009
9034
|
}
|
|
9010
9035
|
}
|
|
9011
9036
|
// ---------------------------------------------------------------------------
|
|
9012
|
-
// Export (
|
|
9037
|
+
// Export (QA 12 Oct): every export on this page is the Dashboard detail (Monthly Performance) "Audit Info"
|
|
9038
|
+
// workbook - one row per audit visit of the chosen stores in the report period - read from
|
|
9039
|
+
// POST /trax/audit/dashboard/detail with by 'scope' (no single audit / store / user), 5000 rows a call.
|
|
9013
9040
|
// ---------------------------------------------------------------------------
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
}
|
|
9018
|
-
/** Top Export: the whole report as filtered (every page): stores in the Store view, the current level in the User view. */
|
|
9041
|
+
/** True while an export is being fetched; a second click waits for it. */
|
|
9042
|
+
exporting = false;
|
|
9043
|
+
/** Top Export: the report as filtered (every page): its stores in the Store view, the stores under the current level in the User view. */
|
|
9019
9044
|
exportAll() {
|
|
9020
9045
|
if (this.loading) {
|
|
9021
9046
|
return;
|
|
9022
9047
|
}
|
|
9023
9048
|
if (this.isStoreMode || this.level === 'store') {
|
|
9024
9049
|
const list = this.isStoreMode ? this.storeRows : this.userStores;
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
return;
|
|
9028
|
-
}
|
|
9029
|
-
this.downloadCsv([this.storeHeader, ...list.map(s => this.storeLine(s))], this.isStoreMode ? 'store-report' : 'store-report-' + this.hierarchyTitle);
|
|
9030
|
-
}
|
|
9031
|
-
else {
|
|
9032
|
-
const list = this.filteredRows;
|
|
9033
|
-
if (!list.length) {
|
|
9034
|
-
this.toast.getErrorToast('Nothing to export');
|
|
9035
|
-
return;
|
|
9036
|
-
}
|
|
9037
|
-
const t = this.totals;
|
|
9038
|
-
this.downloadCsv([
|
|
9039
|
-
[this.levelLabel, 'Email', 'Total stores', 'Audited', 'Not audited', 'Coverage', 'Avg audit score', 'Failed store %'],
|
|
9040
|
-
...list.map(r => [r.name, r.email, r.total, r.audited, r.notAudited, r.coverage, r.avgScore, r.failedPct]),
|
|
9041
|
-
['Total', '', t.total, t.audited, t.total - t.audited, this.totalCoverage, this.totalAverage, this.totalFailedPct]
|
|
9042
|
-
], 'user-report-' + this.hierarchyTitle);
|
|
9050
|
+
this.exportVisits(list.map(s => s.key), this.isStoreMode ? 'Store report' : 'User report - ' + this.hierarchyTitle);
|
|
9051
|
+
return;
|
|
9043
9052
|
}
|
|
9044
|
-
this.
|
|
9053
|
+
const stores = this.filteredRows.reduce((all, row) => all.concat(this.storesUnder(row)), []);
|
|
9054
|
+
this.exportVisits(stores.map(s => s.key), 'User report - ' + this.hierarchyTitle);
|
|
9045
9055
|
}
|
|
9046
|
-
/** Row Export in a store table: that store's
|
|
9056
|
+
/** Row Export in a store table: that store's visits. */
|
|
9047
9057
|
exportStore(s) {
|
|
9048
|
-
|
|
9049
|
-
this.toast.getErrorToast('No audit to export for ' + s.name);
|
|
9050
|
-
return;
|
|
9051
|
-
}
|
|
9052
|
-
this.downloadCsv([this.storeHeader, this.storeLine(s)], 'audit-report-' + s.name);
|
|
9053
|
-
this.toast.getSuccessToast('Report exported for ' + s.name);
|
|
9058
|
+
this.exportVisits([s.key], s.name);
|
|
9054
9059
|
}
|
|
9055
|
-
/** Row Export in the roll-up table: every store under that row. */
|
|
9060
|
+
/** Row Export in the roll-up table: the visits of every store under that row. */
|
|
9056
9061
|
exportRow(row) {
|
|
9057
|
-
|
|
9062
|
+
this.exportVisits(this.storesUnder(row).map(s => s.key), row.name);
|
|
9063
|
+
}
|
|
9064
|
+
storesUnder(row) {
|
|
9065
|
+
return this.allStores.filter(s => {
|
|
9058
9066
|
if (row.key === UNASSIGNED) {
|
|
9059
9067
|
return !s.circleKey;
|
|
9060
9068
|
}
|
|
@@ -9066,21 +9074,80 @@ class AuditV2ReportsComponent {
|
|
|
9066
9074
|
}
|
|
9067
9075
|
return s.aomKey === row.key;
|
|
9068
9076
|
});
|
|
9069
|
-
|
|
9070
|
-
|
|
9077
|
+
}
|
|
9078
|
+
exportVisits(storeIds, title) {
|
|
9079
|
+
const ids = [...new Set(storeIds.filter(Boolean))];
|
|
9080
|
+
if (!ids.length) {
|
|
9081
|
+
this.toast.getErrorToast('No stores to export');
|
|
9082
|
+
return;
|
|
9083
|
+
}
|
|
9084
|
+
if (this.exporting) {
|
|
9071
9085
|
return;
|
|
9072
9086
|
}
|
|
9073
|
-
this.
|
|
9074
|
-
|
|
9087
|
+
this.exporting = true;
|
|
9088
|
+
const visits = [];
|
|
9089
|
+
const done = (error) => {
|
|
9090
|
+
this.exporting = false;
|
|
9091
|
+
if (error) {
|
|
9092
|
+
this.toast.getErrorToast(error);
|
|
9093
|
+
}
|
|
9094
|
+
else if (!visits.length) {
|
|
9095
|
+
this.toast.getErrorToast('No audit visits to export for ' + title);
|
|
9096
|
+
}
|
|
9097
|
+
else {
|
|
9098
|
+
this.traxService.exportWorkbook([{ name: 'Audit Info', rows: visits.map(r => this.visitLine(r)) }], `${title} - audit info - ${this.from} to ${this.to}`);
|
|
9099
|
+
this.toast.getSuccessToast('Report exported for ' + title);
|
|
9100
|
+
}
|
|
9101
|
+
this.cd.detectChanges();
|
|
9102
|
+
};
|
|
9103
|
+
const fetchPage = (offset) => {
|
|
9104
|
+
this.traxService.auditDashboardDetail({
|
|
9105
|
+
clientId: this.headerData?.client,
|
|
9106
|
+
fromDate: this.from,
|
|
9107
|
+
toDate: this.to,
|
|
9108
|
+
storeId: ids,
|
|
9109
|
+
by: 'scope',
|
|
9110
|
+
status: 'all',
|
|
9111
|
+
searchValue: '',
|
|
9112
|
+
limit: EXPORT_PAGE,
|
|
9113
|
+
offset
|
|
9114
|
+
}).pipe(takeUntil$1(this.destroy$)).subscribe({
|
|
9115
|
+
next: (res) => {
|
|
9116
|
+
if (res?.code !== 200) {
|
|
9117
|
+
done('Unable to export');
|
|
9118
|
+
return;
|
|
9119
|
+
}
|
|
9120
|
+
const page = res.data?.rows || [];
|
|
9121
|
+
visits.push(...page);
|
|
9122
|
+
if (page.length === EXPORT_PAGE && visits.length < (res.data?.totalCount || 0)) {
|
|
9123
|
+
fetchPage(offset + 1);
|
|
9124
|
+
return;
|
|
9125
|
+
}
|
|
9126
|
+
done();
|
|
9127
|
+
},
|
|
9128
|
+
error: () => done('Unable to export')
|
|
9129
|
+
});
|
|
9130
|
+
};
|
|
9131
|
+
fetchPage(1);
|
|
9075
9132
|
}
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
const
|
|
9079
|
-
const
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9133
|
+
/** The Dashboard detail export's columns (audit-v2-detail exportRows), one visit per row. */
|
|
9134
|
+
visitLine(r) {
|
|
9135
|
+
const status = r.status === 'submit' ? 'Submitted' : (r.status === 'inprogress' ? 'In Progress' : 'Open');
|
|
9136
|
+
const time = (v) => (v ? dayjs(v).format('hh:mm A, DD MMM YYYY') : '--');
|
|
9137
|
+
return {
|
|
9138
|
+
'Date': r.date ? dayjs(r.date).format('DD MMM YYYY') : '--',
|
|
9139
|
+
'Audit Name': r.checkListName,
|
|
9140
|
+
'Store ID': r.storeId,
|
|
9141
|
+
'Store Name': r.storeName,
|
|
9142
|
+
'User Name': r.userName,
|
|
9143
|
+
'Submitted By': r.userEmail,
|
|
9144
|
+
'Status': status + (r.redo ? ' (Redo)' : ''),
|
|
9145
|
+
'Submitted On': time(r.submittedOn),
|
|
9146
|
+
'Submission Count': r.submissionCount,
|
|
9147
|
+
'Flags': r.flags,
|
|
9148
|
+
'Approved By': r.approvedBy || '--',
|
|
9149
|
+
'Approved On': time(r.approvedOn)
|
|
9150
|
+
};
|
|
9084
9151
|
}
|
|
9085
9152
|
trackByRow(_, row) {
|
|
9086
9153
|
return row.key || row.name;
|
|
@@ -9095,11 +9162,11 @@ class AuditV2ReportsComponent {
|
|
|
9095
9162
|
return c.key;
|
|
9096
9163
|
}
|
|
9097
9164
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ReportsComponent, deps: [{ token: TraxService }, { token: i2.GlobalStateService }, { token: i3.ToastService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
9098
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ReportsComponent, selector: "lib-audit-v2-reports", ngImport: i0, template: "<div class=\"av2-page audit-reports\">\r\n\r\n <!-- Breadcrumb + title -->\r\n <div class=\"rp-head\">\r\n <div class=\"rp-crumb\">Audits \u203A <span class=\"rp-crumb-current\">Reports</span></div>\r\n <div class=\"rp-title\">Store audit report</div>\r\n </div>\r\n\r\n <!-- Filter chips, Filter button at the right end (QA 9 Oct); Export moved to the table head beside its search. -->\r\n <div class=\"rp-controls\">\r\n <button type=\"button\" class=\"rp-chip\" *ngFor=\"let c of chips; trackBy: trackByChip\" (click)=\"openFilters(c.key)\"\r\n [title]=\"c.label + ': ' + c.value\">\r\n <span class=\"rp-chip-key\">{{ c.label }}</span><span class=\"rp-chip-value\">{{ c.value }}</span>\r\n </button>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost rp-filterbtn\" (click)=\"openFilters()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"></polygon></svg>\r\n Filter\r\n <span class=\"rp-countpill\">{{ filterCount }}</span>\r\n </button>\r\n </div>\r\n\r\n <!-- User view: where in the hierarchy -->\r\n <div class=\"rp-drillbar\" *ngIf=\"!isStoreMode\">\r\n <ng-container *ngFor=\"let c of crumbs; let last = last; let first = first\">\r\n <div class=\"rp-drillcrumb\" [class.is-current]=\"last\" (click)=\"goToLevel(c.level)\">\r\n <span class=\"rp-drillsep\" *ngIf=\"!first\">\u203A</span>{{ c.label }}\r\n </div>\r\n </ng-container>\r\n <div class=\"av2-grow\"></div>\r\n <div class=\"rp-hint\">{{ hint }}</div>\r\n </div>\r\n\r\n <!-- Scope -->\r\n <div class=\"rp-scope\">\r\n <div class=\"rp-scope-title\">{{ scopeTitle }}</div>\r\n <div class=\"rp-scope-meta\">{{ scopeMeta }}</div>\r\n </div>\r\n\r\n <!-- KPIs -->\r\n <div class=\"rp-kpis\">\r\n <!-- Old Checklist summary card: figure + label in the gradient strip, note below. -->\r\n <div class=\"av2-ocard\" *ngFor=\"let kpi of kpis\">\r\n <div class=\"av2-ocard-head\">\r\n <div class=\"av2-ocard-count rp-kpi-value\" [class.is-good]=\"kpi.tone === 'good'\" [class.is-bad]=\"kpi.tone === 'bad'\">\r\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--value rp-sk-value\"></span>\r\n <ng-container *ngIf=\"!loading\">{{ kpi.value }}</ng-container>\r\n </div>\r\n <div class=\"av2-ocard-text\">{{ kpi.label }}</div>\r\n </div>\r\n <div class=\"av2-ocard-body\">\r\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--note\"></span>\r\n <div *ngIf=\"!loading\" class=\"av2-ocard-note\">{{ kpi.note }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Report table -->\r\n <section class=\"rp-card\">\r\n <div class=\"rp-card-head\">\r\n <div class=\"rp-card-text\">\r\n <ng-container *ngIf=\"isStoreMode\">\r\n <div class=\"rp-card-title\">Store report</div>\r\n <div class=\"rp-card-meta\">{{ storeRows.length }} {{ storeRows.length === 1 ? 'store' : 'stores' }} \u00B7 audits submitted in the period</div>\r\n </ng-container>\r\n <ng-container *ngIf=\"!isStoreMode\">\r\n <div class=\"rp-card-title\">{{ tableTitle }}</div>\r\n <div class=\"rp-card-meta\">{{ tableMeta }}</div>\r\n </ng-container>\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <label class=\"av2-search rp-search\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"7\"></circle>\r\n <line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line>\r\n </svg>\r\n <input type=\"text\" [placeholder]=\"isStoreMode ? 'Search store' : 'Search ' + levelLabel.toLowerCase()\"\r\n [(ngModel)]=\"search\" (ngModelChange)=\"onSearchChange()\">\r\n </label>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost\" [disabled]=\"loading\" (click)=\"exportAll()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 16V4\"></path><polyline points=\"7 9 12 4 17 9\"></polyline><path d=\"M4 16v4h16v-4\"></path></svg>\r\n Export\r\n </button>\r\n </div>\r\n\r\n <lib-audit-v2-shimmer *ngIf=\"loading\"></lib-audit-v2-shimmer>\r\n\r\n <!-- Store view: one row per store -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && isStoreMode && tableCount\">\r\n <table class=\"rp-table rp-table--stores\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('cluster')\">Cluster <lib-audit-v2-sort-icon [active]=\"sortKey === 'cluster'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('status')\">Result <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('lastAudit')\">Last audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'lastAudit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Export</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let s of storePageRows; trackBy: trackByKey\">\r\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.cluster\">{{ s.cluster || '\u2014' }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\r\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\r\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\r\n <td class=\"t-right\">\r\n <span class=\"rp-result\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\">{{ resultText(s) }}</span>\r\n </td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.lastAudit\">{{ s.lastAudit || 'No audit' }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportStore(s)\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td></td>\r\n <td></td>\r\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td class=\"t-right\">{{ totals.failed }} fail</td>\r\n <td></td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <!-- User view: circle head / zone manager / area manager roll-up -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level !== 'store' && tableCount\">\r\n <table class=\"rp-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">{{ levelLabel }} <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('total')\">Total stores <lib-audit-v2-sort-icon [active]=\"sortKey === 'total'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('notAudited')\">Not audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'notAudited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('coverage')\">Coverage <lib-audit-v2-sort-icon [active]=\"sortKey === 'coverage'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('avgScore')\">Avg audit score <lib-audit-v2-sort-icon [active]=\"sortKey === 'avgScore'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('failedPct')\">Failed store % <lib-audit-v2-sort-icon [active]=\"sortKey === 'failedPct'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Report</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of pageRows; trackBy: trackByRow\" class=\"rp-row\" (click)=\"openRow(row)\">\r\n <td>\r\n <div class=\"rp-name\">\r\n <span class=\"rp-name-main\">{{ row.name }}</span>\r\n <span class=\"rp-name-sub\" *ngIf=\"row.email\">{{ row.email }}</span>\r\n </div>\r\n </td>\r\n <td class=\"t-right\">{{ row.total }}</td>\r\n <td class=\"t-right\">{{ row.audited }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!row.notAudited\">{{ row.notAudited }}</td>\r\n <td class=\"t-right\">{{ row.coverage }}</td>\r\n <td class=\"t-right is-strong\">{{ row.avgScore }}</td>\r\n <td class=\"t-right is-strong\" [class.is-fail]=\"isHighFail(row)\">{{ row.failedPct }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportRow(row); $event.stopPropagation()\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td class=\"t-right\">{{ totals.total }}</td>\r\n <td class=\"t-right\">{{ totals.audited }}</td>\r\n <td class=\"t-right\">{{ totals.total - totals.audited }}</td>\r\n <td class=\"t-right\">{{ totalCoverage }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td class=\"t-right\">{{ totalFailedPct }}</td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <!-- User view, deepest level: the area manager's stores -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level === 'store' && tableCount\">\r\n <table class=\"rp-table rp-table--userstores\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('zone')\">Zone manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'zone'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Export</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let s of userStorePageRows; trackBy: trackByKey\">\r\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.zone\">{{ s.zone || '\u2014' }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\r\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\r\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportStore(s)\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td></td>\r\n <td></td>\r\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <div *ngIf=\"!loading && !tableCount\" class=\"av2-empty\">\r\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\r\n <div class=\"av2-empty-text\">\r\n <div class=\"av2-empty-title\">No data found</div>\r\n <div class=\"av2-empty-sub\">{{ search ? 'No rows match \"' + search + '\"' : 'No stores match the current filters' }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Shared pager (10 / 20 / 30), as on the other audit lists. -->\r\n <div class=\"rp-pager\" *ngIf=\"!loading && tableCount\">\r\n <lib-pagination [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\" [paginationSizes]=\"pageSizes\" [currentPage]=\"page\"\r\n [totalItems]=\"tableCount\" (pageChange)=\"onPageChange($event)\" (pageSizeChange)=\"onPageSizeChange($event)\"></lib-pagination>\r\n </div>\r\n </section>\r\n\r\n <!-- ============ FILTER DRAWER ============ -->\r\n <div class=\"filter-backdrop\" *ngIf=\"filtersOpen\" (click)=\"closeFilters()\"></div>\r\n\r\n <!-- Every control edits the drawer's draft (dr); the page behind changes only on Apply or Reset all. -->\r\n <div class=\"filter-drawer\" *ngIf=\"filtersOpen && draft as dr\">\r\n <div class=\"drawer-head\">\r\n <span class=\"drawer-title\">Filters</span>\r\n <span class=\"rp-countpill\">{{ dr.filterCount }}</span>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"closebtn\" (click)=\"closeFilters()\" title=\"Close\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"drawer-body\">\r\n <div class=\"drawer-nav\">\r\n <!-- trackBy: filterCats is rebuilt on every check, and lib-audit-v2-select's document:mousedown runs one\r\n between press and release; without it the button was replaced mid-click and the click never landed. -->\r\n <button type=\"button\" class=\"drawer-navitem\" *ngFor=\"let c of dr.filterCats; trackBy: trackByChip\" [class.navitem-active]=\"activeCat === c.key\"\r\n (click)=\"selectCat(c.key)\">\r\n <span class=\"navtext\">\r\n <span class=\"navtitle\">{{ c.label }}</span>\r\n <span class=\"navvalue\" [class.is-dirty]=\"c.dirty\">{{ c.value }}</span>\r\n </span>\r\n <span class=\"dirtydot\" *ngIf=\"c.dirty\"></span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"drawer-pane\">\r\n <div class=\"panetitle\">{{ dr.paneTitle }}</div>\r\n <div class=\"panehint\">{{ dr.paneSub }}</div>\r\n\r\n <!-- Date -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'date'\">\r\n <div class=\"av2-datepick\">\r\n <svg class=\"av2-datepick-icon\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\r\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line></svg>\r\n <input type=\"text\" class=\"av2-datepick-input rp-daterange\" ngxDaterangepickerMd readonly autocomplete=\"off\"\r\n placeholder=\"Select date range\" [(ngModel)]=\"dr.range\" [locale]=\"pickerLocale\" [maxDate]=\"today\"\r\n [ranges]=\"ranges\" [showCustomRangeLabel]=\"true\" [alwaysShowCalendars]=\"false\"\r\n [keepCalendarOpeningWithRange]=\"true\" [autoApply]=\"true\" [showCancel]=\"false\"\r\n [drops]=\"'down'\" [opens]=\"'right'\" (datesUpdated)=\"dr.onRangePicked($event)\">\r\n </div>\r\n <div class=\"rp-presets\">\r\n <button type=\"button\" class=\"rp-preset\" *ngFor=\"let p of presets\" [class.is-on]=\"dr.preset === p\"\r\n (click)=\"dr.setPreset(p)\">{{ p }}</button>\r\n </div>\r\n </div>\r\n\r\n <!-- View by -->\r\n <div class=\"pane-options\" *ngIf=\"activeCat === 'mode'\">\r\n <div class=\"pane-option\" [class.is-on]=\"dr.isStoreMode\" (click)=\"dr.setMode('store')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.isStoreMode\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Store</span>\r\n <span class=\"pane-option-help\">One row per store with score, result and last audit date.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"!dr.isStoreMode\" (click)=\"dr.setMode('user')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"!dr.isStoreMode\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">User</span>\r\n <span class=\"pane-option-help\">Rolled up by circle head, zone manager and AOM, drillable down to stores.</span>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Stores (Store view) -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && dr.isStoreMode\">\r\n <label class=\"av2-search rp-pick-search\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\r\n <input type=\"text\" placeholder=\"Search store\" [(ngModel)]=\"dr.storeQuery\">\r\n </label>\r\n <div class=\"rp-picklist\">\r\n <ng-container *ngIf=\"dr.storePickItems.length\">\r\n <label class=\"rp-pick is-all\">\r\n <input type=\"checkbox\" [checked]=\"dr.storePickAllChecked\" (change)=\"dr.toggleStorePickAll()\">\r\n <span>Select All</span>\r\n </label>\r\n <label class=\"rp-pick\" *ngFor=\"let it of dr.storePickItems; trackBy: trackByPick\">\r\n <input type=\"checkbox\" [checked]=\"it.checked\" (change)=\"dr.toggleStorePick(it.store)\">\r\n <span class=\"rp-pick-label\">{{ it.store.name }}</span>\r\n <span class=\"rp-pick-sub\">{{ it.store.cluster || it.store.aom }}</span>\r\n </label>\r\n </ng-container>\r\n <div class=\"rp-pick-empty\" *ngIf=\"!dr.storePickItems.length\">\r\n {{ dr.storeQuery ? 'No stores match \"' + dr.storeQuery + '\"' : 'No stores in scope' }}\r\n </div>\r\n </div>\r\n <div class=\"rp-reading\">\r\n <span>Reading</span>\r\n <strong>{{ dr.storePickReading }}</strong>\r\n <span class=\"av2-grow\"></span>\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.resetStorePick()\">Reset to all stores</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Store hierarchy (User view) -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && !dr.isStoreMode\">\r\n <div class=\"rp-field\">\r\n <div class=\"rp-field-label\">Circle Head <span>{{ dr.circleOptions.length - 1 }} users</span></div>\r\n <lib-audit-v2-select [value]=\"dr.circleKey\" [options]=\"dr.circleOptions\" placeholder=\"All circles\"\r\n ariaLabel=\"Circle Head\" (changed)=\"dr.pickCircle($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.showZonePick\">\r\n <div class=\"rp-field-label\">Zone Manager <span>{{ dr.zoneOptions.length - 1 }} {{ dr.zoneOptions.length === 2 ? 'user' : 'users' }}</span></div>\r\n <lib-audit-v2-select [value]=\"dr.zoneKey\" [options]=\"dr.zoneOptions\" placeholder=\"All zones\"\r\n ariaLabel=\"Zone Manager\" (changed)=\"dr.pickZone($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.zoneKey\">\r\n <div class=\"rp-field-label\">AOM <span>{{ dr.aomOptions.length - 1 }} {{ dr.aomOptions.length === 2 ? 'user' : 'users' }}</span></div>\r\n <lib-audit-v2-select [value]=\"dr.aomKey\" [options]=\"dr.aomOptions\" placeholder=\"All AOMs\"\r\n ariaLabel=\"AOM\" (changed)=\"dr.pickAom($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.aomKey\">\r\n <div class=\"rp-field-label\">Store <span>{{ dr.storeOptions.length - 1 }} stores</span></div>\r\n <lib-audit-v2-select [value]=\"dr.storeKey\" [options]=\"dr.storeOptions\" placeholder=\"All stores\"\r\n ariaLabel=\"Store\" (changed)=\"dr.pickStore($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-reading\">\r\n <span>Reading</span>\r\n <strong>{{ dr.hierarchyReading }}</strong>\r\n <span class=\"av2-grow\"></span>\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.goToLevel('circle')\">Reset to all circles</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Result (Store view) -->\r\n <div class=\"pane-options\" *ngIf=\"activeCat === 'result' && dr.isStoreMode\">\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'all'\" (click)=\"dr.setResult('all')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'all'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">All</span>\r\n <span class=\"pane-option-help\">Every store in scope, audited or not.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'pass'\" (click)=\"dr.setResult('pass')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'pass'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Pass</span>\r\n <span class=\"pane-option-help\">Only stores scoring at or above the {{ passMark }}% pass mark.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'fail'\" (click)=\"dr.setResult('fail')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'fail'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Fail</span>\r\n <span class=\"pane-option-help\">Only stores scoring below the {{ passMark }}% pass mark.</span>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"drawer-foot\">\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"resetFilters()\">Reset all</button>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--wide\" (click)=\"applyFilters()\">Apply</button>\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}.rp-pager{padding-top:20px}.rp-head{display:flex;flex-direction:column;gap:2px}.rp-crumb{font-size:13px;line-height:20px;color:#667085}.rp-crumb-current{color:#00a3ff}.rp-title{font-size:22px;line-height:30px;font-weight:600;color:#101828}.rp-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-countpill{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:9999px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:600}.rp-chip{height:32px;max-width:360px;padding:0 12px;border:none;border-radius:9999px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-size:13px;line-height:20px;white-space:nowrap;cursor:pointer}.rp-chip:hover{background:#f9fafb}.rp-chip-key{font-weight:500;color:#667085}.rp-chip-value{overflow:hidden;text-overflow:ellipsis;font-weight:600;color:#101828}.av2-datepick{position:relative;display:inline-flex;align-items:center}.av2-datepick-icon{position:absolute;left:10px;color:#667085;pointer-events:none}.av2-datepick-input{height:36px;padding:0 10px 0 32px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;background:#fff;font-family:inherit;font-size:13px;font-weight:500;color:#101828;cursor:pointer;outline:none}.av2-datepick-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}:host ::ng-deep .av2-datepick .md-drppicker{margin-top:4px;z-index:1060;font-family:inherit;border-radius:8px;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,inset 0 0 0 1px #eaecf0}:host ::ng-deep .av2-datepick .md-drppicker.double,:host ::ng-deep .av2-datepick .md-drppicker.show-ranges{width:max-content}:host ::ng-deep .av2-datepick .md-drppicker.ltr .ranges{float:left;margin-top:10px}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button{width:160px;padding:12px 16px;border:none;border-radius:8px;background:none;color:#344054;font-size:14px;font-weight:400;line-height:20px;text-align:left;cursor:pointer}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button.active{background:#eaf8ff;color:#00a3ff;font-weight:500}:host ::ng-deep .av2-datepick .md-drppicker th,:host ::ng-deep .av2-datepick .md-drppicker td{width:40px!important;height:40px!important;min-width:32px;padding:0!important;border:1px solid transparent!important;background:transparent!important;font-size:14px!important;font-weight:400!important;line-height:38px}:host ::ng-deep .av2-datepick .md-drppicker th{color:#344054!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker th.month{width:auto!important;font-size:16px!important}:host ::ng-deep .av2-datepick .md-drppicker td{color:#344054!important}:host ::ng-deep .av2-datepick .md-drppicker th.available.prev,:host ::ng-deep .av2-datepick .md-drppicker th.available.next{background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 6 9 12 15 18'/%3E%3C/svg%3E\") center/18px no-repeat!important}:host ::ng-deep .av2-datepick .md-drppicker th.available:hover,:host ::ng-deep .av2-datepick .md-drppicker td.available:hover{background-color:#f2f4f7!important}:host ::ng-deep .av2-datepick .md-drppicker td.in-range{background-color:#eaf8ff!important;color:#101828!important}:host ::ng-deep .av2-datepick .md-drppicker td.active,:host ::ng-deep .av2-datepick .md-drppicker td.active:hover{background-color:#029cf4!important;border-radius:20px;color:#fff!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker td.off,:host ::ng-deep .av2-datepick .md-drppicker td.off.in-range{color:#98a2b3!important;background-color:transparent!important}:host ::ng-deep .av2-datepick .md-drppicker td.disabled{color:#98a2b3!important;background-color:transparent!important;text-decoration:line-through;pointer-events:none}:host ::ng-deep .av2-datepick--compact .md-drppicker th,:host ::ng-deep .av2-datepick--compact .md-drppicker td{width:32px!important;height:32px!important;font-size:12px!important;line-height:30px}:host ::ng-deep .av2-datepick--compact .md-drppicker th.month{font-size:14px!important}.rp-daterange{width:260px;height:44px;font-size:14px}.rp-presets{display:flex;flex-wrap:wrap;gap:8px}.rp-preset{height:36px;padding:0 14px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;font-family:inherit;font-size:14px;font-weight:500;color:#667085;cursor:pointer}.rp-preset.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #99dbff;color:#101828;font-weight:600}.rp-drillbar{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:14px 18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.rp-drillcrumb{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:#00a3ff;cursor:pointer}.rp-drillcrumb.is-current{color:#101828;cursor:default}.rp-drillsep{color:#98a2b3;font-weight:400}.rp-hint{font-size:14px;color:#667085}.rp-scope{display:flex;flex-direction:column;gap:2px}.rp-scope-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-scope-meta{font-size:14px;line-height:20px;color:#667085}.rp-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:16px}.rp-kpi-value.is-good{color:#027a48}.rp-kpi-value.is-bad{color:#d92d20}.rp-sk-value{height:32px;margin:3px 0}.rp-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:18px 20px 12px;display:flex;flex-direction:column;gap:14px}.rp-card-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-card-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:200px}.rp-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-card-meta{font-size:14px;line-height:20px;color:#667085}.rp-search{width:260px}.rp-table{width:100%;border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed}.rp-table th:nth-child(1){width:29%}.rp-table th:nth-child(2){width:9.5%}.rp-table th:nth-child(3){width:8.5%}.rp-table th:nth-child(4){width:9.5%}.rp-table th:nth-child(5){width:9.5%}.rp-table th:nth-child(6){width:12%}.rp-table th:nth-child(7){width:11%}.rp-table th:nth-child(8){width:11%}.rp-table--stores th:nth-child(1){width:14%}.rp-table--stores th:nth-child(2){width:20%}.rp-table--stores th:nth-child(3){width:16%}.rp-table--stores th:nth-child(4){width:9%}.rp-table--stores th:nth-child(5){width:9%}.rp-table--stores th:nth-child(6){width:11%}.rp-table--stores th:nth-child(7){width:12%}.rp-table--stores th:nth-child(8){width:9%}.rp-table--userstores th:nth-child(1){width:18%}.rp-table--userstores th:nth-child(2){width:25%}.rp-table--userstores th:nth-child(3){width:25%}.rp-table--userstores th:nth-child(4){width:11%}.rp-table--userstores th:nth-child(5){width:10%}.rp-table--userstores th:nth-child(6){width:11%}.rp-table thead th{padding:8px 4px;border:0;border-bottom:1px solid #EAECF0;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;white-space:nowrap}.rp-table tbody td{padding:12px 4px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;color:#344054;vertical-align:middle}.rp-table tfoot td{padding:12px 4px;border:0;font-size:14px;line-height:20px;font-weight:700;color:#101828}.rp-table thead th.t-right,.rp-table tbody td.t-right,.rp-table tfoot td.t-right{text-align:right}.rp-table .is-strong{font-weight:600}.rp-table tbody td.is-muted{color:#98a2b3}.rp-table tbody td.is-pass{color:#027a48}.rp-table tbody td.is-fail{color:#d92d20}.rp-table tbody td.rp-cell-name{color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-result{display:inline-flex;padding:2px 10px;border-radius:9999px;background:#f2f4f7;font-size:12px;line-height:18px;font-weight:500;color:#475467;white-space:nowrap}.rp-result.is-pass{background:#ecfdf3;color:#027a48}.rp-result.is-fail{background:#fef3f2;color:#b42318}.rp-row{cursor:pointer}.rp-row:hover td{background:#fcfcfd}.rp-name{display:flex;flex-direction:column;gap:2px;min-width:0}.rp-name-main{font-weight:600;color:#00a3ff}.rp-name-sub{font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-export{height:32px;padding:0 12px;border:none;border-radius:6px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.rp-export:hover{background:#f9fafb}.filter-backdrop{position:fixed;inset:0;background:#10182873;z-index:1050}.filter-drawer{position:fixed;top:0;right:0;bottom:0;width:860px;max-width:96vw;display:flex;flex-direction:column;background:#fff;box-shadow:-10px 0 30px #1018282e;z-index:1051;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.drawer-head{display:flex;align-items:center;gap:10px;padding:18px 20px;box-shadow:inset 0 -1px #eaecf0}.drawer-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.closebtn{width:32px;height:32px;border:none;border-radius:8px;background:transparent;color:#667085;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.closebtn:hover{background:#f2f4f7;color:#344054}.drawer-body{display:flex;flex:1;min-height:0}.drawer-nav{flex:0 0 280px;max-width:280px;background:#f9fafb;box-shadow:inset -1px 0 #eaecf0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:4px}.drawer-navitem{display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border:none;border-radius:8px;background:transparent;text-align:left;font-family:inherit;cursor:pointer}.drawer-navitem:hover{background:#fff}.drawer-navitem.navitem-active{background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d}.navtext{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.navtitle{font-size:14px;line-height:20px;font-weight:600;color:#101828}.navvalue{font-size:14px;line-height:20px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.navvalue.is-dirty{color:#009bf3}.dirtydot{width:8px;height:8px;border-radius:9999px;background:#00a3ff;flex-shrink:0;display:block}.drawer-pane{flex:1;min-width:0;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:6px}.panetitle{font-size:18px;line-height:28px;font-weight:600;color:#101828}.panehint{font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.pane-stack{display:flex;flex-direction:column;gap:14px;margin-top:14px;max-width:560px}.pane-options{display:flex;flex-direction:column;gap:10px;margin-top:14px;max-width:560px}.pane-option{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:8px;cursor:pointer;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0}.pane-option.is-on{background:#f5fbff;box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio{width:18px;height:18px;flex-shrink:0;margin-top:2px;border-radius:9999px;display:flex;align-items:center;justify-content:center;box-shadow:inset 0 0 0 1px #d0d5dd}.pane-radio>span{width:8px;height:8px;border-radius:9999px;background:transparent;display:block}.pane-radio.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio.is-on>span{background:#00a3ff}.pane-option-text{display:flex;flex-direction:column;gap:2px}.pane-option-label{font-size:14px;line-height:20px;font-weight:600;color:#101828}.pane-option-help{font-size:14px;line-height:20px;color:#667085}.drawer-foot{display:flex;align-items:center;gap:10px;padding:14px 20px;box-shadow:inset 0 1px #eaecf0}.rp-reset{border:none;background:transparent;padding:0;font-family:inherit;font-weight:600;text-decoration:none;white-space:nowrap}.rp-pick-search{width:100%}.rp-picklist{max-height:320px;overflow-y:auto;padding:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column}.rp-pick{display:flex;align-items:center;gap:12px;min-height:40px;margin:0;padding:0 10px;border-radius:6px;font-size:14px;color:#344054;cursor:pointer}.rp-pick:hover{background:#f9fafb}.rp-pick.is-all{font-weight:600}.rp-pick input{appearance:none;-webkit-appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid #D0D5DD;border-radius:4px;background:#fff no-repeat center/12px 12px;cursor:pointer;vertical-align:middle;transition:border-color .12s ease,background-color .12s ease}.rp-pick input:hover:not(:disabled){border-color:#00a3ff}.rp-pick input:checked{border-color:#00a3ff;background-color:#eaf8ff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300A3FF' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E\")}.rp-pick input:focus-visible{outline:none;box-shadow:0 0 0 3px #eaf8ff}.rp-pick input:disabled{cursor:not-allowed;opacity:.45}.rp-pick-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-sub{max-width:45%;font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-empty{padding:20px 10px;font-size:14px;color:#667085}.rp-reading{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:8px;background:#f9fafb;font-size:14px;color:#475467}.rp-reading strong{font-weight:600;color:#101828}.rp-field{display:flex;flex-direction:column;gap:6px;min-width:0}.rp-field-label{display:flex;align-items:baseline;gap:8px;font-size:14px;line-height:20px;font-weight:600;color:#1d2939}.rp-field-label span{font-weight:400;color:#667085}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.PaginationComponent, selector: "lib-pagination", inputs: ["collection", "itemsPerPage", "currentPage", "totalItems", "directionLinks", "pageSize", "paginationSizes"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i8.DaterangepickerDirective, selector: "input[ngxDaterangepickerMd]", inputs: ["minDate", "maxDate", "autoApply", "alwaysShowCalendars", "showCustomRangeLabel", "linkedCalendars", "dateLimit", "singleDatePicker", "showWeekNumbers", "showISOWeekNumbers", "showDropdowns", "isInvalidDate", "isCustomDate", "isTooltipDate", "showClearButton", "customRangeDirection", "ranges", "opens", "drops", "firstMonthDayClass", "lastMonthDayClass", "emptyWeekRowClass", "emptyWeekColumnClass", "firstDayOfNextMonthClass", "lastDayOfPreviousMonthClass", "keepCalendarOpeningWithRange", "showRangeLabelOnInput", "showCancel", "lockStartDate", "timePicker", "timePicker24Hour", "timePickerIncrement", "timePickerSeconds", "closeOnAutoApply", "endKeyHolder", "startKey", "locale", "endKey"], outputs: ["change", "rangeClicked", "datesUpdated", "startDateChanged", "endDateChanged", "clearClicked"] }, { kind: "directive", type: AuditV2TipDirective, selector: "[av2Tip]", inputs: ["av2Tip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SelectComponent, selector: "lib-audit-v2-select", inputs: ["options", "placeholder", "searchable", "ariaLabel", "disabled", "value"], outputs: ["changed"] }, { kind: "component", type: AuditV2SortIconComponent, selector: "lib-audit-v2-sort-icon", inputs: ["active", "dir"] }] });
|
|
9165
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ReportsComponent, selector: "lib-audit-v2-reports", ngImport: i0, template: "<div class=\"av2-page audit-reports\">\n\n <!-- Breadcrumb + title -->\n <div class=\"rp-head\">\n <div class=\"rp-crumb\">Audits \u203A <span class=\"rp-crumb-current\">Reports</span></div>\n <div class=\"rp-title\">Store audit report</div>\n </div>\n\n <!-- Filter chips, Filter button at the right end (QA 9 Oct); Export moved to the table head beside its search. -->\n <div class=\"rp-controls\">\n <button type=\"button\" class=\"rp-chip\" *ngFor=\"let c of chips; trackBy: trackByChip\" (click)=\"openFilters(c.key)\"\n [title]=\"c.label + ': ' + c.value\">\n <span class=\"rp-chip-key\">{{ c.label }}</span><span class=\"rp-chip-value\">{{ c.value }}</span>\n </button>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost rp-filterbtn\" (click)=\"openFilters()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"></polygon></svg>\n Filter\n <span class=\"rp-countpill\">{{ filterCount }}</span>\n </button>\n </div>\n\n <!-- User view: where in the hierarchy -->\n <div class=\"rp-drillbar\" *ngIf=\"!isStoreMode\">\n <ng-container *ngFor=\"let c of crumbs; let last = last; let first = first\">\n <div class=\"rp-drillcrumb\" [class.is-current]=\"last\" (click)=\"goToLevel(c.level)\">\n <span class=\"rp-drillsep\" *ngIf=\"!first\">\u203A</span>{{ c.label }}\n </div>\n </ng-container>\n <div class=\"av2-grow\"></div>\n <div class=\"rp-hint\">{{ hint }}</div>\n </div>\n\n <!-- Scope -->\n <div class=\"rp-scope\">\n <div class=\"rp-scope-title\">{{ scopeTitle }}</div>\n <div class=\"rp-scope-meta\">{{ scopeMeta }}</div>\n </div>\n\n <!-- KPIs -->\n <div class=\"rp-kpis\">\n <!-- Old Checklist summary card: figure + label in the gradient strip, note below. -->\n <div class=\"av2-ocard\" *ngFor=\"let kpi of kpis\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count rp-kpi-value\" [class.is-good]=\"kpi.tone === 'good'\" [class.is-bad]=\"kpi.tone === 'bad'\">\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--value rp-sk-value\"></span>\n <ng-container *ngIf=\"!loading\">{{ kpi.value }}</ng-container>\n </div>\n <div class=\"av2-ocard-text\">{{ kpi.label }}</div>\n </div>\n <div class=\"av2-ocard-body\">\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--note\"></span>\n <div *ngIf=\"!loading\" class=\"av2-ocard-note\">{{ kpi.note }}</div>\n </div>\n </div>\n </div>\n\n <!-- Report table -->\n <section class=\"rp-card\">\n <div class=\"rp-card-head\">\n <div class=\"rp-card-text\">\n <ng-container *ngIf=\"isStoreMode\">\n <div class=\"rp-card-title\">Store report</div>\n <div class=\"rp-card-meta\">{{ storeRows.length }} {{ storeRows.length === 1 ? 'store' : 'stores' }} \u00B7 audits submitted in the period</div>\n </ng-container>\n <ng-container *ngIf=\"!isStoreMode\">\n <div class=\"rp-card-title\">{{ tableTitle }}</div>\n <div class=\"rp-card-meta\">{{ tableMeta }}</div>\n </ng-container>\n </div>\n <div class=\"av2-grow\"></div>\n <label class=\"av2-search rp-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"7\"></circle>\n <line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line>\n </svg>\n <input type=\"text\" [placeholder]=\"isStoreMode ? 'Search store' : 'Search ' + levelLabel.toLowerCase()\"\n [(ngModel)]=\"search\" (ngModelChange)=\"onSearchChange()\">\n </label>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost\" [disabled]=\"loading || exporting\" (click)=\"exportAll()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 16V4\"></path><polyline points=\"7 9 12 4 17 9\"></polyline><path d=\"M4 16v4h16v-4\"></path></svg>\n Export\n </button>\n </div>\n\n <lib-audit-v2-shimmer *ngIf=\"loading\"></lib-audit-v2-shimmer>\n\n <!-- Store view: one row per store -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && isStoreMode && tableCount\">\n <table class=\"rp-table rp-table--stores\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('cluster')\">Cluster <lib-audit-v2-sort-icon [active]=\"sortKey === 'cluster'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('status')\">Result <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('lastAudit')\">Last audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'lastAudit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Export</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of storePageRows; trackBy: trackByKey\">\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.cluster\">{{ s.cluster || '\u2014' }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\n <td class=\"t-right\">\n <span class=\"rp-result\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\">{{ resultText(s) }}</span>\n </td>\n <td class=\"t-right\" [class.is-muted]=\"!s.lastAudit\">{{ s.lastAudit || 'No audit' }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportStore(s)\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td></td>\n <td></td>\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td class=\"t-right\">{{ totals.failed }} fail</td>\n <td></td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <!-- User view: circle head / zone manager / area manager roll-up -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level !== 'store' && tableCount\">\n <table class=\"rp-table\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">{{ levelLabel }} <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('total')\">Total stores <lib-audit-v2-sort-icon [active]=\"sortKey === 'total'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('notAudited')\">Not audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'notAudited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('coverage')\">Coverage <lib-audit-v2-sort-icon [active]=\"sortKey === 'coverage'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('avgScore')\">Avg audit score <lib-audit-v2-sort-icon [active]=\"sortKey === 'avgScore'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('failedPct')\">Failed store % <lib-audit-v2-sort-icon [active]=\"sortKey === 'failedPct'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Report</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of pageRows; trackBy: trackByRow\" class=\"rp-row\" (click)=\"openRow(row)\">\n <td>\n <div class=\"rp-name\">\n <span class=\"rp-name-main\">{{ row.name }}</span>\n <span class=\"rp-name-sub\" *ngIf=\"row.email\">{{ row.email }}</span>\n </div>\n </td>\n <td class=\"t-right\">{{ row.total }}</td>\n <td class=\"t-right\">{{ row.audited }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!row.notAudited\">{{ row.notAudited }}</td>\n <td class=\"t-right\">{{ row.coverage }}</td>\n <td class=\"t-right is-strong\">{{ row.avgScore }}</td>\n <td class=\"t-right is-strong\" [class.is-fail]=\"isHighFail(row)\">{{ row.failedPct }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportRow(row); $event.stopPropagation()\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td class=\"t-right\">{{ totals.total }}</td>\n <td class=\"t-right\">{{ totals.audited }}</td>\n <td class=\"t-right\">{{ totals.total - totals.audited }}</td>\n <td class=\"t-right\">{{ totalCoverage }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td class=\"t-right\">{{ totalFailedPct }}</td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <!-- User view, deepest level: the area manager's stores -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level === 'store' && tableCount\">\n <table class=\"rp-table rp-table--userstores\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('zone')\">Zone manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'zone'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Export</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of userStorePageRows; trackBy: trackByKey\">\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.zone\">{{ s.zone || '\u2014' }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportStore(s)\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td></td>\n <td></td>\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <div *ngIf=\"!loading && !tableCount\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ search ? 'No rows match \"' + search + '\"' : 'No stores match the current filters' }}</div>\n </div>\n </div>\n\n <!-- Shared pager (10 / 20 / 30), as on the other audit lists. -->\n <div class=\"rp-pager\" *ngIf=\"!loading && tableCount\">\n <lib-pagination [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\" [paginationSizes]=\"pageSizes\" [currentPage]=\"page\"\n [totalItems]=\"tableCount\" (pageChange)=\"onPageChange($event)\" (pageSizeChange)=\"onPageSizeChange($event)\"></lib-pagination>\n </div>\n </section>\n\n <!-- ============ FILTER DRAWER ============ -->\n <div class=\"filter-backdrop\" *ngIf=\"filtersOpen\" (click)=\"closeFilters()\"></div>\n\n <!-- Every control edits the drawer's draft (dr); the page behind changes only on Apply or Reset all. -->\n <div class=\"filter-drawer\" *ngIf=\"filtersOpen && draft as dr\">\n <div class=\"drawer-head\">\n <span class=\"drawer-title\">Filters</span>\n <span class=\"rp-countpill\">{{ dr.filterCount }}</span>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"closebtn\" (click)=\"closeFilters()\" title=\"Close\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </button>\n </div>\n\n <div class=\"drawer-body\">\n <div class=\"drawer-nav\">\n <!-- trackBy: filterCats is rebuilt on every check, and lib-audit-v2-select's document:mousedown runs one\n between press and release; without it the button was replaced mid-click and the click never landed. -->\n <button type=\"button\" class=\"drawer-navitem\" *ngFor=\"let c of dr.filterCats; trackBy: trackByChip\" [class.navitem-active]=\"activeCat === c.key\"\n (click)=\"selectCat(c.key)\">\n <span class=\"navtext\">\n <span class=\"navtitle\">{{ c.label }}</span>\n <span class=\"navvalue\" [class.is-dirty]=\"c.dirty\">{{ c.value }}</span>\n </span>\n <span class=\"dirtydot\" *ngIf=\"c.dirty\"></span>\n </button>\n </div>\n\n <div class=\"drawer-pane\">\n <div class=\"panetitle\">{{ dr.paneTitle }}</div>\n <div class=\"panehint\">{{ dr.paneSub }}</div>\n\n <!-- Date -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'date'\">\n <div class=\"av2-datepick\">\n <svg class=\"av2-datepick-icon\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line></svg>\n <input type=\"text\" class=\"av2-datepick-input rp-daterange\" ngxDaterangepickerMd readonly autocomplete=\"off\"\n placeholder=\"Select date range\" [(ngModel)]=\"dr.range\" [locale]=\"pickerLocale\" [maxDate]=\"today\"\n [ranges]=\"ranges\" [showCustomRangeLabel]=\"true\" [alwaysShowCalendars]=\"false\"\n [keepCalendarOpeningWithRange]=\"true\" [autoApply]=\"true\" [showCancel]=\"false\"\n [drops]=\"'down'\" [opens]=\"'right'\" (datesUpdated)=\"dr.onRangePicked($event)\">\n </div>\n <div class=\"rp-presets\">\n <button type=\"button\" class=\"rp-preset\" *ngFor=\"let p of presets\" [class.is-on]=\"dr.preset === p\"\n (click)=\"dr.setPreset(p)\">{{ p }}</button>\n </div>\n </div>\n\n <!-- View by -->\n <div class=\"pane-options\" *ngIf=\"activeCat === 'mode'\">\n <div class=\"pane-option\" [class.is-on]=\"dr.isStoreMode\" (click)=\"dr.setMode('store')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.isStoreMode\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Store</span>\n <span class=\"pane-option-help\">One row per store with score, result and last audit date.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"!dr.isStoreMode\" (click)=\"dr.setMode('user')\">\n <span class=\"pane-radio\" [class.is-on]=\"!dr.isStoreMode\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">User</span>\n <span class=\"pane-option-help\">Rolled up by circle head, zone manager and AOM, drillable down to stores.</span>\n </span>\n </div>\n </div>\n\n <!-- Stores (Store view) -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && dr.isStoreMode\">\n <label class=\"av2-search rp-pick-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search store\" [(ngModel)]=\"dr.storeQuery\">\n </label>\n <div class=\"rp-picklist\">\n <ng-container *ngIf=\"dr.storePickItems.length\">\n <label class=\"rp-pick is-all\">\n <input type=\"checkbox\" [checked]=\"dr.storePickAllChecked\" (change)=\"dr.toggleStorePickAll()\">\n <span>Select All</span>\n </label>\n <label class=\"rp-pick\" *ngFor=\"let it of dr.storePickItems; trackBy: trackByPick\">\n <input type=\"checkbox\" [checked]=\"it.checked\" (change)=\"dr.toggleStorePick(it.store)\">\n <span class=\"rp-pick-label\">{{ it.store.name }}</span>\n <span class=\"rp-pick-sub\">{{ it.store.cluster || it.store.aom }}</span>\n </label>\n </ng-container>\n <div class=\"rp-pick-empty\" *ngIf=\"!dr.storePickItems.length\">\n {{ dr.storeQuery ? 'No stores match \"' + dr.storeQuery + '\"' : 'No stores in scope' }}\n </div>\n </div>\n <div class=\"rp-reading\">\n <span>Reading</span>\n <strong>{{ dr.storePickReading }}</strong>\n <span class=\"av2-grow\"></span>\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.resetStorePick()\">Reset to all stores</button>\n </div>\n </div>\n\n <!-- Store hierarchy (User view) -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && !dr.isStoreMode\">\n <div class=\"rp-field\">\n <div class=\"rp-field-label\">Circle Head <span>{{ dr.circleOptions.length - 1 }} users</span></div>\n <lib-audit-v2-select [value]=\"dr.circleKey\" [options]=\"dr.circleOptions\" placeholder=\"All circles\"\n ariaLabel=\"Circle Head\" (changed)=\"dr.pickCircle($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.showZonePick\">\n <div class=\"rp-field-label\">Zone Manager <span>{{ dr.zoneOptions.length - 1 }} {{ dr.zoneOptions.length === 2 ? 'user' : 'users' }}</span></div>\n <lib-audit-v2-select [value]=\"dr.zoneKey\" [options]=\"dr.zoneOptions\" placeholder=\"All zones\"\n ariaLabel=\"Zone Manager\" (changed)=\"dr.pickZone($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.zoneKey\">\n <div class=\"rp-field-label\">AOM <span>{{ dr.aomOptions.length - 1 }} {{ dr.aomOptions.length === 2 ? 'user' : 'users' }}</span></div>\n <lib-audit-v2-select [value]=\"dr.aomKey\" [options]=\"dr.aomOptions\" placeholder=\"All AOMs\"\n ariaLabel=\"AOM\" (changed)=\"dr.pickAom($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.aomKey\">\n <div class=\"rp-field-label\">Store <span>{{ dr.storeOptions.length - 1 }} stores</span></div>\n <lib-audit-v2-select [value]=\"dr.storeKey\" [options]=\"dr.storeOptions\" placeholder=\"All stores\"\n ariaLabel=\"Store\" (changed)=\"dr.pickStore($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-reading\">\n <span>Reading</span>\n <strong>{{ dr.hierarchyReading }}</strong>\n <span class=\"av2-grow\"></span>\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.goToLevel('circle')\">Reset to all circles</button>\n </div>\n </div>\n\n <!-- Result (Store view) -->\n <div class=\"pane-options\" *ngIf=\"activeCat === 'result' && dr.isStoreMode\">\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'all'\" (click)=\"dr.setResult('all')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'all'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">All</span>\n <span class=\"pane-option-help\">Every store in scope, audited or not.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'pass'\" (click)=\"dr.setResult('pass')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'pass'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Pass</span>\n <span class=\"pane-option-help\">Only stores scoring at or above the {{ passMark }}% pass mark.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'fail'\" (click)=\"dr.setResult('fail')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'fail'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Fail</span>\n <span class=\"pane-option-help\">Only stores scoring below the {{ passMark }}% pass mark.</span>\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"drawer-foot\">\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"resetFilters()\">Reset all</button>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--wide\" (click)=\"applyFilters()\">Apply</button>\n </div>\n </div>\n\n</div>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}.rp-pager{padding-top:20px}.rp-head{display:flex;flex-direction:column;gap:2px}.rp-crumb{font-size:13px;line-height:20px;color:#667085}.rp-crumb-current{color:#00a3ff}.rp-title{font-size:22px;line-height:30px;font-weight:600;color:#101828}.rp-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-countpill{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:9999px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:600}.rp-chip{height:32px;max-width:360px;padding:0 12px;border:none;border-radius:9999px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-size:13px;line-height:20px;white-space:nowrap;cursor:pointer}.rp-chip:hover{background:#f9fafb}.rp-chip-key{font-weight:500;color:#667085}.rp-chip-value{overflow:hidden;text-overflow:ellipsis;font-weight:600;color:#101828}.av2-datepick{position:relative;display:inline-flex;align-items:center}.av2-datepick-icon{position:absolute;left:10px;color:#667085;pointer-events:none}.av2-datepick-input{height:36px;padding:0 10px 0 32px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;background:#fff;font-family:inherit;font-size:13px;font-weight:500;color:#101828;cursor:pointer;outline:none}.av2-datepick-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}:host ::ng-deep .av2-datepick .md-drppicker{margin-top:4px;z-index:1060;font-family:inherit;border-radius:8px;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,inset 0 0 0 1px #eaecf0}:host ::ng-deep .av2-datepick .md-drppicker.double,:host ::ng-deep .av2-datepick .md-drppicker.show-ranges{width:max-content}:host ::ng-deep .av2-datepick .md-drppicker.ltr .ranges{float:left;margin-top:10px}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button{width:160px;padding:12px 16px;border:none;border-radius:8px;background:none;color:#344054;font-size:14px;font-weight:400;line-height:20px;text-align:left;cursor:pointer}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button.active{background:#eaf8ff;color:#00a3ff;font-weight:500}:host ::ng-deep .av2-datepick .md-drppicker th,:host ::ng-deep .av2-datepick .md-drppicker td{width:40px!important;height:40px!important;min-width:32px;padding:0!important;border:1px solid transparent!important;background:transparent!important;font-size:14px!important;font-weight:400!important;line-height:38px}:host ::ng-deep .av2-datepick .md-drppicker th{color:#344054!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker th.month{width:auto!important;font-size:16px!important}:host ::ng-deep .av2-datepick .md-drppicker td{color:#344054!important}:host ::ng-deep .av2-datepick .md-drppicker th.available.prev,:host ::ng-deep .av2-datepick .md-drppicker th.available.next{background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 6 9 12 15 18'/%3E%3C/svg%3E\") center/18px no-repeat!important}:host ::ng-deep .av2-datepick .md-drppicker th.available:hover,:host ::ng-deep .av2-datepick .md-drppicker td.available:hover{background-color:#f2f4f7!important}:host ::ng-deep .av2-datepick .md-drppicker td.in-range{background-color:#eaf8ff!important;color:#101828!important}:host ::ng-deep .av2-datepick .md-drppicker td.active,:host ::ng-deep .av2-datepick .md-drppicker td.active:hover{background-color:#029cf4!important;border-radius:20px;color:#fff!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker td.off,:host ::ng-deep .av2-datepick .md-drppicker td.off.in-range{color:#98a2b3!important;background-color:transparent!important}:host ::ng-deep .av2-datepick .md-drppicker td.disabled{color:#98a2b3!important;background-color:transparent!important;text-decoration:line-through;pointer-events:none}:host ::ng-deep .av2-datepick--compact .md-drppicker th,:host ::ng-deep .av2-datepick--compact .md-drppicker td{width:32px!important;height:32px!important;font-size:12px!important;line-height:30px}:host ::ng-deep .av2-datepick--compact .md-drppicker th.month{font-size:14px!important}.rp-daterange{width:260px;height:44px;font-size:14px}.rp-presets{display:flex;flex-wrap:wrap;gap:8px}.rp-preset{height:36px;padding:0 14px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;font-family:inherit;font-size:14px;font-weight:500;color:#667085;cursor:pointer}.rp-preset.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #99dbff;color:#101828;font-weight:600}.rp-drillbar{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:14px 18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.rp-drillcrumb{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:#00a3ff;cursor:pointer}.rp-drillcrumb.is-current{color:#101828;cursor:default}.rp-drillsep{color:#98a2b3;font-weight:400}.rp-hint{font-size:14px;color:#667085}.rp-scope{display:flex;flex-direction:column;gap:2px}.rp-scope-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-scope-meta{font-size:14px;line-height:20px;color:#667085}.rp-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:16px}.rp-kpi-value.is-good{color:#027a48}.rp-kpi-value.is-bad{color:#d92d20}.rp-sk-value{height:32px;margin:3px 0}.rp-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:18px 20px 12px;display:flex;flex-direction:column;gap:14px}.rp-card-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-card-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:200px}.rp-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-card-meta{font-size:14px;line-height:20px;color:#667085}.rp-search{width:260px}.rp-table{width:100%;border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed}.rp-table th:nth-child(1){width:29%}.rp-table th:nth-child(2){width:9.5%}.rp-table th:nth-child(3){width:8.5%}.rp-table th:nth-child(4){width:9.5%}.rp-table th:nth-child(5){width:9.5%}.rp-table th:nth-child(6){width:12%}.rp-table th:nth-child(7){width:11%}.rp-table th:nth-child(8){width:11%}.rp-table--stores th:nth-child(1){width:14%}.rp-table--stores th:nth-child(2){width:20%}.rp-table--stores th:nth-child(3){width:16%}.rp-table--stores th:nth-child(4){width:9%}.rp-table--stores th:nth-child(5){width:9%}.rp-table--stores th:nth-child(6){width:11%}.rp-table--stores th:nth-child(7){width:12%}.rp-table--stores th:nth-child(8){width:9%}.rp-table--userstores th:nth-child(1){width:18%}.rp-table--userstores th:nth-child(2){width:25%}.rp-table--userstores th:nth-child(3){width:25%}.rp-table--userstores th:nth-child(4){width:11%}.rp-table--userstores th:nth-child(5){width:10%}.rp-table--userstores th:nth-child(6){width:11%}.rp-table thead th{padding:8px 4px;border:0;border-bottom:1px solid #EAECF0;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;white-space:nowrap}.rp-table tbody td{padding:12px 4px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;color:#344054;vertical-align:middle}.rp-table tfoot td{padding:12px 4px;border:0;font-size:14px;line-height:20px;font-weight:700;color:#101828}.rp-table thead th.t-right,.rp-table tbody td.t-right,.rp-table tfoot td.t-right{text-align:right}.rp-table .is-strong{font-weight:600}.rp-table tbody td.is-muted{color:#98a2b3}.rp-table tbody td.is-pass{color:#027a48}.rp-table tbody td.is-fail{color:#d92d20}.rp-table tbody td.rp-cell-name{color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-result{display:inline-flex;padding:2px 10px;border-radius:9999px;background:#f2f4f7;font-size:12px;line-height:18px;font-weight:500;color:#475467;white-space:nowrap}.rp-result.is-pass{background:#ecfdf3;color:#027a48}.rp-result.is-fail{background:#fef3f2;color:#b42318}.rp-row{cursor:pointer}.rp-row:hover td{background:#fcfcfd}.rp-name{display:flex;flex-direction:column;gap:2px;min-width:0}.rp-name-main{font-weight:600;color:#00a3ff}.rp-name-sub{font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-export{height:32px;padding:0 12px;border:none;border-radius:6px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.rp-export:hover{background:#f9fafb}.filter-backdrop{position:fixed;inset:0;background:#10182873;z-index:1050}.filter-drawer{position:fixed;top:0;right:0;bottom:0;width:860px;max-width:96vw;display:flex;flex-direction:column;background:#fff;box-shadow:-10px 0 30px #1018282e;z-index:1051;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.drawer-head{display:flex;align-items:center;gap:10px;padding:18px 20px;box-shadow:inset 0 -1px #eaecf0}.drawer-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.closebtn{width:32px;height:32px;border:none;border-radius:8px;background:transparent;color:#667085;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.closebtn:hover{background:#f2f4f7;color:#344054}.drawer-body{display:flex;flex:1;min-height:0}.drawer-nav{flex:0 0 280px;max-width:280px;background:#f9fafb;box-shadow:inset -1px 0 #eaecf0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:4px}.drawer-navitem{display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border:none;border-radius:8px;background:transparent;text-align:left;font-family:inherit;cursor:pointer}.drawer-navitem:hover{background:#fff}.drawer-navitem.navitem-active{background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d}.navtext{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.navtitle{font-size:14px;line-height:20px;font-weight:600;color:#101828}.navvalue{font-size:14px;line-height:20px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.navvalue.is-dirty{color:#009bf3}.dirtydot{width:8px;height:8px;border-radius:9999px;background:#00a3ff;flex-shrink:0;display:block}.drawer-pane{flex:1;min-width:0;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:6px}.panetitle{font-size:18px;line-height:28px;font-weight:600;color:#101828}.panehint{font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.pane-stack{display:flex;flex-direction:column;gap:14px;margin-top:14px;max-width:560px}.pane-options{display:flex;flex-direction:column;gap:10px;margin-top:14px;max-width:560px}.pane-option{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:8px;cursor:pointer;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0}.pane-option.is-on{background:#f5fbff;box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio{width:18px;height:18px;flex-shrink:0;margin-top:2px;border-radius:9999px;display:flex;align-items:center;justify-content:center;box-shadow:inset 0 0 0 1px #d0d5dd}.pane-radio>span{width:8px;height:8px;border-radius:9999px;background:transparent;display:block}.pane-radio.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio.is-on>span{background:#00a3ff}.pane-option-text{display:flex;flex-direction:column;gap:2px}.pane-option-label{font-size:14px;line-height:20px;font-weight:600;color:#101828}.pane-option-help{font-size:14px;line-height:20px;color:#667085}.drawer-foot{display:flex;align-items:center;gap:10px;padding:14px 20px;box-shadow:inset 0 1px #eaecf0}.rp-reset{border:none;background:transparent;padding:0;font-family:inherit;font-weight:600;text-decoration:none;white-space:nowrap}.rp-pick-search{width:100%}.rp-picklist{max-height:320px;overflow-y:auto;padding:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column}.rp-pick{display:flex;align-items:center;gap:12px;min-height:40px;margin:0;padding:0 10px;border-radius:6px;font-size:14px;color:#344054;cursor:pointer}.rp-pick:hover{background:#f9fafb}.rp-pick.is-all{font-weight:600}.rp-pick input{appearance:none;-webkit-appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid #D0D5DD;border-radius:4px;background:#fff no-repeat center/12px 12px;cursor:pointer;vertical-align:middle;transition:border-color .12s ease,background-color .12s ease}.rp-pick input:hover:not(:disabled){border-color:#00a3ff}.rp-pick input:checked{border-color:#00a3ff;background-color:#eaf8ff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300A3FF' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E\")}.rp-pick input:focus-visible{outline:none;box-shadow:0 0 0 3px #eaf8ff}.rp-pick input:disabled{cursor:not-allowed;opacity:.45}.rp-pick-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-sub{max-width:45%;font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-empty{padding:20px 10px;font-size:14px;color:#667085}.rp-reading{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:8px;background:#f9fafb;font-size:14px;color:#475467}.rp-reading strong{font-weight:600;color:#101828}.rp-field{display:flex;flex-direction:column;gap:6px;min-width:0}.rp-field-label{display:flex;align-items:baseline;gap:8px;font-size:14px;line-height:20px;font-weight:600;color:#1d2939}.rp-field-label span{font-weight:400;color:#667085}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.PaginationComponent, selector: "lib-pagination", inputs: ["collection", "itemsPerPage", "currentPage", "totalItems", "directionLinks", "pageSize", "paginationSizes"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i8.DaterangepickerDirective, selector: "input[ngxDaterangepickerMd]", inputs: ["minDate", "maxDate", "autoApply", "alwaysShowCalendars", "showCustomRangeLabel", "linkedCalendars", "dateLimit", "singleDatePicker", "showWeekNumbers", "showISOWeekNumbers", "showDropdowns", "isInvalidDate", "isCustomDate", "isTooltipDate", "showClearButton", "customRangeDirection", "ranges", "opens", "drops", "firstMonthDayClass", "lastMonthDayClass", "emptyWeekRowClass", "emptyWeekColumnClass", "firstDayOfNextMonthClass", "lastDayOfPreviousMonthClass", "keepCalendarOpeningWithRange", "showRangeLabelOnInput", "showCancel", "lockStartDate", "timePicker", "timePicker24Hour", "timePickerIncrement", "timePickerSeconds", "closeOnAutoApply", "endKeyHolder", "startKey", "locale", "endKey"], outputs: ["change", "rangeClicked", "datesUpdated", "startDateChanged", "endDateChanged", "clearClicked"] }, { kind: "directive", type: AuditV2TipDirective, selector: "[av2Tip]", inputs: ["av2Tip"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SelectComponent, selector: "lib-audit-v2-select", inputs: ["options", "placeholder", "searchable", "ariaLabel", "disabled", "value"], outputs: ["changed"] }, { kind: "component", type: AuditV2SortIconComponent, selector: "lib-audit-v2-sort-icon", inputs: ["active", "dir"] }] });
|
|
9099
9166
|
}
|
|
9100
9167
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ReportsComponent, decorators: [{
|
|
9101
9168
|
type: Component,
|
|
9102
|
-
args: [{ selector: 'lib-audit-v2-reports', template: "<div class=\"av2-page audit-reports\">\r\n\r\n <!-- Breadcrumb + title -->\r\n <div class=\"rp-head\">\r\n <div class=\"rp-crumb\">Audits \u203A <span class=\"rp-crumb-current\">Reports</span></div>\r\n <div class=\"rp-title\">Store audit report</div>\r\n </div>\r\n\r\n <!-- Filter chips, Filter button at the right end (QA 9 Oct); Export moved to the table head beside its search. -->\r\n <div class=\"rp-controls\">\r\n <button type=\"button\" class=\"rp-chip\" *ngFor=\"let c of chips; trackBy: trackByChip\" (click)=\"openFilters(c.key)\"\r\n [title]=\"c.label + ': ' + c.value\">\r\n <span class=\"rp-chip-key\">{{ c.label }}</span><span class=\"rp-chip-value\">{{ c.value }}</span>\r\n </button>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost rp-filterbtn\" (click)=\"openFilters()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"></polygon></svg>\r\n Filter\r\n <span class=\"rp-countpill\">{{ filterCount }}</span>\r\n </button>\r\n </div>\r\n\r\n <!-- User view: where in the hierarchy -->\r\n <div class=\"rp-drillbar\" *ngIf=\"!isStoreMode\">\r\n <ng-container *ngFor=\"let c of crumbs; let last = last; let first = first\">\r\n <div class=\"rp-drillcrumb\" [class.is-current]=\"last\" (click)=\"goToLevel(c.level)\">\r\n <span class=\"rp-drillsep\" *ngIf=\"!first\">\u203A</span>{{ c.label }}\r\n </div>\r\n </ng-container>\r\n <div class=\"av2-grow\"></div>\r\n <div class=\"rp-hint\">{{ hint }}</div>\r\n </div>\r\n\r\n <!-- Scope -->\r\n <div class=\"rp-scope\">\r\n <div class=\"rp-scope-title\">{{ scopeTitle }}</div>\r\n <div class=\"rp-scope-meta\">{{ scopeMeta }}</div>\r\n </div>\r\n\r\n <!-- KPIs -->\r\n <div class=\"rp-kpis\">\r\n <!-- Old Checklist summary card: figure + label in the gradient strip, note below. -->\r\n <div class=\"av2-ocard\" *ngFor=\"let kpi of kpis\">\r\n <div class=\"av2-ocard-head\">\r\n <div class=\"av2-ocard-count rp-kpi-value\" [class.is-good]=\"kpi.tone === 'good'\" [class.is-bad]=\"kpi.tone === 'bad'\">\r\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--value rp-sk-value\"></span>\r\n <ng-container *ngIf=\"!loading\">{{ kpi.value }}</ng-container>\r\n </div>\r\n <div class=\"av2-ocard-text\">{{ kpi.label }}</div>\r\n </div>\r\n <div class=\"av2-ocard-body\">\r\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--note\"></span>\r\n <div *ngIf=\"!loading\" class=\"av2-ocard-note\">{{ kpi.note }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Report table -->\r\n <section class=\"rp-card\">\r\n <div class=\"rp-card-head\">\r\n <div class=\"rp-card-text\">\r\n <ng-container *ngIf=\"isStoreMode\">\r\n <div class=\"rp-card-title\">Store report</div>\r\n <div class=\"rp-card-meta\">{{ storeRows.length }} {{ storeRows.length === 1 ? 'store' : 'stores' }} \u00B7 audits submitted in the period</div>\r\n </ng-container>\r\n <ng-container *ngIf=\"!isStoreMode\">\r\n <div class=\"rp-card-title\">{{ tableTitle }}</div>\r\n <div class=\"rp-card-meta\">{{ tableMeta }}</div>\r\n </ng-container>\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <label class=\"av2-search rp-search\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"7\"></circle>\r\n <line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line>\r\n </svg>\r\n <input type=\"text\" [placeholder]=\"isStoreMode ? 'Search store' : 'Search ' + levelLabel.toLowerCase()\"\r\n [(ngModel)]=\"search\" (ngModelChange)=\"onSearchChange()\">\r\n </label>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost\" [disabled]=\"loading\" (click)=\"exportAll()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 16V4\"></path><polyline points=\"7 9 12 4 17 9\"></polyline><path d=\"M4 16v4h16v-4\"></path></svg>\r\n Export\r\n </button>\r\n </div>\r\n\r\n <lib-audit-v2-shimmer *ngIf=\"loading\"></lib-audit-v2-shimmer>\r\n\r\n <!-- Store view: one row per store -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && isStoreMode && tableCount\">\r\n <table class=\"rp-table rp-table--stores\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('cluster')\">Cluster <lib-audit-v2-sort-icon [active]=\"sortKey === 'cluster'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('status')\">Result <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('lastAudit')\">Last audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'lastAudit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Export</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let s of storePageRows; trackBy: trackByKey\">\r\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.cluster\">{{ s.cluster || '\u2014' }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\r\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\r\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\r\n <td class=\"t-right\">\r\n <span class=\"rp-result\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\">{{ resultText(s) }}</span>\r\n </td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.lastAudit\">{{ s.lastAudit || 'No audit' }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportStore(s)\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td></td>\r\n <td></td>\r\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td class=\"t-right\">{{ totals.failed }} fail</td>\r\n <td></td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <!-- User view: circle head / zone manager / area manager roll-up -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level !== 'store' && tableCount\">\r\n <table class=\"rp-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">{{ levelLabel }} <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('total')\">Total stores <lib-audit-v2-sort-icon [active]=\"sortKey === 'total'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('notAudited')\">Not audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'notAudited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('coverage')\">Coverage <lib-audit-v2-sort-icon [active]=\"sortKey === 'coverage'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('avgScore')\">Avg audit score <lib-audit-v2-sort-icon [active]=\"sortKey === 'avgScore'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('failedPct')\">Failed store % <lib-audit-v2-sort-icon [active]=\"sortKey === 'failedPct'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Report</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of pageRows; trackBy: trackByRow\" class=\"rp-row\" (click)=\"openRow(row)\">\r\n <td>\r\n <div class=\"rp-name\">\r\n <span class=\"rp-name-main\">{{ row.name }}</span>\r\n <span class=\"rp-name-sub\" *ngIf=\"row.email\">{{ row.email }}</span>\r\n </div>\r\n </td>\r\n <td class=\"t-right\">{{ row.total }}</td>\r\n <td class=\"t-right\">{{ row.audited }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!row.notAudited\">{{ row.notAudited }}</td>\r\n <td class=\"t-right\">{{ row.coverage }}</td>\r\n <td class=\"t-right is-strong\">{{ row.avgScore }}</td>\r\n <td class=\"t-right is-strong\" [class.is-fail]=\"isHighFail(row)\">{{ row.failedPct }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportRow(row); $event.stopPropagation()\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td class=\"t-right\">{{ totals.total }}</td>\r\n <td class=\"t-right\">{{ totals.audited }}</td>\r\n <td class=\"t-right\">{{ totals.total - totals.audited }}</td>\r\n <td class=\"t-right\">{{ totalCoverage }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td class=\"t-right\">{{ totalFailedPct }}</td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <!-- User view, deepest level: the area manager's stores -->\r\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level === 'store' && tableCount\">\r\n <table class=\"rp-table rp-table--userstores\">\r\n <thead>\r\n <tr>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"av2-sortable\" (click)=\"sortBy('zone')\">Zone manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'zone'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\r\n <th class=\"t-right\">Export</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let s of userStorePageRows; trackBy: trackByKey\">\r\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\r\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.zone\">{{ s.zone || '\u2014' }}</td>\r\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\r\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\r\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\r\n <td class=\"t-right\">\r\n <button type=\"button\" class=\"rp-export\" (click)=\"exportStore(s)\">Export</button>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot>\r\n <tr class=\"rp-total\">\r\n <td>Total</td>\r\n <td></td>\r\n <td></td>\r\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\r\n <td class=\"t-right\">{{ totalAverage }}</td>\r\n <td></td>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n </div>\r\n\r\n <div *ngIf=\"!loading && !tableCount\" class=\"av2-empty\">\r\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\r\n <div class=\"av2-empty-text\">\r\n <div class=\"av2-empty-title\">No data found</div>\r\n <div class=\"av2-empty-sub\">{{ search ? 'No rows match \"' + search + '\"' : 'No stores match the current filters' }}</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Shared pager (10 / 20 / 30), as on the other audit lists. -->\r\n <div class=\"rp-pager\" *ngIf=\"!loading && tableCount\">\r\n <lib-pagination [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\" [paginationSizes]=\"pageSizes\" [currentPage]=\"page\"\r\n [totalItems]=\"tableCount\" (pageChange)=\"onPageChange($event)\" (pageSizeChange)=\"onPageSizeChange($event)\"></lib-pagination>\r\n </div>\r\n </section>\r\n\r\n <!-- ============ FILTER DRAWER ============ -->\r\n <div class=\"filter-backdrop\" *ngIf=\"filtersOpen\" (click)=\"closeFilters()\"></div>\r\n\r\n <!-- Every control edits the drawer's draft (dr); the page behind changes only on Apply or Reset all. -->\r\n <div class=\"filter-drawer\" *ngIf=\"filtersOpen && draft as dr\">\r\n <div class=\"drawer-head\">\r\n <span class=\"drawer-title\">Filters</span>\r\n <span class=\"rp-countpill\">{{ dr.filterCount }}</span>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"closebtn\" (click)=\"closeFilters()\" title=\"Close\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"drawer-body\">\r\n <div class=\"drawer-nav\">\r\n <!-- trackBy: filterCats is rebuilt on every check, and lib-audit-v2-select's document:mousedown runs one\r\n between press and release; without it the button was replaced mid-click and the click never landed. -->\r\n <button type=\"button\" class=\"drawer-navitem\" *ngFor=\"let c of dr.filterCats; trackBy: trackByChip\" [class.navitem-active]=\"activeCat === c.key\"\r\n (click)=\"selectCat(c.key)\">\r\n <span class=\"navtext\">\r\n <span class=\"navtitle\">{{ c.label }}</span>\r\n <span class=\"navvalue\" [class.is-dirty]=\"c.dirty\">{{ c.value }}</span>\r\n </span>\r\n <span class=\"dirtydot\" *ngIf=\"c.dirty\"></span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"drawer-pane\">\r\n <div class=\"panetitle\">{{ dr.paneTitle }}</div>\r\n <div class=\"panehint\">{{ dr.paneSub }}</div>\r\n\r\n <!-- Date -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'date'\">\r\n <div class=\"av2-datepick\">\r\n <svg class=\"av2-datepick-icon\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\r\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line></svg>\r\n <input type=\"text\" class=\"av2-datepick-input rp-daterange\" ngxDaterangepickerMd readonly autocomplete=\"off\"\r\n placeholder=\"Select date range\" [(ngModel)]=\"dr.range\" [locale]=\"pickerLocale\" [maxDate]=\"today\"\r\n [ranges]=\"ranges\" [showCustomRangeLabel]=\"true\" [alwaysShowCalendars]=\"false\"\r\n [keepCalendarOpeningWithRange]=\"true\" [autoApply]=\"true\" [showCancel]=\"false\"\r\n [drops]=\"'down'\" [opens]=\"'right'\" (datesUpdated)=\"dr.onRangePicked($event)\">\r\n </div>\r\n <div class=\"rp-presets\">\r\n <button type=\"button\" class=\"rp-preset\" *ngFor=\"let p of presets\" [class.is-on]=\"dr.preset === p\"\r\n (click)=\"dr.setPreset(p)\">{{ p }}</button>\r\n </div>\r\n </div>\r\n\r\n <!-- View by -->\r\n <div class=\"pane-options\" *ngIf=\"activeCat === 'mode'\">\r\n <div class=\"pane-option\" [class.is-on]=\"dr.isStoreMode\" (click)=\"dr.setMode('store')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.isStoreMode\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Store</span>\r\n <span class=\"pane-option-help\">One row per store with score, result and last audit date.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"!dr.isStoreMode\" (click)=\"dr.setMode('user')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"!dr.isStoreMode\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">User</span>\r\n <span class=\"pane-option-help\">Rolled up by circle head, zone manager and AOM, drillable down to stores.</span>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Stores (Store view) -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && dr.isStoreMode\">\r\n <label class=\"av2-search rp-pick-search\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\r\n <input type=\"text\" placeholder=\"Search store\" [(ngModel)]=\"dr.storeQuery\">\r\n </label>\r\n <div class=\"rp-picklist\">\r\n <ng-container *ngIf=\"dr.storePickItems.length\">\r\n <label class=\"rp-pick is-all\">\r\n <input type=\"checkbox\" [checked]=\"dr.storePickAllChecked\" (change)=\"dr.toggleStorePickAll()\">\r\n <span>Select All</span>\r\n </label>\r\n <label class=\"rp-pick\" *ngFor=\"let it of dr.storePickItems; trackBy: trackByPick\">\r\n <input type=\"checkbox\" [checked]=\"it.checked\" (change)=\"dr.toggleStorePick(it.store)\">\r\n <span class=\"rp-pick-label\">{{ it.store.name }}</span>\r\n <span class=\"rp-pick-sub\">{{ it.store.cluster || it.store.aom }}</span>\r\n </label>\r\n </ng-container>\r\n <div class=\"rp-pick-empty\" *ngIf=\"!dr.storePickItems.length\">\r\n {{ dr.storeQuery ? 'No stores match \"' + dr.storeQuery + '\"' : 'No stores in scope' }}\r\n </div>\r\n </div>\r\n <div class=\"rp-reading\">\r\n <span>Reading</span>\r\n <strong>{{ dr.storePickReading }}</strong>\r\n <span class=\"av2-grow\"></span>\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.resetStorePick()\">Reset to all stores</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Store hierarchy (User view) -->\r\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && !dr.isStoreMode\">\r\n <div class=\"rp-field\">\r\n <div class=\"rp-field-label\">Circle Head <span>{{ dr.circleOptions.length - 1 }} users</span></div>\r\n <lib-audit-v2-select [value]=\"dr.circleKey\" [options]=\"dr.circleOptions\" placeholder=\"All circles\"\r\n ariaLabel=\"Circle Head\" (changed)=\"dr.pickCircle($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.showZonePick\">\r\n <div class=\"rp-field-label\">Zone Manager <span>{{ dr.zoneOptions.length - 1 }} {{ dr.zoneOptions.length === 2 ? 'user' : 'users' }}</span></div>\r\n <lib-audit-v2-select [value]=\"dr.zoneKey\" [options]=\"dr.zoneOptions\" placeholder=\"All zones\"\r\n ariaLabel=\"Zone Manager\" (changed)=\"dr.pickZone($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.zoneKey\">\r\n <div class=\"rp-field-label\">AOM <span>{{ dr.aomOptions.length - 1 }} {{ dr.aomOptions.length === 2 ? 'user' : 'users' }}</span></div>\r\n <lib-audit-v2-select [value]=\"dr.aomKey\" [options]=\"dr.aomOptions\" placeholder=\"All AOMs\"\r\n ariaLabel=\"AOM\" (changed)=\"dr.pickAom($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-field\" *ngIf=\"dr.aomKey\">\r\n <div class=\"rp-field-label\">Store <span>{{ dr.storeOptions.length - 1 }} stores</span></div>\r\n <lib-audit-v2-select [value]=\"dr.storeKey\" [options]=\"dr.storeOptions\" placeholder=\"All stores\"\r\n ariaLabel=\"Store\" (changed)=\"dr.pickStore($event.target.value)\"></lib-audit-v2-select>\r\n </div>\r\n <div class=\"rp-reading\">\r\n <span>Reading</span>\r\n <strong>{{ dr.hierarchyReading }}</strong>\r\n <span class=\"av2-grow\"></span>\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.goToLevel('circle')\">Reset to all circles</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Result (Store view) -->\r\n <div class=\"pane-options\" *ngIf=\"activeCat === 'result' && dr.isStoreMode\">\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'all'\" (click)=\"dr.setResult('all')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'all'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">All</span>\r\n <span class=\"pane-option-help\">Every store in scope, audited or not.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'pass'\" (click)=\"dr.setResult('pass')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'pass'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Pass</span>\r\n <span class=\"pane-option-help\">Only stores scoring at or above the {{ passMark }}% pass mark.</span>\r\n </span>\r\n </div>\r\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'fail'\" (click)=\"dr.setResult('fail')\">\r\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'fail'\"><span></span></span>\r\n <span class=\"pane-option-text\">\r\n <span class=\"pane-option-label\">Fail</span>\r\n <span class=\"pane-option-help\">Only stores scoring below the {{ passMark }}% pass mark.</span>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"drawer-foot\">\r\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"resetFilters()\">Reset all</button>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--wide\" (click)=\"applyFilters()\">Apply</button>\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}.rp-pager{padding-top:20px}.rp-head{display:flex;flex-direction:column;gap:2px}.rp-crumb{font-size:13px;line-height:20px;color:#667085}.rp-crumb-current{color:#00a3ff}.rp-title{font-size:22px;line-height:30px;font-weight:600;color:#101828}.rp-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-countpill{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:9999px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:600}.rp-chip{height:32px;max-width:360px;padding:0 12px;border:none;border-radius:9999px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-size:13px;line-height:20px;white-space:nowrap;cursor:pointer}.rp-chip:hover{background:#f9fafb}.rp-chip-key{font-weight:500;color:#667085}.rp-chip-value{overflow:hidden;text-overflow:ellipsis;font-weight:600;color:#101828}.av2-datepick{position:relative;display:inline-flex;align-items:center}.av2-datepick-icon{position:absolute;left:10px;color:#667085;pointer-events:none}.av2-datepick-input{height:36px;padding:0 10px 0 32px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;background:#fff;font-family:inherit;font-size:13px;font-weight:500;color:#101828;cursor:pointer;outline:none}.av2-datepick-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}:host ::ng-deep .av2-datepick .md-drppicker{margin-top:4px;z-index:1060;font-family:inherit;border-radius:8px;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,inset 0 0 0 1px #eaecf0}:host ::ng-deep .av2-datepick .md-drppicker.double,:host ::ng-deep .av2-datepick .md-drppicker.show-ranges{width:max-content}:host ::ng-deep .av2-datepick .md-drppicker.ltr .ranges{float:left;margin-top:10px}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button{width:160px;padding:12px 16px;border:none;border-radius:8px;background:none;color:#344054;font-size:14px;font-weight:400;line-height:20px;text-align:left;cursor:pointer}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button.active{background:#eaf8ff;color:#00a3ff;font-weight:500}:host ::ng-deep .av2-datepick .md-drppicker th,:host ::ng-deep .av2-datepick .md-drppicker td{width:40px!important;height:40px!important;min-width:32px;padding:0!important;border:1px solid transparent!important;background:transparent!important;font-size:14px!important;font-weight:400!important;line-height:38px}:host ::ng-deep .av2-datepick .md-drppicker th{color:#344054!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker th.month{width:auto!important;font-size:16px!important}:host ::ng-deep .av2-datepick .md-drppicker td{color:#344054!important}:host ::ng-deep .av2-datepick .md-drppicker th.available.prev,:host ::ng-deep .av2-datepick .md-drppicker th.available.next{background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 6 9 12 15 18'/%3E%3C/svg%3E\") center/18px no-repeat!important}:host ::ng-deep .av2-datepick .md-drppicker th.available:hover,:host ::ng-deep .av2-datepick .md-drppicker td.available:hover{background-color:#f2f4f7!important}:host ::ng-deep .av2-datepick .md-drppicker td.in-range{background-color:#eaf8ff!important;color:#101828!important}:host ::ng-deep .av2-datepick .md-drppicker td.active,:host ::ng-deep .av2-datepick .md-drppicker td.active:hover{background-color:#029cf4!important;border-radius:20px;color:#fff!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker td.off,:host ::ng-deep .av2-datepick .md-drppicker td.off.in-range{color:#98a2b3!important;background-color:transparent!important}:host ::ng-deep .av2-datepick .md-drppicker td.disabled{color:#98a2b3!important;background-color:transparent!important;text-decoration:line-through;pointer-events:none}:host ::ng-deep .av2-datepick--compact .md-drppicker th,:host ::ng-deep .av2-datepick--compact .md-drppicker td{width:32px!important;height:32px!important;font-size:12px!important;line-height:30px}:host ::ng-deep .av2-datepick--compact .md-drppicker th.month{font-size:14px!important}.rp-daterange{width:260px;height:44px;font-size:14px}.rp-presets{display:flex;flex-wrap:wrap;gap:8px}.rp-preset{height:36px;padding:0 14px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;font-family:inherit;font-size:14px;font-weight:500;color:#667085;cursor:pointer}.rp-preset.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #99dbff;color:#101828;font-weight:600}.rp-drillbar{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:14px 18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.rp-drillcrumb{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:#00a3ff;cursor:pointer}.rp-drillcrumb.is-current{color:#101828;cursor:default}.rp-drillsep{color:#98a2b3;font-weight:400}.rp-hint{font-size:14px;color:#667085}.rp-scope{display:flex;flex-direction:column;gap:2px}.rp-scope-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-scope-meta{font-size:14px;line-height:20px;color:#667085}.rp-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:16px}.rp-kpi-value.is-good{color:#027a48}.rp-kpi-value.is-bad{color:#d92d20}.rp-sk-value{height:32px;margin:3px 0}.rp-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:18px 20px 12px;display:flex;flex-direction:column;gap:14px}.rp-card-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-card-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:200px}.rp-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-card-meta{font-size:14px;line-height:20px;color:#667085}.rp-search{width:260px}.rp-table{width:100%;border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed}.rp-table th:nth-child(1){width:29%}.rp-table th:nth-child(2){width:9.5%}.rp-table th:nth-child(3){width:8.5%}.rp-table th:nth-child(4){width:9.5%}.rp-table th:nth-child(5){width:9.5%}.rp-table th:nth-child(6){width:12%}.rp-table th:nth-child(7){width:11%}.rp-table th:nth-child(8){width:11%}.rp-table--stores th:nth-child(1){width:14%}.rp-table--stores th:nth-child(2){width:20%}.rp-table--stores th:nth-child(3){width:16%}.rp-table--stores th:nth-child(4){width:9%}.rp-table--stores th:nth-child(5){width:9%}.rp-table--stores th:nth-child(6){width:11%}.rp-table--stores th:nth-child(7){width:12%}.rp-table--stores th:nth-child(8){width:9%}.rp-table--userstores th:nth-child(1){width:18%}.rp-table--userstores th:nth-child(2){width:25%}.rp-table--userstores th:nth-child(3){width:25%}.rp-table--userstores th:nth-child(4){width:11%}.rp-table--userstores th:nth-child(5){width:10%}.rp-table--userstores th:nth-child(6){width:11%}.rp-table thead th{padding:8px 4px;border:0;border-bottom:1px solid #EAECF0;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;white-space:nowrap}.rp-table tbody td{padding:12px 4px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;color:#344054;vertical-align:middle}.rp-table tfoot td{padding:12px 4px;border:0;font-size:14px;line-height:20px;font-weight:700;color:#101828}.rp-table thead th.t-right,.rp-table tbody td.t-right,.rp-table tfoot td.t-right{text-align:right}.rp-table .is-strong{font-weight:600}.rp-table tbody td.is-muted{color:#98a2b3}.rp-table tbody td.is-pass{color:#027a48}.rp-table tbody td.is-fail{color:#d92d20}.rp-table tbody td.rp-cell-name{color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-result{display:inline-flex;padding:2px 10px;border-radius:9999px;background:#f2f4f7;font-size:12px;line-height:18px;font-weight:500;color:#475467;white-space:nowrap}.rp-result.is-pass{background:#ecfdf3;color:#027a48}.rp-result.is-fail{background:#fef3f2;color:#b42318}.rp-row{cursor:pointer}.rp-row:hover td{background:#fcfcfd}.rp-name{display:flex;flex-direction:column;gap:2px;min-width:0}.rp-name-main{font-weight:600;color:#00a3ff}.rp-name-sub{font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-export{height:32px;padding:0 12px;border:none;border-radius:6px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.rp-export:hover{background:#f9fafb}.filter-backdrop{position:fixed;inset:0;background:#10182873;z-index:1050}.filter-drawer{position:fixed;top:0;right:0;bottom:0;width:860px;max-width:96vw;display:flex;flex-direction:column;background:#fff;box-shadow:-10px 0 30px #1018282e;z-index:1051;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.drawer-head{display:flex;align-items:center;gap:10px;padding:18px 20px;box-shadow:inset 0 -1px #eaecf0}.drawer-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.closebtn{width:32px;height:32px;border:none;border-radius:8px;background:transparent;color:#667085;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.closebtn:hover{background:#f2f4f7;color:#344054}.drawer-body{display:flex;flex:1;min-height:0}.drawer-nav{flex:0 0 280px;max-width:280px;background:#f9fafb;box-shadow:inset -1px 0 #eaecf0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:4px}.drawer-navitem{display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border:none;border-radius:8px;background:transparent;text-align:left;font-family:inherit;cursor:pointer}.drawer-navitem:hover{background:#fff}.drawer-navitem.navitem-active{background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d}.navtext{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.navtitle{font-size:14px;line-height:20px;font-weight:600;color:#101828}.navvalue{font-size:14px;line-height:20px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.navvalue.is-dirty{color:#009bf3}.dirtydot{width:8px;height:8px;border-radius:9999px;background:#00a3ff;flex-shrink:0;display:block}.drawer-pane{flex:1;min-width:0;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:6px}.panetitle{font-size:18px;line-height:28px;font-weight:600;color:#101828}.panehint{font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.pane-stack{display:flex;flex-direction:column;gap:14px;margin-top:14px;max-width:560px}.pane-options{display:flex;flex-direction:column;gap:10px;margin-top:14px;max-width:560px}.pane-option{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:8px;cursor:pointer;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0}.pane-option.is-on{background:#f5fbff;box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio{width:18px;height:18px;flex-shrink:0;margin-top:2px;border-radius:9999px;display:flex;align-items:center;justify-content:center;box-shadow:inset 0 0 0 1px #d0d5dd}.pane-radio>span{width:8px;height:8px;border-radius:9999px;background:transparent;display:block}.pane-radio.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio.is-on>span{background:#00a3ff}.pane-option-text{display:flex;flex-direction:column;gap:2px}.pane-option-label{font-size:14px;line-height:20px;font-weight:600;color:#101828}.pane-option-help{font-size:14px;line-height:20px;color:#667085}.drawer-foot{display:flex;align-items:center;gap:10px;padding:14px 20px;box-shadow:inset 0 1px #eaecf0}.rp-reset{border:none;background:transparent;padding:0;font-family:inherit;font-weight:600;text-decoration:none;white-space:nowrap}.rp-pick-search{width:100%}.rp-picklist{max-height:320px;overflow-y:auto;padding:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column}.rp-pick{display:flex;align-items:center;gap:12px;min-height:40px;margin:0;padding:0 10px;border-radius:6px;font-size:14px;color:#344054;cursor:pointer}.rp-pick:hover{background:#f9fafb}.rp-pick.is-all{font-weight:600}.rp-pick input{appearance:none;-webkit-appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid #D0D5DD;border-radius:4px;background:#fff no-repeat center/12px 12px;cursor:pointer;vertical-align:middle;transition:border-color .12s ease,background-color .12s ease}.rp-pick input:hover:not(:disabled){border-color:#00a3ff}.rp-pick input:checked{border-color:#00a3ff;background-color:#eaf8ff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300A3FF' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E\")}.rp-pick input:focus-visible{outline:none;box-shadow:0 0 0 3px #eaf8ff}.rp-pick input:disabled{cursor:not-allowed;opacity:.45}.rp-pick-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-sub{max-width:45%;font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-empty{padding:20px 10px;font-size:14px;color:#667085}.rp-reading{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:8px;background:#f9fafb;font-size:14px;color:#475467}.rp-reading strong{font-weight:600;color:#101828}.rp-field{display:flex;flex-direction:column;gap:6px;min-width:0}.rp-field-label{display:flex;align-items:baseline;gap:8px;font-size:14px;line-height:20px;font-weight:600;color:#1d2939}.rp-field-label span{font-weight:400;color:#667085}\n"] }]
|
|
9169
|
+
args: [{ selector: 'lib-audit-v2-reports', template: "<div class=\"av2-page audit-reports\">\n\n <!-- Breadcrumb + title -->\n <div class=\"rp-head\">\n <div class=\"rp-crumb\">Audits \u203A <span class=\"rp-crumb-current\">Reports</span></div>\n <div class=\"rp-title\">Store audit report</div>\n </div>\n\n <!-- Filter chips, Filter button at the right end (QA 9 Oct); Export moved to the table head beside its search. -->\n <div class=\"rp-controls\">\n <button type=\"button\" class=\"rp-chip\" *ngFor=\"let c of chips; trackBy: trackByChip\" (click)=\"openFilters(c.key)\"\n [title]=\"c.label + ': ' + c.value\">\n <span class=\"rp-chip-key\">{{ c.label }}</span><span class=\"rp-chip-value\">{{ c.value }}</span>\n </button>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost rp-filterbtn\" (click)=\"openFilters()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\"></polygon></svg>\n Filter\n <span class=\"rp-countpill\">{{ filterCount }}</span>\n </button>\n </div>\n\n <!-- User view: where in the hierarchy -->\n <div class=\"rp-drillbar\" *ngIf=\"!isStoreMode\">\n <ng-container *ngFor=\"let c of crumbs; let last = last; let first = first\">\n <div class=\"rp-drillcrumb\" [class.is-current]=\"last\" (click)=\"goToLevel(c.level)\">\n <span class=\"rp-drillsep\" *ngIf=\"!first\">\u203A</span>{{ c.label }}\n </div>\n </ng-container>\n <div class=\"av2-grow\"></div>\n <div class=\"rp-hint\">{{ hint }}</div>\n </div>\n\n <!-- Scope -->\n <div class=\"rp-scope\">\n <div class=\"rp-scope-title\">{{ scopeTitle }}</div>\n <div class=\"rp-scope-meta\">{{ scopeMeta }}</div>\n </div>\n\n <!-- KPIs -->\n <div class=\"rp-kpis\">\n <!-- Old Checklist summary card: figure + label in the gradient strip, note below. -->\n <div class=\"av2-ocard\" *ngFor=\"let kpi of kpis\">\n <div class=\"av2-ocard-head\">\n <div class=\"av2-ocard-count rp-kpi-value\" [class.is-good]=\"kpi.tone === 'good'\" [class.is-bad]=\"kpi.tone === 'bad'\">\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--value rp-sk-value\"></span>\n <ng-container *ngIf=\"!loading\">{{ kpi.value }}</ng-container>\n </div>\n <div class=\"av2-ocard-text\">{{ kpi.label }}</div>\n </div>\n <div class=\"av2-ocard-body\">\n <span *ngIf=\"loading\" class=\"av2-sk av2-sk--note\"></span>\n <div *ngIf=\"!loading\" class=\"av2-ocard-note\">{{ kpi.note }}</div>\n </div>\n </div>\n </div>\n\n <!-- Report table -->\n <section class=\"rp-card\">\n <div class=\"rp-card-head\">\n <div class=\"rp-card-text\">\n <ng-container *ngIf=\"isStoreMode\">\n <div class=\"rp-card-title\">Store report</div>\n <div class=\"rp-card-meta\">{{ storeRows.length }} {{ storeRows.length === 1 ? 'store' : 'stores' }} \u00B7 audits submitted in the period</div>\n </ng-container>\n <ng-container *ngIf=\"!isStoreMode\">\n <div class=\"rp-card-title\">{{ tableTitle }}</div>\n <div class=\"rp-card-meta\">{{ tableMeta }}</div>\n </ng-container>\n </div>\n <div class=\"av2-grow\"></div>\n <label class=\"av2-search rp-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"7\"></circle>\n <line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line>\n </svg>\n <input type=\"text\" [placeholder]=\"isStoreMode ? 'Search store' : 'Search ' + levelLabel.toLowerCase()\"\n [(ngModel)]=\"search\" (ngModelChange)=\"onSearchChange()\">\n </label>\n <button type=\"button\" class=\"av2-btn av2-btn--ghost\" [disabled]=\"loading || exporting\" (click)=\"exportAll()\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 16V4\"></path><polyline points=\"7 9 12 4 17 9\"></polyline><path d=\"M4 16v4h16v-4\"></path></svg>\n Export\n </button>\n </div>\n\n <lib-audit-v2-shimmer *ngIf=\"loading\"></lib-audit-v2-shimmer>\n\n <!-- Store view: one row per store -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && isStoreMode && tableCount\">\n <table class=\"rp-table rp-table--stores\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('cluster')\">Cluster <lib-audit-v2-sort-icon [active]=\"sortKey === 'cluster'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('status')\">Result <lib-audit-v2-sort-icon [active]=\"sortKey === 'status'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('lastAudit')\">Last audit <lib-audit-v2-sort-icon [active]=\"sortKey === 'lastAudit'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Export</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of storePageRows; trackBy: trackByKey\">\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.cluster\">{{ s.cluster || '\u2014' }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\n <td class=\"t-right\">\n <span class=\"rp-result\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\">{{ resultText(s) }}</span>\n </td>\n <td class=\"t-right\" [class.is-muted]=\"!s.lastAudit\">{{ s.lastAudit || 'No audit' }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportStore(s)\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td></td>\n <td></td>\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td class=\"t-right\">{{ totals.failed }} fail</td>\n <td></td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <!-- User view: circle head / zone manager / area manager roll-up -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level !== 'store' && tableCount\">\n <table class=\"rp-table\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">{{ levelLabel }} <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('total')\">Total stores <lib-audit-v2-sort-icon [active]=\"sortKey === 'total'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('notAudited')\">Not audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'notAudited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('coverage')\">Coverage <lib-audit-v2-sort-icon [active]=\"sortKey === 'coverage'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('avgScore')\">Avg audit score <lib-audit-v2-sort-icon [active]=\"sortKey === 'avgScore'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('failedPct')\">Failed store % <lib-audit-v2-sort-icon [active]=\"sortKey === 'failedPct'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Report</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of pageRows; trackBy: trackByRow\" class=\"rp-row\" (click)=\"openRow(row)\">\n <td>\n <div class=\"rp-name\">\n <span class=\"rp-name-main\">{{ row.name }}</span>\n <span class=\"rp-name-sub\" *ngIf=\"row.email\">{{ row.email }}</span>\n </div>\n </td>\n <td class=\"t-right\">{{ row.total }}</td>\n <td class=\"t-right\">{{ row.audited }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!row.notAudited\">{{ row.notAudited }}</td>\n <td class=\"t-right\">{{ row.coverage }}</td>\n <td class=\"t-right is-strong\">{{ row.avgScore }}</td>\n <td class=\"t-right is-strong\" [class.is-fail]=\"isHighFail(row)\">{{ row.failedPct }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportRow(row); $event.stopPropagation()\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td class=\"t-right\">{{ totals.total }}</td>\n <td class=\"t-right\">{{ totals.audited }}</td>\n <td class=\"t-right\">{{ totals.total - totals.audited }}</td>\n <td class=\"t-right\">{{ totalCoverage }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td class=\"t-right\">{{ totalFailedPct }}</td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <!-- User view, deepest level: the area manager's stores -->\n <div class=\"av2-table-wrap\" *ngIf=\"!loading && !isStoreMode && level === 'store' && tableCount\">\n <table class=\"rp-table rp-table--userstores\">\n <thead>\n <tr>\n <th class=\"av2-sortable\" (click)=\"sortBy('name')\">Store <lib-audit-v2-sort-icon [active]=\"sortKey === 'name'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('aom')\">Area manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'aom'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"av2-sortable\" (click)=\"sortBy('zone')\">Zone manager <lib-audit-v2-sort-icon [active]=\"sortKey === 'zone'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('audited')\">Audited <lib-audit-v2-sort-icon [active]=\"sortKey === 'audited'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right av2-sortable\" (click)=\"sortBy('score')\">Score <lib-audit-v2-sort-icon [active]=\"sortKey === 'score'\" [dir]=\"sortDir\"></lib-audit-v2-sort-icon></th>\n <th class=\"t-right\">Export</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of userStorePageRows; trackBy: trackByKey\">\n <td class=\"is-strong rp-cell-name\" [av2Tip]=\"s.name\">{{ s.name }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.aom\">{{ s.aom || '\u2014' }}</td>\n <td class=\"av2-ellipsis\" [av2Tip]=\"s.zone\">{{ s.zone || '\u2014' }}</td>\n <td class=\"t-right\" [class.is-muted]=\"!s.audited\">{{ s.audited ? 'Yes' : 'No' }}</td>\n <td class=\"t-right is-strong\" [class.is-pass]=\"s.status === 'pass'\" [class.is-fail]=\"s.status === 'fail'\"\n [class.is-muted]=\"s.score === null\">{{ scoreText(s) }}</td>\n <td class=\"t-right\">\n <button type=\"button\" class=\"rp-export\" [disabled]=\"exporting\" (click)=\"exportStore(s)\">Export</button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr class=\"rp-total\">\n <td>Total</td>\n <td></td>\n <td></td>\n <td class=\"t-right\">{{ totalAuditedOf }}</td>\n <td class=\"t-right\">{{ totalAverage }}</td>\n <td></td>\n </tr>\n </tfoot>\n </table>\n </div>\n\n <div *ngIf=\"!loading && !tableCount\" class=\"av2-empty\">\n <img class=\"av2-empty-img\" src=\"./assets/tango/Icons/Nodata1.svg\" alt=\"\">\n <div class=\"av2-empty-text\">\n <div class=\"av2-empty-title\">No data found</div>\n <div class=\"av2-empty-sub\">{{ search ? 'No rows match \"' + search + '\"' : 'No stores match the current filters' }}</div>\n </div>\n </div>\n\n <!-- Shared pager (10 / 20 / 30), as on the other audit lists. -->\n <div class=\"rp-pager\" *ngIf=\"!loading && tableCount\">\n <lib-pagination [itemsPerPage]=\"pageSize\" [pageSize]=\"pageSize\" [paginationSizes]=\"pageSizes\" [currentPage]=\"page\"\n [totalItems]=\"tableCount\" (pageChange)=\"onPageChange($event)\" (pageSizeChange)=\"onPageSizeChange($event)\"></lib-pagination>\n </div>\n </section>\n\n <!-- ============ FILTER DRAWER ============ -->\n <div class=\"filter-backdrop\" *ngIf=\"filtersOpen\" (click)=\"closeFilters()\"></div>\n\n <!-- Every control edits the drawer's draft (dr); the page behind changes only on Apply or Reset all. -->\n <div class=\"filter-drawer\" *ngIf=\"filtersOpen && draft as dr\">\n <div class=\"drawer-head\">\n <span class=\"drawer-title\">Filters</span>\n <span class=\"rp-countpill\">{{ dr.filterCount }}</span>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"closebtn\" (click)=\"closeFilters()\" title=\"Close\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\n </button>\n </div>\n\n <div class=\"drawer-body\">\n <div class=\"drawer-nav\">\n <!-- trackBy: filterCats is rebuilt on every check, and lib-audit-v2-select's document:mousedown runs one\n between press and release; without it the button was replaced mid-click and the click never landed. -->\n <button type=\"button\" class=\"drawer-navitem\" *ngFor=\"let c of dr.filterCats; trackBy: trackByChip\" [class.navitem-active]=\"activeCat === c.key\"\n (click)=\"selectCat(c.key)\">\n <span class=\"navtext\">\n <span class=\"navtitle\">{{ c.label }}</span>\n <span class=\"navvalue\" [class.is-dirty]=\"c.dirty\">{{ c.value }}</span>\n </span>\n <span class=\"dirtydot\" *ngIf=\"c.dirty\"></span>\n </button>\n </div>\n\n <div class=\"drawer-pane\">\n <div class=\"panetitle\">{{ dr.paneTitle }}</div>\n <div class=\"panehint\">{{ dr.paneSub }}</div>\n\n <!-- Date -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'date'\">\n <div class=\"av2-datepick\">\n <svg class=\"av2-datepick-icon\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"></line><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"></line><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"></line></svg>\n <input type=\"text\" class=\"av2-datepick-input rp-daterange\" ngxDaterangepickerMd readonly autocomplete=\"off\"\n placeholder=\"Select date range\" [(ngModel)]=\"dr.range\" [locale]=\"pickerLocale\" [maxDate]=\"today\"\n [ranges]=\"ranges\" [showCustomRangeLabel]=\"true\" [alwaysShowCalendars]=\"false\"\n [keepCalendarOpeningWithRange]=\"true\" [autoApply]=\"true\" [showCancel]=\"false\"\n [drops]=\"'down'\" [opens]=\"'right'\" (datesUpdated)=\"dr.onRangePicked($event)\">\n </div>\n <div class=\"rp-presets\">\n <button type=\"button\" class=\"rp-preset\" *ngFor=\"let p of presets\" [class.is-on]=\"dr.preset === p\"\n (click)=\"dr.setPreset(p)\">{{ p }}</button>\n </div>\n </div>\n\n <!-- View by -->\n <div class=\"pane-options\" *ngIf=\"activeCat === 'mode'\">\n <div class=\"pane-option\" [class.is-on]=\"dr.isStoreMode\" (click)=\"dr.setMode('store')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.isStoreMode\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Store</span>\n <span class=\"pane-option-help\">One row per store with score, result and last audit date.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"!dr.isStoreMode\" (click)=\"dr.setMode('user')\">\n <span class=\"pane-radio\" [class.is-on]=\"!dr.isStoreMode\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">User</span>\n <span class=\"pane-option-help\">Rolled up by circle head, zone manager and AOM, drillable down to stores.</span>\n </span>\n </div>\n </div>\n\n <!-- Stores (Store view) -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && dr.isStoreMode\">\n <label class=\"av2-search rp-pick-search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"></circle><line x1=\"16.5\" y1=\"16.5\" x2=\"21\" y2=\"21\"></line></svg>\n <input type=\"text\" placeholder=\"Search store\" [(ngModel)]=\"dr.storeQuery\">\n </label>\n <div class=\"rp-picklist\">\n <ng-container *ngIf=\"dr.storePickItems.length\">\n <label class=\"rp-pick is-all\">\n <input type=\"checkbox\" [checked]=\"dr.storePickAllChecked\" (change)=\"dr.toggleStorePickAll()\">\n <span>Select All</span>\n </label>\n <label class=\"rp-pick\" *ngFor=\"let it of dr.storePickItems; trackBy: trackByPick\">\n <input type=\"checkbox\" [checked]=\"it.checked\" (change)=\"dr.toggleStorePick(it.store)\">\n <span class=\"rp-pick-label\">{{ it.store.name }}</span>\n <span class=\"rp-pick-sub\">{{ it.store.cluster || it.store.aom }}</span>\n </label>\n </ng-container>\n <div class=\"rp-pick-empty\" *ngIf=\"!dr.storePickItems.length\">\n {{ dr.storeQuery ? 'No stores match \"' + dr.storeQuery + '\"' : 'No stores in scope' }}\n </div>\n </div>\n <div class=\"rp-reading\">\n <span>Reading</span>\n <strong>{{ dr.storePickReading }}</strong>\n <span class=\"av2-grow\"></span>\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.resetStorePick()\">Reset to all stores</button>\n </div>\n </div>\n\n <!-- Store hierarchy (User view) -->\n <div class=\"pane-stack\" *ngIf=\"activeCat === 'scope' && !dr.isStoreMode\">\n <div class=\"rp-field\">\n <div class=\"rp-field-label\">Circle Head <span>{{ dr.circleOptions.length - 1 }} users</span></div>\n <lib-audit-v2-select [value]=\"dr.circleKey\" [options]=\"dr.circleOptions\" placeholder=\"All circles\"\n ariaLabel=\"Circle Head\" (changed)=\"dr.pickCircle($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.showZonePick\">\n <div class=\"rp-field-label\">Zone Manager <span>{{ dr.zoneOptions.length - 1 }} {{ dr.zoneOptions.length === 2 ? 'user' : 'users' }}</span></div>\n <lib-audit-v2-select [value]=\"dr.zoneKey\" [options]=\"dr.zoneOptions\" placeholder=\"All zones\"\n ariaLabel=\"Zone Manager\" (changed)=\"dr.pickZone($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.zoneKey\">\n <div class=\"rp-field-label\">AOM <span>{{ dr.aomOptions.length - 1 }} {{ dr.aomOptions.length === 2 ? 'user' : 'users' }}</span></div>\n <lib-audit-v2-select [value]=\"dr.aomKey\" [options]=\"dr.aomOptions\" placeholder=\"All AOMs\"\n ariaLabel=\"AOM\" (changed)=\"dr.pickAom($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-field\" *ngIf=\"dr.aomKey\">\n <div class=\"rp-field-label\">Store <span>{{ dr.storeOptions.length - 1 }} stores</span></div>\n <lib-audit-v2-select [value]=\"dr.storeKey\" [options]=\"dr.storeOptions\" placeholder=\"All stores\"\n ariaLabel=\"Store\" (changed)=\"dr.pickStore($event.target.value)\"></lib-audit-v2-select>\n </div>\n <div class=\"rp-reading\">\n <span>Reading</span>\n <strong>{{ dr.hierarchyReading }}</strong>\n <span class=\"av2-grow\"></span>\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"dr.goToLevel('circle')\">Reset to all circles</button>\n </div>\n </div>\n\n <!-- Result (Store view) -->\n <div class=\"pane-options\" *ngIf=\"activeCat === 'result' && dr.isStoreMode\">\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'all'\" (click)=\"dr.setResult('all')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'all'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">All</span>\n <span class=\"pane-option-help\">Every store in scope, audited or not.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'pass'\" (click)=\"dr.setResult('pass')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'pass'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Pass</span>\n <span class=\"pane-option-help\">Only stores scoring at or above the {{ passMark }}% pass mark.</span>\n </span>\n </div>\n <div class=\"pane-option\" [class.is-on]=\"dr.result === 'fail'\" (click)=\"dr.setResult('fail')\">\n <span class=\"pane-radio\" [class.is-on]=\"dr.result === 'fail'\"><span></span></span>\n <span class=\"pane-option-text\">\n <span class=\"pane-option-label\">Fail</span>\n <span class=\"pane-option-help\">Only stores scoring below the {{ passMark }}% pass mark.</span>\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"drawer-foot\">\n <button type=\"button\" class=\"av2-link rp-reset\" (click)=\"resetFilters()\">Reset all</button>\n <div class=\"av2-grow\"></div>\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--wide\" (click)=\"applyFilters()\">Apply</button>\n </div>\n </div>\n\n</div>\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}::ng-deep .tooltip.av2-tip{--bs-tooltip-bg: #fff;--bs-tooltip-color: #344054;--bs-tooltip-max-width: 320px;--bs-tooltip-opacity: 1}::ng-deep .tooltip.av2-tip .tooltip-inner{background-color:#fff!important;color:#344054!important;padding:8px 12px;border-radius:8px;font-size:13px;line-height:18px;font-weight:500;text-align:left;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,0 0 0 1px #eaecf0}::ng-deep .tooltip.av2-tip .tooltip-arrow:before{border-top-color:#fff;border-bottom-color:#fff}:host ::ng-deep lib-pagination{display:block}:host ::ng-deep lib-pagination .container{max-width:none;padding:0;display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;font-size:14px;color:#475467}:host ::ng-deep lib-pagination .mt-4{margin-top:0!important}:host ::ng-deep lib-pagination .container>.text-center{display:flex;align-items:center}:host ::ng-deep lib-pagination .container>.text-center>ul:not(.ngx-pagination){display:none}:host ::ng-deep lib-pagination pagination-controls{display:flex;align-items:center}:host ::ng-deep lib-pagination .sub-title{color:#475467!important;font-size:14px!important;font-weight:400!important;line-height:20px}:host ::ng-deep lib-pagination .border-val{height:40px;min-width:64px;padding:0 30px 0 12px!important;border:1px solid #D0D5DD!important;border-radius:8px!important;box-shadow:0 1px 2px #1018280d;background-color:#fff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\")!important;background-repeat:no-repeat!important;background-position:right 10px center!important;background-size:14px 14px!important;appearance:none;-webkit-appearance:none;font-size:14px;font-weight:500;color:#1d2939;cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}:host ::ng-deep lib-pagination .border-val:hover{border-color:#98a2b3!important}:host ::ng-deep lib-pagination .border-val:focus{outline:none;border-color:#66c8ff!important;box-shadow:0 0 0 3px #eaf8ff}:host ::ng-deep lib-pagination .ngx-pagination{margin:0;padding:0;display:flex;align-items:center;gap:6px;color:#475467!important;font-size:14px!important;font-weight:500}:host ::ng-deep lib-pagination .ngx-pagination li{display:inline-flex;margin:0}:host ::ng-deep lib-pagination .ngx-pagination li.small-screen{display:none!important}:host ::ng-deep lib-pagination .ngx-pagination a,:host ::ng-deep lib-pagination .ngx-pagination button,:host ::ng-deep lib-pagination .ngx-pagination .current,:host ::ng-deep lib-pagination .ngx-pagination .disabled{min-width:40px!important;height:40px;padding:0 8px!important;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;line-height:20px;color:#475467}:host ::ng-deep lib-pagination .ngx-pagination a:hover,:host ::ng-deep lib-pagination .ngx-pagination button:hover{background:#f2f4f7;padding:0 8px!important}:host ::ng-deep lib-pagination .ngx-pagination .current{background:#eaf8ff!important;color:#00a3ff!important;font-weight:600;font-size:14px!important}:host ::ng-deep lib-pagination .ngx-pagination .disabled{color:#98a2b3}:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-previous.disabled:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next a:after,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:before,:host ::ng-deep lib-pagination .ngx-pagination .pagination-next.disabled:after{margin:0}:host ::ng-deep lib-pagination .ngx-pagination .ellipsis:after{color:#98a2b3;padding:0}.rp-pager{padding-top:20px}.rp-head{display:flex;flex-direction:column;gap:2px}.rp-crumb{font-size:13px;line-height:20px;color:#667085}.rp-crumb-current{color:#00a3ff}.rp-title{font-size:22px;line-height:30px;font-weight:600;color:#101828}.rp-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-countpill{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:9999px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:600}.rp-chip{height:32px;max-width:360px;padding:0 12px;border:none;border-radius:9999px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-size:13px;line-height:20px;white-space:nowrap;cursor:pointer}.rp-chip:hover{background:#f9fafb}.rp-chip-key{font-weight:500;color:#667085}.rp-chip-value{overflow:hidden;text-overflow:ellipsis;font-weight:600;color:#101828}.av2-datepick{position:relative;display:inline-flex;align-items:center}.av2-datepick-icon{position:absolute;left:10px;color:#667085;pointer-events:none}.av2-datepick-input{height:36px;padding:0 10px 0 32px;border:none;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;background:#fff;font-family:inherit;font-size:13px;font-weight:500;color:#101828;cursor:pointer;outline:none}.av2-datepick-input:focus{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}:host ::ng-deep .av2-datepick .md-drppicker{margin-top:4px;z-index:1060;font-family:inherit;border-radius:8px;box-shadow:0 12px 16px -4px #10182814,0 4px 6px -2px #10182808,inset 0 0 0 1px #eaecf0}:host ::ng-deep .av2-datepick .md-drppicker.double,:host ::ng-deep .av2-datepick .md-drppicker.show-ranges{width:max-content}:host ::ng-deep .av2-datepick .md-drppicker.ltr .ranges{float:left;margin-top:10px}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button{width:160px;padding:12px 16px;border:none;border-radius:8px;background:none;color:#344054;font-size:14px;font-weight:400;line-height:20px;text-align:left;cursor:pointer}:host ::ng-deep .av2-datepick .md-drppicker .ranges ul li button.active{background:#eaf8ff;color:#00a3ff;font-weight:500}:host ::ng-deep .av2-datepick .md-drppicker th,:host ::ng-deep .av2-datepick .md-drppicker td{width:40px!important;height:40px!important;min-width:32px;padding:0!important;border:1px solid transparent!important;background:transparent!important;font-size:14px!important;font-weight:400!important;line-height:38px}:host ::ng-deep .av2-datepick .md-drppicker th{color:#344054!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker th.month{width:auto!important;font-size:16px!important}:host ::ng-deep .av2-datepick .md-drppicker td{color:#344054!important}:host ::ng-deep .av2-datepick .md-drppicker th.available.prev,:host ::ng-deep .av2-datepick .md-drppicker th.available.next{background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 6 9 12 15 18'/%3E%3C/svg%3E\") center/18px no-repeat!important}:host ::ng-deep .av2-datepick .md-drppicker th.available:hover,:host ::ng-deep .av2-datepick .md-drppicker td.available:hover{background-color:#f2f4f7!important}:host ::ng-deep .av2-datepick .md-drppicker td.in-range{background-color:#eaf8ff!important;color:#101828!important}:host ::ng-deep .av2-datepick .md-drppicker td.active,:host ::ng-deep .av2-datepick .md-drppicker td.active:hover{background-color:#029cf4!important;border-radius:20px;color:#fff!important;font-weight:500!important}:host ::ng-deep .av2-datepick .md-drppicker td.off,:host ::ng-deep .av2-datepick .md-drppicker td.off.in-range{color:#98a2b3!important;background-color:transparent!important}:host ::ng-deep .av2-datepick .md-drppicker td.disabled{color:#98a2b3!important;background-color:transparent!important;text-decoration:line-through;pointer-events:none}:host ::ng-deep .av2-datepick--compact .md-drppicker th,:host ::ng-deep .av2-datepick--compact .md-drppicker td{width:32px!important;height:32px!important;font-size:12px!important;line-height:30px}:host ::ng-deep .av2-datepick--compact .md-drppicker th.month{font-size:14px!important}.rp-daterange{width:260px;height:44px;font-size:14px}.rp-presets{display:flex;flex-wrap:wrap;gap:8px}.rp-preset{height:36px;padding:0 14px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0;font-family:inherit;font-size:14px;font-weight:500;color:#667085;cursor:pointer}.rp-preset.is-on{background:#eaf8ff;box-shadow:inset 0 0 0 1px #99dbff;color:#101828;font-weight:600}.rp-drillbar{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:14px 18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}.rp-drillcrumb{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:#00a3ff;cursor:pointer}.rp-drillcrumb.is-current{color:#101828;cursor:default}.rp-drillsep{color:#98a2b3;font-weight:400}.rp-hint{font-size:14px;color:#667085}.rp-scope{display:flex;flex-direction:column;gap:2px}.rp-scope-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-scope-meta{font-size:14px;line-height:20px;color:#667085}.rp-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:16px}.rp-kpi-value.is-good{color:#027a48}.rp-kpi-value.is-bad{color:#d92d20}.rp-sk-value{height:32px;margin:3px 0}.rp-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:18px 20px 12px;display:flex;flex-direction:column;gap:14px}.rp-card-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.rp-card-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:200px}.rp-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828}.rp-card-meta{font-size:14px;line-height:20px;color:#667085}.rp-search{width:260px}.rp-table{width:100%;border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed}.rp-table th:nth-child(1){width:29%}.rp-table th:nth-child(2){width:9.5%}.rp-table th:nth-child(3){width:8.5%}.rp-table th:nth-child(4){width:9.5%}.rp-table th:nth-child(5){width:9.5%}.rp-table th:nth-child(6){width:12%}.rp-table th:nth-child(7){width:11%}.rp-table th:nth-child(8){width:11%}.rp-table--stores th:nth-child(1){width:14%}.rp-table--stores th:nth-child(2){width:20%}.rp-table--stores th:nth-child(3){width:16%}.rp-table--stores th:nth-child(4){width:9%}.rp-table--stores th:nth-child(5){width:9%}.rp-table--stores th:nth-child(6){width:11%}.rp-table--stores th:nth-child(7){width:12%}.rp-table--stores th:nth-child(8){width:9%}.rp-table--userstores th:nth-child(1){width:18%}.rp-table--userstores th:nth-child(2){width:25%}.rp-table--userstores th:nth-child(3){width:25%}.rp-table--userstores th:nth-child(4){width:11%}.rp-table--userstores th:nth-child(5){width:10%}.rp-table--userstores th:nth-child(6){width:11%}.rp-table thead th{padding:8px 4px;border:0;border-bottom:1px solid #EAECF0;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;white-space:nowrap}.rp-table tbody td{padding:12px 4px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;color:#344054;vertical-align:middle}.rp-table tfoot td{padding:12px 4px;border:0;font-size:14px;line-height:20px;font-weight:700;color:#101828}.rp-table thead th.t-right,.rp-table tbody td.t-right,.rp-table tfoot td.t-right{text-align:right}.rp-table .is-strong{font-weight:600}.rp-table tbody td.is-muted{color:#98a2b3}.rp-table tbody td.is-pass{color:#027a48}.rp-table tbody td.is-fail{color:#d92d20}.rp-table tbody td.rp-cell-name{color:#101828;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-result{display:inline-flex;padding:2px 10px;border-radius:9999px;background:#f2f4f7;font-size:12px;line-height:18px;font-weight:500;color:#475467;white-space:nowrap}.rp-result.is-pass{background:#ecfdf3;color:#027a48}.rp-result.is-fail{background:#fef3f2;color:#b42318}.rp-row{cursor:pointer}.rp-row:hover td{background:#fcfcfd}.rp-name{display:flex;flex-direction:column;gap:2px;min-width:0}.rp-name-main{font-weight:600;color:#00a3ff}.rp-name-sub{font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-export{height:32px;padding:0 12px;border:none;border-radius:6px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#344054;cursor:pointer}.rp-export:hover{background:#f9fafb}.filter-backdrop{position:fixed;inset:0;background:#10182873;z-index:1050}.filter-drawer{position:fixed;top:0;right:0;bottom:0;width:860px;max-width:96vw;display:flex;flex-direction:column;background:#fff;box-shadow:-10px 0 30px #1018282e;z-index:1051;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.drawer-head{display:flex;align-items:center;gap:10px;padding:18px 20px;box-shadow:inset 0 -1px #eaecf0}.drawer-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.closebtn{width:32px;height:32px;border:none;border-radius:8px;background:transparent;color:#667085;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.closebtn:hover{background:#f2f4f7;color:#344054}.drawer-body{display:flex;flex:1;min-height:0}.drawer-nav{flex:0 0 280px;max-width:280px;background:#f9fafb;box-shadow:inset -1px 0 #eaecf0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:4px}.drawer-navitem{display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border:none;border-radius:8px;background:transparent;text-align:left;font-family:inherit;cursor:pointer}.drawer-navitem:hover{background:#fff}.drawer-navitem.navitem-active{background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d}.navtext{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.navtitle{font-size:14px;line-height:20px;font-weight:600;color:#101828}.navvalue{font-size:14px;line-height:20px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.navvalue.is-dirty{color:#009bf3}.dirtydot{width:8px;height:8px;border-radius:9999px;background:#00a3ff;flex-shrink:0;display:block}.drawer-pane{flex:1;min-width:0;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:6px}.panetitle{font-size:18px;line-height:28px;font-weight:600;color:#101828}.panehint{font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.pane-stack{display:flex;flex-direction:column;gap:14px;margin-top:14px;max-width:560px}.pane-options{display:flex;flex-direction:column;gap:10px;margin-top:14px;max-width:560px}.pane-option{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:8px;cursor:pointer;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0}.pane-option.is-on{background:#f5fbff;box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio{width:18px;height:18px;flex-shrink:0;margin-top:2px;border-radius:9999px;display:flex;align-items:center;justify-content:center;box-shadow:inset 0 0 0 1px #d0d5dd}.pane-radio>span{width:8px;height:8px;border-radius:9999px;background:transparent;display:block}.pane-radio.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.pane-radio.is-on>span{background:#00a3ff}.pane-option-text{display:flex;flex-direction:column;gap:2px}.pane-option-label{font-size:14px;line-height:20px;font-weight:600;color:#101828}.pane-option-help{font-size:14px;line-height:20px;color:#667085}.drawer-foot{display:flex;align-items:center;gap:10px;padding:14px 20px;box-shadow:inset 0 1px #eaecf0}.rp-reset{border:none;background:transparent;padding:0;font-family:inherit;font-weight:600;text-decoration:none;white-space:nowrap}.rp-pick-search{width:100%}.rp-picklist{max-height:320px;overflow-y:auto;padding:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column}.rp-pick{display:flex;align-items:center;gap:12px;min-height:40px;margin:0;padding:0 10px;border-radius:6px;font-size:14px;color:#344054;cursor:pointer}.rp-pick:hover{background:#f9fafb}.rp-pick.is-all{font-weight:600}.rp-pick input{appearance:none;-webkit-appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid #D0D5DD;border-radius:4px;background:#fff no-repeat center/12px 12px;cursor:pointer;vertical-align:middle;transition:border-color .12s ease,background-color .12s ease}.rp-pick input:hover:not(:disabled){border-color:#00a3ff}.rp-pick input:checked{border-color:#00a3ff;background-color:#eaf8ff;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300A3FF' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E\")}.rp-pick input:focus-visible{outline:none;box-shadow:0 0 0 3px #eaf8ff}.rp-pick input:disabled{cursor:not-allowed;opacity:.45}.rp-pick-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-sub{max-width:45%;font-size:12px;color:#667085;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rp-pick-empty{padding:20px 10px;font-size:14px;color:#667085}.rp-reading{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:8px;background:#f9fafb;font-size:14px;color:#475467}.rp-reading strong{font-weight:600;color:#101828}.rp-field{display:flex;flex-direction:column;gap:6px;min-width:0}.rp-field-label{display:flex;align-items:baseline;gap:8px;font-size:14px;line-height:20px;font-weight:600;color:#1d2939}.rp-field-label span{font-weight:400;color:#667085}\n"] }]
|
|
9103
9170
|
}], ctorParameters: () => [{ type: TraxService }, { type: i2.GlobalStateService }, { type: i3.ToastService }, { type: i0.ChangeDetectorRef }] });
|
|
9104
9171
|
|
|
9105
9172
|
/**
|
|
@@ -9368,6 +9435,10 @@ class AuditV2ConfigureComponent {
|
|
|
9368
9435
|
dailySendApprover = true;
|
|
9369
9436
|
dailySendCustom = false;
|
|
9370
9437
|
dailyUsers = [];
|
|
9438
|
+
/** Daily Report > Custom bulk upload popup (as the Checklist Configure page's). */
|
|
9439
|
+
dailyBulkOpen = false;
|
|
9440
|
+
/** Row errors of the last upload; any error rejects the whole file, so nothing partial is applied. */
|
|
9441
|
+
dailyBulkErrors = [];
|
|
9371
9442
|
sharePostApproval = false;
|
|
9372
9443
|
exportSubmissionOn = false;
|
|
9373
9444
|
redoValidFor = 7;
|
|
@@ -9463,8 +9534,9 @@ class AuditV2ConfigureComponent {
|
|
|
9463
9534
|
this.destroy$.next();
|
|
9464
9535
|
this.destroy$.complete();
|
|
9465
9536
|
}
|
|
9466
|
-
/** Escape closes the open dropdown / suggestion list. */
|
|
9537
|
+
/** Escape closes the open dropdown / suggestion list / bulk upload popup. */
|
|
9467
9538
|
onEscape() {
|
|
9539
|
+
this.dailyBulkOpen = false;
|
|
9468
9540
|
this.openSelect = null;
|
|
9469
9541
|
this.openChips = null;
|
|
9470
9542
|
}
|
|
@@ -9948,6 +10020,116 @@ class AuditV2ConfigureComponent {
|
|
|
9948
10020
|
removeChip(list, index) {
|
|
9949
10021
|
this[list] = this[list].filter((_, i) => i !== index);
|
|
9950
10022
|
}
|
|
10023
|
+
// ---- Daily Report custom users: bulk upload ----------------------------------------------
|
|
10024
|
+
openDailyBulk() {
|
|
10025
|
+
this.dailyBulkErrors = [];
|
|
10026
|
+
this.dailyBulkOpen = true;
|
|
10027
|
+
this.openChips = null;
|
|
10028
|
+
this.openSelect = null;
|
|
10029
|
+
}
|
|
10030
|
+
closeDailyBulk() {
|
|
10031
|
+
this.dailyBulkOpen = false;
|
|
10032
|
+
this.dailyBulkErrors = [];
|
|
10033
|
+
}
|
|
10034
|
+
/** Username + Email template, pre-filled with the current Daily Report custom users (as the Checklist one). */
|
|
10035
|
+
downloadDailyTemplate() {
|
|
10036
|
+
const rows = this.dailyUsers.length ? this.dailyUsers.map(u => [u.n, u.e]) : [['', '']];
|
|
10037
|
+
const sheet = XLSX.utils.aoa_to_sheet([['Username', 'Email'], ...rows]);
|
|
10038
|
+
sheet['!cols'] = [{ wch: 28 }, { wch: 36 }];
|
|
10039
|
+
const book = XLSX.utils.book_new();
|
|
10040
|
+
XLSX.utils.book_append_sheet(book, sheet, 'Users');
|
|
10041
|
+
XLSX.writeFile(book, 'dailyReportTemplate.xlsx');
|
|
10042
|
+
}
|
|
10043
|
+
/**
|
|
10044
|
+
* Replaces the Daily Report custom users with the uploaded sheet, as the Checklist Configure page does:
|
|
10045
|
+
* only the Email column counts (the name comes from the client's user list), and every row must be an
|
|
10046
|
+
* existing user. Any invalid row rejects the whole file.
|
|
10047
|
+
*/
|
|
10048
|
+
onDailyBulkFile(event) {
|
|
10049
|
+
const input = event.target;
|
|
10050
|
+
const file = input.files?.[0];
|
|
10051
|
+
input.value = '';
|
|
10052
|
+
if (!file) {
|
|
10053
|
+
return;
|
|
10054
|
+
}
|
|
10055
|
+
this.dailyBulkErrors = [];
|
|
10056
|
+
if (!/\.xlsx$/i.test(file.name)) {
|
|
10057
|
+
this.dailyBulkErrors = ['Please upload a valid .xlsx file.'];
|
|
10058
|
+
this.cd.detectChanges();
|
|
10059
|
+
return;
|
|
10060
|
+
}
|
|
10061
|
+
if (!this.users.length) {
|
|
10062
|
+
this.dailyBulkErrors = ['The users of this client could not be loaded. Reload the page and try again.'];
|
|
10063
|
+
this.cd.detectChanges();
|
|
10064
|
+
return;
|
|
10065
|
+
}
|
|
10066
|
+
file.arrayBuffer().then(buffer => {
|
|
10067
|
+
this.dailyBulkErrors = this.applyDailyBulk(buffer);
|
|
10068
|
+
if (!this.dailyBulkErrors.length) {
|
|
10069
|
+
this.dailyBulkOpen = false;
|
|
10070
|
+
this.toast.getSuccessToast('File uploaded successfully. ' + this.dailyUsers.length
|
|
10071
|
+
+ (this.dailyUsers.length === 1 ? ' user' : ' users') + ' added to the daily report.');
|
|
10072
|
+
}
|
|
10073
|
+
this.cd.detectChanges();
|
|
10074
|
+
}).catch(() => {
|
|
10075
|
+
this.dailyBulkErrors = ['Could not read this file. Upload the downloaded template as .xlsx.'];
|
|
10076
|
+
this.cd.detectChanges();
|
|
10077
|
+
});
|
|
10078
|
+
}
|
|
10079
|
+
/** Applies the sheet to dailyUsers and returns [] on success, else the reasons it was rejected. */
|
|
10080
|
+
applyDailyBulk(buffer) {
|
|
10081
|
+
let rows;
|
|
10082
|
+
try {
|
|
10083
|
+
const book = XLSX.read(buffer, { type: 'array' });
|
|
10084
|
+
rows = XLSX.utils.sheet_to_json(book.Sheets[book.SheetNames[0]], { header: 1, defval: '', blankrows: true });
|
|
10085
|
+
}
|
|
10086
|
+
catch {
|
|
10087
|
+
return ['Could not read this file. Upload the downloaded template as .xlsx.'];
|
|
10088
|
+
}
|
|
10089
|
+
const emailCol = (rows[0] || []).findIndex(h => String(h ?? '').trim().toLowerCase() === 'email');
|
|
10090
|
+
if (emailCol < 0) {
|
|
10091
|
+
return ["The template must contain an 'Email' column."];
|
|
10092
|
+
}
|
|
10093
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
10094
|
+
const byEmail = new Map(this.users.map(u => [u.e, u]));
|
|
10095
|
+
const matched = [];
|
|
10096
|
+
const errors = [];
|
|
10097
|
+
let dataRows = 0;
|
|
10098
|
+
rows.slice(1).forEach((row, i) => {
|
|
10099
|
+
// Skip fully blank rows (any column, not just Email).
|
|
10100
|
+
if (!row.some(v => String(v ?? '').trim() !== '')) {
|
|
10101
|
+
return;
|
|
10102
|
+
}
|
|
10103
|
+
dataRows++;
|
|
10104
|
+
const rowNo = i + 2; // +1 header, +1 to 1-based
|
|
10105
|
+
const email = String(row[emailCol] ?? '').trim().toLowerCase();
|
|
10106
|
+
if (!email) {
|
|
10107
|
+
errors.push('Row ' + rowNo + ': Email is required');
|
|
10108
|
+
return;
|
|
10109
|
+
}
|
|
10110
|
+
if (!emailRegex.test(email)) {
|
|
10111
|
+
errors.push('Row ' + rowNo + ': "' + email + '" is not a valid email');
|
|
10112
|
+
return;
|
|
10113
|
+
}
|
|
10114
|
+
const user = byEmail.get(email);
|
|
10115
|
+
if (!user) {
|
|
10116
|
+
errors.push('Row ' + rowNo + ': "' + email + '" is not an existing user');
|
|
10117
|
+
return;
|
|
10118
|
+
}
|
|
10119
|
+
if (!matched.some(u => u.e === user.e)) {
|
|
10120
|
+
matched.push(user);
|
|
10121
|
+
}
|
|
10122
|
+
});
|
|
10123
|
+
if (!dataRows) {
|
|
10124
|
+
return ['The uploaded file has no data rows.'];
|
|
10125
|
+
}
|
|
10126
|
+
if (errors.length) {
|
|
10127
|
+
return errors;
|
|
10128
|
+
}
|
|
10129
|
+
this.dailyUsers = matched;
|
|
10130
|
+
this.dailySendCustom = true;
|
|
10131
|
+
return [];
|
|
10132
|
+
}
|
|
9951
10133
|
/** What the checklist keeps as assignedUsers, exactly as the Checklist Configure page sends it. */
|
|
9952
10134
|
assignedUsers() {
|
|
9953
10135
|
const d = this.configData?.checkListDetails || {};
|
|
@@ -10204,11 +10386,11 @@ class AuditV2ConfigureComponent {
|
|
|
10204
10386
|
return data;
|
|
10205
10387
|
}
|
|
10206
10388
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ConfigureComponent, deps: [{ token: TraxService }, { token: i2.GlobalStateService }, { token: i1.ActivatedRoute }, { token: i1.Router }, { token: i3.ToastService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
10207
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ConfigureComponent, selector: "lib-audit-v2-configure", host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "<div class=\"av2-page audit-configure\">\r\n\r\n <!-- Back + breadcrumb (as the schedule editor's back bar) -->\r\n <div class=\"cf-backbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm cf-back\" (click)=\"back()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\r\n {{ backLabel }}\r\n </button>\r\n <div class=\"cf-crumb\">\r\n <a href=\"#\" (click)=\"back($event)\">Manage Audit</a> \u203A Configure\r\n </div>\r\n </div>\r\n\r\n <!-- Title + actions -->\r\n <div class=\"cf-header\">\r\n <div class=\"cf-header-text\">\r\n <span class=\"av2-sk av2-sk--title cf-sk-title\" *ngIf=\"loading\"></span>\r\n <div class=\"cf-title\" *ngIf=\"!loading\">{{ auditName || 'Audit' }}</div>\r\n <input type=\"text\" class=\"cf-desc\" placeholder=\"Enter Audit Description\" [(ngModel)]=\"description\">\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary cf-publish\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason || publishBlockedReason\" (click)=\"publish()\">\r\n {{ saving ? 'Saving\u2026' : (published ? 'Save & Publish' : 'Publish') }}\r\n </button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost cf-draft\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason\" (click)=\"saveDraft()\">Save as Draft</button>\r\n </div>\r\n\r\n <div class=\"cf-error cf-error--page\" *ngIf=\"loadError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ loadError }}\r\n </div>\r\n\r\n <!-- Chip picker: chips + input + suggestion list (one template, used for every user list) -->\r\n <ng-template #chipPicker let-list=\"list\" let-large=\"large\">\r\n <div class=\"cf-chipbox\" [class.cf-chipbox--lg]=\"large\" [class.is-open]=\"openChips === list\" (click)=\"focusChips(list, $event)\">\r\n <span class=\"cf-chip\" [class.cf-chip--lg]=\"large\" *ngFor=\"let u of chipsOf(list); let i = index\" [title]=\"u.e\">\r\n <span [class]=\"large ? 'cf-chip-tag' : 'cf-chip-ini'\">{{ u.i }}</span>{{ u.n }}\r\n <a class=\"cf-chip-x\" (click)=\"removeChip(list, i); $event.stopPropagation()\">\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <input type=\"text\" class=\"cf-chip-input\" [class.cf-chip-input--lg]=\"large\" placeholder=\"Add user...\"\r\n [ngModel]=\"draftOf(list)\" (ngModelChange)=\"setDraft(list, $event)\" (focus)=\"focusChips(list, $event)\" (keyup.enter)=\"addChip(list)\">\r\n <div class=\"cf-suggest\" *ngIf=\"openChips === list\">\r\n <div class=\"cf-suggest-item\" *ngFor=\"let u of suggestions(list)\" (click)=\"addSuggestion(list, u, $event)\">\r\n <span class=\"cf-chip-ini\">{{ u.i }}</span>\r\n <span class=\"cf-suggest-name\">{{ u.n }}</span>\r\n <span class=\"cf-suggest-mail\">{{ u.e }}</span>\r\n </div>\r\n <div class=\"cf-suggest-empty\" *ngIf=\"!suggestions(list).length\">\r\n {{ users.length ? 'No matching user' : 'No users for this client' }}\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Dropdown: styled like the prototype instead of the browser's native select -->\r\n <ng-template #dropdown let-key=\"key\" let-options=\"options\">\r\n <span class=\"cf-select\" [class.is-open]=\"openSelect === key\">\r\n <button type=\"button\" class=\"cf-select-btn\" (click)=\"toggleSelect(key, $event)\">\r\n {{ selectLabel(key, options) }}\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </button>\r\n <div class=\"cf-select-menu\" *ngIf=\"openSelect === key\">\r\n <div class=\"cf-select-item\" *ngFor=\"let o of options\" [class.is-on]=\"isPicked(key, o)\"\r\n (click)=\"pick(key, o, $event)\">{{ o.label }}</div>\r\n </div>\r\n </span>\r\n </ng-template>\r\n\r\n <div class=\"cf-body\" *ngIf=\"!loadError\">\r\n <!-- Section tree -->\r\n <aside class=\"cf-left\">\r\n <lib-audit-v2-shimmer *ngIf=\"loading\" [rows]=\"3\"></lib-audit-v2-shimmer>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n <div class=\"cf-left-title\">{{ auditName || 'Audit' }}</div>\r\n\r\n <div class=\"cf-hint\" *ngIf=\"!sections.length\">No questions yet</div>\r\n <ng-container *ngFor=\"let s of sections\">\r\n <div class=\"cf-section\" [class.is-open]=\"s.open\" (click)=\"toggleSection(s)\">\r\n {{ s.label }}\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" [class.rotate]=\"!s.open\">\r\n <polyline points=\"6 9 12 15 18 9\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"cf-items\" *ngIf=\"s.open && s.items.length\">\r\n <div *ngFor=\"let it of s.items\">{{ it }}</div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- No Schedule block (QA 10 Oct): audits have no one-time / repeat schedule here; visits come from Schedules. -->\r\n </ng-container>\r\n </aside>\r\n\r\n <!-- Configuration -->\r\n <div class=\"cf-right\">\r\n\r\n <section class=\"cf-card\" *ngIf=\"loading\">\r\n <lib-audit-v2-shimmer [rows]=\"4\"></lib-audit-v2-shimmer>\r\n </section>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n\r\n <!-- ===== Advance Configuration ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-head\">\r\n <span class=\"cf-block-title\">Advance Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </span>\r\n </div>\r\n\r\n <!-- Audit Owner -->\r\n <div>\r\n <div class=\"cf-label\">Audit Owner</div>\r\n <div class=\"cf-hint\">Owners get access to manage the audit</div>\r\n </div>\r\n <div class=\"cf-row\">\r\n <span class=\"cf-field\">Can be managed by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'owners', large: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Approver -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Approver</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"approverOn\" (click)=\"toggleApprover()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be able to approve the audit</div>\r\n <div class=\"cf-row\" *ngIf=\"approverOn\">\r\n <span class=\"cf-field\">To be approved by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'approvers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"approverError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ approverError }}\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so the {{ approvers.length }} approver{{ approvers.length === 1 ? '' : 's' }} added will be removed when you save. Turn Approver back on to keep {{ approvers.length === 1 ? 'it' : 'them' }}.\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && !approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so submitted audits are not sent for approval. Turn it on to add approvers or to send flags and reports to them.\r\n </div>\r\n\r\n <!-- Reminder -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Reminder</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"reminderOn\" (click)=\"toggleReminder()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be reminded in the selected interval</div>\r\n <div class=\"cf-inner\" *ngIf=\"reminderOn\">\r\n <div class=\"cf-inline\">\r\n Notify user before\r\n <span class=\"cf-reminder\" *ngFor=\"let m of reminders; let i = index\">\r\n <lib-audit-v2-select class=\"cf-reminder-select\" [value]=\"m\" [options]=\"reminderOpts[i] || []\" [searchable]=\"false\"\r\n [ariaLabel]=\"'Reminder ' + (i + 1) + ' in minutes'\" (changed)=\"setReminder(i, $event.target.value)\"></lib-audit-v2-select>\r\n <a class=\"cf-chip-x\" *ngIf=\"reminders.length > 1\" title=\"Remove reminder\" (click)=\"removeReminder(i)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <button type=\"button\" class=\"cf-icon-btn\" *ngIf=\"reminders.length < maxReminders\" title=\"Add reminder\" (click)=\"addReminder()\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>\r\n </button>\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Send alerts {{ reminderSummary }} mins before the audit end time\r\n </div>\r\n </div>\r\n\r\n <!-- Notify Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"notifyFlagsOn\" (click)=\"toggleNotifyFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, all flags will be sent as an email</div>\r\n <ng-container *ngIf=\"notifyFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !notifySendApprover\" (click)=\"toggleSendApprover('notifySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendApprover\">\r\n <svg *ngIf=\"notifySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"notifySendCustom = !notifySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendCustom\">\r\n <svg *ngIf=\"notifySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"notifySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'notifyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-error\" *ngIf=\"notifyFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ notifyFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Notify on Recurring Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify on Recurring Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"recurringFlagsOn\" (click)=\"toggleRecurringFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">When enabled, emails are sent for recurring flags based on the configured threshold</div>\r\n\r\n <div class=\"cf-inner\" *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-inline\">\r\n Send Email if the same question is flagged\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'recurringThreshold', options: thresholdOpts }\"></ng-container>\r\n times by the same store\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Once the threshold is reached and an email is sent, the flag count resets to zero\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !recurringSendApprover\" (click)=\"toggleSendApprover('recurringSendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendApprover\">\r\n <svg *ngIf=\"recurringSendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"toggleRecurringCustom()\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendCustom\">\r\n <svg *ngIf=\"recurringSendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n <label class=\"cf-check\" (click)=\"recurringSameAsNotify = !recurringSameAsNotify\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSameAsNotify\">\r\n <svg *ngIf=\"recurringSameAsNotify\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Use same users from Notify Flags\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"recurringSendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'recurringUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-info\" *ngIf=\"recurringSameAsNotify\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n {{ notifyRecipientsLabel }}\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"recurringFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ recurringFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Daily report -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Enable - Daily Report</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"dailyReportOn\" (click)=\"toggleDailyReport()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By Enabling, compliance score will be sent as an email to the above users</div>\r\n <ng-container *ngIf=\"dailyReportOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !dailySendApprover\" (click)=\"toggleSendApprover('dailySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendApprover\">\r\n <svg *ngIf=\"dailySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"dailySendCustom = !dailySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendCustom\">\r\n <svg *ngIf=\"dailySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"dailySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'dailyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <label class=\"cf-check\" (click)=\"sharePostApproval = !sharePostApproval\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"sharePostApproval\">\r\n <svg *ngIf=\"sharePostApproval\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Share Report Post Approval\r\n </label>\r\n <div class=\"cf-error\" *ngIf=\"dailyReportError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ dailyReportError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Export submission: Tango users only, as the v1 Configure (its stored value is kept for everyone else). -->\r\n <div class=\"cf-grid2\" *ngIf=\"access.isTango\">\r\n <div class=\"cf-stack cf-stack--tight\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Export Submission</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"exportSubmissionOn\" (click)=\"exportSubmissionOn = !exportSubmissionOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint\">Enable this to allow audit submitters to download their submission as a PDF file</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Redo validity -->\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Validity</div>\r\n <div class=\"cf-inline\">\r\n Redo valid for\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoValidFor', options: redoDayOpts }\"></ng-container>\r\n Day from Redo creation\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Auto create task -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Auto Create Task for Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"autoCreateTaskOn\" (click)=\"autoCreateTaskOn = !autoCreateTaskOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, a task is automatically created for every flagged question in the audit</div>\r\n\r\n <!-- Who gets the task and how long it stays open (as the Checklist Configure page) -->\r\n <div class=\"cf-autotask\" *ngIf=\"autoCreateTaskOn\">\r\n <div class=\"cf-autotask-title\">Task Assignee</div>\r\n <div class=\"cf-hint cf-hint--tight\">Choose who the flagged task is assigned to</div>\r\n <div class=\"cf-autotask-choices\">\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'submitter'\" (click)=\"taskAssignee = 'submitter'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'submitter'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Audit Submitter</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user who filled the audit</span>\r\n </span>\r\n </button>\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'store'\" (click)=\"taskAssignee = 'store'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'store'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Store User</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user mapped to the flagged store</span>\r\n </span>\r\n </button>\r\n </div>\r\n <div class=\"cf-autotask-title\">Task Validity</div>\r\n <div class=\"cf-autotask-validity\">\r\n <span>Task valid for</span>\r\n <lib-audit-v2-select class=\"cf-validity-select\" [(ngModel)]=\"taskValidity\" [options]=\"taskValidityOptions\"\r\n [searchable]=\"false\" ariaLabel=\"Task validity in days\"></lib-audit-v2-select>\r\n <span>days from task creation</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Audit Configuration ===== -->\r\n <div class=\"cf-divider-head\">\r\n <span class=\"cf-block-title\">Audit Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n </div>\r\n\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Submission & Visibility</div>\r\n\r\n <!-- cf-box--open: the dispute-window and response-delay menus must not be clipped by the box -->\r\n <div class=\"cf-box cf-box--open\">\r\n <div class=\"cf-box-row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"showResponseInApp\"\r\n (click)=\"showResponseInApp = !showResponseInApp\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Show Response in Mobile App</div>\r\n <div class=\"cf-hint\">By enabling this option, store users can view the audit response in the Mobile App.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sub\" *ngIf=\"showResponseInApp\">\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Response Visibility</div>\r\n <div class=\"cf-hint\">Choose when the response becomes visible to store users</div>\r\n </div>\r\n\r\n <div class=\"cf-options\">\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'pre'\" (click)=\"responseVisibility = 'pre'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'pre'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\">Pre-approval</div>\r\n <div class=\"cf-hint\">The audit response will be visible to store users before it is approved.</div>\r\n <div class=\"cf-inline cf-inline--top\">\r\n Show response\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'respDelay', options: respDelayOpts }\"></ng-container>\r\n after submission\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'post'\" (click)=\"responseVisibility = 'post'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'post'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\" [class.cf-muted]=\"responseVisibility !== 'post'\">Post-approval</div>\r\n <div class=\"cf-hint\">Once the response is approved, it will automatically be displayed in the Mobile App. Store users cannot raise a dispute.</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sep\">\r\n <ng-container *ngIf=\"responseVisibility === 'pre'\">\r\n <div class=\"cf-box-row cf-box-row--flush\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"disputeOn\" (click)=\"disputeOn = !disputeOn\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Dispute Configuration</div>\r\n <div class=\"cf-hint cf-hint--wrap\">When enabled, the store team can raise a dispute against the auditor's submission once the response becomes visible to them.</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--nested\" *ngIf=\"disputeOn\">\r\n <div class=\"cf-inline\">\r\n Dispute window\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'disputeWindow', options: dispWindowOpts }\"></ng-container>\r\n from when the response becomes visible\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes raised inside this window go to the approver. Approved disputes revise the answer and the compliance score.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"!hasApprovers\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n No approver is set, so no one can review disputes. Turn on Approver and add an approver.\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"responseVisibility === 'post'\">\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm cf-muted\">Dispute Configuration</div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes are not available when responses are shown post-approval.\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Pre-submission access -->\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pre-Submission Access</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"preSubmissionAccessOn\" (click)=\"preSubmissionAccessOn = !preSubmissionAccessOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Users added here can view Open and In Progress audits until submission. The Schedule Info tab is also visible only to these users.</div>\r\n <ng-container *ngIf=\"preSubmissionAccessOn\">\r\n <div class=\"cf-row cf-row--top\">\r\n <span class=\"cf-field\">Visible to</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'preSubmissionUsers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error cf-error--indent\" *ngIf=\"preSubmissionEmpty\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n Add at least one user\r\n </div>\r\n </ng-container>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Scoring ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Scoring</div>\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pass/Fail Score Setup</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"passFailOn\" (click)=\"passFailOn = !passFailOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Set the compliance score an audit must reach to be marked {{ passLabel }}. Anything below it is marked {{ failLabel }}.</div>\r\n <div class=\"cf-row cf-row--wrap cf-row--top\" *ngIf=\"passFailOn\">\r\n <span class=\"cf-field\">Minimum score to {{ passLabel }}</span>\r\n <label class=\"cf-num\">\r\n <input type=\"number\" min=\"1\" max=\"100\" [(ngModel)]=\"passThreshold\">\r\n <span>%</span>\r\n </label>\r\n <span class=\"cf-pill cf-pill--pass\">{{ passLabel }} \u2265 {{ passThreshold }}%</span>\r\n <span class=\"cf-pill cf-pill--fail\">{{ failLabel }} < {{ passThreshold }}%</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Approver Controls ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Approver Controls</div>\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Edit Submitted Audit</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"editSubmittedOn\" (click)=\"toggleEditSubmitted()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">Allow Approvers to edit submitted Audit</div>\r\n <ng-container *ngIf=\"editSubmittedOn\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'editUsers', large: true }\"></ng-container>\r\n <div class=\"cf-error\" *ngIf=\"editSubmittedError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ editSubmittedError }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Extension</div>\r\n <div class=\"cf-inline\">\r\n Extend redo up to\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoExtension', options: redoExtensionOpts }\"></ng-container>\r\n Days till approval\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== User Verification ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-title\">User Verification Configuration</div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requirePhoto\" (click)=\"requirePhoto = !requirePhoto\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require Photo Capture</div>\r\n <div class=\"cf-hint\">By enabling, users must capture their photo to complete submission</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requireAcknowledgment\" (click)=\"requireAcknowledgment = !requireAcknowledgment\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require User Acknowledgment</div>\r\n <div class=\"cf-hint\">By enabling, users must type their name as acknowledgment to complete submission</div>\r\n </div>\r\n </div>\r\n </section>\r\n </ng-container>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}.cf-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.cf-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.cf-crumb{font-size:13px;line-height:20px;color:#667085}.cf-crumb a{font-weight:600;color:#00a3ff}.cf-header{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px 20px;display:flex;align-items:center;gap:12px}.cf-header-text{display:flex;flex-direction:column;gap:4px;min-width:0}.cf-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.cf-sk-title{margin:3px 0}.cf-desc{border:none;outline:none;padding:0;background:transparent;font-family:inherit;font-size:13px;line-height:18px;color:#344054;min-width:320px}.cf-desc::placeholder{color:#98a2b3}.cf-publish{padding:0 20px;box-shadow:0 1px 2px #1018280d}.cf-draft{padding:0 18px;box-shadow:inset 0 0 0 1px #d0d5dd,0 1px 2px #1018280d}.cf-body{display:flex;gap:16px;align-items:flex-start}.cf-left{width:300px;flex-shrink:0;background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px;display:flex;flex-direction:column;gap:10px;position:sticky;top:calc(var(--bs-app-header-height, 0px) + 16px);max-height:calc(100vh - var(--bs-app-header-height, 0px) - 32px);overflow-y:auto;scrollbar-width:thin}.cf-left-title{font-size:14px;line-height:20px;font-weight:600;color:#101828}.cf-section{display:flex;align-items:center;gap:8px;padding:2px 0;font-size:13px;font-weight:500;color:#344054;cursor:pointer;white-space:nowrap}.cf-section.is-open{color:#1d2939}.cf-rule{flex:1;border-top:1px solid #EAECF0}.cf-chev{display:flex;color:#98a2b3}.cf-chev svg{transition:transform .15s cubic-bezier(.4,0,.2,1)}.cf-chev .rotate{transform:rotate(-90deg)}.cf-items{display:flex;flex-direction:column;gap:8px;padding-left:12px;font-size:13px;color:#475467}.cf-schedule-title{font-size:14px;font-weight:600;color:#101828;margin-top:6px}.cf-schedule{display:flex;flex-direction:column;gap:6px;font-size:13px;color:#475467}.cf-schedule>div{display:flex;align-items:center;gap:6px}.cf-right{flex:1;min-width:0;display:flex;flex-direction:column;gap:16px}.cf-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px;display:flex;flex-direction:column;gap:14px}.cf-card--lg{border-radius:8px}.cf-block-head{display:flex;align-items:center;gap:12px}.cf-block-title{font-size:15px;font-weight:600;color:#101828}.cf-divider-head{display:flex;align-items:center;gap:10px;margin-top:4px}.cf-label{font-size:14px;font-weight:600;color:#101828}.cf-label-sm{font-size:13px;font-weight:600;color:#101828}.cf-muted{color:#667085}.cf-hint{font-size:12px;line-height:18px;color:#667085}.cf-hint--tight{margin-top:-8px}.cf-hint--wrap{max-width:640px;text-wrap:pretty}.cf-field{font-size:13px;font-weight:500;color:#344054;min-width:150px;flex-shrink:0}.cf-row{display:flex;align-items:center;gap:12px}.cf-row--top{margin-top:6px}.cf-row--wrap{flex-wrap:wrap}.cf-stack{display:flex;flex-direction:column;gap:8px}.cf-stack--tight,.cf-stack--sm{gap:4px}.cf-stack--xs{gap:2px}.cf-grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.cf-toggle-row{display:flex;align-items:center;gap:10px}.cf-switch{width:36px;height:20px;padding:2px;border:none;border-radius:9999px;background:#eaecf0;display:flex;align-items:center;justify-content:flex-start;flex-shrink:0;cursor:pointer;transition:background .15s cubic-bezier(.4,0,.2,1)}.cf-switch>span{width:16px;height:16px;border-radius:9999px;background:#fff;box-shadow:0 1px 2px #1018280d}.cf-switch.is-on{background:#00a3ff;justify-content:flex-end}.cf-switch--top{margin-top:2px}.cf-chipbox{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:8px 10px}.cf-chipbox--lg{gap:8px;padding:10px 12px}.cf-chip{display:flex;align-items:center;gap:6px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;border-radius:9999px;padding:3px 8px;font-size:12px;color:#344054;white-space:nowrap;flex-shrink:0;max-width:100%}.cf-chip--lg{gap:8px;background:#fff;padding:5px 11px;font-size:13px;color:#1d2939}.cf-chip-ini{color:#00a3ff;font-weight:600;font-size:11px}.cf-chip-tag{display:inline-flex;align-items:center;justify-content:center;padding:1px 5px;border-radius:6px;background:#eaf8ff;color:#00a3ff;font-weight:700;font-size:11px;letter-spacing:.02em}.cf-chip-x{display:flex;cursor:pointer;color:#98a2b3}.cf-chip-x:hover{color:#344054}.cf-chip-input{flex:1;min-width:100px;border:none;outline:none;background:transparent;font-family:inherit;font-size:12px;color:#101828}.cf-chip-input::placeholder{color:#98a2b3}.cf-chip-input--lg{min-width:120px;font-size:13px}.cf-inner{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:14px 16px;display:flex;flex-direction:column;gap:8px}.cf-inline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-inline--top{margin-top:2px}.cf-mini{height:32px;padding:0 28px 0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 8px center;outline:none}.cf-info{display:flex;align-items:center;gap:6px;font-size:12px;line-height:18px;color:#667085}.cf-info svg{flex-shrink:0}.cf-info--wrap{align-items:flex-start;max-width:560px;text-wrap:pretty}.cf-info--wrap svg{margin-top:3px}.cf-checks{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-checks-label{font-weight:500}.cf-check{display:flex;align-items:center;gap:6px;margin:0;font-size:13px;color:#344054;cursor:pointer;-webkit-user-select:none;user-select:none}.cf-check-box{width:16px;height:16px;border-radius:4px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center;color:#fff;flex-shrink:0}.cf-check-box.is-on{background:#00a3ff;box-shadow:none}.cf-box{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden;display:flex;flex-direction:column}.cf-box--pad{padding:14px 16px;gap:6px;overflow:visible}.cf-box--row{padding:14px 16px;flex-direction:row;align-items:flex-start;gap:12px}.cf-box--nested{background:#fff;padding:12px 14px;gap:8px;margin-left:46px;overflow:visible}.cf-box--open{overflow:visible}.cf-box--open>.cf-box-sub:last-child{border-radius:0 0 8px 8px}.cf-box-row{padding:14px 16px;display:flex;align-items:flex-start;gap:12px}.cf-box-row--flush{padding:0;gap:10px}.cf-box-sub{border-top:1px solid #EAECF0;background:#f9fafb;padding:16px 16px 18px 64px;display:flex;flex-direction:column;gap:12px}.cf-options{display:flex;flex-direction:column;gap:10px}.cf-option{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;cursor:pointer}.cf-option.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.cf-box-sep{display:flex;flex-direction:column;gap:12px;padding-top:14px;border-top:1px solid #EAECF0}.cf-num{display:flex;align-items:center;gap:8px;height:36px;padding:0 6px 0 12px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;margin:0}.cf-num input{width:52px;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;font-weight:600;color:#101828}.cf-num span{font-size:13px;color:#667085;padding-right:6px}.cf-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;border-radius:9999px;padding:4px 12px}.cf-pill--pass{background:#ecfdf3;color:#027a48}.cf-pill--fail{background:#fef3f2;color:#d92d20}.cf-error{display:flex;gap:6px;font-size:12px;font-weight:500;color:#d92d20;align-items:flex-start;line-height:18px;max-width:640px}.cf-error svg{flex-shrink:0;margin-top:3px}.cf-error--indent{margin-left:162px}.cf-check.is-blocked{color:#98a2b3;cursor:not-allowed}.cf-select{position:relative;display:inline-block;vertical-align:middle}.cf-select-btn{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 10px 0 12px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;white-space:nowrap}.cf-select-btn svg{color:#667085;transition:transform .15s ease}.is-open .cf-select-btn{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.is-open .cf-select-btn svg{transform:rotate(180deg)}.cf-select-menu{position:absolute;top:calc(100% + 4px);left:0;z-index:30;min-width:100%;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-select-item{padding:8px 12px;border-radius:6px;font-size:13px;color:#344054;white-space:nowrap;cursor:pointer}.cf-select-item:hover{background:#f9fafb}.cf-select-item.is-on{background:#eaf8ff;color:#009bf3;font-weight:600}.cf-chipbox{position:relative}.cf-chipbox.is-open{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.cf-suggest{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;max-height:260px;overflow-y:auto;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-suggest-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer}.cf-suggest-item:hover{background:#f9fafb}.cf-suggest-name{font-size:13px;color:#101828}.cf-suggest-mail{font-size:12px;color:#667085;margin-left:auto}.cf-suggest-empty{padding:8px 10px;font-size:12px;color:#667085}.cf-error--page{margin:0 0 12px}.cf-autotask{margin-top:12px;padding:14px 16px;border-radius:10px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column;gap:8px}.cf-autotask-title{font-size:14px;font-weight:600;color:#1d2939}.cf-autotask-title:not(:first-child){margin-top:6px}.cf-autotask-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}@media (max-width: 720px){.cf-autotask-choices{grid-template-columns:1fr}}.cf-choice{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;text-align:left;cursor:pointer}.cf-choice.is-on{background:#f5faff;box-shadow:inset 0 0 0 1px #66c8ff}.cf-radio{width:18px;height:18px;flex-shrink:0;margin-top:1px;border-radius:9999px;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center}.cf-radio span{width:8px;height:8px;border-radius:9999px;background:transparent}.cf-radio.is-on{box-shadow:inset 0 0 0 1px #1570ef}.cf-radio.is-on span{background:#1570ef}.cf-choice-text{display:flex;flex-direction:column;gap:2px;min-width:0}.cf-choice-title{font-size:14px;font-weight:600;color:#101828}.cf-choice-sub{font-size:12px;color:#667085}.cf-autotask-validity{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:13px;color:#344054}.cf-validity-select{width:96px}.cf-reminder{display:inline-flex;align-items:center;gap:6px}.cf-reminder-select{width:120px}.cf-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;cursor:pointer}.cf-icon-btn:hover{background:#f9fafb}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SelectComponent, selector: "lib-audit-v2-select", inputs: ["options", "placeholder", "searchable", "ariaLabel", "disabled", "value"], outputs: ["changed"] }] });
|
|
10389
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AuditV2ConfigureComponent, selector: "lib-audit-v2-configure", host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "<div class=\"av2-page audit-configure\">\r\n\r\n <!-- Back + breadcrumb (as the schedule editor's back bar) -->\r\n <div class=\"cf-backbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm cf-back\" (click)=\"back()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\r\n {{ backLabel }}\r\n </button>\r\n <div class=\"cf-crumb\">\r\n <a href=\"#\" (click)=\"back($event)\">Manage Audit</a> \u203A Configure\r\n </div>\r\n </div>\r\n\r\n <!-- Title + actions -->\r\n <div class=\"cf-header\">\r\n <div class=\"cf-header-text\">\r\n <span class=\"av2-sk av2-sk--title cf-sk-title\" *ngIf=\"loading\"></span>\r\n <div class=\"cf-title\" *ngIf=\"!loading\">{{ auditName || 'Audit' }}</div>\r\n <input type=\"text\" class=\"cf-desc\" placeholder=\"Enter Audit Description\" [(ngModel)]=\"description\">\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary cf-publish\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason || publishBlockedReason\" (click)=\"publish()\">\r\n {{ saving ? 'Saving\u2026' : (published ? 'Save & Publish' : 'Publish') }}\r\n </button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost cf-draft\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason\" (click)=\"saveDraft()\">Save as Draft</button>\r\n </div>\r\n\r\n <div class=\"cf-error cf-error--page\" *ngIf=\"loadError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ loadError }}\r\n </div>\r\n\r\n <!-- Chip picker: chips + input + suggestion list (one template, used for every user list) -->\r\n <ng-template #chipPicker let-list=\"list\" let-large=\"large\">\r\n <div class=\"cf-chipbox\" [class.cf-chipbox--lg]=\"large\" [class.is-open]=\"openChips === list\" (click)=\"focusChips(list, $event)\">\r\n <span class=\"cf-chip\" [class.cf-chip--lg]=\"large\" *ngFor=\"let u of chipsOf(list); let i = index\" [title]=\"u.e\">\r\n <span [class]=\"large ? 'cf-chip-tag' : 'cf-chip-ini'\">{{ u.i }}</span>{{ u.n }}\r\n <a class=\"cf-chip-x\" (click)=\"removeChip(list, i); $event.stopPropagation()\">\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <input type=\"text\" class=\"cf-chip-input\" [class.cf-chip-input--lg]=\"large\" placeholder=\"Add user...\"\r\n [ngModel]=\"draftOf(list)\" (ngModelChange)=\"setDraft(list, $event)\" (focus)=\"focusChips(list, $event)\" (keyup.enter)=\"addChip(list)\">\r\n <div class=\"cf-suggest\" *ngIf=\"openChips === list\">\r\n <div class=\"cf-suggest-item\" *ngFor=\"let u of suggestions(list)\" (click)=\"addSuggestion(list, u, $event)\">\r\n <span class=\"cf-chip-ini\">{{ u.i }}</span>\r\n <span class=\"cf-suggest-name\">{{ u.n }}</span>\r\n <span class=\"cf-suggest-mail\">{{ u.e }}</span>\r\n </div>\r\n <div class=\"cf-suggest-empty\" *ngIf=\"!suggestions(list).length\">\r\n {{ users.length ? 'No matching user' : 'No users for this client' }}\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Dropdown: styled like the prototype instead of the browser's native select -->\r\n <ng-template #dropdown let-key=\"key\" let-options=\"options\">\r\n <span class=\"cf-select\" [class.is-open]=\"openSelect === key\">\r\n <button type=\"button\" class=\"cf-select-btn\" (click)=\"toggleSelect(key, $event)\">\r\n {{ selectLabel(key, options) }}\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </button>\r\n <div class=\"cf-select-menu\" *ngIf=\"openSelect === key\">\r\n <div class=\"cf-select-item\" *ngFor=\"let o of options\" [class.is-on]=\"isPicked(key, o)\"\r\n (click)=\"pick(key, o, $event)\">{{ o.label }}</div>\r\n </div>\r\n </span>\r\n </ng-template>\r\n\r\n <div class=\"cf-body\" *ngIf=\"!loadError\">\r\n <!-- Section tree -->\r\n <aside class=\"cf-left\">\r\n <lib-audit-v2-shimmer *ngIf=\"loading\" [rows]=\"3\"></lib-audit-v2-shimmer>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n <div class=\"cf-left-title\">{{ auditName || 'Audit' }}</div>\r\n\r\n <div class=\"cf-hint\" *ngIf=\"!sections.length\">No questions yet</div>\r\n <ng-container *ngFor=\"let s of sections\">\r\n <div class=\"cf-section\" [class.is-open]=\"s.open\" (click)=\"toggleSection(s)\">\r\n {{ s.label }}\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" [class.rotate]=\"!s.open\">\r\n <polyline points=\"6 9 12 15 18 9\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"cf-items\" *ngIf=\"s.open && s.items.length\">\r\n <div *ngFor=\"let it of s.items\">{{ it }}</div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- No Schedule block (QA 10 Oct): audits have no one-time / repeat schedule here; visits come from Schedules. -->\r\n </ng-container>\r\n </aside>\r\n\r\n <!-- Configuration -->\r\n <div class=\"cf-right\">\r\n\r\n <section class=\"cf-card\" *ngIf=\"loading\">\r\n <lib-audit-v2-shimmer [rows]=\"4\"></lib-audit-v2-shimmer>\r\n </section>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n\r\n <!-- ===== Advance Configuration ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-head\">\r\n <span class=\"cf-block-title\">Advance Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </span>\r\n </div>\r\n\r\n <!-- Audit Owner -->\r\n <div>\r\n <div class=\"cf-label\">Audit Owner</div>\r\n <div class=\"cf-hint\">Owners get access to manage the audit</div>\r\n </div>\r\n <div class=\"cf-row\">\r\n <span class=\"cf-field\">Can be managed by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'owners', large: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Approver -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Approver</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"approverOn\" (click)=\"toggleApprover()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be able to approve the audit</div>\r\n <div class=\"cf-row\" *ngIf=\"approverOn\">\r\n <span class=\"cf-field\">To be approved by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'approvers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"approverError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ approverError }}\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so the {{ approvers.length }} approver{{ approvers.length === 1 ? '' : 's' }} added will be removed when you save. Turn Approver back on to keep {{ approvers.length === 1 ? 'it' : 'them' }}.\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && !approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so submitted audits are not sent for approval. Turn it on to add approvers or to send flags and reports to them.\r\n </div>\r\n\r\n <!-- Reminder -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Reminder</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"reminderOn\" (click)=\"toggleReminder()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be reminded in the selected interval</div>\r\n <div class=\"cf-inner\" *ngIf=\"reminderOn\">\r\n <div class=\"cf-inline\">\r\n Notify user before\r\n <span class=\"cf-reminder\" *ngFor=\"let m of reminders; let i = index\">\r\n <lib-audit-v2-select class=\"cf-reminder-select\" [value]=\"m\" [options]=\"reminderOpts[i] || []\" [searchable]=\"false\"\r\n [ariaLabel]=\"'Reminder ' + (i + 1) + ' in minutes'\" (changed)=\"setReminder(i, $event.target.value)\"></lib-audit-v2-select>\r\n <a class=\"cf-chip-x\" *ngIf=\"reminders.length > 1\" title=\"Remove reminder\" (click)=\"removeReminder(i)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <button type=\"button\" class=\"cf-icon-btn\" *ngIf=\"reminders.length < maxReminders\" title=\"Add reminder\" (click)=\"addReminder()\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>\r\n </button>\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Send alerts {{ reminderSummary }} mins before the audit end time\r\n </div>\r\n </div>\r\n\r\n <!-- Notify Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"notifyFlagsOn\" (click)=\"toggleNotifyFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, all flags will be sent as an email</div>\r\n <ng-container *ngIf=\"notifyFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !notifySendApprover\" (click)=\"toggleSendApprover('notifySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendApprover\">\r\n <svg *ngIf=\"notifySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"notifySendCustom = !notifySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendCustom\">\r\n <svg *ngIf=\"notifySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"notifySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'notifyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-error\" *ngIf=\"notifyFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ notifyFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Notify on Recurring Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify on Recurring Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"recurringFlagsOn\" (click)=\"toggleRecurringFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">When enabled, emails are sent for recurring flags based on the configured threshold</div>\r\n\r\n <div class=\"cf-inner\" *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-inline\">\r\n Send Email if the same question is flagged\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'recurringThreshold', options: thresholdOpts }\"></ng-container>\r\n times by the same store\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Once the threshold is reached and an email is sent, the flag count resets to zero\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !recurringSendApprover\" (click)=\"toggleSendApprover('recurringSendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendApprover\">\r\n <svg *ngIf=\"recurringSendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"toggleRecurringCustom()\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendCustom\">\r\n <svg *ngIf=\"recurringSendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n <label class=\"cf-check\" (click)=\"recurringSameAsNotify = !recurringSameAsNotify\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSameAsNotify\">\r\n <svg *ngIf=\"recurringSameAsNotify\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Use same users from Notify Flags\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"recurringSendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'recurringUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-info\" *ngIf=\"recurringSameAsNotify\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n {{ notifyRecipientsLabel }}\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"recurringFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ recurringFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Daily report -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Enable - Daily Report</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"dailyReportOn\" (click)=\"toggleDailyReport()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By Enabling, compliance score will be sent as an email to the above users</div>\r\n <ng-container *ngIf=\"dailyReportOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !dailySendApprover\" (click)=\"toggleSendApprover('dailySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendApprover\">\r\n <svg *ngIf=\"dailySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"dailySendCustom = !dailySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendCustom\">\r\n <svg *ngIf=\"dailySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"dailySendCustom\">\r\n <div class=\"cf-bulkbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"openDailyBulk()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.67\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.5 12.5V15.8333C17.5 16.2754 17.3244 16.6993 17.0118 17.0118C16.6993 17.3244 16.2754 17.5 15.8333 17.5H4.16667C3.72464 17.5 3.30072 17.3244 2.98816 17.0118C2.67559 16.6993 2.5 16.2754 2.5 15.8333V12.5M14.1667 6.66667L10 2.5M10 2.5L5.83333 6.66667M10 2.5V12.5\"></path></svg>\r\n Bulk Upload\r\n </button>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'dailyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <label class=\"cf-check\" (click)=\"sharePostApproval = !sharePostApproval\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"sharePostApproval\">\r\n <svg *ngIf=\"sharePostApproval\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Share Report Post Approval\r\n </label>\r\n <div class=\"cf-error\" *ngIf=\"dailyReportError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ dailyReportError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Export submission: Tango users only, as the v1 Configure (its stored value is kept for everyone else). -->\r\n <div class=\"cf-grid2\" *ngIf=\"access.isTango\">\r\n <div class=\"cf-stack cf-stack--tight\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Export Submission</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"exportSubmissionOn\" (click)=\"exportSubmissionOn = !exportSubmissionOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint\">Enable this to allow audit submitters to download their submission as a PDF file</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Redo validity -->\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Validity</div>\r\n <div class=\"cf-inline\">\r\n Redo valid for\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoValidFor', options: redoDayOpts }\"></ng-container>\r\n Day from Redo creation\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Auto create task -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Auto Create Task for Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"autoCreateTaskOn\" (click)=\"autoCreateTaskOn = !autoCreateTaskOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, a task is automatically created for every flagged question in the audit</div>\r\n\r\n <!-- Who gets the task and how long it stays open (as the Checklist Configure page) -->\r\n <div class=\"cf-autotask\" *ngIf=\"autoCreateTaskOn\">\r\n <div class=\"cf-autotask-title\">Task Assignee</div>\r\n <div class=\"cf-hint cf-hint--tight\">Choose who the flagged task is assigned to</div>\r\n <div class=\"cf-autotask-choices\">\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'submitter'\" (click)=\"taskAssignee = 'submitter'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'submitter'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Audit Submitter</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user who filled the audit</span>\r\n </span>\r\n </button>\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'store'\" (click)=\"taskAssignee = 'store'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'store'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Store User</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user mapped to the flagged store</span>\r\n </span>\r\n </button>\r\n </div>\r\n <div class=\"cf-autotask-title\">Task Validity</div>\r\n <div class=\"cf-autotask-validity\">\r\n <span>Task valid for</span>\r\n <lib-audit-v2-select class=\"cf-validity-select\" [(ngModel)]=\"taskValidity\" [options]=\"taskValidityOptions\"\r\n [searchable]=\"false\" ariaLabel=\"Task validity in days\"></lib-audit-v2-select>\r\n <span>days from task creation</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Audit Configuration ===== -->\r\n <div class=\"cf-divider-head\">\r\n <span class=\"cf-block-title\">Audit Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n </div>\r\n\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Submission & Visibility</div>\r\n\r\n <!-- cf-box--open: the dispute-window and response-delay menus must not be clipped by the box -->\r\n <div class=\"cf-box cf-box--open\">\r\n <div class=\"cf-box-row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"showResponseInApp\"\r\n (click)=\"showResponseInApp = !showResponseInApp\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Show Response in Mobile App</div>\r\n <div class=\"cf-hint\">By enabling this option, store users can view the audit response in the Mobile App.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sub\" *ngIf=\"showResponseInApp\">\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Response Visibility</div>\r\n <div class=\"cf-hint\">Choose when the response becomes visible to store users</div>\r\n </div>\r\n\r\n <div class=\"cf-options\">\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'pre'\" (click)=\"responseVisibility = 'pre'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'pre'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\">Pre-approval</div>\r\n <div class=\"cf-hint\">The audit response will be visible to store users before it is approved.</div>\r\n <div class=\"cf-inline cf-inline--top\">\r\n Show response\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'respDelay', options: respDelayOpts }\"></ng-container>\r\n after submission\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'post'\" (click)=\"responseVisibility = 'post'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'post'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\" [class.cf-muted]=\"responseVisibility !== 'post'\">Post-approval</div>\r\n <div class=\"cf-hint\">Once the response is approved, it will automatically be displayed in the Mobile App. Store users cannot raise a dispute.</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sep\">\r\n <ng-container *ngIf=\"responseVisibility === 'pre'\">\r\n <div class=\"cf-box-row cf-box-row--flush\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"disputeOn\" (click)=\"disputeOn = !disputeOn\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Dispute Configuration</div>\r\n <div class=\"cf-hint cf-hint--wrap\">When enabled, the store team can raise a dispute against the auditor's submission once the response becomes visible to them.</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--nested\" *ngIf=\"disputeOn\">\r\n <div class=\"cf-inline\">\r\n Dispute window\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'disputeWindow', options: dispWindowOpts }\"></ng-container>\r\n from when the response becomes visible\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes raised inside this window go to the approver. Approved disputes revise the answer and the compliance score.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"!hasApprovers\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n No approver is set, so no one can review disputes. Turn on Approver and add an approver.\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"responseVisibility === 'post'\">\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm cf-muted\">Dispute Configuration</div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes are not available when responses are shown post-approval.\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Pre-submission access -->\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pre-Submission Access</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"preSubmissionAccessOn\" (click)=\"preSubmissionAccessOn = !preSubmissionAccessOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Users added here can view Open and In Progress audits until submission. The Schedule Info tab is also visible only to these users.</div>\r\n <ng-container *ngIf=\"preSubmissionAccessOn\">\r\n <div class=\"cf-row cf-row--top\">\r\n <span class=\"cf-field\">Visible to</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'preSubmissionUsers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error cf-error--indent\" *ngIf=\"preSubmissionEmpty\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n Add at least one user\r\n </div>\r\n </ng-container>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Scoring ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Scoring</div>\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pass/Fail Score Setup</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"passFailOn\" (click)=\"passFailOn = !passFailOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Set the compliance score an audit must reach to be marked {{ passLabel }}. Anything below it is marked {{ failLabel }}.</div>\r\n <div class=\"cf-row cf-row--wrap cf-row--top\" *ngIf=\"passFailOn\">\r\n <span class=\"cf-field\">Minimum score to {{ passLabel }}</span>\r\n <label class=\"cf-num\">\r\n <input type=\"number\" min=\"1\" max=\"100\" [(ngModel)]=\"passThreshold\">\r\n <span>%</span>\r\n </label>\r\n <span class=\"cf-pill cf-pill--pass\">{{ passLabel }} \u2265 {{ passThreshold }}%</span>\r\n <span class=\"cf-pill cf-pill--fail\">{{ failLabel }} < {{ passThreshold }}%</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Approver Controls ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Approver Controls</div>\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Edit Submitted Audit</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"editSubmittedOn\" (click)=\"toggleEditSubmitted()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">Allow Approvers to edit submitted Audit</div>\r\n <ng-container *ngIf=\"editSubmittedOn\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'editUsers', large: true }\"></ng-container>\r\n <div class=\"cf-error\" *ngIf=\"editSubmittedError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ editSubmittedError }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Extension</div>\r\n <div class=\"cf-inline\">\r\n Extend redo up to\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoExtension', options: redoExtensionOpts }\"></ng-container>\r\n Days till approval\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== User Verification ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-title\">User Verification Configuration</div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requirePhoto\" (click)=\"requirePhoto = !requirePhoto\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require Photo Capture</div>\r\n <div class=\"cf-hint\">By enabling, users must capture their photo to complete submission</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requireAcknowledgment\" (click)=\"requireAcknowledgment = !requireAcknowledgment\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require User Acknowledgment</div>\r\n <div class=\"cf-hint\">By enabling, users must type their name as acknowledgment to complete submission</div>\r\n </div>\r\n </div>\r\n </section>\r\n </ng-container>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Daily Report > Custom: bulk upload users (as the Checklist Configure page's popup) -->\r\n <ng-container *ngIf=\"dailyBulkOpen\">\r\n <div class=\"cf-dlg-backdrop\" (click)=\"closeDailyBulk()\"></div>\r\n <div class=\"cf-dlg\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"cf-dlg-title\">\r\n <span class=\"cf-dlg-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.67\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.5 12.5V15.8333C17.5 16.2754 17.3244 16.6993 17.0118 17.0118C16.6993 17.3244 16.2754 17.5 15.8333 17.5H4.16667C3.72464 17.5 3.30072 17.3244 2.98816 17.0118C2.67559 16.6993 2.5 16.2754 2.5 15.8333V12.5M14.1667 6.66667L10 2.5M10 2.5L5.83333 6.66667M10 2.5V12.5\"></path></svg>\r\n </span>\r\n <div class=\"cf-dlg-title\" id=\"cf-dlg-title\">Bulk Upload</div>\r\n <div class=\"cf-dlg-steps\">\r\n <div>Step 1 - <a href=\"#\" (click)=\"$event.preventDefault(); downloadDailyTemplate()\">Download the template here</a></div>\r\n <div>Step 2 - Add the Email of existing users to the template</div>\r\n <div>Step 3 - Upload it below for processing</div>\r\n </div>\r\n <div class=\"cf-dlg-note\">\r\n **Note : Only the Email column is considered - the Username is taken from the existing user list.\r\n Only existing users of this client are accepted. On upload, all the existing data will be replaced.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"dailyBulkErrors.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n <div class=\"cf-dlg-errors\">\r\n <div>The file was not uploaded. Fix {{ dailyBulkErrors.length === 1 ? 'this row' : 'these rows' }} and upload again:</div>\r\n <div *ngFor=\"let e of dailyBulkErrors.slice(0, 5)\">{{ e }}</div>\r\n <div *ngIf=\"dailyBulkErrors.length > 5\">+{{ dailyBulkErrors.length - 5 }} more</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-dlg-foot\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"closeDailyBulk()\">Cancel</button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" (click)=\"dailyBulkFile.click()\">Upload</button>\r\n <input #dailyBulkFile type=\"file\" accept=\".xlsx\" hidden (change)=\"onDailyBulkFile($event)\">\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}.cf-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.cf-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.cf-crumb{font-size:13px;line-height:20px;color:#667085}.cf-crumb a{font-weight:600;color:#00a3ff}.cf-header{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px 20px;display:flex;align-items:center;gap:12px}.cf-header-text{display:flex;flex-direction:column;gap:4px;min-width:0}.cf-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.cf-sk-title{margin:3px 0}.cf-desc{border:none;outline:none;padding:0;background:transparent;font-family:inherit;font-size:13px;line-height:18px;color:#344054;min-width:320px}.cf-desc::placeholder{color:#98a2b3}.cf-publish{padding:0 20px;box-shadow:0 1px 2px #1018280d}.cf-draft{padding:0 18px;box-shadow:inset 0 0 0 1px #d0d5dd,0 1px 2px #1018280d}.cf-body{display:flex;gap:16px;align-items:flex-start}.cf-left{width:300px;flex-shrink:0;background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px;display:flex;flex-direction:column;gap:10px;position:sticky;top:calc(var(--bs-app-header-height, 0px) + 16px);max-height:calc(100vh - var(--bs-app-header-height, 0px) - 32px);overflow-y:auto;scrollbar-width:thin}.cf-left-title{font-size:14px;line-height:20px;font-weight:600;color:#101828}.cf-section{display:flex;align-items:center;gap:8px;padding:2px 0;font-size:13px;font-weight:500;color:#344054;cursor:pointer;white-space:nowrap}.cf-section.is-open{color:#1d2939}.cf-rule{flex:1;border-top:1px solid #EAECF0}.cf-chev{display:flex;color:#98a2b3}.cf-chev svg{transition:transform .15s cubic-bezier(.4,0,.2,1)}.cf-chev .rotate{transform:rotate(-90deg)}.cf-items{display:flex;flex-direction:column;gap:8px;padding-left:12px;font-size:13px;color:#475467}.cf-schedule-title{font-size:14px;font-weight:600;color:#101828;margin-top:6px}.cf-schedule{display:flex;flex-direction:column;gap:6px;font-size:13px;color:#475467}.cf-schedule>div{display:flex;align-items:center;gap:6px}.cf-right{flex:1;min-width:0;display:flex;flex-direction:column;gap:16px}.cf-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px;display:flex;flex-direction:column;gap:14px}.cf-card--lg{border-radius:8px}.cf-block-head{display:flex;align-items:center;gap:12px}.cf-block-title{font-size:15px;font-weight:600;color:#101828}.cf-divider-head{display:flex;align-items:center;gap:10px;margin-top:4px}.cf-label{font-size:14px;font-weight:600;color:#101828}.cf-label-sm{font-size:13px;font-weight:600;color:#101828}.cf-muted{color:#667085}.cf-hint{font-size:12px;line-height:18px;color:#667085}.cf-hint--tight{margin-top:-8px}.cf-hint--wrap{max-width:640px;text-wrap:pretty}.cf-field{font-size:13px;font-weight:500;color:#344054;min-width:150px;flex-shrink:0}.cf-row{display:flex;align-items:center;gap:12px}.cf-row--top{margin-top:6px}.cf-row--wrap{flex-wrap:wrap}.cf-stack{display:flex;flex-direction:column;gap:8px}.cf-stack--tight,.cf-stack--sm{gap:4px}.cf-stack--xs{gap:2px}.cf-grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.cf-toggle-row{display:flex;align-items:center;gap:10px}.cf-switch{width:36px;height:20px;padding:2px;border:none;border-radius:9999px;background:#eaecf0;display:flex;align-items:center;justify-content:flex-start;flex-shrink:0;cursor:pointer;transition:background .15s cubic-bezier(.4,0,.2,1)}.cf-switch>span{width:16px;height:16px;border-radius:9999px;background:#fff;box-shadow:0 1px 2px #1018280d}.cf-switch.is-on{background:#00a3ff;justify-content:flex-end}.cf-switch--top{margin-top:2px}.cf-chipbox{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:8px 10px}.cf-chipbox--lg{gap:8px;padding:10px 12px}.cf-chip{display:flex;align-items:center;gap:6px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;border-radius:9999px;padding:3px 8px;font-size:12px;color:#344054;white-space:nowrap;flex-shrink:0;max-width:100%}.cf-chip--lg{gap:8px;background:#fff;padding:5px 11px;font-size:13px;color:#1d2939}.cf-chip-ini{color:#00a3ff;font-weight:600;font-size:11px}.cf-chip-tag{display:inline-flex;align-items:center;justify-content:center;padding:1px 5px;border-radius:6px;background:#eaf8ff;color:#00a3ff;font-weight:700;font-size:11px;letter-spacing:.02em}.cf-chip-x{display:flex;cursor:pointer;color:#98a2b3}.cf-chip-x:hover{color:#344054}.cf-chip-input{flex:1;min-width:100px;border:none;outline:none;background:transparent;font-family:inherit;font-size:12px;color:#101828}.cf-chip-input::placeholder{color:#98a2b3}.cf-chip-input--lg{min-width:120px;font-size:13px}.cf-inner{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:14px 16px;display:flex;flex-direction:column;gap:8px}.cf-inline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-inline--top{margin-top:2px}.cf-mini{height:32px;padding:0 28px 0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 8px center;outline:none}.cf-info{display:flex;align-items:center;gap:6px;font-size:12px;line-height:18px;color:#667085}.cf-info svg{flex-shrink:0}.cf-info--wrap{align-items:flex-start;max-width:560px;text-wrap:pretty}.cf-info--wrap svg{margin-top:3px}.cf-checks{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-checks-label{font-weight:500}.cf-check{display:flex;align-items:center;gap:6px;margin:0;font-size:13px;color:#344054;cursor:pointer;-webkit-user-select:none;user-select:none}.cf-check-box{width:16px;height:16px;border-radius:4px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center;color:#fff;flex-shrink:0}.cf-check-box.is-on{background:#00a3ff;box-shadow:none}.cf-box{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden;display:flex;flex-direction:column}.cf-box--pad{padding:14px 16px;gap:6px;overflow:visible}.cf-box--row{padding:14px 16px;flex-direction:row;align-items:flex-start;gap:12px}.cf-box--nested{background:#fff;padding:12px 14px;gap:8px;margin-left:46px;overflow:visible}.cf-box--open{overflow:visible}.cf-box--open>.cf-box-sub:last-child{border-radius:0 0 8px 8px}.cf-box-row{padding:14px 16px;display:flex;align-items:flex-start;gap:12px}.cf-box-row--flush{padding:0;gap:10px}.cf-box-sub{border-top:1px solid #EAECF0;background:#f9fafb;padding:16px 16px 18px 64px;display:flex;flex-direction:column;gap:12px}.cf-options{display:flex;flex-direction:column;gap:10px}.cf-option{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;cursor:pointer}.cf-option.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.cf-box-sep{display:flex;flex-direction:column;gap:12px;padding-top:14px;border-top:1px solid #EAECF0}.cf-num{display:flex;align-items:center;gap:8px;height:36px;padding:0 6px 0 12px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;margin:0}.cf-num input{width:52px;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;font-weight:600;color:#101828}.cf-num span{font-size:13px;color:#667085;padding-right:6px}.cf-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;border-radius:9999px;padding:4px 12px}.cf-pill--pass{background:#ecfdf3;color:#027a48}.cf-pill--fail{background:#fef3f2;color:#d92d20}.cf-error{display:flex;gap:6px;font-size:12px;font-weight:500;color:#d92d20;align-items:flex-start;line-height:18px;max-width:640px}.cf-error svg{flex-shrink:0;margin-top:3px}.cf-error--indent{margin-left:162px}.cf-check.is-blocked{color:#98a2b3;cursor:not-allowed}.cf-select{position:relative;display:inline-block;vertical-align:middle}.cf-select-btn{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 10px 0 12px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;white-space:nowrap}.cf-select-btn svg{color:#667085;transition:transform .15s ease}.is-open .cf-select-btn{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.is-open .cf-select-btn svg{transform:rotate(180deg)}.cf-select-menu{position:absolute;top:calc(100% + 4px);left:0;z-index:30;min-width:100%;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-select-item{padding:8px 12px;border-radius:6px;font-size:13px;color:#344054;white-space:nowrap;cursor:pointer}.cf-select-item:hover{background:#f9fafb}.cf-select-item.is-on{background:#eaf8ff;color:#009bf3;font-weight:600}.cf-chipbox{position:relative}.cf-chipbox.is-open{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.cf-suggest{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;max-height:260px;overflow-y:auto;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-suggest-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer}.cf-suggest-item:hover{background:#f9fafb}.cf-suggest-name{font-size:13px;color:#101828}.cf-suggest-mail{font-size:12px;color:#667085;margin-left:auto}.cf-suggest-empty{padding:8px 10px;font-size:12px;color:#667085}.cf-error--page{margin:0 0 12px}.cf-autotask{margin-top:12px;padding:14px 16px;border-radius:10px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column;gap:8px}.cf-autotask-title{font-size:14px;font-weight:600;color:#1d2939}.cf-autotask-title:not(:first-child){margin-top:6px}.cf-autotask-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}@media (max-width: 720px){.cf-autotask-choices{grid-template-columns:1fr}}.cf-choice{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;text-align:left;cursor:pointer}.cf-choice.is-on{background:#f5faff;box-shadow:inset 0 0 0 1px #66c8ff}.cf-radio{width:18px;height:18px;flex-shrink:0;margin-top:1px;border-radius:9999px;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center}.cf-radio span{width:8px;height:8px;border-radius:9999px;background:transparent}.cf-radio.is-on{box-shadow:inset 0 0 0 1px #1570ef}.cf-radio.is-on span{background:#1570ef}.cf-choice-text{display:flex;flex-direction:column;gap:2px;min-width:0}.cf-choice-title{font-size:14px;font-weight:600;color:#101828}.cf-choice-sub{font-size:12px;color:#667085}.cf-autotask-validity{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:13px;color:#344054}.cf-validity-select{width:96px}.cf-reminder{display:inline-flex;align-items:center;gap:6px}.cf-reminder-select{width:120px}.cf-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;cursor:pointer}.cf-icon-btn:hover{background:#f9fafb}.cf-bulkbar{display:flex;justify-content:flex-end;margin-bottom:-4px}.cf-bulkbar .av2-btn{display:inline-flex;align-items:center;gap:6px}.cf-dlg-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.cf-dlg{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:520px;max-width:calc(100vw - 32px);max-height:90vh;overflow-y:auto;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.cf-dlg-icon{width:40px;height:40px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.cf-dlg-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.cf-dlg-steps{display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.cf-dlg-steps a{color:#00a3ff;text-decoration:underline;cursor:pointer}.cf-dlg-note{font-size:13px;line-height:20px;font-weight:600;color:#344054}.cf-dlg-errors{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}.cf-dlg-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:4px}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AuditV2ShimmerComponent, selector: "lib-audit-v2-shimmer", inputs: ["rows"] }, { kind: "component", type: AuditV2SelectComponent, selector: "lib-audit-v2-select", inputs: ["options", "placeholder", "searchable", "ariaLabel", "disabled", "value"], outputs: ["changed"] }] });
|
|
10208
10390
|
}
|
|
10209
10391
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuditV2ConfigureComponent, decorators: [{
|
|
10210
10392
|
type: Component,
|
|
10211
|
-
args: [{ selector: 'lib-audit-v2-configure', template: "<div class=\"av2-page audit-configure\">\r\n\r\n <!-- Back + breadcrumb (as the schedule editor's back bar) -->\r\n <div class=\"cf-backbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm cf-back\" (click)=\"back()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\r\n {{ backLabel }}\r\n </button>\r\n <div class=\"cf-crumb\">\r\n <a href=\"#\" (click)=\"back($event)\">Manage Audit</a> \u203A Configure\r\n </div>\r\n </div>\r\n\r\n <!-- Title + actions -->\r\n <div class=\"cf-header\">\r\n <div class=\"cf-header-text\">\r\n <span class=\"av2-sk av2-sk--title cf-sk-title\" *ngIf=\"loading\"></span>\r\n <div class=\"cf-title\" *ngIf=\"!loading\">{{ auditName || 'Audit' }}</div>\r\n <input type=\"text\" class=\"cf-desc\" placeholder=\"Enter Audit Description\" [(ngModel)]=\"description\">\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary cf-publish\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason || publishBlockedReason\" (click)=\"publish()\">\r\n {{ saving ? 'Saving\u2026' : (published ? 'Save & Publish' : 'Publish') }}\r\n </button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost cf-draft\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason\" (click)=\"saveDraft()\">Save as Draft</button>\r\n </div>\r\n\r\n <div class=\"cf-error cf-error--page\" *ngIf=\"loadError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ loadError }}\r\n </div>\r\n\r\n <!-- Chip picker: chips + input + suggestion list (one template, used for every user list) -->\r\n <ng-template #chipPicker let-list=\"list\" let-large=\"large\">\r\n <div class=\"cf-chipbox\" [class.cf-chipbox--lg]=\"large\" [class.is-open]=\"openChips === list\" (click)=\"focusChips(list, $event)\">\r\n <span class=\"cf-chip\" [class.cf-chip--lg]=\"large\" *ngFor=\"let u of chipsOf(list); let i = index\" [title]=\"u.e\">\r\n <span [class]=\"large ? 'cf-chip-tag' : 'cf-chip-ini'\">{{ u.i }}</span>{{ u.n }}\r\n <a class=\"cf-chip-x\" (click)=\"removeChip(list, i); $event.stopPropagation()\">\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <input type=\"text\" class=\"cf-chip-input\" [class.cf-chip-input--lg]=\"large\" placeholder=\"Add user...\"\r\n [ngModel]=\"draftOf(list)\" (ngModelChange)=\"setDraft(list, $event)\" (focus)=\"focusChips(list, $event)\" (keyup.enter)=\"addChip(list)\">\r\n <div class=\"cf-suggest\" *ngIf=\"openChips === list\">\r\n <div class=\"cf-suggest-item\" *ngFor=\"let u of suggestions(list)\" (click)=\"addSuggestion(list, u, $event)\">\r\n <span class=\"cf-chip-ini\">{{ u.i }}</span>\r\n <span class=\"cf-suggest-name\">{{ u.n }}</span>\r\n <span class=\"cf-suggest-mail\">{{ u.e }}</span>\r\n </div>\r\n <div class=\"cf-suggest-empty\" *ngIf=\"!suggestions(list).length\">\r\n {{ users.length ? 'No matching user' : 'No users for this client' }}\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Dropdown: styled like the prototype instead of the browser's native select -->\r\n <ng-template #dropdown let-key=\"key\" let-options=\"options\">\r\n <span class=\"cf-select\" [class.is-open]=\"openSelect === key\">\r\n <button type=\"button\" class=\"cf-select-btn\" (click)=\"toggleSelect(key, $event)\">\r\n {{ selectLabel(key, options) }}\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </button>\r\n <div class=\"cf-select-menu\" *ngIf=\"openSelect === key\">\r\n <div class=\"cf-select-item\" *ngFor=\"let o of options\" [class.is-on]=\"isPicked(key, o)\"\r\n (click)=\"pick(key, o, $event)\">{{ o.label }}</div>\r\n </div>\r\n </span>\r\n </ng-template>\r\n\r\n <div class=\"cf-body\" *ngIf=\"!loadError\">\r\n <!-- Section tree -->\r\n <aside class=\"cf-left\">\r\n <lib-audit-v2-shimmer *ngIf=\"loading\" [rows]=\"3\"></lib-audit-v2-shimmer>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n <div class=\"cf-left-title\">{{ auditName || 'Audit' }}</div>\r\n\r\n <div class=\"cf-hint\" *ngIf=\"!sections.length\">No questions yet</div>\r\n <ng-container *ngFor=\"let s of sections\">\r\n <div class=\"cf-section\" [class.is-open]=\"s.open\" (click)=\"toggleSection(s)\">\r\n {{ s.label }}\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" [class.rotate]=\"!s.open\">\r\n <polyline points=\"6 9 12 15 18 9\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"cf-items\" *ngIf=\"s.open && s.items.length\">\r\n <div *ngFor=\"let it of s.items\">{{ it }}</div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- No Schedule block (QA 10 Oct): audits have no one-time / repeat schedule here; visits come from Schedules. -->\r\n </ng-container>\r\n </aside>\r\n\r\n <!-- Configuration -->\r\n <div class=\"cf-right\">\r\n\r\n <section class=\"cf-card\" *ngIf=\"loading\">\r\n <lib-audit-v2-shimmer [rows]=\"4\"></lib-audit-v2-shimmer>\r\n </section>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n\r\n <!-- ===== Advance Configuration ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-head\">\r\n <span class=\"cf-block-title\">Advance Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </span>\r\n </div>\r\n\r\n <!-- Audit Owner -->\r\n <div>\r\n <div class=\"cf-label\">Audit Owner</div>\r\n <div class=\"cf-hint\">Owners get access to manage the audit</div>\r\n </div>\r\n <div class=\"cf-row\">\r\n <span class=\"cf-field\">Can be managed by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'owners', large: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Approver -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Approver</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"approverOn\" (click)=\"toggleApprover()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be able to approve the audit</div>\r\n <div class=\"cf-row\" *ngIf=\"approverOn\">\r\n <span class=\"cf-field\">To be approved by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'approvers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"approverError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ approverError }}\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so the {{ approvers.length }} approver{{ approvers.length === 1 ? '' : 's' }} added will be removed when you save. Turn Approver back on to keep {{ approvers.length === 1 ? 'it' : 'them' }}.\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && !approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so submitted audits are not sent for approval. Turn it on to add approvers or to send flags and reports to them.\r\n </div>\r\n\r\n <!-- Reminder -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Reminder</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"reminderOn\" (click)=\"toggleReminder()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be reminded in the selected interval</div>\r\n <div class=\"cf-inner\" *ngIf=\"reminderOn\">\r\n <div class=\"cf-inline\">\r\n Notify user before\r\n <span class=\"cf-reminder\" *ngFor=\"let m of reminders; let i = index\">\r\n <lib-audit-v2-select class=\"cf-reminder-select\" [value]=\"m\" [options]=\"reminderOpts[i] || []\" [searchable]=\"false\"\r\n [ariaLabel]=\"'Reminder ' + (i + 1) + ' in minutes'\" (changed)=\"setReminder(i, $event.target.value)\"></lib-audit-v2-select>\r\n <a class=\"cf-chip-x\" *ngIf=\"reminders.length > 1\" title=\"Remove reminder\" (click)=\"removeReminder(i)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <button type=\"button\" class=\"cf-icon-btn\" *ngIf=\"reminders.length < maxReminders\" title=\"Add reminder\" (click)=\"addReminder()\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>\r\n </button>\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Send alerts {{ reminderSummary }} mins before the audit end time\r\n </div>\r\n </div>\r\n\r\n <!-- Notify Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"notifyFlagsOn\" (click)=\"toggleNotifyFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, all flags will be sent as an email</div>\r\n <ng-container *ngIf=\"notifyFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !notifySendApprover\" (click)=\"toggleSendApprover('notifySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendApprover\">\r\n <svg *ngIf=\"notifySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"notifySendCustom = !notifySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendCustom\">\r\n <svg *ngIf=\"notifySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"notifySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'notifyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-error\" *ngIf=\"notifyFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ notifyFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Notify on Recurring Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify on Recurring Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"recurringFlagsOn\" (click)=\"toggleRecurringFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">When enabled, emails are sent for recurring flags based on the configured threshold</div>\r\n\r\n <div class=\"cf-inner\" *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-inline\">\r\n Send Email if the same question is flagged\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'recurringThreshold', options: thresholdOpts }\"></ng-container>\r\n times by the same store\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Once the threshold is reached and an email is sent, the flag count resets to zero\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !recurringSendApprover\" (click)=\"toggleSendApprover('recurringSendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendApprover\">\r\n <svg *ngIf=\"recurringSendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"toggleRecurringCustom()\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendCustom\">\r\n <svg *ngIf=\"recurringSendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n <label class=\"cf-check\" (click)=\"recurringSameAsNotify = !recurringSameAsNotify\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSameAsNotify\">\r\n <svg *ngIf=\"recurringSameAsNotify\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Use same users from Notify Flags\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"recurringSendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'recurringUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-info\" *ngIf=\"recurringSameAsNotify\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n {{ notifyRecipientsLabel }}\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"recurringFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ recurringFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Daily report -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Enable - Daily Report</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"dailyReportOn\" (click)=\"toggleDailyReport()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By Enabling, compliance score will be sent as an email to the above users</div>\r\n <ng-container *ngIf=\"dailyReportOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !dailySendApprover\" (click)=\"toggleSendApprover('dailySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendApprover\">\r\n <svg *ngIf=\"dailySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"dailySendCustom = !dailySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendCustom\">\r\n <svg *ngIf=\"dailySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"dailySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'dailyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <label class=\"cf-check\" (click)=\"sharePostApproval = !sharePostApproval\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"sharePostApproval\">\r\n <svg *ngIf=\"sharePostApproval\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Share Report Post Approval\r\n </label>\r\n <div class=\"cf-error\" *ngIf=\"dailyReportError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ dailyReportError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Export submission: Tango users only, as the v1 Configure (its stored value is kept for everyone else). -->\r\n <div class=\"cf-grid2\" *ngIf=\"access.isTango\">\r\n <div class=\"cf-stack cf-stack--tight\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Export Submission</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"exportSubmissionOn\" (click)=\"exportSubmissionOn = !exportSubmissionOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint\">Enable this to allow audit submitters to download their submission as a PDF file</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Redo validity -->\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Validity</div>\r\n <div class=\"cf-inline\">\r\n Redo valid for\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoValidFor', options: redoDayOpts }\"></ng-container>\r\n Day from Redo creation\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Auto create task -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Auto Create Task for Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"autoCreateTaskOn\" (click)=\"autoCreateTaskOn = !autoCreateTaskOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, a task is automatically created for every flagged question in the audit</div>\r\n\r\n <!-- Who gets the task and how long it stays open (as the Checklist Configure page) -->\r\n <div class=\"cf-autotask\" *ngIf=\"autoCreateTaskOn\">\r\n <div class=\"cf-autotask-title\">Task Assignee</div>\r\n <div class=\"cf-hint cf-hint--tight\">Choose who the flagged task is assigned to</div>\r\n <div class=\"cf-autotask-choices\">\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'submitter'\" (click)=\"taskAssignee = 'submitter'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'submitter'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Audit Submitter</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user who filled the audit</span>\r\n </span>\r\n </button>\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'store'\" (click)=\"taskAssignee = 'store'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'store'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Store User</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user mapped to the flagged store</span>\r\n </span>\r\n </button>\r\n </div>\r\n <div class=\"cf-autotask-title\">Task Validity</div>\r\n <div class=\"cf-autotask-validity\">\r\n <span>Task valid for</span>\r\n <lib-audit-v2-select class=\"cf-validity-select\" [(ngModel)]=\"taskValidity\" [options]=\"taskValidityOptions\"\r\n [searchable]=\"false\" ariaLabel=\"Task validity in days\"></lib-audit-v2-select>\r\n <span>days from task creation</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Audit Configuration ===== -->\r\n <div class=\"cf-divider-head\">\r\n <span class=\"cf-block-title\">Audit Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n </div>\r\n\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Submission & Visibility</div>\r\n\r\n <!-- cf-box--open: the dispute-window and response-delay menus must not be clipped by the box -->\r\n <div class=\"cf-box cf-box--open\">\r\n <div class=\"cf-box-row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"showResponseInApp\"\r\n (click)=\"showResponseInApp = !showResponseInApp\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Show Response in Mobile App</div>\r\n <div class=\"cf-hint\">By enabling this option, store users can view the audit response in the Mobile App.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sub\" *ngIf=\"showResponseInApp\">\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Response Visibility</div>\r\n <div class=\"cf-hint\">Choose when the response becomes visible to store users</div>\r\n </div>\r\n\r\n <div class=\"cf-options\">\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'pre'\" (click)=\"responseVisibility = 'pre'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'pre'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\">Pre-approval</div>\r\n <div class=\"cf-hint\">The audit response will be visible to store users before it is approved.</div>\r\n <div class=\"cf-inline cf-inline--top\">\r\n Show response\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'respDelay', options: respDelayOpts }\"></ng-container>\r\n after submission\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'post'\" (click)=\"responseVisibility = 'post'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'post'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\" [class.cf-muted]=\"responseVisibility !== 'post'\">Post-approval</div>\r\n <div class=\"cf-hint\">Once the response is approved, it will automatically be displayed in the Mobile App. Store users cannot raise a dispute.</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sep\">\r\n <ng-container *ngIf=\"responseVisibility === 'pre'\">\r\n <div class=\"cf-box-row cf-box-row--flush\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"disputeOn\" (click)=\"disputeOn = !disputeOn\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Dispute Configuration</div>\r\n <div class=\"cf-hint cf-hint--wrap\">When enabled, the store team can raise a dispute against the auditor's submission once the response becomes visible to them.</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--nested\" *ngIf=\"disputeOn\">\r\n <div class=\"cf-inline\">\r\n Dispute window\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'disputeWindow', options: dispWindowOpts }\"></ng-container>\r\n from when the response becomes visible\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes raised inside this window go to the approver. Approved disputes revise the answer and the compliance score.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"!hasApprovers\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n No approver is set, so no one can review disputes. Turn on Approver and add an approver.\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"responseVisibility === 'post'\">\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm cf-muted\">Dispute Configuration</div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes are not available when responses are shown post-approval.\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Pre-submission access -->\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pre-Submission Access</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"preSubmissionAccessOn\" (click)=\"preSubmissionAccessOn = !preSubmissionAccessOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Users added here can view Open and In Progress audits until submission. The Schedule Info tab is also visible only to these users.</div>\r\n <ng-container *ngIf=\"preSubmissionAccessOn\">\r\n <div class=\"cf-row cf-row--top\">\r\n <span class=\"cf-field\">Visible to</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'preSubmissionUsers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error cf-error--indent\" *ngIf=\"preSubmissionEmpty\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n Add at least one user\r\n </div>\r\n </ng-container>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Scoring ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Scoring</div>\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pass/Fail Score Setup</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"passFailOn\" (click)=\"passFailOn = !passFailOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Set the compliance score an audit must reach to be marked {{ passLabel }}. Anything below it is marked {{ failLabel }}.</div>\r\n <div class=\"cf-row cf-row--wrap cf-row--top\" *ngIf=\"passFailOn\">\r\n <span class=\"cf-field\">Minimum score to {{ passLabel }}</span>\r\n <label class=\"cf-num\">\r\n <input type=\"number\" min=\"1\" max=\"100\" [(ngModel)]=\"passThreshold\">\r\n <span>%</span>\r\n </label>\r\n <span class=\"cf-pill cf-pill--pass\">{{ passLabel }} \u2265 {{ passThreshold }}%</span>\r\n <span class=\"cf-pill cf-pill--fail\">{{ failLabel }} < {{ passThreshold }}%</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Approver Controls ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Approver Controls</div>\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Edit Submitted Audit</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"editSubmittedOn\" (click)=\"toggleEditSubmitted()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">Allow Approvers to edit submitted Audit</div>\r\n <ng-container *ngIf=\"editSubmittedOn\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'editUsers', large: true }\"></ng-container>\r\n <div class=\"cf-error\" *ngIf=\"editSubmittedError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ editSubmittedError }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Extension</div>\r\n <div class=\"cf-inline\">\r\n Extend redo up to\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoExtension', options: redoExtensionOpts }\"></ng-container>\r\n Days till approval\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== User Verification ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-title\">User Verification Configuration</div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requirePhoto\" (click)=\"requirePhoto = !requirePhoto\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require Photo Capture</div>\r\n <div class=\"cf-hint\">By enabling, users must capture their photo to complete submission</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requireAcknowledgment\" (click)=\"requireAcknowledgment = !requireAcknowledgment\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require User Acknowledgment</div>\r\n <div class=\"cf-hint\">By enabling, users must type their name as acknowledgment to complete submission</div>\r\n </div>\r\n </div>\r\n </section>\r\n </ng-container>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}.cf-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.cf-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.cf-crumb{font-size:13px;line-height:20px;color:#667085}.cf-crumb a{font-weight:600;color:#00a3ff}.cf-header{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px 20px;display:flex;align-items:center;gap:12px}.cf-header-text{display:flex;flex-direction:column;gap:4px;min-width:0}.cf-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.cf-sk-title{margin:3px 0}.cf-desc{border:none;outline:none;padding:0;background:transparent;font-family:inherit;font-size:13px;line-height:18px;color:#344054;min-width:320px}.cf-desc::placeholder{color:#98a2b3}.cf-publish{padding:0 20px;box-shadow:0 1px 2px #1018280d}.cf-draft{padding:0 18px;box-shadow:inset 0 0 0 1px #d0d5dd,0 1px 2px #1018280d}.cf-body{display:flex;gap:16px;align-items:flex-start}.cf-left{width:300px;flex-shrink:0;background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px;display:flex;flex-direction:column;gap:10px;position:sticky;top:calc(var(--bs-app-header-height, 0px) + 16px);max-height:calc(100vh - var(--bs-app-header-height, 0px) - 32px);overflow-y:auto;scrollbar-width:thin}.cf-left-title{font-size:14px;line-height:20px;font-weight:600;color:#101828}.cf-section{display:flex;align-items:center;gap:8px;padding:2px 0;font-size:13px;font-weight:500;color:#344054;cursor:pointer;white-space:nowrap}.cf-section.is-open{color:#1d2939}.cf-rule{flex:1;border-top:1px solid #EAECF0}.cf-chev{display:flex;color:#98a2b3}.cf-chev svg{transition:transform .15s cubic-bezier(.4,0,.2,1)}.cf-chev .rotate{transform:rotate(-90deg)}.cf-items{display:flex;flex-direction:column;gap:8px;padding-left:12px;font-size:13px;color:#475467}.cf-schedule-title{font-size:14px;font-weight:600;color:#101828;margin-top:6px}.cf-schedule{display:flex;flex-direction:column;gap:6px;font-size:13px;color:#475467}.cf-schedule>div{display:flex;align-items:center;gap:6px}.cf-right{flex:1;min-width:0;display:flex;flex-direction:column;gap:16px}.cf-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px;display:flex;flex-direction:column;gap:14px}.cf-card--lg{border-radius:8px}.cf-block-head{display:flex;align-items:center;gap:12px}.cf-block-title{font-size:15px;font-weight:600;color:#101828}.cf-divider-head{display:flex;align-items:center;gap:10px;margin-top:4px}.cf-label{font-size:14px;font-weight:600;color:#101828}.cf-label-sm{font-size:13px;font-weight:600;color:#101828}.cf-muted{color:#667085}.cf-hint{font-size:12px;line-height:18px;color:#667085}.cf-hint--tight{margin-top:-8px}.cf-hint--wrap{max-width:640px;text-wrap:pretty}.cf-field{font-size:13px;font-weight:500;color:#344054;min-width:150px;flex-shrink:0}.cf-row{display:flex;align-items:center;gap:12px}.cf-row--top{margin-top:6px}.cf-row--wrap{flex-wrap:wrap}.cf-stack{display:flex;flex-direction:column;gap:8px}.cf-stack--tight,.cf-stack--sm{gap:4px}.cf-stack--xs{gap:2px}.cf-grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.cf-toggle-row{display:flex;align-items:center;gap:10px}.cf-switch{width:36px;height:20px;padding:2px;border:none;border-radius:9999px;background:#eaecf0;display:flex;align-items:center;justify-content:flex-start;flex-shrink:0;cursor:pointer;transition:background .15s cubic-bezier(.4,0,.2,1)}.cf-switch>span{width:16px;height:16px;border-radius:9999px;background:#fff;box-shadow:0 1px 2px #1018280d}.cf-switch.is-on{background:#00a3ff;justify-content:flex-end}.cf-switch--top{margin-top:2px}.cf-chipbox{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:8px 10px}.cf-chipbox--lg{gap:8px;padding:10px 12px}.cf-chip{display:flex;align-items:center;gap:6px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;border-radius:9999px;padding:3px 8px;font-size:12px;color:#344054;white-space:nowrap;flex-shrink:0;max-width:100%}.cf-chip--lg{gap:8px;background:#fff;padding:5px 11px;font-size:13px;color:#1d2939}.cf-chip-ini{color:#00a3ff;font-weight:600;font-size:11px}.cf-chip-tag{display:inline-flex;align-items:center;justify-content:center;padding:1px 5px;border-radius:6px;background:#eaf8ff;color:#00a3ff;font-weight:700;font-size:11px;letter-spacing:.02em}.cf-chip-x{display:flex;cursor:pointer;color:#98a2b3}.cf-chip-x:hover{color:#344054}.cf-chip-input{flex:1;min-width:100px;border:none;outline:none;background:transparent;font-family:inherit;font-size:12px;color:#101828}.cf-chip-input::placeholder{color:#98a2b3}.cf-chip-input--lg{min-width:120px;font-size:13px}.cf-inner{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:14px 16px;display:flex;flex-direction:column;gap:8px}.cf-inline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-inline--top{margin-top:2px}.cf-mini{height:32px;padding:0 28px 0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 8px center;outline:none}.cf-info{display:flex;align-items:center;gap:6px;font-size:12px;line-height:18px;color:#667085}.cf-info svg{flex-shrink:0}.cf-info--wrap{align-items:flex-start;max-width:560px;text-wrap:pretty}.cf-info--wrap svg{margin-top:3px}.cf-checks{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-checks-label{font-weight:500}.cf-check{display:flex;align-items:center;gap:6px;margin:0;font-size:13px;color:#344054;cursor:pointer;-webkit-user-select:none;user-select:none}.cf-check-box{width:16px;height:16px;border-radius:4px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center;color:#fff;flex-shrink:0}.cf-check-box.is-on{background:#00a3ff;box-shadow:none}.cf-box{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden;display:flex;flex-direction:column}.cf-box--pad{padding:14px 16px;gap:6px;overflow:visible}.cf-box--row{padding:14px 16px;flex-direction:row;align-items:flex-start;gap:12px}.cf-box--nested{background:#fff;padding:12px 14px;gap:8px;margin-left:46px;overflow:visible}.cf-box--open{overflow:visible}.cf-box--open>.cf-box-sub:last-child{border-radius:0 0 8px 8px}.cf-box-row{padding:14px 16px;display:flex;align-items:flex-start;gap:12px}.cf-box-row--flush{padding:0;gap:10px}.cf-box-sub{border-top:1px solid #EAECF0;background:#f9fafb;padding:16px 16px 18px 64px;display:flex;flex-direction:column;gap:12px}.cf-options{display:flex;flex-direction:column;gap:10px}.cf-option{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;cursor:pointer}.cf-option.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.cf-box-sep{display:flex;flex-direction:column;gap:12px;padding-top:14px;border-top:1px solid #EAECF0}.cf-num{display:flex;align-items:center;gap:8px;height:36px;padding:0 6px 0 12px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;margin:0}.cf-num input{width:52px;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;font-weight:600;color:#101828}.cf-num span{font-size:13px;color:#667085;padding-right:6px}.cf-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;border-radius:9999px;padding:4px 12px}.cf-pill--pass{background:#ecfdf3;color:#027a48}.cf-pill--fail{background:#fef3f2;color:#d92d20}.cf-error{display:flex;gap:6px;font-size:12px;font-weight:500;color:#d92d20;align-items:flex-start;line-height:18px;max-width:640px}.cf-error svg{flex-shrink:0;margin-top:3px}.cf-error--indent{margin-left:162px}.cf-check.is-blocked{color:#98a2b3;cursor:not-allowed}.cf-select{position:relative;display:inline-block;vertical-align:middle}.cf-select-btn{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 10px 0 12px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;white-space:nowrap}.cf-select-btn svg{color:#667085;transition:transform .15s ease}.is-open .cf-select-btn{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.is-open .cf-select-btn svg{transform:rotate(180deg)}.cf-select-menu{position:absolute;top:calc(100% + 4px);left:0;z-index:30;min-width:100%;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-select-item{padding:8px 12px;border-radius:6px;font-size:13px;color:#344054;white-space:nowrap;cursor:pointer}.cf-select-item:hover{background:#f9fafb}.cf-select-item.is-on{background:#eaf8ff;color:#009bf3;font-weight:600}.cf-chipbox{position:relative}.cf-chipbox.is-open{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.cf-suggest{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;max-height:260px;overflow-y:auto;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-suggest-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer}.cf-suggest-item:hover{background:#f9fafb}.cf-suggest-name{font-size:13px;color:#101828}.cf-suggest-mail{font-size:12px;color:#667085;margin-left:auto}.cf-suggest-empty{padding:8px 10px;font-size:12px;color:#667085}.cf-error--page{margin:0 0 12px}.cf-autotask{margin-top:12px;padding:14px 16px;border-radius:10px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column;gap:8px}.cf-autotask-title{font-size:14px;font-weight:600;color:#1d2939}.cf-autotask-title:not(:first-child){margin-top:6px}.cf-autotask-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}@media (max-width: 720px){.cf-autotask-choices{grid-template-columns:1fr}}.cf-choice{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;text-align:left;cursor:pointer}.cf-choice.is-on{background:#f5faff;box-shadow:inset 0 0 0 1px #66c8ff}.cf-radio{width:18px;height:18px;flex-shrink:0;margin-top:1px;border-radius:9999px;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center}.cf-radio span{width:8px;height:8px;border-radius:9999px;background:transparent}.cf-radio.is-on{box-shadow:inset 0 0 0 1px #1570ef}.cf-radio.is-on span{background:#1570ef}.cf-choice-text{display:flex;flex-direction:column;gap:2px;min-width:0}.cf-choice-title{font-size:14px;font-weight:600;color:#101828}.cf-choice-sub{font-size:12px;color:#667085}.cf-autotask-validity{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:13px;color:#344054}.cf-validity-select{width:96px}.cf-reminder{display:inline-flex;align-items:center;gap:6px}.cf-reminder-select{width:120px}.cf-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;cursor:pointer}.cf-icon-btn:hover{background:#f9fafb}\n"] }]
|
|
10393
|
+
args: [{ selector: 'lib-audit-v2-configure', template: "<div class=\"av2-page audit-configure\">\r\n\r\n <!-- Back + breadcrumb (as the schedule editor's back bar) -->\r\n <div class=\"cf-backbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm cf-back\" (click)=\"back()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 6 9 12 15 18\"></polyline></svg>\r\n {{ backLabel }}\r\n </button>\r\n <div class=\"cf-crumb\">\r\n <a href=\"#\" (click)=\"back($event)\">Manage Audit</a> \u203A Configure\r\n </div>\r\n </div>\r\n\r\n <!-- Title + actions -->\r\n <div class=\"cf-header\">\r\n <div class=\"cf-header-text\">\r\n <span class=\"av2-sk av2-sk--title cf-sk-title\" *ngIf=\"loading\"></span>\r\n <div class=\"cf-title\" *ngIf=\"!loading\">{{ auditName || 'Audit' }}</div>\r\n <input type=\"text\" class=\"cf-desc\" placeholder=\"Enter Audit Description\" [(ngModel)]=\"description\">\r\n </div>\r\n <div class=\"av2-grow\"></div>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary cf-publish\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason || publishBlockedReason\" (click)=\"publish()\">\r\n {{ saving ? 'Saving\u2026' : (published ? 'Save & Publish' : 'Publish') }}\r\n </button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost cf-draft\" [disabled]=\"!canSave\" [title]=\"saveBlockedReason\" (click)=\"saveDraft()\">Save as Draft</button>\r\n </div>\r\n\r\n <div class=\"cf-error cf-error--page\" *ngIf=\"loadError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ loadError }}\r\n </div>\r\n\r\n <!-- Chip picker: chips + input + suggestion list (one template, used for every user list) -->\r\n <ng-template #chipPicker let-list=\"list\" let-large=\"large\">\r\n <div class=\"cf-chipbox\" [class.cf-chipbox--lg]=\"large\" [class.is-open]=\"openChips === list\" (click)=\"focusChips(list, $event)\">\r\n <span class=\"cf-chip\" [class.cf-chip--lg]=\"large\" *ngFor=\"let u of chipsOf(list); let i = index\" [title]=\"u.e\">\r\n <span [class]=\"large ? 'cf-chip-tag' : 'cf-chip-ini'\">{{ u.i }}</span>{{ u.n }}\r\n <a class=\"cf-chip-x\" (click)=\"removeChip(list, i); $event.stopPropagation()\">\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <input type=\"text\" class=\"cf-chip-input\" [class.cf-chip-input--lg]=\"large\" placeholder=\"Add user...\"\r\n [ngModel]=\"draftOf(list)\" (ngModelChange)=\"setDraft(list, $event)\" (focus)=\"focusChips(list, $event)\" (keyup.enter)=\"addChip(list)\">\r\n <div class=\"cf-suggest\" *ngIf=\"openChips === list\">\r\n <div class=\"cf-suggest-item\" *ngFor=\"let u of suggestions(list)\" (click)=\"addSuggestion(list, u, $event)\">\r\n <span class=\"cf-chip-ini\">{{ u.i }}</span>\r\n <span class=\"cf-suggest-name\">{{ u.n }}</span>\r\n <span class=\"cf-suggest-mail\">{{ u.e }}</span>\r\n </div>\r\n <div class=\"cf-suggest-empty\" *ngIf=\"!suggestions(list).length\">\r\n {{ users.length ? 'No matching user' : 'No users for this client' }}\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Dropdown: styled like the prototype instead of the browser's native select -->\r\n <ng-template #dropdown let-key=\"key\" let-options=\"options\">\r\n <span class=\"cf-select\" [class.is-open]=\"openSelect === key\">\r\n <button type=\"button\" class=\"cf-select-btn\" (click)=\"toggleSelect(key, $event)\">\r\n {{ selectLabel(key, options) }}\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </button>\r\n <div class=\"cf-select-menu\" *ngIf=\"openSelect === key\">\r\n <div class=\"cf-select-item\" *ngFor=\"let o of options\" [class.is-on]=\"isPicked(key, o)\"\r\n (click)=\"pick(key, o, $event)\">{{ o.label }}</div>\r\n </div>\r\n </span>\r\n </ng-template>\r\n\r\n <div class=\"cf-body\" *ngIf=\"!loadError\">\r\n <!-- Section tree -->\r\n <aside class=\"cf-left\">\r\n <lib-audit-v2-shimmer *ngIf=\"loading\" [rows]=\"3\"></lib-audit-v2-shimmer>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n <div class=\"cf-left-title\">{{ auditName || 'Audit' }}</div>\r\n\r\n <div class=\"cf-hint\" *ngIf=\"!sections.length\">No questions yet</div>\r\n <ng-container *ngFor=\"let s of sections\">\r\n <div class=\"cf-section\" [class.is-open]=\"s.open\" (click)=\"toggleSection(s)\">\r\n {{ s.label }}\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" [class.rotate]=\"!s.open\">\r\n <polyline points=\"6 9 12 15 18 9\"></polyline>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"cf-items\" *ngIf=\"s.open && s.items.length\">\r\n <div *ngFor=\"let it of s.items\">{{ it }}</div>\r\n </div>\r\n </ng-container>\r\n\r\n <!-- No Schedule block (QA 10 Oct): audits have no one-time / repeat schedule here; visits come from Schedules. -->\r\n </ng-container>\r\n </aside>\r\n\r\n <!-- Configuration -->\r\n <div class=\"cf-right\">\r\n\r\n <section class=\"cf-card\" *ngIf=\"loading\">\r\n <lib-audit-v2-shimmer [rows]=\"4\"></lib-audit-v2-shimmer>\r\n </section>\r\n\r\n <ng-container *ngIf=\"!loading\">\r\n\r\n <!-- ===== Advance Configuration ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-head\">\r\n <span class=\"cf-block-title\">Advance Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n <span class=\"cf-chev\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>\r\n </span>\r\n </div>\r\n\r\n <!-- Audit Owner -->\r\n <div>\r\n <div class=\"cf-label\">Audit Owner</div>\r\n <div class=\"cf-hint\">Owners get access to manage the audit</div>\r\n </div>\r\n <div class=\"cf-row\">\r\n <span class=\"cf-field\">Can be managed by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'owners', large: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Approver -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Approver</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"approverOn\" (click)=\"toggleApprover()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be able to approve the audit</div>\r\n <div class=\"cf-row\" *ngIf=\"approverOn\">\r\n <span class=\"cf-field\">To be approved by</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'approvers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"approverError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ approverError }}\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so the {{ approvers.length }} approver{{ approvers.length === 1 ? '' : 's' }} added will be removed when you save. Turn Approver back on to keep {{ approvers.length === 1 ? 'it' : 'them' }}.\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\" *ngIf=\"!approverOn && !approvers.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Approver is off, so submitted audits are not sent for approval. Turn it on to add approvers or to send flags and reports to them.\r\n </div>\r\n\r\n <!-- Reminder -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Reminder</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"reminderOn\" (click)=\"toggleReminder()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, the users will be reminded in the selected interval</div>\r\n <div class=\"cf-inner\" *ngIf=\"reminderOn\">\r\n <div class=\"cf-inline\">\r\n Notify user before\r\n <span class=\"cf-reminder\" *ngFor=\"let m of reminders; let i = index\">\r\n <lib-audit-v2-select class=\"cf-reminder-select\" [value]=\"m\" [options]=\"reminderOpts[i] || []\" [searchable]=\"false\"\r\n [ariaLabel]=\"'Reminder ' + (i + 1) + ' in minutes'\" (changed)=\"setReminder(i, $event.target.value)\"></lib-audit-v2-select>\r\n <a class=\"cf-chip-x\" *ngIf=\"reminders.length > 1\" title=\"Remove reminder\" (click)=\"removeReminder(i)\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\r\n stroke-linecap=\"round\"><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line></svg>\r\n </a>\r\n </span>\r\n <button type=\"button\" class=\"cf-icon-btn\" *ngIf=\"reminders.length < maxReminders\" title=\"Add reminder\" (click)=\"addReminder()\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>\r\n </button>\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Send alerts {{ reminderSummary }} mins before the audit end time\r\n </div>\r\n </div>\r\n\r\n <!-- Notify Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"notifyFlagsOn\" (click)=\"toggleNotifyFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, all flags will be sent as an email</div>\r\n <ng-container *ngIf=\"notifyFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !notifySendApprover\" (click)=\"toggleSendApprover('notifySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendApprover\">\r\n <svg *ngIf=\"notifySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"notifySendCustom = !notifySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"notifySendCustom\">\r\n <svg *ngIf=\"notifySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"notifySendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'notifyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-error\" *ngIf=\"notifyFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ notifyFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Notify on Recurring Flags -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Notify on Recurring Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"recurringFlagsOn\" (click)=\"toggleRecurringFlags()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">When enabled, emails are sent for recurring flags based on the configured threshold</div>\r\n\r\n <div class=\"cf-inner\" *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-inline\">\r\n Send Email if the same question is flagged\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'recurringThreshold', options: thresholdOpts }\"></ng-container>\r\n times by the same store\r\n </div>\r\n <div class=\"cf-info\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Once the threshold is reached and an email is sent, the flag count resets to zero\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"recurringFlagsOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !recurringSendApprover\" (click)=\"toggleSendApprover('recurringSendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendApprover\">\r\n <svg *ngIf=\"recurringSendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"toggleRecurringCustom()\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSendCustom\">\r\n <svg *ngIf=\"recurringSendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n <label class=\"cf-check\" (click)=\"recurringSameAsNotify = !recurringSameAsNotify\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"recurringSameAsNotify\">\r\n <svg *ngIf=\"recurringSameAsNotify\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Use same users from Notify Flags\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"recurringSendCustom\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'recurringUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <div class=\"cf-info\" *ngIf=\"recurringSameAsNotify\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n {{ notifyRecipientsLabel }}\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"recurringFlagsError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ recurringFlagsError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Daily report -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Enable - Daily Report</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"dailyReportOn\" (click)=\"toggleDailyReport()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By Enabling, compliance score will be sent as an email to the above users</div>\r\n <ng-container *ngIf=\"dailyReportOn\">\r\n <div class=\"cf-checks\">\r\n <span class=\"cf-checks-label\">Send To</span>\r\n <label class=\"cf-check\" [class.is-blocked]=\"!hasApprovers && !dailySendApprover\" (click)=\"toggleSendApprover('dailySendApprover')\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendApprover\">\r\n <svg *ngIf=\"dailySendApprover\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Approver\r\n </label>\r\n <label class=\"cf-check\" (click)=\"dailySendCustom = !dailySendCustom\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"dailySendCustom\">\r\n <svg *ngIf=\"dailySendCustom\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Custom\r\n </label>\r\n </div>\r\n <ng-container *ngIf=\"dailySendCustom\">\r\n <div class=\"cf-bulkbar\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"openDailyBulk()\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.67\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.5 12.5V15.8333C17.5 16.2754 17.3244 16.6993 17.0118 17.0118C16.6993 17.3244 16.2754 17.5 15.8333 17.5H4.16667C3.72464 17.5 3.30072 17.3244 2.98816 17.0118C2.67559 16.6993 2.5 16.2754 2.5 15.8333V12.5M14.1667 6.66667L10 2.5M10 2.5L5.83333 6.66667M10 2.5V12.5\"></path></svg>\r\n Bulk Upload\r\n </button>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'dailyUsers', large: false }\"></ng-container>\r\n </ng-container>\r\n <label class=\"cf-check\" (click)=\"sharePostApproval = !sharePostApproval\">\r\n <span class=\"cf-check-box\" [class.is-on]=\"sharePostApproval\">\r\n <svg *ngIf=\"sharePostApproval\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\r\n </span>Share Report Post Approval\r\n </label>\r\n <div class=\"cf-error\" *ngIf=\"dailyReportError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ dailyReportError }}\r\n </div>\r\n </ng-container>\r\n\r\n <!-- Export submission: Tango users only, as the v1 Configure (its stored value is kept for everyone else). -->\r\n <div class=\"cf-grid2\" *ngIf=\"access.isTango\">\r\n <div class=\"cf-stack cf-stack--tight\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Export Submission</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"exportSubmissionOn\" (click)=\"exportSubmissionOn = !exportSubmissionOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint\">Enable this to allow audit submitters to download their submission as a PDF file</div>\r\n </div>\r\n </div>\r\n\r\n <!-- Redo validity -->\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Validity</div>\r\n <div class=\"cf-inline\">\r\n Redo valid for\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoValidFor', options: redoDayOpts }\"></ng-container>\r\n Day from Redo creation\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Auto create task -->\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Auto Create Task for Flags</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"autoCreateTaskOn\" (click)=\"autoCreateTaskOn = !autoCreateTaskOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">By enabling, a task is automatically created for every flagged question in the audit</div>\r\n\r\n <!-- Who gets the task and how long it stays open (as the Checklist Configure page) -->\r\n <div class=\"cf-autotask\" *ngIf=\"autoCreateTaskOn\">\r\n <div class=\"cf-autotask-title\">Task Assignee</div>\r\n <div class=\"cf-hint cf-hint--tight\">Choose who the flagged task is assigned to</div>\r\n <div class=\"cf-autotask-choices\">\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'submitter'\" (click)=\"taskAssignee = 'submitter'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'submitter'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Audit Submitter</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user who filled the audit</span>\r\n </span>\r\n </button>\r\n <button type=\"button\" class=\"cf-choice\" [class.is-on]=\"taskAssignee === 'store'\" (click)=\"taskAssignee = 'store'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"taskAssignee === 'store'\"><span></span></span>\r\n <span class=\"cf-choice-text\">\r\n <span class=\"cf-choice-title\">Store User</span>\r\n <span class=\"cf-choice-sub\">Task is assigned to the user mapped to the flagged store</span>\r\n </span>\r\n </button>\r\n </div>\r\n <div class=\"cf-autotask-title\">Task Validity</div>\r\n <div class=\"cf-autotask-validity\">\r\n <span>Task valid for</span>\r\n <lib-audit-v2-select class=\"cf-validity-select\" [(ngModel)]=\"taskValidity\" [options]=\"taskValidityOptions\"\r\n [searchable]=\"false\" ariaLabel=\"Task validity in days\"></lib-audit-v2-select>\r\n <span>days from task creation</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Audit Configuration ===== -->\r\n <div class=\"cf-divider-head\">\r\n <span class=\"cf-block-title\">Audit Configuration</span>\r\n <span class=\"cf-rule\"></span>\r\n </div>\r\n\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Submission & Visibility</div>\r\n\r\n <!-- cf-box--open: the dispute-window and response-delay menus must not be clipped by the box -->\r\n <div class=\"cf-box cf-box--open\">\r\n <div class=\"cf-box-row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"showResponseInApp\"\r\n (click)=\"showResponseInApp = !showResponseInApp\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Show Response in Mobile App</div>\r\n <div class=\"cf-hint\">By enabling this option, store users can view the audit response in the Mobile App.</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sub\" *ngIf=\"showResponseInApp\">\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Response Visibility</div>\r\n <div class=\"cf-hint\">Choose when the response becomes visible to store users</div>\r\n </div>\r\n\r\n <div class=\"cf-options\">\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'pre'\" (click)=\"responseVisibility = 'pre'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'pre'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\">Pre-approval</div>\r\n <div class=\"cf-hint\">The audit response will be visible to store users before it is approved.</div>\r\n <div class=\"cf-inline cf-inline--top\">\r\n Show response\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'respDelay', options: respDelayOpts }\"></ng-container>\r\n after submission\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"cf-option\" [class.is-on]=\"responseVisibility === 'post'\" (click)=\"responseVisibility = 'post'\">\r\n <span class=\"cf-radio\" [class.is-on]=\"responseVisibility === 'post'\"><span></span></span>\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm\" [class.cf-muted]=\"responseVisibility !== 'post'\">Post-approval</div>\r\n <div class=\"cf-hint\">Once the response is approved, it will automatically be displayed in the Mobile App. Store users cannot raise a dispute.</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"cf-box-sep\">\r\n <ng-container *ngIf=\"responseVisibility === 'pre'\">\r\n <div class=\"cf-box-row cf-box-row--flush\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"disputeOn\" (click)=\"disputeOn = !disputeOn\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label-sm\">Dispute Configuration</div>\r\n <div class=\"cf-hint cf-hint--wrap\">When enabled, the store team can raise a dispute against the auditor's submission once the response becomes visible to them.</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--nested\" *ngIf=\"disputeOn\">\r\n <div class=\"cf-inline\">\r\n Dispute window\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'disputeWindow', options: dispWindowOpts }\"></ng-container>\r\n from when the response becomes visible\r\n </div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes raised inside this window go to the approver. Approved disputes revise the answer and the compliance score.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"!hasApprovers\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n No approver is set, so no one can review disputes. Turn on Approver and add an approver.\r\n </div>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"responseVisibility === 'post'\">\r\n <div class=\"cf-stack cf-stack--sm\">\r\n <div class=\"cf-label-sm cf-muted\">Dispute Configuration</div>\r\n <div class=\"cf-info cf-info--wrap\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>\r\n Disputes are not available when responses are shown post-approval.\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Pre-submission access -->\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pre-Submission Access</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"preSubmissionAccessOn\" (click)=\"preSubmissionAccessOn = !preSubmissionAccessOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Users added here can view Open and In Progress audits until submission. The Schedule Info tab is also visible only to these users.</div>\r\n <ng-container *ngIf=\"preSubmissionAccessOn\">\r\n <div class=\"cf-row cf-row--top\">\r\n <span class=\"cf-field\">Visible to</span>\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'preSubmissionUsers', large: false }\"></ng-container>\r\n </div>\r\n <div class=\"cf-error cf-error--indent\" *ngIf=\"preSubmissionEmpty\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n Add at least one user\r\n </div>\r\n </ng-container>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Scoring ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Scoring</div>\r\n <div class=\"cf-box cf-box--pad\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Pass/Fail Score Setup</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"passFailOn\" (click)=\"passFailOn = !passFailOn\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--wrap\">Set the compliance score an audit must reach to be marked {{ passLabel }}. Anything below it is marked {{ failLabel }}.</div>\r\n <div class=\"cf-row cf-row--wrap cf-row--top\" *ngIf=\"passFailOn\">\r\n <span class=\"cf-field\">Minimum score to {{ passLabel }}</span>\r\n <label class=\"cf-num\">\r\n <input type=\"number\" min=\"1\" max=\"100\" [(ngModel)]=\"passThreshold\">\r\n <span>%</span>\r\n </label>\r\n <span class=\"cf-pill cf-pill--pass\">{{ passLabel }} \u2265 {{ passThreshold }}%</span>\r\n <span class=\"cf-pill cf-pill--fail\">{{ failLabel }} < {{ passThreshold }}%</span>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== Approver Controls ===== -->\r\n <section class=\"cf-card cf-card--lg\">\r\n <div class=\"cf-block-title\">Approver Controls</div>\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-toggle-row\">\r\n <span class=\"cf-label\">Edit Submitted Audit</span>\r\n <button type=\"button\" class=\"cf-switch\" [class.is-on]=\"editSubmittedOn\" (click)=\"toggleEditSubmitted()\"><span></span></button>\r\n </div>\r\n <div class=\"cf-hint cf-hint--tight\">Allow Approvers to edit submitted Audit</div>\r\n <ng-container *ngIf=\"editSubmittedOn\">\r\n <ng-container *ngTemplateOutlet=\"chipPicker; context: { list: 'editUsers', large: true }\"></ng-container>\r\n <div class=\"cf-error\" *ngIf=\"editSubmittedError\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n {{ editSubmittedError }}\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"cf-grid2\">\r\n <div class=\"cf-stack\">\r\n <div class=\"cf-label\">Redo Extension</div>\r\n <div class=\"cf-inline\">\r\n Extend redo up to\r\n <ng-container *ngTemplateOutlet=\"dropdown; context: { key: 'redoExtension', options: redoExtensionOpts }\"></ng-container>\r\n Days till approval\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n\r\n <!-- ===== User Verification ===== -->\r\n <section class=\"cf-card\">\r\n <div class=\"cf-block-title\">User Verification Configuration</div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requirePhoto\" (click)=\"requirePhoto = !requirePhoto\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require Photo Capture</div>\r\n <div class=\"cf-hint\">By enabling, users must capture their photo to complete submission</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-box cf-box--row\">\r\n <button type=\"button\" class=\"cf-switch cf-switch--top\" [class.is-on]=\"requireAcknowledgment\" (click)=\"requireAcknowledgment = !requireAcknowledgment\"><span></span></button>\r\n <div class=\"cf-stack cf-stack--xs\">\r\n <div class=\"cf-label\">Require User Acknowledgment</div>\r\n <div class=\"cf-hint\">By enabling, users must type their name as acknowledgment to complete submission</div>\r\n </div>\r\n </div>\r\n </section>\r\n </ng-container>\r\n\r\n </div>\r\n </div>\r\n\r\n <!-- Daily Report > Custom: bulk upload users (as the Checklist Configure page's popup) -->\r\n <ng-container *ngIf=\"dailyBulkOpen\">\r\n <div class=\"cf-dlg-backdrop\" (click)=\"closeDailyBulk()\"></div>\r\n <div class=\"cf-dlg\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"cf-dlg-title\">\r\n <span class=\"cf-dlg-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.67\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.5 12.5V15.8333C17.5 16.2754 17.3244 16.6993 17.0118 17.0118C16.6993 17.3244 16.2754 17.5 15.8333 17.5H4.16667C3.72464 17.5 3.30072 17.3244 2.98816 17.0118C2.67559 16.6993 2.5 16.2754 2.5 15.8333V12.5M14.1667 6.66667L10 2.5M10 2.5L5.83333 6.66667M10 2.5V12.5\"></path></svg>\r\n </span>\r\n <div class=\"cf-dlg-title\" id=\"cf-dlg-title\">Bulk Upload</div>\r\n <div class=\"cf-dlg-steps\">\r\n <div>Step 1 - <a href=\"#\" (click)=\"$event.preventDefault(); downloadDailyTemplate()\">Download the template here</a></div>\r\n <div>Step 2 - Add the Email of existing users to the template</div>\r\n <div>Step 3 - Upload it below for processing</div>\r\n </div>\r\n <div class=\"cf-dlg-note\">\r\n **Note : Only the Email column is considered - the Username is taken from the existing user list.\r\n Only existing users of this client are accepted. On upload, all the existing data will be replaced.\r\n </div>\r\n <div class=\"cf-error\" *ngIf=\"dailyBulkErrors.length\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\r\n <div class=\"cf-dlg-errors\">\r\n <div>The file was not uploaded. Fix {{ dailyBulkErrors.length === 1 ? 'this row' : 'these rows' }} and upload again:</div>\r\n <div *ngFor=\"let e of dailyBulkErrors.slice(0, 5)\">{{ e }}</div>\r\n <div *ngIf=\"dailyBulkErrors.length > 5\">+{{ dailyBulkErrors.length - 5 }} more</div>\r\n </div>\r\n </div>\r\n <div class=\"cf-dlg-foot\">\r\n <button type=\"button\" class=\"av2-btn av2-btn--ghost av2-btn--sm\" (click)=\"closeDailyBulk()\">Cancel</button>\r\n <button type=\"button\" class=\"av2-btn av2-btn--primary av2-btn--sm\" (click)=\"dailyBulkFile.click()\">Upload</button>\r\n <input #dailyBulkFile type=\"file\" accept=\".xlsx\" hidden (change)=\"onDailyBulkFile($event)\">\r\n </div>\r\n </div>\r\n </ng-container>\r\n\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.av2-page{display:flex;flex-direction:column;gap:16px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#101828;-webkit-font-smoothing:antialiased}.av2-page *,.av2-page *:before,.av2-page *:after{box-sizing:border-box}.av2-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px 24px;display:flex;flex-direction:column;gap:20px}.av2-card--log{padding:20px 24px 24px;gap:18px}.av2-card--table{padding:20px 24px 24px;gap:16px}.av2-card-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.av2-card-head--center{align-items:center;gap:12px}.av2-title-block{display:flex;flex-direction:column;gap:4px;flex:1;min-width:220px}.av2-card-title{font-size:20px;line-height:30px;font-weight:600;color:#101828;display:flex;align-items:center;gap:10px}.av2-card-title--grow{flex:1;min-width:180px}.av2-card-sub{font-size:14px;line-height:20px;color:#667085}.av2-grow{flex:1}.av2-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.av2-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px}.av2-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px}.av2-stat-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:10px}.av2-stat{padding:8px 16px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;align-items:center;gap:20px}.av2-stat-value{font-size:30px;line-height:38px;font-weight:600;color:#101828}.av2-stat-label{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-kpi{background:#fff;border-radius:10px;box-shadow:inset 0 0 0 1px #eaecf0,0 1px 2px #1018280d;display:flex;flex-direction:column;overflow:hidden}.av2-kpi.is-primary{box-shadow:inset 0 0 0 1px #99dbff,0 1px 2px #1018280d}.av2-kpi.is-primary .av2-kpi-head{background:#eaf8ff}.av2-kpi-head{padding:14px 18px;background:#f9fafb;font-size:16px;line-height:24px;font-weight:500;color:#101828}.av2-kpi-body{padding:16px 18px 18px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.av2-kpi-value{font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-kpi-delta{display:flex;align-items:center;gap:4px;font-size:12px;color:#039855}.av2-kpi-delta.is-down{color:#d92d20}.av2-kpi-note{font-size:12px;color:#667085}.av2-ocard{padding:8px;border-radius:12px;border:1px solid #D0D5DD;background:#fff;display:flex;flex-direction:column;min-width:0;height:100%}.av2-ocard-head{min-height:70px;padding:10px 14px;border-radius:6px;border-bottom:2px solid #EAECF0;background:radial-gradient(206.89% 107.47% at 16.16% 32.77%,#fff6,#45bbfe33),#f2f4f7;box-shadow:0 4px 10px #0000000d;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;min-width:0}.av2-ocard-head--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px}.av2-ocard-count{font-size:30px;line-height:38px;font-weight:600;color:#101828;white-space:nowrap}.av2-ocard-text{font-size:14px;line-height:20px;font-weight:500;color:#344054}.av2-ocard-body{flex:1;padding:12px 14px;display:flex;gap:16px;min-width:0}.av2-ocard-cell{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.av2-ocard-cell--center{align-items:center;text-align:center}.av2-ocard-sub{margin:4px 0;font-size:20px;line-height:30px;font-weight:700;color:#101828}.av2-ocard-note{font-size:14px;line-height:20px;font-weight:400;color:#667085}.av2-ocard-delta{margin-top:6px;display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:18px;font-weight:400;color:#1d2939}.av2-ocard-delta b{font-weight:600;color:#667085}.av2-ocard-delta svg{flex-shrink:0;color:#039855}.av2-ocard-delta.is-down svg{color:#d92d20}.av2-search{position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#98a2b3;font-size:14px;flex-shrink:0}.av2-search svg{flex-shrink:0}.av2-search input{flex:1;min-width:0;height:100%;border:0;outline:0;padding:0;background:transparent;font:inherit;font-size:14px;font-weight:500;color:#101828}.av2-search input::placeholder{color:#98a2b3}.av2-search:focus-within{box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-search--sm{width:300px}.av2-search--md{width:320px}.av2-search--lg{width:340px}.av2-select{height:44px;padding:0 36px 0 12px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;font-size:14px;font-weight:500;color:#344054;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23344054' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 12px center;flex-shrink:0}.av2-select:focus{outline:0;box-shadow:inset 0 0 0 1px #66c8ff,0 0 0 4px #eaf8ff}.av2-select--sm{width:180px}.av2-chip{display:flex;align-items:center;gap:8px;height:44px;padding:0 12px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-size:14px;color:#344054;white-space:nowrap;flex-shrink:0}.av2-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:44px;padding:0 16px;border:0;border-radius:8px;font-family:inherit;font-size:14px;line-height:20px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:background-color .15s cubic-bezier(.4,0,.2,1)}.av2-btn svg{flex-shrink:0}.av2-btn:disabled{opacity:.55;cursor:not-allowed}.av2-btn--ghost{background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;font-weight:500}.av2-btn--ghost:hover:not(:disabled){background:#f9fafb}.av2-btn--primary{background:#00a3ff;color:#fff;font-size:16px;line-height:24px}.av2-btn--primary:hover:not(:disabled){background:#009bf3}.av2-btn--sm{height:36px;padding:0 14px;font-size:13px}.av2-btn--wide{padding:0 18px}.av2-tabs{display:flex;align-items:center;gap:6px}.av2-tab{height:44px;padding:0 26px;border:0;border-radius:6px;background:transparent;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;font-size:16px;font-weight:500;color:#475467;cursor:pointer}.av2-tab.is-active{background:#eaf8ff;color:#009bf3;font-weight:500}.av2-badge{display:inline-flex;align-items:center;height:22px;padding:2px 8px;border-radius:16px;background:#eaf8ff;color:#009bf3;font-size:12px;font-weight:500;line-height:18px;white-space:nowrap}.av2-badge--count{height:22px;padding:0 8px}.av2-badge--success{background:#ecfdf3;color:#027a48}.av2-badge--error{background:#fef3f2;color:#b42318}.av2-badge--warning{background:#fffaeb;color:#b54708}.av2-badge--gray{background:#f2f4f7;color:#344054}.av2-badge--purple{background:#f9f5ff;color:#5925dc}.av2-link{color:#00a3ff;font-size:14px;font-weight:500;text-decoration:underline;cursor:pointer}.av2-link:hover{color:#009bf3;text-decoration:underline}.av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.av2-muted{color:#667085}.av2-dim{color:#475467}.av2-faint{color:#98a2b3}table tbody td.av2-dim{color:#475467}table tbody td.av2-faint{color:#98a2b3}.av2-table-wrap{overflow-x:auto}.av2-table{width:100%;border-collapse:separate;border-spacing:0;margin:0}.av2-table thead th{background:#f9fafb;padding:12px;font-size:12px;line-height:18px;font-weight:500;color:#667085;text-align:left;text-transform:none;letter-spacing:0;border:0;white-space:nowrap}.av2-table thead th:first-child{border-radius:8px 0 0}.av2-table thead th:last-child{border-radius:0 8px 0 0}.av2-table tbody td{padding:16px 12px;border:0;border-bottom:1px solid #F2F4F7;font-size:14px;line-height:20px;font-weight:500;color:#101828;vertical-align:middle}.av2-table .av2-th-sort{display:inline-flex;align-items:center;gap:4px}.av2-table .av2-cell-icon{display:flex;align-items:center;gap:8px;min-width:0}.av2-table .av2-cell-icon svg{flex-shrink:0}.av2-table .av2-cell-icon span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-table .av2-cell-stack{display:flex;flex-direction:column;gap:2px}.av2-table .av2-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.av2-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.av2-table--lined thead th{background:transparent;border-bottom:1px solid #EAECF0;border-radius:0!important}.av2-empty{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 32px;text-align:center}.av2-empty-img{display:block;width:160px;height:120px}.av2-empty-text{display:flex;flex-direction:column;gap:4px;align-items:center}.av2-empty-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.av2-empty-sub{max-width:480px;font-size:14px;line-height:20px;color:#667085;text-wrap:pretty}.av2-col-head{border-radius:8px;background:#f9fafb;padding:14px 16px;font-size:12px;line-height:20px;font-weight:500;color:#344054;display:flex;align-items:center;gap:8px}.av2-avatar{width:32px;height:32px;flex-shrink:0;border-radius:9999px;background:#eaf8ff;color:#009bf3;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}.av2-bar{flex:1;height:5px;border-radius:9999px;background:#f2f4f7;overflow:hidden;display:block;min-width:60px}.av2-bar span{display:block;height:5px;border-radius:9999px;background:#00a3ff}@keyframes av2-shimmer{0%{background-position:-1000px 0}to{background-position:1000px 0}}.av2-sk{display:block;width:100%;max-width:100%;height:12px;border-radius:4px;flex-shrink:0;background:linear-gradient(to right,#e6e6e6 5%,#ccc 25%,#e6e6e6 35%);background-size:1000px 100%;animation:av2-shimmer 3s linear infinite}.av2-sk--value{width:72px;height:28px;border-radius:6px}.av2-sk--title{width:220px;height:18px}.av2-sk--note{width:60%}.av2-sk--block{border-radius:8px}@media (prefers-reduced-motion: reduce){.av2-sk{animation:none}}.cf-backbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px}.cf-back{display:inline-flex;align-items:center;gap:4px;flex-shrink:0}.cf-crumb{font-size:13px;line-height:20px;color:#667085}.cf-crumb a{font-weight:600;color:#00a3ff}.cf-header{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px 20px;display:flex;align-items:center;gap:12px}.cf-header-text{display:flex;flex-direction:column;gap:4px;min-width:0}.cf-title{font-size:16px;line-height:24px;font-weight:600;color:#101828}.cf-sk-title{margin:3px 0}.cf-desc{border:none;outline:none;padding:0;background:transparent;font-family:inherit;font-size:13px;line-height:18px;color:#344054;min-width:320px}.cf-desc::placeholder{color:#98a2b3}.cf-publish{padding:0 20px;box-shadow:0 1px 2px #1018280d}.cf-draft{padding:0 18px;box-shadow:inset 0 0 0 1px #d0d5dd,0 1px 2px #1018280d}.cf-body{display:flex;gap:16px;align-items:flex-start}.cf-left{width:300px;flex-shrink:0;background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:16px;display:flex;flex-direction:column;gap:10px;position:sticky;top:calc(var(--bs-app-header-height, 0px) + 16px);max-height:calc(100vh - var(--bs-app-header-height, 0px) - 32px);overflow-y:auto;scrollbar-width:thin}.cf-left-title{font-size:14px;line-height:20px;font-weight:600;color:#101828}.cf-section{display:flex;align-items:center;gap:8px;padding:2px 0;font-size:13px;font-weight:500;color:#344054;cursor:pointer;white-space:nowrap}.cf-section.is-open{color:#1d2939}.cf-rule{flex:1;border-top:1px solid #EAECF0}.cf-chev{display:flex;color:#98a2b3}.cf-chev svg{transition:transform .15s cubic-bezier(.4,0,.2,1)}.cf-chev .rotate{transform:rotate(-90deg)}.cf-items{display:flex;flex-direction:column;gap:8px;padding-left:12px;font-size:13px;color:#475467}.cf-schedule-title{font-size:14px;font-weight:600;color:#101828;margin-top:6px}.cf-schedule{display:flex;flex-direction:column;gap:6px;font-size:13px;color:#475467}.cf-schedule>div{display:flex;align-items:center;gap:6px}.cf-right{flex:1;min-width:0;display:flex;flex-direction:column;gap:16px}.cf-card{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #f1f1f4,0 3px 4px #00000008;padding:20px;display:flex;flex-direction:column;gap:14px}.cf-card--lg{border-radius:8px}.cf-block-head{display:flex;align-items:center;gap:12px}.cf-block-title{font-size:15px;font-weight:600;color:#101828}.cf-divider-head{display:flex;align-items:center;gap:10px;margin-top:4px}.cf-label{font-size:14px;font-weight:600;color:#101828}.cf-label-sm{font-size:13px;font-weight:600;color:#101828}.cf-muted{color:#667085}.cf-hint{font-size:12px;line-height:18px;color:#667085}.cf-hint--tight{margin-top:-8px}.cf-hint--wrap{max-width:640px;text-wrap:pretty}.cf-field{font-size:13px;font-weight:500;color:#344054;min-width:150px;flex-shrink:0}.cf-row{display:flex;align-items:center;gap:12px}.cf-row--top{margin-top:6px}.cf-row--wrap{flex-wrap:wrap}.cf-stack{display:flex;flex-direction:column;gap:8px}.cf-stack--tight,.cf-stack--sm{gap:4px}.cf-stack--xs{gap:2px}.cf-grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}.cf-toggle-row{display:flex;align-items:center;gap:10px}.cf-switch{width:36px;height:20px;padding:2px;border:none;border-radius:9999px;background:#eaecf0;display:flex;align-items:center;justify-content:flex-start;flex-shrink:0;cursor:pointer;transition:background .15s cubic-bezier(.4,0,.2,1)}.cf-switch>span{width:16px;height:16px;border-radius:9999px;background:#fff;box-shadow:0 1px 2px #1018280d}.cf-switch.is-on{background:#00a3ff;justify-content:flex-end}.cf-switch--top{margin-top:2px}.cf-chipbox{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:6px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;padding:8px 10px}.cf-chipbox--lg{gap:8px;padding:10px 12px}.cf-chip{display:flex;align-items:center;gap:6px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;border-radius:9999px;padding:3px 8px;font-size:12px;color:#344054;white-space:nowrap;flex-shrink:0;max-width:100%}.cf-chip--lg{gap:8px;background:#fff;padding:5px 11px;font-size:13px;color:#1d2939}.cf-chip-ini{color:#00a3ff;font-weight:600;font-size:11px}.cf-chip-tag{display:inline-flex;align-items:center;justify-content:center;padding:1px 5px;border-radius:6px;background:#eaf8ff;color:#00a3ff;font-weight:700;font-size:11px;letter-spacing:.02em}.cf-chip-x{display:flex;cursor:pointer;color:#98a2b3}.cf-chip-x:hover{color:#344054}.cf-chip-input{flex:1;min-width:100px;border:none;outline:none;background:transparent;font-family:inherit;font-size:12px;color:#101828}.cf-chip-input::placeholder{color:#98a2b3}.cf-chip-input--lg{min-width:120px;font-size:13px}.cf-inner{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:14px 16px;display:flex;flex-direction:column;gap:8px}.cf-inline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-inline--top{margin-top:2px}.cf-mini{height:32px;padding:0 28px 0 10px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\");background-repeat:no-repeat;background-position:right 8px center;outline:none}.cf-info{display:flex;align-items:center;gap:6px;font-size:12px;line-height:18px;color:#667085}.cf-info svg{flex-shrink:0}.cf-info--wrap{align-items:flex-start;max-width:560px;text-wrap:pretty}.cf-info--wrap svg{margin-top:3px}.cf-checks{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:13px;color:#344054}.cf-checks-label{font-weight:500}.cf-check{display:flex;align-items:center;gap:6px;margin:0;font-size:13px;color:#344054;cursor:pointer;-webkit-user-select:none;user-select:none}.cf-check-box{width:16px;height:16px;border-radius:4px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center;color:#fff;flex-shrink:0}.cf-check-box.is-on{background:#00a3ff;box-shadow:none}.cf-box{border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;overflow:hidden;display:flex;flex-direction:column}.cf-box--pad{padding:14px 16px;gap:6px;overflow:visible}.cf-box--row{padding:14px 16px;flex-direction:row;align-items:flex-start;gap:12px}.cf-box--nested{background:#fff;padding:12px 14px;gap:8px;margin-left:46px;overflow:visible}.cf-box--open{overflow:visible}.cf-box--open>.cf-box-sub:last-child{border-radius:0 0 8px 8px}.cf-box-row{padding:14px 16px;display:flex;align-items:flex-start;gap:12px}.cf-box-row--flush{padding:0;gap:10px}.cf-box-sub{border-top:1px solid #EAECF0;background:#f9fafb;padding:16px 16px 18px 64px;display:flex;flex-direction:column;gap:12px}.cf-options{display:flex;flex-direction:column;gap:10px}.cf-option{background:#fff;border-radius:8px;box-shadow:inset 0 0 0 1px #eaecf0;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;cursor:pointer}.cf-option.is-on{box-shadow:inset 0 0 0 1.5px #00a3ff}.cf-box-sep{display:flex;flex-direction:column;gap:12px;padding-top:14px;border-top:1px solid #EAECF0}.cf-num{display:flex;align-items:center;gap:8px;height:36px;padding:0 6px 0 12px;border-radius:8px;box-shadow:inset 0 0 0 1px #d0d5dd;margin:0}.cf-num input{width:52px;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;font-weight:600;color:#101828}.cf-num span{font-size:13px;color:#667085;padding-right:6px}.cf-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;border-radius:9999px;padding:4px 12px}.cf-pill--pass{background:#ecfdf3;color:#027a48}.cf-pill--fail{background:#fef3f2;color:#d92d20}.cf-error{display:flex;gap:6px;font-size:12px;font-weight:500;color:#d92d20;align-items:flex-start;line-height:18px;max-width:640px}.cf-error svg{flex-shrink:0;margin-top:3px}.cf-error--indent{margin-left:162px}.cf-check.is-blocked{color:#98a2b3;cursor:not-allowed}.cf-select{position:relative;display:inline-block;vertical-align:middle}.cf-select-btn{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 10px 0 12px;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font-family:inherit;font-size:13px;font-weight:600;color:#101828;cursor:pointer;white-space:nowrap}.cf-select-btn svg{color:#667085;transition:transform .15s ease}.is-open .cf-select-btn{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.is-open .cf-select-btn svg{transform:rotate(180deg)}.cf-select-menu{position:absolute;top:calc(100% + 4px);left:0;z-index:30;min-width:100%;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-select-item{padding:8px 12px;border-radius:6px;font-size:13px;color:#344054;white-space:nowrap;cursor:pointer}.cf-select-item:hover{background:#f9fafb}.cf-select-item.is-on{background:#eaf8ff;color:#009bf3;font-weight:600}.cf-chipbox{position:relative}.cf-chipbox.is-open{box-shadow:0 0 0 2px #99dbff,inset 0 0 0 1px #d0d5dd}.cf-suggest{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;max-height:260px;overflow-y:auto;padding:4px;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #eaecf0,0 8px 24px #1018281f}.cf-suggest-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer}.cf-suggest-item:hover{background:#f9fafb}.cf-suggest-name{font-size:13px;color:#101828}.cf-suggest-mail{font-size:12px;color:#667085;margin-left:auto}.cf-suggest-empty{padding:8px 10px;font-size:12px;color:#667085}.cf-error--page{margin:0 0 12px}.cf-autotask{margin-top:12px;padding:14px 16px;border-radius:10px;background:#f9fafb;box-shadow:inset 0 0 0 1px #eaecf0;display:flex;flex-direction:column;gap:8px}.cf-autotask-title{font-size:14px;font-weight:600;color:#1d2939}.cf-autotask-title:not(:first-child){margin-top:6px}.cf-autotask-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}@media (max-width: 720px){.cf-autotask-choices{grid-template-columns:1fr}}.cf-choice{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:0;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;font:inherit;text-align:left;cursor:pointer}.cf-choice.is-on{background:#f5faff;box-shadow:inset 0 0 0 1px #66c8ff}.cf-radio{width:18px;height:18px;flex-shrink:0;margin-top:1px;border-radius:9999px;box-shadow:inset 0 0 0 1px #d0d5dd;display:flex;align-items:center;justify-content:center}.cf-radio span{width:8px;height:8px;border-radius:9999px;background:transparent}.cf-radio.is-on{box-shadow:inset 0 0 0 1px #1570ef}.cf-radio.is-on span{background:#1570ef}.cf-choice-text{display:flex;flex-direction:column;gap:2px;min-width:0}.cf-choice-title{font-size:14px;font-weight:600;color:#101828}.cf-choice-sub{font-size:12px;color:#667085}.cf-autotask-validity{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:13px;color:#344054}.cf-validity-select{width:96px}.cf-reminder{display:inline-flex;align-items:center;gap:6px}.cf-reminder-select{width:120px}.cf-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:none;border-radius:8px;background:#fff;box-shadow:inset 0 0 0 1px #d0d5dd;color:#344054;cursor:pointer}.cf-icon-btn:hover{background:#f9fafb}.cf-bulkbar{display:flex;justify-content:flex-end;margin-bottom:-4px}.cf-bulkbar .av2-btn{display:inline-flex;align-items:center;gap:6px}.cf-dlg-backdrop{position:fixed;inset:0;background:#34405499;z-index:1050}.cf-dlg{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:520px;max-width:calc(100vw - 32px);max-height:90vh;overflow-y:auto;padding:24px;border-radius:8px;background:#fff;box-shadow:0 20px 40px #10182833;z-index:1051;display:flex;flex-direction:column;gap:12px}.cf-dlg-icon{width:40px;height:40px;border-radius:9999px;background:#eaf8ff;color:#00a3ff;display:flex;align-items:center;justify-content:center}.cf-dlg-title{font-size:18px;line-height:28px;font-weight:600;color:#101828}.cf-dlg-steps{display:flex;flex-direction:column;gap:8px;font-size:14px;line-height:20px;color:#344054}.cf-dlg-steps a{color:#00a3ff;text-decoration:underline;cursor:pointer}.cf-dlg-note{font-size:13px;line-height:20px;font-weight:600;color:#344054}.cf-dlg-errors{display:flex;flex-direction:column;gap:2px;min-width:0;overflow-wrap:anywhere}.cf-dlg-foot{display:flex;justify-content:flex-end;gap:12px;margin-top:4px}\n"] }]
|
|
10212
10394
|
}], ctorParameters: () => [{ type: TraxService }, { type: i2.GlobalStateService }, { type: i1.ActivatedRoute }, { type: i1.Router }, { type: i3.ToastService }, { type: i0.ChangeDetectorRef }], propDecorators: { onEscape: [{
|
|
10213
10395
|
type: HostListener,
|
|
10214
10396
|
args: ['document:keydown.escape']
|
|
@@ -13981,4 +14163,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
13981
14163
|
}] });
|
|
13982
14164
|
|
|
13983
14165
|
export { AuditV2Module };
|
|
13984
|
-
//# sourceMappingURL=tango-app-ui-analyse-trax-audit-v2.module-
|
|
14166
|
+
//# sourceMappingURL=tango-app-ui-analyse-trax-audit-v2.module-Bpm0GYMw.mjs.map
|