@nettyapps/ntybase 21.1.25 → 21.1.27

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.
@@ -319,13 +319,7 @@ class ConfirmDialog {
319
319
  }
320
320
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ConfirmDialog, decorators: [{
321
321
  type: Component,
322
- args: [{ selector: 'ntybase-confirm-dialog', imports: [
323
- MatDialogModule,
324
- MatSnackBarModule,
325
- MatIconModule,
326
- MatDividerModule,
327
- TranslateModule,
328
- ], template: "<div class=\"dialog-container\">\n <h2 mat-dialog-title class=\"dialog-title\">\n <mat-icon color=\"warn\" class=\"warning-icon\">warning</mat-icon>\n <span>{{data.title | translate}}</span>\n </h2>\n\n <mat-divider class=\"divider\"></mat-divider>\n\n <mat-dialog-content class=\"dialog-content\">\n <p class=\"message\">{{data.message | translate}}</p>\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button mat-stroked-button [mat-dialog-close]=\"false\" class=\"btn-cancel\">\n {{'@btnCancel' | translate}}\n </button>\n <button\n mat-flat-button\n color=\"warn\"\n [mat-dialog-close]=\"true\"\n class=\"btn-ok\"\n >\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{display:flex;flex-direction:column;min-width:400px;max-width:90vw;padding:24px;border-radius:12px!important}.dialog-title{display:flex;align-items:center;margin:0 0 12px;padding:0;color:var(--mat-sys-primary)}.dialog-title span{margin-left:8px}.warning-icon{color:var(--mat-sys-primary);transform:scale(1.2)}.divider{margin:8px 0 16px;border-top-color:var(--mat-sys-primary)}.dialog-content{padding:8px 0 24px;margin:0;color:var(--mat-sys-primary);line-height:1.6}.dialog-content .message{margin:0;white-space:pre-wrap}.dialog-actions{padding:16px 0 0;margin:0;gap:8px}.btn-ok{padding:8px 16px;border-radius:6px;font-weight:500;background-color:var(--mat-sys-primary);color:var(--mat-sys-primary-container)}.btn-cancel{padding:8px 16px;border-radius:6px;color:var(--mat-sys-secondary-container);background-color:var(--mat-sys-secondary)}\n"] }]
322
+ args: [{ selector: 'ntybase-confirm-dialog', imports: [MatDialogModule, MatSnackBarModule, MatIconModule, MatDividerModule, TranslateModule], template: "<div class=\"dialog-container\">\n <h2 mat-dialog-title class=\"dialog-title\">\n <mat-icon color=\"warn\" class=\"warning-icon\">warning</mat-icon>\n <span>{{data.title | translate}}</span>\n </h2>\n\n <mat-divider class=\"divider\"></mat-divider>\n\n <mat-dialog-content class=\"dialog-content\">\n <p class=\"message\">{{data.message | translate}}</p>\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button mat-stroked-button [mat-dialog-close]=\"false\" class=\"btn-cancel\">\n {{'@btnCancel' | translate}}\n </button>\n <button\n mat-flat-button\n color=\"warn\"\n [mat-dialog-close]=\"true\"\n class=\"btn-ok\"\n >\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{display:flex;flex-direction:column;min-width:400px;max-width:90vw;padding:24px;border-radius:12px!important}.dialog-title{display:flex;align-items:center;margin:0 0 12px;padding:0;color:var(--mat-sys-primary)}.dialog-title span{margin-left:8px}.warning-icon{color:var(--mat-sys-primary);transform:scale(1.2)}.divider{margin:8px 0 16px;border-top-color:var(--mat-sys-primary)}.dialog-content{padding:8px 0 24px;margin:0;color:var(--mat-sys-primary);line-height:1.6}.dialog-content .message{margin:0;white-space:pre-wrap}.dialog-actions{padding:16px 0 0;margin:0;gap:8px}.btn-ok{padding:8px 16px;border-radius:6px;font-weight:500;background-color:var(--mat-sys-primary);color:var(--mat-sys-primary-container)}.btn-cancel{padding:8px 16px;border-radius:6px;color:var(--mat-sys-secondary-container);background-color:var(--mat-sys-secondary)}\n"] }]
329
323
  }] });
330
324
 
331
325
  class ErrorAlert {
@@ -510,7 +504,7 @@ class NettyAppsBase {
510
504
  }
511
505
  // Check if header is present
512
506
  if (!base64Data.startsWith('data:')) {
513
- console.error('Provided data is not in base64 format (missing header)');
507
+ this.alertService.showError('Provided data is not in base64 format (missing header)');
514
508
  return;
515
509
  }
516
510
  const contentType = base64Data.split(';')[0].split(':')[1];
@@ -1602,6 +1596,14 @@ class NettyAgGridBase extends NettyAppsBase {
1602
1596
  }
1603
1597
  sessionStorage.setItem(this.searchValueName(), this.searchValue());
1604
1598
  }
