@nettyapps/ntybase 21.1.28 → 21.1.30
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/{nettyapps-ntybase-en-USbase-DV4K7MNJ.mjs → nettyapps-ntybase-en-USbase-CYjShnUp.mjs} +6 -2
- package/fesm2022/{nettyapps-ntybase-en-USbase-DV4K7MNJ.mjs.map → nettyapps-ntybase-en-USbase-CYjShnUp.mjs.map} +1 -1
- package/fesm2022/{nettyapps-ntybase-tr-TRbase-Dvw5DW_f.mjs → nettyapps-ntybase-tr-TRbase-9sKP7Q5s.mjs} +6 -2
- package/fesm2022/{nettyapps-ntybase-tr-TRbase-Dvw5DW_f.mjs.map → nettyapps-ntybase-tr-TRbase-9sKP7Q5s.mjs.map} +1 -1
- package/fesm2022/nettyapps-ntybase.mjs +48 -38
- package/fesm2022/nettyapps-ntybase.mjs.map +1 -1
- package/package.json +1 -1
- package/translations/en-USbase.json +5 -1
- package/translations/tr-TRbase.json +5 -1
- package/types/nettyapps-ntybase.d.ts +10 -1
|
@@ -270,8 +270,12 @@ var enUSbase = {
|
|
|
270
270
|
"@openInSidenav": "Records will now open in the sidenav",
|
|
271
271
|
"@resetButtonLabel": "Reset",
|
|
272
272
|
"@applyButtonLabel": "Apply",
|
|
273
|
-
"@exportButtonLabel": "Export"
|
|
273
|
+
"@exportButtonLabel": "Export",
|
|
274
|
+
"@minLengthError": "Please enter at least {{value}} characters",
|
|
275
|
+
"@maxLengthError": "Please enter at most {{value}} characters",
|
|
276
|
+
"@dateCannotBeBeforeStart": "Selected date cannot be earlier than the start date",
|
|
277
|
+
"@dateCannotBeAfterEnd": "Selected date cannot be later than the end date"
|
|
274
278
|
};
|
|
275
279
|
|
|
276
280
|
export { AG_GRID, DASHBOARD, ENVIRONMENT_INFO, GANTT, enUSbase as default, mfaCode };
|
|
277
|
-
//# sourceMappingURL=nettyapps-ntybase-en-USbase-
|
|
281
|
+
//# sourceMappingURL=nettyapps-ntybase-en-USbase-CYjShnUp.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nettyapps-ntybase-en-USbase-
|
|
1
|
+
{"version":3,"file":"nettyapps-ntybase-en-USbase-CYjShnUp.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -270,8 +270,12 @@ var trTRbase = {
|
|
|
270
270
|
"@openInSidenav": "Kayıtlar artık yan panelde görüntülenecek",
|
|
271
271
|
"@resetButtonLabel": "Sıfırla",
|
|
272
272
|
"@applyButtonLabel": "Filtrele",
|
|
273
|
-
"@exportButtonLabel": "Dışa Aktar"
|
|
273
|
+
"@exportButtonLabel": "Dışa Aktar",
|
|
274
|
+
"@minLengthError": "En az {{value}} karakter girmelisiniz",
|
|
275
|
+
"@maxLengthError": "En fazla {{value}} karakter girebilirsiniz",
|
|
276
|
+
"@dateCannotBeBeforeStart": "Seçilen tarih, başlangıç tarihinden önce olamaz",
|
|
277
|
+
"@dateCannotBeAfterEnd": "Seçilen tarih, bitiş tarihinden sonra olamaz"
|
|
274
278
|
};
|
|
275
279
|
|
|
276
280
|
export { AG_GRID, DASHBOARD, ENVIRONMENT_INFO, GANTT, trTRbase as default, mfaCode };
|
|
277
|
-
//# sourceMappingURL=nettyapps-ntybase-tr-TRbase-
|
|
281
|
+
//# sourceMappingURL=nettyapps-ntybase-tr-TRbase-9sKP7Q5s.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nettyapps-ntybase-tr-TRbase-
|
|
1
|
+
{"version":3,"file":"nettyapps-ntybase-tr-TRbase-9sKP7Q5s.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -326,11 +326,11 @@ class ErrorAlert {
|
|
|
326
326
|
dialogRef = inject((MatDialogRef));
|
|
327
327
|
data = inject(MAT_DIALOG_DATA);
|
|
328
328
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ErrorAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
329
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ErrorAlert, isStandalone: true, selector: "ntybase-error-alert", ngImport: i0, template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title
|
|
329
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ErrorAlert, isStandalone: true, selector: "ntybase-error-alert", ngImport: i0, template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title }}</h2>\n </div>\n\n <div class=\"error-content\">\n <p>{{ data.message }}</p>\n </div>\n\n <mat-dialog-actions class=\"dialog-actions\">\n <button mat-flat-button [mat-dialog-close]=\"true\" class=\"btn-ok\">\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".error-dialog-container{padding:40px 32px;text-align:center;min-width:380px;max-width:450px;background:var(--mat-sys-primary);border-radius:20px;box-shadow:0 15px 35px #00000012}.error-dialog-container .header{display:flex;flex-direction:column;align-items:center;gap:12px}.error-dialog-container .header mat-icon{font-size:52px;width:52px;height:52px;color:var(--mat-sys-inverse-primary);margin-bottom:8px}.error-dialog-container .header .error-title{margin:0;font-size:1.4rem;font-weight:700;color:var(--mat-sys-surface);letter-spacing:-.02em}.error-dialog-container .error-content{margin:24px 0 32px;font-size:1rem;line-height:1.6;color:var(--mat-sys-surface)}.error-dialog-container .dialog-actions{display:flex;justify-content:center;padding:0;margin:0}.error-dialog-container .btn-ok{min-width:120px;padding:12px 24px;font-weight:600;font-size:1rem;border-radius:10px;background:var(--mat-sys-inverse-primary);color:var(--mat-sys-primary);border:none;cursor:pointer;transition:all .2s ease}.error-dialog-container .btn-ok:hover{background:var(--mat-sys-inverse-primary);opacity:.9;box-shadow:0 5px 15px #0000001a}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
330
330
|
}
|
|
331
331
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ErrorAlert, decorators: [{
|
|
332
332
|
type: Component,
|
|
333
|
-
args: [{ selector: 'ntybase-error-alert', imports: [MatDialogModule, MatIconModule, CommonModule, TranslateModule], template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title
|
|
333
|
+
args: [{ selector: 'ntybase-error-alert', imports: [MatDialogModule, MatIconModule, CommonModule, TranslateModule], template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title }}</h2>\n </div>\n\n <div class=\"error-content\">\n <p>{{ data.message }}</p>\n </div>\n\n <mat-dialog-actions class=\"dialog-actions\">\n <button mat-flat-button [mat-dialog-close]=\"true\" class=\"btn-ok\">\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".error-dialog-container{padding:40px 32px;text-align:center;min-width:380px;max-width:450px;background:var(--mat-sys-primary);border-radius:20px;box-shadow:0 15px 35px #00000012}.error-dialog-container .header{display:flex;flex-direction:column;align-items:center;gap:12px}.error-dialog-container .header mat-icon{font-size:52px;width:52px;height:52px;color:var(--mat-sys-inverse-primary);margin-bottom:8px}.error-dialog-container .header .error-title{margin:0;font-size:1.4rem;font-weight:700;color:var(--mat-sys-surface);letter-spacing:-.02em}.error-dialog-container .error-content{margin:24px 0 32px;font-size:1rem;line-height:1.6;color:var(--mat-sys-surface)}.error-dialog-container .dialog-actions{display:flex;justify-content:center;padding:0;margin:0}.error-dialog-container .btn-ok{min-width:120px;padding:12px 24px;font-weight:600;font-size:1rem;border-radius:10px;background:var(--mat-sys-inverse-primary);color:var(--mat-sys-primary);border:none;cursor:pointer;transition:all .2s ease}.error-dialog-container .btn-ok:hover{background:var(--mat-sys-inverse-primary);opacity:.9;box-shadow:0 5px 15px #0000001a}\n"] }]
|
|
334
334
|
}] });
|
|
335
335
|
|
|
336
336
|
// alert.service.ts
|
|
@@ -378,29 +378,38 @@ class AlertService {
|
|
|
378
378
|
});
|
|
379
379
|
}
|
|
380
380
|
// For error notifications
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
381
|
+
/**
|
|
382
|
+
* Flexible Error Display
|
|
383
|
+
* @param error - Error object from API or string
|
|
384
|
+
* @param fallbackOrComponent - Optional: Fallback message key (@...) OR Custom Component
|
|
385
|
+
* @param customComponent - Optional: Custom component to use if the 2nd parameter is a message
|
|
386
|
+
*/
|
|
387
|
+
showError(error, fallbackOrComponent = ErrorAlert, customComponent = ErrorAlert, width = 'auto', height = 'auto') {
|
|
388
|
+
let componentToOpen = ErrorAlert;
|
|
389
|
+
let fallbackMsg = '';
|
|
390
|
+
if (typeof fallbackOrComponent === 'string' && fallbackOrComponent.startsWith('@')) {
|
|
391
|
+
// showError(err, '@updateFailed', ...)
|
|
392
|
+
fallbackMsg = fallbackOrComponent;
|
|
393
|
+
componentToOpen = (customComponent && typeof customComponent === 'function') ? customComponent : ErrorAlert;
|
|
394
|
+
}
|
|
395
|
+
else if (typeof fallbackOrComponent === 'function') {
|
|
396
|
+
// showError(err, MySpecialComponent)
|
|
397
|
+
componentToOpen = fallbackOrComponent;
|
|
398
|
+
}
|
|
399
|
+
// Extract Message (C# / Backend message has priority)
|
|
400
|
+
const backendError = this.getErrorMessage(error);
|
|
401
|
+
// Final Message Decision: Use backend message if exists, otherwise translate fallback key
|
|
402
|
+
const finalMessage = (backendError && backendError !== JSON.stringify(error))
|
|
403
|
+
? backendError
|
|
404
|
+
: (fallbackMsg ? this.translate.instant(fallbackMsg) : backendError);
|
|
396
405
|
return new Promise((resolve) => {
|
|
397
406
|
const dialogRef = this.dialog.open(componentToOpen, {
|
|
398
407
|
width: width,
|
|
399
408
|
height: height,
|
|
400
409
|
maxWidth: '95vw',
|
|
401
410
|
data: {
|
|
402
|
-
|
|
403
|
-
title: '@errorOccurred',
|
|
411
|
+
message: finalMessage,
|
|
412
|
+
title: this.translate.instant('@errorOccurred'),
|
|
404
413
|
},
|
|
405
414
|
});
|
|
406
415
|
dialogRef.afterClosed().subscribe(() => {
|
|
@@ -408,18 +417,27 @@ class AlertService {
|
|
|
408
417
|
});
|
|
409
418
|
});
|
|
410
419
|
}
|
|
420
|
+
/**
|
|
421
|
+
* Extracts the most meaningful error message from the error object
|
|
422
|
+
*/
|
|
411
423
|
getErrorMessage(error) {
|
|
412
424
|
if (!error)
|
|
413
425
|
return '';
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (error.error && typeof error.error === 'string')
|
|
417
|
-
return error.error;
|
|
418
|
-
if (error.error && error.error.message)
|
|
426
|
+
// 1. C# API / Backend Error Messages
|
|
427
|
+
if (error?.error?.message)
|
|
419
428
|
return error.error.message;
|
|
420
|
-
if (error.
|
|
429
|
+
if (error?.error && typeof error.error === 'string')
|
|
430
|
+
return error.error;
|
|
431
|
+
if (error?.details && typeof error.details === 'string')
|
|
432
|
+
return error.details;
|
|
433
|
+
if (error?.message && typeof error.message === 'string' && !error.message.startsWith('@'))
|
|
421
434
|
return error.message;
|
|
422
|
-
|
|
435
|
+
/// 2. Localization Keys (starting with @)
|
|
436
|
+
if (typeof error === 'string' && error.startsWith('@'))
|
|
437
|
+
return this.translate.instant(error);
|
|
438
|
+
if (error?.message && typeof error.message === 'string' && error.message.startsWith('@'))
|
|
439
|
+
return this.translate.instant(error.message);
|
|
440
|
+
return typeof error === 'string' ? error : JSON.stringify(error);
|
|
423
441
|
}
|
|
424
442
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AlertService, deps: [{ token: i1$2.MatSnackBar }, { token: i1.MatDialog }, { token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
425
443
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AlertService, providedIn: 'root' });
|
|
@@ -2573,7 +2591,7 @@ class NettyAgGridSaveBase extends NettyAppsBase {
|
|
|
2573
2591
|
this.closeSidenav();
|
|
2574
2592
|
this.alertService.showSuccess('@recordCreatedSuccessfully');
|
|
2575
2593
|
},
|
|
2576
|
-
error: (err) => this.alertService.showError('@creationFailed
|
|
2594
|
+
error: (err) => this.alertService.showError('@creationFailed', err),
|
|
2577
2595
|
});
|
|
2578
2596
|
}
|
|
2579
2597
|
/**
|
|
@@ -4027,15 +4045,7 @@ class Login extends AuthBase {
|
|
|
4027
4045
|
}
|
|
4028
4046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Login, decorators: [{
|
|
4029
4047
|
type: Component,
|
|
4030
|
-
args: [{ selector: 'ntybase-login', imports: [
|
|
4031
|
-
FormsModule,
|
|
4032
|
-
ReactiveFormsModule,
|
|
4033
|
-
MatMenuModule,
|
|
4034
|
-
MatIconModule,
|
|
4035
|
-
MatInputModule,
|
|
4036
|
-
MatFormFieldModule,
|
|
4037
|
-
TranslateModule,
|
|
4038
|
-
], 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 (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\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 formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-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"] }]
|
|
4048
|
+
args: [{ selector: 'ntybase-login', 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 (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\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 formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-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"] }]
|
|
4039
4049
|
}] });
|
|
4040
4050
|
|
|
4041
4051
|
class MfaLogin extends AuthBase {
|
|
@@ -4375,8 +4385,8 @@ class NettyBaseApp {
|
|
|
4375
4385
|
alertService = inject(AlertService);
|
|
4376
4386
|
async loadBaseTranslations() {
|
|
4377
4387
|
try {
|
|
4378
|
-
const enUSBase = await import('./nettyapps-ntybase-en-USbase-
|
|
4379
|
-
const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-
|
|
4388
|
+
const enUSBase = await import('./nettyapps-ntybase-en-USbase-CYjShnUp.mjs');
|
|
4389
|
+
const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-9sKP7Q5s.mjs');
|
|
4380
4390
|
this.i18nService.addTranslations('English', enUSBase.default);
|
|
4381
4391
|
this.i18nService.addTranslations('Türkçe', trTRBase.default);
|
|
4382
4392
|
}
|