diff --git a/back-codequest/src/core/rotas.js b/back-codequest/src/core/rotas.js index 28b2c07..88d5b5f 100644 --- a/back-codequest/src/core/rotas.js +++ b/back-codequest/src/core/rotas.js @@ -1,6 +1,7 @@ const Emails = require('../daos/emails.js'); const Email = require('../dbos/email.js'); const Comunicado = require('./comunicado.js'); +const { calculateJob } = require('../functions/CalculateTheProfission.js'); // Added import async function inclusao(req, res) { if(Object.values(req.body).length !=2 || !req.body.id || !req.body.email) { @@ -170,5 +171,38 @@ async function recuperacaoDeTodos(req, res) { } return res.status(200).json(ret); } - -module.exports = { inclusao, atualizacao, remocao, recuperacaoDeUm, recuperacaoDeTodos } \ No newline at end of file + +async function calculateVocationRoute(req, res) { + try { + const { answers } = req.body; + + // Input Validation + if (!answers || !Array.isArray(answers) || answers.length !== 20) { + const erro = Comunicado.novo('DDI','Dados Inválidos', 'As respostas fornecidas são inválidas. Esperava-se um array de 20 números.').object; + return res.status(400).json(erro); + } + + for (const answer of answers) { + if (typeof answer !== 'number') { + const erro = Comunicado.novo('DDI','Dados Inválidos', 'Todas as respostas devem ser números.').object; + return res.status(400).json(erro); + } + } + + // Call Calculation Logic + const result = calculateJob(answers); + return res.status(200).json(result); + + } catch (error) { + console.error('Error calculating vocational test:', error); // Log the error on the server + // Check if the error is from calculateJob's specific validation or a general one + if (error.message && (error.message.includes('Missing Questionnarie') || error.message.includes('Any alternative is null') || error.message.includes('Entering invalid data'))) { + const erro = Comunicado.novo('DDI','Dados Inválidos', error.message).object; + return res.status(400).json(erro); + } + const erro = Comunicado.novo('PFL','Processamento Falhou', 'Ocorreu um erro ao calcular o resultado do teste vocacional.').object; + return res.status(500).json(erro); + } +} + +module.exports = { inclusao, atualizacao, remocao, recuperacaoDeUm, recuperacaoDeTodos, calculateVocationRoute } \ No newline at end of file diff --git a/back-codequest/src/functions/CalculateTheProfission.js b/back-codequest/src/functions/CalculateTheProfission.js index 4870101..d1543a0 100644 --- a/back-codequest/src/functions/CalculateTheProfission.js +++ b/back-codequest/src/functions/CalculateTheProfission.js @@ -6,20 +6,21 @@ class CalculateTheJob { #formAnswers constructor(formAnswers) { - this.#formAnswers = formAnswers; + this.formAnswers = formAnswers; } get formAnswers() { return this.#formAnswers } set formAnswers(formAnswers) { - const ENNEAGRAM_QUESTIONS_QUANTITY = 25; + const EXPECTED_ANSWERS = 20; if(formAnswers === undefined) throw ('Missing Questionnarie'); - if(formAnswers.length !== ENNEAGRAM_QUESTIONS_QUANTITY) throw ('Any alternative is null'); - for(let line = 0; line < ENNEAGRAM_QUESTIONS_QUANTITY; line++) { - if(typeof formAnswers[line] !== Number || + if(formAnswers.length !== EXPECTED_ANSWERS) throw ('Any alternative is null'); + this.#formAnswers = []; + for(let line = 0; line < EXPECTED_ANSWERS; line++) { + if(typeof formAnswers[line] !== 'number' || // Corrected 'Number' to 'number' isNaN(formAnswers[line]) || - formAnswers[line] !== parseInt(formAnswers[line] || - formAnswers[line] <= 0 || formAnswers[line] > 5))  + formAnswers[line] !== parseInt(formAnswers[line]) || // Corrected logical OR error + formAnswers[line] <= 0 || formAnswers[line] > 5)  throw('Entering invalid data'); this.#formAnswers[line] = formAnswers[line]; } @@ -27,29 +28,29 @@ class CalculateTheJob { } function calculateJob(formAnswers){ - formAnswers = new CalculateTheJob(formAnswers); - const ENNEAGRAM_QUESTIONS_QUANTITY = 45; - let sumType1; - let sumType2; - let sumType3; - let sumType4; - let sumType5; - let resp; - for(let line = 0; line < ENNEAGRAM_QUESTIONS_QUANTITY; line++) { - if(line < 5) { - sumType1 += this.formAnswers[line]; + const jobCalculator = new CalculateTheJob(formAnswers); // Create instance + const QUESTIONS_TO_PROCESS = 20; // Define number of questions to process + let sumType1 = 0; // Initialize sumType1 + let sumType2 = 0; // Initialize sumType2 + let sumType3 = 0; // Initialize sumType3 + let sumType4 = 0; // Initialize sumType4 + let sumType5 = 0; // Initialize sumType5 + let resp = []; // Initialize resp + for(let line = 0; line < QUESTIONS_TO_PROCESS; line++) { // Loop through questions to process + if(line < 4) { // Questions 0-3 for sumType1 + sumType1 += jobCalculator.formAnswers[line]; // Access answers from instance } - if(line >= 5 && line < 10) { - sumType2 += this.formAnswers[line]; + if(line >= 4 && line < 8) { // Questions 4-7 for sumType2 + sumType2 += jobCalculator.formAnswers[line]; // Access answers from instance } - if(line >= 10 && line < 15) { - sumType3 += this.formAnswers[line]; + if(line >= 8 && line < 12) { // Questions 8-11 for sumType3 + sumType3 += jobCalculator.formAnswers[line]; // Access answers from instance } - if(line >= 15 && line < 20) { - sumType4 += this.formAnswers[line]; + if(line >= 12 && line < 16) { // Questions 12-15 for sumType4 + sumType4 += jobCalculator.formAnswers[line]; // Access answers from instance } - if(line >= 20 && line < 25) { - sumType5 += this.formAnswers[line]; + if(line >= 16 && line < 20) { // Questions 16-19 for sumType5 + sumType5 += jobCalculator.formAnswers[line]; // Access answers from instance } } if(sumType1 >= 15) resp[0] = sumType1; diff --git a/front-codequest/src/pages/desktop/HomePage.css b/front-codequest/src/pages/desktop/HomePage.css index b3e5e36..38e1271 100644 --- a/front-codequest/src/pages/desktop/HomePage.css +++ b/front-codequest/src/pages/desktop/HomePage.css @@ -1,489 +1,527 @@ -.home-page-desktop { - position: relative; - width: 100%; - text-align: left; - font-size: 1.6vw; /* Use vw para tamanho de fonte responsivo */ - color: var(--color-white); - font-family: var(--font-tt-mussels-trl); - overflow-x: hidden; -} - -.background-contact-icon { - height: 100%; - width: 100%; - max-width: 100%; -} - -.cdquestinsta { - margin-left: 90px; - margin-top: -55px; -} - -.cdquestmail { - margin-left: 90px; - margin-top: 15px; -} - -.cdquestloca { - margin-left: 90px; - margin-top: -50px; -} -.logos-icon { - position: absolute; - top: 195px; - left: 127px; - width: 330px; - height: 255px; - object-fit: cover; -} - -.vector-icon { - position: absolute; - left: 0; -} - -.gmail { - position: absolute; - height: 29.06%; - width: 72.39%; - top: 34.54%; - right: 27.61%; - bottom: 36.41%; -} - -.codequest- { - text-decoration: underline; - position: absolute; - width: 65.21%; - top: 26.31%; - left: 34.79%; - color: inherit; - display: inline-block; -} - -.instagram{ - position: absolute; -} - -.gmail{ - position: absolute; -} - -.local{ - position: absolute; -} - -.local { - height: 30%; - top: 69%; -} - - - -.vector-icon, -.vector-icon1, -.vector-icon2 { - width: 70px; - height: 70px; -} - -.vector-icon:hover, -.vector-icon1:hover, -.vector-icon2:hover { - transform: scale(1.2); - transition: transform 0.2s ease-in-out; -} - -.contact-page, -.socials { - position: absolute; - object-fit: cover; - top: 26.74%; - right: 5.99%; - bottom: 28.41%; - left: 59.11%; -} - -.contact-page { - height: 23.96%; - width: 100%; - top: 76.04%; - right: 0; - bottom: 0; - left: 0; -} - -.image-10-icon, -.rock-of-the-astronaut-1 { - position: absolute; - top: 0; - left: 0; - width: 1925px; - height: 945px; - object-fit: cover; -} - -.rock-of-the-astronaut-1 { - height: 26.14%; - width: 33.18%; - right: 8.49%; - bottom: 73.86%; - left: 58.33%; - max-width: 100%; - overflow: hidden; - max-height: 100%; -} - -.about-us { - margin: 0; - position: absolute; - top: 0; - left: 0; - font-size: inherit; - font-weight: 700; - font-family: inherit; - display: inline-block; - width: 389.01px; -} - -.rectangle-title { - position: absolute; - top: 101px; - left: 0; - background-color: var(--color-midnightblue); - width: 212.55px; - height: 32px; - overflow: hidden; -} - -.rectangle-high { - position: relative; - border-radius: 0px 0px 20px 20px; - background: linear-gradient(90deg, #6113a8, rgba(69, 63, 203, 0)); - backdrop-filter: blur(25px); - width: 100%; - height: 96px; -} - -.title-about { - position: absolute; - top: 116px; - left: 62.16px; - width: 389.01px; - height: 133px; - font-size: var(--font-size-81xl); -} - -.c { - font-family: var(--font-tt-mussels-trl); -} - -.txtAbout { - margin: 0; - position: absolute; - top: 336px; - left: 62.16px; - font-size: var(--font-size-21xl); - display: inline-block; - width: 1700.42px; - font-family: inherit; -} - -.image-6-icon { - position: absolute; - top: 0; - left: 0; - border-radius: var(--br-107xl); - width: 271.71px; - height: 256px; - object-fit: cover; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: transform 0.3s ease; -} - -.image-6-icon:hover { - transform: scale(1.1); -} - -.gustavo-miguel { - margin: 0; - position: absolute; - top: 258px; - left: 15.99px; - font-size: inherit; - font-weight: 400; - font-family: inherit; - display: inline-block; - width: 234.61px; - text-shadow: 2px 1px 0#2d0159; -} - -.gustavo, -.image-4-icon { - position: absolute; - top: 545px; - left: 117.3px; - width: 271.71px; - height: 297px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: transform 0.3s ease; -} - -.image-4-icon:hover { - transform: scale(1.1); -} - -.image-4-icon { - top: 0; - left: 0; - border-radius: var(--br-107xl); - width: 269.7px; - height: 252px; - object-fit: cover; -} - -.kauan-piacente { - margin: 0; - position: absolute; - top: 258px; - left: 18.97px; - font-size: inherit; - font-weight: 400; - font-family: inherit; - display: inline-block; - width: 235.61px; - text-shadow: 2px 1px 0#2d0159; -} - -.kauan { - position: absolute; - top: 545px; - left: 786.04px; - width: 269.7px; - height: 297px; -} - -.joo-victor { - margin: 0; - position: absolute; - top: 264px; - left: 49.08px; - font-size: inherit; - font-weight: 400; - font-family: inherit; - display: inline-block; - width: 167.43px; - text-shadow: 2px 1px 0#2d0159; -} - -.image-5-icon, -.joo { - position: absolute; - width: 269.7px; -} - -.image-5-icon { - top: 0; - left: 0; - border-radius: var(--br-107xl); - height: 263px; - object-fit: cover; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: transform 0.3s ease; -} - -.image-5-icon:hover { - transform: scale(1.1); -} - -.joo { - top: 539px; - left: 1466.81px; - height: 303px; -} - -.about-page, -.background-high-icon { - position: absolute; - top: 1083px; - left: 0; - width: 1925px; - height: 945px; - -} - -.background-high-icon { - top: 0; - height: 1083px; - object-fit: cover; -} - -.astronaut-icon, -.rectangle-high-icon { - position: absolute; - top: 96px; - left: 1079px; - width: 828px; - height: 987px; - object-fit: cover; -} - -.rectangle-high-icon { - top: 0; - left: 0; - border-radius: var(--br-xl); - width: 1925px; - height: 96px; -} - -.logo-branco-icon { - position: absolute; - top: 15px; - left: 42px; - width: 295px; - height: 66px; - object-fit: cover; -} - -.about { - margin: 0; - top: 0; - left: 0; - font-size: inherit; - font-weight: 700; - font-family: inherit; - display: inline-block; - width: 179px; - cursor: pointer; - cursor: pointer; - color: var(--color-white); - font-family: var(--font-tt-mussels-trl); - text-decoration: none; - transition: transform 0.3s ease; -} - -.about:active { - transform: scale(0.9); -} - -.about, -.contact, -.high, -.text-high { - position: absolute; - height: 65px; -} - -.contact { - margin: 0; - top: 0; - left: 294px; - font-size: inherit; - font-weight: 700; - font-family: inherit; - display: inline-block; - width: 179px; - cursor: pointer; - color: var(--color-white); - font-family: var(--font-tt-mussels-trl); - text-decoration: none; - transition: transform 0.3s ease; -} - -.contact:active { - transform: scale(0.9); -} - -.text-high { - top: 16px; - left: 1368px; - width: 473px; -} - -.high { - position: fixed; - top: 0; - left: 0; - width: 1925px; - height: 59px; - text-align: left; - font-size: var(--font-size-31xl); - color: var(--color-white); - font-family: var(--font-tt-mussels-trl); - z-index: 1000; - -} - -.seu-teste-tecnolgico-container { - position: absolute; - top: 0; - left: 0; - font-size: inherit; - font-weight: 700; - font-family: inherit; -} - -.boto-iniciar { - margin: 40px; - width: 270px; - height: 70px; - position: absolute; - top: calc(50% + 127.5px); - left: 450px; - background-image: linear-gradient(to right, #D100FF, #DB00FF); - box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); - border: none; - border-radius: var(--br-31xl); - cursor: pointer; - align-items: center; - justify-content: center; - transition: transform 0.3s ease; - font-size: var(--font-size-21xl); - font-weight: bold; -} - -.boto-iniciar:active { - transform: scale(0.9); -} - -.title4 { - position: absolute; - top: 260px; - left: 142px; - width: 1026px; - height: 495px; - position: absolute; - font-size: inherit; - font-weight: 700; - font-family: inherit; -} - -.high-page { - top: 0; - left: 0; - width: 100%; /* Defina a largura que você deseja, por exemplo, 100% para ocupar toda a largura */ - height: 70px; /* Defina a altura que você deseja, por exemplo, 70px */ - font-size: var(--font-size-131xl); -} - - -.home-page-desktop { - position: relative; - width: 100%; - height: 2659px; - text-align: left; - font-size: var(--font-size-16xl); - color: var(--color-white); - font-family: var(--font-tt-mussels-trl); -} +/* General Reset and Base Styles */ +body, html { + margin: 0; + padding: 0; + width: 100%; + overflow-x: hidden; /* Prevent horizontal scrollbars caused by minor overflows */ + box-sizing: border-box; + font-family: var(--font-tt-mussels-trl), sans-serif; /* Fallback font */ +} + +*, *:before, *:after { + box-sizing: inherit; +} + +.home-page-desktop { + position: relative; + width: 100%; + text-align: left; + color: var(--color-white); + font-family: var(--font-tt-mussels-trl); + /* overflow-x: hidden; /* Already on body, but keep if needed for specific structure */ +} + +/* Variables (assuming they are defined elsewhere, e.g., :root or a theme file) */ +:root { + --font-tt-mussels-trl: "TT Mussels Trl", sans-serif; /* Example, ensure this font is loaded */ + --color-white: #ffffff; + --color-midnightblue: #2d0159; /* Example */ + --br-107xl: 126px; /* Example */ + --br-31xl: 50px; /* Example */ + --font-size-16xl: 1.5rem; /* Base for smaller elements */ + --font-size-21xl: 1.75rem; + --font-size-31xl: 2rem; + --font-size-81xl: 4rem; + --font-size-131xl: 6rem; + + /* Responsive Breakpoints (examples, align with your responsive.tsx if possible) */ + --screen-mobile: 480px; + --screen-tablet: 768px; + --screen-desktop: 1024px; +} + + +/* High Section (Fixed Header) */ +.high { + position: fixed; /* Keep fixed for header behavior */ + top: 0; + left: 0; + width: 100%; + height: auto; /* Adjust height based on content */ + min-height: 70px; /* Minimum height */ + background: linear-gradient(90deg, #6113a8, rgba(69, 63, 203, 0.8)); /* Slightly more solid gradient */ + backdrop-filter: blur(15px); /* Adjusted blur */ + z-index: 1000; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 20px; /* Vertical and horizontal padding */ + box-shadow: 0 2px 10px rgba(0,0,0,0.2); /* Subtle shadow */ +} + +.logo-branco-icon { + height: 50px; /* Adjust height, width will auto-scale */ + width: auto; + max-width: 250px; /* Prevent it from becoming too large */ + object-fit: contain; +} + +.text-high { + display: flex; + align-items: center; + gap: 20px; /* Space between "about" and "contact" */ +} + +.text-high .about, +.text-high .contact { + font-size: var(--font-size-21xl); /* Base size, adjust in media queries */ + font-weight: 700; + color: var(--color-white); + text-decoration: none; + cursor: pointer; + padding: 5px 10px; + transition: transform 0.3s ease, color 0.3s ease; +} + +.text-high .about:hover, +.text-high .contact:hover { + transform: scale(1.1); + color: #ddd; /* Slight hover effect */ +} + +/* Hero Section (high-page content) */ +.high-page { + display: flex; /* Use flex for overall layout */ + flex-direction: column; /* Stack children vertically by default */ + align-items: center; /* Center children horizontally */ + justify-content: center; /* Center children vertically (if section has fixed height) */ + width: 100%; + min-height: 100vh; /* Make it at least full viewport height */ + padding-top: 90px; /* Account for fixed header height */ + position: relative; /* For positioning background image */ + text-align: center; /* Center text for mobile */ + overflow: hidden; /* Prevent astronaut from overflowing weirdly on resize */ +} + +.background-high-icon { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; /* Cover the entire area */ + z-index: -1; /* Behind content */ +} + +.hero-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 90%; /* Max width for content */ + max-width: 1200px; /* Prevent content from becoming too wide */ + position: relative; /* Ensure z-index works for children if needed */ + z-index: 1; +} + +.title-and-button { + width: 100%; +} + +.title4 { + font-size: var(--font-size-81xl); /* Base size for title */ + font-weight: 700; + color: var(--color-white); + margin-bottom: 30px; /* Space below title */ + line-height: 1.2; +} + +.title4 p { + margin: 0; /* Remove default paragraph margins */ +} + +.astronaut-icon { + width: 300px; /* Base size for astronaut */ + max-width: 80%; /* Ensure it doesn't overflow on small screens */ + height: auto; + margin-top: 20px; /* Space above astronaut on mobile */ + object-fit: contain; +} + +.boto-iniciar { + width: 220px; + height: 60px; + background-image: linear-gradient(to right, #D100FF, #DB00FF); + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + border: none; + border-radius: var(--br-31xl); + cursor: pointer; + font-size: var(--font-size-21xl); + font-weight: bold; + color: var(--color-white); + transition: transform 0.3s ease; + margin-top: 20px; /* Space above button */ +} + +.boto-iniciar:hover { + transform: scale(1.05); +} + +/* About Us Section */ +.about-page { + display: flex; + flex-direction: column; + align-items: center; + padding: 50px 20px; /* Vertical and horizontal padding */ + position: relative; /* For background image positioning */ + width: 100%; +} + +.image-10-icon { /* Background for about page */ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: -1; +} + +.title-about-container { + text-align: center; + margin-bottom: 30px; + position: relative; /* For the rectangle-title accent */ +} + +.about-us { + font-size: var(--font-size-81xl); + font-weight: 700; + margin: 0; + position: relative; /* Ensure it's above the rectangle */ + z-index: 1; +} + +.rectangle-title { + position: absolute; + bottom: -5px; /* Position under the title */ + left: 50%; + transform: translateX(-50%); + background-color: var(--color-midnightblue); + width: 150px; /* Shorter accent */ + height: 15px; /* Thicker accent */ + z-index: 0; +} + +.txtAbout-container { + width: 90%; + max-width: 800px; /* Control text width for readability */ + margin-bottom: 40px; +} + +.txtAbout { + font-size: var(--font-size-21xl); + text-align: center; /* Center align the paragraph */ + line-height: 1.6; + margin:0; +} + +.members-container { + display: flex; + justify-content: space-around; + flex-wrap: wrap; /* Allow members to wrap on smaller screens */ + width: 100%; + max-width: 1200px; /* Max width for members area */ +} + +.member-card { + width: 280px; /* Base width for member cards */ + margin: 20px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} + +.member-card img { /* Common style for member images */ + width: 200px; /* Fixed size for consistency */ + height: 200px; + border-radius: 50%; /* Circular images */ + object-fit: cover; + margin-bottom: 15px; + transition: transform 0.3s ease; + box-shadow: 0 4px 15px rgba(0,0,0,0.2); +} + +.member-card img:hover { + transform: scale(1.1); +} + +.member-name { + font-size: var(--font-size-21xl); /* Adjusted for consistency */ + font-weight: 400; + text-shadow: 1px 1px 0px #2d0159; /* Simplified shadow */ +} + +.rock-of-the-astronaut-1 { + display: none; /* Hide by default, show on larger screens if desired */ + width: 200px; /* Example size */ + height: auto; + position: absolute; /* If needed for specific placement, but try to avoid */ + /* top: ...; left: ...; */ +} + + +/* Contact Section */ +.contact-page { + display: flex; + flex-direction: column; + align-items: center; + padding: 50px 20px; + text-align: center; + position: relative; + width: 100%; + min-height: 50vh; /* Ensure it has some height */ +} + +.background-contact-icon { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: -1; +} + +.logos-icon { /* Decorative partner logos */ + width: 250px; /* Adjust size */ + height: auto; + margin-bottom: 30px; + object-fit: contain; +} + +.socials { + display: flex; + flex-direction: column; /* Stack social items */ + align-items: center; /* Center items if stacked, or flex-start if labels are long */ +} + +.social-item { + display: flex; + align-items: center; + margin-bottom: 20px; /* Space between social items */ + text-decoration: none; + color: var(--color-white); +} + +.vector-icon { /* Common style for social icons */ + width: 40px; /* Adjust size */ + height: 40px; + margin-right: 15px; /* Space between icon and text */ + transition: transform 0.2s ease-in-out; +} +.vector-icon:hover { + transform: scale(1.2); +} +/* Specific icon classes if needed, otherwise .vector-icon can be used for all */ +.vector-icon1 {} /* Instagram */ +.vector-icon2 {} /* Location */ + + +.social-text { /* Common style for social text */ + font-size: var(--font-size-16xl); /* Adjust size */ + margin: 0; /* Reset margins */ +} +/* Remove specific margin/positioning for these as flexbox handles it */ +.cdquestinsta, .cdquestmail, .cdquestloca { + margin: 0; +} + + +/* Media Queries */ + +/* Mobile Devices (e.g., max-width: 480px or 576px) */ +@media (max-width: 576px) { + .high { + min-height: 60px; + padding: 5px 15px; + } + .logo-branco-icon { + height: 40px; + } + .text-high { + gap: 10px; /* Smaller gap */ + } + .text-high .about, .text-high .contact { + font-size: var(--font-size-16xl); /* Smaller font for header links */ + padding: 5px; + } + + .title4 { + font-size: 2.5rem; /* Significantly smaller title */ + } + .astronaut-icon { + width: 200px; /* Smaller astronaut */ + margin-top: 30px; + } + .boto-iniciar { + width: 180px; + height: 50px; + font-size: var(--font-size-16xl); /* Smaller button text */ + } + + .about-us { + font-size: 2.8rem; /* Smaller section title */ + } + .rectangle-title { + width: 100px; + height: 10px; + } + .txtAbout { + font-size: var(--font-size-16xl); /* Smaller about text */ + } + .member-card { + width: 80%; /* Member cards take more width */ + margin: 15px 0; + } + .member-card img { + width: 150px; + height: 150px; + } + .member-name { + font-size: var(--font-size-16xl); + } + + .logos-icon { + width: 180px; + margin-bottom: 20px; + } + .vector-icon { + width: 30px; + height: 30px; + margin-right: 10px; + } + .social-text { + font-size: 0.9rem; /* Smaller social text */ + } + .social-item { + margin-bottom: 15px; + } +} + +/* Tablet Devices (e.g., min-width: 577px and max-width: 768px) */ +@media (min-width: 577px) and (max-width: 768px) { + .high-page .hero-content { + /* Could change to row if space allows */ + } + .title4 { + font-size: 3.5rem; + } + .astronaut-icon { + width: 250px; + } + .boto-iniciar { + width: 200px; + height: 55px; + } + + .about-us { + font-size: 3rem; + } + .txtAbout { + font-size: 1.1rem; + } + .member-card { + width: 45%; /* Two cards per row */ + } + .member-card img { + width: 180px; + height: 180px; + } + .socials { + flex-direction: row; /* Social items in a row for tablet */ + flex-wrap: wrap; + justify-content: center; + gap: 20px; + } + .social-item { + margin-bottom: 10px; /* Adjust spacing for row layout */ + } +} + +/* Desktop (adjustments for larger screens if needed) */ +@media (min-width: 769px) { + .high-page .hero-content { + flex-direction: row; /* Title/button on one side, astronaut on other */ + justify-content: space-between; /* Or space-around */ + align-items: center; + text-align: left; /* Align text to left on desktop */ + } + .title-and-button { + width: 50%; /* Example width */ + max-width: 600px; + } + .astronaut-icon { + width: 400px; /* Larger astronaut for desktop */ + max-width: 45%; + margin-top: 0; /* Reset margin */ + } + .title4 { + font-size: var(--font-size-131xl); /* Restore larger desktop font size */ + } + .boto-iniciar { + margin-left: 0; /* Align button to the left of its container */ + } + .about-us { + font-size: var(--font-size-81xl); + } + .txtAbout { + font-size: var(--font-size-21xl); + text-align: left; + } + .member-card { + width: 30%; /* Three cards per row */ + } + .socials { + flex-direction: row; + justify-content: space-evenly; /* Spread out social items */ + width: 100%; + max-width: 800px; /* Limit width of social links container */ + } + .social-item { + margin-bottom: 0; + } + .rock-of-the-astronaut-1 { + display: block; /* Show this decorative image on desktop */ + position: absolute; + width: 25%; + height: auto; + bottom: 50px; /* Example positioning */ + right: 50px; + z-index: 0; + } +} + +/* Ensure any fixed dimensions on .home-page-desktop itself are removed or responsive */ +.home-page-desktop { + /* height: 2659px; Remove fixed height, let content define it */ +} + +/* Legacy absolute positioning from original CSS - to be removed or refactored */ +/* .instagram, .gmail, .local { position: absolute; } -> Handled by flex on .social-item */ +/* .cdquestinsta, .cdquestmail, .cdquestloca { margin-left: ...; margin-top: ...; } -> Handled by flex spacing */ +/* .logos-icon { position: absolute; } -> Now positioned by flex in .contact-page */ +/* .title-about, .txtAbout, .gustavo, .kauan, .joo { position: absolute; } -> Handled by flex/flow */ +/* .high .logo-branco-icon, .high .text-high { position: absolute; } -> Handled by flex on .high */ +/* .high-page .title4, .high-page .astronaut-icon, .high-page .boto-iniciar { position: absolute; } -> Handled by flex on .high-page / .hero-content */ + +/* Ensure .rectangle-high is not used if .high is the header itself */ +.rectangle-high { display: none; } /* This was likely for the old fixed-size header background */ + +/* Cleanup any remaining fixed widths that might cause overflow */ +.about-page, .contact-page { /* These were 1925px */ + width: 100%; +} + +/* Final check for any remaining large fixed dimensions or problematic absolute positions */ +/* The goal is a fluid layout that adapts, not fixed pixel perfection from the original desktop-only design */ diff --git a/front-codequest/src/pages/desktop/HomePage.tsx b/front-codequest/src/pages/desktop/HomePage.tsx index 6c022b8..9eedc38 100644 --- a/front-codequest/src/pages/desktop/HomePage.tsx +++ b/front-codequest/src/pages/desktop/HomePage.tsx @@ -1,170 +1,166 @@ -import { FunctionComponent, useEffect, useState } from "react"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; -import "./HomePage.css"; -import { Link as RouterLink } from 'react-router-dom'; -import { Link as ScrollLink } from 'react-scroll'; - -const HomePageDesktop: FunctionComponent = () => { - const [displayText, setDisplayText] = useState(""); - const [redirecting, setRedirecting] = useState(false); - - const textToType = `Nós somos um grupo de estudantes do Colégio Técnico de Campinas, e esse é o nosso Trabalho de Conclusão de Curso do Departamento de Processamento de Dados.`; - - useEffect(() => { - const aboutPageContainer = document.getElementById("aboutPageContainer"); - - const handleScroll = () => { - if (aboutPageContainer) { - const rect = aboutPageContainer.getBoundingClientRect(); - - // Verifique se o elemento aboutPageContainer está no campo de visão do usuário. - if (rect.top < window.innerHeight * 0.8) { - let currentIndex = 0; - const interval = setInterval(() => { - if (currentIndex <= textToType.length) { - setDisplayText(textToType.substring(0, currentIndex)); - currentIndex++; - } else { - clearInterval(interval); - } - }, 30); // Velocidade da digitação (50 milissegundos) - window.removeEventListener("scroll", handleScroll); // Remova o ouvinte após iniciar a animação. - } - } - }; - - window.addEventListener("scroll", handleScroll); - - return () => { - window.removeEventListener("scroll", handleScroll); - }; - }, [textToType]); - - const handleRedirect = () => { - setRedirecting(true); - - // Simule um atraso de 1 segundo antes do redirecionamento - setTimeout(() => { - setRedirecting(false); - // Realize o redirecionamento real no local apropriado dentro da função handleRedirect. - // history.push("/testpage01"); - }, 1000); // 1000 milissegundos = 1 segundo - }; - - return ( -
-
- - -
- - -
- - about - - - contact - -
-
-
-

