@flusys/ng-auth 5.2.0 → 5.3.0

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.
@@ -1,11 +1,11 @@
1
1
  import { HttpClient } from '@angular/common/http';
2
2
  import * as i0 from '@angular/core';
3
- import { inject, Injectable, signal, computed, effect, PLATFORM_ID, InjectionToken, Component, untracked, DestroyRef, input, Injector, output, resource, makeStateKey, TransferState } from '@angular/core';
3
+ import { inject, Injectable, signal, computed, effect, PLATFORM_ID, InjectionToken, Component, untracked, viewChild, DestroyRef, input, Injector, output, resource, makeStateKey, TransferState } from '@angular/core';
4
4
  import { APP_CONFIG, getServiceUrl, isCompanyFeatureEnabled, isServiceEnabled, isSignUpEnabled, getPermissionMode, getDefaultCompanySlug, getDefaultBranchSlug } from '@flusys/ng-core';
5
5
  import { of, timeout, switchMap, map, tap, catchError, shareReplay, finalize, BehaviorSubject, throwError, filter, take, from, forkJoin, firstValueFrom } from 'rxjs';
6
6
  import * as i2$1 from '@angular/router';
7
7
  import { Router, RouterOutlet, RouterLink, RouterLinkActive, ActivatedRoute } from '@angular/router';
8
- import { PlatformService, TranslateService, ApiResourceService, CookieService, resolveTranslationModule, SHARED_MESSAGES, permissionGuard, USER_PERMISSIONS, COMPANY_PERMISSIONS, BRANCH_PERMISSIONS, USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AUTH_STATE_PROVIDER, PermissionValidatorService, TranslatePipe, AngularModule, PrimeModule, HasPermissionDirective, FileUrlService, FILE_PROVIDER, PROFILE_PERMISSION_PROVIDER, FileUploaderComponent } from '@flusys/ng-shared';
8
+ import { PlatformService, TranslateService, ApiResourceService, CookieService, resolveTranslationModule, SHARED_MESSAGES, permissionGuard, USER_PERMISSIONS, COMPANY_PERMISSIONS, BRANCH_PERMISSIONS, USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AUTH_STATE_PROVIDER, PermissionValidatorService, TranslatePipe, AngularModule, PrimeModule, HasPermissionDirective, BaseFormComponent, BaseListComponent, BaseListTemplateDirective, FileUrlService, FILE_PROVIDER, PROFILE_PERMISSION_PROVIDER, FileUploaderComponent } from '@flusys/ng-shared';
9
9
  import { map as map$1, catchError as catchError$1, tap as tap$1 } from 'rxjs/operators';
10
10
  import * as i1$1 from '@angular/common';
11
11
  import { isPlatformBrowser, CommonModule } from '@angular/common';
@@ -2399,736 +2399,218 @@ var branchList_component = /*#__PURE__*/Object.freeze({
2399
2399
  BranchListComponent: BranchListComponent
2400
2400
  });
2401
2401
 
