From 870de3ca6e95024884d55b024860625dd0acc439 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 24 Aug 2026 09:16:52 -0300 Subject: [PATCH] feat(purchase-list): implement pagination for in-review and paid purchases --- src/app/core/services/checkout.service.ts | 22 +++-- .../purchase-list/purchase-list.html | 94 ++++++++++++++----- .../purchase-list/purchase-list.scss | 17 ++++ .../components/purchase-list/purchase-list.ts | 70 +++++++++++--- 4 files changed, 158 insertions(+), 45 deletions(-) diff --git a/src/app/core/services/checkout.service.ts b/src/app/core/services/checkout.service.ts index 5001900..df1a4e2 100644 --- a/src/app/core/services/checkout.service.ts +++ b/src/app/core/services/checkout.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@angular/core'; import { firstValueFrom } from 'rxjs'; import { environment } from '../../../environments/environment'; +import { ApiPaginatedResponse } from './api-paginated-response.interface'; +import { ApiPaginationQueryParams } from './api-pagination-query-params.interface'; import { BaseApiService } from './base-api.service'; export interface UpdatePurchaseCustomerPayload { @@ -226,12 +228,20 @@ export class CheckoutService extends BaseApiService { async getPurchases( tenantCode: string, status?: string, - ): Promise<{ data: PurchaseSummaryResponse[] }> { - let url = `${environment.url}tenants/${tenantCode}/compras`; - if (status) { - url += `?status=${status}`; - } - const response = await firstValueFrom(this.http.get<{ data: PurchaseSummaryResponse[] }>(url)); + pagination: ApiPaginationQueryParams = {}, + ): Promise> { + const params: Record = {}; + + if (status) params['status'] = status; + if (pagination.page) params['page'] = pagination.page; + if (pagination.per_page) params['per_page'] = pagination.per_page; + + const response = await firstValueFrom( + this.http.get>( + `${environment.url}tenants/${tenantCode}/compras`, + { params }, + ), + ); if (!response) { throw new Error('Error al obtener las compras.'); } diff --git a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.html b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.html index a592759..9bcc6ce 100644 --- a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.html +++ b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.html @@ -1,29 +1,71 @@ -
- - -
-
-
-
-
-
-
-
+
+
+

En revisión

- - - - - -
-
-
-
+ @if (isLoadingInReview()) { + + } @else { + @if (inReviewPurchases().length > 0) { + @for (purchase of inReviewPurchases(); track purchase.id; let last = $last) { + + @if (!last) { +
+ } + } + } @else { +
No hay compras en revisión
+ } - -
- Aún no hay compras realizadas + @if (inReviewPagination(); as pagination) { + + } + } +
+ +
+ + + @if (isLoadingPaid()) { + + } @else { + @if (paidPurchases().length > 0) { + @for (purchase of paidPurchases(); track purchase.id; let last = $last) { + + @if (!last) { +
+ } + } + } @else { +
Aún no hay compras confirmadas
+ } + + @if (paidPagination(); as pagination) { + + } + } +
+ + + @for (i of [1, 2, 3, 4]; track i) { +
+
+
+
- -
+
+
+ } + +
diff --git a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.scss b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.scss index ddc081b..ea7a07c 100644 --- a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.scss +++ b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.scss @@ -1,9 +1,26 @@ .purchase-list-container { display: flex; flex-direction: column; + gap: 2rem; width: 100%; } +.purchase-section { + display: flex; + flex-direction: column; +} + +.purchase-section__title { + margin: 0 0 0.75rem; + font-size: 1.125rem; + font-weight: 600; +} + +.purchase-section__paginator { + align-self: center; + margin-top: 1.5rem; +} + .purchase-divider { height: 1px; background-color: #DDDDDD; diff --git a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.ts b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.ts index 776a6cb..388a6ee 100644 --- a/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.ts +++ b/src/app/features/store/pages/account-page/components/purchase-list/purchase-list.ts @@ -4,6 +4,8 @@ import { PurchaseListItem } from '../purchase-list-item/purchase-list-item'; import { CheckoutService, PurchaseSummaryResponse } from '../../../../../../core/services/checkout.service'; import { ToastService } from '../../../../../../core/services/toast.service'; import { TenantService } from '../../../../../../core/services/tenant.service'; +import { ApiPaginationMeta } from '../../../../../../core/services/api-paginated-response.interface'; +import { PaginatorComponent } from '../../../../../../shared/components/paginator/paginator.component'; type PurchaseListViewModel = { id: number; @@ -13,7 +15,7 @@ type PurchaseListViewModel = { @Component({ selector: 'app-purchase-list', standalone: true, - imports: [CommonModule, PurchaseListItem], + imports: [CommonModule, PurchaseListItem, PaginatorComponent], templateUrl: './purchase-list.html', styleUrl: './purchase-list.scss', }) @@ -22,28 +24,70 @@ export class PurchaseList implements OnInit { private readonly toastService = inject(ToastService); private readonly tenantService = inject(TenantService); - purchases = signal([]); - isLoading = signal(true); + protected readonly inReviewPurchases = signal([]); + protected readonly paidPurchases = signal([]); + protected readonly inReviewPagination = signal(null); + protected readonly paidPagination = signal(null); + protected readonly isLoadingInReview = signal(true); + protected readonly isLoadingPaid = signal(true); async ngOnInit(): Promise { + await Promise.all([this.loadInReviewPurchases(), this.loadPaidPurchases()]); + } + + protected async onInReviewPageChange(page: number): Promise { + await this.loadInReviewPurchases(page); + } + + protected async onPaidPageChange(page: number): Promise { + await this.loadPaidPurchases(page); + } + + private async loadInReviewPurchases(page = 1): Promise { + this.isLoadingInReview.set(true); + try { - const tenantCode = this.tenantService.tenant()?.codigo || ''; - const response = await this.checkoutService .withCustomLoading() - .getPurchases(tenantCode, 'paid'); - const mappedPurchases = response.data.map((purchase: PurchaseSummaryResponse) => ({ - id: purchase.id, - date: this.formatDate(purchase.created_at), - })); - this.purchases.set(mappedPurchases); + .getPurchases(this.tenantCode(), 'in_review', { page }); + + this.inReviewPurchases.set(this.mapPurchases(response.data)); + this.inReviewPagination.set(response.meta); } catch (error) { - this.toastService.danger('Hubo un error al cargar las compras'); + this.toastService.danger('Hubo un error al cargar las compras en revisión'); } finally { - this.isLoading.set(false); + this.isLoadingInReview.set(false); } } + private async loadPaidPurchases(page = 1): Promise { + this.isLoadingPaid.set(true); + + try { + const response = await this.checkoutService + .withCustomLoading() + .getPurchases(this.tenantCode(), 'paid', { page }); + + this.paidPurchases.set(this.mapPurchases(response.data)); + this.paidPagination.set(response.meta); + } catch (error) { + this.toastService.danger('Hubo un error al cargar las compras confirmadas'); + } finally { + this.isLoadingPaid.set(false); + } + } + + private tenantCode(): string { + return this.tenantService.tenant()?.codigo || ''; + } + + private mapPurchases(purchases: PurchaseSummaryResponse[]): PurchaseListViewModel[] { + return purchases.map((purchase) => ({ + id: purchase.id, + date: this.formatDate(purchase.created_at), + })); + } + private formatDate(value: string | null): string { if (!value) { return '-';