Add user module routing, integrate markdown support, and enhance dialog functionality
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<h1 mat-dialog-title>Hi </h1>
|
||||
<form [formGroup]="signUpForm">
|
||||
<div mat-dialog-content>
|
||||
<p>User name</p>
|
||||
<mat-form-field class="fillField">
|
||||
<input matInput
|
||||
formControlName="username"
|
||||
[(ngModel)]="data.username"
|
||||
minlength="3"
|
||||
>
|
||||
</mat-form-field>
|
||||
<p>Email</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput type="email"
|
||||
formControlName="email"
|
||||
|
||||
placeholder="Ex. pat@example.com"
|
||||
[(ngModel)]="data.email"
|
||||
(blur)="updateErrorMessage()"
|
||||
required
|
||||
>
|
||||
@if (emailFormControl.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<p>Password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Enter your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "password"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.password"
|
||||
minlength="6"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<p>Confirm password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Confirm your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "confirmPassword"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.confirmPassword"
|
||||
/>
|
||||
@if (signUpForm.get("confirmPassword")?.value !== signUpForm.get("password")?.value) {
|
||||
<mat-error>Passwords do not match</mat-error>
|
||||
}
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="login()">Login</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">No Thanks</button>
|
||||
<button mat-button cdkFocusInitial (click)="signup()">Ok</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,7 @@
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.fillField{
|
||||
width: 100%;
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DialogSignupComponent } from './dialog-signup.component';
|
||||
|
||||
describe('DialogSignupComponent', () => {
|
||||
let component: DialogSignupComponent;
|
||||
let fixture: ComponentFixture<DialogSignupComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DialogSignupComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DialogSignupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, EventEmitter, Inject, inject, OnInit, Output, signal} from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
FormGroupDirective,
|
||||
FormsModule,
|
||||
NgForm,
|
||||
ReactiveFormsModule, ValidationErrors, ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from '@angular/material/dialog';
|
||||
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {DialogSignupData} from '../../main-module/main.component/main.component';
|
||||
import {ErrorStateMatcher} from '@angular/material/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog-signup.component',
|
||||
imports: [
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogTitle,
|
||||
MatFormField,
|
||||
MatIcon,
|
||||
MatInput,
|
||||
MatLabel,
|
||||
MatSuffix,
|
||||
MatFormField,
|
||||
ReactiveFormsModule,
|
||||
|
||||
],
|
||||
templateUrl: './dialog-signup.component.html',
|
||||
styleUrl: './dialog-signup.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class DialogSignupComponent implements OnInit {
|
||||
readonly dialogRef = inject(MatDialogRef<DialogSignupComponent>);
|
||||
hide = signal(true);
|
||||
|
||||
@Output() signupClicked = new EventEmitter<any>();
|
||||
@Output() loginClicked = new EventEmitter<any>();
|
||||
|
||||
private _snackBar = inject(MatSnackBar);
|
||||
|
||||
durationInSeconds = 5;
|
||||
|
||||
emailFormControl = new FormControl('', [Validators.required, Validators.email]);
|
||||
|
||||
matcher = new MyErrorStateMatcher();
|
||||
|
||||
errorMessage = signal('');
|
||||
|
||||
signUpForm = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
email: new FormControl('', [Validators.required, Validators.email]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
confirmPassword: new FormControl('', [Validators.required, this.validateSamePassword]),
|
||||
});
|
||||
minPw = 8;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogSignupData,
|
||||
private formBuilder: FormBuilder) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
updateErrorMessage() {
|
||||
if (this.emailFormControl.hasError('required')) {
|
||||
this.errorMessage.set('You must enter a value');
|
||||
} else if (this.emailFormControl.hasError('email')) {
|
||||
this.errorMessage.set('Not a valid email');
|
||||
} else {
|
||||
this.errorMessage.set('');
|
||||
}
|
||||
}
|
||||
|
||||
clickEvent(event: MouseEvent) {
|
||||
this.hide.set(!this.hide());
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
openSignupFailedSnackBar(errorMessage : string = "Sign up failed.") {
|
||||
this._snackBar.open(errorMessage , "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
openSignupSuccessSnackBar(message : string = "User registered successfully!") {
|
||||
this._snackBar.open(message, "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
signup() {
|
||||
if (!this.signUpForm.invalid) {
|
||||
this.signupClicked.emit(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginClicked.emit();
|
||||
}
|
||||
|
||||
private validateSamePassword(control: AbstractControl): ValidationErrors | null {
|
||||
const password = control.parent?.get('password');
|
||||
const confirmPassword = control.parent?.get('confirmPassword');
|
||||
return password?.value == confirmPassword?.value ? null : { 'notSame': true };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Error when invalid control is dirty, touched, or submitted. */
|
||||
export class MyErrorStateMatcher implements ErrorStateMatcher {
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const isSubmitted = form && form.submitted;
|
||||
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user