diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cd271dc..bc44431 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17481,9 +17481,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -17492,7 +17492,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { diff --git a/frontend/src/App.js b/frontend/src/App.js index e48473c..2f9e578 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,11 +1,40 @@ +/** + * @fileoverview Superhero Comparison Application + * + * This React application provides a user interface for viewing, selecting, and comparing + * superheroes based on their power statistics. Users can view a table of superheroes, + * select up to two heroes, and compare their stats head-to-head to determine a winner. + * + * The application has two main views: + * - Table View: Displays all superheroes in a table with their statistics + * - Comparison View: Shows a side-by-side comparison of two selected heroes + * + * @author Copilot + * @requires react + * @requires ./App.css + */ + import React, { useEffect, useState } from 'react'; import './App.css'; +/** + * Main App component that manages the superhero comparison application. + * + * This component handles the entire application state including fetching superhero data, + * managing hero selections, switching between views, and rendering the appropriate UI. + * + * @component + * @returns {JSX.Element} The rendered App component + */ function App() { const [superheroes, setSuperheroes] = useState([]); const [selectedHeroes, setSelectedHeroes] = useState([]); const [currentView, setCurrentView] = useState('table'); // 'table' or 'comparison' + /** + * Fetches the list of superheroes from the API on component mount. + * Uses the useEffect hook to trigger the fetch operation once when the component is first rendered. + */ useEffect(() => { fetch('/api/superheroes') .then((response) => response.json()) @@ -13,6 +42,17 @@ function App() { .catch((error) => console.error('Error fetching superheroes:', error)); }, []); + /** + * Handles the selection/deselection of a superhero. + * + * This function manages the selection logic with the following rules: + * - If a hero is already selected, clicking them will deselect them + * - If fewer than 2 heroes are selected, the clicked hero is added to the selection + * - If 2 heroes are already selected, the oldest selection is replaced with the new one + * + * @param {Object} hero - The superhero object to select or deselect + * @param {number} hero.id - The unique identifier of the superhero + */ const handleHeroSelection = (hero) => { setSelectedHeroes(prev => { if (prev.find(h => h.id === hero.id)) { @@ -22,32 +62,66 @@ function App() { // Add if less than 2 selected return [...prev, hero]; } else { - // Replace first selection if 2 already selected + // Replace first selection if 2 already selected (FIFO replacement) return [prev[1], hero]; } }); }; + /** + * Checks if a superhero is currently selected. + * + * @param {number} heroId - The ID of the hero to check + * @returns {boolean} True if the hero is selected, false otherwise + */ const isHeroSelected = (heroId) => { return selectedHeroes.some(h => h.id === heroId); }; + /** + * Switches to the comparison view when exactly 2 heroes are selected. + * + * This function is called when the user clicks the "Compare Heroes" button. + * It only changes the view if exactly 2 heroes are currently selected. + */ const handleCompare = () => { if (selectedHeroes.length === 2) { setCurrentView('comparison'); } }; + /** + * Returns to the table view and clears the selected heroes. + * + * This function is called when the user clicks the "Back to Heroes Table" button + * from the comparison view. It resets both the view and the selection state. + */ const handleBackToTable = () => { setCurrentView('table'); setSelectedHeroes([]); }; + /** + * Calculates which hero wins in a head-to-head comparison. + * + * Compares six power stats (intelligence, strength, speed, durability, power, combat) + * between two heroes. Each stat comparison awards one point to the hero with the higher + * value. The hero with the most points wins. If the points are equal, it's a tie. + * + * @param {Object} hero1 - The first superhero object + * @param {Object} hero1.powerstats - Object containing the hero's power statistics + * @param {Object} hero2 - The second superhero object + * @param {Object} hero2.powerstats - Object containing the hero's power statistics + * @returns {Object} An object containing the winner and the score + * @returns {Object|null} returns.winner - The winning hero object, or null if it's a tie + * @returns {string} returns.score - The score in "X-Y" format + */ const calculateWinner = (hero1, hero2) => { const stats = ['intelligence', 'strength', 'speed', 'durability', 'power', 'combat']; let hero1Score = 0; let hero2Score = 0; + // Compare each stat and award points to the hero with the higher value stats.forEach(stat => { if (hero1.powerstats[stat] > hero2.powerstats[stat]) { hero1Score++; @@ -56,15 +130,28 @@ function App() { } }); + // Determine the winner based on total scores if (hero1Score > hero2Score) { return { winner: hero1, score: `${hero1Score}-${hero2Score}` }; } else if (hero2Score > hero1Score) { return { winner: hero2, score: `${hero2Score}-${hero1Score}` }; } else { + // It's a tie - return null for winner return { winner: null, score: `${hero1Score}-${hero2Score}` }; } }; + /** + * Renders the comparison view displaying two heroes side-by-side. + * + * This view shows: + * - Hero images and names + * - A detailed comparison of all six power stats + * - Highlighting of winning stats for each hero + * - The final winner announcement or tie declaration + * + * @returns {JSX.Element|null} The comparison view component, or null if not exactly 2 heroes selected + */ const renderComparison = () => { if (selectedHeroes.length !== 2) return null; @@ -79,6 +166,7 @@ function App() {

Superhero Comparison

+ {/* Hero cards displaying images and names */}
{hero1.name} @@ -95,10 +183,12 @@ function App() {
+ {/* Stats comparison table with highlighting for winners */}
{stats.map(stat => { const stat1 = hero1.powerstats[stat]; const stat2 = hero2.powerstats[stat]; + // Determine which hero wins this stat comparison (or if it's a tie) const winner = stat1 > stat2 ? 'hero1' : stat1 < stat2 ? 'hero2' : 'tie'; return ( @@ -117,6 +207,7 @@ function App() { })}
+ {/* Final result section showing the overall winner or tie */}

Final Result

{result.winner ? ( @@ -135,6 +226,17 @@ function App() { ); }; + /** + * Renders the main table view displaying all superheroes. + * + * This view includes: + * - A selection counter showing how many heroes are selected + * - Display of currently selected heroes + * - A button to compare the selected heroes (enabled only when 2 are selected) + * - A table showing all heroes with their stats and checkboxes for selection + * + * @returns {JSX.Element} The table view component + */ const renderTable = () => (

Superheroes