2402
- /**
2403
- * Company Form Component
2404
- * Handles creating and editing companies.
2405
- */
2406
- class CompanyFormComponent {
2407
- router = inject(Router);
2408
- route = inject(ActivatedRoute);
2409
- messageService = inject(MessageService);
2410
- companyService = inject(CompanyApiService);
2411
- translateAdapter = inject(TranslateService, {
2412
- optional: true,
2413
- });
2414
- translate(key, vars) {
2415
- return this.translateAdapter?.translate(key, vars) ?? key;
2416
- }
2417
- // Route params as signal
2418
- routeParams = toSignal(this.route.paramMap);
2419
- /** Loading state */
2420
- isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
2421
- /** Existing company data when editing */
2422
- existingCompany = signal(null, ...(ngDevMode ? [{ debugName: "existingCompany" }] : []));
2423
- /** Whether in edit mode */
2424
- isEditMode = computed(() => !!this.existingCompany(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
2425
- // ============================================
2426
- // Form (Signal Forms)
2427
- // ============================================
2428
- /** Form model */
2429
- formModel = signal({
2430
- name: '',
2431
- slug: '',
2432
- email: '',
2433
- phone: '',
2434
- website: '',
2435
- address: '',
2436
- isActive: true,
2437
- }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
2438
- /** Form with validation schema */
2439
- companyForm = form(this.formModel, (f) => {
2440
- required(f.name, { message: this.translate('shared.name.required') });
2441
- required(f.slug, {
2442
- message: this.translate('administrative.company.slug.required'),
2443
- });
2444
- });
2445
- /** Check if form is valid */
2446
- isFormValid = computed(() => {
2447
- const model = this.formModel();
2448
- return model.name.trim().length > 0 && model.slug.trim().length > 0;
2449
- }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
2450
- constructor() {
2451
- // Effect to handle route-based initialization
2452
- effect(() => {
2453
- const params = this.routeParams();
2454
- if (!params)
2455
- return;
2456
- const id = params.get('id');
2457
- if (id && id !== 'new') {
2458
- this.loadCompany(id);
2459
- }
2460
- });
2461
- }
2462
- async loadCompany(id) {
2463
- this.isLoading.set(true);
2464
- try {
2465
- const response = await this.companyService.findById(id);
2466
- if (response.success && response.data) {
2467
- this.existingCompany.set(response.data);
2468
- this.formModel.set({
2469
- name: response.data.name,
2470
- slug: response.data.slug,
2471
- email: response.data.email || '',
2472
- phone: response.data.phone || '',
2473
- website: response.data.website || '',
2474
- address: response.data.address || '',
2475
- isActive: response.data.isActive,
2476
- });
2477
- }
2478
- }
2479
- catch {
2480
- // Error toast handled by global interceptor
2481
- this.router.navigate(['/administration/company']);
2482
- }
2483
- finally {
2484
- this.isLoading.set(false);
2485
- }
2486
- }
2487
- generateSlug() {
2488
- const model = this.formModel();
2489
- if (!model.slug && model.name) {
2490
- const slug = model.name
2491
- .toLowerCase()
2492
- .replace(/[^a-z0-9]+/g, '-')
2493
- .replace(/^-|-$/g, '');
2494
- this.formModel.update((m) => ({ ...m, slug }));
2495
- }
2496
- }
2497
- async onSubmit() {
2498
- if (!this.isFormValid()) {
2499
- this.messageService.add({
2500
- severity: 'error',
2501
- summary: this.translate('shared.validation.error'),
2502
- detail: this.translate('shared.fill.required.fields'),
2503
- });
2504
- return;
2505
- }
2506
- this.isLoading.set(true);
2507
- try {
2508
- const isEdit = this.isEditMode() && this.existingCompany();
2509
- let response;
2510
- if (isEdit) {
2511
- const updateData = {
2512
- id: this.existingCompany().id,
2513
- ...this.buildCompanyData(),
2514
- };
2515
- response = await this.companyService.update(updateData);
2516
- }
2517
- else {
2518
- response = await this.companyService.insert(this.buildCompanyData());
2519
- }
2520
- this.messageService.add({
2521
- severity: 'success',
2522
- summary: this.translate('shared.success'),
2523
- detail: response.messageKey
2524
- ? this.translate(response.messageKey, response.messageVariables)
2525
- : (response.message ?? ''),
2526
- });
2527
- this.router.navigate(['/administration/company']);
2528
- }
2529
- catch {
2530
- // Error toast handled by global interceptor
2531
- }
2532
- finally {
2533
- this.isLoading.set(false);
2534
- }
2535
- }
2536
- onCancel() {
2537
- this.router.navigate(['/administration/company']);
2538
- }
2539
- /** Build company data from form model */
2540
- buildCompanyData() {
2541
- const model = this.formModel();
2542
- return {
2543
- name: model.name,
2544
- slug: model.slug,
2545
- email: model.email || undefined,
2546
- phone: model.phone || undefined,
2547
- website: model.website || undefined,
2548
- address: model.address || undefined,
2549
- isActive: model.isActive,
2550
- };
2551
- }
2552
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2553
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", ngImport: i0, template: `
2554
- <p-card>
2555
- <ng-template #header>
2556
- <div class="flex justify-between items-center p-4">
2557
- <h2 class="text-xl font-semibold m-0">
2558
- {{
2559
- isEditMode()
2560
- ? ('administrative.company.edit' | translate)
2561
- : ('administrative.company.new' | translate)
2562
- }}
2563
- </h2>
2564
- </div>
2565
- </ng-template>
2566
-
2567
- <form
2568
- (ngSubmit)="onSubmit()"
2569
- class="grid grid-cols-1 md:grid-cols-2 gap-4"
2570
- >
2571
- <!-- Name -->
2572
- <div class="flex flex-col gap-2">
2573
- <label for="name" class="font-medium"
2574
- >{{ 'administrative.company.name' | translate }} *</label
2575
- >
2576
- <input
2577
- pInputText
2578
- id="name"
2579
- [formField]="companyForm.name"
2580
- (blur)="generateSlug()"
2581
- [placeholder]="
2582
- 'administrative.company.name.placeholder' | translate
2583
- "
2584
- />
2585
- </div>
2586
-
2587
- <!-- Slug -->
2588
- <div class="flex flex-col gap-2">
2589
- <label for="slug" class="font-medium"
2590
- >{{ 'administrative.company.slug' | translate }} *</label
2591
- >
2592
- <input
2593
- pInputText
2594
- id="slug"
2595
- [formField]="companyForm.slug"
2596
- [placeholder]="
2597
- 'administrative.company.slug.placeholder' | translate
2598
- "
2599
- />
2600
- </div>
2601
-
2602
- <!-- Email -->
2603
- <div class="flex flex-col gap-2">
2604
- <label for="email" class="font-medium">{{
2605
- 'administrative.email.label' | translate
2606
- }}</label>
2607
- <input
2608
- pInputText
2609
- id="email"
2610
- type="email"
2611
- [formField]="companyForm.email"
2612
- [placeholder]="'administrative.email.placeholder' | translate"
2613
- />
2614
- </div>
2615
-
2616
- <!-- Phone -->
2617
- <div class="flex flex-col gap-2">
2618
- <label for="phone" class="font-medium">{{
2619
- 'administrative.phone.label' | translate
2620
- }}</label>
2621
- <input
2622
- pInputText
2623
- id="phone"
2624
- [formField]="companyForm.phone"
2625
- [placeholder]="'administrative.phone.placeholder' | translate"
2626
- />
2627
- </div>
2628
-
2629
- <!-- Website -->
2630
- <div class="flex flex-col gap-2">
2631
- <label for="website" class="font-medium">{{
2632
- 'administrative.company.website' | translate
2633
- }}</label>
2634
- <input
2635
- pInputText
2636
- id="website"
2637
- [formField]="companyForm.website"
2638
- [placeholder]="
2639
- 'administrative.company.website.placeholder' | translate
2640
- "
2641
- />
2642
- </div>
2643
-
2644
- <!-- Is Active -->
2645
- <div class="flex items-center pt-6">
2646
- <label class="p-checkbox-native">
2647
- <input type="checkbox" [formField]="companyForm.isActive" />
2648
- <span>{{ 'shared.active' | translate }}</span>
2649
- </label>
2650
- </div>
2651
-
2652
- <!-- Address -->
2653
- <div class="flex flex-col gap-2 md:col-span-2">
2654
- <label for="address" class="font-medium">{{
2655
- 'administrative.address.label' | translate
2656
- }}</label>
2657
- <textarea
2658
- id="address"
2659
- class="p-inputtextarea p-inputtext p-component"
2660
- [formField]="companyForm.address"
2661
- [placeholder]="'administrative.address.placeholder' | translate"
2662
- rows="3"
2663
- ></textarea>
2664
- </div>
2665
-
2666
- <!-- Actions -->
2667
- <div class="flex justify-end gap-4 md:col-span-2 pt-4">
2668
- <p-button
2669
- [label]="'shared.cancel' | translate"
2670
- severity="secondary"
2671
- [outlined]="true"
2672
- (onClick)="onCancel()"
2673
- />
2674
- <p-button
2675
- [label]="
2676
- isEditMode()
2677
- ? ('shared.update' | translate)
2678
- : ('shared.create' | translate)
2679
- "
2680
- type="submit"
2681
- [loading]="isLoading()"
2682
- [disabled]="!isFormValid() || isLoading()"
2683
- />
2684
- </div>
2685
- </form>
2686
- </p-card>
2687
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
2688
- }
2689
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, decorators: [{
2690
- type: Component,
2691
- args: [{
2692
- selector: 'lib-company-form',
2693
- imports: [AngularModule, PrimeModule, FormField, TranslatePipe],
2694
- template: `
2695
- <p-card>
2696
- <ng-template #header>
2697
- <div class="flex justify-between items-center p-4">
2698
- <h2 class="text-xl font-semibold m-0">
2699
- {{
2700
- isEditMode()
2701
- ? ('administrative.company.edit' | translate)
2702
- : ('administrative.company.new' | translate)
2703
- }}
2704
- </h2>
2705
- </div>
2706
- </ng-template>
2707
-
2708
- <form
2709
- (ngSubmit)="onSubmit()"
2710
- class="grid grid-cols-1 md:grid-cols-2 gap-4"
2711
- >
2712
- <!-- Name -->
2713
- <div class="flex flex-col gap-2">
2714
- <label for="name" class="font-medium"
2715
- >{{ 'administrative.company.name' | translate }} *</label
2716
- >
2717
- <input
2718
- pInputText
2719
- id="name"
2720
- [formField]="companyForm.name"
2721
- (blur)="generateSlug()"
2722
- [placeholder]="
2723
- 'administrative.company.name.placeholder' | translate
2724
- "
2725
- />
2726
- </div>
2727
-
2728
- <!-- Slug -->
2729
- <div class="flex flex-col gap-2">
2730
- <label for="slug" class="font-medium"
2731
- >{{ 'administrative.company.slug' | translate }} *</label
2732
- >
2733
- <input
2734
- pInputText
2735
- id="slug"
2736
- [formField]="companyForm.slug"
2737
- [placeholder]="
2738
- 'administrative.company.slug.placeholder' | translate
2739
- "
2740
- />
2741
- </div>
2742
-
2743
- <!-- Email -->
2744
- <div class="flex flex-col gap-2">
2745
- <label for="email" class="font-medium">{{
2746
- 'administrative.email.label' | translate
2747
- }}</label>
2748
- <input
2749
- pInputText
2750
- id="email"
2751
- type="email"
2752
- [formField]="companyForm.email"
2753
- [placeholder]="'administrative.email.placeholder' | translate"
2754
- />
2755
- </div>
2756
-
2757
- <!-- Phone -->
2758
- <div class="flex flex-col gap-2">
2759
- <label for="phone" class="font-medium">{{
2760
- 'administrative.phone.label' | translate
2761
- }}</label>
2762
- <input
2763
- pInputText
2764
- id="phone"
2765
- [formField]="companyForm.phone"
2766
- [placeholder]="'administrative.phone.placeholder' | translate"
2767
- />
2768
- </div>
2769
-
2770
- <!-- Website -->
2771
- <div class="flex flex-col gap-2">
2772
- <label for="website" class="font-medium">{{
2773
- 'administrative.company.website' | translate
2774
- }}</label>
2775
- <input
2776
- pInputText
2777
- id="website"
2778
- [formField]="companyForm.website"
2779
- [placeholder]="
2780
- 'administrative.company.website.placeholder' | translate
2781
- "
2782
- />
2783
- </div>
2784
-
2785
- <!-- Is Active -->
2786
- <div class="flex items-center pt-6">
2787
- <label class="p-checkbox-native">
2788
- <input type="checkbox" [formField]="companyForm.isActive" />
2789
- <span>{{ 'shared.active' | translate }}</span>
2790
- </label>
2791
- </div>
2792
-
2793
- <!-- Address -->
2794
- <div class="flex flex-col gap-2 md:col-span-2">
2795
- <label for="address" class="font-medium">{{
2796
- 'administrative.address.label' | translate
2797
- }}</label>
2798
- <textarea
2799
- id="address"
2800
- class="p-inputtextarea p-inputtext p-component"
2801
- [formField]="companyForm.address"
2802
- [placeholder]="'administrative.address.placeholder' | translate"
2803
- rows="3"
2804
- ></textarea>
2805
- </div>
2806
-
2807
- <!-- Actions -->
2808
- <div class="flex justify-end gap-4 md:col-span-2 pt-4">
2809
- <p-button
2810
- [label]="'shared.cancel' | translate"
2811
- severity="secondary"
2812
- [outlined]="true"
2813
- (onClick)="onCancel()"
2814
- />
2815
- <p-button
2816
- [label]="
2817
- isEditMode()
2818
- ? ('shared.update' | translate)
2819
- : ('shared.create' | translate)
2820
- "
2821
- type="submit"
2822
- [loading]="isLoading()"
2823
- [disabled]="!isFormValid() || isLoading()"
2824
- />
2825
- </div>
2826
- </form>
2827
- </p-card>
2402
+ class CompanyFormComponent {
2403
+ route = inject(ActivatedRoute);
2404
+ translateAdapter = inject(TranslateService, { optional: true });
2405
+ companyService = inject(CompanyApiService);
2406
+ formRef = viewChild(BaseFormComponent, ...(ngDevMode ? [{ debugName: "formRef" }] : []));
2407
+ routeParams = toSignal(this.route.paramMap);
2408
+ editId = computed(() => {
2409
+ const id = this.routeParams()?.get('id');
2410
+ return id && id !== 'new' ? id : null;
2411
+ }, ...(ngDevMode ? [{ debugName: "editId" }] : []));
2412
+ fields = [
2413
+ {
2414
+ key: 'name',
2415
+ type: 'text',
2416
+ label: this.t('administrative.company.name'),
2417
+ placeholder: this.t('administrative.company.name.placeholder'),
2418
+ required: true,
2419
+ },
2420
+ {
2421
+ key: 'slug',
2422
+ type: 'text',
2423
+ label: this.t('administrative.company.slug'),
2424
+ placeholder: this.t('administrative.company.slug.placeholder'),
2425
+ required: true,
2426
+ },
2427
+ {
2428
+ key: 'email',
2429
+ type: 'email',
2430
+ label: this.t('administrative.email.label'),
2431
+ placeholder: this.t('administrative.email.placeholder'),
2432
+ },
2433
+ {
2434
+ key: 'phone',
2435
+ type: 'text',
2436
+ label: this.t('administrative.phone.label'),
2437
+ placeholder: this.t('administrative.phone.placeholder'),
2438
+ },
2439
+ {
2440
+ key: 'website',
2441
+ type: 'text',
2442
+ label: this.t('administrative.company.website'),
2443
+ placeholder: this.t('administrative.company.website.placeholder'),
2444
+ },
2445
+ {
2446
+ key: 'isActive',
2447
+ type: 'toggle',
2448
+ label: this.t('shared.active'),
2449
+ },
2450
+ {
2451
+ key: 'address',
2452
+ type: 'textarea',
2453
+ label: this.t('administrative.address.label'),
2454
+ placeholder: this.t('administrative.address.placeholder'),
2455
+ fullWidth: true,
2456
+ rows: 3,
2457
+ },
2458
+ ];
2459
+ buildRequest = (data, editId) => ({
2460
+ ...(editId ? { id: editId } : {}),
2461
+ name: data['name'],
2462
+ slug: data['slug'],
2463
+ email: data['email'] || undefined,
2464
+ phone: data['phone'] || undefined,
2465
+ website: data['website'] || undefined,
2466
+ address: data['address'] || undefined,
2467
+ isActive: data['isActive'],
2468
+ });
2469
+ toFormModel = (entity) => {
2470
+ const c = entity;
2471
+ return {
2472
+ name: c.name,
2473
+ slug: c.slug,
2474
+ email: c.email ?? '',
2475
+ phone: c.phone ?? '',
2476
+ website: c.website ?? '',
2477
+ address: c.address ?? '',
2478
+ isActive: c.isActive,
2479
+ };
2480
+ };
2481
+ onFormValueChange(data) {
2482
+ const name = data['name'] ?? '';
2483
+ const slug = data['slug'] ?? '';
2484
+ if (name && !slug) {
2485
+ this.formRef()?.setFieldValue('slug', name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''));
2486
+ }
2487
+ }
2488
+ t(key, vars) {
2489
+ return this.translateAdapter?.translate(key, vars) ?? key;
2490
+ }
2491
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2492
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.5", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", viewQueries: [{ propertyName: "formRef", first: true, predicate: BaseFormComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
2493
+ <lib-base-form
2494
+ [fields]="fields"
2495
+ [service]="companyService"
2496
+ [editId]="editId()"
2497
+ [cancelRoute]="'/administration/company'"
2498
+ [navigateOnSuccess]="'/administration/company'"
2499
+ [createTitle]="'administrative.company.new' | translate"
2500
+ [editTitle]="'administrative.company.edit' | translate"
2501
+ [mapToRequest]="buildRequest"
2502
+ [mapFromEntity]="toFormModel"
2503
+ (onValueChange)="onFormValueChange($event)"
2504
+ />
2505
+ `, isInline: true, dependencies: [{ kind: "component", type: BaseFormComponent, selector: "lib-base-form", inputs: ["fields", "title", "createTitle", "editTitle", "columns", "submitLabel", "cancelLabel", "isLoading", "isEditMode", "initialValue", "service", "editId", "cancelRoute", "navigateOnSuccess", "mapToRequest", "mapFromEntity"], outputs: ["onSubmit", "onCancel", "onValueChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
2506
+ }
2507
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, decorators: [{
2508
+ type: Component,
2509
+ args: [{
2510
+ selector: 'lib-company-form',
2511
+ imports: [BaseFormComponent, TranslatePipe],
2512
+ template: `
2513
+ <lib-base-form
2514
+ [fields]="fields"
2515
+ [service]="companyService"
2516
+ [editId]="editId()"
2517
+ [cancelRoute]="'/administration/company'"
2518
+ [navigateOnSuccess]="'/administration/company'"
2519
+ [createTitle]="'administrative.company.new' | translate"
2520
+ [editTitle]="'administrative.company.edit' | translate"
2521
+ [mapToRequest]="buildRequest"
2522
+ [mapFromEntity]="toFormModel"
2523
+ (onValueChange)="onFormValueChange($event)"
2524
+ />
2828
2525
  `,
2829
2526
  }]
2830
- }], ctorParameters: () => [] });
2527
+ }], propDecorators: { formRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => BaseFormComponent), { isSignal: true }] }] } });
2831
2528
 
