fix: filters use string[] (not Set), charts use TvAdvancedChart for reliable multi-instance rendering

This commit is contained in:
caty21
2026-06-27 22:53:46 +02:00
parent cc1c4caf5e
commit 204e62cb6c
2 changed files with 20 additions and 23 deletions
+5 -5
View File
@@ -14,7 +14,7 @@ import YieldsTab from "@/components/YieldsTab";
import NewsTab from "@/components/NewsTab";
import CotTab from "@/components/CotTab";
import ReportTab from "@/components/ReportTab";
import { TvMiniChart } from "@/components/TvChart";
import { TvAdvancedChart } from "@/components/TvChart";
import type { CalendarEvent } from "@/app/api/calendar/route";
import type { NewsItem } from "@/app/api/news/route";
import type { CotHistory } from "@/app/api/cot-history/route";
@@ -607,10 +607,10 @@ export default function Dashboard() {
<div className="h-px flex-1 bg-sky-500/20" />
</div>
<div className="grid grid-cols-2 gap-4">
<TvMiniChart symbol="SP:SPX" label="S&P 500 · Daily" dateRange="12M" height={220} />
<TvMiniChart symbol="TVC:VIX" label="VIX · Daily" dateRange="12M" height={220} />
<TvMiniChart symbol="TVC:DXY" label="DXY Dollar Index · Weekly" dateRange="60M" height={220} />
<TvMiniChart symbol="TVC:GOLD" label="Or (XAU/USD) · Weekly" dateRange="60M" height={220} />
<TvAdvancedChart symbol="SP:SPX" label="S&P 500 · Daily" interval="D" height={220} />
<TvAdvancedChart symbol="TVC:VIX" label="VIX · Daily" interval="D" height={220} />
<TvAdvancedChart symbol="TVC:DXY" label="DXY Dollar Index · Weekly" interval="W" height={220} />
<TvAdvancedChart symbol="TVC:GOLD" label="Or (XAU/USD) · Weekly" interval="W" height={220} />
</div>
</div>
)}
+15 -18
View File
@@ -91,7 +91,7 @@ interface Props {
}
export default function NewsTab({ items, loading, onRefresh }: Props) {
const [selectedCats, setSelectedCats] = useState<Set<string>>(new Set());
const [selectedCats, setSelectedCats] = useState<string[]>([]);
const [filterDir, setFilterDir] = useState<"all" | "bullish" | "bearish">("all");
const [priorityOnly, setPriorityOnly] = useState(false);
const [autoRefresh, setAutoRefresh] = useState(true);
@@ -106,23 +106,20 @@ export default function NewsTab({ items, loading, onRefresh }: Props) {
}, [autoRefresh, onRefresh]);
const toggleCat = (cat: string) => {
setSelectedCats(prev => {
const next = new Set(prev);
if (next.has(cat)) next.delete(cat);
else next.add(cat);
return next;
});
setSelectedCats(prev =>
prev.includes(cat) ? prev.filter(c => c !== cat) : [...prev, cat]
);
};
// Filtre + tri — articles avec catégories macro et articles sans
const { topFiltered, otherItems } = useMemo(() => {
const hasActiveFilter = selectedCats.size > 0 || filterDir !== "all" || priorityOnly;
const hasActiveFilter = selectedCats.length > 0 || filterDir !== "all" || priorityOnly;
// Articles filtrés (tous)
const allFiltered = items
.filter(item => {
if (priorityOnly && !item.categories.some(c => HIGH_PRIO.has(c))) return false;
if (selectedCats.size > 0 && !item.categories.some(c => selectedCats.has(c))) return false;
if (selectedCats.length > 0 && !item.categories.some(c => selectedCats.includes(c))) return false;
if (filterDir !== "all" && !item.impacts.some(i => i.direction === filterDir)) return false;
return true;
})
@@ -143,14 +140,14 @@ export default function NewsTab({ items, loading, onRefresh }: Props) {
// Boutons de catégories : dynamiques + catégories "toujours visibles"
const activeCats = useMemo(() => {
const set = new Set<string>();
for (const item of items) item.categories.forEach(c => set.add(c));
ALWAYS_VISIBLE.forEach(c => set.add(c)); // toujours afficher ces catégories
return PRIORITY_CATS.filter(c => set.has(c));
const seen = new Set<string>();
for (const item of items) item.categories.forEach(c => seen.add(c));
ALWAYS_VISIBLE.forEach(c => seen.add(c));
return PRIORITY_CATS.filter(c => seen.has(c));
}, [items]);
const anyFilter = selectedCats.size > 0 || filterDir !== "all" || priorityOnly;
const clearFilters = () => { setSelectedCats(new Set()); setFilterDir("all"); setPriorityOnly(false); };
const anyFilter = selectedCats.length > 0 || filterDir !== "all" || priorityOnly;
const clearFilters = () => { setSelectedCats([]); setFilterDir("all"); setPriorityOnly(false); };
return (
<div className="space-y-3">
@@ -226,9 +223,9 @@ export default function NewsTab({ items, loading, onRefresh }: Props) {
<span className="text-[9px] text-amber-400 uppercase tracking-wider font-semibold shrink-0">
Catégorie
</span>
<button onClick={() => setSelectedCats(new Set())}
<button onClick={() => setSelectedCats([])}
className={`text-[10px] px-2 py-0.5 rounded-full font-semibold border transition-colors shrink-0 ${
selectedCats.size === 0
selectedCats.length === 0
? "bg-slate-700 text-slate-300 border-slate-600"
: "text-slate-500 border-slate-700/40 hover:text-slate-300"
}`}>
@@ -236,7 +233,7 @@ export default function NewsTab({ items, loading, onRefresh }: Props) {
</button>
{activeCats.map(cat => {
const meta = CATEGORY_META[cat];
const isActive = selectedCats.has(cat);
const isActive = selectedCats.includes(cat);
return (
<button key={cat} onClick={() => toggleCat(cat)}
className={`flex items-center gap-1 text-[10px] px-2 py-0.5 rounded-full font-semibold border transition-colors shrink-0 ${