feat: implement direct purchase functionality and enhance product buy events

This commit is contained in:
2026-07-27 16:25:38 -03:00
parent 902f65d8d0
commit f063bac527
9 changed files with 140 additions and 12 deletions

View File

@@ -12,6 +12,8 @@ import { catchError, distinctUntilChanged, map, of, switchMap, tap } from 'rxjs'
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CartService } from '../../../../core/services/cart/cart.service';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { CheckoutService } from '../../../../core/services/checkout.service';
import {
CatalogFeaturedItem,
CatalogFeaturedItems,
@@ -24,6 +26,7 @@ import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import {
ProductListCartEvent,
ProductListBuyEvent,
ProductListComponent,
ProductListItem,
} from '../../../../shared/components/product-list/product-list.component';
@@ -43,7 +46,9 @@ interface SearchRouteState {
export class SearchPageComponent {
private readonly minSearchLength = 3;
private readonly cartService = inject(CartService);
private readonly authService = inject(AuthService);
private readonly catalogService = inject(CatalogService);
private readonly checkoutService = inject(CheckoutService);
private readonly destroyRef = inject(DestroyRef);
private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router);
@@ -54,6 +59,7 @@ export class SearchPageComponent {
protected readonly results = signal<ApiPaginatedResponse<CatalogFeaturedItem[]> | null>(null);
protected readonly loading = signal(false);
protected readonly error = signal<string | null>(null);
protected readonly creatingDirectPurchase = signal(false);
protected readonly productLayout = computed<CatalogProductLayout>(
() => this.tenantService.tenant()?.search_product_layout ?? 'column_with_image',
@@ -131,8 +137,45 @@ export class SearchPageComponent {
});
}
protected onBuyProduct(product: ProductListItem): void {
void this.router.navigate(['/producto', product.id]);
protected async onBuyProduct(event: ProductListBuyEvent): Promise<void> {
if (!event.directPurchase) {
await this.router.navigate(['/producto', event.product.id]);
return;
}
if (this.creatingDirectPurchase()) {
return;
}
if (!this.authService.user()) {
await this.router.navigate(['/login'], {
queryParams: { returnUrl: `/producto/${event.product.id}` },
});
return;
}
const tenant = this.tenantService.tenant();
if (!tenant) {
this.toastService.danger('No se pudo identificar la tienda.');
return;
}
this.creatingDirectPurchase.set(true);
try {
const purchase = await this.checkoutService.startCheckout(tenant.codigo, {
direct_item: {
catalog_item_id: event.product.id,
variant_id: event.variant ?? null,
cantidad: event.quantity,
},
});
await this.router.navigate(['/checkout'], { queryParams: { purchase: purchase.id } });
} catch (error) {
console.error('Failed to create direct purchase:', error);
this.toastService.danger('No se pudo iniciar la compra directa.');
} finally {
this.creatingDirectPurchase.set(false);
}
}
protected onAddToCart(event: ProductListCartEvent): void {

View File

@@ -12,13 +12,16 @@ import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { CartService } from '../../../../core/services/cart/cart.service';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { CatalogFeaturedGroup } from '../../../../core/services/catalog/catalog.interface';
import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import { CheckoutService } from '../../../../core/services/checkout.service';
import {
ProductListComponent,
ProductListCartEvent,
ProductListBuyEvent,
ProductListItem,
} from '../../../../shared/components/product-list/product-list.component';
import { HeroBannerComponent } from '../../../../shared/components/hero-banner/hero-banner.component';
@@ -43,7 +46,9 @@ import {
})
export class StoreHomePageComponent implements OnInit, OnDestroy {
private readonly cartService = inject(CartService);
private readonly authService = inject(AuthService);
private readonly catalogService = inject(CatalogService);
private readonly checkoutService = inject(CheckoutService);
private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router);
private readonly tenantService = inject(TenantService);
@@ -55,6 +60,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
protected readonly loadingGroupIds = signal<ReadonlySet<number>>(new Set());
protected readonly error = signal<string | null>(null);
protected readonly mainCarouselReady = signal(false);
protected readonly creatingDirectPurchase = signal(false);
protected readonly hasMainCarouselImages = computed(
() => (this.tenant()?.main_carousel_images?.length ?? 0) > 0,
);
@@ -118,8 +124,45 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
this.groupRequestSubscriptions.set(groupId, subscription);
}
protected onBuyProduct(product: ProductListItem): void {
this.router.navigate(['/producto', product.id]);
protected async onBuyProduct(event: ProductListBuyEvent): Promise<void> {
if (!event.directPurchase) {
await this.router.navigate(['/producto', event.product.id]);
return;
}
if (this.creatingDirectPurchase()) {
return;
}
if (!this.authService.user()) {
await this.router.navigate(['/login'], {
queryParams: { returnUrl: `/producto/${event.product.id}` },
});
return;
}
const tenant = this.tenantService.tenant();
if (!tenant) {
this.toastService.danger('No se pudo identificar la tienda.');
return;
}
this.creatingDirectPurchase.set(true);
try {
const purchase = await this.checkoutService.startCheckout(tenant.codigo, {
direct_item: {
catalog_item_id: event.product.id,
variant_id: event.variant ?? null,
cantidad: event.quantity,
},
});
await this.router.navigate(['/checkout'], { queryParams: { purchase: purchase.id } });
} catch (error) {
console.error('Failed to create direct purchase:', error);
this.toastService.danger('No se pudo iniciar la compra directa.');
} finally {
this.creatingDirectPurchase.set(false);
}
}
protected onAddToCart(event: ProductListCartEvent): void {