mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:25:22 +02:00
feat: improve 'Group By' dropdown UI/UX in Grid tab (click-to-open and click-outside to close)
This commit is contained in:
+46
-23
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useMemo, useEffect } from 'react';
|
||||
import React, { useState, useMemo, useEffect, useRef } from 'react';
|
||||
import {
|
||||
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
|
||||
} from 'recharts';
|
||||
@@ -233,6 +233,19 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData =
|
||||
const [visibleMetrics, setVisibleMetrics] = useState<('sellOut' | 'units')[]>(['sellOut', 'units']);
|
||||
const [showAdsMetrics, setShowAdsMetrics] = useState(true);
|
||||
const [showAttributedSales, setShowAttributedSales] = useState(false);
|
||||
const [showDimensionMenu, setShowDimensionMenu] = useState(false);
|
||||
const dimensionRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Close dimension menu on click outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (dimensionRef.current && !dimensionRef.current.contains(event.target as Node)) {
|
||||
setShowDimensionMenu(false);
|
||||
}
|
||||
};
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
// Calculate Ads Summary for the Grid
|
||||
const adsSummary = useMemo(() => {
|
||||
@@ -682,31 +695,41 @@ const DataGrid: React.FC<DataGridProps> = ({ data, hasCustomerFilter, adsData =
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3 w-full lg:w-auto">
|
||||
{/* Dimensions Selector */}
|
||||
<div className="relative group z-30">
|
||||
<button className="flex items-center gap-2 px-3 py-2 bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-lg text-sm font-medium transition-colors">
|
||||
<div className="relative z-30" ref={dimensionRef}>
|
||||
<button
|
||||
onClick={() => setShowDimensionMenu(!showDimensionMenu)}
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all border shadow-sm ${showDimensionMenu ? 'bg-slate-700 text-white border-indigo-500/50 ring-1 ring-indigo-500/30' : 'bg-slate-800 text-slate-300 border-slate-700 hover:bg-slate-700'}`}
|
||||
>
|
||||
<span className="text-slate-300">Group By:</span>
|
||||
<span className="text-white font-bold">{effectiveDimensions.length} Columns</span>
|
||||
<svg className="w-4 h-4 text-slate-400" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></svg>
|
||||
<svg className={`w-4 h-4 text-slate-400 transition-transform duration-200 ${showDimensionMenu ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></svg>
|
||||
</button>
|
||||
<div className="absolute top-full left-0 mt-2 w-48 bg-slate-900 border border-slate-700 rounded-xl shadow-xl p-2 hidden group-hover:block animate-fade-in">
|
||||
{DIMENSION_OPTIONS.map(dim => (
|
||||
<label key={dim.value} className="flex items-center gap-2 p-2 hover:bg-slate-800 rounded cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedDimensions.includes(dim.value)}
|
||||
onChange={() => {
|
||||
if (selectedDimensions.includes(dim.value)) {
|
||||
setSelectedDimensions(selectedDimensions.filter(d => d !== dim.value));
|
||||
} else {
|
||||
setSelectedDimensions([...selectedDimensions, dim.value]);
|
||||
}
|
||||
}}
|
||||
className="rounded border-slate-600 bg-slate-800 text-primary focus:ring-primary"
|
||||
/>
|
||||
<span className="text-sm text-slate-300">{dim.label}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
{showDimensionMenu && (
|
||||
<div className="absolute top-full left-0 mt-2 w-56 bg-slate-900 border border-slate-700 rounded-xl shadow-2xl p-2 animate-fade-in z-50">
|
||||
<div className="px-2 py-1.5 mb-1 border-b border-slate-800">
|
||||
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest">Select Columns</span>
|
||||
</div>
|
||||
{DIMENSION_OPTIONS.map(dim => (
|
||||
<label key={dim.value} className="flex items-center gap-3 p-2.5 hover:bg-white/[0.03] rounded-lg cursor-pointer group transition-colors">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedDimensions.includes(dim.value)}
|
||||
onChange={() => {
|
||||
if (selectedDimensions.includes(dim.value)) {
|
||||
setSelectedDimensions(selectedDimensions.filter(d => d !== dim.value));
|
||||
} else {
|
||||
setSelectedDimensions([...selectedDimensions, dim.value]);
|
||||
}
|
||||
}}
|
||||
className="w-4 h-4 rounded border-slate-600 bg-slate-800 text-indigo-500 focus:ring-indigo-500/50 transition-all"
|
||||
/>
|
||||
<span className={`text-sm font-medium transition-colors ${selectedDimensions.includes(dim.value) ? 'text-white' : 'text-slate-400 group-hover:text-slate-300'}`}>
|
||||
{dim.label}
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Filter Builder Trigger */}
|
||||
|
||||
Reference in New Issue
Block a user