@eric-emg/symphiq-components 1.2.247 → 1.2.248
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/symphiq-components.mjs +1328 -1296
- package/fesm2022/symphiq-components.mjs.map +1 -1
- package/index.d.ts +43 -35
- package/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/styles.css +70 -37
|
@@ -13667,39 +13667,39 @@ class RelatedRecommendationChipsComponent {
|
|
|
13667
13667
|
standalone: true,
|
|
13668
13668
|
imports: [CommonModule, SymphiqIconComponent],
|
|
13669
13669
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
13670
|
-
template: `
|
|
13671
|
-
@if (displayedRecommendations().length > 0) {
|
|
13672
|
-
<div class="space-y-3">
|
|
13673
|
-
<div class="flex flex-wrap gap-2">
|
|
13674
|
-
@for (rec of displayedRecommendations(); track rec.id) {
|
|
13675
|
-
<button
|
|
13676
|
-
type="button"
|
|
13677
|
-
[ngClass]="getChipClasses(rec)"
|
|
13678
|
-
(click)="openRecommendationModal(rec.id!, $event)"
|
|
13679
|
-
class="transition-all duration-200 cursor-pointer"
|
|
13680
|
-
>
|
|
13681
|
-
<symphiq-icon [icon]="getPriorityIcon(rec)" size="w-3.5 h-3.5" class="flex-shrink-0"></symphiq-icon>
|
|
13682
|
-
<span class="font-medium">{{ rec.title }}</span>
|
|
13683
|
-
<symphiq-icon [icon]="{ name: 'chevron-right', source: IconSourceEnum.HEROICONS }" size="w-3.5 h-3.5" class="flex-shrink-0 opacity-60"></symphiq-icon>
|
|
13684
|
-
</button>
|
|
13685
|
-
}
|
|
13686
|
-
</div>
|
|
13687
|
-
|
|
13688
|
-
@if (hasMoreRecommendations()) {
|
|
13689
|
-
<button
|
|
13690
|
-
type="button"
|
|
13691
|
-
(click)="toggleShowAll($event)"
|
|
13692
|
-
[ngClass]="getViewMoreButtonClasses()"
|
|
13693
|
-
class="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer"
|
|
13694
|
-
>
|
|
13695
|
-
<span>{{ showAll() ? 'Show Less' : 'View More' }}</span>
|
|
13696
|
-
<svg class="w-4 h-4 transition-transform duration-200" [class.rotate-180]="showAll()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
13697
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
|
13698
|
-
</svg>
|
|
13699
|
-
</button>
|
|
13700
|
-
}
|
|
13701
|
-
</div>
|
|
13702
|
-
}
|
|
13670
|
+
template: `
|
|
13671
|
+
@if (displayedRecommendations().length > 0) {
|
|
13672
|
+
<div class="space-y-3">
|
|
13673
|
+
<div class="flex flex-wrap gap-2">
|
|
13674
|
+
@for (rec of displayedRecommendations(); track rec.id) {
|
|
13675
|
+
<button
|
|
13676
|
+
type="button"
|
|
13677
|
+
[ngClass]="getChipClasses(rec)"
|
|
13678
|
+
(click)="openRecommendationModal(rec.id!, $event)"
|
|
13679
|
+
class="transition-all duration-200 cursor-pointer"
|
|
13680
|
+
>
|
|
13681
|
+
<symphiq-icon [icon]="getPriorityIcon(rec)" size="w-3.5 h-3.5" class="flex-shrink-0"></symphiq-icon>
|
|
13682
|
+
<span class="font-medium">{{ rec.title }}</span>
|
|
13683
|
+
<symphiq-icon [icon]="{ name: 'chevron-right', source: IconSourceEnum.HEROICONS }" size="w-3.5 h-3.5" class="flex-shrink-0 opacity-60"></symphiq-icon>
|
|
13684
|
+
</button>
|
|
13685
|
+
}
|
|
13686
|
+
</div>
|
|
13687
|
+
|
|
13688
|
+
@if (hasMoreRecommendations()) {
|
|
13689
|
+
<button
|
|
13690
|
+
type="button"
|
|
13691
|
+
(click)="toggleShowAll($event)"
|
|
13692
|
+
[ngClass]="getViewMoreButtonClasses()"
|
|
13693
|
+
class="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 cursor-pointer"
|
|
13694
|
+
>
|
|
13695
|
+
<span>{{ showAll() ? 'Show Less' : 'View More' }}</span>
|
|
13696
|
+
<svg class="w-4 h-4 transition-transform duration-200" [class.rotate-180]="showAll()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
13697
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
|
13698
|
+
</svg>
|
|
13699
|
+
</button>
|
|
13700
|
+
}
|
|
13701
|
+
</div>
|
|
13702
|
+
}
|
|
13703
13703
|
`
|
|
13704
13704
|
}]
|
|
13705
13705
|
}], null, { recommendations: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendations", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], maxInitialDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxInitialDisplay", required: false }] }], inModalContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "inModalContext", required: false }] }] }); })();
|
|
@@ -47936,1001 +47936,1001 @@ class SymphiqFunnelAnalysisDashboardComponent {
|
|
|
47936
47936
|
ViewModeSwitcherModalComponent,
|
|
47937
47937
|
ProfileAnalysisModalComponent,
|
|
47938
47938
|
BusinessAnalysisModalComponent,
|
|
47939
|
-
], template: `
|
|
47940
|
-
<div
|
|
47941
|
-
class="bg-transparent"
|
|
47942
|
-
[class.min-h-screen]="!embedded()"
|
|
47943
|
-
[class.relative]="!embedded()"
|
|
47944
|
-
[style.display]="embedded() ? 'block' : null"
|
|
47945
|
-
[style.min-height]="embedded() ? 'auto' : null"
|
|
47946
|
-
#dashboardContainer>
|
|
47947
|
-
<!-- Animated Background Bubbles -->
|
|
47948
|
-
<div class="animated-bubbles" [class.light-mode]="isLightMode()" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100vw; height: 100vh; z-index: 1; pointer-events: none;"></div>
|
|
47949
|
-
|
|
47950
|
-
<!-- Scroll Progress Bar -->
|
|
47951
|
-
<div [class]="embedded() ? 'sticky top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30' : 'fixed top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30'">
|
|
47952
|
-
<div
|
|
47953
|
-
[style.width.%]="scrollProgress()"
|
|
47954
|
-
[ngClass]="isLightMode() ? 'bg-gradient-to-r from-blue-500 to-purple-500' : 'bg-gradient-to-r from-blue-400 to-purple-400'"
|
|
47955
|
-
class="h-full transition-all duration-200 ease-out">
|
|
47956
|
-
</div>
|
|
47957
|
-
</div>
|
|
47958
|
-
|
|
47959
|
-
<header [class]="headerClass()" class="sticky top-0 z-50 animate-fade-in" style="animation-delay: 0s;">
|
|
47960
|
-
<!-- Expanded Header (default state) -->
|
|
47961
|
-
<div
|
|
47962
|
-
class="transition-all duration-300 ease-in-out overflow-hidden"
|
|
47963
|
-
[class.max-h-0]="isScrolled()"
|
|
47964
|
-
[class.opacity-0]="isScrolled()"
|
|
47965
|
-
[class.max-h-96]="!isScrolled()"
|
|
47966
|
-
[class.opacity-100]="!isScrolled()">
|
|
47967
|
-
<div
|
|
47968
|
-
class="max-w-7xl mx-auto px-6 sm:px-8 py-6 sm:py-8"
|
|
47969
|
-
[class.pointer-events-none]="isScrolled()"
|
|
47970
|
-
[class.pointer-events-auto]="!isScrolled()">
|
|
47971
|
-
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-0">
|
|
47972
|
-
<div class="flex-1">
|
|
47973
|
-
<div class="flex items-center gap-3">
|
|
47974
|
-
<h1 class="text-2xl sm:text-3xl font-bold mb-2 bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
|
|
47975
|
-
@if (isLoading() && !isShowingLoader()) {
|
|
47976
|
-
<!-- Subtle refresh indicator -->
|
|
47977
|
-
<div class="animate-spin w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full" title="Refreshing data..."></div>
|
|
47978
|
-
}
|
|
47979
|
-
</div>
|
|
47980
|
-
<div class="flex flex-wrap items-center justify-between gap-3 sm:gap-4">
|
|
47981
|
-
<p [class]="headerSubtitleClass()" class="text-sm sm:text-base">Revenue Orchestration & Funnel Analysis</p>
|
|
47982
|
-
<div class="flex items-center gap-4">
|
|
47983
|
-
@if (!isSimplifiedView()) {
|
|
47984
|
-
<!-- Search Button -->
|
|
47985
|
-
<button
|
|
47986
|
-
type="button"
|
|
47987
|
-
(click)="searchService.openSearch(); $event.preventDefault()"
|
|
47988
|
-
[class]="buttonClass()"
|
|
47989
|
-
class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105"
|
|
47990
|
-
title="Search (/ or Cmd+K)">
|
|
47991
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
47992
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
47993
|
-
</svg>
|
|
47994
|
-
<span>Search</span>
|
|
47995
|
-
</button>
|
|
47996
|
-
}
|
|
47997
|
-
<!-- View Mode Switcher Button -->
|
|
47998
|
-
<button
|
|
47999
|
-
type="button"
|
|
48000
|
-
(click)="openViewModeSwitcher(); $event.preventDefault()"
|
|
48001
|
-
[class]="buttonClass()"
|
|
48002
|
-
class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105">
|
|
48003
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48004
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
48005
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
48006
|
-
</svg>
|
|
48007
|
-
<span>{{ displayModeLabel() }}</span>
|
|
48008
|
-
</button>
|
|
48009
|
-
@if (!isSimplifiedView()) {
|
|
48010
|
-
<div class="flex items-center gap-2 sm:gap-3 whitespace-nowrap">
|
|
48011
|
-
<label [class]="metaLabelClass()" class="text-xs sm:text-sm font-medium">View:</label>
|
|
48012
|
-
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
|
|
48013
|
-
<select
|
|
48014
|
-
[ngModel]="selectedSectionFilter()"
|
|
48015
|
-
(ngModelChange)="changeSectionFilter($event)"
|
|
48016
|
-
[class]="selectClass()"
|
|
48017
|
-
class="px-3 sm:px-4 py-1.5 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
|
|
48018
|
-
@for (section of sectionFilters; track section.value) {
|
|
48019
|
-
<option [value]="section.value">{{ section.label }}</option>
|
|
48020
|
-
}
|
|
48021
|
-
</select>
|
|
48022
|
-
</div>
|
|
48023
|
-
</div>
|
|
48024
|
-
}
|
|
48025
|
-
</div>
|
|
48026
|
-
</div>
|
|
48027
|
-
</div>
|
|
48028
|
-
<div class="flex flex-col gap-4 min-w-[180px]">
|
|
48029
|
-
@if (formattedGeneratedDate()) {
|
|
48030
|
-
<div class="text-left sm:text-right">
|
|
48031
|
-
<div [class]="metaLabelClass()" class="text-xs sm:text-sm">Generated At</div>
|
|
48032
|
-
<div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ formattedGeneratedDate() }}</div>
|
|
48033
|
-
</div>
|
|
48034
|
-
}
|
|
48035
|
-
<div class="text-left sm:text-right">
|
|
48036
|
-
<div [class]="metaLabelClass()" class="text-xs sm:text-sm">Requested by</div>
|
|
48037
|
-
<div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ requestedByUser()?.firstName }} {{ requestedByUser()?.lastName }}</div>
|
|
48038
|
-
</div>
|
|
48039
|
-
</div>
|
|
48040
|
-
</div>
|
|
48041
|
-
</div>
|
|
48042
|
-
</div>
|
|
48043
|
-
|
|
48044
|
-
<!-- Condensed Header (scrolled state) -->
|
|
48045
|
-
<div
|
|
48046
|
-
class="transition-all duration-300 ease-in-out overflow-hidden"
|
|
48047
|
-
[class.max-h-0]="!isScrolled()"
|
|
48048
|
-
[class.opacity-0]="!isScrolled()"
|
|
48049
|
-
[class.max-h-20]="isScrolled()"
|
|
48050
|
-
[class.opacity-100]="isScrolled()">
|
|
48051
|
-
<div
|
|
48052
|
-
class="max-w-7xl mx-auto px-6 sm:px-8 py-3"
|
|
48053
|
-
[class.pointer-events-none]="!isScrolled()"
|
|
48054
|
-
[class.pointer-events-auto]="isScrolled()">
|
|
48055
|
-
<div class="flex items-center justify-between gap-4">
|
|
48056
|
-
<div class="flex items-center gap-4 flex-1 min-w-0">
|
|
48057
|
-
<h1 class="text-lg font-bold truncate bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
|
|
48058
|
-
@if (revenueMetric()) {
|
|
48059
|
-
<div class="hidden lg:flex items-center gap-3 px-4 py-1.5 rounded-lg" [ngClass]="isLightMode() ? 'bg-emerald-50 border border-emerald-200' : 'bg-emerald-500/10 border border-emerald-500/20'">
|
|
48060
|
-
<span [class]="metaLabelClass()" class="text-xs font-medium">Revenue:</span>
|
|
48061
|
-
<span [class]="headerTitleClass()" class="text-sm font-bold">{{ formatValue(revenueValue()) }}</span>
|
|
48062
|
-
<span class="text-xs font-semibold" [ngClass]="revenueTrend() >= 0 ? 'text-emerald-600' : 'text-red-600'">
|
|
48063
|
-
{{ revenueTrend() >= 0 ? '+' : '' }}{{ revenueTrend().toFixed(1) }}%
|
|
48064
|
-
</span>
|
|
48065
|
-
</div>
|
|
48066
|
-
}
|
|
48067
|
-
</div>
|
|
48068
|
-
<div class="flex items-center gap-3">
|
|
48069
|
-
@if (!isSimplifiedView()) {
|
|
48070
|
-
<!-- Search Button (Icon Only in Sticky Header) -->
|
|
48071
|
-
<button
|
|
48072
|
-
type="button"
|
|
48073
|
-
(click)="searchService.openSearch(); $event.preventDefault()"
|
|
48074
|
-
[class]="buttonClass()"
|
|
48075
|
-
title="Search (/ or Cmd+K)"
|
|
48076
|
-
class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
|
|
48077
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48078
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
48079
|
-
</svg>
|
|
48080
|
-
</button>
|
|
48081
|
-
}
|
|
48082
|
-
<!-- View Mode Switcher (Icon Only in Sticky Header) -->
|
|
48083
|
-
<button
|
|
48084
|
-
type="button"
|
|
48085
|
-
(click)="openViewModeSwitcher(); $event.preventDefault()"
|
|
48086
|
-
[class]="buttonClass()"
|
|
48087
|
-
[title]="'Change View Mode: ' + displayModeLabel()"
|
|
48088
|
-
class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
|
|
48089
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48090
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
48091
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
48092
|
-
</svg>
|
|
48093
|
-
</button>
|
|
48094
|
-
@if (!isSimplifiedView()) {
|
|
48095
|
-
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
|
|
48096
|
-
<select
|
|
48097
|
-
[ngModel]="selectedSectionFilter()"
|
|
48098
|
-
(ngModelChange)="changeSectionFilter($event)"
|
|
48099
|
-
[class]="selectClass()"
|
|
48100
|
-
class="px-3 py-1.5 rounded-lg text-xs font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
|
|
48101
|
-
@for (section of sectionFilters; track section.value) {
|
|
48102
|
-
<option [value]="section.value">{{ section.label }}</option>
|
|
48103
|
-
}
|
|
48104
|
-
</select>
|
|
48105
|
-
</div>
|
|
48106
|
-
}
|
|
48107
|
-
</div>
|
|
48108
|
-
</div>
|
|
48109
|
-
</div>
|
|
48110
|
-
</div>
|
|
48111
|
-
</header>
|
|
48112
|
-
|
|
48113
|
-
<!-- Search Breadcrumb -->
|
|
48114
|
-
@if (searchService.activeSearchResult()) {
|
|
48115
|
-
<div [ngClass]="isLightMode() ? 'bg-blue-50/95 border-blue-200' : 'bg-blue-900/20 border-blue-800/30'" class="sticky top-[var(--header-height)] z-40 border-b backdrop-blur-md animate-slide-up-fade">
|
|
48116
|
-
<div class="max-w-7xl mx-auto px-6 sm:px-8 py-3">
|
|
48117
|
-
<div class="flex items-center justify-between gap-4">
|
|
48118
|
-
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
48119
|
-
<svg [ngClass]="isLightMode() ? 'text-blue-600' : 'text-blue-400'" class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48120
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
48121
|
-
</svg>
|
|
48122
|
-
<div class="flex items-center gap-2 flex-1 min-w-0">
|
|
48123
|
-
<span [ngClass]="isLightMode() ? 'text-blue-900' : 'text-blue-100'" class="text-sm font-medium">Showing:</span>
|
|
48124
|
-
<span [ngClass]="isLightMode() ? 'text-blue-700' : 'text-blue-300'" class="text-sm font-semibold truncate">
|
|
48125
|
-
{{ searchService.activeSearchResult()!.title }}
|
|
48126
|
-
</span>
|
|
48127
|
-
<span [ngClass]="isLightMode() ? 'bg-blue-100 text-blue-700 border-blue-200' : 'bg-blue-800/50 text-blue-300 border-blue-700/50'" class="px-2 py-0.5 rounded text-xs font-medium uppercase border flex-shrink-0">
|
|
48128
|
-
{{ searchService.activeSearchResult()!.type }}
|
|
48129
|
-
</span>
|
|
48130
|
-
</div>
|
|
48131
|
-
</div>
|
|
48132
|
-
<button
|
|
48133
|
-
(click)="clearSearchResult(); $event.stopPropagation()"
|
|
48134
|
-
[ngClass]="isLightMode() ? 'text-blue-600 hover:text-blue-800 hover:bg-blue-100' : 'text-blue-400 hover:text-blue-200 hover:bg-blue-800/50'"
|
|
48135
|
-
class="p-2 rounded-lg transition-colors flex-shrink-0"
|
|
48136
|
-
title="Clear search">
|
|
48137
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48138
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
48139
|
-
</svg>
|
|
48140
|
-
</button>
|
|
48141
|
-
</div>
|
|
48142
|
-
</div>
|
|
48143
|
-
</div>
|
|
48144
|
-
}
|
|
48145
|
-
|
|
48146
|
-
<!-- Floating Table of Contents -->
|
|
48147
|
-
@if (!isSimplifiedView()) {
|
|
48148
|
-
<symphiq-floating-toc
|
|
48149
|
-
[sections]="tocSections()"
|
|
48150
|
-
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48151
|
-
[embedded]="embedded()"
|
|
48152
|
-
[scrollElement]="scrollElement() ?? undefined"
|
|
48153
|
-
/>
|
|
48154
|
-
}
|
|
48155
|
-
|
|
48156
|
-
<!-- Quick Navigation Dots -->
|
|
48157
|
-
@if (!isSimplifiedView()) {
|
|
48158
|
-
<div class="fixed right-6 top-1/2 -translate-y-1/2 z-40 hidden xl:flex flex-col gap-4">
|
|
48159
|
-
@if (showOverallPerformance()) {
|
|
48160
|
-
<button
|
|
48161
|
-
(click)="scrollToTop()"
|
|
48162
|
-
[libSymphiqTooltip]="'Scroll to Top'"
|
|
48163
|
-
[tooltipPosition]="'left'"
|
|
48164
|
-
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48165
|
-
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48166
|
-
</button>
|
|
48167
|
-
}
|
|
48168
|
-
@if (showKeyInsights()) {
|
|
48169
|
-
<button
|
|
48170
|
-
(click)="scrollToSection('section-insights')"
|
|
48171
|
-
[libSymphiqTooltip]="'Key Insights'"
|
|
48172
|
-
[tooltipPosition]="'left'"
|
|
48173
|
-
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48174
|
-
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48175
|
-
</button>
|
|
48176
|
-
}
|
|
48177
|
-
@if (showPerformanceMetrics()) {
|
|
48178
|
-
<button
|
|
48179
|
-
(click)="scrollToSection('section-metrics')"
|
|
48180
|
-
[libSymphiqTooltip]="'Performance Metrics'"
|
|
48181
|
-
[tooltipPosition]="'left'"
|
|
48182
|
-
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48183
|
-
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48184
|
-
</button>
|
|
48185
|
-
}
|
|
48186
|
-
@if (showPerformanceBreakdowns()) {
|
|
48187
|
-
<button
|
|
48188
|
-
(click)="scrollToSection('section-breakdowns')"
|
|
48189
|
-
[libSymphiqTooltip]="'Performance Breakdowns'"
|
|
48190
|
-
[tooltipPosition]="'left'"
|
|
48191
|
-
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48192
|
-
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48193
|
-
</button>
|
|
48194
|
-
}
|
|
48195
|
-
@if (showCompetitiveIntelligence()) {
|
|
48196
|
-
<button
|
|
48197
|
-
(click)="scrollToSection('section-competitive')"
|
|
48198
|
-
[libSymphiqTooltip]="'Competitive Intelligence'"
|
|
48199
|
-
[tooltipPosition]="'left'"
|
|
48200
|
-
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-indigo-500' : 'bg-slate-600 hover:bg-indigo-400'"
|
|
48201
|
-
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48202
|
-
</button>
|
|
48203
|
-
}
|
|
48204
|
-
</div>
|
|
48205
|
-
}
|
|
48206
|
-
|
|
48207
|
-
@if (isSimplifiedView()) {
|
|
48208
|
-
<!-- Journey Progress Banner -->
|
|
48209
|
-
@if (!isOnboarded()) {
|
|
48210
|
-
<symphiq-journey-progress-indicator
|
|
48211
|
-
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48212
|
-
[currentStepId]="JourneyStepIdEnum.FUNNEL_ANALYSIS"
|
|
48213
|
-
[showNextStepAction]="true"
|
|
48214
|
-
[forDemo]="forDemo()"
|
|
48215
|
-
[maxAccessibleStepId]="maxAccessibleStepId()"
|
|
48216
|
-
(stepClick)="stepClick.emit($event)"
|
|
48217
|
-
(nextStepClick)="nextStepClick.emit()"
|
|
48218
|
-
/>
|
|
48219
|
-
}
|
|
48220
|
-
|
|
48221
|
-
<main class="max-w-7xl mx-auto px-6 sm:px-8">
|
|
48222
|
-
<div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
|
|
48223
|
-
<!-- Welcome Banner -->
|
|
48224
|
-
<div class="mb-8">
|
|
48225
|
-
<symphiq-funnel-welcome-banner
|
|
48226
|
-
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48227
|
-
[isOnboarded]="isOnboarded()"
|
|
48228
|
-
/>
|
|
48229
|
-
</div>
|
|
48230
|
-
|
|
48231
|
-
<!-- Key Insights Section -->
|
|
48232
|
-
@if (showKeyInsights()) {
|
|
48233
|
-
<section id="section-insights" class="mb-8">
|
|
48234
|
-
<div class="flex items-center justify-between mb-6">
|
|
48235
|
-
<div class="flex items-center gap-3">
|
|
48236
|
-
<div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
|
|
48237
|
-
<div class="flex items-center gap-3">
|
|
48238
|
-
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48239
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
|
|
48240
|
-
</svg>
|
|
48241
|
-
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
|
|
48242
|
-
</div>
|
|
48243
|
-
</div>
|
|
48244
|
-
</div>
|
|
48245
|
-
<span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
|
|
48246
|
-
</div>
|
|
48247
|
-
|
|
48248
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
48249
|
-
@for (insight of insights(); track $index) {
|
|
48250
|
-
<symphiq-funnel-analysis-insight-card
|
|
48251
|
-
[insight]="insight"
|
|
48252
|
-
[allMetrics]="allMetrics()"
|
|
48253
|
-
[charts]="chartsForInsight(insight)"
|
|
48254
|
-
[allCharts]="allCharts()"
|
|
48255
|
-
[allBusinessInsights]="allBusinessInsights()"
|
|
48256
|
-
[isLightMode]="isLightMode()"
|
|
48257
|
-
[viewMode]="viewMode()"
|
|
48258
|
-
[isCompactMode]="true"
|
|
48259
|
-
[isLoading]="isDataLoading()" />
|
|
48260
|
-
}
|
|
48261
|
-
</div>
|
|
48262
|
-
</section>
|
|
48263
|
-
}
|
|
48264
|
-
|
|
48265
|
-
<!-- Supporting Data Section -->
|
|
48266
|
-
<symphiq-collapsible-funnel-section-group
|
|
48267
|
-
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK">
|
|
48268
|
-
<!-- Overall Performance Slot -->
|
|
48269
|
-
<div slot="overall-performance">
|
|
48270
|
-
@if (showOverallPerformance()) {
|
|
48271
|
-
<div class="p-6">
|
|
48272
|
-
@if (isDataLoading()) {
|
|
48273
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48274
|
-
} @else {
|
|
48275
|
-
<symphiq-funnel-analysis-overall-assessment
|
|
48276
|
-
[assessment]="performanceOverview().overallAssessment || {}"
|
|
48277
|
-
[revenueMetric]="revenueMetric()"
|
|
48278
|
-
[charts]="chartsForItem('OVERALL_ASSESSMENT')"
|
|
48279
|
-
[metrics]="allMetrics()"
|
|
48280
|
-
[isLightMode]="isLightMode()"
|
|
48281
|
-
[isLoading]="isOverallAssessmentLoading()"
|
|
48282
|
-
[isCompactMode]="true"
|
|
48283
|
-
[isChartsLoading]="areChartsLoading()"
|
|
48284
|
-
[strengths]="strengths()"
|
|
48285
|
-
[weaknesses]="weaknesses()"
|
|
48286
|
-
[currencySymbol]="currencySymbol()"
|
|
48287
|
-
(scrollToSection)="scrollToSection($event)" />
|
|
48288
|
-
}
|
|
48289
|
-
</div>
|
|
48290
|
-
}
|
|
48291
|
-
</div>
|
|
48292
|
-
|
|
48293
|
-
<!-- Performance Metrics Slot -->
|
|
48294
|
-
<div slot="performance-metrics">
|
|
48295
|
-
@if (showPerformanceMetrics()) {
|
|
48296
|
-
<div class="p-6 space-y-8">
|
|
48297
|
-
@for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
|
|
48298
|
-
<!-- Funnel Stage Metric (Full Width) -->
|
|
48299
|
-
<div class="w-full">
|
|
48300
|
-
<symphiq-funnel-analysis-metric-card
|
|
48301
|
-
[metric]="funnelGroup.funnelMetric"
|
|
48302
|
-
[insights]="insights()"
|
|
48303
|
-
[charts]="chartsForMetric(funnelGroup.funnelMetric)"
|
|
48304
|
-
[allCharts]="allCharts()"
|
|
48305
|
-
[analysis]="analysisData()"
|
|
48306
|
-
[isLightMode]="isLightMode()"
|
|
48307
|
-
[viewMode]="viewMode()"
|
|
48308
|
-
[isCompactMode]="true"
|
|
48309
|
-
[currencySymbol]="currencySymbol()" />
|
|
48310
|
-
</div>
|
|
48311
|
-
<!-- Related Metrics (Grid Layout) -->
|
|
48312
|
-
@if (funnelGroup.relatedMetrics.length > 0) {
|
|
48313
|
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-4">
|
|
48314
|
-
@for (metric of funnelGroup.relatedMetrics; track $index) {
|
|
48315
|
-
<symphiq-funnel-analysis-metric-card
|
|
48316
|
-
[metric]="metric"
|
|
48317
|
-
[insights]="insights()"
|
|
48318
|
-
[charts]="chartsForMetric(metric)"
|
|
48319
|
-
[allCharts]="allCharts()"
|
|
48320
|
-
[analysis]="analysisData()"
|
|
48321
|
-
[isLightMode]="isLightMode()"
|
|
48322
|
-
[viewMode]="viewMode()"
|
|
48323
|
-
[isCompactMode]="true"
|
|
48324
|
-
[currencySymbol]="currencySymbol()" />
|
|
48325
|
-
}
|
|
48326
|
-
</div>
|
|
48327
|
-
}
|
|
48328
|
-
}
|
|
48329
|
-
</div>
|
|
48330
|
-
}
|
|
48331
|
-
</div>
|
|
48332
|
-
|
|
48333
|
-
<!-- Performance Breakdowns Slot -->
|
|
48334
|
-
<div slot="performance-breakdowns">
|
|
48335
|
-
@if (showPerformanceBreakdowns()) {
|
|
48336
|
-
<div class="p-6 space-y-8">
|
|
48337
|
-
@for (breakdown of breakdowns(); track $index) {
|
|
48338
|
-
<symphiq-funnel-analysis-breakdown-section
|
|
48339
|
-
[breakdown]="breakdown"
|
|
48340
|
-
[charts]="chartsForBreakdown(breakdown)"
|
|
48341
|
-
[isLightMode]="isLightMode()"
|
|
48342
|
-
[isLoading]="isDataLoading()"
|
|
48343
|
-
[isCompactMode]="true"
|
|
48344
|
-
[currencySymbol]="currencySymbol()" />
|
|
48345
|
-
}
|
|
48346
|
-
</div>
|
|
48347
|
-
}
|
|
48348
|
-
</div>
|
|
48349
|
-
|
|
48350
|
-
<!-- Competitive Intelligence Slot -->
|
|
48351
|
-
<div slot="competitive-intelligence">
|
|
48352
|
-
@if (showCompetitiveIntelligence()) {
|
|
48353
|
-
<div class="p-6">
|
|
48354
|
-
<symphiq-competitive-intelligence-view
|
|
48355
|
-
[metrics]="competitiveMetrics()"
|
|
48356
|
-
[allCharts]="allCharts()"
|
|
48357
|
-
[isLightMode]="isLightMode()"
|
|
48358
|
-
[isCompactMode]="true"
|
|
48359
|
-
[competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
|
|
48360
|
-
[currencySymbol]="currencySymbol()" />
|
|
48361
|
-
</div>
|
|
48362
|
-
}
|
|
48363
|
-
</div>
|
|
48364
|
-
</symphiq-collapsible-funnel-section-group>
|
|
48365
|
-
</div>
|
|
48366
|
-
</main>
|
|
48367
|
-
} @else {
|
|
48368
|
-
<main class="max-w-7xl mx-auto px-6 sm:px-8">
|
|
48369
|
-
<div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
|
|
48370
|
-
@if (showOverallPerformance()) {
|
|
48371
|
-
<div id="section-overall" class="animate-fade-in-up mb-20 sm:mb-28" style="animation-delay: 0.1s;">
|
|
48372
|
-
@if (isDataLoading()) {
|
|
48373
|
-
<!-- Overall Assessment Skeleton -->
|
|
48374
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 sm:p-8 animate-pulse">
|
|
48375
|
-
<div class="space-y-6">
|
|
48376
|
-
<!-- Header -->
|
|
48377
|
-
<div class="flex items-center gap-3">
|
|
48378
|
-
<symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48379
|
-
<div class="flex-1 space-y-2">
|
|
48380
|
-
<symphiq-skeleton-loader [width]="'40%'" [height]="'32px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48381
|
-
<symphiq-skeleton-loader [width]="'60%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48382
|
-
</div>
|
|
48383
|
-
</div>
|
|
48384
|
-
<!-- Summary text -->
|
|
48385
|
-
<div class="space-y-2">
|
|
48386
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48387
|
-
<symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48388
|
-
<symphiq-skeleton-loader [width]="'90%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48389
|
-
</div>
|
|
48390
|
-
<!-- Chart placeholder -->
|
|
48391
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
|
|
48392
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48393
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48394
|
-
</div>
|
|
48395
|
-
</div>
|
|
48396
|
-
</div>
|
|
48397
|
-
} @else {
|
|
48398
|
-
<symphiq-funnel-analysis-overall-assessment
|
|
48399
|
-
[assessment]="performanceOverview().overallAssessment || {}"
|
|
48400
|
-
[revenueMetric]="revenueMetric()"
|
|
48401
|
-
[charts]="chartsForItem('OVERALL_ASSESSMENT')"
|
|
48402
|
-
[metrics]="allMetrics()"
|
|
48403
|
-
[isLightMode]="isLightMode()"
|
|
48404
|
-
[isLoading]="isOverallAssessmentLoading()"
|
|
48405
|
-
[isCompactMode]="viewModeService.isCompact()"
|
|
48406
|
-
[isChartsLoading]="areChartsLoading()"
|
|
48407
|
-
[strengths]="strengths()"
|
|
48408
|
-
[weaknesses]="weaknesses()"
|
|
48409
|
-
[currencySymbol]="currencySymbol()"
|
|
48410
|
-
(scrollToSection)="scrollToSection($event)" />
|
|
48411
|
-
}
|
|
48412
|
-
</div>
|
|
48413
|
-
}
|
|
48414
|
-
|
|
48415
|
-
@if (showKeyInsights()) {
|
|
48416
|
-
@if (selectedSectionFilter() === 'ALL') {
|
|
48417
|
-
<!-- Section Divider -->
|
|
48418
|
-
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.15s"></symphiq-section-divider>
|
|
48419
|
-
}
|
|
48420
|
-
|
|
48421
|
-
<section id="section-insights" class="relative">
|
|
48422
|
-
<!-- Background Pattern -->
|
|
48423
|
-
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-blue-50/50 to-transparent' : 'bg-gradient-to-br from-blue-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
|
|
48424
|
-
<div class="relative">
|
|
48425
|
-
<div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.2s;">
|
|
48426
|
-
<div class="flex items-center gap-3">
|
|
48427
|
-
<div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
|
|
48428
|
-
<div class="flex items-center gap-3">
|
|
48429
|
-
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48430
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
|
|
48431
|
-
</svg>
|
|
48432
|
-
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
|
|
48433
|
-
</div>
|
|
48434
|
-
</div>
|
|
48435
|
-
</div>
|
|
48436
|
-
<span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
|
|
48437
|
-
</div>
|
|
48438
|
-
<!-- Masonry Layout for Insights -->
|
|
48439
|
-
@if (isDataLoading() || (viewModeService.isExpanded() && viewModeService.getIsTransitioning())) {
|
|
48440
|
-
<!-- Skeleton loaders during data loading or transition to expanded view -->
|
|
48441
|
-
<div class="masonry-grid">
|
|
48442
|
-
@for (i of [1,2,3,4,5,6]; track i) {
|
|
48443
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[280px]">
|
|
48444
|
-
<div class="space-y-4">
|
|
48445
|
-
<div class="flex items-center gap-3 mb-4">
|
|
48446
|
-
<symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48447
|
-
<symphiq-skeleton-loader [width]="'60%'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48448
|
-
</div>
|
|
48449
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48450
|
-
<symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48451
|
-
<symphiq-skeleton-loader [width]="'85%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48452
|
-
<div class="mt-6 space-y-2">
|
|
48453
|
-
<symphiq-skeleton-loader [width]="'40%'" [height]="'14px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48454
|
-
<symphiq-skeleton-loader [width]="'50%'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48455
|
-
</div>
|
|
48456
|
-
<div class="flex gap-2 mt-4">
|
|
48457
|
-
<symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48458
|
-
<symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48459
|
-
</div>
|
|
48460
|
-
</div>
|
|
48461
|
-
</div>
|
|
48462
|
-
}
|
|
48463
|
-
</div>
|
|
48464
|
-
} @else if (viewModeService.isExpanded()) {
|
|
48465
|
-
<div class="masonry-grid">
|
|
48466
|
-
@for (insight of insights(); track $index) {
|
|
48467
|
-
<div
|
|
48468
|
-
[class]="getInsightCardClass(insight)"
|
|
48469
|
-
class="animate-fade-in-up"
|
|
48470
|
-
[style.animation-delay]="(0.3 + $index * 0.1) + 's'"
|
|
48471
|
-
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48472
|
-
[highlightId]="'insight-' + $index">
|
|
48473
|
-
<symphiq-funnel-analysis-insight-card
|
|
48474
|
-
[insight]="insight"
|
|
48475
|
-
[allMetrics]="allMetrics()"
|
|
48476
|
-
[charts]="chartsForInsight(insight)"
|
|
48477
|
-
[allCharts]="allCharts()"
|
|
48478
|
-
[allBusinessInsights]="allBusinessInsights()"
|
|
48479
|
-
[isLightMode]="isLightMode()"
|
|
48480
|
-
[viewMode]="viewMode()"
|
|
48481
|
-
[isCompactMode]="false" />
|
|
48482
|
-
</div>
|
|
48483
|
-
}
|
|
48484
|
-
</div>
|
|
48485
|
-
} @else {
|
|
48486
|
-
<!-- Compact Grid for Insights -->
|
|
48487
|
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
48488
|
-
@for (insight of insights(); track $index) {
|
|
48489
|
-
<div class="animate-fade-in-up" [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
|
|
48490
|
-
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48491
|
-
[highlightId]="'insight-' + $index">
|
|
48492
|
-
<symphiq-funnel-analysis-insight-card
|
|
48493
|
-
[insight]="insight"
|
|
48494
|
-
[allMetrics]="allMetrics()"
|
|
48495
|
-
[charts]="chartsForInsight(insight)"
|
|
48496
|
-
[allCharts]="allCharts()"
|
|
48497
|
-
[allBusinessInsights]="allBusinessInsights()"
|
|
48498
|
-
[isLightMode]="isLightMode()"
|
|
48499
|
-
[viewMode]="viewMode()"
|
|
48500
|
-
[isCompactMode]="true" />
|
|
48501
|
-
</div>
|
|
48502
|
-
}
|
|
48503
|
-
</div>
|
|
48504
|
-
}
|
|
48505
|
-
</div>
|
|
48506
|
-
</section>
|
|
48507
|
-
}
|
|
48508
|
-
|
|
48509
|
-
@if (showPerformanceMetrics()) {
|
|
48510
|
-
@if (selectedSectionFilter() === 'ALL') {
|
|
48511
|
-
<!-- Section Divider -->
|
|
48512
|
-
<div class="relative mb-14 sm:mb-24 mt-24 sm:mt-32 animate-fade-in" style="animation-delay: 0.35s;">
|
|
48513
|
-
<div class="absolute inset-0 flex items-center" aria-hidden="true">
|
|
48514
|
-
<div class="w-full h-px bg-gradient-to-r" [ngClass]="isLightMode() ? 'from-transparent via-emerald-500/30 to-transparent' : 'from-transparent via-emerald-400/20 to-transparent'"></div>
|
|
48515
|
-
</div>
|
|
48516
|
-
<div class="relative flex justify-center">
|
|
48517
|
-
<div class="px-4 py-2 rounded-full" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-emerald-50 to-teal-50 border border-emerald-200/50 shadow-lg shadow-emerald-500/10' : 'bg-gradient-to-br from-slate-900 to-slate-800 border border-emerald-500/20 shadow-lg shadow-emerald-500/5'">
|
|
48518
|
-
<svg class="w-5 h-5" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48519
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
|
|
48520
|
-
</svg>
|
|
48521
|
-
</div>
|
|
48522
|
-
</div>
|
|
48523
|
-
</div>
|
|
48524
|
-
}
|
|
48525
|
-
|
|
48526
|
-
<section id="section-metrics" class="relative">
|
|
48527
|
-
<!-- Background Pattern -->
|
|
48528
|
-
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tl from-emerald-50/50 to-transparent' : 'bg-gradient-to-tl from-emerald-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at top right, black 0%, transparent 70%);"></div>
|
|
48529
|
-
<div class="relative">
|
|
48530
|
-
<div class="flex flex-col gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.4s;">
|
|
48531
|
-
<div class="flex items-center justify-between">
|
|
48532
|
-
<div class="flex items-center gap-3">
|
|
48533
|
-
<div [ngClass]="isLightMode() ? 'border-l-4 border-emerald-500' : 'border-l-4 border-emerald-400'" class="pl-4">
|
|
48534
|
-
<div class="flex items-center gap-3">
|
|
48535
|
-
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48536
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
|
48537
|
-
</svg>
|
|
48538
|
-
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Metrics</h2>
|
|
48539
|
-
</div>
|
|
48540
|
-
</div>
|
|
48541
|
-
</div>
|
|
48542
|
-
<!-- Desktop controls -->
|
|
48543
|
-
<div class="hidden sm:flex gap-2 sm:gap-3 items-center relative">
|
|
48544
|
-
@if (isCategoryTransitioning()) {
|
|
48545
|
-
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48546
|
-
<div class="w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full animate-spin"></div>
|
|
48547
|
-
</div>
|
|
48548
|
-
}
|
|
48549
|
-
<select
|
|
48550
|
-
[ngModel]="selectedCategory()"
|
|
48551
|
-
(ngModelChange)="changeCategoryFilter($event)"
|
|
48552
|
-
[class]="selectClass()"
|
|
48553
|
-
[class.opacity-70]="isCategoryTransitioning()"
|
|
48554
|
-
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
|
|
48555
|
-
@for (cat of categories; track cat.value) {
|
|
48556
|
-
@if (cat.divider) {
|
|
48557
|
-
<option [value]="cat.value" disabled class="font-semibold">{{ cat.label }}</option>
|
|
48558
|
-
} @else {
|
|
48559
|
-
<option [value]="cat.value">{{ cat.label }}</option>
|
|
48560
|
-
}
|
|
48561
|
-
}
|
|
48562
|
-
</select>
|
|
48563
|
-
<button
|
|
48564
|
-
(click)="toggleSortOrder()"
|
|
48565
|
-
[class]="sortButtonClass()"
|
|
48566
|
-
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all flex items-center gap-2 cursor-pointer hover:scale-105 active:scale-95"
|
|
48567
|
-
[title]="reverseSortOrder() ? 'Sort: Revenue to Views' : 'Sort: Views to Revenue'">
|
|
48568
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48569
|
-
@if (!reverseSortOrder()) {
|
|
48570
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"></path>
|
|
48571
|
-
}
|
|
48572
|
-
@if (reverseSortOrder()) {
|
|
48573
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"></path>
|
|
48574
|
-
}
|
|
48575
|
-
</svg>
|
|
48576
|
-
<span>Sort</span>
|
|
48577
|
-
</button>
|
|
48578
|
-
</div>
|
|
48579
|
-
</div>
|
|
48580
|
-
|
|
48581
|
-
<!-- Mobile horizontal scrolling category pills -->
|
|
48582
|
-
<div class="sm:hidden -mx-6 px-6">
|
|
48583
|
-
<div class="flex gap-2 overflow-x-auto pb-2 snap-x snap-mandatory scrollbar-hide">
|
|
48584
|
-
@for (cat of categories; track cat.value) {
|
|
48585
|
-
@if (!cat.divider) {
|
|
48586
|
-
<button
|
|
48587
|
-
(click)="changeCategoryFilter(cat.value)"
|
|
48588
|
-
[ngClass]="getCategoryPillClass(cat.value)"
|
|
48589
|
-
[class.opacity-70]="isCategoryTransitioning()"
|
|
48590
|
-
class="px-4 py-2 rounded-full text-xs font-medium whitespace-nowrap transition-all duration-200 flex-shrink-0 snap-start active:scale-95">
|
|
48591
|
-
{{ cat.label }}
|
|
48592
|
-
</button>
|
|
48593
|
-
}
|
|
48594
|
-
}
|
|
48595
|
-
</div>
|
|
48596
|
-
</div>
|
|
48597
|
-
</div>
|
|
48598
|
-
@if (isDataLoading()) {
|
|
48599
|
-
<!-- Metrics Skeleton -->
|
|
48600
|
-
<div class="space-y-8 sm:space-y-10">
|
|
48601
|
-
@for (i of [1,2,3]; track i) {
|
|
48602
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48603
|
-
<div class="flex items-center justify-between mb-4">
|
|
48604
|
-
<div class="flex items-center gap-3">
|
|
48605
|
-
<symphiq-skeleton-loader [width]="'40px'" [height]="'40px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48606
|
-
<div class="space-y-2">
|
|
48607
|
-
<symphiq-skeleton-loader [width]="'150px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48608
|
-
<symphiq-skeleton-loader [width]="'100px'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48609
|
-
</div>
|
|
48610
|
-
</div>
|
|
48611
|
-
<symphiq-skeleton-loader [width]="'80px'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48612
|
-
</div>
|
|
48613
|
-
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
|
|
48614
|
-
@for (j of [1,2,3,4]; track j) {
|
|
48615
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48616
|
-
}
|
|
48617
|
-
</div>
|
|
48618
|
-
</div>
|
|
48619
|
-
}
|
|
48620
|
-
</div>
|
|
48621
|
-
} @else {
|
|
48622
|
-
<div class="space-y-8 sm:space-y-10" [class.animate-content-change]="isCategoryTransitioning()" [class.transition-opacity-slow]="isCategoryTransitioning()">
|
|
48623
|
-
@for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
|
|
48624
|
-
<div class="w-full animate-fade-in-up" [style.animation-delay]="(0.5 + groupIdx * 0.15) + 's'"
|
|
48625
|
-
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48626
|
-
[highlightId]="'metric-' + groupIdx">
|
|
48627
|
-
<symphiq-funnel-analysis-metric-card
|
|
48628
|
-
[metric]="funnelGroup.funnelMetric"
|
|
48629
|
-
[insights]="insights()"
|
|
48630
|
-
[charts]="chartsForMetric(funnelGroup.funnelMetric)"
|
|
48631
|
-
[allCharts]="allCharts()"
|
|
48632
|
-
[analysis]="analysisData()"
|
|
48633
|
-
[isLightMode]="isLightMode()"
|
|
48634
|
-
[viewMode]="viewMode()"
|
|
48635
|
-
[isCompactMode]="viewModeService.isCompact()"
|
|
48636
|
-
[currencySymbol]="currencySymbol()" />
|
|
48637
|
-
</div>
|
|
48638
|
-
@if (funnelGroup.relatedMetrics.length > 0) {
|
|
48639
|
-
<!-- Bento Box Grid Layout -->
|
|
48640
|
-
@if (viewModeService.isExpanded()) {
|
|
48641
|
-
<div class="bento-grid mt-4">
|
|
48642
|
-
@for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
|
|
48643
|
-
<div
|
|
48644
|
-
[class]="getBentoCardClass(metric, metricIdx)"
|
|
48645
|
-
class="animate-fade-in-up"
|
|
48646
|
-
[style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
|
|
48647
|
-
<symphiq-funnel-analysis-metric-card
|
|
48648
|
-
class="h-full"
|
|
48649
|
-
[metric]="metric"
|
|
48650
|
-
[insights]="insights()"
|
|
48651
|
-
[charts]="chartsForMetric(metric)"
|
|
48652
|
-
[allCharts]="allCharts()"
|
|
48653
|
-
[analysis]="analysisData()"
|
|
48654
|
-
[isLightMode]="isLightMode()"
|
|
48655
|
-
[viewMode]="viewMode()"
|
|
48656
|
-
[isCompactMode]="false"
|
|
48657
|
-
[currencySymbol]="currencySymbol()" />
|
|
48658
|
-
</div>
|
|
48659
|
-
}
|
|
48660
|
-
</div>
|
|
48661
|
-
} @else if (!viewModeService.isExpanded()) {
|
|
48662
|
-
<!-- Compact Grid Layout -->
|
|
48663
|
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mt-4">
|
|
48664
|
-
@for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
|
|
48665
|
-
<div class="animate-fade-in-up" [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
|
|
48666
|
-
<symphiq-funnel-analysis-metric-card
|
|
48667
|
-
[metric]="metric"
|
|
48668
|
-
[insights]="insights()"
|
|
48669
|
-
[charts]="chartsForMetric(metric)"
|
|
48670
|
-
[allCharts]="allCharts()"
|
|
48671
|
-
[analysis]="analysisData()"
|
|
48672
|
-
[isLightMode]="isLightMode()"
|
|
48673
|
-
[viewMode]="viewMode()"
|
|
48674
|
-
[isCompactMode]="true"
|
|
48675
|
-
[currencySymbol]="currencySymbol()" />
|
|
48676
|
-
</div>
|
|
48677
|
-
}
|
|
48678
|
-
</div>
|
|
48679
|
-
} @else {
|
|
48680
|
-
<!-- Skeleton loaders during transition to expanded view -->
|
|
48681
|
-
<div class="bento-grid mt-4">
|
|
48682
|
-
@for (i of [1,2,3,4]; track i) {
|
|
48683
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[240px]">
|
|
48684
|
-
<div class="space-y-4">
|
|
48685
|
-
<div class="flex items-center justify-between">
|
|
48686
|
-
<symphiq-skeleton-loader [width]="'60%'" [height]="'22px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48687
|
-
<symphiq-skeleton-loader [width]="'60px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48688
|
-
</div>
|
|
48689
|
-
<symphiq-skeleton-loader [width]="'45%'" [height]="'42px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48690
|
-
<div class="flex items-center gap-3 mt-4">
|
|
48691
|
-
<symphiq-skeleton-loader [width]="'24px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48692
|
-
<symphiq-skeleton-loader [width]="'30%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48693
|
-
</div>
|
|
48694
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48695
|
-
<symphiq-skeleton-loader [width]="'85%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48696
|
-
<div class="mt-4">
|
|
48697
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48698
|
-
</div>
|
|
48699
|
-
</div>
|
|
48700
|
-
</div>
|
|
48701
|
-
}
|
|
48702
|
-
</div>
|
|
48703
|
-
}
|
|
48704
|
-
}
|
|
48705
|
-
} @empty {
|
|
48706
|
-
<div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
|
|
48707
|
-
<svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48708
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
|
48709
|
-
</svg>
|
|
48710
|
-
<h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Metrics Found</h3>
|
|
48711
|
-
<p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance metrics match your current filter selection. Try adjusting your filters to see more results.</p>
|
|
48712
|
-
</div>
|
|
48713
|
-
}
|
|
48714
|
-
</div>
|
|
48715
|
-
}
|
|
48716
|
-
</div>
|
|
48717
|
-
</section>
|
|
48718
|
-
}
|
|
48719
|
-
|
|
48720
|
-
@if (showPerformanceBreakdowns()) {
|
|
48721
|
-
@if (selectedSectionFilter() === 'ALL') {
|
|
48722
|
-
<!-- Section Divider -->
|
|
48723
|
-
<div class="mt-28 sm:mt-36">
|
|
48724
|
-
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.65s"></symphiq-section-divider>
|
|
48725
|
-
</div>
|
|
48726
|
-
}
|
|
48727
|
-
|
|
48728
|
-
<section id="section-breakdowns" class="relative">
|
|
48729
|
-
<!-- Background Pattern -->
|
|
48730
|
-
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tr from-purple-50/50 to-transparent' : 'bg-gradient-to-tr from-purple-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at bottom left, black 0%, transparent 70%);"></div>
|
|
48731
|
-
<div class="relative">
|
|
48732
|
-
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.7s;">
|
|
48733
|
-
<div [ngClass]="isLightMode() ? 'border-l-4 border-purple-500' : 'border-l-4 border-purple-400'" class="pl-4">
|
|
48734
|
-
<div class="flex items-center gap-3">
|
|
48735
|
-
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-purple-500' : 'text-purple-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48736
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
|
48737
|
-
</svg>
|
|
48738
|
-
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Breakdowns</h2>
|
|
48739
|
-
</div>
|
|
48740
|
-
</div>
|
|
48741
|
-
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()" class="relative inline-block">
|
|
48742
|
-
@if (isBreakdownTransitioning()) {
|
|
48743
|
-
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48744
|
-
<div class="w-4 h-4 border-2 border-purple-500/30 border-t-purple-500 rounded-full animate-spin"></div>
|
|
48745
|
-
</div>
|
|
48746
|
-
}
|
|
48747
|
-
<select
|
|
48748
|
-
[ngModel]="selectedBreakdownFilter()"
|
|
48749
|
-
(ngModelChange)="changeBreakdownFilter($event)"
|
|
48750
|
-
[ngClass]="isLightMode()
|
|
48751
|
-
? 'bg-white border-slate-300 text-slate-900 hover:border-blue-400 focus:border-blue-500'
|
|
48752
|
-
: 'bg-slate-700 border-slate-600 text-white hover:border-slate-500 focus:border-blue-500'"
|
|
48753
|
-
[class.opacity-70]="isBreakdownTransitioning()"
|
|
48754
|
-
class="px-3 py-2 text-sm rounded-lg border transition-all duration-200 cursor-pointer focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
|
48755
|
-
@for (filter of breakdownFilters; track filter.value) {
|
|
48756
|
-
@if (filter.divider) {
|
|
48757
|
-
<option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
|
|
48758
|
-
} @else {
|
|
48759
|
-
<option [value]="filter.value">{{ filter.label }}</option>
|
|
48760
|
-
}
|
|
48761
|
-
}
|
|
48762
|
-
</select>
|
|
48763
|
-
</div>
|
|
48764
|
-
</div>
|
|
48765
|
-
@if (isDataLoading()) {
|
|
48766
|
-
<!-- Breakdowns Skeleton -->
|
|
48767
|
-
<div class="space-y-6">
|
|
48768
|
-
@for (i of [1,2]; track i) {
|
|
48769
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48770
|
-
<div class="flex items-center justify-between mb-4">
|
|
48771
|
-
<symphiq-skeleton-loader [width]="'200px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48772
|
-
<symphiq-skeleton-loader [width]="'100px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48773
|
-
</div>
|
|
48774
|
-
<div class="space-y-3">
|
|
48775
|
-
@for (j of [1,2,3,4]; track j) {
|
|
48776
|
-
<div class="flex items-center justify-between p-3 rounded-lg" [ngClass]="isLightMode() ? 'bg-slate-50' : 'bg-slate-700/50'">
|
|
48777
|
-
<symphiq-skeleton-loader [width]="'150px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48778
|
-
<symphiq-skeleton-loader [width]="'80px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48779
|
-
</div>
|
|
48780
|
-
}
|
|
48781
|
-
</div>
|
|
48782
|
-
</div>
|
|
48783
|
-
}
|
|
48784
|
-
</div>
|
|
48785
|
-
} @else {
|
|
48786
|
-
<div class="space-y-6" [class.animate-content-change]="isBreakdownTransitioning()" [class.transition-opacity-slow]="isBreakdownTransitioning()">
|
|
48787
|
-
@for (breakdown of breakdowns(); track $index) {
|
|
48788
|
-
<div class="animate-fade-in-up" [style.animation-delay]="(0.8 + $index * 0.1) + 's'"
|
|
48789
|
-
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48790
|
-
[highlightId]="'breakdown-' + $index">
|
|
48791
|
-
<symphiq-funnel-analysis-breakdown-section
|
|
48792
|
-
[breakdown]="breakdown"
|
|
48793
|
-
[charts]="chartsForBreakdown(breakdown)"
|
|
48794
|
-
[isLightMode]="isLightMode()"
|
|
48795
|
-
[isCompactMode]="viewModeService.isCompact()"
|
|
48796
|
-
[currencySymbol]="currencySymbol()" />
|
|
48797
|
-
</div>
|
|
48798
|
-
} @empty {
|
|
48799
|
-
<div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
|
|
48800
|
-
<svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48801
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
|
48802
|
-
</svg>
|
|
48803
|
-
<h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Breakdowns Found</h3>
|
|
48804
|
-
<p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance breakdowns match your current filter selection. Try adjusting your filters to see more results.</p>
|
|
48805
|
-
</div>
|
|
48806
|
-
}
|
|
48807
|
-
</div>
|
|
48808
|
-
}
|
|
48809
|
-
</div>
|
|
48810
|
-
</section>
|
|
48811
|
-
}
|
|
48812
|
-
|
|
48813
|
-
@if (showCompetitiveIntelligence()) {
|
|
48814
|
-
@if (selectedSectionFilter() === 'ALL') {
|
|
48815
|
-
<!-- Section Divider -->
|
|
48816
|
-
<div class="mt-28 sm:mt-36">
|
|
48817
|
-
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.85s"></symphiq-section-divider>
|
|
48818
|
-
</div>
|
|
48819
|
-
}
|
|
48820
|
-
|
|
48821
|
-
<!-- Competitive Intelligence Section -->
|
|
48822
|
-
<section id="section-competitive" class="relative">
|
|
48823
|
-
<!-- Background Pattern -->
|
|
48824
|
-
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-indigo-50/50 to-transparent' : 'bg-gradient-to-br from-indigo-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
|
|
48825
|
-
<div class="relative">
|
|
48826
|
-
<div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.9s;">
|
|
48827
|
-
<div class="flex items-center gap-3">
|
|
48828
|
-
<div [ngClass]="isLightMode() ? 'border-l-4 border-indigo-500' : 'border-l-4 border-indigo-400'" class="pl-4">
|
|
48829
|
-
<div class="flex items-center gap-3">
|
|
48830
|
-
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-indigo-500' : 'text-indigo-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48831
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
48832
|
-
</svg>
|
|
48833
|
-
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Competitive Intelligence</h2>
|
|
48834
|
-
</div>
|
|
48835
|
-
</div>
|
|
48836
|
-
</div>
|
|
48837
|
-
<!-- Filter Dropdown -->
|
|
48838
|
-
<div class="hidden sm:block relative">
|
|
48839
|
-
@if (isCompetitiveTransitioning()) {
|
|
48840
|
-
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48841
|
-
<div class="w-4 h-4 border-2 border-indigo-500/30 border-t-indigo-500 rounded-full animate-spin"></div>
|
|
48842
|
-
</div>
|
|
48843
|
-
}
|
|
48844
|
-
<select
|
|
48845
|
-
[ngModel]="selectedCompetitiveFilter()"
|
|
48846
|
-
(ngModelChange)="changeCompetitiveFilter($event)"
|
|
48847
|
-
[class]="selectClass()"
|
|
48848
|
-
[class.opacity-70]="isCompetitiveTransitioning()"
|
|
48849
|
-
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
|
|
48850
|
-
@for (filter of competitiveFilters; track filter.value) {
|
|
48851
|
-
@if (filter.divider) {
|
|
48852
|
-
<option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
|
|
48853
|
-
} @else {
|
|
48854
|
-
<option [value]="filter.value">{{ filter.label }}</option>
|
|
48855
|
-
}
|
|
48856
|
-
}
|
|
48857
|
-
</select>
|
|
48858
|
-
</div>
|
|
48859
|
-
</div>
|
|
48860
|
-
|
|
48861
|
-
@if (isDataLoading()) {
|
|
48862
|
-
<!-- Competitive Intelligence Skeleton -->
|
|
48863
|
-
<div class="space-y-6">
|
|
48864
|
-
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48865
|
-
<symphiq-skeleton-loader [width]="'60%'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48866
|
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
|
|
48867
|
-
@for (i of [1,2,3]; track i) {
|
|
48868
|
-
<symphiq-skeleton-loader [width]="'100%'" [height]="'140px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48869
|
-
}
|
|
48870
|
-
</div>
|
|
48871
|
-
</div>
|
|
48872
|
-
</div>
|
|
48873
|
-
} @else {
|
|
48874
|
-
<symphiq-competitive-intelligence-view
|
|
48875
|
-
[metrics]="competitiveMetrics()"
|
|
48876
|
-
[allCharts]="allCharts()"
|
|
48877
|
-
[isLightMode]="isLightMode()"
|
|
48878
|
-
[isCompactMode]="viewModeService.isCompact()"
|
|
48879
|
-
[competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
|
|
48880
|
-
[currencySymbol]="currencySymbol()" />
|
|
48881
|
-
}
|
|
48882
|
-
</div>
|
|
48883
|
-
</section>
|
|
48884
|
-
}
|
|
48885
|
-
</div>
|
|
48886
|
-
</main>
|
|
48887
|
-
}
|
|
48888
|
-
|
|
48889
|
-
<symphiq-funnel-analysis-modal
|
|
48890
|
-
[isLightMode]="isLightMode()"
|
|
48891
|
-
[viewMode]="viewMode()"
|
|
48892
|
-
[allMetrics]="allMetrics()"
|
|
48893
|
-
[allInsights]="insights()"
|
|
48894
|
-
[allCharts]="allCharts()"
|
|
48895
|
-
[currencySymbol]="currencySymbol()"
|
|
48896
|
-
[businessProfile]="businessProfile()"></symphiq-funnel-analysis-modal>
|
|
48897
|
-
<symphiq-profile-analysis-modal
|
|
48898
|
-
[isLightMode]="isLightMode()"
|
|
48899
|
-
[allMetrics]="allMetrics()"
|
|
48900
|
-
></symphiq-profile-analysis-modal>
|
|
48901
|
-
<symphiq-business-analysis-modal [isLightMode]="isLightMode()" />
|
|
48902
|
-
<symphiq-tooltip-container></symphiq-tooltip-container>
|
|
48903
|
-
<symphiq-search-bar
|
|
48904
|
-
[isLightMode]="isLightMode()"
|
|
48905
|
-
(resultSelected)="handleSearchResult($event)" />
|
|
48906
|
-
|
|
48907
|
-
<!-- View Mode Switcher Modal -->
|
|
48908
|
-
<symphiq-view-mode-switcher-modal
|
|
48909
|
-
[isOpen]="isViewModeSwitcherOpen()"
|
|
48910
|
-
[currentMode]="displayMode()"
|
|
48911
|
-
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48912
|
-
[isLoading]="isViewModeSwitching()"
|
|
48913
|
-
(close)="closeViewModeSwitcher()"
|
|
48914
|
-
(modeSelected)="handleDisplayModeChange($event)"
|
|
48915
|
-
/>
|
|
48916
|
-
|
|
48917
|
-
<!-- Mobile FAB -->
|
|
48918
|
-
<symphiq-mobile-fab
|
|
48919
|
-
[isLightMode]="isLightMode()"
|
|
48920
|
-
[isCompactMode]="viewModeService.isCompact()"
|
|
48921
|
-
[isExpanded]="fabExpanded()"
|
|
48922
|
-
(expandedChange)="fabExpanded.set($event)"
|
|
48923
|
-
(scrollToTop)="scrollToTop()"
|
|
48924
|
-
(toggleView)="viewModeService.toggleViewMode()" />
|
|
48925
|
-
|
|
48926
|
-
<!-- Mobile Bottom Navigation -->
|
|
48927
|
-
<symphiq-mobile-bottom-nav
|
|
48928
|
-
[isLightMode]="isLightMode()"
|
|
48929
|
-
[sections]="navSections"
|
|
48930
|
-
[activeSection]="activeNavSection()"
|
|
48931
|
-
(navigate)="handleMobileNavigation($event)" />
|
|
48932
|
-
|
|
48933
|
-
</div>
|
|
47939
|
+
], template: `
|
|
47940
|
+
<div
|
|
47941
|
+
class="bg-transparent"
|
|
47942
|
+
[class.min-h-screen]="!embedded()"
|
|
47943
|
+
[class.relative]="!embedded()"
|
|
47944
|
+
[style.display]="embedded() ? 'block' : null"
|
|
47945
|
+
[style.min-height]="embedded() ? 'auto' : null"
|
|
47946
|
+
#dashboardContainer>
|
|
47947
|
+
<!-- Animated Background Bubbles -->
|
|
47948
|
+
<div class="animated-bubbles" [class.light-mode]="isLightMode()" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100vw; height: 100vh; z-index: 1; pointer-events: none;"></div>
|
|
47949
|
+
|
|
47950
|
+
<!-- Scroll Progress Bar -->
|
|
47951
|
+
<div [class]="embedded() ? 'sticky top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30' : 'fixed top-0 left-0 right-0 h-1 z-[60] bg-slate-200/30'">
|
|
47952
|
+
<div
|
|
47953
|
+
[style.width.%]="scrollProgress()"
|
|
47954
|
+
[ngClass]="isLightMode() ? 'bg-gradient-to-r from-blue-500 to-purple-500' : 'bg-gradient-to-r from-blue-400 to-purple-400'"
|
|
47955
|
+
class="h-full transition-all duration-200 ease-out">
|
|
47956
|
+
</div>
|
|
47957
|
+
</div>
|
|
47958
|
+
|
|
47959
|
+
<header [class]="headerClass()" class="sticky top-0 z-50 animate-fade-in" style="animation-delay: 0s;">
|
|
47960
|
+
<!-- Expanded Header (default state) -->
|
|
47961
|
+
<div
|
|
47962
|
+
class="transition-all duration-300 ease-in-out overflow-hidden"
|
|
47963
|
+
[class.max-h-0]="isScrolled()"
|
|
47964
|
+
[class.opacity-0]="isScrolled()"
|
|
47965
|
+
[class.max-h-96]="!isScrolled()"
|
|
47966
|
+
[class.opacity-100]="!isScrolled()">
|
|
47967
|
+
<div
|
|
47968
|
+
class="max-w-7xl mx-auto px-6 sm:px-8 py-6 sm:py-8"
|
|
47969
|
+
[class.pointer-events-none]="isScrolled()"
|
|
47970
|
+
[class.pointer-events-auto]="!isScrolled()">
|
|
47971
|
+
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-0">
|
|
47972
|
+
<div class="flex-1">
|
|
47973
|
+
<div class="flex items-center gap-3">
|
|
47974
|
+
<h1 class="text-2xl sm:text-3xl font-bold mb-2 bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
|
|
47975
|
+
@if (isLoading() && !isShowingLoader()) {
|
|
47976
|
+
<!-- Subtle refresh indicator -->
|
|
47977
|
+
<div class="animate-spin w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full" title="Refreshing data..."></div>
|
|
47978
|
+
}
|
|
47979
|
+
</div>
|
|
47980
|
+
<div class="flex flex-wrap items-center justify-between gap-3 sm:gap-4">
|
|
47981
|
+
<p [class]="headerSubtitleClass()" class="text-sm sm:text-base">Revenue Orchestration & Funnel Analysis</p>
|
|
47982
|
+
<div class="flex items-center gap-4">
|
|
47983
|
+
@if (!isSimplifiedView()) {
|
|
47984
|
+
<!-- Search Button -->
|
|
47985
|
+
<button
|
|
47986
|
+
type="button"
|
|
47987
|
+
(click)="searchService.openSearch(); $event.preventDefault()"
|
|
47988
|
+
[class]="buttonClass()"
|
|
47989
|
+
class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105"
|
|
47990
|
+
title="Search (/ or Cmd+K)">
|
|
47991
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
47992
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
47993
|
+
</svg>
|
|
47994
|
+
<span>Search</span>
|
|
47995
|
+
</button>
|
|
47996
|
+
}
|
|
47997
|
+
<!-- View Mode Switcher Button -->
|
|
47998
|
+
<button
|
|
47999
|
+
type="button"
|
|
48000
|
+
(click)="openViewModeSwitcher(); $event.preventDefault()"
|
|
48001
|
+
[class]="buttonClass()"
|
|
48002
|
+
class="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all duration-200 hover:scale-105">
|
|
48003
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48004
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
48005
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
48006
|
+
</svg>
|
|
48007
|
+
<span>{{ displayModeLabel() }}</span>
|
|
48008
|
+
</button>
|
|
48009
|
+
@if (!isSimplifiedView()) {
|
|
48010
|
+
<div class="flex items-center gap-2 sm:gap-3 whitespace-nowrap">
|
|
48011
|
+
<label [class]="metaLabelClass()" class="text-xs sm:text-sm font-medium">View:</label>
|
|
48012
|
+
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
|
|
48013
|
+
<select
|
|
48014
|
+
[ngModel]="selectedSectionFilter()"
|
|
48015
|
+
(ngModelChange)="changeSectionFilter($event)"
|
|
48016
|
+
[class]="selectClass()"
|
|
48017
|
+
class="px-3 sm:px-4 py-1.5 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
|
|
48018
|
+
@for (section of sectionFilters; track section.value) {
|
|
48019
|
+
<option [value]="section.value">{{ section.label }}</option>
|
|
48020
|
+
}
|
|
48021
|
+
</select>
|
|
48022
|
+
</div>
|
|
48023
|
+
</div>
|
|
48024
|
+
}
|
|
48025
|
+
</div>
|
|
48026
|
+
</div>
|
|
48027
|
+
</div>
|
|
48028
|
+
<div class="flex flex-col gap-4 min-w-[180px]">
|
|
48029
|
+
@if (formattedGeneratedDate()) {
|
|
48030
|
+
<div class="text-left sm:text-right">
|
|
48031
|
+
<div [class]="metaLabelClass()" class="text-xs sm:text-sm">Generated At</div>
|
|
48032
|
+
<div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ formattedGeneratedDate() }}</div>
|
|
48033
|
+
</div>
|
|
48034
|
+
}
|
|
48035
|
+
<div class="text-left sm:text-right">
|
|
48036
|
+
<div [class]="metaLabelClass()" class="text-xs sm:text-sm">Requested by</div>
|
|
48037
|
+
<div [class]="headerTitleClass()" class="text-sm sm:text-base font-medium">{{ requestedByUser()?.firstName }} {{ requestedByUser()?.lastName }}</div>
|
|
48038
|
+
</div>
|
|
48039
|
+
</div>
|
|
48040
|
+
</div>
|
|
48041
|
+
</div>
|
|
48042
|
+
</div>
|
|
48043
|
+
|
|
48044
|
+
<!-- Condensed Header (scrolled state) -->
|
|
48045
|
+
<div
|
|
48046
|
+
class="transition-all duration-300 ease-in-out overflow-hidden"
|
|
48047
|
+
[class.max-h-0]="!isScrolled()"
|
|
48048
|
+
[class.opacity-0]="!isScrolled()"
|
|
48049
|
+
[class.max-h-20]="isScrolled()"
|
|
48050
|
+
[class.opacity-100]="isScrolled()">
|
|
48051
|
+
<div
|
|
48052
|
+
class="max-w-7xl mx-auto px-6 sm:px-8 py-3"
|
|
48053
|
+
[class.pointer-events-none]="!isScrolled()"
|
|
48054
|
+
[class.pointer-events-auto]="isScrolled()">
|
|
48055
|
+
<div class="flex items-center justify-between gap-4">
|
|
48056
|
+
<div class="flex items-center gap-4 flex-1 min-w-0">
|
|
48057
|
+
<h1 class="text-lg font-bold truncate bg-gradient-to-r from-blue-600 via-purple-600 to-indigo-600 bg-clip-text text-transparent">{{analysisData()?.title}}</h1>
|
|
48058
|
+
@if (revenueMetric()) {
|
|
48059
|
+
<div class="hidden lg:flex items-center gap-3 px-4 py-1.5 rounded-lg" [ngClass]="isLightMode() ? 'bg-emerald-50 border border-emerald-200' : 'bg-emerald-500/10 border border-emerald-500/20'">
|
|
48060
|
+
<span [class]="metaLabelClass()" class="text-xs font-medium">Revenue:</span>
|
|
48061
|
+
<span [class]="headerTitleClass()" class="text-sm font-bold">{{ formatValue(revenueValue()) }}</span>
|
|
48062
|
+
<span class="text-xs font-semibold" [ngClass]="revenueTrend() >= 0 ? 'text-emerald-600' : 'text-red-600'">
|
|
48063
|
+
{{ revenueTrend() >= 0 ? '+' : '' }}{{ revenueTrend().toFixed(1) }}%
|
|
48064
|
+
</span>
|
|
48065
|
+
</div>
|
|
48066
|
+
}
|
|
48067
|
+
</div>
|
|
48068
|
+
<div class="flex items-center gap-3">
|
|
48069
|
+
@if (!isSimplifiedView()) {
|
|
48070
|
+
<!-- Search Button (Icon Only in Sticky Header) -->
|
|
48071
|
+
<button
|
|
48072
|
+
type="button"
|
|
48073
|
+
(click)="searchService.openSearch(); $event.preventDefault()"
|
|
48074
|
+
[class]="buttonClass()"
|
|
48075
|
+
title="Search (/ or Cmd+K)"
|
|
48076
|
+
class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
|
|
48077
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48078
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
48079
|
+
</svg>
|
|
48080
|
+
</button>
|
|
48081
|
+
}
|
|
48082
|
+
<!-- View Mode Switcher (Icon Only in Sticky Header) -->
|
|
48083
|
+
<button
|
|
48084
|
+
type="button"
|
|
48085
|
+
(click)="openViewModeSwitcher(); $event.preventDefault()"
|
|
48086
|
+
[class]="buttonClass()"
|
|
48087
|
+
[title]="'Change View Mode: ' + displayModeLabel()"
|
|
48088
|
+
class="p-2 rounded-lg transition-all duration-200 hover:scale-110">
|
|
48089
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48090
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
48091
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
48092
|
+
</svg>
|
|
48093
|
+
</button>
|
|
48094
|
+
@if (!isSimplifiedView()) {
|
|
48095
|
+
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()">
|
|
48096
|
+
<select
|
|
48097
|
+
[ngModel]="selectedSectionFilter()"
|
|
48098
|
+
(ngModelChange)="changeSectionFilter($event)"
|
|
48099
|
+
[class]="selectClass()"
|
|
48100
|
+
class="px-3 py-1.5 rounded-lg text-xs font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200 cursor-pointer">
|
|
48101
|
+
@for (section of sectionFilters; track section.value) {
|
|
48102
|
+
<option [value]="section.value">{{ section.label }}</option>
|
|
48103
|
+
}
|
|
48104
|
+
</select>
|
|
48105
|
+
</div>
|
|
48106
|
+
}
|
|
48107
|
+
</div>
|
|
48108
|
+
</div>
|
|
48109
|
+
</div>
|
|
48110
|
+
</div>
|
|
48111
|
+
</header>
|
|
48112
|
+
|
|
48113
|
+
<!-- Search Breadcrumb -->
|
|
48114
|
+
@if (searchService.activeSearchResult()) {
|
|
48115
|
+
<div [ngClass]="isLightMode() ? 'bg-blue-50/95 border-blue-200' : 'bg-blue-900/20 border-blue-800/30'" class="sticky top-[var(--header-height)] z-40 border-b backdrop-blur-md animate-slide-up-fade">
|
|
48116
|
+
<div class="max-w-7xl mx-auto px-6 sm:px-8 py-3">
|
|
48117
|
+
<div class="flex items-center justify-between gap-4">
|
|
48118
|
+
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
48119
|
+
<svg [ngClass]="isLightMode() ? 'text-blue-600' : 'text-blue-400'" class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48120
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
48121
|
+
</svg>
|
|
48122
|
+
<div class="flex items-center gap-2 flex-1 min-w-0">
|
|
48123
|
+
<span [ngClass]="isLightMode() ? 'text-blue-900' : 'text-blue-100'" class="text-sm font-medium">Showing:</span>
|
|
48124
|
+
<span [ngClass]="isLightMode() ? 'text-blue-700' : 'text-blue-300'" class="text-sm font-semibold truncate">
|
|
48125
|
+
{{ searchService.activeSearchResult()!.title }}
|
|
48126
|
+
</span>
|
|
48127
|
+
<span [ngClass]="isLightMode() ? 'bg-blue-100 text-blue-700 border-blue-200' : 'bg-blue-800/50 text-blue-300 border-blue-700/50'" class="px-2 py-0.5 rounded text-xs font-medium uppercase border flex-shrink-0">
|
|
48128
|
+
{{ searchService.activeSearchResult()!.type }}
|
|
48129
|
+
</span>
|
|
48130
|
+
</div>
|
|
48131
|
+
</div>
|
|
48132
|
+
<button
|
|
48133
|
+
(click)="clearSearchResult(); $event.stopPropagation()"
|
|
48134
|
+
[ngClass]="isLightMode() ? 'text-blue-600 hover:text-blue-800 hover:bg-blue-100' : 'text-blue-400 hover:text-blue-200 hover:bg-blue-800/50'"
|
|
48135
|
+
class="p-2 rounded-lg transition-colors flex-shrink-0"
|
|
48136
|
+
title="Clear search">
|
|
48137
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48138
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
48139
|
+
</svg>
|
|
48140
|
+
</button>
|
|
48141
|
+
</div>
|
|
48142
|
+
</div>
|
|
48143
|
+
</div>
|
|
48144
|
+
}
|
|
48145
|
+
|
|
48146
|
+
<!-- Floating Table of Contents -->
|
|
48147
|
+
@if (!isSimplifiedView()) {
|
|
48148
|
+
<symphiq-floating-toc
|
|
48149
|
+
[sections]="tocSections()"
|
|
48150
|
+
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48151
|
+
[embedded]="embedded()"
|
|
48152
|
+
[scrollElement]="scrollElement() ?? undefined"
|
|
48153
|
+
/>
|
|
48154
|
+
}
|
|
48155
|
+
|
|
48156
|
+
<!-- Quick Navigation Dots -->
|
|
48157
|
+
@if (!isSimplifiedView()) {
|
|
48158
|
+
<div class="fixed right-6 top-1/2 -translate-y-1/2 z-40 hidden xl:flex flex-col gap-4">
|
|
48159
|
+
@if (showOverallPerformance()) {
|
|
48160
|
+
<button
|
|
48161
|
+
(click)="scrollToTop()"
|
|
48162
|
+
[libSymphiqTooltip]="'Scroll to Top'"
|
|
48163
|
+
[tooltipPosition]="'left'"
|
|
48164
|
+
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48165
|
+
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48166
|
+
</button>
|
|
48167
|
+
}
|
|
48168
|
+
@if (showKeyInsights()) {
|
|
48169
|
+
<button
|
|
48170
|
+
(click)="scrollToSection('section-insights')"
|
|
48171
|
+
[libSymphiqTooltip]="'Key Insights'"
|
|
48172
|
+
[tooltipPosition]="'left'"
|
|
48173
|
+
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48174
|
+
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48175
|
+
</button>
|
|
48176
|
+
}
|
|
48177
|
+
@if (showPerformanceMetrics()) {
|
|
48178
|
+
<button
|
|
48179
|
+
(click)="scrollToSection('section-metrics')"
|
|
48180
|
+
[libSymphiqTooltip]="'Performance Metrics'"
|
|
48181
|
+
[tooltipPosition]="'left'"
|
|
48182
|
+
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48183
|
+
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48184
|
+
</button>
|
|
48185
|
+
}
|
|
48186
|
+
@if (showPerformanceBreakdowns()) {
|
|
48187
|
+
<button
|
|
48188
|
+
(click)="scrollToSection('section-breakdowns')"
|
|
48189
|
+
[libSymphiqTooltip]="'Performance Breakdowns'"
|
|
48190
|
+
[tooltipPosition]="'left'"
|
|
48191
|
+
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-blue-500' : 'bg-slate-600 hover:bg-blue-400'"
|
|
48192
|
+
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48193
|
+
</button>
|
|
48194
|
+
}
|
|
48195
|
+
@if (showCompetitiveIntelligence()) {
|
|
48196
|
+
<button
|
|
48197
|
+
(click)="scrollToSection('section-competitive')"
|
|
48198
|
+
[libSymphiqTooltip]="'Competitive Intelligence'"
|
|
48199
|
+
[tooltipPosition]="'left'"
|
|
48200
|
+
[ngClass]="isLightMode() ? 'bg-slate-300 hover:bg-indigo-500' : 'bg-slate-600 hover:bg-indigo-400'"
|
|
48201
|
+
class="w-3 h-3 rounded-full transition-all duration-200 hover:scale-150 active:scale-100 cursor-pointer">
|
|
48202
|
+
</button>
|
|
48203
|
+
}
|
|
48204
|
+
</div>
|
|
48205
|
+
}
|
|
48206
|
+
|
|
48207
|
+
@if (isSimplifiedView()) {
|
|
48208
|
+
<!-- Journey Progress Banner -->
|
|
48209
|
+
@if (!isOnboarded()) {
|
|
48210
|
+
<symphiq-journey-progress-indicator
|
|
48211
|
+
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48212
|
+
[currentStepId]="JourneyStepIdEnum.FUNNEL_ANALYSIS"
|
|
48213
|
+
[showNextStepAction]="true"
|
|
48214
|
+
[forDemo]="forDemo()"
|
|
48215
|
+
[maxAccessibleStepId]="maxAccessibleStepId()"
|
|
48216
|
+
(stepClick)="stepClick.emit($event)"
|
|
48217
|
+
(nextStepClick)="nextStepClick.emit()"
|
|
48218
|
+
/>
|
|
48219
|
+
}
|
|
48220
|
+
|
|
48221
|
+
<main class="max-w-7xl mx-auto px-6 sm:px-8">
|
|
48222
|
+
<div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
|
|
48223
|
+
<!-- Welcome Banner -->
|
|
48224
|
+
<div class="mb-8">
|
|
48225
|
+
<symphiq-funnel-welcome-banner
|
|
48226
|
+
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48227
|
+
[isOnboarded]="isOnboarded()"
|
|
48228
|
+
/>
|
|
48229
|
+
</div>
|
|
48230
|
+
|
|
48231
|
+
<!-- Key Insights Section -->
|
|
48232
|
+
@if (showKeyInsights()) {
|
|
48233
|
+
<section id="section-insights" class="mb-8">
|
|
48234
|
+
<div class="flex items-center justify-between mb-6">
|
|
48235
|
+
<div class="flex items-center gap-3">
|
|
48236
|
+
<div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
|
|
48237
|
+
<div class="flex items-center gap-3">
|
|
48238
|
+
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48239
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
|
|
48240
|
+
</svg>
|
|
48241
|
+
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
|
|
48242
|
+
</div>
|
|
48243
|
+
</div>
|
|
48244
|
+
</div>
|
|
48245
|
+
<span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
|
|
48246
|
+
</div>
|
|
48247
|
+
|
|
48248
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
48249
|
+
@for (insight of insights(); track $index) {
|
|
48250
|
+
<symphiq-funnel-analysis-insight-card
|
|
48251
|
+
[insight]="insight"
|
|
48252
|
+
[allMetrics]="allMetrics()"
|
|
48253
|
+
[charts]="chartsForInsight(insight)"
|
|
48254
|
+
[allCharts]="allCharts()"
|
|
48255
|
+
[allBusinessInsights]="allBusinessInsights()"
|
|
48256
|
+
[isLightMode]="isLightMode()"
|
|
48257
|
+
[viewMode]="viewMode()"
|
|
48258
|
+
[isCompactMode]="true"
|
|
48259
|
+
[isLoading]="isDataLoading()" />
|
|
48260
|
+
}
|
|
48261
|
+
</div>
|
|
48262
|
+
</section>
|
|
48263
|
+
}
|
|
48264
|
+
|
|
48265
|
+
<!-- Supporting Data Section -->
|
|
48266
|
+
<symphiq-collapsible-funnel-section-group
|
|
48267
|
+
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK">
|
|
48268
|
+
<!-- Overall Performance Slot -->
|
|
48269
|
+
<div slot="overall-performance">
|
|
48270
|
+
@if (showOverallPerformance()) {
|
|
48271
|
+
<div class="p-6">
|
|
48272
|
+
@if (isDataLoading()) {
|
|
48273
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48274
|
+
} @else {
|
|
48275
|
+
<symphiq-funnel-analysis-overall-assessment
|
|
48276
|
+
[assessment]="performanceOverview().overallAssessment || {}"
|
|
48277
|
+
[revenueMetric]="revenueMetric()"
|
|
48278
|
+
[charts]="chartsForItem('OVERALL_ASSESSMENT')"
|
|
48279
|
+
[metrics]="allMetrics()"
|
|
48280
|
+
[isLightMode]="isLightMode()"
|
|
48281
|
+
[isLoading]="isOverallAssessmentLoading()"
|
|
48282
|
+
[isCompactMode]="true"
|
|
48283
|
+
[isChartsLoading]="areChartsLoading()"
|
|
48284
|
+
[strengths]="strengths()"
|
|
48285
|
+
[weaknesses]="weaknesses()"
|
|
48286
|
+
[currencySymbol]="currencySymbol()"
|
|
48287
|
+
(scrollToSection)="scrollToSection($event)" />
|
|
48288
|
+
}
|
|
48289
|
+
</div>
|
|
48290
|
+
}
|
|
48291
|
+
</div>
|
|
48292
|
+
|
|
48293
|
+
<!-- Performance Metrics Slot -->
|
|
48294
|
+
<div slot="performance-metrics">
|
|
48295
|
+
@if (showPerformanceMetrics()) {
|
|
48296
|
+
<div class="p-6 space-y-8">
|
|
48297
|
+
@for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
|
|
48298
|
+
<!-- Funnel Stage Metric (Full Width) -->
|
|
48299
|
+
<div class="w-full">
|
|
48300
|
+
<symphiq-funnel-analysis-metric-card
|
|
48301
|
+
[metric]="funnelGroup.funnelMetric"
|
|
48302
|
+
[insights]="insights()"
|
|
48303
|
+
[charts]="chartsForMetric(funnelGroup.funnelMetric)"
|
|
48304
|
+
[allCharts]="allCharts()"
|
|
48305
|
+
[analysis]="analysisData()"
|
|
48306
|
+
[isLightMode]="isLightMode()"
|
|
48307
|
+
[viewMode]="viewMode()"
|
|
48308
|
+
[isCompactMode]="true"
|
|
48309
|
+
[currencySymbol]="currencySymbol()" />
|
|
48310
|
+
</div>
|
|
48311
|
+
<!-- Related Metrics (Grid Layout) -->
|
|
48312
|
+
@if (funnelGroup.relatedMetrics.length > 0) {
|
|
48313
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-4">
|
|
48314
|
+
@for (metric of funnelGroup.relatedMetrics; track $index) {
|
|
48315
|
+
<symphiq-funnel-analysis-metric-card
|
|
48316
|
+
[metric]="metric"
|
|
48317
|
+
[insights]="insights()"
|
|
48318
|
+
[charts]="chartsForMetric(metric)"
|
|
48319
|
+
[allCharts]="allCharts()"
|
|
48320
|
+
[analysis]="analysisData()"
|
|
48321
|
+
[isLightMode]="isLightMode()"
|
|
48322
|
+
[viewMode]="viewMode()"
|
|
48323
|
+
[isCompactMode]="true"
|
|
48324
|
+
[currencySymbol]="currencySymbol()" />
|
|
48325
|
+
}
|
|
48326
|
+
</div>
|
|
48327
|
+
}
|
|
48328
|
+
}
|
|
48329
|
+
</div>
|
|
48330
|
+
}
|
|
48331
|
+
</div>
|
|
48332
|
+
|
|
48333
|
+
<!-- Performance Breakdowns Slot -->
|
|
48334
|
+
<div slot="performance-breakdowns">
|
|
48335
|
+
@if (showPerformanceBreakdowns()) {
|
|
48336
|
+
<div class="p-6 space-y-8">
|
|
48337
|
+
@for (breakdown of breakdowns(); track $index) {
|
|
48338
|
+
<symphiq-funnel-analysis-breakdown-section
|
|
48339
|
+
[breakdown]="breakdown"
|
|
48340
|
+
[charts]="chartsForBreakdown(breakdown)"
|
|
48341
|
+
[isLightMode]="isLightMode()"
|
|
48342
|
+
[isLoading]="isDataLoading()"
|
|
48343
|
+
[isCompactMode]="true"
|
|
48344
|
+
[currencySymbol]="currencySymbol()" />
|
|
48345
|
+
}
|
|
48346
|
+
</div>
|
|
48347
|
+
}
|
|
48348
|
+
</div>
|
|
48349
|
+
|
|
48350
|
+
<!-- Competitive Intelligence Slot -->
|
|
48351
|
+
<div slot="competitive-intelligence">
|
|
48352
|
+
@if (showCompetitiveIntelligence()) {
|
|
48353
|
+
<div class="p-6">
|
|
48354
|
+
<symphiq-competitive-intelligence-view
|
|
48355
|
+
[metrics]="competitiveMetrics()"
|
|
48356
|
+
[allCharts]="allCharts()"
|
|
48357
|
+
[isLightMode]="isLightMode()"
|
|
48358
|
+
[isCompactMode]="true"
|
|
48359
|
+
[competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
|
|
48360
|
+
[currencySymbol]="currencySymbol()" />
|
|
48361
|
+
</div>
|
|
48362
|
+
}
|
|
48363
|
+
</div>
|
|
48364
|
+
</symphiq-collapsible-funnel-section-group>
|
|
48365
|
+
</div>
|
|
48366
|
+
</main>
|
|
48367
|
+
} @else {
|
|
48368
|
+
<main class="max-w-7xl mx-auto px-6 sm:px-8">
|
|
48369
|
+
<div class="pt-8 sm:pt-12 pb-16 sm:pb-24">
|
|
48370
|
+
@if (showOverallPerformance()) {
|
|
48371
|
+
<div id="section-overall" class="animate-fade-in-up mb-20 sm:mb-28" style="animation-delay: 0.1s;">
|
|
48372
|
+
@if (isDataLoading()) {
|
|
48373
|
+
<!-- Overall Assessment Skeleton -->
|
|
48374
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 sm:p-8 animate-pulse">
|
|
48375
|
+
<div class="space-y-6">
|
|
48376
|
+
<!-- Header -->
|
|
48377
|
+
<div class="flex items-center gap-3">
|
|
48378
|
+
<symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48379
|
+
<div class="flex-1 space-y-2">
|
|
48380
|
+
<symphiq-skeleton-loader [width]="'40%'" [height]="'32px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48381
|
+
<symphiq-skeleton-loader [width]="'60%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48382
|
+
</div>
|
|
48383
|
+
</div>
|
|
48384
|
+
<!-- Summary text -->
|
|
48385
|
+
<div class="space-y-2">
|
|
48386
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48387
|
+
<symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48388
|
+
<symphiq-skeleton-loader [width]="'90%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48389
|
+
</div>
|
|
48390
|
+
<!-- Chart placeholder -->
|
|
48391
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
|
|
48392
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48393
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'200px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48394
|
+
</div>
|
|
48395
|
+
</div>
|
|
48396
|
+
</div>
|
|
48397
|
+
} @else {
|
|
48398
|
+
<symphiq-funnel-analysis-overall-assessment
|
|
48399
|
+
[assessment]="performanceOverview().overallAssessment || {}"
|
|
48400
|
+
[revenueMetric]="revenueMetric()"
|
|
48401
|
+
[charts]="chartsForItem('OVERALL_ASSESSMENT')"
|
|
48402
|
+
[metrics]="allMetrics()"
|
|
48403
|
+
[isLightMode]="isLightMode()"
|
|
48404
|
+
[isLoading]="isOverallAssessmentLoading()"
|
|
48405
|
+
[isCompactMode]="viewModeService.isCompact()"
|
|
48406
|
+
[isChartsLoading]="areChartsLoading()"
|
|
48407
|
+
[strengths]="strengths()"
|
|
48408
|
+
[weaknesses]="weaknesses()"
|
|
48409
|
+
[currencySymbol]="currencySymbol()"
|
|
48410
|
+
(scrollToSection)="scrollToSection($event)" />
|
|
48411
|
+
}
|
|
48412
|
+
</div>
|
|
48413
|
+
}
|
|
48414
|
+
|
|
48415
|
+
@if (showKeyInsights()) {
|
|
48416
|
+
@if (selectedSectionFilter() === 'ALL') {
|
|
48417
|
+
<!-- Section Divider -->
|
|
48418
|
+
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.15s"></symphiq-section-divider>
|
|
48419
|
+
}
|
|
48420
|
+
|
|
48421
|
+
<section id="section-insights" class="relative">
|
|
48422
|
+
<!-- Background Pattern -->
|
|
48423
|
+
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-blue-50/50 to-transparent' : 'bg-gradient-to-br from-blue-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
|
|
48424
|
+
<div class="relative">
|
|
48425
|
+
<div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.2s;">
|
|
48426
|
+
<div class="flex items-center gap-3">
|
|
48427
|
+
<div [ngClass]="isLightMode() ? 'border-l-4 border-blue-500' : 'border-l-4 border-blue-400'" class="pl-4">
|
|
48428
|
+
<div class="flex items-center gap-3">
|
|
48429
|
+
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-blue-500' : 'text-blue-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48430
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
|
|
48431
|
+
</svg>
|
|
48432
|
+
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Key Insights</h2>
|
|
48433
|
+
</div>
|
|
48434
|
+
</div>
|
|
48435
|
+
</div>
|
|
48436
|
+
<span [class]="metaLabelClass()" class="text-xs sm:text-sm">{{ insights().length }} insights</span>
|
|
48437
|
+
</div>
|
|
48438
|
+
<!-- Masonry Layout for Insights -->
|
|
48439
|
+
@if (isDataLoading() || (viewModeService.isExpanded() && viewModeService.getIsTransitioning())) {
|
|
48440
|
+
<!-- Skeleton loaders during data loading or transition to expanded view -->
|
|
48441
|
+
<div class="masonry-grid">
|
|
48442
|
+
@for (i of [1,2,3,4,5,6]; track i) {
|
|
48443
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[280px]">
|
|
48444
|
+
<div class="space-y-4">
|
|
48445
|
+
<div class="flex items-center gap-3 mb-4">
|
|
48446
|
+
<symphiq-skeleton-loader [width]="'48px'" [height]="'48px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48447
|
+
<symphiq-skeleton-loader [width]="'60%'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48448
|
+
</div>
|
|
48449
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48450
|
+
<symphiq-skeleton-loader [width]="'95%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48451
|
+
<symphiq-skeleton-loader [width]="'85%'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48452
|
+
<div class="mt-6 space-y-2">
|
|
48453
|
+
<symphiq-skeleton-loader [width]="'40%'" [height]="'14px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48454
|
+
<symphiq-skeleton-loader [width]="'50%'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48455
|
+
</div>
|
|
48456
|
+
<div class="flex gap-2 mt-4">
|
|
48457
|
+
<symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48458
|
+
<symphiq-skeleton-loader [width]="'80px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48459
|
+
</div>
|
|
48460
|
+
</div>
|
|
48461
|
+
</div>
|
|
48462
|
+
}
|
|
48463
|
+
</div>
|
|
48464
|
+
} @else if (viewModeService.isExpanded()) {
|
|
48465
|
+
<div class="masonry-grid">
|
|
48466
|
+
@for (insight of insights(); track $index) {
|
|
48467
|
+
<div
|
|
48468
|
+
[class]="getInsightCardClass(insight)"
|
|
48469
|
+
class="animate-fade-in-up"
|
|
48470
|
+
[style.animation-delay]="(0.3 + $index * 0.1) + 's'"
|
|
48471
|
+
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48472
|
+
[highlightId]="'insight-' + $index">
|
|
48473
|
+
<symphiq-funnel-analysis-insight-card
|
|
48474
|
+
[insight]="insight"
|
|
48475
|
+
[allMetrics]="allMetrics()"
|
|
48476
|
+
[charts]="chartsForInsight(insight)"
|
|
48477
|
+
[allCharts]="allCharts()"
|
|
48478
|
+
[allBusinessInsights]="allBusinessInsights()"
|
|
48479
|
+
[isLightMode]="isLightMode()"
|
|
48480
|
+
[viewMode]="viewMode()"
|
|
48481
|
+
[isCompactMode]="false" />
|
|
48482
|
+
</div>
|
|
48483
|
+
}
|
|
48484
|
+
</div>
|
|
48485
|
+
} @else {
|
|
48486
|
+
<!-- Compact Grid for Insights -->
|
|
48487
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
48488
|
+
@for (insight of insights(); track $index) {
|
|
48489
|
+
<div class="animate-fade-in-up" [style.animation-delay]="(0.3 + $index * 0.1) + 's'"
|
|
48490
|
+
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48491
|
+
[highlightId]="'insight-' + $index">
|
|
48492
|
+
<symphiq-funnel-analysis-insight-card
|
|
48493
|
+
[insight]="insight"
|
|
48494
|
+
[allMetrics]="allMetrics()"
|
|
48495
|
+
[charts]="chartsForInsight(insight)"
|
|
48496
|
+
[allCharts]="allCharts()"
|
|
48497
|
+
[allBusinessInsights]="allBusinessInsights()"
|
|
48498
|
+
[isLightMode]="isLightMode()"
|
|
48499
|
+
[viewMode]="viewMode()"
|
|
48500
|
+
[isCompactMode]="true" />
|
|
48501
|
+
</div>
|
|
48502
|
+
}
|
|
48503
|
+
</div>
|
|
48504
|
+
}
|
|
48505
|
+
</div>
|
|
48506
|
+
</section>
|
|
48507
|
+
}
|
|
48508
|
+
|
|
48509
|
+
@if (showPerformanceMetrics()) {
|
|
48510
|
+
@if (selectedSectionFilter() === 'ALL') {
|
|
48511
|
+
<!-- Section Divider -->
|
|
48512
|
+
<div class="relative mb-14 sm:mb-24 mt-24 sm:mt-32 animate-fade-in" style="animation-delay: 0.35s;">
|
|
48513
|
+
<div class="absolute inset-0 flex items-center" aria-hidden="true">
|
|
48514
|
+
<div class="w-full h-px bg-gradient-to-r" [ngClass]="isLightMode() ? 'from-transparent via-emerald-500/30 to-transparent' : 'from-transparent via-emerald-400/20 to-transparent'"></div>
|
|
48515
|
+
</div>
|
|
48516
|
+
<div class="relative flex justify-center">
|
|
48517
|
+
<div class="px-4 py-2 rounded-full" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-emerald-50 to-teal-50 border border-emerald-200/50 shadow-lg shadow-emerald-500/10' : 'bg-gradient-to-br from-slate-900 to-slate-800 border border-emerald-500/20 shadow-lg shadow-emerald-500/5'">
|
|
48518
|
+
<svg class="w-5 h-5" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48519
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
|
|
48520
|
+
</svg>
|
|
48521
|
+
</div>
|
|
48522
|
+
</div>
|
|
48523
|
+
</div>
|
|
48524
|
+
}
|
|
48525
|
+
|
|
48526
|
+
<section id="section-metrics" class="relative">
|
|
48527
|
+
<!-- Background Pattern -->
|
|
48528
|
+
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tl from-emerald-50/50 to-transparent' : 'bg-gradient-to-tl from-emerald-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at top right, black 0%, transparent 70%);"></div>
|
|
48529
|
+
<div class="relative">
|
|
48530
|
+
<div class="flex flex-col gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.4s;">
|
|
48531
|
+
<div class="flex items-center justify-between">
|
|
48532
|
+
<div class="flex items-center gap-3">
|
|
48533
|
+
<div [ngClass]="isLightMode() ? 'border-l-4 border-emerald-500' : 'border-l-4 border-emerald-400'" class="pl-4">
|
|
48534
|
+
<div class="flex items-center gap-3">
|
|
48535
|
+
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-emerald-500' : 'text-emerald-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48536
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
|
48537
|
+
</svg>
|
|
48538
|
+
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Metrics</h2>
|
|
48539
|
+
</div>
|
|
48540
|
+
</div>
|
|
48541
|
+
</div>
|
|
48542
|
+
<!-- Desktop controls -->
|
|
48543
|
+
<div class="hidden sm:flex gap-2 sm:gap-3 items-center relative">
|
|
48544
|
+
@if (isCategoryTransitioning()) {
|
|
48545
|
+
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48546
|
+
<div class="w-4 h-4 border-2 border-blue-500/30 border-t-blue-500 rounded-full animate-spin"></div>
|
|
48547
|
+
</div>
|
|
48548
|
+
}
|
|
48549
|
+
<select
|
|
48550
|
+
[ngModel]="selectedCategory()"
|
|
48551
|
+
(ngModelChange)="changeCategoryFilter($event)"
|
|
48552
|
+
[class]="selectClass()"
|
|
48553
|
+
[class.opacity-70]="isCategoryTransitioning()"
|
|
48554
|
+
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
|
|
48555
|
+
@for (cat of categories; track cat.value) {
|
|
48556
|
+
@if (cat.divider) {
|
|
48557
|
+
<option [value]="cat.value" disabled class="font-semibold">{{ cat.label }}</option>
|
|
48558
|
+
} @else {
|
|
48559
|
+
<option [value]="cat.value">{{ cat.label }}</option>
|
|
48560
|
+
}
|
|
48561
|
+
}
|
|
48562
|
+
</select>
|
|
48563
|
+
<button
|
|
48564
|
+
(click)="toggleSortOrder()"
|
|
48565
|
+
[class]="sortButtonClass()"
|
|
48566
|
+
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all flex items-center gap-2 cursor-pointer hover:scale-105 active:scale-95"
|
|
48567
|
+
[title]="reverseSortOrder() ? 'Sort: Revenue to Views' : 'Sort: Views to Revenue'">
|
|
48568
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48569
|
+
@if (!reverseSortOrder()) {
|
|
48570
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"></path>
|
|
48571
|
+
}
|
|
48572
|
+
@if (reverseSortOrder()) {
|
|
48573
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"></path>
|
|
48574
|
+
}
|
|
48575
|
+
</svg>
|
|
48576
|
+
<span>Sort</span>
|
|
48577
|
+
</button>
|
|
48578
|
+
</div>
|
|
48579
|
+
</div>
|
|
48580
|
+
|
|
48581
|
+
<!-- Mobile horizontal scrolling category pills -->
|
|
48582
|
+
<div class="sm:hidden -mx-6 px-6">
|
|
48583
|
+
<div class="flex gap-2 overflow-x-auto pb-2 snap-x snap-mandatory scrollbar-hide">
|
|
48584
|
+
@for (cat of categories; track cat.value) {
|
|
48585
|
+
@if (!cat.divider) {
|
|
48586
|
+
<button
|
|
48587
|
+
(click)="changeCategoryFilter(cat.value)"
|
|
48588
|
+
[ngClass]="getCategoryPillClass(cat.value)"
|
|
48589
|
+
[class.opacity-70]="isCategoryTransitioning()"
|
|
48590
|
+
class="px-4 py-2 rounded-full text-xs font-medium whitespace-nowrap transition-all duration-200 flex-shrink-0 snap-start active:scale-95">
|
|
48591
|
+
{{ cat.label }}
|
|
48592
|
+
</button>
|
|
48593
|
+
}
|
|
48594
|
+
}
|
|
48595
|
+
</div>
|
|
48596
|
+
</div>
|
|
48597
|
+
</div>
|
|
48598
|
+
@if (isDataLoading()) {
|
|
48599
|
+
<!-- Metrics Skeleton -->
|
|
48600
|
+
<div class="space-y-8 sm:space-y-10">
|
|
48601
|
+
@for (i of [1,2,3]; track i) {
|
|
48602
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48603
|
+
<div class="flex items-center justify-between mb-4">
|
|
48604
|
+
<div class="flex items-center gap-3">
|
|
48605
|
+
<symphiq-skeleton-loader [width]="'40px'" [height]="'40px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48606
|
+
<div class="space-y-2">
|
|
48607
|
+
<symphiq-skeleton-loader [width]="'150px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48608
|
+
<symphiq-skeleton-loader [width]="'100px'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48609
|
+
</div>
|
|
48610
|
+
</div>
|
|
48611
|
+
<symphiq-skeleton-loader [width]="'80px'" [height]="'36px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48612
|
+
</div>
|
|
48613
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
|
|
48614
|
+
@for (j of [1,2,3,4]; track j) {
|
|
48615
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48616
|
+
}
|
|
48617
|
+
</div>
|
|
48618
|
+
</div>
|
|
48619
|
+
}
|
|
48620
|
+
</div>
|
|
48621
|
+
} @else {
|
|
48622
|
+
<div class="space-y-8 sm:space-y-10" [class.animate-content-change]="isCategoryTransitioning()" [class.transition-opacity-slow]="isCategoryTransitioning()">
|
|
48623
|
+
@for (funnelGroup of groupedMetrics(); track $index; let groupIdx = $index) {
|
|
48624
|
+
<div class="w-full animate-fade-in-up" [style.animation-delay]="(0.5 + groupIdx * 0.15) + 's'"
|
|
48625
|
+
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48626
|
+
[highlightId]="'metric-' + groupIdx">
|
|
48627
|
+
<symphiq-funnel-analysis-metric-card
|
|
48628
|
+
[metric]="funnelGroup.funnelMetric"
|
|
48629
|
+
[insights]="insights()"
|
|
48630
|
+
[charts]="chartsForMetric(funnelGroup.funnelMetric)"
|
|
48631
|
+
[allCharts]="allCharts()"
|
|
48632
|
+
[analysis]="analysisData()"
|
|
48633
|
+
[isLightMode]="isLightMode()"
|
|
48634
|
+
[viewMode]="viewMode()"
|
|
48635
|
+
[isCompactMode]="viewModeService.isCompact()"
|
|
48636
|
+
[currencySymbol]="currencySymbol()" />
|
|
48637
|
+
</div>
|
|
48638
|
+
@if (funnelGroup.relatedMetrics.length > 0) {
|
|
48639
|
+
<!-- Bento Box Grid Layout -->
|
|
48640
|
+
@if (viewModeService.isExpanded()) {
|
|
48641
|
+
<div class="bento-grid mt-4">
|
|
48642
|
+
@for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
|
|
48643
|
+
<div
|
|
48644
|
+
[class]="getBentoCardClass(metric, metricIdx)"
|
|
48645
|
+
class="animate-fade-in-up"
|
|
48646
|
+
[style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
|
|
48647
|
+
<symphiq-funnel-analysis-metric-card
|
|
48648
|
+
class="h-full"
|
|
48649
|
+
[metric]="metric"
|
|
48650
|
+
[insights]="insights()"
|
|
48651
|
+
[charts]="chartsForMetric(metric)"
|
|
48652
|
+
[allCharts]="allCharts()"
|
|
48653
|
+
[analysis]="analysisData()"
|
|
48654
|
+
[isLightMode]="isLightMode()"
|
|
48655
|
+
[viewMode]="viewMode()"
|
|
48656
|
+
[isCompactMode]="false"
|
|
48657
|
+
[currencySymbol]="currencySymbol()" />
|
|
48658
|
+
</div>
|
|
48659
|
+
}
|
|
48660
|
+
</div>
|
|
48661
|
+
} @else if (!viewModeService.isExpanded()) {
|
|
48662
|
+
<!-- Compact Grid Layout -->
|
|
48663
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mt-4">
|
|
48664
|
+
@for (metric of funnelGroup.relatedMetrics; track $index; let metricIdx = $index) {
|
|
48665
|
+
<div class="animate-fade-in-up" [style.animation-delay]="(0.6 + groupIdx * 0.15 + metricIdx * 0.08) + 's'">
|
|
48666
|
+
<symphiq-funnel-analysis-metric-card
|
|
48667
|
+
[metric]="metric"
|
|
48668
|
+
[insights]="insights()"
|
|
48669
|
+
[charts]="chartsForMetric(metric)"
|
|
48670
|
+
[allCharts]="allCharts()"
|
|
48671
|
+
[analysis]="analysisData()"
|
|
48672
|
+
[isLightMode]="isLightMode()"
|
|
48673
|
+
[viewMode]="viewMode()"
|
|
48674
|
+
[isCompactMode]="true"
|
|
48675
|
+
[currencySymbol]="currencySymbol()" />
|
|
48676
|
+
</div>
|
|
48677
|
+
}
|
|
48678
|
+
</div>
|
|
48679
|
+
} @else {
|
|
48680
|
+
<!-- Skeleton loaders during transition to expanded view -->
|
|
48681
|
+
<div class="bento-grid mt-4">
|
|
48682
|
+
@for (i of [1,2,3,4]; track i) {
|
|
48683
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse min-h-[240px]">
|
|
48684
|
+
<div class="space-y-4">
|
|
48685
|
+
<div class="flex items-center justify-between">
|
|
48686
|
+
<symphiq-skeleton-loader [width]="'60%'" [height]="'22px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48687
|
+
<symphiq-skeleton-loader [width]="'60px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48688
|
+
</div>
|
|
48689
|
+
<symphiq-skeleton-loader [width]="'45%'" [height]="'42px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48690
|
+
<div class="flex items-center gap-3 mt-4">
|
|
48691
|
+
<symphiq-skeleton-loader [width]="'24px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48692
|
+
<symphiq-skeleton-loader [width]="'30%'" [height]="'20px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48693
|
+
</div>
|
|
48694
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48695
|
+
<symphiq-skeleton-loader [width]="'85%'" [height]="'16px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48696
|
+
<div class="mt-4">
|
|
48697
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'120px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48698
|
+
</div>
|
|
48699
|
+
</div>
|
|
48700
|
+
</div>
|
|
48701
|
+
}
|
|
48702
|
+
</div>
|
|
48703
|
+
}
|
|
48704
|
+
}
|
|
48705
|
+
} @empty {
|
|
48706
|
+
<div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
|
|
48707
|
+
<svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48708
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
|
48709
|
+
</svg>
|
|
48710
|
+
<h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Metrics Found</h3>
|
|
48711
|
+
<p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance metrics match your current filter selection. Try adjusting your filters to see more results.</p>
|
|
48712
|
+
</div>
|
|
48713
|
+
}
|
|
48714
|
+
</div>
|
|
48715
|
+
}
|
|
48716
|
+
</div>
|
|
48717
|
+
</section>
|
|
48718
|
+
}
|
|
48719
|
+
|
|
48720
|
+
@if (showPerformanceBreakdowns()) {
|
|
48721
|
+
@if (selectedSectionFilter() === 'ALL') {
|
|
48722
|
+
<!-- Section Divider -->
|
|
48723
|
+
<div class="mt-28 sm:mt-36">
|
|
48724
|
+
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.65s"></symphiq-section-divider>
|
|
48725
|
+
</div>
|
|
48726
|
+
}
|
|
48727
|
+
|
|
48728
|
+
<section id="section-breakdowns" class="relative">
|
|
48729
|
+
<!-- Background Pattern -->
|
|
48730
|
+
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-tr from-purple-50/50 to-transparent' : 'bg-gradient-to-tr from-purple-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at bottom left, black 0%, transparent 70%);"></div>
|
|
48731
|
+
<div class="relative">
|
|
48732
|
+
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.7s;">
|
|
48733
|
+
<div [ngClass]="isLightMode() ? 'border-l-4 border-purple-500' : 'border-l-4 border-purple-400'" class="pl-4">
|
|
48734
|
+
<div class="flex items-center gap-3">
|
|
48735
|
+
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-purple-500' : 'text-purple-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48736
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
|
48737
|
+
</svg>
|
|
48738
|
+
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Performance Breakdowns</h2>
|
|
48739
|
+
</div>
|
|
48740
|
+
</div>
|
|
48741
|
+
<div (click)="$event.stopPropagation()" (mousedown)="$event.stopPropagation()" (pointerdown)="$event.stopPropagation()" class="relative inline-block">
|
|
48742
|
+
@if (isBreakdownTransitioning()) {
|
|
48743
|
+
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48744
|
+
<div class="w-4 h-4 border-2 border-purple-500/30 border-t-purple-500 rounded-full animate-spin"></div>
|
|
48745
|
+
</div>
|
|
48746
|
+
}
|
|
48747
|
+
<select
|
|
48748
|
+
[ngModel]="selectedBreakdownFilter()"
|
|
48749
|
+
(ngModelChange)="changeBreakdownFilter($event)"
|
|
48750
|
+
[ngClass]="isLightMode()
|
|
48751
|
+
? 'bg-white border-slate-300 text-slate-900 hover:border-blue-400 focus:border-blue-500'
|
|
48752
|
+
: 'bg-slate-700 border-slate-600 text-white hover:border-slate-500 focus:border-blue-500'"
|
|
48753
|
+
[class.opacity-70]="isBreakdownTransitioning()"
|
|
48754
|
+
class="px-3 py-2 text-sm rounded-lg border transition-all duration-200 cursor-pointer focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
|
48755
|
+
@for (filter of breakdownFilters; track filter.value) {
|
|
48756
|
+
@if (filter.divider) {
|
|
48757
|
+
<option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
|
|
48758
|
+
} @else {
|
|
48759
|
+
<option [value]="filter.value">{{ filter.label }}</option>
|
|
48760
|
+
}
|
|
48761
|
+
}
|
|
48762
|
+
</select>
|
|
48763
|
+
</div>
|
|
48764
|
+
</div>
|
|
48765
|
+
@if (isDataLoading()) {
|
|
48766
|
+
<!-- Breakdowns Skeleton -->
|
|
48767
|
+
<div class="space-y-6">
|
|
48768
|
+
@for (i of [1,2]; track i) {
|
|
48769
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48770
|
+
<div class="flex items-center justify-between mb-4">
|
|
48771
|
+
<symphiq-skeleton-loader [width]="'200px'" [height]="'28px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48772
|
+
<symphiq-skeleton-loader [width]="'100px'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48773
|
+
</div>
|
|
48774
|
+
<div class="space-y-3">
|
|
48775
|
+
@for (j of [1,2,3,4]; track j) {
|
|
48776
|
+
<div class="flex items-center justify-between p-3 rounded-lg" [ngClass]="isLightMode() ? 'bg-slate-50' : 'bg-slate-700/50'">
|
|
48777
|
+
<symphiq-skeleton-loader [width]="'150px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48778
|
+
<symphiq-skeleton-loader [width]="'80px'" [height]="'18px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48779
|
+
</div>
|
|
48780
|
+
}
|
|
48781
|
+
</div>
|
|
48782
|
+
</div>
|
|
48783
|
+
}
|
|
48784
|
+
</div>
|
|
48785
|
+
} @else {
|
|
48786
|
+
<div class="space-y-6" [class.animate-content-change]="isBreakdownTransitioning()" [class.transition-opacity-slow]="isBreakdownTransitioning()">
|
|
48787
|
+
@for (breakdown of breakdowns(); track $index) {
|
|
48788
|
+
<div class="animate-fade-in-up" [style.animation-delay]="(0.8 + $index * 0.1) + 's'"
|
|
48789
|
+
[libSymphiqSearchHighlight]="searchService.highlightedResultId()"
|
|
48790
|
+
[highlightId]="'breakdown-' + $index">
|
|
48791
|
+
<symphiq-funnel-analysis-breakdown-section
|
|
48792
|
+
[breakdown]="breakdown"
|
|
48793
|
+
[charts]="chartsForBreakdown(breakdown)"
|
|
48794
|
+
[isLightMode]="isLightMode()"
|
|
48795
|
+
[isCompactMode]="viewModeService.isCompact()"
|
|
48796
|
+
[currencySymbol]="currencySymbol()" />
|
|
48797
|
+
</div>
|
|
48798
|
+
} @empty {
|
|
48799
|
+
<div [ngClass]="isLightMode() ? 'bg-slate-50 border-slate-200' : 'bg-slate-800/50 border-slate-700'" class="rounded-xl p-12 border text-center animate-fade-in">
|
|
48800
|
+
<svg class="w-16 h-16 mx-auto mb-4" [ngClass]="isLightMode() ? 'text-slate-300' : 'text-slate-600'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48801
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
|
48802
|
+
</svg>
|
|
48803
|
+
<h3 [ngClass]="isLightMode() ? 'text-slate-900' : 'text-white'" class="text-lg font-semibold mb-2">No Breakdowns Found</h3>
|
|
48804
|
+
<p [ngClass]="isLightMode() ? 'text-slate-600' : 'text-slate-400'" class="text-sm">No performance breakdowns match your current filter selection. Try adjusting your filters to see more results.</p>
|
|
48805
|
+
</div>
|
|
48806
|
+
}
|
|
48807
|
+
</div>
|
|
48808
|
+
}
|
|
48809
|
+
</div>
|
|
48810
|
+
</section>
|
|
48811
|
+
}
|
|
48812
|
+
|
|
48813
|
+
@if (showCompetitiveIntelligence()) {
|
|
48814
|
+
@if (selectedSectionFilter() === 'ALL') {
|
|
48815
|
+
<!-- Section Divider -->
|
|
48816
|
+
<div class="mt-28 sm:mt-36">
|
|
48817
|
+
<symphiq-section-divider [viewMode]="viewMode()" animationDelay="0.85s"></symphiq-section-divider>
|
|
48818
|
+
</div>
|
|
48819
|
+
}
|
|
48820
|
+
|
|
48821
|
+
<!-- Competitive Intelligence Section -->
|
|
48822
|
+
<section id="section-competitive" class="relative">
|
|
48823
|
+
<!-- Background Pattern -->
|
|
48824
|
+
<div class="absolute inset-0 -mx-6 sm:-mx-8 -mt-8 rounded-3xl opacity-30 backdrop-blur-sm" [ngClass]="isLightMode() ? 'bg-gradient-to-br from-indigo-50/50 to-transparent' : 'bg-gradient-to-br from-indigo-950/20 to-transparent'" style="mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);"></div>
|
|
48825
|
+
<div class="relative">
|
|
48826
|
+
<div class="flex items-center justify-between mb-6 sm:mb-8 animate-fade-in" style="animation-delay: 0.9s;">
|
|
48827
|
+
<div class="flex items-center gap-3">
|
|
48828
|
+
<div [ngClass]="isLightMode() ? 'border-l-4 border-indigo-500' : 'border-l-4 border-indigo-400'" class="pl-4">
|
|
48829
|
+
<div class="flex items-center gap-3">
|
|
48830
|
+
<svg class="w-6 h-6" [ngClass]="isLightMode() ? 'text-indigo-500' : 'text-indigo-400'" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48831
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
48832
|
+
</svg>
|
|
48833
|
+
<h2 [class]="sectionTitleClass()" class="text-xl sm:text-2xl font-bold">Competitive Intelligence</h2>
|
|
48834
|
+
</div>
|
|
48835
|
+
</div>
|
|
48836
|
+
</div>
|
|
48837
|
+
<!-- Filter Dropdown -->
|
|
48838
|
+
<div class="hidden sm:block relative">
|
|
48839
|
+
@if (isCompetitiveTransitioning()) {
|
|
48840
|
+
<div class="absolute -right-2 top-1/2 -translate-y-1/2 z-10">
|
|
48841
|
+
<div class="w-4 h-4 border-2 border-indigo-500/30 border-t-indigo-500 rounded-full animate-spin"></div>
|
|
48842
|
+
</div>
|
|
48843
|
+
}
|
|
48844
|
+
<select
|
|
48845
|
+
[ngModel]="selectedCompetitiveFilter()"
|
|
48846
|
+
(ngModelChange)="changeCompetitiveFilter($event)"
|
|
48847
|
+
[class]="selectClass()"
|
|
48848
|
+
[class.opacity-70]="isCompetitiveTransitioning()"
|
|
48849
|
+
class="px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 cursor-pointer">
|
|
48850
|
+
@for (filter of competitiveFilters; track filter.value) {
|
|
48851
|
+
@if (filter.divider) {
|
|
48852
|
+
<option [value]="filter.value" disabled class="font-semibold">{{ filter.label }}</option>
|
|
48853
|
+
} @else {
|
|
48854
|
+
<option [value]="filter.value">{{ filter.label }}</option>
|
|
48855
|
+
}
|
|
48856
|
+
}
|
|
48857
|
+
</select>
|
|
48858
|
+
</div>
|
|
48859
|
+
</div>
|
|
48860
|
+
|
|
48861
|
+
@if (isDataLoading()) {
|
|
48862
|
+
<!-- Competitive Intelligence Skeleton -->
|
|
48863
|
+
<div class="space-y-6">
|
|
48864
|
+
<div [ngClass]="isLightMode() ? 'bg-white border-slate-200' : 'bg-slate-800 border-slate-700'" class="rounded-xl border p-6 animate-pulse">
|
|
48865
|
+
<symphiq-skeleton-loader [width]="'60%'" [height]="'24px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48866
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
|
|
48867
|
+
@for (i of [1,2,3]; track i) {
|
|
48868
|
+
<symphiq-skeleton-loader [width]="'100%'" [height]="'140px'" [isLightMode]="isLightMode()"></symphiq-skeleton-loader>
|
|
48869
|
+
}
|
|
48870
|
+
</div>
|
|
48871
|
+
</div>
|
|
48872
|
+
</div>
|
|
48873
|
+
} @else {
|
|
48874
|
+
<symphiq-competitive-intelligence-view
|
|
48875
|
+
[metrics]="competitiveMetrics()"
|
|
48876
|
+
[allCharts]="allCharts()"
|
|
48877
|
+
[isLightMode]="isLightMode()"
|
|
48878
|
+
[isCompactMode]="viewModeService.isCompact()"
|
|
48879
|
+
[competitiveBenchmark]="performanceOverview().overallAssessment?.competitiveBenchmark"
|
|
48880
|
+
[currencySymbol]="currencySymbol()" />
|
|
48881
|
+
}
|
|
48882
|
+
</div>
|
|
48883
|
+
</section>
|
|
48884
|
+
}
|
|
48885
|
+
</div>
|
|
48886
|
+
</main>
|
|
48887
|
+
}
|
|
48888
|
+
|
|
48889
|
+
<symphiq-funnel-analysis-modal
|
|
48890
|
+
[isLightMode]="isLightMode()"
|
|
48891
|
+
[viewMode]="viewMode()"
|
|
48892
|
+
[allMetrics]="allMetrics()"
|
|
48893
|
+
[allInsights]="insights()"
|
|
48894
|
+
[allCharts]="allCharts()"
|
|
48895
|
+
[currencySymbol]="currencySymbol()"
|
|
48896
|
+
[businessProfile]="businessProfile()"></symphiq-funnel-analysis-modal>
|
|
48897
|
+
<symphiq-profile-analysis-modal
|
|
48898
|
+
[isLightMode]="isLightMode()"
|
|
48899
|
+
[allMetrics]="allMetrics()"
|
|
48900
|
+
></symphiq-profile-analysis-modal>
|
|
48901
|
+
<symphiq-business-analysis-modal [isLightMode]="isLightMode()" />
|
|
48902
|
+
<symphiq-tooltip-container></symphiq-tooltip-container>
|
|
48903
|
+
<symphiq-search-bar
|
|
48904
|
+
[isLightMode]="isLightMode()"
|
|
48905
|
+
(resultSelected)="handleSearchResult($event)" />
|
|
48906
|
+
|
|
48907
|
+
<!-- View Mode Switcher Modal -->
|
|
48908
|
+
<symphiq-view-mode-switcher-modal
|
|
48909
|
+
[isOpen]="isViewModeSwitcherOpen()"
|
|
48910
|
+
[currentMode]="displayMode()"
|
|
48911
|
+
[viewMode]="isLightMode() ? ViewModeEnum.LIGHT : ViewModeEnum.DARK"
|
|
48912
|
+
[isLoading]="isViewModeSwitching()"
|
|
48913
|
+
(close)="closeViewModeSwitcher()"
|
|
48914
|
+
(modeSelected)="handleDisplayModeChange($event)"
|
|
48915
|
+
/>
|
|
48916
|
+
|
|
48917
|
+
<!-- Mobile FAB -->
|
|
48918
|
+
<symphiq-mobile-fab
|
|
48919
|
+
[isLightMode]="isLightMode()"
|
|
48920
|
+
[isCompactMode]="viewModeService.isCompact()"
|
|
48921
|
+
[isExpanded]="fabExpanded()"
|
|
48922
|
+
(expandedChange)="fabExpanded.set($event)"
|
|
48923
|
+
(scrollToTop)="scrollToTop()"
|
|
48924
|
+
(toggleView)="viewModeService.toggleViewMode()" />
|
|
48925
|
+
|
|
48926
|
+
<!-- Mobile Bottom Navigation -->
|
|
48927
|
+
<symphiq-mobile-bottom-nav
|
|
48928
|
+
[isLightMode]="isLightMode()"
|
|
48929
|
+
[sections]="navSections"
|
|
48930
|
+
[activeSection]="activeNavSection()"
|
|
48931
|
+
(navigate)="handleMobileNavigation($event)" />
|
|
48932
|
+
|
|
48933
|
+
</div>
|
|
48934
48934
|
`, styles: [":host{display:block;min-height:100%}.bg-gradient-radial{background:radial-gradient(circle,var(--tw-gradient-stops))}.bento-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem;grid-auto-flow:dense}@media (min-width: 768px){.bento-grid{grid-template-columns:repeat(6,1fr)}}.bento-small{grid-column:span 2;grid-row:span 1}.bento-medium{grid-column:span 3;grid-row:span 1}.bento-large{grid-column:span 4;grid-row:span 1}.bento-featured{grid-column:span 6;grid-row:span 1}@media (max-width: 767px){.bento-small,.bento-medium,.bento-large,.bento-featured{grid-column:span 1}}.masonry-grid{column-count:1;column-gap:1.5rem}@media (min-width: 768px){.masonry-grid{column-count:2}}@media (min-width: 1280px){.masonry-grid{column-count:3}}.masonry-grid>div{break-inside:avoid;margin-bottom:1.5rem}.masonry-featured{column-span:all}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}@media (max-width: 640px){.animate-fade-in-up{animation-duration:.4s}}\n"] }]
|
|
48935
48935
|
}], () => [{ type: FunnelOrderService }, { type: ViewModeService }, { type: SearchService }, { type: TooltipService }, { type: ProfileContextService }, { type: ProfileItemLookupService }], { modalComponent: [{
|
|
48936
48936
|
type: ViewChild,
|
|
@@ -54699,12 +54699,12 @@ function getPacingColorDark(pacingPercentage) {
|
|
|
54699
54699
|
}
|
|
54700
54700
|
function getPacingBgClass(status, isDark) {
|
|
54701
54701
|
if (status === 'ahead') {
|
|
54702
|
-
return isDark ? 'bg-emerald-
|
|
54702
|
+
return isDark ? 'bg-emerald-500/25' : 'bg-emerald-50';
|
|
54703
54703
|
}
|
|
54704
54704
|
if (status === 'on-pace') {
|
|
54705
|
-
return isDark ? 'bg-amber-
|
|
54705
|
+
return isDark ? 'bg-amber-500/25' : 'bg-amber-50';
|
|
54706
54706
|
}
|
|
54707
|
-
return isDark ? 'bg-red-
|
|
54707
|
+
return isDark ? 'bg-red-500/25' : 'bg-red-50';
|
|
54708
54708
|
}
|
|
54709
54709
|
function getPacingTextClass(status, isDark) {
|
|
54710
54710
|
if (status === 'ahead') {
|
|
@@ -54717,12 +54717,12 @@ function getPacingTextClass(status, isDark) {
|
|
|
54717
54717
|
}
|
|
54718
54718
|
function getPacingBorderClass(status, isDark) {
|
|
54719
54719
|
if (status === 'ahead') {
|
|
54720
|
-
return isDark ? 'border-emerald-
|
|
54720
|
+
return isDark ? 'border-emerald-400/40' : 'border-emerald-200';
|
|
54721
54721
|
}
|
|
54722
54722
|
if (status === 'on-pace') {
|
|
54723
|
-
return isDark ? 'border-amber-
|
|
54723
|
+
return isDark ? 'border-amber-400/40' : 'border-amber-200';
|
|
54724
54724
|
}
|
|
54725
|
-
return isDark ? 'border-red-
|
|
54725
|
+
return isDark ? 'border-red-400/40' : 'border-red-200';
|
|
54726
54726
|
}
|
|
54727
54727
|
function formatPacingDisplay(pacingPercentage) {
|
|
54728
54728
|
const sign = pacingPercentage >= 0 ? '+' : '';
|
|
@@ -54828,7 +54828,7 @@ function PacingStatusBadgeComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
|
|
|
54828
54828
|
i0.ɵɵadvance();
|
|
54829
54829
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.iconSymbol(), " ");
|
|
54830
54830
|
i0.ɵɵadvance();
|
|
54831
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.
|
|
54831
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.animatedPercentage(), " ");
|
|
54832
54832
|
i0.ɵɵadvance();
|
|
54833
54833
|
i0.ɵɵclassMap(ctx_r0.sizeClasses());
|
|
54834
54834
|
i0.ɵɵadvance(2);
|
|
@@ -54861,6 +54861,7 @@ class PacingStatusBadgeComponent {
|
|
|
54861
54861
|
this.showAsFullText = input(false, ...(ngDevMode ? [{ debugName: "showAsFullText" }] : []));
|
|
54862
54862
|
this.isCompact = input(false, ...(ngDevMode ? [{ debugName: "isCompact" }] : []));
|
|
54863
54863
|
this.showEmphasizedPercentage = input(false, ...(ngDevMode ? [{ debugName: "showEmphasizedPercentage" }] : []));
|
|
54864
|
+
this.animatedValue = signal(0, ...(ngDevMode ? [{ debugName: "animatedValue" }] : []));
|
|
54864
54865
|
this.displayInfo = computed(() => {
|
|
54865
54866
|
const isDark = this.viewMode() === ViewModeEnum.DARK;
|
|
54866
54867
|
return getPacingDisplayInfo(this.pacingPercentage(), this.status(), isDark);
|
|
@@ -54871,9 +54872,12 @@ class PacingStatusBadgeComponent {
|
|
|
54871
54872
|
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
54872
54873
|
this.containerSizeClasses = computed(() => {
|
|
54873
54874
|
const compact = this.isCompact();
|
|
54875
|
+
const status = this.status();
|
|
54876
|
+
const tiltClass = status === 'ahead' ? 'rotate-1' : status === 'behind' ? '-rotate-1' : '';
|
|
54877
|
+
const baseClasses = 'inline-flex flex-row items-center rounded-xl border-2 overflow-visible transition-transform hover:rotate-0';
|
|
54874
54878
|
return compact
|
|
54875
|
-
?
|
|
54876
|
-
:
|
|
54879
|
+
? `${baseClasses} pl-1.5 ${tiltClass}`
|
|
54880
|
+
: `${baseClasses} pl-2 ${tiltClass}`;
|
|
54877
54881
|
}, ...(ngDevMode ? [{ debugName: "containerSizeClasses" }] : []));
|
|
54878
54882
|
this.badgeClasses = computed(() => {
|
|
54879
54883
|
const info = this.displayInfo();
|
|
@@ -54889,7 +54893,9 @@ class PacingStatusBadgeComponent {
|
|
|
54889
54893
|
}, ...(ngDevMode ? [{ debugName: "sizeClasses" }] : []));
|
|
54890
54894
|
this.fullBadgeSizeClasses = computed(() => {
|
|
54891
54895
|
const isCompact = this.isCompact();
|
|
54892
|
-
const
|
|
54896
|
+
const status = this.status();
|
|
54897
|
+
const tiltClass = status === 'ahead' ? 'rotate-1' : status === 'behind' ? '-rotate-1' : '';
|
|
54898
|
+
const baseClasses = `inline-flex items-center gap-1.5 rounded-xl border-2 font-bold tracking-wide shadow-md transition-all hover:rotate-0 ${tiltClass}`;
|
|
54893
54899
|
if (isCompact) {
|
|
54894
54900
|
return `${baseClasses} px-2.5 py-1 text-xs`;
|
|
54895
54901
|
}
|
|
@@ -54921,6 +54927,9 @@ class PacingStatusBadgeComponent {
|
|
|
54921
54927
|
: this.displayInfo().displayText;
|
|
54922
54928
|
return /\d+\.?\d*%/.test(fullText);
|
|
54923
54929
|
}, ...(ngDevMode ? [{ debugName: "hasPercentage" }] : []));
|
|
54930
|
+
this.animatedPercentage = computed(() => {
|
|
54931
|
+
return `${this.animatedValue().toFixed(1)}%`;
|
|
54932
|
+
}, ...(ngDevMode ? [{ debugName: "animatedPercentage" }] : []));
|
|
54924
54933
|
this.extractPercentage = computed(() => {
|
|
54925
54934
|
const fullText = this.showAsFullText()
|
|
54926
54935
|
? formatPacingDisplayFullText(this.pacingPercentage(), this.status())
|
|
@@ -54940,24 +54949,44 @@ class PacingStatusBadgeComponent {
|
|
|
54940
54949
|
const isDark = this.viewMode() === ViewModeEnum.DARK;
|
|
54941
54950
|
if (status === 'ahead') {
|
|
54942
54951
|
return isDark
|
|
54943
|
-
? 'bg-
|
|
54944
|
-
: 'bg-
|
|
54952
|
+
? 'bg-emerald-600 text-emerald-50'
|
|
54953
|
+
: 'bg-emerald-500 text-white';
|
|
54945
54954
|
}
|
|
54946
54955
|
if (status === 'on-pace') {
|
|
54947
54956
|
return isDark
|
|
54948
|
-
? 'bg-
|
|
54949
|
-
: 'bg-
|
|
54957
|
+
? 'bg-amber-600 text-amber-50'
|
|
54958
|
+
: 'bg-amber-500 text-white';
|
|
54950
54959
|
}
|
|
54951
54960
|
return isDark
|
|
54952
|
-
? 'bg-
|
|
54953
|
-
: 'bg-
|
|
54961
|
+
? 'bg-red-600 text-red-50'
|
|
54962
|
+
: 'bg-red-500 text-white';
|
|
54954
54963
|
}, ...(ngDevMode ? [{ debugName: "overlayBadgeClasses" }] : []));
|
|
54955
54964
|
this.overlaySizeClasses = computed(() => {
|
|
54956
54965
|
const compact = this.isCompact();
|
|
54957
54966
|
return compact
|
|
54958
|
-
? 'px-2 py-1.5 rounded text-sm font-extrabold tracking-
|
|
54959
|
-
: 'px-2.5 py-2 rounded-
|
|
54967
|
+
? 'px-2 py-1.5 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
|
|
54968
|
+
: 'px-2.5 py-2 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
|
|
54960
54969
|
}, ...(ngDevMode ? [{ debugName: "overlaySizeClasses" }] : []));
|
|
54970
|
+
effect(() => {
|
|
54971
|
+
const target = Math.abs(this.pacingPercentage());
|
|
54972
|
+
this.animateValue(target);
|
|
54973
|
+
});
|
|
54974
|
+
}
|
|
54975
|
+
animateValue(target) {
|
|
54976
|
+
const start = 0;
|
|
54977
|
+
const duration = 800;
|
|
54978
|
+
const startTime = performance.now();
|
|
54979
|
+
const animate = (currentTime) => {
|
|
54980
|
+
const elapsed = currentTime - startTime;
|
|
54981
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
54982
|
+
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
|
|
54983
|
+
const current = start + (target - start) * easeOutQuart;
|
|
54984
|
+
this.animatedValue.set(current);
|
|
54985
|
+
if (progress < 1) {
|
|
54986
|
+
requestAnimationFrame(animate);
|
|
54987
|
+
}
|
|
54988
|
+
};
|
|
54989
|
+
requestAnimationFrame(animate);
|
|
54961
54990
|
}
|
|
54962
54991
|
static { this.ɵfac = function PacingStatusBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PacingStatusBadgeComponent)(); }; }
|
|
54963
54992
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PacingStatusBadgeComponent, selectors: [["symphiq-pacing-status-badge"]], inputs: { viewMode: [1, "viewMode"], pacingPercentage: [1, "pacingPercentage"], status: [1, "status"], showAsFullText: [1, "showAsFullText"], isCompact: [1, "isCompact"], showEmphasizedPercentage: [1, "showEmphasizedPercentage"] }, decls: 2, vars: 1, consts: [[3, "ngClass", "class"], [3, "ngClass"]], template: function PacingStatusBadgeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -54973,35 +55002,35 @@ class PacingStatusBadgeComponent {
|
|
|
54973
55002
|
standalone: true,
|
|
54974
55003
|
imports: [CommonModule],
|
|
54975
55004
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
54976
|
-
template: `
|
|
54977
|
-
@if (showEmphasizedPercentage() && hasPercentage()) {
|
|
54978
|
-
<div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
|
|
54979
|
-
<div [ngClass]="overlayBadgeClasses()" [class]="overlaySizeClasses()">
|
|
54980
|
-
<span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
|
|
54981
|
-
{{ iconSymbol() }}
|
|
54982
|
-
</span>
|
|
54983
|
-
{{
|
|
54984
|
-
</div>
|
|
54985
|
-
<div
|
|
54986
|
-
[class]="sizeClasses()"
|
|
54987
|
-
>
|
|
54988
|
-
<span>{{ displayTextWithoutPercentage() }}</span>
|
|
54989
|
-
</div>
|
|
54990
|
-
</div>
|
|
54991
|
-
} @else {
|
|
54992
|
-
<div
|
|
54993
|
-
[ngClass]="badgeClasses()"
|
|
54994
|
-
[class]="fullBadgeSizeClasses()"
|
|
54995
|
-
>
|
|
54996
|
-
<span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
|
|
54997
|
-
{{ iconSymbol() }}
|
|
54998
|
-
</span>
|
|
54999
|
-
<span>{{ displayText() }}</span>
|
|
55000
|
-
</div>
|
|
55001
|
-
}
|
|
55005
|
+
template: `
|
|
55006
|
+
@if (showEmphasizedPercentage() && hasPercentage()) {
|
|
55007
|
+
<div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
|
|
55008
|
+
<div [ngClass]="overlayBadgeClasses()" [class]="overlaySizeClasses()">
|
|
55009
|
+
<span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
|
|
55010
|
+
{{ iconSymbol() }}
|
|
55011
|
+
</span>
|
|
55012
|
+
{{ animatedPercentage() }}
|
|
55013
|
+
</div>
|
|
55014
|
+
<div
|
|
55015
|
+
[class]="sizeClasses()"
|
|
55016
|
+
>
|
|
55017
|
+
<span>{{ displayTextWithoutPercentage() }}</span>
|
|
55018
|
+
</div>
|
|
55019
|
+
</div>
|
|
55020
|
+
} @else {
|
|
55021
|
+
<div
|
|
55022
|
+
[ngClass]="badgeClasses()"
|
|
55023
|
+
[class]="fullBadgeSizeClasses()"
|
|
55024
|
+
>
|
|
55025
|
+
<span [ngClass]="iconClasses()" [class]="iconSizeClasses()">
|
|
55026
|
+
{{ iconSymbol() }}
|
|
55027
|
+
</span>
|
|
55028
|
+
<span>{{ displayText() }}</span>
|
|
55029
|
+
</div>
|
|
55030
|
+
}
|
|
55002
55031
|
`
|
|
55003
55032
|
}]
|
|
55004
|
-
}],
|
|
55033
|
+
}], () => [], { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], pacingPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "pacingPercentage", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showAsFullText: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAsFullText", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }], showEmphasizedPercentage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmphasizedPercentage", required: false }] }] }); })();
|
|
55005
55034
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PacingStatusBadgeComponent, { className: "PacingStatusBadgeComponent", filePath: "lib/components/revenue-calculator-dashboard/pacing-status-badge.component.ts", lineNumber: 39 }); })();
|
|
55006
55035
|
|
|
55007
55036
|
class TargetChangeBadgeComponent {
|
|
@@ -55011,6 +55040,7 @@ class TargetChangeBadgeComponent {
|
|
|
55011
55040
|
this.metric = input('', ...(ngDevMode ? [{ debugName: "metric" }] : []));
|
|
55012
55041
|
this.priorYear = input(new Date().getFullYear() - 1, ...(ngDevMode ? [{ debugName: "priorYear" }] : []));
|
|
55013
55042
|
this.isCompact = input(false, ...(ngDevMode ? [{ debugName: "isCompact" }] : []));
|
|
55043
|
+
this.animatedValue = signal(0, ...(ngDevMode ? [{ debugName: "animatedValue" }] : []));
|
|
55014
55044
|
this.isDark = computed(() => this.viewMode() === ViewModeEnum.DARK, ...(ngDevMode ? [{ debugName: "isDark" }] : []));
|
|
55015
55045
|
this.isIncreaseBad = computed(() => {
|
|
55016
55046
|
const metricStr = this.metric();
|
|
@@ -55026,11 +55056,11 @@ class TargetChangeBadgeComponent {
|
|
|
55026
55056
|
return '↘';
|
|
55027
55057
|
return '→';
|
|
55028
55058
|
}, ...(ngDevMode ? [{ debugName: "iconSymbol" }] : []));
|
|
55029
|
-
this.
|
|
55059
|
+
this.animatedPercentageText = computed(() => {
|
|
55030
55060
|
const sign = this.isIncreaseBad() ? '' : '+';
|
|
55031
|
-
const absValue = Math.abs(this.
|
|
55061
|
+
const absValue = Math.abs(this.animatedValue());
|
|
55032
55062
|
return `${sign}${formatPercentage(absValue, 1)}`;
|
|
55033
|
-
}, ...(ngDevMode ? [{ debugName: "
|
|
55063
|
+
}, ...(ngDevMode ? [{ debugName: "animatedPercentageText" }] : []));
|
|
55034
55064
|
this.descriptionText = computed(() => {
|
|
55035
55065
|
const action = this.isIncreaseBad() ? 'decrease from' : 'increase over';
|
|
55036
55066
|
return `${action} ${this.priorYear()}`;
|
|
@@ -55038,26 +55068,30 @@ class TargetChangeBadgeComponent {
|
|
|
55038
55068
|
this.containerClasses = computed(() => {
|
|
55039
55069
|
const dark = this.isDark();
|
|
55040
55070
|
return dark
|
|
55041
|
-
? 'bg-purple-500/
|
|
55042
|
-
: 'bg-purple-
|
|
55071
|
+
? 'bg-purple-500/25 border-purple-400/40'
|
|
55072
|
+
: 'bg-purple-50 border-purple-200';
|
|
55043
55073
|
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
55074
|
+
this.isIncrease = computed(() => this.percentageChange() > 0, ...(ngDevMode ? [{ debugName: "isIncrease" }] : []));
|
|
55044
55075
|
this.containerSizeClasses = computed(() => {
|
|
55045
55076
|
const compact = this.isCompact();
|
|
55077
|
+
const change = this.percentageChange();
|
|
55078
|
+
const tiltClass = change > 0 ? 'rotate-1' : change < 0 ? '-rotate-1' : '';
|
|
55079
|
+
const baseClasses = 'inline-flex flex-row items-center rounded-xl border-2 overflow-visible transition-transform hover:rotate-0';
|
|
55046
55080
|
return compact
|
|
55047
|
-
?
|
|
55048
|
-
:
|
|
55081
|
+
? `${baseClasses} pl-1.5 ${tiltClass}`
|
|
55082
|
+
: `${baseClasses} pl-2 ${tiltClass}`;
|
|
55049
55083
|
}, ...(ngDevMode ? [{ debugName: "containerSizeClasses" }] : []));
|
|
55050
55084
|
this.overlayClasses = computed(() => {
|
|
55051
55085
|
const dark = this.isDark();
|
|
55052
55086
|
return dark
|
|
55053
|
-
? 'bg-
|
|
55054
|
-
: 'bg-
|
|
55087
|
+
? 'bg-purple-600 text-purple-50'
|
|
55088
|
+
: 'bg-purple-500 text-white';
|
|
55055
55089
|
}, ...(ngDevMode ? [{ debugName: "overlayClasses" }] : []));
|
|
55056
55090
|
this.overlaySizeClasses = computed(() => {
|
|
55057
55091
|
const compact = this.isCompact();
|
|
55058
55092
|
return compact
|
|
55059
|
-
? 'px-2 py-1.5 rounded text-sm font-extrabold tracking-
|
|
55060
|
-
: 'px-2.5 py-2 rounded-
|
|
55093
|
+
? 'px-2 py-1.5 rounded-lg text-sm font-extrabold tracking-wide shadow-md transition-all duration-200 -my-1 -mr-1 z-10 inline-flex items-center gap-0.5'
|
|
55094
|
+
: 'px-2.5 py-2 rounded-lg font-extrabold text-base tracking-wide shadow-md transition-all duration-200 -my-1.5 -mr-1 z-10 inline-flex items-center gap-1';
|
|
55061
55095
|
}, ...(ngDevMode ? [{ debugName: "overlaySizeClasses" }] : []));
|
|
55062
55096
|
this.iconSizeClass = computed(() => {
|
|
55063
55097
|
return this.isCompact() ? 'text-sm' : 'text-base';
|
|
@@ -55068,6 +55102,26 @@ class TargetChangeBadgeComponent {
|
|
|
55068
55102
|
? 'px-2.5 py-0.5 text-xs font-semibold inline-block'
|
|
55069
55103
|
: 'px-3 py-0.5 font-semibold text-xs inline-block';
|
|
55070
55104
|
}, ...(ngDevMode ? [{ debugName: "descriptionSizeClasses" }] : []));
|
|
55105
|
+
effect(() => {
|
|
55106
|
+
const target = this.percentageChange();
|
|
55107
|
+
this.animateValue(target);
|
|
55108
|
+
});
|
|
55109
|
+
}
|
|
55110
|
+
animateValue(target) {
|
|
55111
|
+
const start = 0;
|
|
55112
|
+
const duration = 800;
|
|
55113
|
+
const startTime = performance.now();
|
|
55114
|
+
const animate = (currentTime) => {
|
|
55115
|
+
const elapsed = currentTime - startTime;
|
|
55116
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
55117
|
+
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
|
|
55118
|
+
const current = start + (target - start) * easeOutQuart;
|
|
55119
|
+
this.animatedValue.set(current);
|
|
55120
|
+
if (progress < 1) {
|
|
55121
|
+
requestAnimationFrame(animate);
|
|
55122
|
+
}
|
|
55123
|
+
};
|
|
55124
|
+
requestAnimationFrame(animate);
|
|
55071
55125
|
}
|
|
55072
55126
|
static { this.ɵfac = function TargetChangeBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TargetChangeBadgeComponent)(); }; }
|
|
55073
55127
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TargetChangeBadgeComponent, selectors: [["symphiq-target-change-badge"]], inputs: { viewMode: [1, "viewMode"], percentageChange: [1, "percentageChange"], metric: [1, "metric"], priorYear: [1, "priorYear"], isCompact: [1, "isCompact"] }, decls: 7, vars: 13, consts: [[3, "ngClass"]], template: function TargetChangeBadgeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -55090,7 +55144,7 @@ class TargetChangeBadgeComponent {
|
|
|
55090
55144
|
i0.ɵɵadvance();
|
|
55091
55145
|
i0.ɵɵtextInterpolate(ctx.iconSymbol());
|
|
55092
55146
|
i0.ɵɵadvance();
|
|
55093
|
-
i0.ɵɵtextInterpolate1(" ", ctx.
|
|
55147
|
+
i0.ɵɵtextInterpolate1(" ", ctx.animatedPercentageText(), " ");
|
|
55094
55148
|
i0.ɵɵadvance();
|
|
55095
55149
|
i0.ɵɵclassMap(ctx.descriptionSizeClasses());
|
|
55096
55150
|
i0.ɵɵadvance();
|
|
@@ -55104,19 +55158,19 @@ class TargetChangeBadgeComponent {
|
|
|
55104
55158
|
standalone: true,
|
|
55105
55159
|
imports: [CommonModule],
|
|
55106
55160
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
55107
|
-
template: `
|
|
55108
|
-
<div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
|
|
55109
|
-
<div [ngClass]="overlayClasses()" [class]="overlaySizeClasses()">
|
|
55110
|
-
<span [class]="iconSizeClass()">{{ iconSymbol() }}</span>
|
|
55111
|
-
{{
|
|
55112
|
-
</div>
|
|
55113
|
-
<div [class]="descriptionSizeClasses()">
|
|
55114
|
-
{{ descriptionText() }}
|
|
55115
|
-
</div>
|
|
55116
|
-
</div>
|
|
55161
|
+
template: `
|
|
55162
|
+
<div [ngClass]="containerClasses()" [class]="containerSizeClasses()">
|
|
55163
|
+
<div [ngClass]="overlayClasses()" [class]="overlaySizeClasses()">
|
|
55164
|
+
<span [class]="iconSizeClass()">{{ iconSymbol() }}</span>
|
|
55165
|
+
{{ animatedPercentageText() }}
|
|
55166
|
+
</div>
|
|
55167
|
+
<div [class]="descriptionSizeClasses()">
|
|
55168
|
+
{{ descriptionText() }}
|
|
55169
|
+
</div>
|
|
55170
|
+
</div>
|
|
55117
55171
|
`
|
|
55118
55172
|
}]
|
|
55119
|
-
}],
|
|
55173
|
+
}], () => [], { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], percentageChange: [{ type: i0.Input, args: [{ isSignal: true, alias: "percentageChange", required: false }] }], metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: false }] }], priorYear: [{ type: i0.Input, args: [{ isSignal: true, alias: "priorYear", required: false }] }], isCompact: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCompact", required: false }] }] }); })();
|
|
55120
55174
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TargetChangeBadgeComponent, { className: "TargetChangeBadgeComponent", filePath: "lib/components/revenue-calculator-dashboard/target-change-badge.component.ts", lineNumber: 23 }); })();
|
|
55121
55175
|
|
|
55122
55176
|
const _forTrack0$j = ($index, $item) => $item.stageMetric.metric;
|
|
@@ -56705,8 +56759,7 @@ class LineChartComponent {
|
|
|
56705
56759
|
// Check for explicit keywords
|
|
56706
56760
|
if (name.includes('last year') ||
|
|
56707
56761
|
name.includes('prior year') ||
|
|
56708
|
-
name.includes('previous year')
|
|
56709
|
-
name.includes('comparison')) {
|
|
56762
|
+
name.includes('previous year')) {
|
|
56710
56763
|
return true;
|
|
56711
56764
|
}
|
|
56712
56765
|
// Check for year patterns - extract any 4-digit year and compare to current year
|
|
@@ -56717,13 +56770,6 @@ class LineChartComponent {
|
|
|
56717
56770
|
}
|
|
56718
56771
|
return false;
|
|
56719
56772
|
}
|
|
56720
|
-
isProjectionSeries(seriesData) {
|
|
56721
|
-
if (!seriesData || !seriesData.name) {
|
|
56722
|
-
return false;
|
|
56723
|
-
}
|
|
56724
|
-
const name = seriesData.name.toLowerCase();
|
|
56725
|
-
return name.includes('projection') || name.includes('projected') || name.includes('target');
|
|
56726
|
-
}
|
|
56727
56773
|
extractMetricName(seriesName) {
|
|
56728
56774
|
// Extract metric name from series name by removing year patterns
|
|
56729
56775
|
// e.g., "Purchase Revenue (2025)" -> "Purchase Revenue"
|
|
@@ -56924,8 +56970,6 @@ class LineChartComponent {
|
|
|
56924
56970
|
const seriesColor = color(seriesColorValue);
|
|
56925
56971
|
// Check if this is a prior year series for YoY charts
|
|
56926
56972
|
const isPriorYear = isYoYChart && this.isPriorYearSeries(seriesData);
|
|
56927
|
-
const isProjection = this.isProjectionSeries(seriesData);
|
|
56928
|
-
console.log('[LineChart] Series:', seriesData.name, { isPriorYear, isProjection, isYoYChart, dataPoints: parsedData.length });
|
|
56929
56973
|
if (!this.chartElement || !this.root)
|
|
56930
56974
|
return;
|
|
56931
56975
|
const series = this.chartElement.series.push(LineSeries.new(this.root, {
|
|
@@ -56937,7 +56981,7 @@ class LineChartComponent {
|
|
|
56937
56981
|
stroke: seriesColor
|
|
56938
56982
|
}));
|
|
56939
56983
|
// Store valueFormat and prior year flag in userData for tooltip formatting
|
|
56940
|
-
series.set('userData', { valueFormat: seriesData.valueFormat, isPriorYear
|
|
56984
|
+
series.set('userData', { valueFormat: seriesData.valueFormat, isPriorYear });
|
|
56941
56985
|
// Disable individual series tooltips - use floating tooltip instead
|
|
56942
56986
|
series.set('tooltip', undefined);
|
|
56943
56987
|
// Configure stroke styling based on series type
|
|
@@ -56955,16 +56999,6 @@ class LineChartComponent {
|
|
|
56955
56999
|
stroke.set('strokeOpacity', 0.5);
|
|
56956
57000
|
});
|
|
56957
57001
|
}
|
|
56958
|
-
else if (isProjection) {
|
|
56959
|
-
// Apply dotted line for projection data
|
|
56960
|
-
series.strokes.template.setAll({
|
|
56961
|
-
strokeDasharray: [10, 5],
|
|
56962
|
-
strokeWidth: 3
|
|
56963
|
-
});
|
|
56964
|
-
series.strokes.each((stroke) => {
|
|
56965
|
-
stroke.set('strokeDasharray', [10, 5]);
|
|
56966
|
-
});
|
|
56967
|
-
}
|
|
56968
57002
|
// Add bullets with larger hit area for better hover detection
|
|
56969
57003
|
series.bullets.push(() => {
|
|
56970
57004
|
const bulletConfig = {
|
|
@@ -57018,10 +57052,10 @@ class LineChartComponent {
|
|
|
57018
57052
|
}
|
|
57019
57053
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LineChartComponent, [{
|
|
57020
57054
|
type: Component,
|
|
57021
|
-
args: [{ selector: 'symphiq-line-chart', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
57022
|
-
<div class="chart-container" [class.mini-mode]="!showAxisLabels()">
|
|
57023
|
-
<div #chartdiv class="chart" [style.height]="chartHeight()" style="width: 100%;"></div>
|
|
57024
|
-
</div>
|
|
57055
|
+
args: [{ selector: 'symphiq-line-chart', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
57056
|
+
<div class="chart-container" [class.mini-mode]="!showAxisLabels()">
|
|
57057
|
+
<div #chartdiv class="chart" [style.height]="chartHeight()" style="width: 100%;"></div>
|
|
57058
|
+
</div>
|
|
57025
57059
|
`, styles: [".chart-container{width:100%;padding:1rem}.chart-container.mini-mode{padding:.25rem}\n"] }]
|
|
57026
57060
|
}], () => [], { chart: [{ type: i0.Input, args: [{ isSignal: true, alias: "chart", required: false }] }], showAxisLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAxisLabels", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], currencySymbol: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencySymbol", required: false }] }], chartDiv: [{
|
|
57027
57061
|
type: ViewChild,
|
|
@@ -57110,6 +57144,10 @@ class ProgressToTargetChartComponent {
|
|
|
57110
57144
|
return;
|
|
57111
57145
|
this.chart.series.clear();
|
|
57112
57146
|
this.xAxis.axisRanges.clear();
|
|
57147
|
+
if (this.legend) {
|
|
57148
|
+
this.legend.dispose();
|
|
57149
|
+
this.legend = undefined;
|
|
57150
|
+
}
|
|
57113
57151
|
this.buildChart(chartData);
|
|
57114
57152
|
}
|
|
57115
57153
|
buildChart(chartData) {
|
|
@@ -57216,15 +57254,15 @@ class ProgressToTargetChartComponent {
|
|
|
57216
57254
|
dy: -18,
|
|
57217
57255
|
fill: this.labelColor()
|
|
57218
57256
|
});
|
|
57219
|
-
|
|
57257
|
+
this.legend = this.chart.children.push(Legend.new(this.root, {
|
|
57220
57258
|
centerX: p50,
|
|
57221
57259
|
x: p50,
|
|
57222
57260
|
marginTop: 8
|
|
57223
57261
|
}));
|
|
57224
|
-
legend.labels.template.setAll({
|
|
57262
|
+
this.legend.labels.template.setAll({
|
|
57225
57263
|
fill: this.labelColor()
|
|
57226
57264
|
});
|
|
57227
|
-
legend.data.setAll(this.chart.series.values.slice().reverse());
|
|
57265
|
+
this.legend.data.setAll(this.chart.series.values.slice().reverse());
|
|
57228
57266
|
this.chart.appear(1000, 100);
|
|
57229
57267
|
paceSeries.appear();
|
|
57230
57268
|
currentSeries.appear();
|
|
@@ -57289,20 +57327,20 @@ class ProgressToTargetChartComponent {
|
|
|
57289
57327
|
i0.ɵɵdomElementStart(0, "div", 1);
|
|
57290
57328
|
i0.ɵɵdomElement(1, "div", 2, 0);
|
|
57291
57329
|
i0.ɵɵdomElementEnd();
|
|
57292
|
-
} }, dependencies: [CommonModule], styles: [".progress-chart-container[_ngcontent-%COMP%]{width:100
|
|
57330
|
+
} }, dependencies: [CommonModule], styles: [".progress-chart-container[_ngcontent-%COMP%]{width:100%;margin-top:24px}"], changeDetection: 0 }); }
|
|
57293
57331
|
}
|
|
57294
57332
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ProgressToTargetChartComponent, [{
|
|
57295
57333
|
type: Component,
|
|
57296
|
-
args: [{ selector: 'symphiq-progress-to-target-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
57297
|
-
<div class="progress-chart-container">
|
|
57298
|
-
<div #chartdiv class="chart" style="width: 100%; height: 160px;"></div>
|
|
57299
|
-
</div>
|
|
57300
|
-
`, styles: [".progress-chart-container{width:100
|
|
57334
|
+
args: [{ selector: 'symphiq-progress-to-target-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
57335
|
+
<div class="progress-chart-container">
|
|
57336
|
+
<div #chartdiv class="chart" style="width: 100%; height: 160px;"></div>
|
|
57337
|
+
</div>
|
|
57338
|
+
`, styles: [".progress-chart-container{width:100%;margin-top:24px}\n"] }]
|
|
57301
57339
|
}], () => [], { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], chartDiv: [{
|
|
57302
57340
|
type: ViewChild,
|
|
57303
57341
|
args: ['chartdiv', { static: true }]
|
|
57304
57342
|
}] }); })();
|
|
57305
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProgressToTargetChartComponent, { className: "ProgressToTargetChartComponent", filePath: "lib/components/revenue-calculator-dashboard/progress-to-target-chart.component.ts", lineNumber:
|
|
57343
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProgressToTargetChartComponent, { className: "ProgressToTargetChartComponent", filePath: "lib/components/revenue-calculator-dashboard/progress-to-target-chart.component.ts", lineNumber: 62 }); })();
|
|
57306
57344
|
|
|
57307
57345
|
const _forTrack0$i = ($index, $item) => $item.metric;
|
|
57308
57346
|
function MetricReportModalComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -57410,7 +57448,7 @@ function MetricReportModalComponent_Conditional_0_Conditional_65_For_15_Template
|
|
|
57410
57448
|
} }
|
|
57411
57449
|
function MetricReportModalComponent_Conditional_0_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
57412
57450
|
i0.ɵɵelementStart(0, "div", 16)(1, "h4", 17);
|
|
57413
|
-
i0.ɵɵtext(2, " Contributing
|
|
57451
|
+
i0.ɵɵtext(2, " Contributing Metric Targets ");
|
|
57414
57452
|
i0.ɵɵelementEnd();
|
|
57415
57453
|
i0.ɵɵelementStart(3, "div", 36)(4, "table", 37)(5, "thead")(6, "tr", 38)(7, "th", 39);
|
|
57416
57454
|
i0.ɵɵtext(8, "Metric");
|
|
@@ -57443,6 +57481,9 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
|
|
|
57443
57481
|
i0.ɵɵelementEnd();
|
|
57444
57482
|
i0.ɵɵelementStart(5, "p", 54);
|
|
57445
57483
|
i0.ɵɵtext(6);
|
|
57484
|
+
i0.ɵɵelementEnd();
|
|
57485
|
+
i0.ɵɵelementStart(7, "p", 55);
|
|
57486
|
+
i0.ɵɵtext(8);
|
|
57446
57487
|
i0.ɵɵelementEnd()();
|
|
57447
57488
|
} if (rf & 2) {
|
|
57448
57489
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -57454,7 +57495,11 @@ function MetricReportModalComponent_Conditional_0_Conditional_66_Template(rf, ct
|
|
|
57454
57495
|
i0.ɵɵadvance();
|
|
57455
57496
|
i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
|
|
57456
57497
|
i0.ɵɵadvance();
|
|
57457
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.
|
|
57498
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence1(), " ");
|
|
57499
|
+
i0.ɵɵadvance();
|
|
57500
|
+
i0.ɵɵproperty("ngClass", ctx_r1.descriptionClasses());
|
|
57501
|
+
i0.ɵɵadvance();
|
|
57502
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.chartDescriptionSentence2(), " ");
|
|
57458
57503
|
} }
|
|
57459
57504
|
function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
57460
57505
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
@@ -57538,7 +57583,7 @@ function MetricReportModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1
|
|
|
57538
57583
|
i0.ɵɵconditionalCreate(64, MetricReportModalComponent_Conditional_0_Conditional_64_Template, 6, 10);
|
|
57539
57584
|
i0.ɵɵelementEnd();
|
|
57540
57585
|
i0.ɵɵconditionalCreate(65, MetricReportModalComponent_Conditional_0_Conditional_65_Template, 16, 3, "div", 16);
|
|
57541
|
-
i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template,
|
|
57586
|
+
i0.ɵɵconditionalCreate(66, MetricReportModalComponent_Conditional_0_Conditional_66_Template, 9, 10, "div", 29);
|
|
57542
57587
|
i0.ɵɵelementEnd();
|
|
57543
57588
|
i0.ɵɵelementStart(67, "div", 30)(68, "button", 31);
|
|
57544
57589
|
i0.ɵɵlistener("click", function MetricReportModalComponent_Conditional_0_Template_button_click_68_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.close()); });
|
|
@@ -57701,6 +57746,18 @@ class MetricReportModalComponent {
|
|
|
57701
57746
|
}
|
|
57702
57747
|
return 0;
|
|
57703
57748
|
}, ...(ngDevMode ? [{ debugName: "samePeriodLastYearValue" }] : []));
|
|
57749
|
+
this.fullYearLastYearValue = computed(() => {
|
|
57750
|
+
const pacingResponse = this.pacingMetrics();
|
|
57751
|
+
const metric = this.metricData();
|
|
57752
|
+
if (!pacingResponse || !metric)
|
|
57753
|
+
return 0;
|
|
57754
|
+
const monthlyData = pacingResponse.lastYearMetricValuesMonthly;
|
|
57755
|
+
if (!monthlyData)
|
|
57756
|
+
return 0;
|
|
57757
|
+
return monthlyData
|
|
57758
|
+
.filter(item => item.metric === metric.metric)
|
|
57759
|
+
.reduce((total, item) => total + (parseFloat(item.value || '0') || 0), 0);
|
|
57760
|
+
}, ...(ngDevMode ? [{ debugName: "fullYearLastYearValue" }] : []));
|
|
57704
57761
|
this.ytdChangePercentage = computed(() => {
|
|
57705
57762
|
const current = this.ytdValue();
|
|
57706
57763
|
const lastYear = this.samePeriodLastYearValue();
|
|
@@ -57794,12 +57851,23 @@ class MetricReportModalComponent {
|
|
|
57794
57851
|
status: pacing.status
|
|
57795
57852
|
};
|
|
57796
57853
|
}, ...(ngDevMode ? [{ debugName: "progressToTargetData" }] : []));
|
|
57797
|
-
this.
|
|
57798
|
-
const
|
|
57799
|
-
const
|
|
57854
|
+
this.chartDescriptionSentence1 = computed(() => {
|
|
57855
|
+
const metricData = this.metricData();
|
|
57856
|
+
const metricName = this.metricTitle().toLowerCase();
|
|
57857
|
+
const startDate = this.ytdStartDate();
|
|
57858
|
+
const endDate = this.ytdEndDate();
|
|
57859
|
+
const ytdValue = this.formatMetricValue(this.ytdValue(), metricData?.metric || '');
|
|
57860
|
+
const samePeriodLastYear = this.formatMetricValue(this.samePeriodLastYearValue(), metricData?.metric || '');
|
|
57800
57861
|
const priorYear = this.priorYear();
|
|
57801
|
-
return `
|
|
57802
|
-
}, ...(ngDevMode ? [{ debugName: "
|
|
57862
|
+
return `For the period (${startDate} - ${endDate}) you had ${ytdValue} ${metricName}, compared to ${samePeriodLastYear} for the same period in ${priorYear}.`;
|
|
57863
|
+
}, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence1" }] : []));
|
|
57864
|
+
this.chartDescriptionSentence2 = computed(() => {
|
|
57865
|
+
const metricData = this.metricData();
|
|
57866
|
+
const metricName = this.metricTitle().toLowerCase();
|
|
57867
|
+
const projectedValue = this.formatMetricValue(this.pacingInfo()?.projectedValue || 0, metricData?.metric || '');
|
|
57868
|
+
const fullYearLastYear = this.formatMetricValue(this.fullYearLastYearValue(), metricData?.metric || '');
|
|
57869
|
+
return `By maintaining this pace, your ${metricName} could increase to ${projectedValue} compared to ${fullYearLastYear} last year.`;
|
|
57870
|
+
}, ...(ngDevMode ? [{ debugName: "chartDescriptionSentence2" }] : []));
|
|
57803
57871
|
this.pacingChartData = computed(() => {
|
|
57804
57872
|
const metric = this.metricData();
|
|
57805
57873
|
const pacingResponse = this.pacingMetrics();
|
|
@@ -57808,16 +57876,10 @@ class MetricReportModalComponent {
|
|
|
57808
57876
|
const currentYearData = this.generateCurrentYearData(pacingResponse, metric.metric);
|
|
57809
57877
|
const priorYearData = this.generatePriorYearData(pacingResponse, metric.metric);
|
|
57810
57878
|
const projectionData = this.generateProjectionData(pacingResponse, metric.metric);
|
|
57811
|
-
console.log('[PaceChart] Metric:', metric.metric);
|
|
57812
|
-
console.log('[PaceChart] Current Year Data:', currentYearData);
|
|
57813
|
-
console.log('[PaceChart] Prior Year Data:', priorYearData);
|
|
57814
|
-
console.log('[PaceChart] Projection Data:', projectionData);
|
|
57815
|
-
console.log('[PaceChart] Pacing Response:', pacingResponse);
|
|
57816
57879
|
return {
|
|
57817
57880
|
chartType: 'LINE',
|
|
57818
57881
|
title: 'Pace',
|
|
57819
57882
|
description: '',
|
|
57820
|
-
lineChartUseCase: LineChartUseCaseEnum.THIS_YEAR_VS_LAST_YEAR,
|
|
57821
57883
|
lineChartData: {
|
|
57822
57884
|
series: [
|
|
57823
57885
|
{
|
|
@@ -57837,94 +57899,61 @@ class MetricReportModalComponent {
|
|
|
57837
57899
|
};
|
|
57838
57900
|
}, ...(ngDevMode ? [{ debugName: "pacingChartData" }] : []));
|
|
57839
57901
|
}
|
|
57840
|
-
formatDateForChart(year, month, day) {
|
|
57841
|
-
const m = String(month + 1).padStart(2, '0');
|
|
57842
|
-
const d = String(day).padStart(2, '0');
|
|
57843
|
-
return `${year}-${m}-${d}`;
|
|
57844
|
-
}
|
|
57845
57902
|
generateCurrentYearData(pacingResponse, metricEnum) {
|
|
57846
57903
|
const data = [];
|
|
57847
57904
|
const currentYear = this.currentYear();
|
|
57848
|
-
|
|
57849
|
-
|
|
57850
|
-
|
|
57851
|
-
|
|
57852
|
-
|
|
57905
|
+
const monthlyData = pacingResponse?.soFarMetricValuesMonthly;
|
|
57906
|
+
if (monthlyData) {
|
|
57907
|
+
monthlyData
|
|
57908
|
+
.filter(item => item.metric === metricEnum)
|
|
57909
|
+
.forEach((item) => {
|
|
57910
|
+
if (item.value && item.date) {
|
|
57911
|
+
const month = new Date(item.date).getMonth();
|
|
57853
57912
|
data.push({
|
|
57854
|
-
date:
|
|
57855
|
-
value: parseFloat(
|
|
57913
|
+
date: new Date(currentYear, month, 15).toISOString(),
|
|
57914
|
+
value: parseFloat(item.value) || 0
|
|
57856
57915
|
});
|
|
57857
57916
|
}
|
|
57858
57917
|
});
|
|
57859
57918
|
}
|
|
57860
|
-
if (data.length === 0) {
|
|
57861
|
-
const baseValue = this.metricData()?.currentValue || 1000;
|
|
57862
|
-
const now = new Date();
|
|
57863
|
-
const currentMonth = now.getMonth();
|
|
57864
|
-
for (let i = 0; i <= currentMonth; i++) {
|
|
57865
|
-
const value = baseValue * ((i + 1) / 12);
|
|
57866
|
-
data.push({
|
|
57867
|
-
date: this.formatDateForChart(currentYear, i, 15),
|
|
57868
|
-
value: Math.round(value * 100) / 100
|
|
57869
|
-
});
|
|
57870
|
-
}
|
|
57871
|
-
}
|
|
57872
57919
|
return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
|
57873
57920
|
}
|
|
57874
57921
|
generatePriorYearData(pacingResponse, metricEnum) {
|
|
57875
57922
|
const data = [];
|
|
57876
57923
|
const currentYear = this.currentYear();
|
|
57877
|
-
|
|
57878
|
-
|
|
57879
|
-
|
|
57880
|
-
|
|
57881
|
-
|
|
57924
|
+
const monthlyData = pacingResponse?.lastYearMetricValuesMonthly;
|
|
57925
|
+
if (monthlyData) {
|
|
57926
|
+
monthlyData
|
|
57927
|
+
.filter(item => item.metric === metricEnum)
|
|
57928
|
+
.forEach((item) => {
|
|
57929
|
+
if (item.value && item.date) {
|
|
57930
|
+
const month = new Date(item.date).getMonth();
|
|
57882
57931
|
data.push({
|
|
57883
|
-
date:
|
|
57884
|
-
value: parseFloat(
|
|
57932
|
+
date: new Date(currentYear, month, 15).toISOString(),
|
|
57933
|
+
value: parseFloat(item.value) || 0
|
|
57885
57934
|
});
|
|
57886
57935
|
}
|
|
57887
57936
|
});
|
|
57888
57937
|
}
|
|
57889
|
-
if (data.length === 0) {
|
|
57890
|
-
const baseValue = this.metricData()?.currentValue || 1000;
|
|
57891
|
-
for (let i = 0; i < 12; i++) {
|
|
57892
|
-
const value = baseValue * ((i + 1) / 12) * 0.9;
|
|
57893
|
-
data.push({
|
|
57894
|
-
date: this.formatDateForChart(currentYear, i, 15),
|
|
57895
|
-
value: Math.round(value * 100) / 100
|
|
57896
|
-
});
|
|
57897
|
-
}
|
|
57898
|
-
}
|
|
57899
57938
|
return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
|
57900
57939
|
}
|
|
57901
57940
|
generateProjectionData(pacingResponse, metricEnum) {
|
|
57902
57941
|
const data = [];
|
|
57903
57942
|
const currentYear = this.currentYear();
|
|
57904
|
-
|
|
57905
|
-
|
|
57906
|
-
|
|
57907
|
-
|
|
57908
|
-
|
|
57943
|
+
const monthlyData = pacingResponse?.projectedMetricValuesMonthly;
|
|
57944
|
+
if (monthlyData) {
|
|
57945
|
+
monthlyData
|
|
57946
|
+
.filter(item => item.metric === metricEnum)
|
|
57947
|
+
.forEach((item) => {
|
|
57948
|
+
if (item.value && item.date) {
|
|
57949
|
+
const month = new Date(item.date).getMonth();
|
|
57909
57950
|
data.push({
|
|
57910
|
-
date:
|
|
57911
|
-
value: parseFloat(
|
|
57951
|
+
date: new Date(currentYear, month, 15).toISOString(),
|
|
57952
|
+
value: parseFloat(item.value) || 0
|
|
57912
57953
|
});
|
|
57913
57954
|
}
|
|
57914
57955
|
});
|
|
57915
57956
|
}
|
|
57916
|
-
if (data.length === 0) {
|
|
57917
|
-
const targetValue = this.metricData()?.targetValue || 1200;
|
|
57918
|
-
const now = new Date();
|
|
57919
|
-
const currentMonth = now.getMonth();
|
|
57920
|
-
for (let i = currentMonth; i < 12; i++) {
|
|
57921
|
-
const value = targetValue * ((i + 1) / 12);
|
|
57922
|
-
data.push({
|
|
57923
|
-
date: this.formatDateForChart(currentYear, i, 15),
|
|
57924
|
-
value: Math.round(value * 100) / 100
|
|
57925
|
-
});
|
|
57926
|
-
}
|
|
57927
|
-
}
|
|
57928
57957
|
return data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
|
|
57929
57958
|
}
|
|
57930
57959
|
formatMetricValue(value, metric, fromUiData = true) {
|
|
@@ -58071,7 +58100,7 @@ class MetricReportModalComponent {
|
|
|
58071
58100
|
: 'bg-slate-700 hover:bg-slate-600 text-white';
|
|
58072
58101
|
}
|
|
58073
58102
|
static { this.ɵfac = function MetricReportModalComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MetricReportModalComponent)(); }; }
|
|
58074
|
-
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MetricReportModalComponent, selectors: [["symphiq-metric-report-modal"]], inputs: { viewMode: [1, "viewMode"], metricEnum: [1, "metricEnum"], metricData: [1, "metricData"], contributingMetrics: [1, "contributingMetrics"], pacingMetrics: [1, "pacingMetrics"], isOpen: [1, "isOpen"] }, outputs: { closed: "closed" }, decls: 1, vars: 1, consts: [[1, "fixed", "inset-0", "overflow-y-auto", "z-50"], [1, "fixed", "inset-0", "overflow-y-auto", "z-50", 3, "click"], [1, "flex", "items-center", "justify-center", "min-h-screen", "px-4", "pt-4", "pb-20", "text-center", "sm:block", "sm:p-0"], ["aria-hidden", "true", 1, "fixed", "inset-0", "backdrop-blur-md", 3, "ngClass"], ["aria-hidden", "true", 1, "hidden", "sm:inline-block", "sm:align-middle", "sm:h-screen"], [1, "relative", "inline-block", "align-bottom", "rounded-2xl", "text-left", "overflow-hidden", "shadow-xl", "sm:my-8", "sm:align-middle", "sm:w-full", "sm:max-w-4xl", "border", "backdrop-blur-xl", 3, "click", "ngClass"], [1, "px-6", "py-5", "border-b", "backdrop-blur-sm", "sticky", "top-0", "z-10", 3, "ngClass"], [1, "flex", "items-start", "justify-between"], [1, "flex-1"], [1, "flex", "items-center", "gap-3", "mb-2"], [1, "text-xl", "font-bold", 3, "ngClass"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-7", "h-7", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", "self-center", 3, "ngClass", "libSymphiqTooltip"], [1, "ml-4", "transition-all", "rounded-lg", "p-1", "hover:scale-110", "active:scale-90", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-6", "h-6"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M6 18L18 6M6 6l12 12"], [1, "px-6", "py-6", "max-h-[70vh]", "overflow-y-auto", "backdrop-blur-sm", 3, "ngClass"], [1, "rounded-xl", "p-6", "mb-6", 3, "ngClass"], [1, "text-sm", "font-semibold", "uppercase", "tracking-wider", "mb-4", 3, "ngClass"], [1, "grid", "grid-cols-1", "sm:grid-cols-2", "lg:grid-cols-3", "gap-6"], [1, "mb-1.5"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", 3, "ngClass"], [1, "text-xs", 3, "ngClass"], [1, "text-xl", "font-bold", "mb-2", 3, "ngClass"], [3, "viewMode", "percentageChange", "metric", "priorYear", "isCompact"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-1.5", 3, "ngClass"], [1, "mb-4"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-2", 3, "ngClass"], [1, "text-3xl", "font-extrabold", "mb-3", 3, "ngClass"], [1, "text-sm", "leading-relaxed", 3, "ngClass"], [1, "rounded-xl", "p-6", 3, "ngClass"], [1, "px-6", "py-4", "border-t", 3, "ngClass"], [1, "w-full", "px-4", "py-2", "rounded-lg", "transition-all", "font-medium", "hover:scale-[1.02]", "active:scale-[0.98]", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [3, "viewMode", "pacingPercentage", "status", "showAsFullText", "isCompact", "showEmphasizedPercentage"], [3, "data", "viewMode"], [1, "overflow-x-auto"], [1, "w-full"], [1, "border-b", 3, "ngClass"], [1, "text-left", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "text-right", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "border-b", "transition-colors", 3, "ngClass"], [1, "py-3", "px-4"], [1, "flex", "items-center", "gap-2"], [1, "text-sm", "font-medium"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-5", "h-5", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", 3, "ngClass", "libSymphiqTooltip"], [1, "py-3", "px-4", "text-right"], [1, "text-sm", "font-semibold", 3, "ngClass"], [1, "flex", "items-center", "justify-end", "gap-2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4", "text-emerald-500"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3"], [1, "min-h-[400px]"], [3, "chart", "showAxisLabels", "viewMode", "currencySymbol"], [1, "text-sm", "leading-relaxed", "mt-4", 3, "ngClass"]], template: function MetricReportModalComponent_Template(rf, ctx) { if (rf & 1) {
|
|
58103
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MetricReportModalComponent, selectors: [["symphiq-metric-report-modal"]], inputs: { viewMode: [1, "viewMode"], metricEnum: [1, "metricEnum"], metricData: [1, "metricData"], contributingMetrics: [1, "contributingMetrics"], pacingMetrics: [1, "pacingMetrics"], isOpen: [1, "isOpen"] }, outputs: { closed: "closed" }, decls: 1, vars: 1, consts: [[1, "fixed", "inset-0", "overflow-y-auto", "z-50"], [1, "fixed", "inset-0", "overflow-y-auto", "z-50", 3, "click"], [1, "flex", "items-center", "justify-center", "min-h-screen", "px-4", "pt-4", "pb-20", "text-center", "sm:block", "sm:p-0"], ["aria-hidden", "true", 1, "fixed", "inset-0", "backdrop-blur-md", 3, "ngClass"], ["aria-hidden", "true", 1, "hidden", "sm:inline-block", "sm:align-middle", "sm:h-screen"], [1, "relative", "inline-block", "align-bottom", "rounded-2xl", "text-left", "overflow-hidden", "shadow-xl", "sm:my-8", "sm:align-middle", "sm:w-full", "sm:max-w-4xl", "border", "backdrop-blur-xl", 3, "click", "ngClass"], [1, "px-6", "py-5", "border-b", "backdrop-blur-sm", "sticky", "top-0", "z-10", 3, "ngClass"], [1, "flex", "items-start", "justify-between"], [1, "flex-1"], [1, "flex", "items-center", "gap-3", "mb-2"], [1, "text-xl", "font-bold", 3, "ngClass"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-7", "h-7", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", "self-center", 3, "ngClass", "libSymphiqTooltip"], [1, "ml-4", "transition-all", "rounded-lg", "p-1", "hover:scale-110", "active:scale-90", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-6", "h-6"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M6 18L18 6M6 6l12 12"], [1, "px-6", "py-6", "max-h-[70vh]", "overflow-y-auto", "backdrop-blur-sm", 3, "ngClass"], [1, "rounded-xl", "p-6", "mb-6", 3, "ngClass"], [1, "text-sm", "font-semibold", "uppercase", "tracking-wider", "mb-4", 3, "ngClass"], [1, "grid", "grid-cols-1", "sm:grid-cols-2", "lg:grid-cols-3", "gap-6"], [1, "mb-1.5"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", 3, "ngClass"], [1, "text-xs", 3, "ngClass"], [1, "text-xl", "font-bold", "mb-2", 3, "ngClass"], [3, "viewMode", "percentageChange", "metric", "priorYear", "isCompact"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-1.5", 3, "ngClass"], [1, "mb-4"], [1, "text-xs", "font-medium", "uppercase", "tracking-wider", "mb-2", 3, "ngClass"], [1, "text-3xl", "font-extrabold", "mb-3", 3, "ngClass"], [1, "text-sm", "leading-relaxed", 3, "ngClass"], [1, "rounded-xl", "p-6", 3, "ngClass"], [1, "px-6", "py-4", "border-t", 3, "ngClass"], [1, "w-full", "px-4", "py-2", "rounded-lg", "transition-all", "font-medium", "hover:scale-[1.02]", "active:scale-[0.98]", 3, "click", "ngClass"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [3, "viewMode", "pacingPercentage", "status", "showAsFullText", "isCompact", "showEmphasizedPercentage"], [3, "data", "viewMode"], [1, "overflow-x-auto"], [1, "w-full"], [1, "border-b", 3, "ngClass"], [1, "text-left", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "text-right", "py-3", "px-4", "text-xs", "font-semibold", "uppercase", "tracking-wider"], [1, "border-b", "transition-colors", 3, "ngClass"], [1, "py-3", "px-4"], [1, "flex", "items-center", "gap-2"], [1, "text-sm", "font-medium"], ["type", "button", "tooltipType", "markdown", "tooltipPosition", "right", 1, "flex-shrink-0", "w-5", "h-5", "rounded-full", "inline-flex", "items-center", "justify-center", "transition-colors", 3, "ngClass", "libSymphiqTooltip"], [1, "py-3", "px-4", "text-right"], [1, "text-sm", "font-semibold", 3, "ngClass"], [1, "flex", "items-center", "justify-end", "gap-2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-4", "h-4", "text-emerald-500"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3"], [1, "min-h-[400px]"], [3, "chart", "showAxisLabels", "viewMode", "currencySymbol"], [1, "text-sm", "leading-relaxed", "mt-4", 3, "ngClass"], [1, "text-sm", "leading-relaxed", "mt-2", 3, "ngClass"]], template: function MetricReportModalComponent_Template(rf, ctx) { if (rf & 1) {
|
|
58075
58104
|
i0.ɵɵconditionalCreate(0, MetricReportModalComponent_Conditional_0_Template, 70, 51, "div", 0);
|
|
58076
58105
|
} if (rf & 2) {
|
|
58077
58106
|
i0.ɵɵconditional(ctx.isOpen() ? 0 : -1);
|
|
@@ -58325,7 +58354,7 @@ class MetricReportModalComponent {
|
|
|
58325
58354
|
@if (contributingMetrics().length > 0) {
|
|
58326
58355
|
<div [ngClass]="sectionCardClasses()" class="rounded-xl p-6 mb-6">
|
|
58327
58356
|
<h4 [ngClass]="sectionTitleClasses()" class="text-sm font-semibold uppercase tracking-wider mb-4">
|
|
58328
|
-
Contributing
|
|
58357
|
+
Contributing Metric Targets
|
|
58329
58358
|
</h4>
|
|
58330
58359
|
<div class="overflow-x-auto">
|
|
58331
58360
|
<table class="w-full">
|
|
@@ -58403,7 +58432,10 @@ class MetricReportModalComponent {
|
|
|
58403
58432
|
/>
|
|
58404
58433
|
</div>
|
|
58405
58434
|
<p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-4">
|
|
58406
|
-
{{
|
|
58435
|
+
{{ chartDescriptionSentence1() }}
|
|
58436
|
+
</p>
|
|
58437
|
+
<p [ngClass]="descriptionClasses()" class="text-sm leading-relaxed mt-2">
|
|
58438
|
+
{{ chartDescriptionSentence2() }}
|
|
58407
58439
|
</p>
|
|
58408
58440
|
</div>
|
|
58409
58441
|
}
|
|
@@ -58425,7 +58457,7 @@ class MetricReportModalComponent {
|
|
|
58425
58457
|
`
|
|
58426
58458
|
}]
|
|
58427
58459
|
}], null, { viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }], metricEnum: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricEnum", required: false }] }], metricData: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricData", required: false }] }], contributingMetrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "contributingMetrics", required: false }] }], pacingMetrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "pacingMetrics", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] }); })();
|
|
58428
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber:
|
|
58460
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MetricReportModalComponent, { className: "MetricReportModalComponent", filePath: "lib/components/revenue-calculator-dashboard/metric-report-modal.component.ts", lineNumber: 346 }); })();
|
|
58429
58461
|
|
|
58430
58462
|
const _c0$q = ["absoluteInputRef"];
|
|
58431
58463
|
const _c1$b = ["percentageInputRef"];
|
|
@@ -63753,92 +63785,92 @@ class CollapsibleSectionGroupComponent {
|
|
|
63753
63785
|
standalone: true,
|
|
63754
63786
|
imports: [CommonModule, SymphiqIconComponent, ProfileSectionComponent],
|
|
63755
63787
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
63756
|
-
template: `
|
|
63757
|
-
<div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
|
|
63758
|
-
<div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
|
|
63759
|
-
<div class="flex items-center justify-between">
|
|
63760
|
-
<div class="flex items-center gap-3">
|
|
63761
|
-
<div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
|
|
63762
|
-
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
63763
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
|
63764
|
-
</svg>
|
|
63765
|
-
</div>
|
|
63766
|
-
<div>
|
|
63767
|
-
<h2 [ngClass]="titleClasses()" class="text-xl font-bold">
|
|
63768
|
-
Supporting Business Context
|
|
63769
|
-
</h2>
|
|
63770
|
-
<p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
|
|
63771
|
-
Additional insights gathered from publicly available information
|
|
63772
|
-
</p>
|
|
63773
|
-
</div>
|
|
63774
|
-
</div>
|
|
63775
|
-
</div>
|
|
63776
|
-
</div>
|
|
63777
|
-
|
|
63778
|
-
<div [ngClass]="contentClasses()" class="p-6">
|
|
63779
|
-
<div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
|
|
63780
|
-
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
63781
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
63782
|
-
</svg>
|
|
63783
|
-
<div class="flex-1">
|
|
63784
|
-
<h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
|
|
63785
|
-
Building Context for Better Recommendations
|
|
63786
|
-
</h4>
|
|
63787
|
-
<p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
|
|
63788
|
-
The information below was gathered from your website and competitor research. While recommendations above are based on this initial analysis, connecting your GA4 data will provide quantitative insights that dramatically improve recommendation accuracy.
|
|
63789
|
-
</p>
|
|
63790
|
-
</div>
|
|
63791
|
-
</div>
|
|
63792
|
-
|
|
63793
|
-
<div class="space-y-3">
|
|
63794
|
-
@for (section of sections(); track section.id; let idx = $index) {
|
|
63795
|
-
<div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
|
|
63796
|
-
<button
|
|
63797
|
-
type="button"
|
|
63798
|
-
(click)="toggleSection(idx)"
|
|
63799
|
-
[ngClass]="sectionHeaderClasses(section, idx)"
|
|
63800
|
-
class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
|
|
63801
|
-
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
63802
|
-
@if (section.icon) {
|
|
63803
|
-
<div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
|
|
63804
|
-
<symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
|
|
63805
|
-
</div>
|
|
63806
|
-
}
|
|
63807
|
-
<div class="flex-1 min-w-0">
|
|
63808
|
-
<h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
|
|
63809
|
-
{{ section.title }}
|
|
63810
|
-
</h3>
|
|
63811
|
-
<p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
|
|
63812
|
-
{{ getSectionItemCount(section) }} items
|
|
63813
|
-
</p>
|
|
63814
|
-
</div>
|
|
63815
|
-
</div>
|
|
63816
|
-
<svg
|
|
63817
|
-
[ngClass]="chevronClasses(idx)"
|
|
63818
|
-
[class.rotate-180]="expandedSections()[idx]"
|
|
63819
|
-
class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
|
|
63820
|
-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
63821
|
-
</svg>
|
|
63822
|
-
</button>
|
|
63823
|
-
|
|
63824
|
-
<div
|
|
63825
|
-
class="grid transition-[grid-template-rows] duration-300 ease-in-out"
|
|
63826
|
-
[style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
|
|
63827
|
-
<div class="overflow-hidden">
|
|
63828
|
-
<div [ngClass]="sectionContentClasses()" class="border-t">
|
|
63829
|
-
<symphiq-profile-section
|
|
63830
|
-
[section]="section"
|
|
63831
|
-
[viewMode]="viewMode()"
|
|
63832
|
-
[forceExpanded]="false"
|
|
63833
|
-
/>
|
|
63834
|
-
</div>
|
|
63835
|
-
</div>
|
|
63836
|
-
</div>
|
|
63837
|
-
</div>
|
|
63838
|
-
}
|
|
63839
|
-
</div>
|
|
63840
|
-
</div>
|
|
63841
|
-
</div>
|
|
63788
|
+
template: `
|
|
63789
|
+
<div [ngClass]="containerClasses()" class="rounded-2xl border shadow-lg overflow-hidden">
|
|
63790
|
+
<div [ngClass]="headerClasses()" class="px-6 py-5 border-b">
|
|
63791
|
+
<div class="flex items-center justify-between">
|
|
63792
|
+
<div class="flex items-center gap-3">
|
|
63793
|
+
<div [ngClass]="iconContainerClasses()" class="p-2.5 rounded-lg">
|
|
63794
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
63795
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
|
63796
|
+
</svg>
|
|
63797
|
+
</div>
|
|
63798
|
+
<div>
|
|
63799
|
+
<h2 [ngClass]="titleClasses()" class="text-xl font-bold">
|
|
63800
|
+
Supporting Business Context
|
|
63801
|
+
</h2>
|
|
63802
|
+
<p [ngClass]="subtitleClasses()" class="text-sm mt-0.5">
|
|
63803
|
+
Additional insights gathered from publicly available information
|
|
63804
|
+
</p>
|
|
63805
|
+
</div>
|
|
63806
|
+
</div>
|
|
63807
|
+
</div>
|
|
63808
|
+
</div>
|
|
63809
|
+
|
|
63810
|
+
<div [ngClass]="contentClasses()" class="p-6">
|
|
63811
|
+
<div [ngClass]="infoBoxClasses()" class="mb-6 p-4 rounded-xl border flex items-start gap-3">
|
|
63812
|
+
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" [ngClass]="infoIconClasses()" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
63813
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
63814
|
+
</svg>
|
|
63815
|
+
<div class="flex-1">
|
|
63816
|
+
<h4 [ngClass]="infoTitleClasses()" class="font-semibold text-sm mb-1">
|
|
63817
|
+
Building Context for Better Recommendations
|
|
63818
|
+
</h4>
|
|
63819
|
+
<p [ngClass]="infoTextClasses()" class="text-sm leading-relaxed">
|
|
63820
|
+
The information below was gathered from your website and competitor research. While recommendations above are based on this initial analysis, connecting your GA4 data will provide quantitative insights that dramatically improve recommendation accuracy.
|
|
63821
|
+
</p>
|
|
63822
|
+
</div>
|
|
63823
|
+
</div>
|
|
63824
|
+
|
|
63825
|
+
<div class="space-y-3">
|
|
63826
|
+
@for (section of sections(); track section.id; let idx = $index) {
|
|
63827
|
+
<div [id]="'collapsible-section-' + idx" [ngClass]="sectionCardClasses()" class="rounded-xl border overflow-hidden transition-all duration-200">
|
|
63828
|
+
<button
|
|
63829
|
+
type="button"
|
|
63830
|
+
(click)="toggleSection(idx)"
|
|
63831
|
+
[ngClass]="sectionHeaderClasses(section, idx)"
|
|
63832
|
+
class="cursor-pointer w-full px-5 py-4 flex items-center justify-between gap-4 text-left transition-colors duration-200">
|
|
63833
|
+
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
63834
|
+
@if (section.icon) {
|
|
63835
|
+
<div [ngClass]="sectionIconContainerClasses(idx)" class="p-2 rounded-lg flex-shrink-0 transition-colors duration-200">
|
|
63836
|
+
<symphiq-icon [icon]="section.icon" size="w-4 h-4"></symphiq-icon>
|
|
63837
|
+
</div>
|
|
63838
|
+
}
|
|
63839
|
+
<div class="flex-1 min-w-0">
|
|
63840
|
+
<h3 [ngClass]="sectionTitleClasses(idx)" class="font-semibold transition-colors duration-200">
|
|
63841
|
+
{{ section.title }}
|
|
63842
|
+
</h3>
|
|
63843
|
+
<p [ngClass]="sectionDescriptionClasses(idx)" class="text-sm mt-0.5 transition-colors duration-200">
|
|
63844
|
+
{{ getSectionItemCount(section) }} items
|
|
63845
|
+
</p>
|
|
63846
|
+
</div>
|
|
63847
|
+
</div>
|
|
63848
|
+
<svg
|
|
63849
|
+
[ngClass]="chevronClasses(idx)"
|
|
63850
|
+
[class.rotate-180]="expandedSections()[idx]"
|
|
63851
|
+
class="w-5 h-5 flex-shrink-0 transition-transform duration-200">
|
|
63852
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
63853
|
+
</svg>
|
|
63854
|
+
</button>
|
|
63855
|
+
|
|
63856
|
+
<div
|
|
63857
|
+
class="grid transition-[grid-template-rows] duration-300 ease-in-out"
|
|
63858
|
+
[style.grid-template-rows]="expandedSections()[idx] ? '1fr' : '0fr'">
|
|
63859
|
+
<div class="overflow-hidden">
|
|
63860
|
+
<div [ngClass]="sectionContentClasses()" class="border-t">
|
|
63861
|
+
<symphiq-profile-section
|
|
63862
|
+
[section]="section"
|
|
63863
|
+
[viewMode]="viewMode()"
|
|
63864
|
+
[forceExpanded]="false"
|
|
63865
|
+
/>
|
|
63866
|
+
</div>
|
|
63867
|
+
</div>
|
|
63868
|
+
</div>
|
|
63869
|
+
</div>
|
|
63870
|
+
}
|
|
63871
|
+
</div>
|
|
63872
|
+
</div>
|
|
63873
|
+
</div>
|
|
63842
63874
|
`
|
|
63843
63875
|
}]
|
|
63844
63876
|
}], null, { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], viewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewMode", required: false }] }] }); })();
|