feat(purchase-list): implement loading skeleton and enhance purchase list fetching logic
This commit is contained in:
@@ -62,6 +62,20 @@ export class CheckoutService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPurchases(tenantCode: string, status?: string): Promise<{ data: any[] }> {
|
||||||
|
let url = `${environment.url}tenants/${tenantCode}/compras`;
|
||||||
|
if (status) {
|
||||||
|
url += `?status=${status}`;
|
||||||
|
}
|
||||||
|
const response = await firstValueFrom(
|
||||||
|
this.http.get<{ data: any[] }>(url)
|
||||||
|
);
|
||||||
|
if (!response) {
|
||||||
|
throw new Error('Error al obtener las compras.');
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
async getPurchase(tenantCode: string, purchaseId: string | number): Promise<PurchaseStatusResponse> {
|
async getPurchase(tenantCode: string, purchaseId: string | number): Promise<PurchaseStatusResponse> {
|
||||||
const response = await firstValueFrom(
|
const response = await firstValueFrom(
|
||||||
this.http.get<{ data?: PurchaseStatusResponse } | PurchaseStatusResponse>(`${environment.url}tenants/${tenantCode}/compras/${purchaseId}`)
|
this.http.get<{ data?: PurchaseStatusResponse } | PurchaseStatusResponse>(`${environment.url}tenants/${tenantCode}/compras/${purchaseId}`)
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
<div class="purchase-list-container">
|
<div class="purchase-list-container">
|
||||||
<ng-container *ngFor="let purchase of purchases; let last = last">
|
<ng-container *ngIf="isLoading(); else contentTpl">
|
||||||
<app-purchase-list-item
|
<!-- Skeleton -->
|
||||||
[purchase]="purchase">
|
<div class="skeleton-item" *ngFor="let i of [1, 2, 3, 4]">
|
||||||
</app-purchase-list-item>
|
<div class="skeleton-info">
|
||||||
<div class="purchase-divider" *ngIf="!last"></div>
|
<div class="skeleton-id"></div>
|
||||||
|
<div class="skeleton-date"></div>
|
||||||
|
</div>
|
||||||
|
<div class="skeleton-action"></div>
|
||||||
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-template #contentTpl>
|
||||||
|
<ng-container *ngIf="purchases().length > 0; else emptyTpl">
|
||||||
|
<ng-container *ngFor="let purchase of purchases(); let last = last">
|
||||||
|
<app-purchase-list-item
|
||||||
|
[purchase]="purchase">
|
||||||
|
</app-purchase-list-item>
|
||||||
|
<div class="purchase-divider" *ngIf="!last"></div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #emptyTpl>
|
||||||
|
<div class="empty-state">
|
||||||
|
Aún no hay compras realizadas
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,3 +9,65 @@
|
|||||||
background-color: #DDDDDD;
|
background-color: #DDDDDD;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 2rem 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skeleton */
|
||||||
|
.skeleton-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-bottom: 1px solid #DDDDDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-id {
|
||||||
|
width: 100px;
|
||||||
|
height: 1rem;
|
||||||
|
background-color: #EEEEEE;
|
||||||
|
border-radius: 4px;
|
||||||
|
animation: pulse 1.5s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-date {
|
||||||
|
width: 150px;
|
||||||
|
height: 0.8rem;
|
||||||
|
background-color: #EEEEEE;
|
||||||
|
border-radius: 4px;
|
||||||
|
animation: pulse 1.5s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-action {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #EEEEEE;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 1.5s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
background-color: #EEEEEE;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-color: #EEEEEE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit, inject, signal } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { PurchaseListItem } from '../purchase-list-item/purchase-list-item';
|
import { PurchaseListItem } from '../purchase-list-item/purchase-list-item';
|
||||||
|
import { CheckoutService } from '../../../../../../core/services/checkout.service';
|
||||||
|
import { ToastService } from '../../../../../../core/services/toast.service';
|
||||||
|
import { TenantService } from '../../../../../../core/services/tenant.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-purchase-list',
|
selector: 'app-purchase-list',
|
||||||
@@ -9,11 +12,28 @@ import { PurchaseListItem } from '../purchase-list-item/purchase-list-item';
|
|||||||
templateUrl: './purchase-list.html',
|
templateUrl: './purchase-list.html',
|
||||||
styleUrl: './purchase-list.scss',
|
styleUrl: './purchase-list.scss',
|
||||||
})
|
})
|
||||||
export class PurchaseList {
|
export class PurchaseList implements OnInit {
|
||||||
purchases = [
|
private readonly checkoutService = inject(CheckoutService);
|
||||||
{ id: '#A00028', date: '08/06/2026' },
|
private readonly toastService = inject(ToastService);
|
||||||
{ id: '#A00013', date: '15/04/2026' },
|
private readonly tenantService = inject(TenantService);
|
||||||
{ id: '#A00013', date: '15/04/2026' },
|
|
||||||
{ id: '#A00013', date: '15/04/2026' }
|
purchases = signal<{ id: string; date: string }[]>([]);
|
||||||
];
|
isLoading = signal<boolean>(true);
|
||||||
|
|
||||||
|
async ngOnInit(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const tenantCode = this.tenantService.tenant()?.codigo || '';
|
||||||
|
|
||||||
|
const response = await this.checkoutService.getPurchases(tenantCode, 'paid');
|
||||||
|
const mappedPurchases = response.data.map((purchase: any) => ({
|
||||||
|
id: `#${purchase.id.toString().padStart(5, '0')}`,
|
||||||
|
date: '08/06/2026' // Fecha hardcodeada temporalmente
|
||||||
|
}));
|
||||||
|
this.purchases.set(mappedPurchases);
|
||||||
|
} catch (error) {
|
||||||
|
this.toastService.danger('Hubo un error al cargar las compras');
|
||||||
|
} finally {
|
||||||
|
this.isLoading.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user