Add user module routing, integrate markdown support, and enhance dialog functionality

This commit is contained in:
liosha84
2025-07-05 14:26:02 +03:00
parent 25e54d5050
commit fa27aca298
44 changed files with 2616 additions and 135 deletions
@@ -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%;
};
@@ -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));
}
}