feat(stepper): implement reusable stepper component with navigation and validation

This commit is contained in:
2026-07-03 10:10:53 -03:00
parent 625e2fea6c
commit 510c72624b
9 changed files with 464 additions and 1 deletions

View File

@@ -336,6 +336,94 @@
<hr class="section-divider" />
<div class="stepper-showcase">
<h2>Form Stepper</h2>
<p class="text-muted mb-4">
Stepper vertical reutilizable. Cada paso maneja sus propios botones de navegacion. No se puede avanzar si el paso no es valido.
</p>
<app-stepper #demoStepper>
<!-- Paso 1: Siempre valido -->
<app-step label="Informacion Personal" [isValid]="true">
<div class="row g-3">
<div class="col-md-6 input-field">
<label for="stepper-name">Nombre</label>
<app-input id="stepper-name" placeholder="Juan Perez" [(value)]="user" />
</div>
<div class="col-md-6 input-field">
<label for="stepper-email">Email</label>
<app-input id="stepper-email" type="email" placeholder="mail@empresa.com" [(value)]="email" />
</div>
</div>
<div class="d-flex justify-content-end mt-4">
<app-button (click)="demoStepper.next()">
Siguiente <i class="fa-solid fa-arrow-right ms-1"></i>
</app-button>
</div>
</app-step>
<!-- Paso 2: Valido solo si testStep2Valid es true -->
<app-step label="Configuracion de Cuenta" [isValid]="testStep2Valid">
<div class="row g-3">
<div class="col-md-6 input-field">
<label for="stepper-password">Contraseña</label>
<app-input id="stepper-password" type="password-toggle" placeholder="********" [(value)]="password" />
</div>
<div class="col-md-6 input-field">
<label for="stepper-amount">Presupuesto mensual</label>
<app-input id="stepper-amount" type="currency" placeholder="0" [(value)]="amount" />
</div>
</div>
<div class="stepper-validity-control mt-3 d-flex align-items-center gap-3">
<span class="text-muted small">
Simular validez del paso:
</span>
<app-button
[variant]="testStep2Valid ? 'secondary' : 'primary'"
(click)="testStep2Valid = !testStep2Valid"
>
@if (testStep2Valid) {
<i class="fa-solid fa-check me-1"></i> Valido
} @else {
<i class="fa-solid fa-xmark me-1"></i> Invalido — Siguiente bloqueado
}
</app-button>
</div>
<div class="d-flex justify-content-between mt-4">
<app-button variant="secondary" (click)="demoStepper.previous()">
<i class="fa-solid fa-arrow-left me-1"></i> Volver
</app-button>
<app-button (click)="demoStepper.next()" [disabled]="!testStep2Valid">
Siguiente <i class="fa-solid fa-arrow-right ms-1"></i>
</app-button>
</div>
</app-step>
<!-- Paso 3: Revision final, siempre valido -->
<app-step label="Revision y Confirmacion" [isValid]="true">
<div class="p-3 rounded bg-light">
<p class="mb-1"><strong>Nombre:</strong> {{ user }}</p>
<p class="mb-1"><strong>Email:</strong> {{ email }}</p>
<p class="mb-0"><strong>Presupuesto:</strong> {{ amount }}</p>
</div>
<div class="d-flex justify-content-between mt-4">
<app-button variant="secondary" (click)="demoStepper.previous()">
<i class="fa-solid fa-arrow-left me-1"></i> Volver
</app-button>
<app-button (click)="triggerToast('success')">
<i class="fa-solid fa-check me-1"></i> Confirmar
</app-button>
</div>
</app-step>
</app-stepper>
</div>
<hr class="section-divider" />
<div class="cart-showcase">
<div class="cart-showcase__header">
<div>

View File

@@ -13,6 +13,8 @@ import { StoreSectionComponent } from '../../../../shared/components/store-secti
import { ModalService } from '../../../../core/services/modal.service';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import { StepperComponent } from '../../../../shared/components/stepper/stepper.component';
import { StepComponent } from '../../../../shared/components/stepper/step.component';
@Component({
selector: 'app-reutilizables-test-page',
@@ -24,7 +26,9 @@ import { ToastService } from '../../../../core/services/toast.service';
ProductCardComponent,
StoreSectionComponent,
IconButtonComponent,
CartIconComponent
CartIconComponent,
StepperComponent,
StepComponent
],
templateUrl: './reutilizables-test-page.component.html',
styleUrl: './reutilizables-test-page.component.scss'
@@ -33,6 +37,9 @@ export class ReutilizablesTestPageComponent {
private readonly tenantService = inject(TenantService);
private readonly toastService = inject(ToastService);
private readonly modalService = inject(ModalService);
protected testStep1Valid = true;
protected testStep2Valid = false;
protected readonly tenant = this.tenantService.tenant;
protected textValue = 'Auriculares';
protected numberValue = '24';