diff --git a/src/app/features/auth/components/register/register.html b/src/app/features/auth/components/register/register.html index 83a02af..d246cda 100644 --- a/src/app/features/auth/components/register/register.html +++ b/src/app/features/auth/components/register/register.html @@ -1,51 +1,74 @@ -
+

Register

-

Sign up with your
email address to get started

+

Sign up with your
email address to get started

@for (error of errors(); track error) { -

{{ error }}

+

{{ error }}

}
-
-
-
- Name - -
-
- Mobile Number - -
-
- Email - -

your-email-address@email.com

-
-
-
-
- Password - -
+ +
+ Name* + + +
-
- Confirm Password - -
+
+ Mobile Number* + + +
+ +
+ Email* + +

your-email-address@email.com

+ +
+ +
+ City* + + +
+ +
+ Password* + + +
+ +
+ Confirm Password* + + +
-
- City - -
-
- + Already have an account ? LoginAlready have an account ? Login
diff --git a/src/app/features/auth/components/register/register.ts b/src/app/features/auth/components/register/register.ts index 4b14aa6..23392d0 100644 --- a/src/app/features/auth/components/register/register.ts +++ b/src/app/features/auth/components/register/register.ts @@ -1,39 +1,42 @@ -import {Component, inject, signal} from "@angular/core"; -import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms"; -import {AuthService} from "../../services/auth-service"; -import {RegisterUserRequest} from "../../../../core/models/user.model"; +import { Component, inject, signal } from "@angular/core"; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; +import { AuthService } from "../../services/auth-service"; +import { RegisterUserRequest } from "../../../../core/models/user.model"; +import { Error } from "../../../../shared/components/error/error"; @Component({ selector: "app-register", - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, Error], templateUrl: "./register.html", styleUrl: "./register.css", }) export class Register { - authService = inject(AuthService); errors = signal([]); registerForm = new FormGroup({ - name: new FormControl(''), - email: new FormControl(''), - mobile_number: new FormControl(''), - password: new FormControl(''), - password_confirmation: new FormControl(''), - city: new FormControl(''), + name: new FormControl("", { validators: [Validators.required] }), + email: new FormControl("", { validators: [Validators.required, Validators.email] }), + mobile_number: new FormControl("", { validators: [Validators.required] }), + password: new FormControl("", { validators: [Validators.required] }), + password_confirmation: new FormControl("", { validators: [Validators.required] }), + city: new FormControl("", { validators: [Validators.required] }), }); registerUser() { - this.authService.register(this.registerForm.value as RegisterUserRequest) - .subscribe({ - next: () => console.log('success'), - error: (error) => { - const errors: Record = error?.error?.errors || {}; - const errorMessages :string[] = Object.values(errors).flat(); - this.errors.set(errorMessages) ; - } - }); + // validation errors if user submit early + if (this.registerForm.invalid) { + this.registerForm.markAllAsTouched(); + return; + } + + this.authService.register(this.registerForm.value as RegisterUserRequest).subscribe({ + next: () => console.log("success"), + error: (error) => { + const errors: Record = error?.error?.errors || {}; + const errorMessages: string[] = Object.values(errors).flat(); + this.errors.set(errorMessages); + }, + }); } - - } diff --git a/src/app/shared/components/error/error.ts b/src/app/shared/components/error/error.ts new file mode 100644 index 0000000..c447a09 --- /dev/null +++ b/src/app/shared/components/error/error.ts @@ -0,0 +1,47 @@ +import { Component, Input } from "@angular/core"; +import { AbstractControl } from "@angular/forms"; +import { UpperCaseFirstPipe } from "../../pipes/upper-case-first-pipe"; + +@Component({ + selector: "app-error", + imports: [UpperCaseFirstPipe], + template: ` + @if (this.control && this.control.touched) { + @for (error of getErrorMessages(); track error) { +

{{ error | upperCaseFirst }}

+ } + } + `, +}) +export class Error { + @Input() control!: AbstractControl | null; + @Input() fieldName = "This field"; + + getErrorMessages() { + const messages: string[] = []; + + if (this.control && this.control.errors) { + const errors = this.control.errors; + + if (errors["required"]) { + messages.push(`${this.fieldName} is required.`); + } + if (errors["email"]) { + messages.push(`Please enter a valid email address.`); + } + if (errors["minlength"]) { + messages.push( + `${this.fieldName} must be at least ${errors["minlength"].requiredLength} characters.`, + ); + } + if (errors["pattern"]) { + messages.push(`${this.fieldName} is formatted incorrectly.`); + } + if (errors["serverError"]) { + messages.push(errors["serverError"]); + } + } + + return messages; + } +} diff --git a/src/app/shared/pipes/upper-case-first-pipe.spec.ts b/src/app/shared/pipes/upper-case-first-pipe.spec.ts new file mode 100644 index 0000000..bff32d1 --- /dev/null +++ b/src/app/shared/pipes/upper-case-first-pipe.spec.ts @@ -0,0 +1,8 @@ +import { UpperCaseFirstPipe } from "./upper-case-first-pipe"; + +describe("UpperCaseFirstPipe", () => { + it("create an instance", () => { + const pipe = new UpperCaseFirstPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/shared/pipes/upper-case-first-pipe.ts b/src/app/shared/pipes/upper-case-first-pipe.ts new file mode 100644 index 0000000..48c1fdb --- /dev/null +++ b/src/app/shared/pipes/upper-case-first-pipe.ts @@ -0,0 +1,10 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +@Pipe({ + name: "upperCaseFirst", +}) +export class UpperCaseFirstPipe implements PipeTransform { + transform(value: string): unknown { + return value.charAt(0).toUpperCase() + value.slice(1); + } +} diff --git a/src/styles.css b/src/styles.css index bef2447..9123e1d 100644 --- a/src/styles.css +++ b/src/styles.css @@ -21,7 +21,7 @@ body { } .btn { - @apply rounded-full transition-all duration-200 font-medium ease-out flex justify-center active:translate-y-[1px]; + @apply rounded-full transition-all duration-200 font-medium ease-out flex justify-center active:translate-y-px disabled:opacity-50 disabled:cursor-not-allowed; } .btn-ghost {