From ec92217882c04f61b7898656f4f193c4750af09f Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Thu, 22 Jan 2026 11:49:47 -0300 Subject: [PATCH] feat: enhance selection tool with Ethernet and display options, improve answer handling and results display --- app/seletor/page.jsx | 527 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 442 insertions(+), 85 deletions(-) diff --git a/app/seletor/page.jsx b/app/seletor/page.jsx index a97f685..e721f60 100644 --- a/app/seletor/page.jsx +++ b/app/seletor/page.jsx @@ -8,6 +8,7 @@ import seriesData from "@/public/series.json"; export default function Seletor() { const [currentStep, setCurrentStep] = useState(0); + const [currentAnswer, setCurrentAnswer] = useState(null); const [answers, setAnswers] = useState({ wifi: null, bluetooth: null, @@ -17,7 +18,11 @@ export default function Seletor() { gpio: null, usb: null, lowPower: null, + ethernet: null, + display: null, }); + const [showResults, setShowResults] = useState(false); + const [showSummary, setShowSummary] = useState(false); const questions = [ { @@ -40,6 +45,15 @@ export default function Seletor() { { value: "no", label: "Não preciso", icon: "🚫" }, ] }, + { + id: "ethernet", + question: "Precisa de conexão Ethernet (cabeada)?", + description: "Ethernet oferece conexão mais estável e rápida que Wi-Fi", + options: [ + { value: "yes", label: "Sim, preciso", icon: "🔌" }, + { value: "no", label: "Não preciso", icon: "🚫" }, + ] + }, { id: "cores", question: "Quantos núcleos de processamento você precisa?", @@ -59,6 +73,17 @@ export default function Seletor() { { value: "no", label: "Não preciso", icon: "🚫" }, ] }, + { + id: "display", + question: "Precisa conectar display ou câmera?", + description: "Interfaces LCD/MIPI para displays e DVP/CSI para câmeras", + options: [ + { value: "both", label: "Display e câmera", icon: "📱📷" }, + { value: "display", label: "Apenas display", icon: "📺" }, + { value: "camera", label: "Apenas câmera", icon: "📷" }, + { value: "no", label: "Não preciso", icon: "🚫" }, + ] + }, { id: "matter", question: "Precisa de suporte a Matter, Zigbee ou Thread?", @@ -101,14 +126,27 @@ export default function Seletor() { ]; const handleAnswer = (questionId, value) => { + setCurrentAnswer(value); setAnswers({ ...answers, [questionId]: value }); - if (currentStep < questions.length - 1) { - setCurrentStep(currentStep + 1); + }; + + const handleNext = () => { + if (currentAnswer !== null) { + if (currentStep < questions.length - 1) { + setCurrentStep(currentStep + 1); + setCurrentAnswer(answers[questions[currentStep + 1].id] || null); + } else { + // Última pergunta - mostrar resumo primeiro + setShowSummary(true); + } } }; const resetQuiz = () => { setCurrentStep(0); + setCurrentAnswer(null); + setShowResults(false); + setShowSummary(false); setAnswers({ wifi: null, bluetooth: null, @@ -118,109 +156,212 @@ export default function Seletor() { gpio: null, usb: null, lowPower: null, + ethernet: null, + display: null, }); }; const goBack = () => { if (currentStep > 0) { setCurrentStep(currentStep - 1); + setCurrentAnswer(answers[questions[currentStep - 1].id] || null); } }; const calculateRecommendations = () => { const scores = {}; + const reasons = {}; Object.keys(seriesData).forEach(key => { scores[key] = 0; + reasons[key] = []; const serie = seriesData[key]; // Wi-Fi - if (answers.wifi === "required" && serie.wifi && !String(serie.wifi).includes("Não")) { - scores[key] += 10; - } else if (answers.wifi === "no" && (!serie.wifi || String(serie.wifi).includes("Não"))) { - scores[key] += 5; + if (answers.wifi === "required") { + if (serie.wifi && !String(serie.wifi).includes("Não")) { + scores[key] += 10; + reasons[key].push(`✅ Wi-Fi ${serie.wifi.includes("Wi-Fi 6") ? "6 (última geração)" : "disponível"}`); + } else { + scores[key] -= 100; + reasons[key].push("❌ Wi-Fi não disponível (requisito essencial)"); + } } else if (answers.wifi === "nice" && serie.wifi && !String(serie.wifi).includes("Não")) { scores[key] += 3; - } else if (answers.wifi === "required" && (!serie.wifi || String(serie.wifi).includes("Não"))) { - scores[key] -= 100; // Desqualifica + reasons[key].push(`💡 Wi-Fi ${serie.wifi.includes("Wi-Fi 6") ? "6" : ""} disponível`); } // Bluetooth - if (answers.bluetooth === "required" && serie.bluetooth !== "Não") { - scores[key] += 10; - } else if (answers.bluetooth === "no" && serie.bluetooth === "Não") { - scores[key] += 5; + if (answers.bluetooth === "required") { + if (serie.bluetooth !== "Não") { + scores[key] += 10; + reasons[key].push(`✅ ${serie.bluetooth}`); + } else { + scores[key] -= 100; + reasons[key].push("❌ Bluetooth não disponível (requisito essencial)"); + } } else if (answers.bluetooth === "nice" && serie.bluetooth !== "Não") { scores[key] += 3; - } else if (answers.bluetooth === "required" && serie.bluetooth === "Não") { - scores[key] -= 100; // Desqualifica + reasons[key].push(`💡 ${serie.bluetooth}`); + } + + // Ethernet + if (answers.ethernet === "yes") { + if (serie.ethernet === "Sim") { + scores[key] += 12; + reasons[key].push("✅ Ethernet MAC integrado"); + } else { + scores[key] -= 8; + reasons[key].push("⚠️ Ethernet não disponível"); + } } // Núcleos - if (answers.cores === "dual" && serie.nucleos.includes("2")) { - scores[key] += 8; + if (answers.cores === "dual") { + if (serie.nucleos.includes("2")) { + scores[key] += 8; + reasons[key].push("✅ Dual-core para processamento paralelo"); + } else { + scores[key] -= 5; + reasons[key].push("⚠️ Apenas single-core"); + } } else if (answers.cores === "single" && serie.nucleos.includes("1")) { scores[key] += 5; - } else if (answers.cores === "dual" && !serie.nucleos.includes("2")) { - scores[key] -= 5; + reasons[key].push("✅ Single-core eficiente"); } // IA - if (answers.ai === "yes" && serie.aceleradores_ia) { - scores[key] += 15; - } else if (answers.ai === "yes" && !serie.aceleradores_ia) { - scores[key] -= 10; + if (answers.ai === "yes") { + if (serie.aceleradores_ia) { + scores[key] += 15; + reasons[key].push("✅ Aceleradores de IA integrados"); + } else { + scores[key] -= 10; + reasons[key].push("⚠️ Sem aceleradores de IA dedicados"); + } + } + + // Display/Câmera + if (answers.display === "both") { + if ((serie.lcd || serie.mipi_dsi) && (serie.camera || serie.mipi_csi)) { + scores[key] += 15; + reasons[key].push("✅ Interfaces para display e câmera"); + } else { + scores[key] -= 8; + reasons[key].push("⚠️ Interfaces limitadas para display/câmera"); + } + } else if (answers.display === "display") { + if (serie.lcd || serie.mipi_dsi) { + scores[key] += 10; + reasons[key].push(`✅ Interface ${serie.mipi_dsi ? "MIPI DSI" : "LCD"} para display`); + } else { + scores[key] -= 5; + reasons[key].push("⚠️ Interface de display limitada"); + } + } else if (answers.display === "camera") { + if (serie.camera || serie.mipi_csi) { + scores[key] += 10; + reasons[key].push(`✅ Interface ${serie.mipi_csi ? "MIPI CSI" : "DVP"} para câmera`); + } else { + scores[key] -= 5; + reasons[key].push("⚠️ Interface de câmera limitada"); + } } // Matter/Zigbee/Thread - if (answers.matter === "yes" && serie.matter === "Sim") { - scores[key] += 12; - } else if (answers.matter === "yes" && serie.matter !== "Sim") { - scores[key] -= 8; + if (answers.matter === "yes") { + if (serie.matter === "Sim") { + scores[key] += 12; + reasons[key].push("✅ Suporte a Matter/Thread/Zigbee"); + } else { + scores[key] -= 8; + reasons[key].push("⚠️ Sem suporte a Matter/Thread/Zigbee"); + } } // GPIO const gpioCount = parseInt(serie.gpio); - if (answers.gpio === "many" && gpioCount >= 35) { - scores[key] += 8; - } else if (answers.gpio === "medium" && gpioCount >= 20 && gpioCount < 35) { - scores[key] += 8; + if (answers.gpio === "many") { + if (gpioCount >= 35) { + scores[key] += 8; + reasons[key].push(`✅ ${gpioCount} pinos GPIO (muitos)`); + } else { + scores[key] -= 5; + reasons[key].push(`⚠️ ${gpioCount} GPIO (pode ser limitado)`); + } + } else if (answers.gpio === "medium") { + if (gpioCount >= 20 && gpioCount < 35) { + scores[key] += 8; + reasons[key].push(`✅ ${gpioCount} pinos GPIO (quantidade média)`); + } else if (gpioCount >= 35) { + scores[key] += 6; + reasons[key].push(`✅ ${gpioCount} pinos GPIO (mais que o necessário)`); + } else { + scores[key] -= 3; + reasons[key].push(`⚠️ ${gpioCount} GPIO (pode ser limitado)`); + } } else if (answers.gpio === "few" && gpioCount < 20) { scores[key] += 8; - } else if (answers.gpio === "many" && gpioCount < 35) { - scores[key] -= 5; + reasons[key].push(`✅ ${gpioCount} pinos GPIO (suficiente)`); } // USB - if (answers.usb === "yes" && serie.usb && serie.usb !== "Não") { - scores[key] += 10; + if (answers.usb === "yes") { + if (serie.usb && serie.usb !== "Não") { + scores[key] += 10; + reasons[key].push(`✅ ${serie.usb}`); + } else { + scores[key] -= 5; + reasons[key].push("⚠️ USB não disponível"); + } } else if (answers.usb === "nice" && serie.usb && serie.usb !== "Não") { scores[key] += 5; - } else if (answers.usb === "yes" && (!serie.usb || serie.usb === "Não")) { - scores[key] -= 5; + reasons[key].push(`💡 ${serie.usb} disponível`); } // Baixo consumo if (answers.lowPower === "critical") { const deepSleep = serie.consumo_energia?.deep_sleep; - if (deepSleep && (deepSleep.includes("µA") || deepSleep.includes("5 µA") || deepSleep.includes("7 µA"))) { - scores[key] += 12; + if (deepSleep) { + const microAmps = deepSleep.match(/(\d+)\s*µA/); + if (microAmps && parseInt(microAmps[1]) <= 10) { + scores[key] += 12; + reasons[key].push(`✅ Consumo ultra-baixo: ${deepSleep} em deep sleep`); + } else { + scores[key] += 5; + reasons[key].push(`💡 Consumo: ${deepSleep} em deep sleep`); + } } + } else if (answers.lowPower === "nice") { + const deepSleep = serie.consumo_energia?.deep_sleep; + if (deepSleep) { + const microAmps = deepSleep.match(/(\d+)\s*µA/); + if (microAmps && parseInt(microAmps[1]) <= 10) { + scores[key] += 5; + reasons[key].push(`💡 Baixo consumo: ${deepSleep}`); + } + } + } + + // Bonus: Características adicionais + if (serie.frequencia && parseInt(serie.frequencia) >= 240) { + reasons[key].push(`⚡ Alta performance: ${serie.frequencia}`); } }); - // Ordenar por pontuação - const sortedSeries = Object.entries(scores) - .filter(([_, score]) => score > 0) - .sort(([, a], [, b]) => b - a) - .slice(0, 3); - - return sortedSeries.map(([key]) => key); + return { scores, reasons }; }; - const recommendations = currentStep === questions.length - 1 && Object.values(answers).every(a => a !== null) + const { scores: allScores, reasons: allReasons } = showResults && Object.values(answers).every(a => a !== null) ? calculateRecommendations() - : []; + : { scores: {}, reasons: {} }; + + const recommendations = Object.entries(allScores) + .filter(([_, score]) => score > 0) + .sort(([, a], [, b]) => b - a); + + const topRecommendations = recommendations.slice(0, 3); + const otherRecommendations = recommendations.slice(3); const progress = ((currentStep + 1) / questions.length) * 100; @@ -263,43 +404,54 @@ export default function Seletor() { {/* Question Card */} - {currentStep < questions.length && recommendations.length === 0 && ( -
+ {currentStep < questions.length && !showResults && !showSummary && ( +
-

+

{questions[currentStep].question}

-

+

{questions[currentStep].description}

-
+
{questions[currentStep].options.map((option) => ( ))}
{/* Navigation Buttons */} -
+
+
+ )} + + {/* Summary Page */} + {showSummary && !showResults && ( +
+
+
+ 📋 +
+

+ Resumo das suas Respostas +

+

+ Revise suas escolhas antes de ver as recomendações +

+
+ +
+ {questions.map((question) => { + const answer = answers[question.id]; + const selectedOption = question.options.find(opt => opt.value === answer); + + return ( +
+
+
+

+ {question.question} +

+ {selectedOption && ( +
+ {selectedOption.icon} + + {selectedOption.label} + +
+ )} +
+ +
+
+ ); + })} +
+ +
+ + +
)} {/* Results */} - {recommendations.length > 0 && ( + {showResults && recommendations.length > 0 && (
-
+
-
- ✨ +
+ ✨
-

+

Recomendações para seu Projeto

-

+

Baseado nas suas respostas, estas são as melhores opções de ESP32 para você:

-
- {recommendations.map((seriesKey, index) => { +
+ {topRecommendations.map(([seriesKey, score], index) => { const serie = seriesData[seriesKey]; const badges = ["🥇 Melhor Opção", "🥈 Segunda Opção", "🥉 Terceira Opção"]; + const matchReasons = allReasons[seriesKey] || []; return (
-
+
- + {badges[index]} -
{serie.icone}
-

{seriesKey}

-

{serie.descricao}

+
{serie.icone}
+

{seriesKey}

+

{serie.descricao}

+
+ Score: + {score} +
-
-
+ {/* Match Reasons */} + {matchReasons.length > 0 && ( +
+

Por que esta série?

+
    + {matchReasons.slice(0, 5).map((reason, idx) => ( +
  • + {reason} +
  • + ))} + {matchReasons.length > 5 && ( +
  • + +{matchReasons.length - 5} mais vantagens +
  • + )} +
+
+ )} + +
+
Arquitetura: {serie.arquitetura.split(' ')[0]}
-
+
Núcleos: {serie.nucleos}
-
+
Frequência: {serie.frequencia}
-
+
SRAM: {serie.memoria_sram}
-
+
GPIO: {serie.gpio}
-
+
Ver Detalhes @@ -392,10 +665,43 @@ export default function Seletor() { })}
-
+ {/* Other Compatible Options */} + {otherRecommendations.length > 0 && ( +
+

+ Outras Opções Compatíveis +

+
+ {otherRecommendations.map(([seriesKey, score]) => { + const serie = seriesData[seriesKey]; + return ( +
+
+
{serie.icone}
+

{seriesKey}

+ Score: {score} +
+ + Ver Detalhes + +
+ ); + })} +
+
+ )} + +
📊 Comparar Recomendações @@ -403,7 +709,7 @@ export default function Seletor() {
)} + + {/* No Results Found */} + {showResults && recommendations.length === 0 && ( +
+
+
+ 🤔 +
+

+ Nenhuma Correspondência Perfeita +

+

+ Não encontramos uma série ESP32 que atenda completamente aos seus requisitos. + Isso pode acontecer quando você combina requisitos que são mutuamente exclusivos ou muito específicos. +

+
+

💡 Sugestões:

+
    +
  • + • + Revise seus requisitos e considere quais são realmente essenciais +
  • +
  • + • + Algumas combinações (como Wi-Fi 6 + aceleradores de IA) podem requerer séries específicas +
  • +
  • + • + Considere usar múltiplos módulos ESP32 para diferentes funções do seu projeto +
  • +
+
+
+ + + 📊 + Ver Todas as Séries + +
+
+
+ )}