feat(prospecting): improve prospect detail with score details and tech badge

- Score Breakdown: show point-by-point contributions from score_breakdown
  dict, sorted by value, color-coded green (positive) vs red (negative)
- Tech Profile: prominent CMS badge (WordPress, Shopify, etc.) with
  e-commerce platform tag, "Custom / Unknown CMS" fallback
- Add SSL issuer and expiry date to tech profile card

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 21:24:19 +02:00
parent 754bfca87d
commit 28b08580c8
2 changed files with 40 additions and 8 deletions

View File

@@ -123,6 +123,11 @@ function prospectDetail(prospectId) {
return 'text-gray-600';
},
isPositiveFlag(flag) {
var positive = ['has_website', 'has_contacts', 'has_email', 'has_phone', 'has_ssl', 'modern_cms', 'fast_site', 'mobile_friendly'];
return positive.indexOf(flag) !== -1;
},
techProfileEntries() {
const tp = this.prospect?.tech_profile;
if (!tp) return [];

View File

@@ -110,15 +110,24 @@
<span class="text-gray-600 dark:text-gray-400">Engagement</span>
<span class="font-semibold text-gray-700 dark:text-gray-200" x-text="prospect.score.engagement_score + '/10'"></span>
</div>
<div class="pt-3 border-t border-gray-100 dark:border-gray-700">
<h4 class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase mb-2">Issues</h4>
<div class="flex flex-wrap gap-2">
<template x-for="flag in prospect.score.reason_flags || []" :key="flag">
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-700 rounded-full dark:bg-red-900 dark:text-red-300"
x-text="flag.replace('_', ' ')"></span>
</template>
<!-- Point-by-point breakdown -->
<template x-if="prospect.score.score_breakdown && Object.keys(prospect.score.score_breakdown).length">
<div class="pt-3 border-t border-gray-100 dark:border-gray-700">
<h4 class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase mb-2">Details</h4>
<div class="space-y-1">
<template x-for="[flag, points] in Object.entries(prospect.score.score_breakdown).sort((a,b) => b[1] - a[1])" :key="flag">
<div class="flex items-center justify-between text-xs">
<span class="text-gray-600 dark:text-gray-400" x-text="flag.replaceAll('_', ' ')"></span>
<span class="font-semibold px-1.5 py-0.5 rounded"
:class="isPositiveFlag(flag)
? 'text-green-700 bg-green-50 dark:text-green-300 dark:bg-green-900/30'
: 'text-red-700 bg-red-50 dark:text-red-300 dark:bg-red-900/30'"
x-text="(isPositiveFlag(flag) ? '+' : '-') + points"></span>
</div>
</template>
</div>
</div>
</div>
</template>
</div>
</template>
<p x-show="!prospect.score" class="text-sm text-gray-400 text-center py-4">Not scored yet</p>
@@ -127,6 +136,15 @@
<!-- Tech Profile Summary -->
<div x-show="prospect.tech_profile" class="p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
{{ section_header('Technology', icon='code') }}
<!-- CMS badge (prominent) -->
<div x-show="prospect.tech_profile?.cms" class="mb-3 flex items-center gap-2">
<span class="px-3 py-1.5 text-sm font-semibold rounded-lg bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-300"
x-text="(prospect.tech_profile?.cms || '').charAt(0).toUpperCase() + (prospect.tech_profile?.cms || '').slice(1) + (prospect.tech_profile?.cms_version ? ' ' + prospect.tech_profile.cms_version : '')"></span>
<span x-show="prospect.tech_profile?.ecommerce_platform"
class="px-2 py-1 text-xs font-medium rounded-lg bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300"
x-text="prospect.tech_profile?.ecommerce_platform"></span>
</div>
<p x-show="!prospect.tech_profile?.cms" class="mb-3 text-sm text-gray-500 dark:text-gray-400">Custom / Unknown CMS</p>
<div class="space-y-2 text-sm">
<template x-for="[key, val] in techProfileEntries()" :key="key">
<div class="flex justify-between">
@@ -134,6 +152,15 @@
<span class="font-medium text-gray-700 dark:text-gray-300" x-text="val"></span>
</div>
</template>
<div x-show="prospect.tech_profile?.cert_issuer" class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">SSL Issuer</span>
<span class="font-medium text-gray-700 dark:text-gray-300" x-text="prospect.tech_profile?.cert_issuer"></span>
</div>
<div x-show="prospect.tech_profile?.cert_expires_at" class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">SSL Expires</span>
<span class="font-medium text-gray-700 dark:text-gray-300"
x-text="prospect.tech_profile?.cert_expires_at ? new Date(prospect.tech_profile.cert_expires_at).toLocaleDateString() : '—'"></span>
</div>
</div>
</div>