mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-08-18 06:58:06 +00:00
fix: cache no-store sur routes API, EUR emploi, NZD OIS (RBNZ), ReportTab charts 750px
- app/api/*/route.ts : export const dynamic = force-dynamic + Cache-Control no-store - lib/tecpi.ts : regex emploi EUR (grew/rose/fell), fallback body HTML, unite %/percent - lib/rateprobability.ts : RBNZ_MEETINGS 2026-2027, buildRBNZPath (mirrors buildSNBPath) CHF/NZD skippes du loop Investing.com (SNB/RBNZ rate monitor = 404) Taux RBNZ 2.25% (etait 3.25%) - components/ReportTab.tsx : hauteur charts 400 -> 750px (SPX, VIX, DXY, Gold) - lib/tradingeconomics.ts, lib/types.ts, lib/newsfeed.ts : correctifs associes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
eca5800372
commit
f5e5d51c72
@@ -333,9 +333,15 @@ function NewsCard({ item, secondary = false }: { item: NewsItem; secondary?: boo
|
||||
return (
|
||||
<div className={`rounded-xl border ${borderCls} ${bgCls} overflow-hidden ${isPriority ? "ring-1 ring-offset-0 ring-amber-500/20" : ""}`}>
|
||||
<div className="p-3">
|
||||
{/* Heure · Source · Catégorie · Prioritaire */}
|
||||
{/* Heure · Analyse · Source · Catégorie · Prioritaire */}
|
||||
<div className="flex items-center gap-2 mb-1.5 flex-wrap">
|
||||
<span className="text-[9px] text-white whitespace-nowrap shrink-0">{formatRelativeTime(item.publishedAt)}</span>
|
||||
{!secondary && (
|
||||
<button onClick={() => setExpanded(e => !e)}
|
||||
className="text-[9px] text-slate-400 hover:text-white px-1.5 py-0.5 rounded-full border border-slate-600/50 transition-colors whitespace-nowrap shrink-0">
|
||||
{expanded ? "▲" : "▼ Analyse"}
|
||||
</button>
|
||||
)}
|
||||
<span className={`text-[9px] font-semibold px-2 py-0.5 rounded-full ${SOURCE_COLORS[item.source] ?? "bg-slate-700/40 text-slate-400"}`}>
|
||||
{item.source}
|
||||
</span>
|
||||
@@ -350,8 +356,8 @@ function NewsCard({ item, secondary = false }: { item: NewsItem; secondary?: boo
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Titre + Analyse (bouton en fin de ligne) */}
|
||||
<div className="flex items-start gap-2 mb-1.5">
|
||||
{/* Titre seul */}
|
||||
<div className="flex items-start gap-1 mb-1.5">
|
||||
<a href={item.url} target="_blank" rel="noopener noreferrer"
|
||||
className="group flex items-start gap-1 flex-1 min-w-0">
|
||||
<span className={`text-[12px] leading-snug font-medium group-hover:text-white transition-colors ${secondary ? "text-slate-400" : "text-slate-200"}`}>
|
||||
@@ -359,12 +365,6 @@ function NewsCard({ item, secondary = false }: { item: NewsItem; secondary?: boo
|
||||
</span>
|
||||
<ExternalLink size={10} className="text-slate-600 group-hover:text-slate-400 shrink-0 mt-0.5" />
|
||||
</a>
|
||||
{!secondary && (
|
||||
<button onClick={() => setExpanded(e => !e)}
|
||||
className="text-[9px] text-slate-400 hover:text-white px-1.5 py-0.5 rounded-full border border-slate-600/50 transition-colors whitespace-nowrap shrink-0 mt-0.5">
|
||||
{expanded ? "▲" : "▼ Analyse"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{item.summary && !secondary && (
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { DriverData } from "@/lib/types";
|
||||
import type { FxWeeklyEntry } from "@/app/api/fx-weekly/route";
|
||||
import type { CotHistory } from "@/app/api/cot-history/route";
|
||||
import { CURRENCY_META } from "@/lib/constants";
|
||||
import { TvMiniChart, TvAdvancedChart } from "@/components/TvChart";
|
||||
import { TvAdvancedChart } from "@/components/TvChart";
|
||||
|
||||
interface Props {
|
||||
calEvents: CalendarEvent[];
|
||||
@@ -509,12 +509,12 @@ export default function ReportTab({ calEvents, drivers, cotHistory }: Props) {
|
||||
<div className="h-px flex-1 bg-sky-500/30" />
|
||||
</div>
|
||||
|
||||
{/* Macro overview : S&P, VIX, DXY, Or */}
|
||||
{/* Macro overview : S&P, VIX, DXY, Or — bougies interactives avec outils de dessin */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<TvMiniChart symbol="SP:SPX" label="S&P 500 · Daily" dateRange="12M" height={200} />
|
||||
<TvMiniChart symbol="TVC:VIX" label="VIX · Daily" dateRange="12M" height={200} />
|
||||
<TvMiniChart symbol="TVC:DXY" label="DXY Dollar Index · Weekly" dateRange="60M" height={200} />
|
||||
<TvMiniChart symbol="TVC:GOLD" label="Or (XAU/USD) · Weekly" dateRange="60M" height={200} />
|
||||
<TvAdvancedChart symbol="SP:SPX" label="S&P 500" interval="D" height={750} />
|
||||
<TvAdvancedChart symbol="TVC:VIX" label="VIX" interval="D" height={750} />
|
||||
<TvAdvancedChart symbol="TVC:DXY" label="DXY Dollar Index" interval="W" height={750} />
|
||||
<TvAdvancedChart symbol="TVC:GOLD" label="Or (XAU/USD)" interval="W" height={750} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4 pt-2">
|
||||
|
||||
@@ -178,6 +178,7 @@ function PairRow({ pairName, sym, base, quote, showVol }: {
|
||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
||||
export default function SentimentPairsTab({ symbols }: Props) {
|
||||
const [showVol, setShowVol] = useState(true);
|
||||
const [showContrariens, setShowContrariens] = useState(false);
|
||||
|
||||
const symMap: Record<string, MyfxSymbol> = {};
|
||||
for (const s of symbols ?? []) symMap[s.name] = s;
|
||||
@@ -221,30 +222,38 @@ export default function SentimentPairsTab({ symbols }: Props) {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Résumé signaux contrarien */}
|
||||
{/* Résumé signaux contrariens — compact / déroulant */}
|
||||
{contrarians.length > 0 && (
|
||||
<div className="bg-amber-500/8 border border-amber-500/20 rounded-xl p-3">
|
||||
<p className="text-[10px] font-semibold text-amber-400 uppercase tracking-wider mb-2">
|
||||
⚡ {contrarians.length} signal{contrarians.length > 1 ? "s" : ""} contrarien{contrarians.length > 1 ? "s" : ""}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{contrarians.slice(0, 8).map(p => {
|
||||
const dir = p.sym!.longPercentage >= 70 ? "short" : "long";
|
||||
return (
|
||||
<div key={p.std} className={`flex items-center gap-1.5 px-2.5 py-1 rounded-lg border text-[11px] font-medium ${
|
||||
dir === "short"
|
||||
? "bg-red-500/10 border-red-500/20 text-red-300"
|
||||
: "bg-emerald-500/10 border-emerald-500/20 text-emerald-300"
|
||||
}`}>
|
||||
<span>{CURRENCY_META[p.base]?.flag}{CURRENCY_META[p.quote]?.flag}</span>
|
||||
<span className="font-bold">{p.std}</span>
|
||||
<span className="text-[10px] opacity-70">
|
||||
{p.sym!.longPercentage}%L → signal {dir === "short" ? "↓ SELL" : "↑ BUY"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="border border-amber-500/20 rounded-xl overflow-hidden">
|
||||
<button
|
||||
onClick={() => setShowContrariens(s => !s)}
|
||||
className="w-full flex items-center justify-between px-3 py-2 bg-amber-500/8 hover:bg-amber-500/12 transition-colors"
|
||||
>
|
||||
<span className="text-[10px] font-semibold text-amber-400 uppercase tracking-wider">
|
||||
⚡ {contrarians.length} signal{contrarians.length > 1 ? "s" : ""} contrarien{contrarians.length > 1 ? "s" : ""}
|
||||
</span>
|
||||
<span className="text-amber-400/60 text-[10px]">{showContrariens ? "▲" : "▼"}</span>
|
||||
</button>
|
||||
{showContrariens && (
|
||||
<div className="flex flex-wrap gap-2 px-3 py-2.5 bg-amber-500/5">
|
||||
{contrarians.slice(0, 12).map(p => {
|
||||
const dir = p.sym!.longPercentage >= 70 ? "short" : "long";
|
||||
return (
|
||||
<div key={p.std} className={`flex items-center gap-1.5 px-2.5 py-1 rounded-lg border text-[11px] font-medium ${
|
||||
dir === "short"
|
||||
? "bg-red-500/10 border-red-500/20 text-red-300"
|
||||
: "bg-emerald-500/10 border-emerald-500/20 text-emerald-300"
|
||||
}`}>
|
||||
<span>{CURRENCY_META[p.base]?.flag}{CURRENCY_META[p.quote]?.flag}</span>
|
||||
<span className="font-bold">{p.std}</span>
|
||||
<span className="text-[10px] opacity-70">
|
||||
{p.sym!.longPercentage}%L → {dir === "short" ? "↓ SELL" : "↑ BUY"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -87,10 +87,10 @@ export function TvAdvancedChart({
|
||||
hide_legend: false,
|
||||
allow_symbol_change: false,
|
||||
calendar: false,
|
||||
hide_volume: true,
|
||||
hide_volume: false,
|
||||
isTransparent: true,
|
||||
save_image: true,
|
||||
drawings_access: { type: "all", tools: [{ name: "Regression Trend" }] },
|
||||
drawings_access: { type: "all" },
|
||||
container_id: containerId,
|
||||
},
|
||||
height
|
||||
|
||||
Reference in New Issue
Block a user