From 57f58c92be105a7d6fbceacc7f654726423f68c1 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 2 Jul 2026 15:57:54 -0300 Subject: [PATCH] feat(register): add register page with routing and form implementation --- src/app/app.routes.spec.ts | 29 +++++++++++++++ .../login-page/login-page.component.html | 9 +++-- .../login-page/login-page.component.scss | 1 - .../pages/login-page/login-page.component.ts | 11 ++++-- .../register-page.component.html | 35 +++++++++++++++++++ .../register-page.component.scss | 15 ++++++++ .../register-page/register-page.component.ts | 20 +++++++++++ src/app/features/store/store.routes.ts | 11 ++++++ .../components/button/button.component.scss | 22 +++++++++++- .../button/button.component.spec.ts | 19 ++++++++++ .../components/button/button.component.ts | 2 ++ 11 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 src/app/features/store/pages/register-page/register-page.component.html create mode 100644 src/app/features/store/pages/register-page/register-page.component.scss create mode 100644 src/app/features/store/pages/register-page/register-page.component.ts create mode 100644 src/app/shared/components/button/button.component.spec.ts diff --git a/src/app/app.routes.spec.ts b/src/app/app.routes.spec.ts index 8e29615..f749829 100644 --- a/src/app/app.routes.spec.ts +++ b/src/app/app.routes.spec.ts @@ -106,6 +106,35 @@ describe('app routes', () => { expect(compiled.textContent).toContain('Componentes reutilizables'); }); + it('loads the login page at /login and shows the create account CTA', async () => { + const { fixture, router } = await renderAppAt('/login'); + const compiled = fixture.nativeElement as HTMLElement; + + expect(router.url).toBe('/login'); + expect(compiled.querySelector('app-login-page')).not.toBeNull(); + expect(compiled.textContent).toContain('Iniciar sesión'); + expect(compiled.textContent).toContain('Crear cuenta'); + }); + + it('loads the register page at /register and renders the shared auth fields', async () => { + const { fixture, router } = await renderAppAt('/register'); + const compiled = fixture.nativeElement as HTMLElement; + const placeholders = Array.from(compiled.querySelectorAll('input')).map((input) => + input.getAttribute('placeholder') + ); + + expect(router.url).toBe('/register'); + expect(compiled.querySelector('app-register-page')).not.toBeNull(); + expect(compiled.textContent).toContain('CREAR CUENTA'); + expect(compiled.textContent).toContain('Volver'); + expect(placeholders).toEqual([ + 'Nombre y Apellido', + 'Email', + 'Contraseña', + 'Repetir Contraseña' + ]); + }); + it('renders the tenant not found screen for any route when the tenant is missing', async () => { const { fixture } = await renderAppAt( '/componentes-test/reutilizables', diff --git a/src/app/features/store/pages/login-page/login-page.component.html b/src/app/features/store/pages/login-page/login-page.component.html index 04c76ae..7fb477b 100644 --- a/src/app/features/store/pages/login-page/login-page.component.html +++ b/src/app/features/store/pages/login-page/login-page.component.html @@ -20,9 +20,14 @@
Ingresar - +
diff --git a/src/app/features/store/pages/login-page/login-page.component.scss b/src/app/features/store/pages/login-page/login-page.component.scss index b8b7016..d3457aa 100644 --- a/src/app/features/store/pages/login-page/login-page.component.scss +++ b/src/app/features/store/pages/login-page/login-page.component.scss @@ -18,7 +18,6 @@ .login-page__create-account { min-height: 40px; - font-weight: 700; } .login-page__divider { diff --git a/src/app/features/store/pages/login-page/login-page.component.ts b/src/app/features/store/pages/login-page/login-page.component.ts index a87463a..3beb38b 100644 --- a/src/app/features/store/pages/login-page/login-page.component.ts +++ b/src/app/features/store/pages/login-page/login-page.component.ts @@ -1,4 +1,5 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; import { ButtonComponent } from '../../../../shared/components/button/button.component'; import { InputComponent } from '../../../../shared/components/input/input.component'; @@ -10,4 +11,10 @@ import { InputComponent } from '../../../../shared/components/input/input.compon styleUrl: './login-page.component.scss', changeDetection: ChangeDetectionStrategy.OnPush }) -export class LoginPageComponent {} +export class LoginPageComponent { + private readonly router = inject(Router); + + goToRegister(): void { + void this.router.navigate(['/register']); + } +} diff --git a/src/app/features/store/pages/register-page/register-page.component.html b/src/app/features/store/pages/register-page/register-page.component.html new file mode 100644 index 0000000..52926f0 --- /dev/null +++ b/src/app/features/store/pages/register-page/register-page.component.html @@ -0,0 +1,35 @@ +
+

CREAR CUENTA

+
+ +
+
+ + + + + + + + + + + +
+ +
+ Crear Cuenta + + Volver + +
+
diff --git a/src/app/features/store/pages/register-page/register-page.component.scss b/src/app/features/store/pages/register-page/register-page.component.scss new file mode 100644 index 0000000..124bea4 --- /dev/null +++ b/src/app/features/store/pages/register-page/register-page.component.scss @@ -0,0 +1,15 @@ +:host { + display: block; +} + +.register-page__header { + margin-bottom: 1.5rem; +} + +.register-page__form { + width: 100%; +} + +.register-page__back-action { + min-height: 40px; +} diff --git a/src/app/features/store/pages/register-page/register-page.component.ts b/src/app/features/store/pages/register-page/register-page.component.ts new file mode 100644 index 0000000..2f8ad68 --- /dev/null +++ b/src/app/features/store/pages/register-page/register-page.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; + +import { ButtonComponent } from '../../../../shared/components/button/button.component'; +import { InputComponent } from '../../../../shared/components/input/input.component'; + +@Component({ + selector: 'app-register-page', + imports: [InputComponent, ButtonComponent], + templateUrl: './register-page.component.html', + styleUrl: './register-page.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class RegisterPageComponent { + private readonly router = inject(Router); + + goToLogin(): void { + void this.router.navigate(['/login']); + } +} diff --git a/src/app/features/store/store.routes.ts b/src/app/features/store/store.routes.ts index f3ee026..ab565fe 100644 --- a/src/app/features/store/store.routes.ts +++ b/src/app/features/store/store.routes.ts @@ -3,6 +3,7 @@ import { Routes } from '@angular/router'; import { AuthLayoutComponent } from '../../core/layout/auth-layout/auth-layout.component'; import { StoreLayoutComponent } from '../../core/layout/store-layout/store-layout.component'; import { LoginPageComponent } from './pages/login-page/login-page.component'; +import { RegisterPageComponent } from './pages/register-page/register-page.component'; import { StoreHomePageComponent } from './pages/store-home-page/store-home-page.component'; export const routes: Routes = [ @@ -24,6 +25,16 @@ export const routes: Routes = [ } ] }, + { + path: 'register', + component: AuthLayoutComponent, + children: [ + { + path: '', + component: RegisterPageComponent + } + ] + }, { path: 'producto/:id', loadComponent: () => diff --git a/src/app/shared/components/button/button.component.scss b/src/app/shared/components/button/button.component.scss index 4290b08..8de9e72 100644 --- a/src/app/shared/components/button/button.component.scss +++ b/src/app/shared/components/button/button.component.scss @@ -30,7 +30,8 @@ .btn-outline-primary, .btn-outline-neutral, -.btn-outline-danger { +.btn-outline-danger, +.btn-borderless { --bs-btn-bg: transparent; --bs-btn-hover-color: #fff; --bs-btn-active-color: #fff; @@ -107,3 +108,22 @@ --bs-btn-disabled-color: color-mix(in srgb, transparent 35%, var(--tenant-danger)); --bs-btn-disabled-border-color: color-mix(in srgb, transparent 35%, var(--tenant-danger)); } + +.btn-borderless { + min-width: auto; + padding-inline: 0; + border: 0; + color: var(--tenant-primary); + font-weight: 700; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: color-mix(in srgb, black 18%, var(--tenant-primary)); + --bs-btn-hover-bg: transparent; + --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: color-mix(in srgb, black 24%, var(--tenant-primary)); + --bs-btn-active-bg: transparent; + --bs-btn-active-border-color: transparent; + --bs-btn-disabled-color: color-mix(in srgb, transparent 35%, var(--tenant-primary)); + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: transparent; + --bs-btn-disabled-opacity: 1; +} diff --git a/src/app/shared/components/button/button.component.spec.ts b/src/app/shared/components/button/button.component.spec.ts new file mode 100644 index 0000000..00c9608 --- /dev/null +++ b/src/app/shared/components/button/button.component.spec.ts @@ -0,0 +1,19 @@ +import { TestBed } from '@angular/core/testing'; + +import { ButtonComponent } from './button.component'; + +describe('ButtonComponent', () => { + it('applies the borderless variant class', async () => { + await TestBed.configureTestingModule({ + imports: [ButtonComponent] + }).compileComponents(); + + const fixture = TestBed.createComponent(ButtonComponent); + fixture.componentRef.setInput('variant', 'borderless'); + fixture.detectChanges(); + + const button = fixture.nativeElement.querySelector('button') as HTMLButtonElement; + + expect(button.classList.contains('btn-borderless')).toBe(true); + }); +}); diff --git a/src/app/shared/components/button/button.component.ts b/src/app/shared/components/button/button.component.ts index fbce322..c202cc6 100644 --- a/src/app/shared/components/button/button.component.ts +++ b/src/app/shared/components/button/button.component.ts @@ -5,6 +5,7 @@ export type ButtonVariant = | 'primary' | 'secondary' | 'neutral-outline' + | 'borderless' | 'danger' | 'danger-secondary' | 'cancel'; @@ -31,6 +32,7 @@ export class ButtonComponent { primary: 'btn-primary', secondary: 'btn-outline-primary', 'neutral-outline': 'btn-outline-neutral', + borderless: 'btn-borderless', danger: 'btn-danger', 'danger-secondary': 'btn-outline-danger', cancel: 'btn-secondary'