@acontplus/ng-auth 1.0.1 → 1.0.2
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/README.md +160 -0
- package/fesm2022/acontplus-ng-auth.mjs +30 -231
- package/fesm2022/acontplus-ng-auth.mjs.map +1 -1
- package/index.d.ts +13 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -126,3 +126,163 @@ export class AppModule { }
|
|
|
126
126
|
## Running unit tests
|
|
127
127
|
|
|
128
128
|
Run `nx test ng-auth` to execute the unit tests.
|
|
129
|
+
|
|
130
|
+
## Login Component
|
|
131
|
+
|
|
132
|
+
The `LoginComponent` provides a flexible, themeable authentication UI component with support for custom fields and dynamic content.
|
|
133
|
+
|
|
134
|
+
### Basic Usage
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { LoginComponent } from '@acontplus/ng-auth/ui/login';
|
|
138
|
+
|
|
139
|
+
@Component({
|
|
140
|
+
template: `
|
|
141
|
+
<acp-login
|
|
142
|
+
title="Welcome Back"
|
|
143
|
+
[showRegisterButton]="true">
|
|
144
|
+
</acp-login>
|
|
145
|
+
`,
|
|
146
|
+
imports: [LoginComponent]
|
|
147
|
+
})
|
|
148
|
+
export class AuthPageComponent {}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Flexible Form Fields
|
|
152
|
+
|
|
153
|
+
The component supports additional form fields through two approaches:
|
|
154
|
+
|
|
155
|
+
#### 1. Additional Form Controls via Inputs
|
|
156
|
+
|
|
157
|
+
Pass additional form controls programmatically:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { FormControl, Validators } from '@angular/forms';
|
|
161
|
+
|
|
162
|
+
@Component({...})
|
|
163
|
+
export class AuthPageComponent {
|
|
164
|
+
signinExtras = {
|
|
165
|
+
companyId: new FormControl('', Validators.required),
|
|
166
|
+
rememberMe: new FormControl(false)
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
signupExtras = {
|
|
170
|
+
companyId: new FormControl('', Validators.required),
|
|
171
|
+
role: new FormControl('', Validators.required),
|
|
172
|
+
validationPin: new FormControl('', [Validators.required, Validators.pattern(/^\d{6}$/)])
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```html
|
|
178
|
+
<acp-login
|
|
179
|
+
[additionalSigninControls]="signinExtras"
|
|
180
|
+
[additionalSignupControls]="signupExtras">
|
|
181
|
+
</acp-login>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### 2. Content Projection for Custom Templates
|
|
185
|
+
|
|
186
|
+
Use content projection slots for custom field templates:
|
|
187
|
+
|
|
188
|
+
```html
|
|
189
|
+
<acp-login>
|
|
190
|
+
<!-- Additional fields for signin form -->
|
|
191
|
+
<div signin-fields>
|
|
192
|
+
<mat-form-field class="w-100">
|
|
193
|
+
<mat-label>Company</mat-label>
|
|
194
|
+
<mat-select formControlName="companyId">
|
|
195
|
+
@for (company of companies; track company.id) {
|
|
196
|
+
<mat-option [value]="company.id">
|
|
197
|
+
{{ company.name }}
|
|
198
|
+
</mat-option>
|
|
199
|
+
}
|
|
200
|
+
</mat-select>
|
|
201
|
+
</mat-form-field>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<!-- Additional fields for signup form -->
|
|
205
|
+
<div signup-fields>
|
|
206
|
+
<mat-form-field class="w-100">
|
|
207
|
+
<mat-label>Company</mat-label>
|
|
208
|
+
<mat-select formControlName="companyId" required>
|
|
209
|
+
@for (company of companies; track company.id) {
|
|
210
|
+
<mat-option [value]="company.id">
|
|
211
|
+
{{ company.name }}
|
|
212
|
+
</mat-option>
|
|
213
|
+
}
|
|
214
|
+
</mat-select>
|
|
215
|
+
</mat-form-field>
|
|
216
|
+
|
|
217
|
+
<mat-form-field class="w-100">
|
|
218
|
+
<mat-label>Role</mat-label>
|
|
219
|
+
<mat-select formControlName="role" required>
|
|
220
|
+
<mat-option value="admin">Administrator</mat-option>
|
|
221
|
+
<mat-option value="user">User</mat-option>
|
|
222
|
+
<mat-option value="manager">Manager</mat-option>
|
|
223
|
+
</mat-select>
|
|
224
|
+
</mat-form-field>
|
|
225
|
+
|
|
226
|
+
<mat-form-field class="w-100">
|
|
227
|
+
<mat-label>Validation PIN</mat-label>
|
|
228
|
+
<input matInput type="text" placeholder="Enter PIN" formControlName="validationPin" required />
|
|
229
|
+
</mat-form-field>
|
|
230
|
+
</div>
|
|
231
|
+
</acp-login>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Dynamic Footer Content
|
|
235
|
+
|
|
236
|
+
Customize the footer with dynamic content:
|
|
237
|
+
|
|
238
|
+
```html
|
|
239
|
+
<ng-template #customFooter>
|
|
240
|
+
<div class="row mt-3">
|
|
241
|
+
<div class="col-12 text-center">
|
|
242
|
+
<a mat-button color="primary" href="/terms">Terms of Service</a>
|
|
243
|
+
<a mat-button color="primary" href="/privacy">Privacy Policy</a>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
</ng-template>
|
|
247
|
+
|
|
248
|
+
<acp-login [footerContent]="customFooter">
|
|
249
|
+
<!-- form content -->
|
|
250
|
+
</acp-login>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Theme Color Inheritance
|
|
254
|
+
|
|
255
|
+
The component uses CSS custom properties to inherit colors from the parent app's theme:
|
|
256
|
+
|
|
257
|
+
- Background gradient: Uses `--mdc-theme-primary` and `--mdc-theme-secondary`
|
|
258
|
+
- Title color: Uses `--mdc-theme-on-surface`
|
|
259
|
+
- Error alerts: Uses `--mdc-theme-error`, `--mdc-theme-error-container`, `--mdc-theme-on-error-container`
|
|
260
|
+
|
|
261
|
+
Fallback colors use Angular Material's Material Design 3 (M3) neutral color tokens:
|
|
262
|
+
- Primary: #5c5f5c (M3 neutral primary)
|
|
263
|
+
- Secondary: #79747e (M3 neutral secondary)
|
|
264
|
+
- On surface: #1c1b1f (M3 on-surface)
|
|
265
|
+
- Error: #ba1a1a (M3 error)
|
|
266
|
+
- Error container: #ffdad6 (M3 error-container)
|
|
267
|
+
- On error container: #410002 (M3 on-error-container)
|
|
268
|
+
|
|
269
|
+
To customize colors, define these CSS variables in your app's global styles:
|
|
270
|
+
|
|
271
|
+
```css
|
|
272
|
+
:root {
|
|
273
|
+
--mdc-theme-primary: #your-primary-color;
|
|
274
|
+
--mdc-theme-secondary: #your-secondary-color;
|
|
275
|
+
--mdc-theme-on-surface: #your-text-color;
|
|
276
|
+
--mdc-theme-error: #your-error-color;
|
|
277
|
+
--mdc-theme-error-container: #your-error-bg;
|
|
278
|
+
--mdc-theme-on-error-container: #your-error-text;
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Component Inputs
|
|
283
|
+
|
|
284
|
+
- `title: string` - The title displayed in the card header (default: 'Login')
|
|
285
|
+
- `showRegisterButton: boolean` - Whether to show the register button (default: true)
|
|
286
|
+
- `additionalSigninControls: Record<string, AbstractControl>` - Additional controls for signin form
|
|
287
|
+
- `additionalSignupControls: Record<string, AbstractControl>` - Additional controls for signup form
|
|
288
|
+
- `footerContent: TemplateRef<any> | null` - Custom footer template
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { UserRepository } from '@acontplus/ng-infrastructure';
|
|
2
2
|
export { TOKEN_PROVIDER } from '@acontplus/ng-infrastructure';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { inject, PLATFORM_ID, Injectable, signal, input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { inject, PLATFORM_ID, Injectable, signal, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
5
|
import { Router } from '@angular/router';
|
|
6
|
-
import
|
|
6
|
+
import * as i1 from '@angular/common';
|
|
7
|
+
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
7
8
|
import { jwtDecode } from 'jwt-decode';
|
|
8
9
|
import { ENVIRONMENT, AUTH_API } from '@acontplus/ng-config';
|
|
9
10
|
import { HttpClient } from '@angular/common/http';
|
|
10
11
|
import { from, map, of, tap, catchError, throwError } from 'rxjs';
|
|
11
12
|
import { switchMap } from 'rxjs/operators';
|
|
12
13
|
import { AuthTokens } from '@acontplus/core';
|
|
13
|
-
import * as
|
|
14
|
+
import * as i2 from '@angular/forms';
|
|
14
15
|
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
15
16
|
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent, MatCardFooter } from '@angular/material/card';
|
|
16
17
|
import { MatLabel, MatFormField } from '@angular/material/form-field';
|
|
17
18
|
import { MatInput } from '@angular/material/input';
|
|
18
19
|
import { MatIcon } from '@angular/material/icon';
|
|
19
20
|
import { MatButton, MatAnchor } from '@angular/material/button';
|
|
20
|
-
import { MatTooltip } from '@angular/material/tooltip';
|
|
21
21
|
|
|
22
22
|
class TokenRepository {
|
|
23
23
|
environment = inject(ENVIRONMENT);
|
|
@@ -612,6 +612,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImpor
|
|
|
612
612
|
// src/lib/presentation/components/login/login.component.ts
|
|
613
613
|
class LoginComponent {
|
|
614
614
|
title = input('Login', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
615
|
+
showRegisterButton = input(true, ...(ngDevMode ? [{ debugName: "showRegisterButton" }] : []));
|
|
616
|
+
// Additional form controls that can be passed from parent components
|
|
617
|
+
additionalSigninControls = input({}, ...(ngDevMode ? [{ debugName: "additionalSigninControls" }] : []));
|
|
618
|
+
additionalSignupControls = input({}, ...(ngDevMode ? [{ debugName: "additionalSignupControls" }] : []));
|
|
619
|
+
// Additional field templates
|
|
620
|
+
additionalSigninFields = input(null, ...(ngDevMode ? [{ debugName: "additionalSigninFields" }] : []));
|
|
621
|
+
additionalSignupFields = input(null, ...(ngDevMode ? [{ debugName: "additionalSignupFields" }] : []));
|
|
622
|
+
// Footer content template
|
|
623
|
+
footerContent = input(null, ...(ngDevMode ? [{ debugName: "footerContent" }] : []));
|
|
624
|
+
// Computed signal to check if footer content exists
|
|
625
|
+
hasFooterContent = computed(() => this.footerContent() !== null, ...(ngDevMode ? [{ debugName: "hasFooterContent" }] : []));
|
|
615
626
|
fb = inject(FormBuilder);
|
|
616
627
|
loginUseCase = inject(LoginUseCase);
|
|
617
628
|
registerUseCase = inject(RegisterUseCase);
|
|
@@ -632,7 +643,17 @@ class LoginComponent {
|
|
|
632
643
|
password: ['', [Validators.required, Validators.minLength(6)]],
|
|
633
644
|
});
|
|
634
645
|
}
|
|
635
|
-
|
|
646
|
+
ngOnInit() {
|
|
647
|
+
// Add additional controls to signin form
|
|
648
|
+
Object.entries(this.additionalSigninControls()).forEach(([key, control]) => {
|
|
649
|
+
this.signinForm.addControl(key, control);
|
|
650
|
+
});
|
|
651
|
+
// Add additional controls to signup form
|
|
652
|
+
Object.entries(this.additionalSignupControls()).forEach(([key, control]) => {
|
|
653
|
+
this.signupForm.addControl(key, control);
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
switchMode() {
|
|
636
657
|
this.isLoginMode.set(!this.isLoginMode());
|
|
637
658
|
this.errorMessage.set(null);
|
|
638
659
|
}
|
|
@@ -671,122 +692,12 @@ class LoginComponent {
|
|
|
671
692
|
}
|
|
672
693
|
}
|
|
673
694
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
674
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: LoginComponent, isStandalone: true, selector: "
|
|
675
|
-
<section id="wrapper" class="d-flex justify-content-center align-items-center">
|
|
676
|
-
<mat-card class="mat-elevation-z8 p-4 rounded">
|
|
677
|
-
<mat-card-header>
|
|
678
|
-
<mat-card-title class="text-center">{{ title() }}</mat-card-title>
|
|
679
|
-
</mat-card-header>
|
|
680
|
-
<mat-card-content>
|
|
681
|
-
@if (isLoginMode()) {
|
|
682
|
-
<form [formGroup]="signinForm" (ngSubmit)="signIn()" class="d-flex flex-column gap-3">
|
|
683
|
-
<mat-form-field class="w-100">
|
|
684
|
-
<mat-label>Usuario</mat-label>
|
|
685
|
-
<input matInput type="text" placeholder="Ingrese su usuario" formControlName="email" />
|
|
686
|
-
</mat-form-field>
|
|
687
|
-
|
|
688
|
-
<mat-form-field class="w-100">
|
|
689
|
-
<mat-label>Contraseña</mat-label>
|
|
690
|
-
<input matInput type="password" placeholder="Ingrese su contraseña" formControlName="password" />
|
|
691
|
-
</mat-form-field>
|
|
692
|
-
|
|
693
|
-
<div class="d-flex justify-content-center mt-3">
|
|
694
|
-
<button
|
|
695
|
-
mat-raised-button
|
|
696
|
-
color="primary"
|
|
697
|
-
[disabled]="!signinForm.valid || isLoading()"
|
|
698
|
-
type="submit"
|
|
699
|
-
class="w-100"
|
|
700
|
-
>
|
|
701
|
-
@if (isLoading()) {
|
|
702
|
-
Ingresando...
|
|
703
|
-
} @else {
|
|
704
|
-
<ng-container>Ingresar <mat-icon>login</mat-icon></ng-container>
|
|
705
|
-
}
|
|
706
|
-
</button>
|
|
707
|
-
</div>
|
|
708
|
-
|
|
709
|
-
<!-- <div class="text-center mt-2">
|
|
710
|
-
<button
|
|
711
|
-
mat-button
|
|
712
|
-
type="button"
|
|
713
|
-
(click)="toggleMode()"
|
|
714
|
-
>
|
|
715
|
-
¿No tienes cuenta? Regístrate
|
|
716
|
-
</button>
|
|
717
|
-
</div> -->
|
|
718
|
-
</form>
|
|
719
|
-
} @else {
|
|
720
|
-
<form [formGroup]="signupForm" (ngSubmit)="registerUser()" class="d-flex flex-column gap-3">
|
|
721
|
-
<mat-form-field class="w-100">
|
|
722
|
-
<mat-label>Nombre</mat-label>
|
|
723
|
-
<input matInput type="text" placeholder="Ingrese su nombre" formControlName="displayName" />
|
|
724
|
-
</mat-form-field>
|
|
725
|
-
|
|
726
|
-
<mat-form-field class="w-100">
|
|
727
|
-
<mat-label>Email</mat-label>
|
|
728
|
-
<input matInput type="email" placeholder="Ingrese su email" formControlName="email" />
|
|
729
|
-
</mat-form-field>
|
|
730
|
-
|
|
731
|
-
<mat-form-field class="w-100">
|
|
732
|
-
<mat-label>Contraseña</mat-label>
|
|
733
|
-
<input matInput type="password" placeholder="Ingrese su contraseña" formControlName="password" />
|
|
734
|
-
</mat-form-field>
|
|
735
|
-
|
|
736
|
-
<div class="d-flex justify-content-center mt-3">
|
|
737
|
-
<button
|
|
738
|
-
mat-raised-button
|
|
739
|
-
color="primary"
|
|
740
|
-
[disabled]="!signupForm.valid || isLoading()"
|
|
741
|
-
type="submit"
|
|
742
|
-
class="w-100"
|
|
743
|
-
>
|
|
744
|
-
@if (isLoading()) {
|
|
745
|
-
Registrando...
|
|
746
|
-
} @else {
|
|
747
|
-
<ng-container>Registrarse <mat-icon>person_add</mat-icon></ng-container>
|
|
748
|
-
}
|
|
749
|
-
</button>
|
|
750
|
-
</div>
|
|
751
|
-
|
|
752
|
-
<div class="text-center mt-2">
|
|
753
|
-
<button mat-button type="button" (click)="toggleMode()">¿Ya tienes cuenta? Inicia sesión</button>
|
|
754
|
-
</div>
|
|
755
|
-
</form>
|
|
756
|
-
}
|
|
757
|
-
@if (errorMessage()) {
|
|
758
|
-
<div class="alert alert-danger mt-3" role="alert">
|
|
759
|
-
{{ errorMessage() }}
|
|
760
|
-
</div>
|
|
761
|
-
}
|
|
762
|
-
</mat-card-content>
|
|
763
|
-
<mat-card-footer>
|
|
764
|
-
<div class="row mt-3">
|
|
765
|
-
<div class="col-xs-12 col-sm-12 col-md-12 m-t-10 text-center">
|
|
766
|
-
<div class="social">
|
|
767
|
-
<a
|
|
768
|
-
mat-button
|
|
769
|
-
color="primary"
|
|
770
|
-
matTooltip="Ir a Acontplus Web"
|
|
771
|
-
aria-label="Acontplus"
|
|
772
|
-
href="https://app.acontplus.com"
|
|
773
|
-
target="_blank"
|
|
774
|
-
rel="noopener noreferrer"
|
|
775
|
-
>
|
|
776
|
-
<mat-icon>arrow_outward</mat-icon>
|
|
777
|
-
Acontplus Web
|
|
778
|
-
</a>
|
|
779
|
-
</div>
|
|
780
|
-
</div>
|
|
781
|
-
</div>
|
|
782
|
-
</mat-card-footer>
|
|
783
|
-
</mat-card>
|
|
784
|
-
</section>
|
|
785
|
-
`, isInline: true, styles: ["#wrapper{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#667eea,#764ba2);padding:20px}mat-card{width:100%;max-width:400px;border-radius:12px;box-shadow:0 8px 32px #0000001a}mat-card-header{text-align:center;margin-bottom:20px}mat-card-title{font-size:24px;font-weight:600;color:#333}mat-form-field{width:100%}.w-100{width:100%}.d-flex{display:flex}.flex-column{flex-direction:column}.gap-3{gap:12px}.justify-content-center{justify-content:center}.align-items-center{align-items:center}.mt-3{margin-top:12px}.mt-2{margin-top:8px}.text-center{text-align:center}.p-4{padding:16px}.rounded{border-radius:12px}.alert-danger{background-color:#f8d7da;border-color:#f5c6cb;color:#721c24;padding:12px;border-radius:4px;border:1px solid transparent}.row{display:flex;flex-wrap:wrap;margin:0 -15px}.col-xs-12,.col-sm-12,.col-md-12{flex:0 0 100%;max-width:100%;padding:0 15px}.m-t-10{margin-top:10px}.social{display:flex;justify-content:center}mat-button{border-radius:8px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatCardFooter, selector: "mat-card-footer" }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
695
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: LoginComponent, isStandalone: true, selector: "acp-login", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, showRegisterButton: { classPropertyName: "showRegisterButton", publicName: "showRegisterButton", isSignal: true, isRequired: false, transformFunction: null }, additionalSigninControls: { classPropertyName: "additionalSigninControls", publicName: "additionalSigninControls", isSignal: true, isRequired: false, transformFunction: null }, additionalSignupControls: { classPropertyName: "additionalSignupControls", publicName: "additionalSignupControls", isSignal: true, isRequired: false, transformFunction: null }, additionalSigninFields: { classPropertyName: "additionalSigninFields", publicName: "additionalSigninFields", isSignal: true, isRequired: false, transformFunction: null }, additionalSignupFields: { classPropertyName: "additionalSignupFields", publicName: "additionalSignupFields", isSignal: true, isRequired: false, transformFunction: null }, footerContent: { classPropertyName: "footerContent", publicName: "footerContent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section id=\"wrapper\" class=\"d-flex justify-content-center align-items-center\">\n <mat-card class=\"mat-elevation-z8 p-4 rounded\">\n <mat-card-header>\n <mat-card-title class=\"text-center\">{{ title() }}</mat-card-title>\n </mat-card-header>\n <mat-card-content>\n @if (isLoginMode()) {\n <form [formGroup]=\"signinForm\" (ngSubmit)=\"signIn()\" class=\"d-flex flex-column gap-3\">\n <mat-form-field class=\"w-100\">\n <mat-label>Usuario</mat-label>\n <input matInput type=\"text\" placeholder=\"Ingrese su usuario\" formControlName=\"email\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Contrase\u00F1a</mat-label>\n <input matInput type=\"password\" placeholder=\"Ingrese su contrase\u00F1a\" formControlName=\"password\" />\n </mat-form-field>\n\n <!-- Additional signin fields -->\n <ng-container *ngTemplateOutlet=\"additionalSigninFields()\"></ng-container>\n\n <div class=\"d-flex justify-content-center mt-3\">\n <button mat-raised-button color=\"primary\" [disabled]=\"!signinForm.valid || isLoading()\" type=\"submit\"\n class=\"w-100\">\n @if (isLoading()) {\n Ingresando...\n } @else {\n <ng-container>Ingresar <mat-icon>login</mat-icon></ng-container>\n }\n </button>\n </div>\n\n <div class=\"text-center mt-2\">\n @if (showRegisterButton()) {\n <button mat-button type=\"button\" (click)=\"switchMode()\">\n \u00BFNo tienes cuenta? Reg\u00EDstrate\n </button>\n }\n </div>\n </form>\n } @else {\n <form [formGroup]=\"signupForm\" (ngSubmit)=\"registerUser()\" class=\"d-flex flex-column gap-3\">\n <mat-form-field class=\"w-100\">\n <mat-label>Nombre</mat-label>\n <input matInput type=\"text\" placeholder=\"Ingrese su nombre\" formControlName=\"displayName\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Email</mat-label>\n <input matInput type=\"email\" placeholder=\"Ingrese su email\" formControlName=\"email\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Contrase\u00F1a</mat-label>\n <input matInput type=\"password\" placeholder=\"Ingrese su contrase\u00F1a\" formControlName=\"password\" />\n </mat-form-field>\n\n <!-- Additional signup fields -->\n <ng-container *ngTemplateOutlet=\"additionalSignupFields()\"></ng-container>\n\n <div class=\"d-flex justify-content-center mt-3\">\n <button mat-raised-button color=\"primary\" [disabled]=\"!signupForm.valid || isLoading()\" type=\"submit\"\n class=\"w-100\">\n @if (isLoading()) {\n Registrando...\n } @else {\n <ng-container>Registrarse <mat-icon>person_add</mat-icon></ng-container>\n }\n </button>\n </div>\n\n <div class=\"text-center mt-2\">\n <button mat-button type=\"button\" (click)=\"switchMode()\">\u00BFYa tienes cuenta? Inicia sesi\u00F3n</button>\n </div>\n </form>\n }\n @if (errorMessage()) {\n <div class=\"alert alert-danger mt-3\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n }\n </mat-card-content>\n @if (hasFooterContent()) {\n <mat-card-footer>\n <ng-container *ngTemplateOutlet=\"footerContent()\"></ng-container>\n </mat-card-footer>\n }\n </mat-card>\n</section>\n", styles: ["#wrapper{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--mdc-theme-primary, #5c5f5c) 0%,var(--mdc-theme-secondary, #79747e) 100%);padding:20px}mat-card{width:100%;max-width:400px;border-radius:12px;box-shadow:0 8px 32px #0000001a}mat-card-header{text-align:center;margin-bottom:20px}mat-card-title{font-size:24px;font-weight:600;color:var(--mdc-theme-on-surface, #1c1b1f)}mat-form-field{width:100%}.w-100{width:100%}.d-flex{display:flex}.flex-column{flex-direction:column}.gap-3{gap:12px}.justify-content-center{justify-content:center}.align-items-center{align-items:center}.mt-3{margin-top:12px}.mt-2{margin-top:8px}.text-center{text-align:center}.p-4{padding:16px}.rounded{border-radius:12px}.alert-danger{background-color:var(--mdc-theme-error-container, #ffdad6);border-color:var(--mdc-theme-error, #ba1a1a);color:var(--mdc-theme-on-error-container, #410002);padding:12px;border-radius:4px;border:1px solid transparent}.row{display:flex;flex-wrap:wrap;margin:0 -15px}.col-xs-12,.col-sm-12,.col-md-12{flex:0 0 100%;max-width:100%;padding:0 15px}.m-t-10{margin-top:10px}.social{display:flex;justify-content:center}mat-button{border-radius:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "component", type: MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "directive", type: MatCardContent, selector: "mat-card-content" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatCardFooter, selector: "mat-card-footer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
786
696
|
}
|
|
787
697
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LoginComponent, decorators: [{
|
|
788
698
|
type: Component,
|
|
789
|
-
args: [{ selector: '
|
|
699
|
+
args: [{ selector: 'acp-login', imports: [
|
|
700
|
+
CommonModule,
|
|
790
701
|
ReactiveFormsModule,
|
|
791
702
|
MatCard,
|
|
792
703
|
MatCardHeader,
|
|
@@ -798,120 +709,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImpor
|
|
|
798
709
|
MatIcon,
|
|
799
710
|
MatButton,
|
|
800
711
|
MatCardFooter,
|
|
801
|
-
MatTooltip,
|
|
802
712
|
MatAnchor,
|
|
803
|
-
], template:
|
|
804
|
-
<section id="wrapper" class="d-flex justify-content-center align-items-center">
|
|
805
|
-
<mat-card class="mat-elevation-z8 p-4 rounded">
|
|
806
|
-
<mat-card-header>
|
|
807
|
-
<mat-card-title class="text-center">{{ title() }}</mat-card-title>
|
|
808
|
-
</mat-card-header>
|
|
809
|
-
<mat-card-content>
|
|
810
|
-
@if (isLoginMode()) {
|
|
811
|
-
<form [formGroup]="signinForm" (ngSubmit)="signIn()" class="d-flex flex-column gap-3">
|
|
812
|
-
<mat-form-field class="w-100">
|
|
813
|
-
<mat-label>Usuario</mat-label>
|
|
814
|
-
<input matInput type="text" placeholder="Ingrese su usuario" formControlName="email" />
|
|
815
|
-
</mat-form-field>
|
|
816
|
-
|
|
817
|
-
<mat-form-field class="w-100">
|
|
818
|
-
<mat-label>Contraseña</mat-label>
|
|
819
|
-
<input matInput type="password" placeholder="Ingrese su contraseña" formControlName="password" />
|
|
820
|
-
</mat-form-field>
|
|
821
|
-
|
|
822
|
-
<div class="d-flex justify-content-center mt-3">
|
|
823
|
-
<button
|
|
824
|
-
mat-raised-button
|
|
825
|
-
color="primary"
|
|
826
|
-
[disabled]="!signinForm.valid || isLoading()"
|
|
827
|
-
type="submit"
|
|
828
|
-
class="w-100"
|
|
829
|
-
>
|
|
830
|
-
@if (isLoading()) {
|
|
831
|
-
Ingresando...
|
|
832
|
-
} @else {
|
|
833
|
-
<ng-container>Ingresar <mat-icon>login</mat-icon></ng-container>
|
|
834
|
-
}
|
|
835
|
-
</button>
|
|
836
|
-
</div>
|
|
837
|
-
|
|
838
|
-
<!-- <div class="text-center mt-2">
|
|
839
|
-
<button
|
|
840
|
-
mat-button
|
|
841
|
-
type="button"
|
|
842
|
-
(click)="toggleMode()"
|
|
843
|
-
>
|
|
844
|
-
¿No tienes cuenta? Regístrate
|
|
845
|
-
</button>
|
|
846
|
-
</div> -->
|
|
847
|
-
</form>
|
|
848
|
-
} @else {
|
|
849
|
-
<form [formGroup]="signupForm" (ngSubmit)="registerUser()" class="d-flex flex-column gap-3">
|
|
850
|
-
<mat-form-field class="w-100">
|
|
851
|
-
<mat-label>Nombre</mat-label>
|
|
852
|
-
<input matInput type="text" placeholder="Ingrese su nombre" formControlName="displayName" />
|
|
853
|
-
</mat-form-field>
|
|
854
|
-
|
|
855
|
-
<mat-form-field class="w-100">
|
|
856
|
-
<mat-label>Email</mat-label>
|
|
857
|
-
<input matInput type="email" placeholder="Ingrese su email" formControlName="email" />
|
|
858
|
-
</mat-form-field>
|
|
859
|
-
|
|
860
|
-
<mat-form-field class="w-100">
|
|
861
|
-
<mat-label>Contraseña</mat-label>
|
|
862
|
-
<input matInput type="password" placeholder="Ingrese su contraseña" formControlName="password" />
|
|
863
|
-
</mat-form-field>
|
|
864
|
-
|
|
865
|
-
<div class="d-flex justify-content-center mt-3">
|
|
866
|
-
<button
|
|
867
|
-
mat-raised-button
|
|
868
|
-
color="primary"
|
|
869
|
-
[disabled]="!signupForm.valid || isLoading()"
|
|
870
|
-
type="submit"
|
|
871
|
-
class="w-100"
|
|
872
|
-
>
|
|
873
|
-
@if (isLoading()) {
|
|
874
|
-
Registrando...
|
|
875
|
-
} @else {
|
|
876
|
-
<ng-container>Registrarse <mat-icon>person_add</mat-icon></ng-container>
|
|
877
|
-
}
|
|
878
|
-
</button>
|
|
879
|
-
</div>
|
|
880
|
-
|
|
881
|
-
<div class="text-center mt-2">
|
|
882
|
-
<button mat-button type="button" (click)="toggleMode()">¿Ya tienes cuenta? Inicia sesión</button>
|
|
883
|
-
</div>
|
|
884
|
-
</form>
|
|
885
|
-
}
|
|
886
|
-
@if (errorMessage()) {
|
|
887
|
-
<div class="alert alert-danger mt-3" role="alert">
|
|
888
|
-
{{ errorMessage() }}
|
|
889
|
-
</div>
|
|
890
|
-
}
|
|
891
|
-
</mat-card-content>
|
|
892
|
-
<mat-card-footer>
|
|
893
|
-
<div class="row mt-3">
|
|
894
|
-
<div class="col-xs-12 col-sm-12 col-md-12 m-t-10 text-center">
|
|
895
|
-
<div class="social">
|
|
896
|
-
<a
|
|
897
|
-
mat-button
|
|
898
|
-
color="primary"
|
|
899
|
-
matTooltip="Ir a Acontplus Web"
|
|
900
|
-
aria-label="Acontplus"
|
|
901
|
-
href="https://app.acontplus.com"
|
|
902
|
-
target="_blank"
|
|
903
|
-
rel="noopener noreferrer"
|
|
904
|
-
>
|
|
905
|
-
<mat-icon>arrow_outward</mat-icon>
|
|
906
|
-
Acontplus Web
|
|
907
|
-
</a>
|
|
908
|
-
</div>
|
|
909
|
-
</div>
|
|
910
|
-
</div>
|
|
911
|
-
</mat-card-footer>
|
|
912
|
-
</mat-card>
|
|
913
|
-
</section>
|
|
914
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["#wrapper{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#667eea,#764ba2);padding:20px}mat-card{width:100%;max-width:400px;border-radius:12px;box-shadow:0 8px 32px #0000001a}mat-card-header{text-align:center;margin-bottom:20px}mat-card-title{font-size:24px;font-weight:600;color:#333}mat-form-field{width:100%}.w-100{width:100%}.d-flex{display:flex}.flex-column{flex-direction:column}.gap-3{gap:12px}.justify-content-center{justify-content:center}.align-items-center{align-items:center}.mt-3{margin-top:12px}.mt-2{margin-top:8px}.text-center{text-align:center}.p-4{padding:16px}.rounded{border-radius:12px}.alert-danger{background-color:#f8d7da;border-color:#f5c6cb;color:#721c24;padding:12px;border-radius:4px;border:1px solid transparent}.row{display:flex;flex-wrap:wrap;margin:0 -15px}.col-xs-12,.col-sm-12,.col-md-12{flex:0 0 100%;max-width:100%;padding:0 15px}.m-t-10{margin-top:10px}.social{display:flex;justify-content:center}mat-button{border-radius:8px}\n"] }]
|
|
713
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section id=\"wrapper\" class=\"d-flex justify-content-center align-items-center\">\n <mat-card class=\"mat-elevation-z8 p-4 rounded\">\n <mat-card-header>\n <mat-card-title class=\"text-center\">{{ title() }}</mat-card-title>\n </mat-card-header>\n <mat-card-content>\n @if (isLoginMode()) {\n <form [formGroup]=\"signinForm\" (ngSubmit)=\"signIn()\" class=\"d-flex flex-column gap-3\">\n <mat-form-field class=\"w-100\">\n <mat-label>Usuario</mat-label>\n <input matInput type=\"text\" placeholder=\"Ingrese su usuario\" formControlName=\"email\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Contrase\u00F1a</mat-label>\n <input matInput type=\"password\" placeholder=\"Ingrese su contrase\u00F1a\" formControlName=\"password\" />\n </mat-form-field>\n\n <!-- Additional signin fields -->\n <ng-container *ngTemplateOutlet=\"additionalSigninFields()\"></ng-container>\n\n <div class=\"d-flex justify-content-center mt-3\">\n <button mat-raised-button color=\"primary\" [disabled]=\"!signinForm.valid || isLoading()\" type=\"submit\"\n class=\"w-100\">\n @if (isLoading()) {\n Ingresando...\n } @else {\n <ng-container>Ingresar <mat-icon>login</mat-icon></ng-container>\n }\n </button>\n </div>\n\n <div class=\"text-center mt-2\">\n @if (showRegisterButton()) {\n <button mat-button type=\"button\" (click)=\"switchMode()\">\n \u00BFNo tienes cuenta? Reg\u00EDstrate\n </button>\n }\n </div>\n </form>\n } @else {\n <form [formGroup]=\"signupForm\" (ngSubmit)=\"registerUser()\" class=\"d-flex flex-column gap-3\">\n <mat-form-field class=\"w-100\">\n <mat-label>Nombre</mat-label>\n <input matInput type=\"text\" placeholder=\"Ingrese su nombre\" formControlName=\"displayName\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Email</mat-label>\n <input matInput type=\"email\" placeholder=\"Ingrese su email\" formControlName=\"email\" />\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>Contrase\u00F1a</mat-label>\n <input matInput type=\"password\" placeholder=\"Ingrese su contrase\u00F1a\" formControlName=\"password\" />\n </mat-form-field>\n\n <!-- Additional signup fields -->\n <ng-container *ngTemplateOutlet=\"additionalSignupFields()\"></ng-container>\n\n <div class=\"d-flex justify-content-center mt-3\">\n <button mat-raised-button color=\"primary\" [disabled]=\"!signupForm.valid || isLoading()\" type=\"submit\"\n class=\"w-100\">\n @if (isLoading()) {\n Registrando...\n } @else {\n <ng-container>Registrarse <mat-icon>person_add</mat-icon></ng-container>\n }\n </button>\n </div>\n\n <div class=\"text-center mt-2\">\n <button mat-button type=\"button\" (click)=\"switchMode()\">\u00BFYa tienes cuenta? Inicia sesi\u00F3n</button>\n </div>\n </form>\n }\n @if (errorMessage()) {\n <div class=\"alert alert-danger mt-3\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n }\n </mat-card-content>\n @if (hasFooterContent()) {\n <mat-card-footer>\n <ng-container *ngTemplateOutlet=\"footerContent()\"></ng-container>\n </mat-card-footer>\n }\n </mat-card>\n</section>\n", styles: ["#wrapper{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--mdc-theme-primary, #5c5f5c) 0%,var(--mdc-theme-secondary, #79747e) 100%);padding:20px}mat-card{width:100%;max-width:400px;border-radius:12px;box-shadow:0 8px 32px #0000001a}mat-card-header{text-align:center;margin-bottom:20px}mat-card-title{font-size:24px;font-weight:600;color:var(--mdc-theme-on-surface, #1c1b1f)}mat-form-field{width:100%}.w-100{width:100%}.d-flex{display:flex}.flex-column{flex-direction:column}.gap-3{gap:12px}.justify-content-center{justify-content:center}.align-items-center{align-items:center}.mt-3{margin-top:12px}.mt-2{margin-top:8px}.text-center{text-align:center}.p-4{padding:16px}.rounded{border-radius:12px}.alert-danger{background-color:var(--mdc-theme-error-container, #ffdad6);border-color:var(--mdc-theme-error, #ba1a1a);color:var(--mdc-theme-on-error-container, #410002);padding:12px;border-radius:4px;border:1px solid transparent}.row{display:flex;flex-wrap:wrap;margin:0 -15px}.col-xs-12,.col-sm-12,.col-md-12{flex:0 0 100%;max-width:100%;padding:0 15px}.m-t-10{margin-top:10px}.social{display:flex;justify-content:center}mat-button{border-radius:8px}\n"] }]
|
|
915
714
|
}], ctorParameters: () => [] });
|
|
916
715
|
|
|
917
716
|
// src/lib/presentation/components/index.ts
|