2832
2529
  var companyForm_component = /*#__PURE__*/Object.freeze({
2833
2530
  __proto__: null,
2834
2531
  CompanyFormComponent: CompanyFormComponent
2835
2532
  });
2836
2533
 
2837
- /**
2838
- * Company List Component
2839
- * Displays a list of companies with CRUD operations.
2840
- * Only visible when company feature is enabled.
2841
- */
2842
2534
  class CompanyListComponent {
2843
- // Permission constants for template
2844
- COMPANY_PERMISSIONS = COMPANY_PERMISSIONS;
2845
- BRANCH_PERMISSIONS = BRANCH_PERMISSIONS;
2535
+ permissionValidator = inject(PermissionValidatorService);
2536
+ translateAdapter = inject(TranslateService, { optional: true });
2846
2537
  router = inject(Router);
2847
- messageService = inject(MessageService);
2848
- confirmationService = inject(ConfirmationService);
2849
2538
  companyService = inject(CompanyApiService);
2850
- translateAdapter = inject(TranslateService, {
2851
- optional: true,
2852
- });
2853
- translate(key, vars) {
2854
- return this.translateAdapter?.translate(key, vars) ?? key;
2855
- }
2856
- /** Companies from service */
2857
- companies = this.companyService.data;
2858
- /** Loading state from service */
2859
- isLoading = this.companyService.isLoading;
2860
- /** Total count from service */
2861
- total = this.companyService.total;
2862
- onLazyLoad(event) {
2863
- const first = event.first ?? 0;
2864
- const rows = event.rows ?? 10;
2865
- const page = Math.floor(first / rows);
2866
- this.companyService.fetchList('', {
2867
- pagination: { currentPage: page, pageSize: rows },
2868
- });
2869
- }
2870
- onCreate() {
2871
- this.router.navigate(['/administration/company/new']);
2872
- }
2873
- onEdit(company) {
2874
- this.router.navigate(['/administration/company', company.id]);
2875
- }
2876
- onViewBranches(company) {
2877
- this.router.navigate(['/administration/branch'], {
2878
- queryParams: { companyId: company.id },
2879
- });
2880
- }
2881
- onDelete(company) {
2882
- this.confirmationService.confirm({
2883
- message: this.translate('shared.confirm.delete.item', {
2884
- name: company.name,
2539
+ canCreate = computed(() => this.permissionValidator.hasPermission(COMPANY_PERMISSIONS.CREATE), ...(ngDevMode ? [{ debugName: "canCreate" }] : []));
2540
+ canEditFn = (_item) => this.permissionValidator.hasPermission(COMPANY_PERMISSIONS.UPDATE);
2541
+ canDeleteFn = (item) => !item.readOnly && this.permissionValidator.hasPermission(COMPANY_PERMISSIONS.DELETE);
2542
+ viewBranchesAction = [{
2543
+ icon: 'pi pi-building',
2544
+ tooltip: 'administrative.branch.view.branches',
2545
+ severity: 'secondary',
2546
+ show: () => this.permissionValidator.hasPermission(BRANCH_PERMISSIONS.READ),
2547
+ handler: (c) => this.router.navigate(['/administration/branch'], {
2548
+ queryParams: { companyId: c.id },
2885
2549
  }),
2886
- header: this.translate('administrative.company.delete.title'),
2887
- icon: 'pi pi-exclamation-triangle',
2888
- acceptButtonStyleClass: 'p-button-danger',
2889
- accept: async () => {
2890
- try {
2891
- const response = await this.companyService.delete({
2892
- id: company.id,
2893
- type: 'delete',
2894
- });
2895
- this.messageService.add({
2896
- severity: 'success',
2897
- summary: this.translate('shared.success'),
2898
- detail: response?.messageKey
2899
- ? this.translate(response.messageKey, response.messageVariables)
2900
- : (response?.message ?? ''),
2901
- });
2902
- this.companyService.reload();
2903
- }
2904
- catch {
2905
- // Error toast handled by global interceptor
2906
- }
2907
- },
2908
- });
2550
+ }];
2551
+ columns = [
2552
+ { field: 'name', header: this.t('administrative.company.name'), type: 'text' },
2553
+ { field: 'slug', header: this.t('administrative.company.slug'), type: 'text' },
2554
+ { field: 'email', header: this.t('administrative.email.label'), type: 'text' },
2555
+ { field: 'phone', header: this.t('administrative.phone.label'), type: 'text' },
2556
+ { field: 'isActive', header: this.t('shared.status'), type: 'custom' },
2557
+ ];
2558
+ asCompany(item) {
2559
+ return item;
2560
+ }
2561
+ t(key) {
2562
+ return this.translateAdapter?.translate(key) ?? key;
2909
2563
  }
2910
2564
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2911
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2912
- <p-card>
2913
- <ng-template #header>
2914
- <div
2915
- class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4"
2916
- >
2917
- <h2 class="text-xl font-semibold m-0">
2918
- {{ 'administrative.company.title' | translate }}
2919
- </h2>
2920
- <p-button
2921
- *hasPermission="COMPANY_PERMISSIONS.CREATE"
2922
- [label]="'administrative.company.add' | translate"
2923
- icon="pi pi-plus"
2924
- (onClick)="onCreate()"
2925
- />
2926
- </div>
2565
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2566
+ <lib-base-list
2567
+ [columns]="columns"
2568
+ [actions]="viewBranchesAction"
2569
+ [service]="companyService"
2570
+ [title]="'administrative.company.title' | translate"
2571
+ [showCreateButton]="canCreate()"
2572
+ [createButtonLabel]="'administrative.company.add' | translate"
2573
+ [createRoute]="'/administration/company/new'"
2574
+ [editRoute]="'/administration/company'"
2575
+ [deleteConfirmField]="'name'"
2576
+ [canEdit]="canEditFn"
2577
+ [canDelete]="canDeleteFn"
2578
+ >
2579
+ <ng-template baseListTemplate="isActive" let-item>
2580
+ <p-tag
2581
+ [value]="asCompany(item).isActive ? ('shared.active' | translate) : ('shared.inactive' | translate)"
2582
+ [severity]="asCompany(item).isActive ? 'success' : 'danger'"
2583
+ />
2927
2584
  </ng-template>
2928
-
2929
- <div class="overflow-x-auto">
2930
- <p-table
2931
- [value]="companies()"
2932
- [loading]="isLoading()"
2933
- [paginator]="total() > 0"
2934
- [rows]="10"
2935
- [rowsPerPageOptions]="[10, 25, 50]"
2936
- [totalRecords]="total()"
2937
- [lazy]="true"
2938
- (onLazyLoad)="onLazyLoad($event)"
2939
- [scrollable]="true"
2940
- styleClass="p-datatable-striped"
2941
- >
2942
- <ng-template #header>
2943
- <tr>
2944
- <th>{{ 'administrative.company.name' | translate }}</th>
2945
- <th>{{ 'administrative.company.slug' | translate }}</th>
2946
- <th>{{ 'administrative.email.label' | translate }}</th>
2947
- <th>{{ 'administrative.phone.label' | translate }}</th>
2948
- <th>{{ 'shared.status' | translate }}</th>
2949
- <th class="w-[150px]">{{ 'shared.actions' | translate }}</th>
2950
- </tr>
2951
- </ng-template>
2952
- <ng-template #body let-company>
2953
- <tr>
2954
- <td>{{ company.name }}</td>
2955
- <td>{{ company.slug }}</td>
2956
- <td>{{ company.email || '-' }}</td>
2957
- <td>{{ company.phone || '-' }}</td>
2958
- <td>
2959
- <p-tag
2960
- [value]="
2961
- company.isActive
2962
- ? ('shared.active' | translate)
2963
- : ('shared.inactive' | translate)
2964
- "
2965
- [severity]="company.isActive ? 'success' : 'danger'"
2966
- />
2967
- </td>
2968
- <td>
2969
- <div class="flex gap-2">
2970
- <p-button
2971
- *hasPermission="COMPANY_PERMISSIONS.UPDATE"
2972
- icon="pi pi-pencil"
2973
- [rounded]="true"
2974
- [text]="true"
2975
- severity="info"
2976
- [pTooltip]="'shared.edit' | translate"
2977
- (onClick)="onEdit(company)"
2978
- />
2979
- <p-button
2980
- *hasPermission="BRANCH_PERMISSIONS.READ"
2981
- icon="pi pi-building"
2982
- [rounded]="true"
2983
- [text]="true"
2984
- severity="secondary"
2985
- [pTooltip]="
2986
- 'administrative.branch.view.branches' | translate
2987
- "
2988
- (onClick)="onViewBranches(company)"
2989
- />
2990
- @if (!company.readOnly) {
2991
- <p-button
2992
- *hasPermission="COMPANY_PERMISSIONS.DELETE"
2993
- icon="pi pi-trash"
2994
- [rounded]="true"
2995
- [text]="true"
2996
- severity="danger"
2997
- [pTooltip]="'shared.delete' | translate"
2998
- (onClick)="onDelete(company)"
2999
- />
3000
- }
3001
- </div>
3002
- </td>
3003
- </tr>
3004
- </ng-template>
3005
- <ng-template #emptymessage>
3006
- <tr>
3007
- <td colspan="6" class="text-center py-8">
3008
- {{ 'administrative.company.no.companies' | translate }}
3009
- </td>
3010
- </tr>
3011
- </ng-template>
3012
- </p-table>
3013
- </div>
3014
- </p-card>
3015
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
2585
+ </lib-base-list>
2586
+ `, isInline: true, dependencies: [{ kind: "component", type: BaseListComponent, selector: "lib-base-list", inputs: ["columns", "actions", "title", "showCreateButton", "searchable", "pageSize", "emptyMessage", "createButtonLabel", "createButtonIcon", "data", "total", "isLoading", "service", "filter", "createRoute", "editRoute", "deleteConfirmField", "idField", "canEdit", "canDelete"], outputs: ["onCreate", "onLazyLoad", "onSearch"] }, { kind: "directive", type: BaseListTemplateDirective, selector: "ng-template[baseListTemplate]", inputs: ["baseListTemplate"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
3016
2587
  }
3017
2588
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyListComponent, decorators: [{
3018
2589
  type: Component,
3019
2590
  args: [{
3020
2591
  selector: 'lib-company-list',
3021
- imports: [
3022
- AngularModule,
3023
- PrimeModule,
3024
- TagModule,
3025
- HasPermissionDirective,
3026
- TranslatePipe,
3027
- ],
2592
+ imports: [BaseListComponent, BaseListTemplateDirective, PrimeModule, TranslatePipe],
3028
2593
  template: `
3029
- <p-card>
3030
- <ng-template #header>
3031
- <div
3032
- class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4"
3033
- >
3034
- <h2 class="text-xl font-semibold m-0">
3035
- {{ 'administrative.company.title' | translate }}
3036
- </h2>
3037
- <p-button
3038
- *hasPermission="COMPANY_PERMISSIONS.CREATE"
3039
- [label]="'administrative.company.add' | translate"
3040
- icon="pi pi-plus"
3041
- (onClick)="onCreate()"
3042
- />
3043
- </div>
2594
+ <lib-base-list
2595
+ [columns]="columns"
2596
+ [actions]="viewBranchesAction"
2597
+ [service]="companyService"
2598
+ [title]="'administrative.company.title' | translate"
2599
+ [showCreateButton]="canCreate()"
2600
+ [createButtonLabel]="'administrative.company.add' | translate"
2601
+ [createRoute]="'/administration/company/new'"
2602
+ [editRoute]="'/administration/company'"
2603
+ [deleteConfirmField]="'name'"
2604
+ [canEdit]="canEditFn"
2605
+ [canDelete]="canDeleteFn"
2606
+ >
2607
+ <ng-template baseListTemplate="isActive" let-item>
2608
+ <p-tag
2609
+ [value]="asCompany(item).isActive ? ('shared.active' | translate) : ('shared.inactive' | translate)"
2610
+ [severity]="asCompany(item).isActive ? 'success' : 'danger'"
2611
+ />
3044
2612
  </ng-template>
3045
-
3046
- <div class="overflow-x-auto">
3047
- <p-table
3048
- [value]="companies()"
3049
- [loading]="isLoading()"
3050
- [paginator]="total() > 0"
3051
- [rows]="10"
3052
- [rowsPerPageOptions]="[10, 25, 50]"
3053
- [totalRecords]="total()"
3054
- [lazy]="true"
3055
- (onLazyLoad)="onLazyLoad($event)"
3056
- [scrollable]="true"
3057
- styleClass="p-datatable-striped"
3058
- >
3059
- <ng-template #header>
3060
- <tr>
3061
- <th>{{ 'administrative.company.name' | translate }}</th>
3062
- <th>{{ 'administrative.company.slug' | translate }}</th>
3063
- <th>{{ 'administrative.email.label' | translate }}</th>
3064
- <th>{{ 'administrative.phone.label' | translate }}</th>
3065
- <th>{{ 'shared.status' | translate }}</th>
3066
- <th class="w-[150px]">{{ 'shared.actions' | translate }}</th>
3067
- </tr>
3068
- </ng-template>
3069
- <ng-template #body let-company>
3070
- <tr>
3071
- <td>{{ company.name }}</td>
3072
- <td>{{ company.slug }}</td>
3073
- <td>{{ company.email || '-' }}</td>
3074
- <td>{{ company.phone || '-' }}</td>
3075
- <td>
3076
- <p-tag
3077
- [value]="
3078
- company.isActive
3079
- ? ('shared.active' | translate)
3080
- : ('shared.inactive' | translate)
3081
- "
3082
- [severity]="company.isActive ? 'success' : 'danger'"
3083
- />
3084
- </td>
3085
- <td>
3086
- <div class="flex gap-2">
3087
- <p-button
3088
- *hasPermission="COMPANY_PERMISSIONS.UPDATE"
3089
- icon="pi pi-pencil"
3090
- [rounded]="true"
3091
- [text]="true"
3092
- severity="info"
3093
- [pTooltip]="'shared.edit' | translate"
3094
- (onClick)="onEdit(company)"
3095
- />
3096
- <p-button
3097
- *hasPermission="BRANCH_PERMISSIONS.READ"
3098
- icon="pi pi-building"
3099
- [rounded]="true"
3100
- [text]="true"
3101
- severity="secondary"
3102
- [pTooltip]="
3103
- 'administrative.branch.view.branches' | translate
3104
- "
3105
- (onClick)="onViewBranches(company)"
3106
- />
3107
- @if (!company.readOnly) {
3108
- <p-button
3109
- *hasPermission="COMPANY_PERMISSIONS.DELETE"
3110
- icon="pi pi-trash"
3111
- [rounded]="true"
3112
- [text]="true"
3113
- severity="danger"
3114
- [pTooltip]="'shared.delete' | translate"
3115
- (onClick)="onDelete(company)"
3116
- />
3117
- }
3118
- </div>
3119
- </td>
3120
- </tr>
3121
- </ng-template>
3122
- <ng-template #emptymessage>
3123
- <tr>
3124
- <td colspan="6" class="text-center py-8">
3125
- {{ 'administrative.company.no.companies' | translate }}
3126
- </td>
3127
- </tr>
3128
- </ng-template>
3129
- </p-table>
3130
- </div>
3131
- </p-card>
2613
+ </lib-base-list>
3132
2614
  `,
3133
2615
  }]
3134
2616
  }] });