All files / app/carousel-banner carousel-banner.component.ts

100% Statements 60/60
100% Branches 50/50
100% Functions 17/17
100% Lines 56/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 1761x 1x 1x   1x 1x   1x                                                                       1x 16x 16x 16x         16x 16x     16x   16x     10x 9x 9x           3x   2x       9x   8x 7x 7x 7x 7x   1x       1x 1x 1x           9x   8x 7x 7x 6x 6x         1x           6x   6x                 7x 7x 10x     7x   7x 7x   7x                                   45x 31x   14x 13x 13x 7x     7x       38x       1x       2x 1x      
import { Component, OnInit, AfterViewInit, ViewChild, signal, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { NgFor } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { ApiService, SliderApiResponse, SliderPost, OfferTextApiResponse, OfferTextPost } from '../common/services/api.service';
import { NgbCarousel, NgbSlide } from '@ng-bootstrap/ng-bootstrap';
 
import { MatIcon } from '@angular/material/icon';
 
export interface HeroBanner {
  id?: number;
  title: string;
  subtitle: string;
  badges: string[];
  checklist: string[];
  ctaLabel: string;
  secondaryCtaLabel: string;
  heroImage: string;
  heroImage2: string; // New field
  label1: string; // New field
  label2: string; // New field
  link: string;
}
 
export interface OfferBanner {
  title: string;
  description: string;
  ctaLabel: string;
  link: string;
}
 
@Component({
  selector: 'app-m-banner',
  standalone: true,
  templateUrl: './carousel-banner.component.html',
  styleUrls: ['./carousel-banner.component.css'],
  imports: [
    NgbCarousel,
    NgbSlide,
    MatIcon,
    NgFor,
  ],
})
export class CarouselBannerComponent implements OnInit {
  private readonly apiService = inject(ApiService);
  private readonly platformId = inject(PLATFORM_ID);
  readonly isBrowser = isPlatformBrowser(this.platformId);
 
  @ViewChild('carousel') private carousel?: NgbCarousel;
 
  // Loading state
  readonly isLoading = signal<boolean>(true);
  readonly hasError = signal<boolean>(false);
 
  // Component-level state (defaults kept empty — data comes from API)
  readonly banners = signal<HeroBanner[]>([]);
 
  readonly offerBanner = signal<OfferBanner | null>(null);
 
  ngOnInit(): void {
    if (this.isBrowser) {
      this.loadSliderData();
      this.loadOfferTextData();
    }
  }
 
  // Called when a slide change occurs (e.g. user clicked next/prev)
  onSlide(event: any): void {
    if (!this.isBrowser) return;
    // ensure carousel restarts auto-cycling after manual navigation
    setTimeout(() => this.carousel?.cycle(), 100);
  }
 
  private loadSliderData(): void {
    this.apiService.getSlider().subscribe({
      next: (response: SliderApiResponse[]) => {
        if (response && response.length > 0) {
          const sliderData = response[0];
          const mappedBanners = this.mapSliderPostsToBanners(sliderData.posts);
          this.banners.set(mappedBanners);
          this.isLoading.set(false);
        } else {
          this.isLoading.set(false);
        }
      },
      error: (err) => {
        console.error('Slider API Error:', err);
        this.hasError.set(true);
        this.isLoading.set(false);
      }
    });
  }
 
  private loadOfferTextData(): void {
    this.apiService.getOfferText().subscribe({
      next: (response: OfferTextApiResponse[]) => {
        if (response && response.length > 0) {
          const offerData = response[0];
          if (offerData.posts && offerData.posts.length > 0) {
            const mappedOffer = this.mapOfferTextPostToBanner(offerData.posts[0]);
            this.offerBanner.set(mappedOffer);
          }
        }
      },
      error: (err) => {
        console.error('Offer Text API Error:', err);
      }
    });
  }
 
  private mapOfferTextPostToBanner(post: OfferTextPost): OfferBanner {
    const description = this.getWpText(post.description);
 
    return {
      title: this.getWpText(post.title, 'PNB Offers'),
      description: description,
      ctaLabel: post.card_data?.button_label || 'Explore Offers',
      link: post.card_data?.button_url || 'https://www.rupay.co.in/domestic-offers'
    };
  }
 
  private mapSliderPostsToBanners(posts: SliderPost[]): HeroBanner[] {
    return posts.map(post => {
      const checklist = this.getWpText(post.card_features)
        ? this.getWpText(post.card_features).split(',').map(feature => feature.trim())
        : [];
 
      const subtitle = this.getWpText(post.description);
 
      const excerpt = this.getWpText(post.excerpt);
      const badges = excerpt ? [excerpt] : [];
 
      return {
        id: post.id,
        title: this.getWpText(post.title, 'PNB Credit Card'),
        subtitle: subtitle,
        badges: badges,
        checklist: checklist,
        ctaLabel: post.card_data?.button_label || 'Apply Now',
        secondaryCtaLabel: post.card_data?.button_label || 'Learn More',
        heroImage: post.featured_image || 'assets/images/banner1.webp',
        heroImage2: post.featured_image2 || '', // Mapped from featured_image2
        label1: post.banner_label1_text_box || '', // Mapped from banner_label1_text_box
        label2: post.banner_label2_text_box || '', // Mapped from banner_label2_text_box
        link: post.card_data?.button_url || 'https://www.rupay.co.in/domestic-offers'
      };
    });
  }
 
  private getWpText(value: unknown, fallback = ''): string {
    if (typeof value === 'string') {
      return this.cleanText(value);
    }
    if (value && typeof value === 'object' && 'rendered' in value) {
      const rendered = (value as { rendered?: unknown }).rendered;
      if (typeof rendered === 'string') {
        return this.cleanText(rendered);
      }
    }
    return fallback;
  }
 
  private cleanText(value: string): string {
    return value.replace(/<[^>]*>/g, '').trim();
  }
 
  openApplyPagebanner(): void {
    window.open('https://apply.creditcard.pnb.bank.in/', '_blank');
  }
 
  openApplyPage(url: string): void {
    if (!url) return;
    window.open(url, '_blank', 'noopener,noreferrer');
  }
}