i-tech-shared-components 1.4.40 → 1.4.42
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/fesm2022/i-tech-shared-components.mjs +361 -3
- package/fesm2022/i-tech-shared-components.mjs.map +1 -1
- package/lib/components/ag-grid/date-range-selection/date-range-selection.component.d.ts +34 -0
- package/lib/components/ag-grid/select-with-search/select-with-search.component.d.ts +44 -0
- package/lib/interfaces/date-range-filtration.interface.d.ts +7 -0
- package/lib/interfaces/selection-filtration-configuration.interface.d.ts +59 -0
- package/lib/interfaces/selection-filtration.tokens.d.ts +6 -0
- package/lib/services/filtration-helper.service.d.ts +18 -0
- package/package.json +1 -1
- package/public-api.d.ts +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Pipe, inject, Injectable, HostListener, Input, Directive, EventEmitter, Output, Component, ViewChild } from '@angular/core';
|
|
2
|
+
import { Pipe, inject, Injectable, HostListener, Input, Directive, EventEmitter, Output, Component, ViewChild, InjectionToken, Optional, Inject } from '@angular/core';
|
|
3
3
|
import * as i1 from '@ngx-translate/core';
|
|
4
4
|
import { TranslateModule, TranslatePipe, TranslateService } from '@ngx-translate/core';
|
|
5
5
|
import * as i3 from '@angular/forms';
|
|
@@ -7,6 +7,7 @@ import { NgControl, FormControlName, ReactiveFormsModule, UntypedFormGroup, Unty
|
|
|
7
7
|
import moment from 'moment';
|
|
8
8
|
import * as momentTimezone from 'moment-timezone';
|
|
9
9
|
import { MatIconButton, MatFabButton, MatButton } from '@angular/material/button';
|
|
10
|
+
import * as i2$1 from '@angular/common';
|
|
10
11
|
import { NgClass, NgIf, NgOptimizedImage, NgFor, NgForOf, UpperCasePipe, SlicePipe, LowerCasePipe, CommonModule } from '@angular/common';
|
|
11
12
|
import * as i1$2 from '@angular/material/tooltip';
|
|
12
13
|
import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip';
|
|
@@ -27,10 +28,14 @@ import { MatChip } from '@angular/material/chips';
|
|
|
27
28
|
import * as i1$3 from '@angular/router';
|
|
28
29
|
import { NavigationEnd, RouterLink } from '@angular/router';
|
|
29
30
|
import * as i5$1 from '@angular/material/core';
|
|
30
|
-
import { MatRippleModule } from '@angular/material/core';
|
|
31
|
+
import { MatRippleModule, MatRipple } from '@angular/material/core';
|
|
31
32
|
import * as i2 from '@angular/common/http';
|
|
33
|
+
import { HttpParams } from '@angular/common/http';
|
|
32
34
|
import * as libphonenumber from 'google-libphonenumber';
|
|
33
35
|
import { PhoneNumberUtil } from 'google-libphonenumber';
|
|
36
|
+
import { MatCheckbox } from '@angular/material/checkbox';
|
|
37
|
+
import { of, BehaviorSubject, Subject, combineLatest, debounceTime, distinctUntilChanged, tap, filter, switchMap, takeUntil } from 'rxjs';
|
|
38
|
+
import { map } from 'rxjs/operators';
|
|
34
39
|
|
|
35
40
|
class GenerateErrorMessagesPipe {
|
|
36
41
|
constructor(translateService) {
|
|
@@ -2002,6 +2007,12 @@ var DriverStatus;
|
|
|
2002
2007
|
DriverStatus["TERMINATED"] = "TERMINATED";
|
|
2003
2008
|
})(DriverStatus || (DriverStatus = {}));
|
|
2004
2009
|
|
|
2010
|
+
/**
|
|
2011
|
+
* Global Token for the project's API Gateway URL.
|
|
2012
|
+
* Injected at the root level of each application (TMT, T3, etc.).
|
|
2013
|
+
*/
|
|
2014
|
+
const DATA_ENDPOINT = new InjectionToken('DATA_ENDPOINT');
|
|
2015
|
+
|
|
2005
2016
|
class AgGridFunctionsService {
|
|
2006
2017
|
findSortQuery(sortModel) {
|
|
2007
2018
|
if (!sortModel || sortModel.length === 0)
|
|
@@ -2333,6 +2344,353 @@ function internationalPhoneValidator() {
|
|
|
2333
2344
|
};
|
|
2334
2345
|
}
|
|
2335
2346
|
|
|
2347
|
+
class DateRangeSelectionComponent {
|
|
2348
|
+
constructor(dateService) {
|
|
2349
|
+
this.dateService = dateService;
|
|
2350
|
+
this.form = new UntypedFormGroup({
|
|
2351
|
+
range: new UntypedFormControl(null)
|
|
2352
|
+
});
|
|
2353
|
+
this.defaultValueForDates = [];
|
|
2354
|
+
}
|
|
2355
|
+
agInit(params) {
|
|
2356
|
+
this.params = params;
|
|
2357
|
+
this.config = params['customParams'];
|
|
2358
|
+
}
|
|
2359
|
+
/**
|
|
2360
|
+
* Selection event from the Datepicker component
|
|
2361
|
+
*/
|
|
2362
|
+
onDateChange(event) {
|
|
2363
|
+
this.form.get('range').setValue(event);
|
|
2364
|
+
// Notify AG Grid to trigger getModel()
|
|
2365
|
+
this.params.filterChangedCallback();
|
|
2366
|
+
}
|
|
2367
|
+
/**
|
|
2368
|
+
* AG Grid calls this to get the state of the filter
|
|
2369
|
+
*/
|
|
2370
|
+
getModel() {
|
|
2371
|
+
const value = this.form.get('range').value;
|
|
2372
|
+
if (!value || (!value[0] && !value[1]))
|
|
2373
|
+
return null;
|
|
2374
|
+
const [start, end] = value;
|
|
2375
|
+
const model = {};
|
|
2376
|
+
// Start Date mapping: 00:00:00
|
|
2377
|
+
if (start && this.config.returnValueByKey[0]) {
|
|
2378
|
+
const date = typeof start === 'string' ? new Date(start) : start;
|
|
2379
|
+
model[this.config.returnValueByKey[0]] =
|
|
2380
|
+
this.dateService.changeFormat(date, 'YYYY-MM-DD') + 'T00:00:00';
|
|
2381
|
+
}
|
|
2382
|
+
// End Date mapping: 23:59:59
|
|
2383
|
+
if (end && this.config.returnValueByKey[1]) {
|
|
2384
|
+
const date = typeof end === 'string' ? new Date(end) : end;
|
|
2385
|
+
model[this.config.returnValueByKey[1]] =
|
|
2386
|
+
this.dateService.changeFormat(date, 'YYYY-MM-DD') + 'T23:59:59';
|
|
2387
|
+
}
|
|
2388
|
+
// Include targetFields if provided
|
|
2389
|
+
if (this.config.targetFields?.length) {
|
|
2390
|
+
model.targetFields = this.config.targetFields;
|
|
2391
|
+
}
|
|
2392
|
+
return model;
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* AG Grid calls this to restore the filter state
|
|
2396
|
+
*/
|
|
2397
|
+
setModel(model) {
|
|
2398
|
+
if (!model) {
|
|
2399
|
+
this.form.get('range').setValue(null);
|
|
2400
|
+
this.defaultValueForDates = [];
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
const start = model[this.config.returnValueByKey[0]];
|
|
2404
|
+
const end = model[this.config.returnValueByKey[1]];
|
|
2405
|
+
this.defaultValueForDates = [start, end];
|
|
2406
|
+
this.form.get('range').setValue([start, end]);
|
|
2407
|
+
}
|
|
2408
|
+
isFilterActive() {
|
|
2409
|
+
const val = this.form.get('range').value;
|
|
2410
|
+
return !!(val && (val[0] || val[1]));
|
|
2411
|
+
}
|
|
2412
|
+
// Not used for server-side filtering but required by interface
|
|
2413
|
+
doesFilterPass(params) {
|
|
2414
|
+
return true;
|
|
2415
|
+
}
|
|
2416
|
+
afterGuiDetached() {
|
|
2417
|
+
this.rangePicker.picker.close();
|
|
2418
|
+
}
|
|
2419
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DateRangeSelectionComponent, deps: [{ token: ParseDateService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2420
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DateRangeSelectionComponent, isStandalone: true, selector: "i-tech-date-range-selection", providers: [ParseDateService], viewQueries: [{ propertyName: "rangePicker", first: true, predicate: DateRangeDatepickerComponent, descendants: true }], ngImport: i0, template: "<div class=\"ag-date-filter-wrapper\">\n <i-tech-mat-range-datepicker\n [label]=\"''\"\n [panelClass]=\"'ag-filtration-date-range ag-custom-component-popup'\"\n [placeholder]=\"config?.DATE_RANGE?.placeholder || ['From', 'To']\"\n [defaultValue]=\"defaultValueForDates\"\n (selectionChange)=\"onDateChange($event)\"\n >\n </i-tech-mat-range-datepicker>\n</div>\n", styles: [".ag-date-filter-wrapper{border-radius:0}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-subscript-wrapper.mat-mdc-form-field-bottom-align{display:none!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-infix{display:flex;padding-top:0!important;padding-bottom:0!important;align-items:center}.ag-date-filter-wrapper::ng-deep .mdc-notched-outline>*{border-color:transparent!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field{width:296px!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-infix{width:fit-content}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content{box-shadow:4px 6px 12px -4px #0000004d;border:unset!important;border-radius:0!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar{height:auto!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar-header{padding:0!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar-header .mat-calendar-controls{margin:5px 0!important}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DateRangeDatepickerComponent, selector: "i-tech-mat-range-datepicker", inputs: ["label", "placeholder", "value", "defaultValue", "key", "submit", "clearValue", "errorMessage", "onePlaceholder", "hintText", "testId", "panelClass"], outputs: ["resetForm", "selectionChange"] }] }); }
|
|
2421
|
+
}
|
|
2422
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DateRangeSelectionComponent, decorators: [{
|
|
2423
|
+
type: Component,
|
|
2424
|
+
args: [{ selector: 'i-tech-date-range-selection', standalone: true, imports: [ReactiveFormsModule, DateRangeDatepickerComponent], providers: [ParseDateService], template: "<div class=\"ag-date-filter-wrapper\">\n <i-tech-mat-range-datepicker\n [label]=\"''\"\n [panelClass]=\"'ag-filtration-date-range ag-custom-component-popup'\"\n [placeholder]=\"config?.DATE_RANGE?.placeholder || ['From', 'To']\"\n [defaultValue]=\"defaultValueForDates\"\n (selectionChange)=\"onDateChange($event)\"\n >\n </i-tech-mat-range-datepicker>\n</div>\n", styles: [".ag-date-filter-wrapper{border-radius:0}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-subscript-wrapper.mat-mdc-form-field-bottom-align{display:none!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-infix{display:flex;padding-top:0!important;padding-bottom:0!important;align-items:center}.ag-date-filter-wrapper::ng-deep .mdc-notched-outline>*{border-color:transparent!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field{width:296px!important}.ag-date-filter-wrapper::ng-deep .mat-mdc-form-field-infix{width:fit-content}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content{box-shadow:4px 6px 12px -4px #0000004d;border:unset!important;border-radius:0!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar{height:auto!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar-header{padding:0!important}::ng-deep .mat-datepicker-popup:has(.ag-custom-component-popup) .mat-datepicker-content .mat-calendar-header .mat-calendar-controls{margin:5px 0!important}\n"] }]
|
|
2425
|
+
}], ctorParameters: () => [{ type: ParseDateService }], propDecorators: { rangePicker: [{
|
|
2426
|
+
type: ViewChild,
|
|
2427
|
+
args: [DateRangeDatepickerComponent]
|
|
2428
|
+
}] } });
|
|
2429
|
+
|
|
2430
|
+
class FiltrationHelperService {
|
|
2431
|
+
constructor(http, dataEndpoint) {
|
|
2432
|
+
this.http = http;
|
|
2433
|
+
this.dataEndpoint = dataEndpoint;
|
|
2434
|
+
}
|
|
2435
|
+
getData(config, page = 1, size = 20, search = '') {
|
|
2436
|
+
// Safe check to prevent the destructuring error
|
|
2437
|
+
if (!config || !config.source) {
|
|
2438
|
+
return of(this.wrapInFakePagination([]));
|
|
2439
|
+
}
|
|
2440
|
+
const { source } = config;
|
|
2441
|
+
const idPath = config.renderAndKeys.valueByKeys || 'id';
|
|
2442
|
+
// 1. Handle Local Sources (FIXED / MAP)
|
|
2443
|
+
if (source.type === 'FIXED' || source.type === 'MAP') {
|
|
2444
|
+
const rawData = source.type === 'FIXED' ? source.data :
|
|
2445
|
+
Object.entries(source.data).map(([key, value]) => (typeof value === 'object') ? { ...value, id: key } : { id: key, value });
|
|
2446
|
+
const processed = this.filterLocal(rawData, search, config).map(item => ({
|
|
2447
|
+
...item,
|
|
2448
|
+
__uniqueId: this.getValueByPath(item, idPath)
|
|
2449
|
+
}));
|
|
2450
|
+
return of(this.wrapInFakePagination(processed));
|
|
2451
|
+
}
|
|
2452
|
+
// 2. Handle Remote Source (HTTP)
|
|
2453
|
+
const fullUrl = `${this.dataEndpoint}/${source.url.replace(/^\//, '')}`;
|
|
2454
|
+
let params = new HttpParams()
|
|
2455
|
+
.set('page', page.toString())
|
|
2456
|
+
.set('size', size.toString());
|
|
2457
|
+
if (search)
|
|
2458
|
+
params = params.set('search', search);
|
|
2459
|
+
let filter = {};
|
|
2460
|
+
if (source.method === 'POST') {
|
|
2461
|
+
filter = source.payload || { filter: {} };
|
|
2462
|
+
if (search) {
|
|
2463
|
+
filter.searchBy = search;
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
const request$ = source.method === 'POST'
|
|
2467
|
+
? this.http.post(fullUrl, filter, { params })
|
|
2468
|
+
: this.http.get(fullUrl, { params });
|
|
2469
|
+
return request$.pipe(map(res => {
|
|
2470
|
+
const isStandardResponse = res && res.content;
|
|
2471
|
+
const rawContent = isStandardResponse ? res.content : (Array.isArray(res) ? res : []);
|
|
2472
|
+
// SINGLE PASS: Wrap and Inject __uniqueId
|
|
2473
|
+
const mappedContent = rawContent.map((item) => ({
|
|
2474
|
+
...item,
|
|
2475
|
+
__uniqueId: this.getValueByPath(item, idPath)
|
|
2476
|
+
}));
|
|
2477
|
+
return isStandardResponse
|
|
2478
|
+
? { ...res, content: mappedContent }
|
|
2479
|
+
: this.wrapInFakePagination(mappedContent);
|
|
2480
|
+
}));
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Universal path extractor for strings or hierarchical arrays ['user', 'role', 'id']
|
|
2484
|
+
*/
|
|
2485
|
+
getValueByPath(item, path) {
|
|
2486
|
+
if (!item || !path)
|
|
2487
|
+
return null;
|
|
2488
|
+
return Array.isArray(path)
|
|
2489
|
+
? path.reduce((obj, key) => (obj && obj[key] !== undefined ? obj[key] : null), item)
|
|
2490
|
+
: item[path];
|
|
2491
|
+
}
|
|
2492
|
+
filterLocal(data, search, config) {
|
|
2493
|
+
if (!search)
|
|
2494
|
+
return data;
|
|
2495
|
+
const s = search.toLowerCase();
|
|
2496
|
+
return data.filter(item => config.renderAndKeys.labelKeys.some(key => String(this.getValueByPath(item, key)).toLowerCase().includes(s)));
|
|
2497
|
+
}
|
|
2498
|
+
wrapInFakePagination(data) {
|
|
2499
|
+
return {
|
|
2500
|
+
content: data,
|
|
2501
|
+
last: true,
|
|
2502
|
+
totalElements: data.length,
|
|
2503
|
+
totalPages: 1,
|
|
2504
|
+
size: data.length,
|
|
2505
|
+
number: 1,
|
|
2506
|
+
first: true,
|
|
2507
|
+
empty: data.length === 0
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FiltrationHelperService, deps: [{ token: i2.HttpClient }, { token: DATA_ENDPOINT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2511
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FiltrationHelperService, providedIn: 'root' }); }
|
|
2512
|
+
}
|
|
2513
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FiltrationHelperService, decorators: [{
|
|
2514
|
+
type: Injectable,
|
|
2515
|
+
args: [{ providedIn: 'root' }]
|
|
2516
|
+
}], ctorParameters: () => [{ type: i2.HttpClient }, { type: undefined, decorators: [{
|
|
2517
|
+
type: Optional
|
|
2518
|
+
}, {
|
|
2519
|
+
type: Inject,
|
|
2520
|
+
args: [DATA_ENDPOINT]
|
|
2521
|
+
}] }] });
|
|
2522
|
+
|
|
2523
|
+
class SelectWithSearchComponent {
|
|
2524
|
+
constructor(dataService) {
|
|
2525
|
+
this.dataService = dataService;
|
|
2526
|
+
this.items = [];
|
|
2527
|
+
this.selectedIds = new Set(); // O(1) performance for large grids
|
|
2528
|
+
this.allSelected = false;
|
|
2529
|
+
this.partiallySelected = false;
|
|
2530
|
+
this.currentPage = 1;
|
|
2531
|
+
this.isLastPage = false;
|
|
2532
|
+
this.loading = false;
|
|
2533
|
+
this.searchForm = new UntypedFormGroup({
|
|
2534
|
+
search: new UntypedFormControl('')
|
|
2535
|
+
});
|
|
2536
|
+
this.search$ = new BehaviorSubject('');
|
|
2537
|
+
this.pageLoad$ = new BehaviorSubject(0);
|
|
2538
|
+
this.destroy$ = new Subject();
|
|
2539
|
+
}
|
|
2540
|
+
agInit(params) {
|
|
2541
|
+
this.params = params;
|
|
2542
|
+
this.config = params.customParams;
|
|
2543
|
+
if (this.config?.renderAndKeys) {
|
|
2544
|
+
this.config.renderAndKeys.needTranslate = this.config.renderAndKeys.needTranslate !== false;
|
|
2545
|
+
}
|
|
2546
|
+
this.pageLoad$.next(1);
|
|
2547
|
+
}
|
|
2548
|
+
// AG GRID INTERFACE: Logic to hide/show rows
|
|
2549
|
+
doesFilterPass(params) {
|
|
2550
|
+
const valuePath = this.config.renderAndKeys.valueByKeys?.[0] || 'id';
|
|
2551
|
+
const rowValue = this.dataService.getValueByPath(params.data, valuePath);
|
|
2552
|
+
if (this.allSelected) {
|
|
2553
|
+
return !this.selectedIds.has(rowValue);
|
|
2554
|
+
}
|
|
2555
|
+
if (this.selectedIds.size === 0)
|
|
2556
|
+
return true;
|
|
2557
|
+
return this.selectedIds.has(rowValue);
|
|
2558
|
+
}
|
|
2559
|
+
isFilterActive() {
|
|
2560
|
+
return this.selectedIds.size > 0 || this.allSelected;
|
|
2561
|
+
}
|
|
2562
|
+
getModel() {
|
|
2563
|
+
if (!this.isFilterActive())
|
|
2564
|
+
return null;
|
|
2565
|
+
const selections = Array.from(this.selectedIds);
|
|
2566
|
+
const backKey = this.config.backEndKey;
|
|
2567
|
+
// CASE 1: Simple but Named Model (returnFlatArray is true or undefined)
|
|
2568
|
+
if (this.config.returnFlatArray !== false) {
|
|
2569
|
+
let value = selections;
|
|
2570
|
+
if (this.config.mode === 'SINGLE') {
|
|
2571
|
+
value = selections.length ? selections[0] : null;
|
|
2572
|
+
}
|
|
2573
|
+
return { [backKey]: value };
|
|
2574
|
+
}
|
|
2575
|
+
// CASE 2: Hard Model (returnFlatArray is false)
|
|
2576
|
+
return {
|
|
2577
|
+
[backKey]: selections,
|
|
2578
|
+
selectAll: this.config.selectAll ? this.allSelected : false
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
setModel(model) {
|
|
2582
|
+
if (model && typeof model === 'object') {
|
|
2583
|
+
const backKey = this.config.backEndKey;
|
|
2584
|
+
// We can use the same extraction logic for both formats
|
|
2585
|
+
const selections = model[backKey] || [];
|
|
2586
|
+
this.selectedIds = new Set(selections);
|
|
2587
|
+
// selectAll will be undefined in the "Simple" version, which evaluates to false
|
|
2588
|
+
this.allSelected = model.selectAll || false;
|
|
2589
|
+
}
|
|
2590
|
+
else {
|
|
2591
|
+
// Reset internal state if model is null
|
|
2592
|
+
this.allSelected = false;
|
|
2593
|
+
this.selectedIds.clear();
|
|
2594
|
+
}
|
|
2595
|
+
this.updateCheckboxState();
|
|
2596
|
+
}
|
|
2597
|
+
ngOnInit() {
|
|
2598
|
+
this.initCombinedStream();
|
|
2599
|
+
}
|
|
2600
|
+
initCombinedStream() {
|
|
2601
|
+
combineLatest([
|
|
2602
|
+
this.search$.pipe(debounceTime(300), distinctUntilChanged(), tap(() => {
|
|
2603
|
+
this.items = [];
|
|
2604
|
+
this.currentPage = 1;
|
|
2605
|
+
})),
|
|
2606
|
+
this.pageLoad$
|
|
2607
|
+
]).pipe(filter(() => !!this.config), tap(() => this.loading = true), switchMap(([term, page]) => this.dataService.getData(this.config, page, 20, term)), takeUntil(this.destroy$)).subscribe(res => {
|
|
2608
|
+
if (res.number <= 1)
|
|
2609
|
+
this.items = res.content;
|
|
2610
|
+
else
|
|
2611
|
+
this.items = [...this.items, ...res.content];
|
|
2612
|
+
this.isLastPage = res.last;
|
|
2613
|
+
this.loading = false;
|
|
2614
|
+
this.updateCheckboxState();
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
updateCheckboxState() {
|
|
2618
|
+
if (this.config?.mode !== 'MULTI' || !this.config?.selectAll || this.items.length === 0) {
|
|
2619
|
+
this.allSelected = false;
|
|
2620
|
+
this.partiallySelected = false;
|
|
2621
|
+
return;
|
|
2622
|
+
}
|
|
2623
|
+
const selectedInView = this.items.filter(item => this.selectedIds.has(item.__uniqueId)).length;
|
|
2624
|
+
this.allSelected = selectedInView === this.items.length;
|
|
2625
|
+
this.partiallySelected = selectedInView > 0 && selectedInView < this.items.length;
|
|
2626
|
+
}
|
|
2627
|
+
toggleAll(checked) {
|
|
2628
|
+
this.items.forEach(item => checked ? this.selectedIds.add(item.__uniqueId) : this.selectedIds.delete(item.__uniqueId));
|
|
2629
|
+
this.updateCheckboxState();
|
|
2630
|
+
this.params.filterChangedCallback(); // Tell AG Grid to re-run doesFilterPass
|
|
2631
|
+
}
|
|
2632
|
+
onSearchChange(value) {
|
|
2633
|
+
this.search$.next(value || '');
|
|
2634
|
+
}
|
|
2635
|
+
handleScroll(e) {
|
|
2636
|
+
const t = e.target;
|
|
2637
|
+
// Standard infinite scroll threshold
|
|
2638
|
+
if (t.scrollHeight - t.scrollTop <= t.clientHeight + 15 && !this.loading && !this.isLastPage) {
|
|
2639
|
+
this.currentPage++; // Moves to 2, 3, etc.
|
|
2640
|
+
this.pageLoad$.next(this.currentPage);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
resetFilter() {
|
|
2644
|
+
// 1. Clear Selections
|
|
2645
|
+
this.selectedIds.clear();
|
|
2646
|
+
this.allSelected = false;
|
|
2647
|
+
this.partiallySelected = false;
|
|
2648
|
+
// 2. Clear Search Input (This triggers the debounceTime/switchMap stream)
|
|
2649
|
+
this.searchForm.reset();
|
|
2650
|
+
this.search$.next('');
|
|
2651
|
+
// 3. Notify AG Grid to refresh the table rows
|
|
2652
|
+
this.params.filterChangedCallback();
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Handles selection logic for the custom list.
|
|
2656
|
+
* Supports SINGLE (radio-like) and MULTI (checkbox) modes.
|
|
2657
|
+
*/
|
|
2658
|
+
onItemClick(item) {
|
|
2659
|
+
const id = item.__uniqueId;
|
|
2660
|
+
if (this.config.mode === 'SINGLE') {
|
|
2661
|
+
// Single mode: Clear others and set this one
|
|
2662
|
+
this.selectedIds.clear();
|
|
2663
|
+
this.selectedIds.add(id);
|
|
2664
|
+
}
|
|
2665
|
+
else {
|
|
2666
|
+
// Multi mode: Toggle selection
|
|
2667
|
+
if (this.selectedIds.has(id)) {
|
|
2668
|
+
this.selectedIds.delete(id);
|
|
2669
|
+
}
|
|
2670
|
+
else {
|
|
2671
|
+
this.selectedIds.add(id);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
this.updateCheckboxState();
|
|
2675
|
+
this.params.filterChangedCallback(); // Notify AG Grid to filter rows
|
|
2676
|
+
}
|
|
2677
|
+
ngOnDestroy() {
|
|
2678
|
+
this.destroy$.next();
|
|
2679
|
+
this.destroy$.complete();
|
|
2680
|
+
this.search$.complete();
|
|
2681
|
+
this.pageLoad$.complete();
|
|
2682
|
+
}
|
|
2683
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SelectWithSearchComponent, deps: [{ token: FiltrationHelperService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2684
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SelectWithSearchComponent, isStandalone: true, selector: "i-tech-select-with-search", ngImport: i0, template: "@if (config) {\n <div class=\"universal-selector-container\">\n\n @if (config.search) {\n <div class=\"search-wrapper\" [formGroup]=\"searchForm\">\n <i-tech-text-input\n formControlName=\"search\"\n [inputData]=\"{\n type: 'text',\n placeholder: config.search.placeholder || 'Search...',\n submit: false,\n hideLabel: true,\n iconPrefix: 'search',\n emitValueChanges: true,\n clearable: true\n }\"\n (valueChangeEmitter)=\"onSearchChange($event)\">\n </i-tech-text-input>\n </div>\n }\n\n <div class=\"header-section flex_between_align_center\"\n *ngIf=\"(config.mode === 'MULTI' && config.selectAll) || (selectedIds.size > 0 || allSelected)\"\n >\n <div class=\"header-left w-100\">\n @if (config.mode === 'MULTI' && config.selectAll) {\n\n <div class=\"custom-list-item select_all\"\n matRipple\n >\n <mat-checkbox\n color=\"primary\"\n [checked]=\"allSelected\"\n [indeterminate]=\"partiallySelected\"\n (change)=\"toggleAll($event.checked)\"\n >\n <span class=\"item-label\">{{ '(Select All)' | translate }}</span>\n </mat-checkbox>\n </div>\n } @else {\n <span class=\"header-text\">{{ 'Options' | translate }}</span>\n }\n </div>\n\n @if (selectedIds.size > 0 || allSelected) {\n <i-tech-icon-button\n [iconName]=\"'refresh'\"\n [matTooltip]=\"'Reset Filter' | translate\"\n (click)=\"resetFilter()\"\n ></i-tech-icon-button>\n }\n </div>\n\n <div class=\"scroll-viewport\" (scroll)=\"handleScroll($event)\">\n <div class=\"custom-list\">\n @for (item of items; track item.__uniqueId) {\n <div class=\"custom-list-item\"\n matRipple\n [class.selected]=\"selectedIds.has(item.__uniqueId)\"\n (click)=\"onItemClick(item)\"\n >\n <mat-checkbox\n color=\"primary\"\n [checked]=\"selectedIds.has(item.__uniqueId)\"\n >\n <span class=\"item-label\">\n @let label = (config.renderAndKeys.labelKeys | getValueByKeyFromObject: item : null : config.renderAndKeys.separator);\n {{ config.renderAndKeys.needTranslate ? (label | translate) : label }}\n </span>\n </mat-checkbox>\n </div>\n }\n </div>\n\n @if (loading) {\n <div class=\"loader-container\">\n <mat-progress-spinner diameter=\"24\" mode=\"indeterminate\"></mat-progress-spinner>\n </div>\n }\n </div>\n </div>\n}\n", styles: [".universal-selector-container{display:flex;flex-direction:column;min-width:280px;background:#fff}.universal-selector-container .search-wrapper::ng-deep .mat-mdc-form-field:not(.mat-focused) .mdc-notched-outline *{outline:unset!important;border:unset!important}.universal-selector-container .header-section{height:40px;border-bottom:1px solid rgba(0,0,0,.12);background:#fafafa}.universal-selector-container .header-section .header-text{font-size:16px;font-weight:500;line-height:24px;padding-left:12px;color:var(--mat-option-selected-state-label-text-color)}.universal-selector-container .custom-list-item{display:flex;align-items:center;cursor:pointer;padding:10px 12px}.universal-selector-container .custom-list-item::ng-deep .mat-mdc-checkbox{--mdc-checkbox-state-layer-size: 16px !important}.universal-selector-container .custom-list-item::ng-deep .mat-mdc-checkbox .mdc-label{font-size:13px;font-weight:500;line-height:20px;padding-left:16px;color:var(--mat-option-selected-state-label-text-color)}.universal-selector-container .custom-list-item:not(.select_all).selected,.universal-selector-container .custom-list-item:not(.select_all):hover{background-color:var(--mat-option-selected-state-layer-color)}.universal-selector-container .scroll-viewport{flex:1;overflow-y:auto;max-height:350px}.universal-selector-container .scroll-viewport::-webkit-scrollbar{width:5px}.universal-selector-container .scroll-viewport::-webkit-scrollbar-thumb{background:#bdbdbd;border-radius:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "pipe", type: GetValueByKeyFromObjectPipe, name: "getValueByKeyFromObject" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: TextInputComponent, selector: "i-tech-text-input", inputs: ["inputData"], outputs: ["focusOutEmitter", "valueChangeEmitter"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: IconButtonComponent, selector: "i-tech-icon-button", inputs: ["size", "type", "iconSvg", "iconName", "tooltip", "disabled", "testId"], outputs: ["buttonClick"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }] }); }
|
|
2685
|
+
}
|
|
2686
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SelectWithSearchComponent, decorators: [{
|
|
2687
|
+
type: Component,
|
|
2688
|
+
args: [{ selector: 'i-tech-select-with-search', standalone: true, imports: [
|
|
2689
|
+
CommonModule, MatProgressSpinner, GetValueByKeyFromObjectPipe, TranslateModule, MatCheckbox,
|
|
2690
|
+
TextInputComponent, ReactiveFormsModule, IconButtonComponent, MatTooltip, MatRipple
|
|
2691
|
+
], template: "@if (config) {\n <div class=\"universal-selector-container\">\n\n @if (config.search) {\n <div class=\"search-wrapper\" [formGroup]=\"searchForm\">\n <i-tech-text-input\n formControlName=\"search\"\n [inputData]=\"{\n type: 'text',\n placeholder: config.search.placeholder || 'Search...',\n submit: false,\n hideLabel: true,\n iconPrefix: 'search',\n emitValueChanges: true,\n clearable: true\n }\"\n (valueChangeEmitter)=\"onSearchChange($event)\">\n </i-tech-text-input>\n </div>\n }\n\n <div class=\"header-section flex_between_align_center\"\n *ngIf=\"(config.mode === 'MULTI' && config.selectAll) || (selectedIds.size > 0 || allSelected)\"\n >\n <div class=\"header-left w-100\">\n @if (config.mode === 'MULTI' && config.selectAll) {\n\n <div class=\"custom-list-item select_all\"\n matRipple\n >\n <mat-checkbox\n color=\"primary\"\n [checked]=\"allSelected\"\n [indeterminate]=\"partiallySelected\"\n (change)=\"toggleAll($event.checked)\"\n >\n <span class=\"item-label\">{{ '(Select All)' | translate }}</span>\n </mat-checkbox>\n </div>\n } @else {\n <span class=\"header-text\">{{ 'Options' | translate }}</span>\n }\n </div>\n\n @if (selectedIds.size > 0 || allSelected) {\n <i-tech-icon-button\n [iconName]=\"'refresh'\"\n [matTooltip]=\"'Reset Filter' | translate\"\n (click)=\"resetFilter()\"\n ></i-tech-icon-button>\n }\n </div>\n\n <div class=\"scroll-viewport\" (scroll)=\"handleScroll($event)\">\n <div class=\"custom-list\">\n @for (item of items; track item.__uniqueId) {\n <div class=\"custom-list-item\"\n matRipple\n [class.selected]=\"selectedIds.has(item.__uniqueId)\"\n (click)=\"onItemClick(item)\"\n >\n <mat-checkbox\n color=\"primary\"\n [checked]=\"selectedIds.has(item.__uniqueId)\"\n >\n <span class=\"item-label\">\n @let label = (config.renderAndKeys.labelKeys | getValueByKeyFromObject: item : null : config.renderAndKeys.separator);\n {{ config.renderAndKeys.needTranslate ? (label | translate) : label }}\n </span>\n </mat-checkbox>\n </div>\n }\n </div>\n\n @if (loading) {\n <div class=\"loader-container\">\n <mat-progress-spinner diameter=\"24\" mode=\"indeterminate\"></mat-progress-spinner>\n </div>\n }\n </div>\n </div>\n}\n", styles: [".universal-selector-container{display:flex;flex-direction:column;min-width:280px;background:#fff}.universal-selector-container .search-wrapper::ng-deep .mat-mdc-form-field:not(.mat-focused) .mdc-notched-outline *{outline:unset!important;border:unset!important}.universal-selector-container .header-section{height:40px;border-bottom:1px solid rgba(0,0,0,.12);background:#fafafa}.universal-selector-container .header-section .header-text{font-size:16px;font-weight:500;line-height:24px;padding-left:12px;color:var(--mat-option-selected-state-label-text-color)}.universal-selector-container .custom-list-item{display:flex;align-items:center;cursor:pointer;padding:10px 12px}.universal-selector-container .custom-list-item::ng-deep .mat-mdc-checkbox{--mdc-checkbox-state-layer-size: 16px !important}.universal-selector-container .custom-list-item::ng-deep .mat-mdc-checkbox .mdc-label{font-size:13px;font-weight:500;line-height:20px;padding-left:16px;color:var(--mat-option-selected-state-label-text-color)}.universal-selector-container .custom-list-item:not(.select_all).selected,.universal-selector-container .custom-list-item:not(.select_all):hover{background-color:var(--mat-option-selected-state-layer-color)}.universal-selector-container .scroll-viewport{flex:1;overflow-y:auto;max-height:350px}.universal-selector-container .scroll-viewport::-webkit-scrollbar{width:5px}.universal-selector-container .scroll-viewport::-webkit-scrollbar-thumb{background:#bdbdbd;border-radius:10px}\n"] }]
|
|
2692
|
+
}], ctorParameters: () => [{ type: FiltrationHelperService }] });
|
|
2693
|
+
|
|
2336
2694
|
/*
|
|
2337
2695
|
* Public API Surface of shared-components
|
|
2338
2696
|
*/
|
|
@@ -2341,5 +2699,5 @@ function internationalPhoneValidator() {
|
|
|
2341
2699
|
* Generated bundle index. Do not edit.
|
|
2342
2700
|
*/
|
|
2343
2701
|
|
|
2344
|
-
export { AgGridButtonCellComponent, AgGridFunctionsService, ArrayToStringPipe, AutocompleteSelectComponent, ButtonComponent, ButtonType, ClearValueComponent, CompaniesEnum, DatePickerComponent, DateRangeDatepickerComponent, DateTimePickerComponent, DriverCategories, DriverCategoryEnum, DriverStatus, GenerateErrorMessagesPipe, GetValueByKeyFromObjectPipe, IconButtonComponent, InputMaskDirective, InputService, LabelComponent, LabelTypeEnum, MenuComponent, NewSidebarComponent, ParseDateService, PhoneNumberInputComponent, ProcessedStatusCellRendererComponent, RoleEnum, TextInputComponent, TooltipCellRendererComponent, formatPhoneNumber, internationalPhoneValidator };
|
|
2702
|
+
export { AgGridButtonCellComponent, AgGridFunctionsService, ArrayToStringPipe, AutocompleteSelectComponent, ButtonComponent, ButtonType, ClearValueComponent, CompaniesEnum, DATA_ENDPOINT, DatePickerComponent, DateRangeDatepickerComponent, DateRangeSelectionComponent, DateTimePickerComponent, DriverCategories, DriverCategoryEnum, DriverStatus, GenerateErrorMessagesPipe, GetValueByKeyFromObjectPipe, IconButtonComponent, InputMaskDirective, InputService, LabelComponent, LabelTypeEnum, MenuComponent, NewSidebarComponent, ParseDateService, PhoneNumberInputComponent, ProcessedStatusCellRendererComponent, RoleEnum, SelectWithSearchComponent, TextInputComponent, TooltipCellRendererComponent, formatPhoneNumber, internationalPhoneValidator };
|
|
2345
2703
|
//# sourceMappingURL=i-tech-shared-components.mjs.map
|