1599
+ async refreshData() {
1600
+ try {
1601
+ this.loadData();
1602
+ }
1603
+ catch (err) {
1604
+ this.alertService.showError(err);
1605
+ }
1606
+ }
1605
1607
  /**
1606
1608
  * Update a single row in the grid
1607
1609
  * @param rowData The updated row data
@@ -1613,7 +1615,7 @@ class NettyAgGridBase extends NettyAppsBase {
1613
1615
  const field = idField || this.pkFieldName();
1614
1616
  const id = rowData[field];
1615
1617
  if (id === undefined || id === null) {
1616
- this.loadData();
1618
+ this.refreshData();
1617
1619
  return;
1618
1620
  }
1619
1621
  let rowNode = this.gridApi.getRowNode(id.toString());
@@ -1628,8 +1630,9 @@ class NettyAgGridBase extends NettyAppsBase {
1628
1630
  }
1629
1631
  if (rowNode) {
1630
1632
  rowNode.setData(rowData);
1631
- const params = { rowNodes: [rowNode], force: true, suppressFlash: false, };
1633
+ const params = { rowNodes: [rowNode], force: true, suppressFlash: false };
1632
1634
  this.gridApi.refreshCells(params);
1635
+ this.recordList.update(currentList => currentList.map(item => item[field] === id ? rowData : item));
1633
1636
  }
1634
1637
  else {
1635
1638
  this.loadData(); // Reload all data if row not found
@@ -1936,7 +1939,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1936
1939
 
1937
1940
  ModuleRegistry.registerModules([AllCommunityModule, StatusBarModule, ClientSideRowModelModule, ClipboardModule, ExcelExportModule, ColumnMenuModule,
1938
1941
  ContextMenuModule, CellSelectionModule, HighlightChangesModule, RowSelectionModule, SetFilterModule, MultiFilterModule, TextFilterModule, NumberFilterModule, DateFilterModule]);
1939
- // AgGrid Dark Mode Row Style
1940
1942
  class NettyAgGridListBase extends NettyAgGridBase {
1941
1943
  // ********************************************
1942
1944
  // *** INPUTS ***
@@ -2115,14 +2117,6 @@ class NettyAgGridListBase extends NettyAgGridBase {
2115
2117
  error: (err) => this.alertService.showError('@dataLoadFailed', err),
2116
2118
  });
2117
2119
  }
2118
- async refreshData() {
2119
- try {
2120
- this.loadData();
2121
- }
2122
- catch (err) {
2123
- this.alertService.showError(err);
2124
- }
2125
- }
2126
2120
  async deleteSelected() {
2127
2121
  if (!this.gridApi)
2128
2122
  return;
@@ -2306,12 +2300,7 @@ class NettyAgGridListFilterBase extends NettyAgGridListBase {
2306
2300
  * Triggers the filter component to refresh its data
2307
2301
  */
2308
2302
  refreshFilterData() {
2309
- let value = this.filterRefreshTrigger();
2310
- if (value > 10000) {
2311
- value = 0;
2312
- }
2313
- value++;
2314
- this.filterRefreshTrigger.set(value);
2303
+ this.filterRefreshTrigger.update(val => val > 10000 ? 1 : val + 1);
2315
2304
  }
2316
2305
  onReverseIsFilterValid() {
2317
2306
  this.isFilterValid.update((a) => !a);
@@ -2375,14 +2364,6 @@ class NettyAgGridLogBase extends NettyAgGridBase {
2375
2364
  error: (err) => this.alertService.showError('@dataLoadFailed', err),
2376
2365
  });
2377
2366
  }
2378
- async refreshData() {
2379
- try {
2380
- this.loadData();
2381
- }
2382
- catch (err) {
2383
- this.alertService.showError(err);
2384
- }
2385
- }
2386
2367
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridLogBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2387
2368
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: NettyAgGridLogBase, isStandalone: true, selector: "ntybase-ag-grid-log-base", host: { attributes: { "ntybase-id": "NettyAgGridLogBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2388
2369
  }
@@ -2593,7 +2574,7 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2593
2574
  this.closeSidenav();
2594
2575
  this.alertService.showSuccess('@recordCreatedSuccessfully');
2595
2576
  },
2596
- error: (err) => console.error('@creationFailed:', err),
2577
+ error: (err) => this.alertService.showError('@creationFailed:', err),
2597
2578
  });
2598
2579
  }
