All files / lib/testimonials trust-score.ts

100% Statements 55/55
100% Branches 16/16
100% Functions 4/4
100% Lines 55/55

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113                                                          1x 18x 18x 18x 18x 18x 18x 18x 18x     18x     18x 5x 5x     18x 5x 5x     18x 6x 6x     18x 18x     18x 18x 18x 18x 18x 18x   18x 18x         18x 18x 18x 18x 18x 18x 18x 18x 18x 18x         1x       17x 17x 4x 4x 17x 4x 4x 17x 4x 4x 5x 5x         1x 10x 10x  
/**
 * Trust Score Calculation
 *
 * Calculates trust scores for testimonials based on various signals
 */
 
import type { TestimonialVerificationType } from './verification';
 
export interface TrustScoreFactors {
  verificationType: TestimonialVerificationType;
  hasRequest: boolean;
  relationshipContext: string | null;
  hasRating: boolean;
  contentLength: number;
  hasAuthorTitle: boolean;
}
 
export interface TrustScoreBreakdown {
  total: number;
  verification: number;
  request: number;
  relationship: number;
  content: number;
  details: number;
}
 
/**
 * Calculate trust score for a testimonial
 */
export function calculateTrustScore(factors: TrustScoreFactors): TrustScoreBreakdown {
  const breakdown: TrustScoreBreakdown = {
    total: 0,
    verification: 0,
    request: 0,
    relationship: 0,
    content: 0,
    details: 0,
  };
 
  // Verification type score (0-50)
  breakdown.verification = getVerificationScore(factors.verificationType);
 
  // Request system bonus (0-15)
  if (factors.hasRequest) {
    breakdown.request = 15;
  }
 
  // Relationship context bonus (0-10)
  if (factors.relationshipContext) {
    breakdown.relationship = 10;
  }
 
  // Content quality bonus (0-15)
  if (factors.contentLength > 100) {
    breakdown.content = Math.min(15, Math.floor(factors.contentLength / 50));
  }
 
  // Additional details bonus (0-10)
  if (factors.hasRating) breakdown.details += 5;
  if (factors.hasAuthorTitle) breakdown.details += 5;
 
  // Calculate total
  breakdown.total =
    breakdown.verification +
    breakdown.request +
    breakdown.relationship +
    breakdown.content +
    breakdown.details;
 
  return breakdown;
}
 
/**
 * Get base score for verification type
 */
function getVerificationScore(type: TestimonialVerificationType): number {
  const scores: Record<TestimonialVerificationType, number> = {
    work_verified: 50,
    domain_verified: 40,
    identity_linked: 35,
    email_verified: 20,
    unverified: 0,
  };
  return scores[type] || 0;
}
 
/**
 * Get trust level label from score
 */
export function getTrustLevel(score: number): {
  level: 'low' | 'medium' | 'high' | 'verified';
  label: string;
  color: string;
} {
  if (score >= 70) {
    return { level: 'verified', label: 'Highly Trusted', color: 'text-emerald-600' };
  }
  if (score >= 50) {
    return { level: 'high', label: 'Trusted', color: 'text-blue-600' };
  }
  if (score >= 25) {
    return { level: 'medium', label: 'Moderate Trust', color: 'text-amber-600' };
  }
  return { level: 'low', label: 'Unverified', color: 'text-gray-500' };
}
 
/**
 * Format trust score for display
 */
export function formatTrustScore(score: number): string {
  return `${Math.round(score)}%`;
}