SEU TESTE

-

TECNOLÓGICO

-

AQUI.

- - - -
-
- -
- - -
-

- About us -

-
-
-

-

- {displayText} -

-

-
- -

- Gustavo Miguel -

-
-
- -

- Kauan Piacente -

-
-
-

- João Victor -

- -
-
- -
- - -
-
- - - -

@codequest_

- -
-
- - - -

codequest03@gmail.com

- -
-
- - - -

R. Culto à Ciência - Centro, Campinas - SP

- - -
-
- -
- - -
- ); -}; - -export default HomePageDesktop; +import { FunctionComponent, useEffect, useState } from "react"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; +import "./HomePage.css"; +import { Link as RouterLink } from 'react-router-dom'; +import { Link as ScrollLink } from 'react-scroll'; + +const HomePageDesktop: FunctionComponent = () => { + const [displayText, setDisplayText] = useState(""); + const [redirecting, setRedirecting] = useState(false); + + const textToType = `Nós somos um grupo de estudantes do Colégio Técnico de Campinas, e esse é o nosso Trabalho de Conclusão de Curso do Departamento de Processamento de Dados.`; + + useEffect(() => { + const aboutPageContainer = document.getElementById("aboutPageContainer"); + + const handleScroll = () => { + if (aboutPageContainer) { + const rect = aboutPageContainer.getBoundingClientRect(); + if (rect.top < window.innerHeight * 0.8 && displayText === "") { // Start typing only once + let currentIndex = 0; + const interval = setInterval(() => { + if (currentIndex <= textToType.length) { + setDisplayText(textToType.substring(0, currentIndex)); + currentIndex++; + } else { + clearInterval(interval); + } + }, 30); + window.removeEventListener("scroll", handleScroll); + } + } + }; + + window.addEventListener("scroll", handleScroll); + + return () => { + window.removeEventListener("scroll", handleScroll); + }; + }, [textToType, displayText]); // Added displayText to dependencies + + const handleRedirect = () => { + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + // Navigation is handled by RouterLink, this is for visual feedback if needed + }, 1000); + }; + + return ( +
+
+ CodeQuest Logo + +
+ +
+ +
+
+
+

SEU TESTE

+

TECNOLÓGICO

+

AQUI.

+
+ + + +
+ Astronauta +
+
+ +
+ Fundo Sobre Nós + Pedra do astronauta +
+

+ SOBRE NÓS +

+
+
+
+

{/* Changed h2 to p for semantic text */} + {displayText} +

+
+
{/* Added wrapper */} +
+ Gustavo Miguel +

+ Gustavo Miguel +

+
+
+ Kauan Piacente +

+ Kauan Piacente +

+
+
+ João Victor +

+ João Victor +

+
+
+
+ + +
+ ); +}; + +export default HomePageDesktop; diff --git a/front-codequest/src/pages/desktop/SavePage.tsx b/front-codequest/src/pages/desktop/SavePage.tsx index 1e03a3b..97e7ca7 100644 --- a/front-codequest/src/pages/desktop/SavePage.tsx +++ b/front-codequest/src/pages/desktop/SavePage.tsx @@ -1,99 +1,191 @@ -import { FunctionComponent, useState } from "react"; -import "./SavePage.css"; -import { Link } from 'react-router-dom'; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; - -const SavePageDesktop: FunctionComponent = () => { - const [email, setEmail] = useState(""); - const [redirecting, setRedirecting] = useState(false); - - const handleEmailChange = (e: React.ChangeEvent) => { - setEmail(e.target.value); - }; - - const handleRedirect = async () => { - if (email) { - setRedirecting(true); - - try { - const response = await fetch('http://localhost:3306/emails/incluir', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ email }), // Envie o email digitado pelo usuário para o backend - }); - - if (response.ok) { - // Se a resposta do servidor foi bem-sucedida, redirecione para a homepage ou faça outra ação necessária - setTimeout(() => { - setRedirecting(false); - // Realize o redirecionamento aqui, por exemplo: - // history.push("/"); - }, 1000); - } else { - // Trate a falha na requisição - console.error('Falha ao enviar e-mail'); - setRedirecting(false); - } - } catch (error) { - // Trate erros de rede ou outros erros - console.error('Erro ao enviar e-mail:', error); - setRedirecting(false); - } - } - }; - - - - return ( -
-
-
-
- -
-
- -
- - - -
-
Finalizando seu teste!
-
- por favor, digite seu email e nós enviaremos seu teste em breve -
-
- - - -
-
-
- ); -}; - -export default SavePageDesktop; +import { FunctionComponent, useState, useEffect } from "react"; // Added useEffect +import "./SavePage.css"; +import { Link, useNavigate } from 'react-router-dom'; // Added useNavigate +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; + +const SavePageDesktop: FunctionComponent = () => { + const [email, setEmail] = useState(""); // Keep if email feature is desired (optional for now) + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const navigate = useNavigate(); // Initialize useNavigate + + // Optional: keep handleEmailChange if email input is kept + const handleEmailChange = (e: React.ChangeEvent) => { + setEmail(e.target.value); + }; + + const handleProceed = async () => { + setIsLoading(true); + setError(null); + + try { + let allAnswers: (number | null)[] = []; + for (let i = 1; i <= 5; i++) { + const key = `respostasPage${i}`; + const pageAnswersString = localStorage.getItem(key); + if (pageAnswersString) { + try { + const parsedAnswers = JSON.parse(pageAnswersString); + // Ensure correct property names if they differ from resposta1-4 + allAnswers.push(parsedAnswers.resposta1 ?? null); + allAnswers.push(parsedAnswers.resposta2 ?? null); + allAnswers.push(parsedAnswers.resposta3 ?? null); + allAnswers.push(parsedAnswers.resposta4 ?? null); + } catch (e) { + console.error(`Error parsing localStorage for ${key}:`, e); + // Add nulls for all 4 questions of the page if parsing fails + allAnswers.push(null, null, null, null); + } + } else { + console.warn(`No data found in localStorage for ${key}`); + // Add nulls for all 4 questions of the page if data is missing + allAnswers.push(null, null, null, null); + } + } + + if (allAnswers.length !== 20) { + // This check might be redundant if the loop always pushes 4 values + // but good for sanity check if logic changes + console.error("Collected answers length is not 20:", allAnswers.length); + throw new Error("Não foi possível coletar todas as respostas. Por favor, tente refazer o teste."); + } + + // Replace nulls with 3 (neutral) before sending to backend + const finalAnswers = allAnswers.map(ans => ans === null ? 3 : ans); + + // **Optional Email Submission (Commented out as per instruction)** + // if (email) { + // try { + // const emailResponse = await fetch('http://localhost:3306/emails/incluir', { // Ensure this port and path are correct + // method: 'POST', + // headers: { 'Content-Type': 'application/json' }, + // body: JSON.stringify({ email }), + // }); + // if (!emailResponse.ok) console.error('Falha ao enviar e-mail'); + // } catch (emailError) { + // console.error('Erro ao enviar e-mail:', emailError); + // } + // } + + // **Call Vocational Test API:** + const response = await fetch('/api/calculate-vocation', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ answers: finalAnswers }), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Erro do servidor: ${response.status} ${errorText}`); + } + + const result = await response.json(); + + if (!result || !Array.isArray(result) || result.length === 0) { // Check for empty array too + console.error("Resultado inesperado ou vazio do servidor:", result); + throw new Error("Resultado inesperado ou vazio do servidor."); + } + + const scores: number[] = result.map(score => typeof score === 'number' ? score : 0); // Ensure scores are numbers + let maxScore = -1; + let bestVocationIndex = -1; + + for (let i = 0; i < scores.length; i++) { + if (scores[i] > maxScore) { + maxScore = scores[i]; + bestVocationIndex = i; + } + } + + // Ensure there's at least one score and it's not negative from initialization + if (bestVocationIndex === -1 && scores.length > 0) { + // If all scores are 0 or less (e.g. from default mapping), pick first as a fallback + // or handle as "undetermined". For now, let's assume valid positive scores are expected. + // If all scores are 0 (e.g. if all answers were neutral and backend returns 0s), + // this logic might need a tie-breaking rule or specific handling. + // For now, if maxScore remains <=0 and there are scores, it indicates no clear preference. + if (maxScore <= 0) { + console.warn("Nenhuma vocação teve pontuação positiva clara. Verifique a lógica de pontuação ou respostas.", scores); + // Fallback: could navigate to a generic "results" page or show a message. + // For now, let's throw an error to indicate this state. + throw new Error("Não foi possível determinar uma vocação clara com as pontuações atuais."); + } + } + + + const vocationRoutes = [ + "/dessoftware", // Index 0 + "/desweb", // Index 1 + "/desaplicativos",// Index 2 + "/analisedados", // Index 3 + "/segti" // Index 4 + ]; + + if (bestVocationIndex >= 0 && bestVocationIndex < vocationRoutes.length) { + navigate(vocationRoutes[bestVocationIndex]); + } else { + console.error("Não foi possível determinar a vocação. Índice inválido ou pontuações não conclusivas.", result); + throw new Error("Não foi possível determinar sua vocação com base nas respostas."); + } + + } catch (err: any) { + setError(err.message || "Ocorreu um erro ao processar seu teste."); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+
+
+ +
+
+ +
+ {/* Link component removed from around the button as navigate is used */} + +
+
Finalizando seu teste!
+ {/* Updated text to be more generic if email is optional */} +
+ Clique em "VER RESULTADO" para descobrir sua área. +
+
+ {error &&
{error}
} + + + +
+
+
+ ); +}; + +export default SavePageDesktop; diff --git a/front-codequest/src/pages/desktop/TestPage01.tsx b/front-codequest/src/pages/desktop/TestPage01.tsx index 280b7a1..53456db 100644 --- a/front-codequest/src/pages/desktop/TestPage01.tsx +++ b/front-codequest/src/pages/desktop/TestPage01.tsx @@ -1,368 +1,389 @@ -import { FunctionComponent, SetStateAction } from "react"; -import React, { useState, useEffect } from 'react'; -import "./TestPage01.css"; -import { Button } from "react-bootstrap"; -import { Link } from 'react-router-dom'; -import handleInputChange from '../../handleResp'; -import respostasData from '../../respostasData'; - -interface TestPage01DesktopProps { - onRespostasChange: (respostas: { resposta1: string; resposta2: string; resposta3: string; resposta4: string; }) => void; -} - -const TestPage01Desktop: FunctionComponent = ({ onRespostasChange }) => { - -const [redirecting, setRedirecting] = useState(false); -const [respostas, setRespostas] = useState({ - resposta1: "", - resposta2: "", - resposta3: "", - resposta4: "", -}); - -React.useEffect(() => { - onRespostasChange(respostas); -}, [onRespostasChange, respostas]); - -useEffect(() => { - // Carregar respostas salvas quando o componente monta - const savedRespostas = localStorage.getItem("respostas"); - if (savedRespostas) { - setRespostas(JSON.parse(savedRespostas)); - } -}, []); - -useEffect(() => { - // Salvar respostas no localStorage sempre que elas mudam - localStorage.setItem("respostas", JSON.stringify(respostas)); -}, [respostas]); -const handleRespostaChange = (pergunta: string, resposta: string) => { - setRespostas((prevRespostas) => ({ - ...prevRespostas, - [pergunta]: resposta, - })); -}; - - const handleRedirect = () => { - setRedirecting(true); - setTimeout(() => { - setRedirecting(false); - }, 5000); - }; - - return ( -
-
-
- -
- -
    -

    -
      -

      - - Se sente empolgado com a ideia de criar programas que podem - melhorar a forma como as empresas ou pessoas realizam tarefas? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -

    -
    -
      -

      - - Gostaria de aprender a linguagem "código" para criar - aplicativos, jogos ou software? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
    -
      -

      - - Se sente atraído por trabalhar em equipe para criar - aplicativos ou software maiores? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
    -
      -

      - - Considera emocionante a possibilidade de ver suas ideias se - transformarem em programas ou aplicativos reais? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
-
-
-
- Em uma escala de 1 a 5, o quanto você: -
-
- - - - - - -
-
- ); -} - -export default TestPage01Desktop; +import { FunctionComponent, SetStateAction } from "react"; +import React, { useState, useEffect } from 'react'; +import "./TestPage01.css"; +import { Button } from "react-bootstrap"; +import { Link } from 'react-router-dom'; + +const LOCAL_STORAGE_KEY = "respostasPage1"; + +const answerMapping: { [key: string]: number } = { + "nadaEmpolgado": 1, "poucoEmpolgado": 2, "neutro": 3, "empolgado": 4, "muitoEmpolgado": 5, + "nadaInteressado": 1, "poucoInteressado": 2, "interessado": 4, "muitoInteressado": 5, + "nadaAtraido": 1, "poucoAtraido": 2, "atraido": 4, "muitoAtraido": 5, + "nadaEmocionante": 1, "poucoEmocionante": 2, "emocionante": 4, "muitoEmocionante": 5 +}; + +interface TestPage01DesktopProps { + onRespostasChange: (respostas: { resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }) => void; +} + +const TestPage01Desktop: FunctionComponent = ({ onRespostasChange }) => { + +const [redirecting, setRedirecting] = useState(false); // Keep for button visual feedback if desired +const [respostas, setRespostas] = useState<{ resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }>({ + resposta1: null, + resposta2: null, + resposta3: null, + resposta4: null, +}); + +React.useEffect(() => { + onRespostasChange(respostas); +}, [onRespostasChange, respostas]); + +useEffect(() => { + const savedRespostas = localStorage.getItem(LOCAL_STORAGE_KEY); + if (savedRespostas) { + try { + const parsedRespostas = JSON.parse(savedRespostas); + setRespostas({ + resposta1: typeof parsedRespostas.resposta1 === 'number' ? parsedRespostas.resposta1 : null, + resposta2: typeof parsedRespostas.resposta2 === 'number' ? parsedRespostas.resposta2 : null, + resposta3: typeof parsedRespostas.resposta3 === 'number' ? parsedRespostas.resposta3 : null, + resposta4: typeof parsedRespostas.resposta4 === 'number' ? parsedRespostas.resposta4 : null, + }); + } catch (error) { + console.error("Failed to parse respostas from localStorage for Page 1", error); + setRespostas({ resposta1: null, resposta2: null, resposta3: null, resposta4: null }); + } + } +}, []); + +useEffect(() => { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(respostas)); +}, [respostas]); + +const handleRespostaChange = (pergunta: keyof typeof respostas, respostaValue: string) => { + const mappedValue = answerMapping[respostaValue]; + setRespostas((prevRespostas) => ({ + ...prevRespostas, + [pergunta]: mappedValue !== undefined ? mappedValue : (respostaValue === "neutro" ? 3 : null), + })); +}; + + const handleLinkClick = () => { // Renamed from handleRedirect to avoid confusion + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + }, 1000); // Shorter delay for link clicks + }; + + return ( +
+
{/* Renamed from test-page3 for clarity */} + {/* The background image div is removed, .test-page-container will be styled */} + CodeQuest Logo {/* Simplified class */} + +
{/* Simplified class */} +
{/* Simplified class */} +
{/* Simplified class */} + Em uma escala de 1 a 5, o quanto você: +
+
+ +
{/* Renamed from text-test3 */} +
+
{/* Added base class */} +
    {/* Renamed for clarity */} +

    {/* Simplified class */} + + Se sente empolgado com a ideia de criar programas que podem + melhorar a forma como as empresas ou pessoas realizam tarefas? + +

    + {/* Options */} +
  • {/* Changed h4 to li for semantic list */} + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
{/* Added base class */} +
    +

    + + Gostaria de aprender a linguagem "código" para criar + aplicativos, jogos ou software? + +

    + {/* Options */} +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+ +
+
{/* Added base class */} +
    +

    + + Se sente atraído por trabalhar em equipe para criar + aplicativos ou software maiores? + +

    + {/* Options */} +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
{/* Added base class */} +
    +

    + + Considera emocionante a possibilidade de ver suas ideias se + transformarem em programas ou aplicativos reais? + +

    + {/* Options */} +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+ +
+ + + + + + +
+
+
+ ); +} + +export default TestPage01Desktop; diff --git a/front-codequest/src/pages/desktop/TestPage02.tsx b/front-codequest/src/pages/desktop/TestPage02.tsx index 6c9eeb8..40f7b57 100644 --- a/front-codequest/src/pages/desktop/TestPage02.tsx +++ b/front-codequest/src/pages/desktop/TestPage02.tsx @@ -1,369 +1,396 @@ -import { FunctionComponent, useEffect } from "react"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; -import "./TestPage02.css"; -import { Link } from 'react-router-dom'; -import { useState } from "react"; -import React from "react"; - -interface TestPage02DesktopProps { - onRespostasChange: (respostas: { resposta1: string; resposta2: string; resposta3: string; resposta4: string; }) => void; -} - -const TestPage02Desktop: FunctionComponent = ({ onRespostasChange }) => { - const [redirecting, setRedirecting] = useState(false); - const [respostas, setRespostas] = useState({ - resposta1: "", - resposta2: "", - resposta3: "", - resposta4: "", - }); - React.useEffect(() => { - onRespostasChange(respostas); - }, [onRespostasChange, respostas]); - useEffect(() => { - // Carregar respostas salvas quando o componente monta - const savedRespostas = localStorage.getItem("respostas"); - if (savedRespostas) { - setRespostas(JSON.parse(savedRespostas)); - } - }, []); - - useEffect(() => { - // Salvar respostas no localStorage sempre que elas mudam - localStorage.setItem("respostas", JSON.stringify(respostas)); - }, [respostas]); - - const handleRespostaChange = (pergunta: string, resposta: string) => { - setRespostas((prevRespostas) => ({ - ...prevRespostas, - [pergunta]: resposta, - })); - }; - - const handleRedirect = () => { - setRedirecting(true); - setTimeout(() => { - setRedirecting(false); - }, 5000); - }; - - - return ( -
-
-
- -
- -
    -

    -
      -

      - - Acha bacana a ideia de criar aplicativos que possam ser usados - em smartphones ou tablets? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -

    -
    -
      -

      - - Imagina-se aprendendo a desenvolver aplicativos que facilitem - a vida das pessoas, como apps de transporte ou de pedidos de - comida? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
    -
      -

      - - Valoriza a ideia de criar interfaces amigáveis e atraentes - para seus aplicativos? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
    -
      -

      - - Gostaria de criar aplicativos que aproveitassem recursos - específicos de dispositivos móveis, como câmeras e sensores? - -

      -
    -
      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -

      - -

      -
    -
    -
-
-
-
- Em uma escala de 1 a 5, o quanto você: -
-
- - - - - - -
-
- ); -}; - -export default TestPage02Desktop; +import { FunctionComponent, useEffect } from "react"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; +import "./TestPage02.css"; // Assuming TestPage02.css will be created or updated for responsive styles +import { Link } from 'react-router-dom'; +import { useState } from "react"; +import React from "react"; + +const LOCAL_STORAGE_KEY = "respostasPage2"; + +const answerMapping: { [key: string]: number } = { + "nadaBacana": 1, "poucoBacana": 2, "neutro": 3, "bacana": 4, "muitoBacana": 5, + "nadaImaginavel": 1, "poucoImaginavel": 2, "imaginavel": 4, "muitoImaginavel": 5, + "nadaValorizo": 1, "poucoValorizo": 2, "valorizo": 4, "muitoValorizo": 5, + "nadaGostaria": 1, "poucoGostaria": 2, "gostaria": 4, "muitoGostaria": 5 +}; + +interface TestPage02DesktopProps { + onRespostasChange: (respostas: { resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }) => void; +} + +const TestPage02Desktop: FunctionComponent = ({ onRespostasChange }) => { + const [redirecting, setRedirecting] = useState(false); + const [respostas, setRespostas] = useState<{ resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }>({ + resposta1: null, + resposta2: null, + resposta3: null, + resposta4: null, + }); + + React.useEffect(() => { + onRespostasChange(respostas); + }, [onRespostasChange, respostas]); + + useEffect(() => { + const savedRespostas = localStorage.getItem(LOCAL_STORAGE_KEY); + if (savedRespostas) { + try { + const parsedRespostas = JSON.parse(savedRespostas); + setRespostas({ + resposta1: typeof parsedRespostas.resposta1 === 'number' ? parsedRespostas.resposta1 : null, + resposta2: typeof parsedRespostas.resposta2 === 'number' ? parsedRespostas.resposta2 : null, + resposta3: typeof parsedRespostas.resposta3 === 'number' ? parsedRespostas.resposta3 : null, + resposta4: typeof parsedRespostas.resposta4 === 'number' ? parsedRespostas.resposta4 : null, + }); + } catch (error) { + console.error("Failed to parse respostas from localStorage for TestPage02", error); + setRespostas({ resposta1: null, resposta2: null, resposta3: null, resposta4: null }); + } + } + }, []); + + useEffect(() => { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(respostas)); + }, [respostas]); + + const handleRespostaChange = (pergunta: keyof typeof respostas, respostaValue: string) => { + const mappedValue = answerMapping[respostaValue]; + setRespostas((prevRespostas) => ({ + ...prevRespostas, + [pergunta]: mappedValue !== undefined ? mappedValue : (respostaValue === "neutro" ? 3 : null), + })); + }; + + const handleLinkClick = () => { + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + }, 1000); + }; + + return ( + // General container class for consistent padding/max-width if TestPage02.css is created +
+
{/* Renamed from test-page2 */} + {/* Background image div can be removed if .test-page-container handles background */} + {/*
+ +
*/} + CodeQuest Logo {/* Simplified class */} + +
{/* Simplified class */} +
{/* Simplified class */} +
{/* Simplified class */} + Em uma escala de 1 a 5, o quanto você: +
+
+ + {/* Changed
    to
    for questions area */} +
    {/* Renamed from text-test2 */} +
    +
    {/* Use a common class + specific one */} +

    {/* Simplified class */} + + Acha bacana a ideia de criar aplicativos que possam ser usados + em smartphones ou tablets? + +

    +
      {/* Wrapper for options */} +
    • {/* h4 changed to li */} + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
    + +
    +

    + + Imagina-se aprendendo a desenvolver aplicativos que facilitem + a vida das pessoas, como apps de transporte ou de pedidos de + comida? + +

    +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
    +
    + +
    +
    +

    + + Valoriza a ideia de criar interfaces amigáveis e atraentes + para seus aplicativos? + +

    +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
    + +
    +

    + + Gostaria de criar aplicativos que aproveitassem recursos + específicos de dispositivos móveis, como câmeras e sensores? + +

    +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
    +
    +
    + +
    + + + + + + +
    +
    +
+ ); +}; + +export default TestPage02Desktop; diff --git a/front-codequest/src/pages/desktop/TestPage03.tsx b/front-codequest/src/pages/desktop/TestPage03.tsx index 41a99d8..66b0c3c 100644 --- a/front-codequest/src/pages/desktop/TestPage03.tsx +++ b/front-codequest/src/pages/desktop/TestPage03.tsx @@ -1,348 +1,368 @@ -import { FunctionComponent } from "react"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; -import "./TestPage03.css"; -import { Link } from 'react-router-dom'; -import React, { useState, useEffect } from "react"; - -interface TestPage03DesktopProps { - onRespostasChange: (respostas: { resposta1: string; resposta2: string; resposta3: string; resposta4: string; }) => void; -} - -const TestPage03Desktop: FunctionComponent = ({ onRespostasChange }) => { - const [redirecting, setRedirecting] = useState(false); - const [respostas, setRespostas] = useState({ - resposta1: "", - resposta2: "", - resposta3: "", - resposta4: "", - }); - - React.useEffect(() => { - onRespostasChange(respostas); - }, [onRespostasChange, respostas]); - - useEffect(() => { - // Carregar respostas salvas quando o componente monta - const savedRespostas = localStorage.getItem("respostas"); - if (savedRespostas) { - setRespostas(JSON.parse(savedRespostas)); - } - }, []); - - useEffect(() => { - // Salvar respostas no localStorage sempre que elas mudam - localStorage.setItem("respostas", JSON.stringify(respostas)); - }, [respostas]); - - const handleRespostaChange = (pergunta: string, resposta: string) => { - setRespostas((prevRespostas) => ({ - ...prevRespostas, - [pergunta]: resposta, - })); - }; - - const handleRedirect = () => { - // Ativar o sinalizador de redirecionamento para mostrar algum indicador de carregamento (opcional). - setRedirecting(true); - - // Atraso de 1000 milissegundos (1 segundo) antes do redirecionamento. - setTimeout(() => { - setRedirecting(false); // Desativar o sinalizador de redirecionamento. - }, 5000); // 1000 milissegundos = 1 segundo - }; - - return ( -
-
-
- -
- -
-
-
    -

    - - Gostaria de aprender a fazer páginas na internet usando coisas - simples, como imagens e textos? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Transformar designs visuais em sites interativos e funcionais - te atrai? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Valoriza a capacidade de criar sites que se adaptam a - diferentes dispositivos, como computadores, tablets e - smartphones? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Se sente motivado a aprender a construir sites modernos, - utilizando as últimas tecnologias da web? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
-
-
- Em uma escala de 1 a 5, o quanto você: -
-
- - - - - - -
-
- ); -}; - -export default TestPage03Desktop; +import { FunctionComponent } from "react"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; +import "./TestPage03.css"; // Assuming TestPage03.css will be created/updated +import { Link } from 'react-router-dom'; +import React, { useState, useEffect } from "react"; + +const LOCAL_STORAGE_KEY = "respostasPage3"; + +const answerMapping: { [key: string]: number } = { + "nadaGostaria": 1, "poucoGostaria": 2, "neutro": 3, "gostaria": 4, "muitoGostaria": 5, + "nadaAtrai": 1, "poucoAtrai": 2, "atrai": 4, "muitoAtrai": 5, + "nadaValorizo": 1, "poucoValorizo": 2, "valorizo": 4, "muitoValorizo": 5, + "nadaMotivado": 1, "poucoMotivado": 2, "motivado": 4, "muitoMotivado": 5 +}; + +interface TestPage03DesktopProps { + onRespostasChange: (respostas: { resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }) => void; +} + +const TestPage03Desktop: FunctionComponent = ({ onRespostasChange }) => { + const [redirecting, setRedirecting] = useState(false); + const [respostas, setRespostas] = useState<{ resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }>({ + resposta1: null, + resposta2: null, + resposta3: null, + resposta4: null, + }); + + React.useEffect(() => { + onRespostasChange(respostas); + }, [onRespostasChange, respostas]); + + useEffect(() => { + const savedRespostas = localStorage.getItem(LOCAL_STORAGE_KEY); + if (savedRespostas) { + try { + const parsedRespostas = JSON.parse(savedRespostas); + setRespostas({ + resposta1: typeof parsedRespostas.resposta1 === 'number' ? parsedRespostas.resposta1 : null, + resposta2: typeof parsedRespostas.resposta2 === 'number' ? parsedRespostas.resposta2 : null, + resposta3: typeof parsedRespostas.resposta3 === 'number' ? parsedRespostas.resposta3 : null, + resposta4: typeof parsedRespostas.resposta4 === 'number' ? parsedRespostas.resposta4 : null, + }); + } catch (error) { + console.error("Failed to parse respostas from localStorage for TestPage03", error); + setRespostas({ resposta1: null, resposta2: null, resposta3: null, resposta4: null }); + } + } + }, []); + + useEffect(() => { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(respostas)); + }, [respostas]); + + const handleRespostaChange = (pergunta: keyof typeof respostas, respostaValue: string) => { + const mappedValue = answerMapping[respostaValue]; + setRespostas((prevRespostas) => ({ + ...prevRespostas, + [pergunta]: mappedValue !== undefined ? mappedValue : (respostaValue === "neutro" ? 3 : null), + })); + }; + + const handleLinkClick = () => { + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + }, 1000); + }; + + return ( +
{/* Consistent wrapper */} +
{/* Renamed from test-page1 */} + CodeQuest Logo {/* Simplified class */} + +
{/* Simplified class */} +
{/* Simplified class */} +
{/* Simplified class */} + Em uma escala de 1 a 5, o quanto você: +
+
+ +
{/* Renamed from text-test1 */} +
+
{/* Base + specific class */} +

+ + Gostaria de aprender a fazer páginas na internet usando coisas + simples, como imagens e textos? + +

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
+

+ + Transformar designs visuais em sites interativos e funcionais + te atrai? + +

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+ +
+
+

+ + Valoriza a capacidade de criar sites que se adaptam a + diferentes dispositivos, como computadores, tablets e + smartphones? + +

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ +
+

+ + Se sente motivado a aprender a construir sites modernos, + utilizando as últimas tecnologias da web? + +

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+ +
+ + + + + + +
+
+
+ ); +}; + +export default TestPage03Desktop; diff --git a/front-codequest/src/pages/desktop/TestPage04.tsx b/front-codequest/src/pages/desktop/TestPage04.tsx index b7c6256..3cdd0df 100644 --- a/front-codequest/src/pages/desktop/TestPage04.tsx +++ b/front-codequest/src/pages/desktop/TestPage04.tsx @@ -1,369 +1,219 @@ -import { FunctionComponent } from "react"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; -import "./TestPage04.css"; -import { Link } from 'react-router-dom'; -import React,{ useState, useEffect } from "react"; - -interface TestPage04DesktopProps { - onRespostasChange: (respostas: { resposta1: string; resposta2: string; resposta3: string; resposta4: string; }) => void; -} - -const TestPage04Desktop: FunctionComponent = ({ onRespostasChange }) => { - const [redirecting, setRedirecting] = useState(false); - const [respostas, setRespostas] = useState({ - resposta1: "", - resposta2: "", - resposta3: "", - resposta4: "", - }); - React.useEffect(() => { - onRespostasChange(respostas); - }, [onRespostasChange, respostas]); - useEffect(() => { - // Carregar respostas salvas quando o componente monta - const savedRespostas = localStorage.getItem("respostas"); - if (savedRespostas) { - setRespostas(JSON.parse(savedRespostas)); - } - }, []); - - useEffect(() => { - // Salvar respostas no localStorage sempre que elas mudam - localStorage.setItem("respostas", JSON.stringify(respostas)); - }, [respostas]); - - const handleRespostaChange = (pergunta: string, resposta: string) => { - setRespostas((prevRespostas) => ({ - ...prevRespostas, - [pergunta]: resposta, - })); - }; - - const handleRedirect = () => { - // Ativar o sinalizador de redirecionamento para mostrar algum indicador de carregamento (opcional). - setRedirecting(true); - - // Atraso de 1000 milissegundos (1 segundo) antes do redirecionamento. - setTimeout(() => { - setRedirecting(false); // Desativar o sinalizador de redirecionamento. - }, 5000); // 1000 milissegundos = 1 segundo - }; - - return ( -
-
-
- -
- -
-
-
    -

    - - Se interessa por descobrir informações importantes escondidas - em grandes quantidades de dados? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Gostaria de aprender como usar números e estatísticas para - encontrar padrões e tendências em conjuntos de informações? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Valoriza a possibilidade de ajudar empresas a tomar decisões - melhores com base em dados concretos? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Se sente motivado a criar visualizações de dados interessantes - para tornar informações complexas mais compreensíveis? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
-
-
- Em uma escala de 1 a 5, o quanto você: -
-
- - - - - - -
-
- ); -}; - -export default TestPage04Desktop; +import { FunctionComponent } from "react"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; +import "./TestPage04.css"; // Assuming TestPage04.css will be created/updated +import { Link } from 'react-router-dom'; +import React,{ useState, useEffect } from "react"; + +const LOCAL_STORAGE_KEY = "respostasPage4"; + +const answerMapping: { [key: string]: number } = { + "nadaInteressado": 1, "poucoInteressado": 2, "neutro": 3, "interessado": 4, "muitoInteressado": 5 + // This mapping applies to all questions on this page +}; + +interface TestPage04DesktopProps { + onRespostasChange: (respostas: { resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }) => void; +} + +const TestPage04Desktop: FunctionComponent = ({ onRespostasChange }) => { + const [redirecting, setRedirecting] = useState(false); + const [respostas, setRespostas] = useState<{ resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }>({ + resposta1: null, + resposta2: null, + resposta3: null, + resposta4: null, + }); + + React.useEffect(() => { + onRespostasChange(respostas); + }, [onRespostasChange, respostas]); + + useEffect(() => { + const savedRespostas = localStorage.getItem(LOCAL_STORAGE_KEY); + if (savedRespostas) { + try { + const parsedRespostas = JSON.parse(savedRespostas); + setRespostas({ + resposta1: typeof parsedRespostas.resposta1 === 'number' ? parsedRespostas.resposta1 : null, + resposta2: typeof parsedRespostas.resposta2 === 'number' ? parsedRespostas.resposta2 : null, + resposta3: typeof parsedRespostas.resposta3 === 'number' ? parsedRespostas.resposta3 : null, + resposta4: typeof parsedRespostas.resposta4 === 'number' ? parsedRespostas.resposta4 : null, + }); + } catch (error) { + console.error("Failed to parse respostas from localStorage for TestPage04", error); + setRespostas({ resposta1: null, resposta2: null, resposta3: null, resposta4: null }); + } + } + }, []); + + useEffect(() => { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(respostas)); + }, [respostas]); + + const handleRespostaChange = (pergunta: keyof typeof respostas, respostaValue: string) => { + const mappedValue = answerMapping[respostaValue]; + setRespostas((prevRespostas) => ({ + ...prevRespostas, + [pergunta]: mappedValue !== undefined ? mappedValue : (respostaValue === "neutro" ? 3 : null), + })); + }; + + const handleLinkClick = () => { + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + }, 1000); + }; + + return ( +
{/* Consistent wrapper */} +
{/* Renamed from test-page */} + {/* Background image div can be removed */} + CodeQuest Logo {/* Simplified class */} + +
{/* Simplified class, was title-test3 */} +
{/* Simplified class */} +
{/* Simplified class */} + Em uma escala de 1 a 5, o quanto você: +
+
+ +
{/* Renamed from text-test */} +
+
{/* Base + specific class */} +

+ + Se interessa por descobrir informações importantes escondidas + em grandes quantidades de dados? + +

+
    + {["nadaInteressado", "poucoInteressado", "neutro", "interessado", "muitoInteressado"].map(value => ( +
  • + +
  • + ))} +
+
+ +
+

+ + Gostaria de aprender como usar números e estatísticas para + encontrar padrões e tendências em conjuntos de informações? + +

+
    + {["nadaInteressado", "poucoInteressado", "neutro", "interessado", "muitoInteressado"].map(value => ( +
  • + +
  • + ))} +
+
+
+ +
+
+

+ + Valoriza a possibilidade de ajudar empresas a tomar decisões + melhores com base em dados concretos? + +

+
    + {["nadaInteressado", "poucoInteressado", "neutro", "interessado", "muitoInteressado"].map(value => ( +
  • + +
  • + ))} +
+
+ +
+

+ + Se sente motivado a criar visualizações de dados interessantes + para tornar informações complexas mais compreensíveis? + +

+
    + {["nadaInteressado", "poucoInteressado", "neutro", "interessado", "muitoInteressado"].map(value => ( +
  • + +
  • + ))} +
+
+
+
+ +
+ + + + + + +
+
+
+ ); +}; + +export default TestPage04Desktop; diff --git a/front-codequest/src/pages/desktop/TestPage05.tsx b/front-codequest/src/pages/desktop/TestPage05.tsx index 1458371..cfaeef7 100644 --- a/front-codequest/src/pages/desktop/TestPage05.tsx +++ b/front-codequest/src/pages/desktop/TestPage05.tsx @@ -1,366 +1,189 @@ -import { FunctionComponent } from "react"; -import "./TestPage05.css"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { Button } from "react-bootstrap"; -import { Link } from 'react-router-dom'; -import React,{ useState, useEffect } from "react"; - -interface TestPage05DesktopProps { - onRespostasChange: (respostas: { resposta1: string; resposta2: string; resposta3: string; resposta4: string; }) => void; -} - -const TestPage05Desktop: FunctionComponent = ({ onRespostasChange }) => { - const [redirecting, setRedirecting] = useState(false); - const [respostas, setRespostas] = useState({ - resposta1: "", - resposta2: "", - resposta3: "", - resposta4: "", - }); - - React.useEffect(() => { - onRespostasChange(respostas); - }, [onRespostasChange, respostas]); - - useEffect(() => { - // Carregar respostas salvas quando o componente monta - const savedRespostas = localStorage.getItem("respostas"); - if (savedRespostas) { - setRespostas(JSON.parse(savedRespostas)); - } - }, []); - - useEffect(() => { - // Salvar respostas no localStorage sempre que elas mudam - localStorage.setItem("respostas", JSON.stringify(respostas)); - }, [respostas]); - - const handleRespostaChange = (pergunta: string, resposta: string) => { - setRespostas((prevRespostas) => ({ - ...prevRespostas, - [pergunta]: resposta, - })); - }; - - const handleRedirect = () => { - // Ativar o sinalizador de redirecionamento para mostrar algum indicador de carregamento (opcional). - setRedirecting(true); - - // Atraso de 1000 milissegundos (1 segundo) antes do redirecionamento. - setTimeout(() => { - setRedirecting(false); // Desativar o sinalizador de redirecionamento. - }, 5000); // 1000 milissegundos = 1 segundo - }; - - return ( -
-
-
- -
- -
-
-
    -

    - - Se preocupa em proteger informações pessoais e digitais de - possíveis ameaças? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Se sente atraído pela ideia de entender como hackers trabalham - para criar defesas contra ataques cibernéticos? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Gostaria de aprender a criar estratégias de segurança para - proteger sistemas e redes de possíveis invasões? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
    -

    - - Se sente motivado a estar atualizado sobre as últimas ameaças - digitais e como se defender delas? - -

    -
-
    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -

    - -

    -
-
-
-
-
-
- Em uma escala de 1 a 5, o quanto você: -
-
- - - - - - -
-
- ); -}; - -export default TestPage05Desktop; +import { FunctionComponent } from "react"; +import "./TestPage05.css"; // Assuming TestPage05.css will be created/updated +import "bootstrap/dist/css/bootstrap.min.css"; +import { Button } from "react-bootstrap"; +import { Link } from 'react-router-dom'; +import React,{ useState, useEffect } from "react"; + +const LOCAL_STORAGE_KEY = "respostasPage5"; + +const answerMapping: { [key: string]: number } = { + "nadaPreocupado": 1, "poucoPreocupado": 2, "neutro": 3, "preocupado": 4, "muitoPreocupado": 5, + "nadaInteressado": 1, "poucoIneressado": 2, "poucoInteressado": 2, "interessado": 4, "muitoInteressado": 5, + "nadaMotivado": 1, "poucoMotivado": 2, "motivado": 4, "muitoMotivado": 5 +}; + +interface TestPage05DesktopProps { + onRespostasChange: (respostas: { resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }) => void; +} + +const TestPage05Desktop: FunctionComponent = ({ onRespostasChange }) => { + const [redirecting, setRedirecting] = useState(false); + const [respostas, setRespostas] = useState<{ resposta1: number | null; resposta2: number | null; resposta3: number | null; resposta4: number | null; }>({ + resposta1: null, + resposta2: null, + resposta3: null, + resposta4: null, + }); + + React.useEffect(() => { + onRespostasChange(respostas); + }, [onRespostasChange, respostas]); + + useEffect(() => { + const savedRespostas = localStorage.getItem(LOCAL_STORAGE_KEY); + if (savedRespostas) { + try { + const parsedRespostas = JSON.parse(savedRespostas); + setRespostas({ + resposta1: typeof parsedRespostas.resposta1 === 'number' ? parsedRespostas.resposta1 : null, + resposta2: typeof parsedRespostas.resposta2 === 'number' ? parsedRespostas.resposta2 : null, + resposta3: typeof parsedRespostas.resposta3 === 'number' ? parsedRespostas.resposta3 : null, + resposta4: typeof parsedRespostas.resposta4 === 'number' ? parsedRespostas.resposta4 : null, + }); + } catch (error) { + console.error("Failed to parse respostas from localStorage for TestPage05", error); + setRespostas({ resposta1: null, resposta2: null, resposta3: null, resposta4: null }); + } + } + }, []); + + useEffect(() => { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(respostas)); + }, [respostas]); + + const handleRespostaChange = (pergunta: keyof typeof respostas, respostaValue: string) => { + const mappedValue = answerMapping[respostaValue]; + setRespostas((prevRespostas) => ({ + ...prevRespostas, + [pergunta]: mappedValue !== undefined ? mappedValue : (respostaValue === "neutro" ? 3 : null), + })); + }; + + const handleLinkClick = () => { + setRedirecting(true); + setTimeout(() => { + setRedirecting(false); + }, 1000); + }; + + // Helper to generate radio options for a question + const renderOptions = (questionName: keyof typeof respostas, options: string[]) => { + return options.map(value => ( +
  • + +
  • + )); + }; + + return ( +
    {/* Consistent wrapper */} +
    {/* Renamed from test-page4 */} + CodeQuest Logo {/* Simplified class */} + +
    {/* Simplified class, was title-test3 */} +
    {/* Simplified class */} +
    {/* Simplified class */} + Em uma escala de 1 a 5, o quanto você: +
    +
    + +
    {/* Renamed from text-test4 */} +
    +
    {/* Base + specific class */} +

    + + Se preocupa em proteger informações pessoais e digitais de + possíveis ameaças? + +

    +
      + {renderOptions("resposta1", ["nadaPreocupado", "poucoPreocupado", "neutro", "preocupado", "muitoPreocupado"])} +
    +
    + +
    +

    + + Se sente atraído pela ideia de entender como hackers trabalham + para criar defesas contra ataques cibernéticos? + +

    +
      + {/* Note the typo "poucoIneressado" here as per original file value */} + {renderOptions("resposta2", ["nadaInteressado", "poucoIneressado", "neutro", "interessado", "muitoInteressado"])} +
    +
    +
    + +
    +
    +

    + + Gostaria de aprender a criar estratégias de segurança para + proteger sistemas e redes de possíveis invasões? + +

    +
      + {/* This uses "poucoInteressado" (correct spelling) */} + {renderOptions("resposta3", ["nadaInteressado", "poucoInteressado", "neutro", "interessado", "muitoInteressado"])} +
    +
    + +
    +

    + + Se sente motivado a estar atualizado sobre as últimas ameaças + digitais e como se defender delas? + +

    +
      + {renderOptions("resposta4", ["nadaMotivado", "poucoMotivado", "neutro", "motivado", "muitoMotivado"])} +
    +
    +
    +
    + +
    + + + + {/* Link to /save (SavePage) as this is the last test page */} + + + +
    +
    +
    + ); +}; + +export default TestPage05Desktop;