'use client'; import { useMemo } from 'react'; import { X, Filter, TrendingUp, TrendingDown, Minus } from 'lucide-react'; import type { URTDomainPoint, URTDomain } from '../types'; import { useReviewIQFilters } from '@/contexts/ReviewIQFilterContext'; interface URTBarChartProps { data: URTDomainPoint[]; } // User-friendly domain config with emojis and descriptions const DOMAIN_CONFIG: Record = { P: { emoji: '👥', label: 'Staff & Service', color: '#3b82f6', bgColor: '#dbeafe' }, V: { emoji: '💰', label: 'Pricing & Value', color: '#ec4899', bgColor: '#fce7f3' }, J: { emoji: '⏱️', label: 'Speed & Process', color: '#8b5cf6', bgColor: '#ede9fe' }, O: { emoji: '🛍️', label: 'Product Quality', color: '#f97316', bgColor: '#ffedd5' }, A: { emoji: '📍', label: 'Availability', color: '#10b981', bgColor: '#d1fae5' }, E: { emoji: '🏢', label: 'Facilities', color: '#06b6d4', bgColor: '#cffafe' }, R: { emoji: '🤝', label: 'Trust & Ethics', color: '#f59e0b', bgColor: '#fef3c7' }, }; // Ordered domains by typical business priority const DOMAIN_ORDER = ['P', 'V', 'J', 'O', 'A', 'E', 'R']; /** * Domain Distribution - Horizontal bar chart showing what customers talk about. * User-friendly design with emojis and clear progress bars. * Click to filter by domain. */ export function URTBarChart({ data }: URTBarChartProps) { const { filters, setURTDomain } = useReviewIQFilters(); // Process and sort data const processedData = useMemo(() => { const lookup = new Map(); let maxCount = 0; let totalMentions = 0; data.forEach((d) => { lookup.set(d.domain, d); if (d.count > maxCount) maxCount = d.count; totalMentions += d.count; }); // Sort by domain order, then build rows const rows = DOMAIN_ORDER .filter(domain => lookup.has(domain)) .map(domain => { const d = lookup.get(domain)!; const config = DOMAIN_CONFIG[d.domain] || { emoji: '📊', label: d.domain_name || d.domain, color: '#6b7280', bgColor: '#f3f4f6', }; const percentage = totalMentions > 0 ? (d.count / totalMentions) * 100 : 0; const barWidth = maxCount > 0 ? (d.count / maxCount) * 100 : 0; // Health indicator based on positive/negative ratio const total = d.positive_count + d.negative_count + d.neutral_count; const positiveRatio = total > 0 ? d.positive_count / total : 0; const negativeRatio = total > 0 ? d.negative_count / total : 0; let health: 'good' | 'warning' | 'critical' = 'warning'; if (positiveRatio > 0.6) health = 'good'; else if (negativeRatio > 0.5) health = 'critical'; return { domain: d.domain, config, count: d.count, reviewCount: d.review_count, percentage, barWidth, health, positiveCount: d.positive_count, negativeCount: d.negative_count, }; }) // Sort by count descending .sort((a, b) => b.count - a.count); return { rows, maxCount, totalMentions }; }, [data]); const handleClick = (domain: string) => { setURTDomain(filters.urtDomain === domain ? null : domain as URTDomain); }; const isFiltering = filters.urtDomain !== null; const hasSentimentFilter = filters.sentiment.length > 0; return (

What Customers Talk About

{processedData.totalMentions.toLocaleString()} total mentions

{hasSentimentFilter && !isFiltering && ( {filters.sentiment.join(', ')} )} {isFiltering && ( <> {DOMAIN_CONFIG[filters.urtDomain!]?.label || filters.urtDomain} )}
{processedData.rows.length === 0 ? (
No data available
) : (
{processedData.rows.map((row) => { const isActive = filters.urtDomain === row.domain; return ( ); })}
)} {/* Legend */}
Mostly positive Mixed Needs attention
); }