"use client"; import { useEffect, useMemo, useState } from "react"; import { usePathname } from "next/navigation"; import { ArrowUpRight, ChevronLeft, ChevronRight } from "lucide-react"; import { boardsForChips, imageOf, reasonFor, weightedOrder } from "@/lib/boardSuggestions"; import { linkForLocale } from "@/lib/boardLinks"; const TEXTOS = { pt: { titulo: "Placa sugerida", afiliado: "Link de afiliado", ver: "Ver no AliExpress", anterior: "Placa anterior", proxima: "Próxima placa", de: "de", aba: "(abre em nova aba)", regiao: "Placas sugeridas com estes chips" }, en: { titulo: "Suggested board", afiliado: "Affiliate link", ver: "View on AliExpress", anterior: "Previous board", proxima: "Next board", de: "of", aba: "(opens in new tab)", regiao: "Suggested boards with these chips" }, es: { titulo: "Placa sugerida", afiliado: "Enlace de afiliado", ver: "Ver en AliExpress", anterior: "Placa anterior", proxima: "Siguiente placa", de: "de", aba: "(abre en una pestaña nueva)", regiao: "Placas sugeridas con estos chips" }, fr: { titulo: "Carte suggérée", afiliado: "Lien d'affiliation", ver: "Voir sur AliExpress", anterior: "Carte précédente", proxima: "Carte suivante", de: "sur", aba: "(ouvre un nouvel onglet)", regiao: "Cartes suggérées avec ces puces" }, de: { titulo: "Board-Vorschlag", afiliado: "Affiliate-Link", ver: "Auf AliExpress ansehen", anterior: "Vorheriges Board", proxima: "Nächstes Board", de: "von", aba: "(öffnet in neuem Tab)", regiao: "Board-Vorschläge mit diesen Chips" }, "zh-CN": { titulo: "推荐开发板", afiliado: "推广链接", ver: "在 AliExpress 查看", anterior: "上一块开发板", proxima: "下一块开发板", de: "/", aba: "(在新标签页打开)", regiao: "搭载这些芯片的推荐开发板" }, }; function localeFrom(pathname) { for (const loc of ["en", "es", "fr", "de", "zh-CN"]) { if (pathname === `/${loc}` || pathname.startsWith(`/${loc}/`)) return loc; } return "pt"; } // Uma só busca por visita, compartilhada entre as instâncias; falha vira "sem placas". let promessaDePlacas; function carregarPlacas() { if (!promessaDePlacas) { promessaDePlacas = fetch("/api/placas") .then((resposta) => (resposta.ok ? resposta.json() : Promise.reject(new Error(String(resposta.status))))) .then((json) => json.data || []) .catch(() => { promessaDePlacas = undefined; return []; }); } return promessaDePlacas; } // Faixa discreta com uma placa sorteada dos chips da página. Complementa a documentação: // fica parada, só troca quando o leitor usa as setas, e some se não houver placa. export default function PlacasSugeridas({ chips, className = "" }) { const pathname = usePathname() || ""; const locale = localeFrom(pathname); const t = TEXTOS[locale]; const chipsKey = [...chips].sort().join("|"); const [placas, setPlacas] = useState(null); const [indice, setIndice] = useState(0); const [sentido, setSentido] = useState("entrada"); useEffect(() => { let ativo = true; carregarPlacas().then((dados) => ativo && setPlacas(dados)); return () => { ativo = false; }; }, []); // O sorteio refaz só quando os dados ou o conjunto de chips mudam, não a cada render. const ordem = useMemo(() => { if (!placas) return null; return weightedOrder(boardsForChips(placas, chipsKey ? chipsKey.split("|") : [], locale)); }, [placas, chipsKey, locale]); useEffect(() => { setIndice(0); setSentido("entrada"); }, [chipsKey]); // Enquanto carrega, reserva a altura da faixa para a página não pular quando ela aparece. if (ordem === null) return
; if (ordem.length === 0) return null; const placa = ordem[Math.min(indice, ordem.length - 1)]; const total = ordem.length; const imagem = imageOf(placa); const motivo = reasonFor(placa, locale); const mostrarChip = chips.length > 1; const ir = (passo) => { setSentido(passo > 0 ? "proxima" : "anterior"); setIndice((atual) => (atual + passo + total) % total); }; return ({mostrarChip ? placa["Série"] : t.titulo} · {t.afiliado}
{placa.Nome}
{motivo}
{`${placa.Nome}, ${Math.min(indice, total - 1) + 1} ${t.de} ${total}`}