@mintplayer/ng-spark 22.29.0 → 22.31.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.
Files changed (103) hide show
  1. package/README.md +3 -3
  2. package/auth/README.md +216 -0
  3. package/fesm2022/mintplayer-ng-spark-auth-account.mjs +2023 -0
  4. package/fesm2022/mintplayer-ng-spark-auth-account.mjs.map +1 -0
  5. package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs +96 -0
  6. package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs.map +1 -0
  7. package/fesm2022/mintplayer-ng-spark-auth-confirm-email.mjs +200 -0
  8. package/fesm2022/mintplayer-ng-spark-auth-confirm-email.mjs.map +1 -0
  9. package/fesm2022/mintplayer-ng-spark-auth-core.mjs +452 -0
  10. package/fesm2022/mintplayer-ng-spark-auth-core.mjs.map +1 -0
  11. package/fesm2022/mintplayer-ng-spark-auth-external-login.mjs +201 -0
  12. package/fesm2022/mintplayer-ng-spark-auth-external-login.mjs.map +1 -0
  13. package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs +196 -0
  14. package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs.map +1 -0
  15. package/fesm2022/mintplayer-ng-spark-auth-guards.mjs +16 -0
  16. package/fesm2022/mintplayer-ng-spark-auth-guards.mjs.map +1 -0
  17. package/fesm2022/mintplayer-ng-spark-auth-interceptors.mjs +18 -0
  18. package/fesm2022/mintplayer-ng-spark-auth-interceptors.mjs.map +1 -0
  19. package/fesm2022/mintplayer-ng-spark-auth-login.mjs +282 -0
  20. package/fesm2022/mintplayer-ng-spark-auth-login.mjs.map +1 -0
  21. package/fesm2022/mintplayer-ng-spark-auth-models.mjs +114 -0
  22. package/fesm2022/mintplayer-ng-spark-auth-models.mjs.map +1 -0
  23. package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs +43 -0
  24. package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs.map +1 -0
  25. package/fesm2022/mintplayer-ng-spark-auth-register.mjs +216 -0
  26. package/fesm2022/mintplayer-ng-spark-auth-register.mjs.map +1 -0
  27. package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs +223 -0
  28. package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs.map +1 -0
  29. package/fesm2022/mintplayer-ng-spark-auth-routes.mjs +194 -0
  30. package/fesm2022/mintplayer-ng-spark-auth-routes.mjs.map +1 -0
  31. package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs +210 -0
  32. package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs.map +1 -0
  33. package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs +218 -0
  34. package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs.map +1 -0
  35. package/fesm2022/mintplayer-ng-spark-auth.mjs +48 -0
  36. package/fesm2022/mintplayer-ng-spark-auth.mjs.map +1 -0
  37. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +368 -2
  38. package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
  39. package/fesm2022/mintplayer-ng-spark-grid.mjs +22 -9
  40. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  41. package/fesm2022/mintplayer-ng-spark-identity-provider-connected-applications.mjs +389 -0
  42. package/fesm2022/mintplayer-ng-spark-identity-provider-connected-applications.mjs.map +1 -0
  43. package/fesm2022/mintplayer-ng-spark-identity-provider-core.mjs +204 -0
  44. package/fesm2022/mintplayer-ng-spark-identity-provider-core.mjs.map +1 -0
  45. package/fesm2022/mintplayer-ng-spark-identity-provider-developers.mjs +486 -0
  46. package/fesm2022/mintplayer-ng-spark-identity-provider-developers.mjs.map +1 -0
  47. package/fesm2022/mintplayer-ng-spark-identity-provider-management.mjs +350 -0
  48. package/fesm2022/mintplayer-ng-spark-identity-provider-management.mjs.map +1 -0
  49. package/fesm2022/mintplayer-ng-spark-identity-provider.mjs +66 -0
  50. package/fesm2022/mintplayer-ng-spark-identity-provider.mjs.map +1 -0
  51. package/fesm2022/mintplayer-ng-spark-models.mjs +2 -1
  52. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  53. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +13 -3
  54. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  55. package/fesm2022/mintplayer-ng-spark-po-form.mjs +6 -3
  56. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  57. package/fesm2022/mintplayer-ng-spark-pwa.mjs +162 -0
  58. package/fesm2022/mintplayer-ng-spark-pwa.mjs.map +1 -0
  59. package/fesm2022/mintplayer-ng-spark-query-list.mjs +5 -2
  60. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  61. package/fesm2022/mintplayer-ng-spark-renderers.mjs +109 -4
  62. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  63. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +36 -6
  64. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
  65. package/fesm2022/mintplayer-ng-spark-services.mjs +48 -6
  66. package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
  67. package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
  68. package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
  69. package/package.json +101 -3
  70. package/types/mintplayer-ng-spark-auth-account.d.ts +255 -0
  71. package/types/mintplayer-ng-spark-auth-auth-bar.d.ts +22 -0
  72. package/types/mintplayer-ng-spark-auth-confirm-email.d.ts +21 -0
  73. package/types/mintplayer-ng-spark-auth-core.d.ts +197 -0
  74. package/types/mintplayer-ng-spark-auth-external-login.d.ts +132 -0
  75. package/types/mintplayer-ng-spark-auth-forgot-password.d.ts +18 -0
  76. package/types/mintplayer-ng-spark-auth-guards.d.ts +15 -0
  77. package/types/mintplayer-ng-spark-auth-interceptors.d.ts +2 -0
  78. package/types/mintplayer-ng-spark-auth-login.d.ts +46 -0
  79. package/types/mintplayer-ng-spark-auth-models.d.ts +489 -0
  80. package/types/mintplayer-ng-spark-auth-pipes.d.ts +8 -0
  81. package/types/mintplayer-ng-spark-auth-register.d.ts +21 -0
  82. package/types/mintplayer-ng-spark-auth-reset-password.d.ts +25 -0
  83. package/types/mintplayer-ng-spark-auth-routes.d.ts +154 -0
  84. package/types/mintplayer-ng-spark-auth-sign-in.d.ts +84 -0
  85. package/types/mintplayer-ng-spark-auth-two-factor.d.ts +23 -0
  86. package/types/mintplayer-ng-spark-auth.d.ts +24 -0
  87. package/types/mintplayer-ng-spark-client-operations.d.ts +148 -3
  88. package/types/mintplayer-ng-spark-grid.d.ts +19 -1
  89. package/types/mintplayer-ng-spark-identity-provider-connected-applications.d.ts +35 -0
  90. package/types/mintplayer-ng-spark-identity-provider-core.d.ts +144 -0
  91. package/types/mintplayer-ng-spark-identity-provider-developers.d.ts +55 -0
  92. package/types/mintplayer-ng-spark-identity-provider-management.d.ts +33 -0
  93. package/types/mintplayer-ng-spark-identity-provider.d.ts +64 -0
  94. package/types/mintplayer-ng-spark-models.d.ts +28 -0
  95. package/types/mintplayer-ng-spark-po-detail.d.ts +8 -0
  96. package/types/mintplayer-ng-spark-po-form.d.ts +2 -0
  97. package/types/mintplayer-ng-spark-pwa.d.ts +89 -0
  98. package/types/mintplayer-ng-spark-query-list.d.ts +2 -0
  99. package/types/mintplayer-ng-spark-renderers.d.ts +47 -0
  100. package/types/mintplayer-ng-spark-retry-action-modal.d.ts +1 -0
  101. package/types/mintplayer-ng-spark-services.d.ts +37 -1
  102. package/types/mintplayer-ng-spark-shell.d.ts +2 -2
  103. package/types/mintplayer-ng-spark.d.ts +4 -4