2599
2580
  /**
@@ -2607,7 +2588,7 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2607
2588
  this.nettyAppsProxy.update(updateData).subscribe({
2608
2589
  next: (updatedRecord) => {
2609
2590
  this.initializeFormData(updatedRecord);
2610
- this.commonService.notifyUpdate('Item', 'update', updatedRecord);
2591
+ this.commonService.notifyUpdate(this.recordType(), 'update', updatedRecord);
2611
2592
  this.closeSidenav();
2612
2593
  this.alertService.showSuccess('@recordUpdatedSuccessfully');
2613
2594
  },
@@ -2622,7 +2603,7 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2622
2603
  let newRecord = this.createNewRecord();
2623
2604
  newRecord = await lastValueFrom(this.nettyAppsProxy.initRecord(newRecord))
2624
2605
  .catch((er) => {
2625
- console.error('@initRecordFailed:', er);
2606
+ this.alertService.showError('@initRecordFailed:', er);
2626
2607
  return this.createNewRecord();
2627
2608
  });
2628
2609
  this.initializeFormData(newRecord);
@@ -2701,12 +2682,7 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2701
2682
  disableClose: true,
2702
2683
  hasBackdrop: false,
2703
2684
  })
2704
- .afterClosed()
2705
- .subscribe((result) => {
2706
- if (result === 'saved') {
2707
- //this.updateRowInGrid;
2708
- }
2709
- });
2685
+ .afterClosed();
2710
2686
  return;
2711
2687
  }
2712
2688
  // Log control
@@ -3864,7 +3840,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
3864
3840
  }] });
3865
3841
 
3866
3842
  class AuthBase {
3867
- // Inject dependencies
3843
+ // Services
3868
3844
  router = inject(Router);
3869
3845
  route = inject(ActivatedRoute);
3870
3846
  environmentProxy = inject(EnvironmentProxy);
@@ -3873,8 +3849,6 @@ class AuthBase {
3873
3849
  urlHelperService = inject(UrlHelperService);
3874
3850
  onDestroy$ = new Subject();
3875
3851
  ngOnDestroy() {
3876
- //Called once, before the instance is destroyed.
3877
- //Add 'implements OnDestroy' to the class.
3878
3852
  this.onDestroy$.next();
3879
3853
  this.onDestroy$.complete();
3880
3854
  }
@@ -3980,7 +3954,7 @@ class Login extends AuthBase {
3980
3954
  }
3981
3955
  }
3982
3956
  catch (error) {
3983
- console.error('Error handling remember me:', error);
3957
+ this.alertService.showError('Error handling remember me:', error);
3984
3958
  }
3985
3959
  }
3986
3960
  loadRememberedUsername() {
@@ -3995,7 +3969,7 @@ class Login extends AuthBase {
3995
3969
  }
3996
3970
  }
3997
3971
  catch (error) {
3998
- console.error('Error loading remembered username:', error);
3972
+ this.alertService.showError('Error loading remembered username:', error);
3999
3973
  }
4000
3974
  }
4001
3975
  login() {
@@ -4340,15 +4314,7 @@ class ForgotPassword extends AuthBase {
4340
4314
  }
4341
4315
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ForgotPassword, decorators: [{
4342
4316
  type: Component,
4343
- args: [{ selector: 'ntybase-forgot-password', imports: [
4344
- FormsModule,
4345
- ReactiveFormsModule,
4346
- MatMenuModule,
4347
- MatIconModule,
4348
- MatInputModule,
4349
- MatFormFieldModule,
4350
- TranslateModule
4351
- ], template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"] }]
4317
+ args: [{ selector: 'ntybase-forgot-password', imports: [FormsModule, ReactiveFormsModule, MatMenuModule, MatIconModule, MatInputModule, MatFormFieldModule, TranslateModule], template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"] }]
4352
4318
  }], ctorParameters: () => [] });
4353
4319
 
4354
4320
  // text-image.service.ts
@@ -4407,6 +4373,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
4407
4373
 
4408
4374
  class NettyBaseApp {
4409
4375
  i18nService = inject(I18nService);
4376
+ alertService = inject(AlertService);
4410
4377
  async loadBaseTranslations() {
4411
4378
  try {
4412
4379
  const enUSBase = await import('./nettyapps-ntybase-en-USbase-DV4K7MNJ.mjs');
@@ -4415,7 +4382,7 @@ class NettyBaseApp {
4415
4382
  this.i18nService.addTranslations('Türkçe', trTRBase.default);
4416
4383
  }
4417
4384
  catch (error) {
4418
- console.error('Error loading base translations in component:', error);
4385
+ this.alertService.showError('Error loading base translations in component:', error);
4419
4386
  throw error;
4420
4387
  }
4421
4388
  }
@@ -4561,6 +4528,7 @@ class NettyMenuService {
4561
4528
  http = inject(HttpClient);
4562
4529
  environmentProxy = inject(EnvironmentProxy);
4563
4530
  i18nService = inject(I18nService);
4531
+ alertService = inject(AlertService);
4564
4532
  menuName = signal('', ...(ngDevMode ? [{ debugName: "menuName" }] : []));
4565
4533
  menu = signal(null, ...(ngDevMode ? [{ debugName: "menu" }] : []));
4566
4534
  setMenuName(name) {
@@ -4582,7 +4550,7 @@ class NettyMenuService {
4582
4550
  this.http.get(functionUrl).subscribe({
4583
4551
  next: (data) => this.menu.set(data),
4584
4552
  error: (err) => {
4585
- console.error('Failed to fetch menu:', err);
4553
+ this.alertService.showError('Failed to fetch menu:', err);
4586
4554
  this.menu.set(null);
4587
4555
  },
4588
4556
  });