exercises

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

product.component.ts (3225B)


      1 import { CommonModule } from '@angular/common';
      2 import { Component, computed, ElementRef, inject, input, signal, viewChild } from '@angular/core';
      3 import { Router, RouterLink } from '@angular/router';
      4 import { CartService } from '../services/cart.service';
      5 
      6 const morphAndFadeKeyframes = (sx: string, sy: string) => {
      7   const rect = window.cartBtnPosition();
      8   const dx = `${rect.x}px`;
      9   const dy = `${rect.y}px`;
     10   console.log({ sx, sy, dx, dy });
     11   return [
     12     // 0%
     13     {
     14       opacity: 0,
     15       transform: `translate(${sx}, ${sy}) scale(.75)`,
     16       offset: 0.0,
     17     },
     18     // 8%
     19     {
     20       opacity: 0.5,
     21       transform: `translate(${sx}, ${sy}) scale(1)`,
     22       offset: 0.08,
     23     },
     24     // 20%
     25     {
     26       opacity: 1,
     27       transform: `translate(${sx}, ${sy}) scale(1.5)`,
     28       offset: 0.2,
     29     },
     30     // 80% (Movement to destination, maintaining scale and opacity)
     31     {
     32       opacity: 1,
     33       transform: `translate(${dx}, ${dy}) scale(1.25)`,
     34       offset: 0.8,
     35     },
     36     // 90%
     37     {
     38       opacity: 0.75,
     39       transform: `translate(${dx}, ${dy}) scale(1)`,
     40       offset: 0.8,
     41     },
     42     {
     43       opacity: 0.5,
     44       transform: `translate(${dx}, ${dy}) scale(.5)`,
     45       offset: 0.9,
     46     },
     47     // 100%
     48     {
     49       opacity: 0,
     50       transform: `translate(${dx}, ${dy}) scale(.1)`,
     51       offset: 1.0,
     52     },
     53   ];
     54 };
     55 
     56 @Component({
     57   selector: 'div.product',
     58   templateUrl: './product.component.html',
     59   styleUrls: ['./product.component.scss'],
     60   standalone: true,
     61   imports: [CommonModule, RouterLink],
     62 })
     63 export class ProductComponent {
     64   private cartService = inject(CartService);
     65   readonly product = input<ProductCard>({} as ProductCard);
     66   readonly addingToCart = signal<boolean>(false);
     67   private morphDiv = viewChild<ElementRef<HTMLDivElement>>('morphDiv');
     68   private div = computed(() => this.morphDiv()?.nativeElement as HTMLDivElement);
     69 
     70   ratingStars = computed(() => {
     71     const rating = this.product().average_rating || 0;
     72     return rating === 0 ? '' : Number.isInteger(rating) ? '-fill' : '-half';
     73   });
     74 
     75   get discount(): number {
     76     const initial = parseFloat(this.product().initial_price || '0');
     77     const discount = parseFloat(this.product().discount || '0');
     78     return initial > 0 ? Math.round((discount / initial) * 100) : 0;
     79   }
     80 
     81   addToCart($event: Event): void {
     82     $event.preventDefault();
     83     $event.stopPropagation();
     84     const btn = $event.target as HTMLButtonElement;
     85 
     86     this.addingToCart.set(true);
     87     const options = {
     88       duration: 1000, // Example duration in milliseconds (adjust as needed)
     89       iterations: 1,
     90       fill: 'forwards', // Keeps the final state (opacity: 0, scaled down, at destination)
     91       easing: 'cubic-bezier(0.42, 0, 0.58, 1)', // Applies a general easing across the duration
     92     } as KeyframeAnimationOptions;
     93 
     94     const { x, y, width, height } = btn.getBoundingClientRect();
     95     const keyframes = morphAndFadeKeyframes(`${x + 10}px`, `${y - 3}px`);
     96     const div = document.body.appendChild(this.div().cloneNode(true) as HTMLDivElement);
     97     const animation = div.animate(keyframes, options);
     98     animation.onfinish = () => {
     99       this.cartService.addToCart(this.product());
    100       this.addingToCart.set(false);
    101       div.remove();
    102     };
    103   }
    104 }