@@ -0,0 +1,216 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
3
+ import * as i1 from "@angular/forms";
4
+ import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
5
+ import { Router, RouterLink } from "@angular/router";
6
+ import { HttpErrorResponse } from "@angular/common/http";
7
+ import { Color } from "@mintplayer/ng-bootstrap";
8
+ import { BsAlertComponent } from "@mintplayer/ng-bootstrap/alert";
9
+ import { BsCardComponent, BsCardHeaderComponent } from "@mintplayer/ng-bootstrap/card";
10
+ import { BsFormComponent, BsFormControlDirective } from "@mintplayer/ng-bootstrap/form";
11
+ import { BsSpinnerComponent } from "@mintplayer/ng-bootstrap/spinner";
12
+ import { SPARK_AUTH_ROUTE_PATHS } from "@mintplayer/ng-spark/auth/models";
13
+ import { SparkAuthService, SparkAuthTranslationService } from "@mintplayer/ng-spark/auth/core";
14
+ import { TranslateKeyPipe } from "@mintplayer/ng-spark/auth/pipes";
15
+ function passwordMatchValidator(control) {
16
+ const password = control.get("password");
17
+ const confirmPassword = control.get("confirmPassword");
18
+ if (password && confirmPassword && password.value !== confirmPassword.value) return { passwordMismatch: true };
19
+ return null;
20
+ }
21
+ var SparkRegisterComponent = class SparkRegisterComponent {
22
+ fb = inject(FormBuilder);
23
+ authService = inject(SparkAuthService);
24
+ router = inject(Router);
25
+ translation = inject(SparkAuthTranslationService);
26
+ routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
27
+ colors = Color;
28
+ loading = signal(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
29
+ errorMessage = signal("", ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
30
+ form = this.fb.group({
31
+ email: ["", [Validators.required, Validators.email]],
32
+ userName: ["", [Validators.required, Validators.pattern(/^[^@]*$/)]],
33
+ password: ["", Validators.required],
34
+ confirmPassword: ["", Validators.required]
35
+ }, { validators: passwordMatchValidator });
36
+ async onSubmit() {
37
+ if (this.form.invalid) {
38
+ this.form.markAllAsTouched();
39
+ return;
40
+ }
41
+ this.loading.set(true);
42
+ this.errorMessage.set("");
43
+ const { email, userName, password } = this.form.value;
44
+ try {
45
+ await this.authService.register(email, password, userName.trim());
46
+ this.router.navigate([this.routePaths.login ?? "/"], { queryParams: { registered: "true" } });
47
+ } catch (err) {
48
+ if (err instanceof HttpErrorResponse) {
49
+ if (err.status === 400 && err.error?.errors) {
50
+ const messages = [].concat(...Object.values(err.error.errors));
51
+ this.errorMessage.set(messages.join(" "));
52
+ } else if (err.error?.detail) this.errorMessage.set(err.error.detail);
53
+ else this.errorMessage.set(this.translation.t("auth.registrationFailed"));
54
+ } else this.errorMessage.set(this.translation.t("auth.registrationFailed"));
55
+ } finally {
56
+ this.loading.set(false);
57
+ }
58
+ }
59
+ static ɵfac = i0.ɵɵngDeclareFactory({
60
+ minVersion: "12.0.0",
61
+ version: "22.2.0",
62
+ ngImport: i0,
63
+ type: SparkRegisterComponent,
64
+ deps: [],
65
+ target: i0.ɵɵFactoryTarget.Component
66
+ });
67
+ static ɵcmp = i0.ɵɵngDeclareComponent({
68
+ minVersion: "17.0.0",
69
+ version: "22.2.0",
70
+ type: SparkRegisterComponent,
71
+ isStandalone: true,
72
+ selector: "spark-register",
73
+ ngImport: i0,
74
+ template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.register' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"email\" class=\"form-label\">{{ 'auth.email' | t }}</label>\n <input\n type=\"email\"\n id=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n />\n @if (form.get('email')?.touched && form.get('email')?.hasError('email')) {\n <div class=\"text-danger mt-1\">{{ 'auth.invalidEmail' | t }}</div>\n }\n </div>\n\n <div class=\"mb-3\">\n <label for=\"userName\" class=\"form-label\">{{ 'auth.userName' | t }}</label>\n <input\n type=\"text\"\n id=\"userName\"\n formControlName=\"userName\"\n autocomplete=\"username\"\n />\n <div class=\"form-text\" [class.text-danger]=\"form.get('userName')?.touched && form.get('userName')?.invalid\">{{ 'auth.userNameHint' | t }}</div>\n </div>\n\n <div class=\"mb-3\">\n <label for=\"password\" class=\"form-label\">{{ 'auth.password' | t }}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.register' | t }}\n </button>\n </form>\n </bs-form>\n\n <!-- withRegistration() is opt-in independently of withLocalLogin(), so the password form may\n not be mounted. An unguarded [routerLink]=\"undefined\" navigates to the current route. -->\n @if (routePaths.login) {\n <div class=\"mt-3 text-center\">\n <span>{{ 'auth.alreadyHaveAccount' | t }} </span>\n <a [routerLink]=\"routePaths.login\">{{ 'auth.login' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n",
75
+ dependencies: [
76
+ {
77
+ kind: "ngmodule",
78
+ type: ReactiveFormsModule
79
+ },
80
+ {
81
+ kind: "directive",
82
+ type: i1.ɵNgNoValidate,
83
+ selector: "form:not([ngNoForm]):not([ngNativeValidate])"
84
+ },
85
+ {
86
+ kind: "directive",
87
+ type: i1.DefaultValueAccessor,
88
+ selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
89
+ },
90
+ {
91
+ kind: "directive",
92
+ type: i1.NgControlStatus,
93
+ selector: "[formControlName],[ngModel],[formControl]"
94
+ },
95
+ {
96
+ kind: "directive",
97
+ type: i1.NgControlStatusGroup,
98
+ selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
99
+ },
100
+ {
101
+ kind: "directive",
102
+ type: i1.FormGroupDirective,
103
+ selector: "[formGroup]",
104
+ inputs: ["formGroup"],
105
+ outputs: ["ngSubmit"],
106
+ exportAs: ["ngForm"]
107
+ },
108
+ {
109
+ kind: "directive",
110
+ type: i1.FormControlName,
111
+ selector: "[formControlName]",
112
+ inputs: [
113
+ "formControlName",
114
+ "disabled",
115
+ "ngModel"
116
+ ],
117
+ outputs: ["ngModelChange"]
118
+ },
119
+ {
120
+ kind: "directive",
121
+ type: RouterLink,
122
+ selector: "[routerLink]",
123
+ inputs: [
124
+ "target",
125
+ "queryParams",
126
+ "fragment",
127
+ "queryParamsHandling",
128
+ "state",
129
+ "info",
130
+ "relativeTo",
131
+ "preserveFragment",
132
+ "skipLocationChange",
133
+ "replaceUrl",
134
+ "browserUrl",
135
+ "routerLink"
136
+ ]
137
+ },
138
+ {
139
+ kind: "component",
140
+ type: BsAlertComponent,
141
+ selector: "bs-alert",
142
+ inputs: [
143
+ "type",
144
+ "announce",
145
+ "isVisible"
146
+ ],
147
+ outputs: ["isVisibleChange", "afterOpenedOrClosed"]
148
+ },
149
+ {
150
+ kind: "component",
151
+ type: BsCardComponent,
152
+ selector: "bs-card",
153
+ inputs: ["color", "outline"]
154
+ },
155
+ {
156
+ kind: "component",
157
+ type: BsCardHeaderComponent,
158
+ selector: "bs-card-header",
159
+ inputs: ["color", "navStyle"]
160
+ },
161
+ {
162
+ kind: "component",
163
+ type: BsFormComponent,
164
+ selector: "bs-form",
165
+ inputs: ["action", "method"],
166
+ outputs: ["submitted"]
167
+ },
168
+ {
169
+ kind: "directive",
170
+ type: BsFormControlDirective,
171
+ selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)"
172
+ },
173
+ {
174
+ kind: "component",
175
+ type: BsSpinnerComponent,
176
+ selector: "bs-spinner",
177
+ inputs: ["type", "color"]
178
+ },
179
+ {
180
+ kind: "pipe",
181
+ type: TranslateKeyPipe,
182
+ name: "t"
183
+ }
184
+ ],
185
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
186
+ });
187
+ };
188
+ i0.ɵɵngDeclareClassMetadata({
189
+ minVersion: "12.0.0",
190
+ version: "22.2.0",
191
+ ngImport: i0,
192
+ type: SparkRegisterComponent,
193
+ decorators: [{
194
+ type: Component,
195
+ args: [{
196
+ selector: "spark-register",
197
+ standalone: true,
198
+ changeDetection: ChangeDetectionStrategy.OnPush,
199
+ imports: [
200
+ ReactiveFormsModule,
201
+ RouterLink,
202
+ BsAlertComponent,
203
+ BsCardComponent,
204
+ BsCardHeaderComponent,
205
+ BsFormComponent,
206
+ BsFormControlDirective,
207
+ BsSpinnerComponent,
208
+ TranslateKeyPipe
209
+ ],
210
+ template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.register' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"email\" class=\"form-label\">{{ 'auth.email' | t }}</label>\n <input\n type=\"email\"\n id=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n />\n @if (form.get('email')?.touched && form.get('email')?.hasError('email')) {\n <div class=\"text-danger mt-1\">{{ 'auth.invalidEmail' | t }}</div>\n }\n </div>\n\n <div class=\"mb-3\">\n <label for=\"userName\" class=\"form-label\">{{ 'auth.userName' | t }}</label>\n <input\n type=\"text\"\n id=\"userName\"\n formControlName=\"userName\"\n autocomplete=\"username\"\n />\n <div class=\"form-text\" [class.text-danger]=\"form.get('userName')?.touched && form.get('userName')?.invalid\">{{ 'auth.userNameHint' | t }}</div>\n </div>\n\n <div class=\"mb-3\">\n <label for=\"password\" class=\"form-label\">{{ 'auth.password' | t }}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.register' | t }}\n </button>\n </form>\n </bs-form>\n\n <!-- withRegistration() is opt-in independently of withLocalLogin(), so the password form may\n not be mounted. An unguarded [routerLink]=\"undefined\" navigates to the current route. -->\n @if (routePaths.login) {\n <div class=\"mt-3 text-center\">\n <span>{{ 'auth.alreadyHaveAccount' | t }} </span>\n <a [routerLink]=\"routePaths.login\">{{ 'auth.login' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n"
211
+ }]
212
+ }]
213
+ });
214
+ export { SparkRegisterComponent };
215
+
216
+ //# sourceMappingURL=mintplayer-ng-spark-auth-register.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintplayer-ng-spark-auth-register.mjs","names":[],"sources":["../../auth/register/src/spark-register.component.ts","../../auth/register/src/spark-register.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { ReactiveFormsModule, FormBuilder, Validators, AbstractControl, ValidationErrors } from '@angular/forms';\nimport { RouterLink, Router } from '@angular/router';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { Color } from '@mintplayer/ng-bootstrap';\nimport { BsAlertComponent } from '@mintplayer/ng-bootstrap/alert';\nimport { BsCardComponent, BsCardHeaderComponent } from '@mintplayer/ng-bootstrap/card';\nimport { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';\nimport { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';\nimport { SPARK_AUTH_ROUTE_PATHS } from '@mintplayer/ng-spark/auth/models';\nimport { SparkAuthService, SparkAuthTranslationService } from '@mintplayer/ng-spark/auth/core';\nimport { TranslateKeyPipe } from '@mintplayer/ng-spark/auth/pipes';\n\nfunction passwordMatchValidator(control: AbstractControl): ValidationErrors | null {\n const password = control.get('password');\n const confirmPassword = control.get('confirmPassword');\n if (password && confirmPassword && password.value !== confirmPassword.value) {\n return { passwordMismatch: true };\n }\n return null;\n}\n\n@Component({\n selector: 'spark-register',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [ReactiveFormsModule, RouterLink, BsAlertComponent, BsCardComponent, BsCardHeaderComponent, BsFormComponent, BsFormControlDirective, BsSpinnerComponent, TranslateKeyPipe],\n templateUrl: './spark-register.component.html',\n})\nexport class SparkRegisterComponent {\n private readonly fb = inject(FormBuilder);\n private readonly authService = inject(SparkAuthService);\n private readonly router = inject(Router);\n private readonly translation = inject(SparkAuthTranslationService);\n readonly routePaths = inject(SPARK_AUTH_ROUTE_PATHS);\n\n colors = Color;\n readonly loading = signal(false);\n readonly errorMessage = signal('');\n\n readonly form = this.fb.group({\n email: ['', [Validators.required, Validators.email]],\n // The public handle other users see; the server refuses '@' too (never an email address).\n userName: ['', [Validators.required, Validators.pattern(/^[^@]*$/)]],\n password: ['', Validators.required],\n confirmPassword: ['', Validators.required],\n }, { validators: passwordMatchValidator });\n\n async onSubmit(): Promise<void> {\n if (this.form.invalid) {\n this.form.markAllAsTouched();\n return;\n }\n\n this.loading.set(true);\n this.errorMessage.set('');\n\n const { email, userName, password } = this.form.value;\n\n try {\n await this.authService.register(email!, password!, userName!.trim());\n // An app can mount registration without the password form (external-only sign-in with\n // self-service account creation). Landing on the site root beats navigating to `undefined`,\n // which the router resolves to the current route — leaving the user on a form they just\n // submitted successfully.\n this.router.navigate([this.routePaths.login ?? '/'], {\n queryParams: { registered: 'true' },\n });\n } catch (err: any) {\n if (err instanceof HttpErrorResponse) {\n if (err.status === 400 && err.error?.errors) {\n const messages = ([] as string[]).concat(...Object.values(err.error.errors) as string[][]);\n this.errorMessage.set(messages.join(' '));\n } else if (err.error?.detail) {\n this.errorMessage.set(err.error.detail);\n } else {\n this.errorMessage.set(this.translation.t('auth.registrationFailed'));\n }\n } else {\n this.errorMessage.set(this.translation.t('auth.registrationFailed'));\n }\n } finally {\n this.loading.set(false);\n }\n }\n}\n\nexport default SparkRegisterComponent;\n","<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.register' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"email\" class=\"form-label\">{{ 'auth.email' | t }}</label>\n <input\n type=\"email\"\n id=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n />\n @if (form.get('email')?.touched && form.get('email')?.hasError('email')) {\n <div class=\"text-danger mt-1\">{{ 'auth.invalidEmail' | t }}</div>\n }\n </div>\n\n <div class=\"mb-3\">\n <label for=\"userName\" class=\"form-label\">{{ 'auth.userName' | t }}</label>\n <input\n type=\"text\"\n id=\"userName\"\n formControlName=\"userName\"\n autocomplete=\"username\"\n />\n <div class=\"form-text\" [class.text-danger]=\"form.get('userName')?.touched && form.get('userName')?.invalid\">{{ 'auth.userNameHint' | t }}</div>\n </div>\n\n <div class=\"mb-3\">\n <label for=\"password\" class=\"form-label\">{{ 'auth.password' | t }}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.register' | t }}\n </button>\n </form>\n </bs-form>\n\n <!-- withRegistration() is opt-in independently of withLocalLogin(), so the password form may\n not be mounted. An unguarded [routerLink]=\"undefined\" navigates to the current route. -->\n @if (routePaths.login) {\n <div class=\"mt-3 text-center\">\n <span>{{ 'auth.alreadyHaveAccount' | t }} </span>\n <a [routerLink]=\"routePaths.login\">{{ 'auth.login' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n"],"mappings":"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"}
@@ -0,0 +1,223 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
3
+ import * as i1 from "@angular/forms";
4
+ import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
5
+ import { ActivatedRoute, Router, RouterLink } from "@angular/router";
6
+ import { HttpErrorResponse } from "@angular/common/http";
7
+ import { Color } from "@mintplayer/ng-bootstrap";
8
+ import { BsAlertComponent } from "@mintplayer/ng-bootstrap/alert";
9
+ import { BsCardComponent, BsCardHeaderComponent } from "@mintplayer/ng-bootstrap/card";
10
+ import { BsFormComponent, BsFormControlDirective } from "@mintplayer/ng-bootstrap/form";
11
+ import { BsSpinnerComponent } from "@mintplayer/ng-bootstrap/spinner";
12
+ import { SPARK_AUTH_ROUTE_PATHS } from "@mintplayer/ng-spark/auth/models";
13
+ import { SparkAuthService, SparkAuthTranslationService } from "@mintplayer/ng-spark/auth/core";
14
+ import { TranslateKeyPipe } from "@mintplayer/ng-spark/auth/pipes";
15
+ function passwordMatchValidator(control) {
16
+ const password = control.get("newPassword");
17
+ const confirmPassword = control.get("confirmPassword");
18
+ if (password && confirmPassword && password.value !== confirmPassword.value) return { passwordMismatch: true };
19
+ return null;
20
+ }
21
+ var SparkResetPasswordComponent = class SparkResetPasswordComponent {
22
+ fb = inject(FormBuilder);
23
+ authService = inject(SparkAuthService);
24
+ router = inject(Router);
25
+ route = inject(ActivatedRoute);
26
+ translation = inject(SparkAuthTranslationService);
27
+ routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
28
+ colors = Color;
29
+ loading = signal(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
30
+ errorMessage = signal("", ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
31
+ successMessage = signal("", ...ngDevMode ? [{ debugName: "successMessage" }] : /* istanbul ignore next */ []);
32
+ email = "";
33
+ code = "";
34
+ form = this.fb.group({
35
+ newPassword: ["", Validators.required],
36
+ confirmPassword: ["", Validators.required]
37
+ }, { validators: passwordMatchValidator });
38
+ ngOnInit() {
39
+ this.email = this.route.snapshot.queryParamMap.get("email") ?? "";
40
+ this.code = this.route.snapshot.queryParamMap.get("code") ?? "";
41
+ if (!this.email || !this.code) this.errorMessage.set(this.translation.t("auth.invalidResetLink"));
42
+ }
43
+ async onSubmit() {
44
+ if (this.form.invalid) {
45
+ this.form.markAllAsTouched();
46
+ return;
47
+ }
48
+ if (!this.email || !this.code) {
49
+ this.errorMessage.set(this.translation.t("auth.invalidResetLink"));
50
+ return;
51
+ }
52
+ this.loading.set(true);
53
+ this.errorMessage.set("");
54
+ this.successMessage.set("");
55
+ const { newPassword } = this.form.value;
56
+ try {
57
+ await this.authService.resetPassword(this.email, this.code, newPassword);
58
+ this.successMessage.set(this.translation.t("auth.resetSuccess"));
59
+ } catch (err) {
60
+ if (err instanceof HttpErrorResponse && err.error?.detail) this.errorMessage.set(err.error.detail);
61
+ else this.errorMessage.set(this.translation.t("auth.resetFailed"));
62
+ } finally {
63
+ this.loading.set(false);
64
+ }
65
+ }
66
+ static ɵfac = i0.ɵɵngDeclareFactory({
67
+ minVersion: "12.0.0",
68
+ version: "22.2.0",
69
+ ngImport: i0,
70
+ type: SparkResetPasswordComponent,
71
+ deps: [],
72
+ target: i0.ɵɵFactoryTarget.Component
73
+ });
74
+ static ɵcmp = i0.ɵɵngDeclareComponent({
75
+ minVersion: "17.0.0",
76
+ version: "22.2.0",
77
+ type: SparkResetPasswordComponent,
78
+ isStandalone: true,
79
+ selector: "spark-reset-password",
80
+ ngImport: i0,
81
+ template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.resetPassword' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (successMessage()) {\n <bs-alert [type]=\"colors.success\" class=\"mb-3\">\n {{ successMessage() }}\n <div class=\"mt-2\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.goToLogin' | t }}</a>\n </div>\n </bs-alert>\n }\n\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n @if (!successMessage()) {\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"newPassword\" class=\"form-label\">{{ 'auth.newPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.resetPassword' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n",
82
+ dependencies: [
83
+ {
84
+ kind: "ngmodule",
85
+ type: ReactiveFormsModule
86
+ },
87
+ {
88
+ kind: "directive",
89
+ type: i1.ɵNgNoValidate,
90
+ selector: "form:not([ngNoForm]):not([ngNativeValidate])"
91
+ },
92
+ {
93
+ kind: "directive",
94
+ type: i1.DefaultValueAccessor,
95
+ selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
96
+ },
97
+ {
98
+ kind: "directive",
99
+ type: i1.NgControlStatus,
100
+ selector: "[formControlName],[ngModel],[formControl]"
101
+ },
102
+ {
103
+ kind: "directive",
104
+ type: i1.NgControlStatusGroup,
105
+ selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
106
+ },
107
+ {
108
+ kind: "directive",
109
+ type: i1.FormGroupDirective,
110
+ selector: "[formGroup]",
111
+ inputs: ["formGroup"],
112
+ outputs: ["ngSubmit"],
113
+ exportAs: ["ngForm"]
114
+ },
115
+ {
116
+ kind: "directive",
117
+ type: i1.FormControlName,
118
+ selector: "[formControlName]",
119
+ inputs: [
120
+ "formControlName",
121
+ "disabled",
122
+ "ngModel"
123
+ ],
124
+ outputs: ["ngModelChange"]
125
+ },
126
+ {
127
+ kind: "directive",
128
+ type: RouterLink,
129
+ selector: "[routerLink]",
130
+ inputs: [
131
+ "target",
132
+ "queryParams",
133
+ "fragment",
134
+ "queryParamsHandling",
135
+ "state",
136
+ "info",
137
+ "relativeTo",
138
+ "preserveFragment",
139
+ "skipLocationChange",
140
+ "replaceUrl",
141
+ "browserUrl",
142
+ "routerLink"
143
+ ]
144
+ },
145
+ {
146
+ kind: "component",
147
+ type: BsAlertComponent,
148
+ selector: "bs-alert",
149
+ inputs: [
150
+ "type",
151
+ "announce",
152
+ "isVisible"
153
+ ],
154
+ outputs: ["isVisibleChange", "afterOpenedOrClosed"]
155
+ },
156
+ {
157
+ kind: "component",
158
+ type: BsCardComponent,
159
+ selector: "bs-card",
160
+ inputs: ["color", "outline"]
161
+ },
162
+ {
163
+ kind: "component",
164
+ type: BsCardHeaderComponent,
165
+ selector: "bs-card-header",
166
+ inputs: ["color", "navStyle"]
167
+ },
168
+ {
169
+ kind: "component",
170
+ type: BsFormComponent,
171
+ selector: "bs-form",
172
+ inputs: ["action", "method"],
173
+ outputs: ["submitted"]
174
+ },
175
+ {
176
+ kind: "directive",
177
+ type: BsFormControlDirective,
178
+ selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)"
179
+ },
180
+ {
181
+ kind: "component",
182
+ type: BsSpinnerComponent,
183
+ selector: "bs-spinner",
184
+ inputs: ["type", "color"]
185
+ },
186
+ {
187
+ kind: "pipe",
188
+ type: TranslateKeyPipe,
189
+ name: "t"
190
+ }
191
+ ],
192
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
193
+ });
194
+ };
195
+ i0.ɵɵngDeclareClassMetadata({
196
+ minVersion: "12.0.0",
197
+ version: "22.2.0",
198
+ ngImport: i0,
199
+ type: SparkResetPasswordComponent,
200
+ decorators: [{
201
+ type: Component,
202
+ args: [{
203
+ selector: "spark-reset-password",
204
+ standalone: true,
205
+ changeDetection: ChangeDetectionStrategy.OnPush,
206
+ imports: [
207
+ ReactiveFormsModule,
208
+ RouterLink,
209
+ BsAlertComponent,
210
+ BsCardComponent,
211
+ BsCardHeaderComponent,
212
+ BsFormComponent,
213
+ BsFormControlDirective,
214
+ BsSpinnerComponent,
215
+ TranslateKeyPipe
216
+ ],
217
+ template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.resetPassword' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (successMessage()) {\n <bs-alert [type]=\"colors.success\" class=\"mb-3\">\n {{ successMessage() }}\n <div class=\"mt-2\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.goToLogin' | t }}</a>\n </div>\n </bs-alert>\n }\n\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n @if (!successMessage()) {\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"newPassword\" class=\"form-label\">{{ 'auth.newPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.resetPassword' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n"
218
+ }]
219
+ }]
220
+ });
221
+ export { SparkResetPasswordComponent };
222
+
223
+ //# sourceMappingURL=mintplayer-ng-spark-auth-reset-password.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintplayer-ng-spark-auth-reset-password.mjs","names":[],"sources":["../../auth/reset-password/src/spark-reset-password.component.ts","../../auth/reset-password/src/spark-reset-password.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { ReactiveFormsModule, FormBuilder, Validators, AbstractControl, ValidationErrors } from '@angular/forms';\nimport { RouterLink, ActivatedRoute, Router } from '@angular/router';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { Color } from '@mintplayer/ng-bootstrap';\nimport { BsAlertComponent } from '@mintplayer/ng-bootstrap/alert';\nimport { BsCardComponent, BsCardHeaderComponent } from '@mintplayer/ng-bootstrap/card';\nimport { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';\nimport { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';\nimport { SPARK_AUTH_ROUTE_PATHS } from '@mintplayer/ng-spark/auth/models';\nimport { SparkAuthService, SparkAuthTranslationService } from '@mintplayer/ng-spark/auth/core';\nimport { TranslateKeyPipe } from '@mintplayer/ng-spark/auth/pipes';\n\nfunction passwordMatchValidator(control: AbstractControl): ValidationErrors | null {\n const password = control.get('newPassword');\n const confirmPassword = control.get('confirmPassword');\n if (password && confirmPassword && password.value !== confirmPassword.value) {\n return { passwordMismatch: true };\n }\n return null;\n}\n\n@Component({\n selector: 'spark-reset-password',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [ReactiveFormsModule, RouterLink, BsAlertComponent, BsCardComponent, BsCardHeaderComponent, BsFormComponent, BsFormControlDirective, BsSpinnerComponent, TranslateKeyPipe],\n templateUrl: './spark-reset-password.component.html',\n})\nexport class SparkResetPasswordComponent implements OnInit {\n private readonly fb = inject(FormBuilder);\n private readonly authService = inject(SparkAuthService);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly translation = inject(SparkAuthTranslationService);\n readonly routePaths = inject(SPARK_AUTH_ROUTE_PATHS);\n\n colors = Color;\n readonly loading = signal(false);\n readonly errorMessage = signal('');\n readonly successMessage = signal('');\n\n private email = '';\n private code = '';\n\n readonly form = this.fb.group({\n newPassword: ['', Validators.required],\n confirmPassword: ['', Validators.required],\n }, { validators: passwordMatchValidator });\n\n ngOnInit(): void {\n this.email = this.route.snapshot.queryParamMap.get('email') ?? '';\n this.code = this.route.snapshot.queryParamMap.get('code') ?? '';\n\n if (!this.email || !this.code) {\n this.errorMessage.set(this.translation.t('auth.invalidResetLink'));\n }\n }\n\n async onSubmit(): Promise<void> {\n if (this.form.invalid) {\n this.form.markAllAsTouched();\n return;\n }\n\n if (!this.email || !this.code) {\n this.errorMessage.set(this.translation.t('auth.invalidResetLink'));\n return;\n }\n\n this.loading.set(true);\n this.errorMessage.set('');\n this.successMessage.set('');\n\n const { newPassword } = this.form.value;\n\n try {\n await this.authService.resetPassword(this.email, this.code, newPassword!);\n this.successMessage.set(this.translation.t('auth.resetSuccess'));\n } catch (err: any) {\n if (err instanceof HttpErrorResponse && err.error?.detail) {\n this.errorMessage.set(err.error.detail);\n } else {\n this.errorMessage.set(this.translation.t('auth.resetFailed'));\n }\n } finally {\n this.loading.set(false);\n }\n }\n}\n\nexport default SparkResetPasswordComponent;\n","<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.resetPassword' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (successMessage()) {\n <bs-alert [type]=\"colors.success\" class=\"mb-3\">\n {{ successMessage() }}\n <div class=\"mt-2\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.goToLogin' | t }}</a>\n </div>\n </bs-alert>\n }\n\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n @if (!successMessage()) {\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <div class=\"mb-3\">\n <label for=\"newPassword\" class=\"form-label\">{{ 'auth.newPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\"\n />\n </div>\n\n <div class=\"mb-3\">\n <label for=\"confirmPassword\" class=\"form-label\">{{ 'auth.confirmPassword' | t }}</label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\"\n />\n @if (form.touched && form.hasError('passwordMismatch')) {\n <div class=\"text-danger mt-1\">{{ 'auth.passwordMismatch' | t }}</div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.resetPassword' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n }\n </div>\n </bs-card>\n</div>\n"],"mappings":"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"}