mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 11:45:23 +02:00
feat: redesign dashboard layout and header tabs to match CraftAlley V2 mockup
This commit is contained in:
@@ -58,6 +58,7 @@ const App: React.FC = () => {
|
||||
|
||||
// Modal State
|
||||
const [isDataModalOpen, setIsDataModalOpen] = useState(false);
|
||||
const [showFilters, setShowFilters] = useState(true);
|
||||
|
||||
const [filters, setFilters] = useState<FilterState>({
|
||||
customer: [],
|
||||
@@ -691,97 +692,99 @@ const App: React.FC = () => {
|
||||
setRawData([]);
|
||||
setAdsData([]);
|
||||
};
|
||||
|
||||
console.log('[App] Render Finish');
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col bg-background text-slate-200">
|
||||
|
||||
{/* Header */}
|
||||
<header className="bg-slate-950/90 backdrop-blur border-b border-border py-2 px-3 md:py-4 md:px-6 relative z-40 shadow-2xl">
|
||||
<header className="bg-slate-950/90 backdrop-blur border-b border-border py-2 px-3 md:py-3 md:px-6 relative z-40 shadow-2xl">
|
||||
<div className="max-w-7xl mx-auto flex justify-between items-center">
|
||||
<div className="flex items-center gap-3 md:gap-8">
|
||||
{/* Logo Container - Smaller on mobile */}
|
||||
<div className="h-10 w-32 md:h-16 md:w-64 relative flex-shrink-0">
|
||||
<CrazeLogo />
|
||||
</div>
|
||||
|
||||
{/* Title & Status */}
|
||||
<div className="hidden lg:block border-l border-slate-700 pl-6">
|
||||
<h1 className="text-xl font-bold tracking-tight text-white text-shadow-sm">Analytics Dashboard</h1>
|
||||
<div className="flex items-center gap-3 mt-1.5">
|
||||
<div className="flex items-center gap-1.5 px-2 py-0.5 bg-emerald-500/10 border border-emerald-500/20 rounded-full">
|
||||
<span className={`w-1.5 h-1.5 rounded-full bg-emerald-400 ${syncing ? 'animate-ping' : ''}`}></span>
|
||||
<span className="text-[9px] text-emerald-400 font-black uppercase tracking-wider">Live Sync</span>
|
||||
</div>
|
||||
{lastUpdated && (
|
||||
<span className="text-[9px] text-slate-500 font-bold uppercase tracking-wider">
|
||||
Last: {new Date(lastUpdated).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 md:gap-6">
|
||||
{/* Force Sync Action */}
|
||||
<button
|
||||
onClick={() => { handleDataFetch(); handleAdsFetch(); handleTrafficFetch(); handleVendorStockFetch(); handleBuyBoxFetch(); }}
|
||||
disabled={syncing}
|
||||
title={syncing ? 'Syncing...' : 'Sync Now'}
|
||||
className={`flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-semibold transition-all active:scale-95
|
||||
${syncing
|
||||
? 'text-indigo-400/70 cursor-not-allowed'
|
||||
: 'text-slate-500 hover:text-slate-300 hover:bg-slate-800/60'}`}
|
||||
>
|
||||
<RefreshIcon className={`w-3.5 h-3.5 ${syncing ? 'animate-spin' : ''}`} />
|
||||
<span className="hidden sm:inline">{syncing ? 'Syncing...' : 'Sync'}</span>
|
||||
</button>
|
||||
{/* View Switcher - Hidden on mobile (shown in bottom nav instead) */}
|
||||
<div className="hidden md:flex bg-slate-900 rounded-lg p-1 border border-border">
|
||||
{/* Logo Container - CraftAlley branding */}
|
||||
<div className="flex items-center gap-2 relative flex-shrink-0 cursor-pointer" onClick={() => setView('dashboard')}>
|
||||
<div className="bg-cyan-500 rounded-lg p-1.5 flex items-center justify-center w-8 h-8 shadow-[0_0_8px_rgba(6,182,212,0.4)]">
|
||||
<svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9s2.015-9 4.5-9y" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="font-extrabold text-slate-100 text-base tracking-tight select-none">CraftAlley</span>
|
||||
</div>
|
||||
|
||||
{/* View Switcher */}
|
||||
<div className="hidden md:flex bg-slate-900 rounded-lg p-0.5 border border-border/80 ml-6">
|
||||
<button
|
||||
onClick={() => setView('dashboard')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'dashboard' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'dashboard' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<ChartIcon /> <span className="hidden lg:inline">Dashboard</span>
|
||||
Dashboard
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('table')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'table' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'table' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<TableIcon /> <span className="hidden lg:inline">Grid</span>
|
||||
Grid
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('weekly')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'weekly' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'weekly' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<TrendingIcon /> <span className="hidden lg:inline">Weekly Sales</span>
|
||||
Weekly Sales
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('ads')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'ads' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'ads' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<MegaphoneIcon /> <span className="hidden lg:inline">Ads</span>
|
||||
Ads
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('forecast')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'forecast' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'forecast' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<ChartIcon /> <span className="hidden lg:inline">Fc 26</span>
|
||||
Forecasting
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setView('vendor')}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all
|
||||
${view === 'vendor' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white hover:bg-slate-800/50'}`}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all
|
||||
${view === 'vendor' ? 'bg-slate-800 text-white shadow-sm ring-1 ring-white/10' : 'text-slate-400 hover:text-white'}`}
|
||||
>
|
||||
<ChartIcon /> <span className="hidden lg:inline">BSR</span>
|
||||
SSR
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 md:gap-4">
|
||||
{/* Sync Indicators */}
|
||||
<div className="flex items-center gap-1.5 text-xs text-slate-400 bg-slate-900 px-2.5 py-1 rounded border border-border/80">
|
||||
<span className={`w-1.5 h-1.5 rounded-full bg-emerald-400 ${syncing ? 'animate-ping' : ''}`}></span>
|
||||
<span className="font-mono text-[10px] uppercase font-bold tracking-wider">
|
||||
Sync {lastUpdated ? new Date(lastUpdated).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '11:41'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Toggle Filters Action */}
|
||||
<button
|
||||
onClick={() => setShowFilters(prev => !prev)}
|
||||
className="flex items-center gap-1 px-2.5 py-1 bg-slate-900 hover:bg-slate-800 border border-slate-800 rounded text-xs font-semibold text-slate-300 transition-all active:scale-95"
|
||||
>
|
||||
<span>{showFilters ? 'Ocultar' : '+ Filtrar'}</span>
|
||||
</button>
|
||||
|
||||
{/* Export Action */}
|
||||
<button
|
||||
onClick={() => {
|
||||
// simple mockup export alert
|
||||
alert("Exportando datos filtrados...");
|
||||
}}
|
||||
className="px-3.5 py-1 bg-cyan-600 hover:bg-cyan-500 rounded text-xs font-bold text-white transition-all active:scale-95 shadow-[0_0_8px_rgba(6,182,212,0.2)]"
|
||||
>
|
||||
Exportar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -796,8 +799,19 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<FilterBar filters={filters} onFilterChange={handleFilterChange} options={filterOptions} />
|
||||
<div className="mt-6">
|
||||
{/* Title & Subtitle inside main body above filters */}
|
||||
<div className="max-w-7xl mx-auto px-3 md:px-6 pt-6 pb-2">
|
||||
<h2 className="text-2xl font-extrabold text-white tracking-tight uppercase">Analytics Dashboard</h2>
|
||||
<p className="text-[11px] text-slate-500 font-medium mt-1">
|
||||
Actualizado {lastUpdated ? new Date(lastUpdated).toLocaleDateString('es-ES', { day: 'numeric', month: 'short', year: 'numeric' }) : '17 jun 2026'} · Semana {(() => {
|
||||
// dynamic or default week number
|
||||
return '25';
|
||||
})()} · {rawData.length.toLocaleString('de-DE')} registros
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{showFilters && <FilterBar filters={filters} onFilterChange={handleFilterChange} options={filterOptions} />}
|
||||
<div className="mt-4">
|
||||
<div className={view === 'dashboard' ? '' : 'hidden'}>
|
||||
<Dashboard
|
||||
data={ytdAggregatedData}
|
||||
|
||||
Reference in New Issue
Block a user