Skip to content

Instantly share code, notes, and snippets.

@ashwath007
Created February 7, 2026 05:32
Show Gist options
  • Select an option

  • Save ashwath007/d019d45c063f265c40ec40e2261a6897 to your computer and use it in GitHub Desktop.

Select an option

Save ashwath007/d019d45c063f265c40ec40e2261a6897 to your computer and use it in GitHub Desktop.
Competitor New UI
import React, { useState, useMemo } from 'react';
import {
Zap,
Globe,
Facebook,
Youtube,
ExternalLink,
Target,
MessageSquare,
BadgePercent,
Languages,
ChevronDown,
Calendar,
MapPin,
Filter,
PieChart,
BarChart3,
TrendingUp,
ArrowUpRight,
Eye,
Activity,
Layers,
Search,
CheckSquare,
Square,
MousePointer2,
RefreshCcw,
UserCircle,
Hash,
Box,
ChevronRight,
BarChart as BarChartIcon,
ArrowRight,
Image as ImageIcon
} from 'lucide-react';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, Legend, ComposedChart, Line } from 'recharts';
// --- Global Data Structures ---
const oemSpendData = [
{
id: 'bajaj',
name: 'Bajaj Auto',
spend: 4.2,
metaSpend: 2.8,
googleSpend: 1.4,
sov: 48,
brands: 12,
topBrand: 'Chetak',
subBrands: [
{ name: 'Chetak (EV)', brandKey: 'chetak', spend: 1.8, meta: 1.2, google: 0.6, sov: 22, volume: 450 },
{ name: 'Pulsar Series', brandKey: 'chetak', spend: 1.4, meta: 0.9, google: 0.5, sov: 15, volume: 380 },
{ name: 'Dominar', brandKey: 'chetak', spend: 0.6, meta: 0.4, google: 0.2, sov: 7, volume: 120 },
{ name: 'Platina/CT', brandKey: 'chetak', spend: 0.4, meta: 0.3, google: 0.1, sov: 4, volume: 90 }
]
},
{
id: 'tvs',
name: 'TVS Motor',
spend: 2.8,
metaSpend: 1.6,
googleSpend: 1.2,
sov: 22,
brands: 8,
topBrand: 'iQube',
subBrands: [
{ name: 'iQube (EV)', brandKey: 'iqube', spend: 0.9, meta: 0.5, google: 0.4, sov: 10, volume: 310 },
{ name: 'Jupiter', brandKey: 'iqube', spend: 1.1, meta: 0.7, google: 0.4, sov: 7, volume: 280 },
{ name: 'Apache', brandKey: 'iqube', spend: 0.5, meta: 0.3, google: 0.2, sov: 3, volume: 140 },
{ name: 'NTORQ', brandKey: 'iqube', spend: 0.3, meta: 0.1, google: 0.2, sov: 2, volume: 110 }
]
},
{
id: 'ather',
name: 'Ather Energy',
spend: 1.5,
metaSpend: 0.9,
googleSpend: 0.6,
sov: 18,
brands: 3,
topBrand: '450X',
subBrands: [
{ name: '450X', brandKey: 'ather', spend: 0.8, meta: 0.5, google: 0.3, sov: 10, volume: 190 },
{ name: '450S', brandKey: 'ather', spend: 0.4, meta: 0.2, google: 0.2, sov: 5, volume: 90 },
{ name: 'Rizta', brandKey: 'ather', spend: 0.3, meta: 0.2, google: 0.1, sov: 3, volume: 70 }
]
},
];
const segmentationData = [
{ segment: 'Premium Motorcycle', meta: 1.2, google: 0.9, volume: 450 },
{ segment: 'Economy Motorcycle', meta: 0.8, google: 0.6, volume: 820 },
{ segment: 'Executive Motorcycle', meta: 1.0, google: 0.8, volume: 610 },
{ segment: 'Premium Scooter', meta: 0.5, google: 0.4, volume: 210 },
{ segment: 'Economy Scooter', meta: 0.7, google: 0.4, volume: 540 },
{ segment: 'Executive Scooter', meta: 0.4, google: 0.3, volume: 320 },
{ segment: 'EV Motorcycle', meta: 0.8, google: 0.4, volume: 290 },
{ segment: 'EV Scooter', meta: 2.0, google: 1.2, volume: 1150 },
];
const brandComparisonData = {
chetak: ['iqube', 'ather'],
iqube: ['chetak', 'ather'],
ather: ['chetak', 'iqube']
};
const brandsData = {
chetak: {
name: 'Chetak',
ratio: '70/30',
totalSpend: '₹1.63 Cr',
metaSpend: '₹1.14 Cr',
googleSpend: '₹49.0 L',
metaValue: 42,
googleValue: 20,
sov: 45,
campaigns: [
{
id: 'c1',
url: 'https://www.chetak.com/enquire',
cost: '₹11.2L',
tags: ['Performance', 'Lead Gen'],
type: 'conversion',
images: [
'https://images.unsplash.com/photo-1551288049-bebda4e38f71?q=80&w=600&auto=format&fit=crop',
'https://images.unsplash.com/photo-1614165933833-315930353406?q=80&w=200&auto=format&fit=crop',
'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?q=80&w=200&auto=format&fit=crop'
],
efficacy: { ctr: '1.2%', cpm: '₹140', status: 'above' },
funnel: { traffic: '160k', bounce: '22%', conversion: '4.2%' },
strategy: 'Direct Lead Generation focus with sticky enquiry form.',
offers: ['Special financing available', 'Extended warranty'],
languages: 'English, Hindi, Marathi'
},
{
id: 'c2',
url: 'https://www.chetak.com/experience',
cost: '₹3.2L',
tags: ['Brand', 'Awareness'],
type: 'awareness',
images: [
'https://images.unsplash.com/photo-1620939511596-7377519a79c9?q=80&w=600&auto=format&fit=crop',
'https://images.unsplash.com/photo-1609630875171-b1321377ee53?q=80&w=200&auto=format&fit=crop'
],
efficacy: { ctr: '0.8%', cpm: '₹95', status: 'below' },
funnel: { traffic: '450k', bounce: '45%', conversion: '0.8%' },
strategy: 'Lifestyle-led brand campaign focusing on EV transition.',
offers: ['Festive Experience Passes'],
languages: 'English, Hindi'
}
]
},
iqube: {
name: 'TVS iQube',
ratio: '60/40',
totalSpend: '₹48.9L',
metaSpend: '₹29.3 L',
googleSpend: '₹19.6 L',
metaValue: 12,
googleValue: 10,
sov: 25,
campaigns: [
{
id: 'i1',
url: 'https://www.tvsmotor.com/book-ride',
cost: '₹4.89L',
tags: ['Performance', 'Lead Gen'],
type: 'conversion',
images: [
'https://images.unsplash.com/photo-1609630875171-b1321377ee53?q=80&w=600&auto=format&fit=crop',
'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?q=80&w=200&auto=format&fit=crop',
'https://images.unsplash.com/photo-1614165933833-315930353406?q=80&w=200&auto=format&fit=crop'
],
efficacy: { ctr: '1.5%', cpm: '₹125', status: 'above' },
funnel: { traffic: '33k', bounce: '32%', conversion: '5.1%' },
strategy: 'Test-ride drive with geographic convenience focus.',
offers: ['Festive Cashback: ₹5,000'],
languages: 'English, Malayalam'
}
]
},
ather: {
name: 'Ather 450X',
ratio: '55/45',
totalSpend: '₹15.3L',
metaSpend: '₹8.4 L',
googleSpend: '₹6.9 L',
metaValue: 8,
googleValue: 8,
sov: 30,
campaigns: [
{
id: 'a1',
url: 'https://www.atherenergy.com/flexipay',
cost: '₹5.4L',
tags: ['Mid-Funnel', 'Financing'],
type: 'consideration',
images: [
'https://images.unsplash.com/photo-1556742049-0cfed4f7a07d?q=80&w=600&auto=format&fit=crop',
'https://images.unsplash.com/photo-1594144408214-496ff9430df4?q=80&w=200&auto=format&fit=crop'
],
efficacy: { ctr: '2.1%', cpm: '₹180', status: 'below' },
funnel: { traffic: '8.7k', bounce: '64%', conversion: '1.8%' },
strategy: 'EMI calculator to lower high premium entry barrier.',
offers: ['Zero Processing Fee'],
languages: 'English, Hindi'
}
]
}
};
const funnelStages = [
{ id: 'awareness', label: 'Awareness', description: 'Brand Building & Top-Funnel Reach', color: 'bg-emerald-500', icon: Globe },
{ id: 'consideration', label: 'Consideration', description: 'Product Specs & Comparison', color: 'bg-indigo-500', icon: Layers },
{ id: 'conversion', label: 'Conversion', description: 'Lead Generation & Sales Intent', color: 'bg-blue-600', icon: Target }
];
const App = () => {
const [viewMode, setViewMode] = useState('oem');
const [primaryBrand, setPrimaryBrand] = useState('chetak');
const [expandedOems, setExpandedOems] = useState([]);
const [filters, setFilters] = useState({
dateRange: 'October 2024',
states: ['All States'],
platform: ['Meta', 'Google', 'YouTube'],
type: 'all'
});
const togglePlatform = (p) => {
setFilters(prev => ({
...prev,
platform: prev.platform.includes(p) ? prev.platform.filter(item => item !== p) : [...prev.platform, p]
}));
};
const toggleOemExpansion = (id) => {
setExpandedOems(prev =>
prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]
);
};
const handleBrandClick = (brandKey) => {
setPrimaryBrand(brandKey);
setViewMode('competition');
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const competitors = useMemo(() => brandComparisonData[primaryBrand] || [], [primaryBrand]);
const activeBrandsList = useMemo(() => [primaryBrand, ...competitors], [primaryBrand, competitors]);
const competitionChartData = useMemo(() => {
return [brandsData[primaryBrand], ...competitors.map(c => brandsData[c])].map(brand => ({
name: brand.name,
metaSOE: brand.metaValue,
googleSOE: brand.googleValue,
sov: brand.sov
}));
}, [primaryBrand, competitors]);
return (
<div className="flex flex-col h-screen bg-[#FDFDFD] font-sans text-slate-900 overflow-hidden">
{/* GLOBAL HEADER & FILTER BAR */}
<header className="bg-white border-b border-slate-200 sticky top-0 z-50 shadow-sm">
<div className="px-8 py-4 flex justify-between items-center border-b border-slate-100">
<div className="flex items-center gap-6">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-black rounded flex items-center justify-center text-white font-bold shadow-lg">H</div>
<span className="text-lg font-black tracking-tighter uppercase">HAWKY</span>
</div>
<div className="h-6 w-px bg-slate-200" />
<div className="flex bg-slate-100 p-1 rounded-lg">
<button onClick={() => setViewMode('oem')} className={`px-4 py-1.5 flex items-center gap-2 text-xs font-bold rounded-md transition-all ${viewMode === 'oem' ? 'bg-white shadow-sm text-black' : 'text-slate-500 hover:text-slate-700'}`}>
<BarChart3 size={14} /> OEM Level
</button>
<button onClick={() => setViewMode('competition')} className={`px-4 py-1.5 flex items-center gap-2 text-xs font-bold rounded-md transition-all ${viewMode === 'competition' ? 'bg-white shadow-sm text-black' : 'text-slate-500 hover:text-slate-700'}`}>
<Target size={14} /> Competition
</button>
</div>
</div>
<div className="flex items-center gap-4">
<span className="text-[10px] font-black text-slate-400 uppercase">TVS Digital Team Sync</span>
<button className="h-9 px-4 bg-black text-white text-[10px] font-black uppercase rounded-md shadow-lg hover:bg-slate-800 transition-all">Export Dashboard</button>
</div>
</div>
<div className="px-8 py-3 bg-white flex items-center gap-8 overflow-x-auto no-scrollbar border-b border-slate-100 shadow-sm">
<FilterGroup label="Selected Period">
<div className="flex items-center gap-2 px-3 py-1.5 border border-slate-200 rounded-md bg-slate-50 shadow-sm">
<Calendar size={14} className="text-slate-400" />
<select className="bg-transparent text-xs font-bold outline-none cursor-pointer" value={filters.dateRange} onChange={(e) => setFilters({...filters, dateRange: e.target.value})}>
<option>October 2024</option>
<option>September 2024</option>
<option>Diwali Week</option>
<option>Navratri (Festive)</option>
</select>
</div>
</FilterGroup>
<FilterGroup label="State Market">
<div className="flex items-center gap-2 px-3 py-1.5 border border-slate-200 rounded-md bg-slate-50 shadow-sm">
<MapPin size={14} className="text-slate-400" />
<span className="text-xs font-bold text-blue-600">Kerala + 2 Others</span>
<ChevronDown size={12} className="text-slate-300" />
</div>
</FilterGroup>
<FilterGroup label="Objective Type">
<div className="flex bg-slate-100 p-1 rounded-lg">
{['all', 'perf', 'mid', 'brand'].map(t => (
<button key={t} onClick={() => setFilters({...filters, type: t})} className={`px-3 py-1 text-[10px] font-bold rounded-md transition-all ${filters.type === t ? 'bg-white shadow-sm text-black' : 'text-slate-400 hover:text-slate-600'}`}>
{t.toUpperCase()}
</button>
))}
</div>
</FilterGroup>
<FilterGroup label="Platform Analysis">
<div className="flex items-center gap-4 py-1.5">
{['Meta', 'Google', 'YouTube'].map(p => (
<div key={p} onClick={() => togglePlatform(p)} className="flex items-center gap-2 cursor-pointer group">
<div className={`w-4 h-4 rounded border transition-all flex items-center justify-center ${filters.platform.includes(p) ? 'bg-black border-black shadow-sm' : 'bg-white border-slate-300'}`}>
{filters.platform.includes(p) && <div className="w-1.5 h-1.5 bg-white rounded-full" />}
</div>
<span className={`text-[11px] font-bold ${filters.platform.includes(p) ? 'text-black' : 'text-slate-400'}`}>{p}</span>
</div>
))}
</div>
</FilterGroup>
{viewMode === 'competition' && (
<div className="ml-auto flex flex-col gap-1 min-w-max">
<label className="text-[9px] font-bold text-slate-400 uppercase tracking-wider text-right">Switch Analysis Brand</label>
<select className="bg-black text-white rounded-md px-3 py-1.5 text-xs font-bold outline-none shadow-lg cursor-pointer" value={primaryBrand} onChange={(e) => setPrimaryBrand(e.target.value)}>
<option value="chetak">Chetak</option>
<option value="iqube">TVS iQube</option>
<option value="ather">Ather 450X</option>
</select>
</div>
)}
</div>
</header>
{/* DASHBOARD BODY */}
<main className="flex-1 overflow-y-auto p-8 space-y-16 bg-[#FBFBFC]">
{viewMode === 'oem' ? (
/* --- OEM PORTFOLIO VIEW --- */
<div className="space-y-12 max-w-7xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
{/* TOP METRICS TILES */}
<section className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm group hover:border-black transition-all">
<div className="flex justify-between items-start mb-4">
<div className="p-2 rounded-lg bg-slate-50 text-slate-400">
<PieChart size={18} />
</div>
<ArrowUpRight size={14} className="text-slate-300" />
</div>
<p className="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">Estimated Market Spend</p>
<h4 className="text-2xl font-black text-slate-900 mb-2 uppercase tracking-tighter">₹12.4 Cr</h4>
<div className="flex gap-4 pt-3 border-t border-slate-50">
<div className="flex flex-col">
<span className="text-[8px] font-black text-slate-400 uppercase">Meta Spend</span>
<span className="text-xs font-black text-blue-600">₹7.8 Cr</span>
</div>
<div className="flex flex-col">
<span className="text-[8px] font-black text-slate-400 uppercase">Google Spend</span>
<span className="text-xs font-black text-indigo-600">₹4.6 Cr</span>
</div>
</div>
</div>
<KPICard title="Market Comparison IDs" value={activeBrandsList.length.toString()} sub={activeBrandsList.map(b => brandsData[b]?.name || b).join(', ')} icon={Target} color="blue" />
<KPICard title="Analysis Date Range" value={filters.dateRange} sub="Selected Month Reporting" icon={Calendar} color="emerald" />
</section>
{/* BRAND SEGMENTATION DISTRIBUTION */}
<section className="bg-white rounded-2xl border border-slate-200 overflow-hidden shadow-sm">
<div className="p-6 border-b border-slate-100 flex justify-between items-center bg-white">
<div>
<h3 className="font-black text-sm uppercase tracking-tighter text-slate-900">Category Spend Mix</h3>
<p className="text-[10px] text-slate-400 font-bold uppercase mt-1">Cross-platform distribution by vehicle segment</p>
</div>
<div className="flex gap-4">
<div className="flex items-center gap-2">
<div className="w-2.5 h-2.5 bg-blue-600 rounded-full" />
<span className="text-[9px] font-black text-slate-400 uppercase tracking-tight">Meta</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2.5 h-2.5 bg-slate-300 rounded-full" />
<span className="text-[9px] font-black text-slate-400 uppercase tracking-tight">Google</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2.5 h-2.5 bg-indigo-500 rounded-full" />
<span className="text-[9px] font-black text-slate-400 uppercase tracking-tight">Ad Vol</span>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-0 divide-x divide-slate-100">
<div className="lg:col-span-3 p-6">
<div className="h-[400px] w-full">
<ResponsiveContainer width="100%" height="100%">
<ComposedChart data={segmentationData} margin={{ top: 20, right: 30, left: 0, bottom: 20 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#F1F5F9" />
<XAxis dataKey="segment" axisLine={false} tickLine={false} tick={{fontSize: 8, fontWeight: 700, fill: '#64748b'}} interval={0}/>
<YAxis yAxisId="left" axisLine={false} tickLine={false} tick={{fontSize: 9, fill: '#94a3b8'}} tickFormatter={(v) => `₹${v}Cr`}/>
<YAxis yAxisId="right" orientation="right" axisLine={false} tickLine={false} tick={{fontSize: 9, fill: '#94a3b8'}} />
<Tooltip contentStyle={{ borderRadius: '12px', border: 'none', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' }} cursor={{ fill: '#F8FAFC' }}/>
<Bar yAxisId="left" name="Meta Spend" dataKey="meta" stackId="a" fill="#2563eb" barSize={35} />
<Bar yAxisId="left" name="Google Spend" dataKey="google" stackId="a" fill="#cbd5e1" radius={[4, 4, 0, 0]} barSize={35} />
<Line yAxisId="right" type="monotone" name="Ad Volume" dataKey="volume" stroke="#6366f1" strokeWidth={3} dot={{ r: 4, fill: '#6366f1' }} />
</ComposedChart>
</ResponsiveContainer>
</div>
</div>
<div className="p-6 bg-slate-50/50 space-y-4">
<h4 className="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-4">Market Efficiency</h4>
{segmentationData.slice(0, 4).map((s, i) => (
<div key={i} className="bg-white p-3 rounded-xl border border-slate-200 shadow-sm">
<p className="text-[8px] font-bold text-slate-400 uppercase mb-1">{s.segment}</p>
<div className="flex justify-between items-baseline mb-2">
<span className="text-sm font-black text-slate-900">₹{(s.meta + s.google).toFixed(1)}Cr</span>
<span className="text-[9px] font-bold text-indigo-600">{s.volume} Ads</span>
</div>
<div className="flex justify-between text-[8px] font-black uppercase text-slate-400">
<span>M: ₹{s.meta}Cr</span>
<span>G: ₹{s.google}Cr</span>
</div>
</div>
))}
</div>
</div>
</section>
{/* MANUFACTURER BENCHMARK TABLE */}
<section className="bg-white rounded-2xl border border-slate-200 overflow-hidden shadow-sm">
<div className="p-6 border-b border-slate-100 flex justify-between items-center bg-white">
<h3 className="font-black text-sm uppercase tracking-tighter">Manufacturer Benchmark Table</h3>
<span className="text-[9px] font-black text-slate-400 bg-slate-100 px-2 py-0.5 rounded uppercase">Full Portfolio</span>
</div>
<table className="w-full text-left">
<thead className="bg-slate-50 border-b border-slate-100 uppercase text-[9px] font-black text-slate-400">
<tr>
<th className="w-12 px-6 py-4"></th>
<th className="px-6 py-4">Manufacturer</th>
<th className="px-6 py-4 text-center">Meta Spend</th>
<th className="px-6 py-4 text-center">Google Spend</th>
<th className="px-6 py-4 text-center">SOV %</th>
<th className="px-6 py-4">Primary Brand</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-100">
{oemSpendData.map(oem => (
<React.Fragment key={oem.id}>
<tr className="hover:bg-slate-50 cursor-pointer transition-colors" onClick={() => toggleOemExpansion(oem.id)}>
<td className="px-6 py-4"><ChevronRight size={16} className={`transition-transform duration-200 ${expandedOems.includes(oem.id) ? 'rotate-90' : 'text-slate-300'}`} /></td>
<td className="px-6 py-4 font-black text-sm text-slate-900">{oem.name}</td>
<td className="px-6 py-4 text-center text-blue-600 font-black">₹{oem.metaSpend}Cr</td>
<td className="px-6 py-4 text-center text-indigo-600 font-black">₹{oem.googleSpend}Cr</td>
<td className="px-6 py-4 text-center font-black">{oem.sov}%</td>
<td className="px-6 py-4"><span className="text-[10px] font-black bg-slate-100 px-2 py-1 rounded border border-slate-200 shadow-sm">{oem.topBrand}</span></td>
</tr>
{expandedOems.includes(oem.id) && (
<tr className="bg-slate-50/30">
<td colSpan={6} className="px-12 py-6 border-b border-slate-100">
<div className="grid grid-cols-4 gap-4 animate-in fade-in slide-in-from-top-2 duration-300">
{oem.subBrands.map((brand, i) => (
<div
key={i}
className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm hover:border-black transition-all cursor-pointer group/subbrand active:scale-95 shadow-sm"
onClick={(e) => { e.stopPropagation(); handleBrandClick(brand.brandKey); }}
>
<div className="flex justify-between items-start mb-3">
<p className="text-xs font-black uppercase text-slate-900">{brand.name}</p>
<Target size={12} className="text-slate-300 group-hover/subbrand:text-blue-600" />
</div>
<div className="flex justify-between text-[10px] mb-1 font-bold">
<span className="text-slate-400 uppercase tracking-tighter">Meta</span>
<span className="text-blue-600">₹{brand.meta}L</span>
</div>
<div className="flex justify-between text-[10px] font-bold">
<span className="text-slate-400 uppercase tracking-tighter">Google</span>
<span className="text-indigo-600">₹{brand.google}L</span>
</div>
<div className="mt-3 pt-3 border-t border-slate-50 flex justify-between items-center text-[9px] font-bold uppercase text-slate-400">
<span>SOV: {brand.sov}%</span>
<span className="text-blue-600 opacity-0 group-hover/subbrand:opacity-100 transition-opacity">Drill Down <ChevronRight size={10} className="inline ml-1" /></span>
</div>
</div>
))}
</div>
</td>
</tr>
)}
</React.Fragment>
))}
</tbody>
</table>
</section>
</div>
) : (
/* --- COMPETITION VIEW --- */
<div className="space-y-16 animate-in fade-in duration-500">
{/* Header Navigation for Competition View */}
<div className="flex justify-between items-center bg-black text-white p-6 rounded-2xl shadow-xl">
<div>
<SectionTag tier="COMP" label="Live Analysis" invert />
<h2 className="text-2xl font-black uppercase tracking-tighter mt-1">
Competition: {brandsData[primaryBrand]?.name} vs Alternatives
</h2>
</div>
<button onClick={() => setViewMode('oem')} className="text-[10px] font-black border border-white/20 px-3 py-1.5 rounded-lg hover:bg-white/10 transition-colors">Return to OEM Portfolio</button>
</div>
{/* TIER 1: STRATEGIC COMPETITION OVERVIEW WITH PLATFORM SPLIT */}
<section className="bg-white p-8 rounded-2xl border border-slate-200 shadow-sm relative overflow-hidden group">
<div className="absolute top-0 right-0 p-4 opacity-[0.03] group-hover:opacity-[0.05] transition-opacity">
<Target size={160} />
</div>
<div className="flex justify-between items-start mb-10 relative z-10">
<div>
<SectionTag tier="1" label="Strategic Overview" />
<h3 className="text-lg font-black tracking-tighter mt-1 uppercase text-slate-900">Share of Expense (Meta/Google) vs Share of Voice</h3>
</div>
<div className="flex gap-4">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-blue-600" />
<span className="text-[9px] font-black text-slate-400 uppercase">Meta SOE</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-slate-300" />
<span className="text-[9px] font-black text-slate-400 uppercase">Google SOE</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-black" />
<span className="text-[9px] font-black text-slate-400 uppercase">SOV Share</span>
</div>
</div>
</div>
<div className="h-72 relative z-10 w-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={competitionChartData} margin={{ left: -20, bottom: 0 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#F1F5F9" />
<XAxis dataKey="name" axisLine={false} tickLine={false} tick={{fontSize: 10, fontWeight: 800, fill: '#64748b'}} dy={10} />
<YAxis axisLine={false} tickLine={false} tick={{fontSize: 9, fill: '#94a3b8'}} tickFormatter={(v) => `${v}%`} />
<Tooltip
contentStyle={{ borderRadius: '12px', border: 'none', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)' }}
cursor={{ fill: '#F8FAFC' }}
/>
<Legend verticalAlign="top" align="right" iconType="circle" wrapperStyle={{ paddingBottom: '20px', fontSize: '9px', fontWeight: 'bold', textTransform: 'uppercase' }} />
{/* Stacked SOE bars: Meta + Google */}
<Bar name="Meta Share of Exp." dataKey="metaSOE" stackId="soe" fill="#2563eb" barSize={32} />
<Bar name="Google Share of Exp." dataKey="googleSOE" stackId="soe" fill="#cbd5e1" radius={[4, 4, 0, 0]} barSize={32} />
{/* Separate SOV bar for direct comparison */}
<Bar name="Share of Voice" dataKey="sov" fill="#000" radius={[4, 4, 0, 0]} barSize={32} />
</BarChart>
</ResponsiveContainer>
</div>
</section>
{/* TIER 3: SIDE-BY-SIDE PANELS */}
<section className="space-y-6">
<div className="flex justify-between items-end">
<div>
<SectionTag tier="3" label="Tactical Competition" />
<h3 className="text-lg font-black tracking-tighter uppercase text-slate-900">Side-by-Side Brand Analysis</h3>
</div>
<div className="text-[10px] font-black text-slate-400 uppercase tracking-wider flex gap-4">
<span>URL Classification Engine Active</span>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{[primaryBrand, ...competitors].map((brandKey, idx) => (
<div key={brandKey} className={`space-y-6 ${idx === 0 ? '' : 'opacity-80'}`}>
<div className={`p-6 rounded-2xl bg-white border ${idx === 0 ? 'border-black shadow-lg' : 'border-slate-200 shadow-sm'}`}>
<div className="flex justify-between items-start mb-4">
<h4 className="font-black text-lg uppercase tracking-tight">{brandsData[brandKey].name}</h4>
<span className="text-[10px] font-black bg-slate-100 px-2 py-0.5 rounded uppercase">Total {brandsData[brandKey].totalSpend}</span>
</div>
<div className="flex gap-6 text-[10px] font-black uppercase">
<div className="flex flex-col"><span className="text-slate-400 text-[8px]">Meta Spend</span><span className="text-blue-600">{brandsData[brandKey].metaSpend}</span></div>
<div className="flex flex-col"><span className="text-slate-400 text-[8px]">Google Spend</span><span className="text-indigo-600">{brandsData[brandKey].googleSpend}</span></div>
</div>
<div className="mt-4 space-y-2">
<div className="flex justify-between text-[8px] font-bold text-slate-400 uppercase">
<span>Strategy Ratio</span>
<span className="text-black font-black">{brandsData[brandKey].ratio}</span>
</div>
<div className="h-1.5 w-full bg-slate-100 rounded-full overflow-hidden flex">
<div className="h-full bg-black" style={{ width: brandsData[brandKey].ratio.split('/')[0] + '%' }}></div>
<div className="h-full bg-slate-300" style={{ width: brandsData[brandKey].ratio.split('/')[1] + '%' }}></div>
</div>
</div>
</div>
</div>
))}
</div>
</section>
{/* NEW TIER 4: STRATEGIC FUNNEL JOURNEY */}
<section className="space-y-12">
<div className="flex flex-col gap-2">
<SectionTag tier="4" label="Funnel Analysis" />
<h3 className="text-xl font-black uppercase tracking-tighter text-slate-900">Funnel Journey & Spend Distribution</h3>
<p className="text-xs text-slate-400 font-bold uppercase">Cross-brand tactical efficiency breakdown from Awareness to Conversion</p>
</div>
{funnelStages.map((stage, sIdx) => (
<div key={stage.id} className="space-y-8 p-8 rounded-3xl bg-white border border-slate-200 shadow-sm relative overflow-hidden group">
<div className="absolute top-0 right-0 p-4 opacity-[0.04]">
<stage.icon size={120} />
</div>
<div className="flex justify-between items-end border-b border-slate-100 pb-6 relative z-10">
<div className="flex items-center gap-4">
<div className={`w-12 h-12 rounded-2xl ${stage.color} flex items-center justify-center text-white shadow-lg`}>
<stage.icon size={24} />
</div>
<div>
<h4 className="text-lg font-black uppercase tracking-tighter">{stage.label} Stage</h4>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">{stage.description}</p>
</div>
</div>
<div className="flex gap-12 text-right">
<div>
<p className="text-[9px] font-black text-slate-400 uppercase mb-1 tracking-tighter">Stage Meta Spend</p>
<p className="text-xl font-black text-blue-600">₹{45 - (sIdx * 10)}.2 L</p>
</div>
<div>
<p className="text-[9px] font-black text-slate-400 uppercase mb-1 tracking-tighter">Stage Google Spend</p>
<p className="text-xl font-black text-indigo-600">₹{25 + (sIdx * 5)}.8 L</p>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8 pt-4">
{[primaryBrand, ...competitors].map(brandKey => {
const stageCampaigns = brandsData[brandKey].campaigns.filter(c => c.type === stage.id);
return (
<div key={brandKey} className="space-y-4">
{stageCampaigns.length > 0 ? (
stageCampaigns.map(camp => (
<FunnelCampaignCard key={camp.id} camp={camp} brandName={brandsData[brandKey].name} />
))
) : (
<div className="h-full min-h-[160px] rounded-2xl border border-dashed border-slate-200 flex flex-col items-center justify-center p-6 text-center bg-slate-50/20">
<p className="text-[9px] font-black text-slate-300 uppercase leading-relaxed tracking-wider">No active {stage.label} assets<br/>for {brandsData[brandKey].name}</p>
</div>
)}
</div>
);
})}
</div>
</div>
))}
</section>
</div>
)}
</main>
</div>
);
};
// --- Sub-components ---
const FilterGroup = ({ label, children }) => (
<div className="flex flex-col gap-1 min-w-max">
<label className="text-[9px] font-black text-slate-400 uppercase tracking-widest">{label}</label>
{children}
</div>
);
const SectionTag = ({ tier, label, invert = false }) => (
<div className="flex items-center gap-2 mb-1">
<span className={`${invert ? 'bg-white text-black' : 'bg-black text-white'} text-[8px] font-black px-1.5 py-0.5 rounded shadow-sm uppercase`}>TIER {tier}</span>
<span className={`text-[10px] font-black ${invert ? 'text-white/50' : 'text-slate-400'} uppercase tracking-widest`}>{label}</span>
</div>
);
const KPICard = ({ title, value, sub, icon: Icon, color = "slate" }) => (
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm group hover:border-black transition-all">
<div className="flex justify-between items-start mb-4">
<div className={`p-2 rounded-lg bg-slate-50 ${color === 'blue' ? 'text-blue-600' : color === 'emerald' ? 'text-emerald-600' : 'text-slate-400'}`}>
<Icon size={18} />
</div>
<ArrowUpRight size={14} className="text-slate-300" />
</div>
<p className="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">{title}</p>
<h4 className="text-2xl font-black text-slate-900 mb-1 tracking-tighter uppercase">{value}</h4>
<p className="text-[10px] text-slate-500 font-bold uppercase overflow-hidden whitespace-nowrap text-ellipsis">{sub}</p>
</div>
);
const FunnelCampaignCard = ({ camp, brandName }) => (
<div className="bg-white border border-slate-200 rounded-3xl overflow-hidden shadow-sm hover:shadow-xl transition-all flex flex-col group/card">
<div className="p-4 bg-slate-50 border-b border-slate-100 flex justify-between items-center">
<span className="text-[9px] font-black uppercase text-slate-400 tracking-tighter">{brandName} Asset</span>
<div className="bg-emerald-100 text-emerald-700 text-[10px] font-black px-2 py-0.5 rounded border border-emerald-200">{camp.cost}</div>
</div>
<div className="p-4 space-y-4">
<div className="flex flex-col gap-1 min-w-0">
<div className="text-blue-600 text-[10px] font-bold truncate flex items-center gap-1 group-hover:text-blue-700">
<Globe size={10} /> {camp.url}
</div>
<div className="flex gap-1.5 mt-1.5">
{camp.tags.map((t, idx) => (
<span key={idx} className="text-[8px] font-black uppercase bg-white text-slate-400 px-2 py-0.5 rounded-full border border-slate-200 shadow-sm">
{t}
</span>
))}
</div>
</div>
{/* IMPROVED PREVIEW WITH MULTI-IMAGE GALLERY */}
<div className="space-y-2">
<div className="relative aspect-[16/10] rounded-2xl overflow-hidden border border-slate-100 bg-gray-50 group shadow-inner">
<img src={camp.images[0]} alt="Primary Creative" className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-1000" />
<div className="absolute inset-0 bg-black/10 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
<button className="bg-white text-black text-[9px] font-black px-4 py-2 rounded-full shadow-xl flex items-center gap-2">
<Search size={12} /> Asset Analysis
</button>
</div>
</div>
{camp.images.length > 1 && (
<div className="flex gap-2 overflow-x-auto no-scrollbar pb-1">
{camp.images.slice(1).map((img, i) => (
<div key={i} className="w-16 aspect-square rounded-lg overflow-hidden border border-slate-100 bg-slate-50 flex-shrink-0 cursor-pointer hover:border-blue-400 transition-all opacity-80 hover:opacity-100">
<img src={img} alt={`Asset ${i+2}`} className="w-full h-full object-cover" />
</div>
))}
<div className="w-16 aspect-square rounded-lg border border-dashed border-slate-200 flex flex-col items-center justify-center bg-slate-50/50 flex-shrink-0 group/add cursor-pointer">
<ImageIcon size={12} className="text-slate-300 group-hover/add:text-blue-400 transition-colors" />
<span className="text-[6px] font-black text-slate-300 mt-1 uppercase tracking-widest group-hover/add:text-blue-400">+2 Assets</span>
</div>
</div>
)}
</div>
<div className="grid grid-cols-2 gap-px bg-slate-200 border border-slate-200 rounded-xl overflow-hidden shadow-sm">
<div className="bg-white p-3 text-center">
<p className="text-[7px] font-black text-slate-400 uppercase tracking-widest mb-0.5">CTR (Efficacy)</p>
<p className={`text-xs font-black ${camp.efficacy.status === 'above' ? 'text-emerald-600' : 'text-slate-900'}`}>{camp.efficacy.ctr}</p>
</div>
<div className="bg-white p-3 text-center">
<p className="text-[7px] font-black text-slate-400 uppercase tracking-widest mb-0.5">CPM (Market)</p>
<p className="text-xs font-black text-slate-900">{camp.efficacy.cpm}</p>
</div>
</div>
<div className="bg-slate-50 p-3 rounded-2xl border border-slate-100 group-hover/card:border-slate-300 transition-colors">
<div className="flex items-center gap-1.5 text-[8px] font-black text-slate-400 uppercase mb-1.5 tracking-widest">
<MessageSquare size={10} className="text-slate-900" /> Primary Messaging
</div>
<p className="text-[10px] text-slate-700 font-bold leading-relaxed italic line-clamp-2 uppercase tracking-tight">"{camp.strategy}"</p>
</div>
<div className="grid grid-cols-3 pt-3 border-t border-slate-100 text-center gap-2">
<div><p className="text-[7px] font-black text-slate-400 uppercase mb-0.5 tracking-widest">Traffic</p><p className="text-[10px] font-black">{camp.funnel.traffic}</p></div>
<div><p className="text-[7px] font-black text-slate-400 uppercase mb-0.5 tracking-widest">Conv.</p><p className="text-[10px] font-black text-emerald-600">{camp.funnel.conversion}</p></div>
<div><p className="text-[7px] font-black text-slate-400 uppercase mb-0.5 tracking-widest">Bounce</p><p className="text-[10px] font-black text-red-500">{camp.funnel.bounce}</p></div>
</div>
</div>
</div>
);
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment