From 0a427476f3fed60b2b35e0dfad040feb6bf68d39 Mon Sep 17 00:00:00 2001 From: ZIad9990 Date: Fri, 22 Mar 2024 03:14:04 +0200 Subject: [PATCH 1/4] adding index.js --- src/client/assets/javascript/index.js | 168 +++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 19 deletions(-) diff --git a/src/client/assets/javascript/index.js b/src/client/assets/javascript/index.js index feaaa646..1f2675ce 100644 --- a/src/client/assets/javascript/index.js +++ b/src/client/assets/javascript/index.js @@ -78,23 +78,54 @@ async function handleCreateRace() { renderAt('#race', renderRaceStartView()) // TODO - Get player_id and track_id from the store + const player_id = store.player_id; + const track_id = store.track_id; // const race = TODO - invoke the API call to create the race, then save the result + const race = await createRace(player_id , track_id) + // TODO - update the store with the race id // For the API to work properly, the race id should be race id - 1 + store.race_id = race.ID - 1; // The race has been created, now start the countdown // TODO - call the async function runCountdown + runCountdown(); // TODO - call the async function startRace - + startRace(); // TODO - call the async function runRace + runRace() } function runRace(raceID) { return new Promise(resolve => { // TODO - use Javascript's built in setInterval method to get race info every 500ms + const raceInterval = setInterval(async () => { + try { + const response = await fetch(`${SERVER}/api/races/${raceID}`); + + if (!response.ok) { + throw new Error(`Failed to get race info: ${response.status}`); + } + + const raceInfo = await response.json(); + + if (raceInfo.status === "in-progress") { + renderAt('#leaderBoard', raceProgress(raceInfo.positions)); + } + + if (raceInfo.status === "finished") { + clearInterval(raceInterval); + renderAt('#race', resultsView(raceInfo.positions)); + resolve(raceInfo); + } + } catch (error) { + console.error('there is an error', error); + } + }, 500); + }); /* TODO - if the race info status property is "in-progress", update the leaderboard by calling: @@ -102,37 +133,45 @@ function runRace(raceID) { renderAt('#leaderBoard', raceProgress(res.positions)) */ - /* + /* TODO - if the race info status property is "finished", run the following: clearInterval(raceInterval) // to stop the interval from repeating renderAt('#race', resultsView(res.positions)) // to render the results view reslove(res) // resolve the promise - */ - }) + */ // remember to add error handling for the Promise -} + // this part is done + // look up ^^ + } + async function runCountdown() { - try { - // wait for the DOM to load - await delay(1000) - let timer = 3 + try { + // Wait for the DOM to load + await delay(1000); - return new Promise(resolve => { - // TODO - use Javascript's built in setInterval method to count down once per second + let timer = 3; // Initial countdown value + return new Promise(resolve => { + // TODO - use Javascript's built in setInterval method to count down once per second + const countdownInterval = setInterval(() => { + document.getElementById('big-numbers').innerHTML = --timer; // run this DOM manipulation to decrement the countdown for the user - document.getElementById('big-numbers').innerHTML = --timer // TODO - if the countdown is done, clear the interval, resolve the promise, and return - - }) - } catch(error) { - console.log(error); - } + if (timer === 0) { + clearInterval(countdownInterval); + resolve(); + } + }, 1000); // Run the interval every 1000 milliseconds (1 second) + }); + } catch (error) { + console.error(error); + } } + function handleSelectPodRacer(target) { console.log("selected a pod", target.id) @@ -322,12 +361,61 @@ function defaultFetchOpts() { function getTracks() { // GET request to `${SERVER}/api/tracks` + fetch(`${SERVER}/api/tracks`) + .then(result => { + if (!result.ok) { + throw new error (`error: ${result.status}`); + } else { + return result.json(); + } + }) + + .then(data => { + data.forEach(data => { + const track_id = data.tracks.id + const track_name = data.tracks.name + const track_segments = data.tracks.segments + }) + }) + + .catch ( + error => console.error(`there is an error: ${error}`) + ) } function getRacers() { // GET request to `${SERVER}/api/cars` + fetch(`${SERVER}/api/cars`) + .then( + result => { + if (!result.ok) { + console.error(`error: ${result.status}`) + } else { + return result.json() + } + } + ) + .then( + data => { + data.forEach(data => { + const car_id = data.cars.id + const car_driverName = data.cars.driver_name + const car_topSpeed = data.cars.top_speed + const car_acceleration = data.cars.acceleration + const car_handling = data.cars.handling + }) + } + ) + .catch (error => console.error(`there is an error: ${error}`)) + } + + + + + + function createRace(player_id, track_id) { player_id = parseInt(player_id) track_id = parseInt(track_id) @@ -345,8 +433,40 @@ function createRace(player_id, track_id) { function getRace(id) { // GET request to `${SERVER}/api/races/${id}` + fetch(`${SERVER}/api/races/${id}`) + .then(result => { + if (!result.ok) { + throw new Error(`Error: ${result.status}`); + } + else { + return result.json(); + } + }) + .then(data => { + data.forEach(race => { + race.status = mapRaceStatus(race.status); + }); + console.log(data); + }) + .catch(error => { + console.error('Error fetching race:', error); + }); +} + +function mapRaceStatus(status) { + switch (status) { + case "started": + return "Started"; + case "in-progress": + return "In Progress"; + case "finished": + return "Finished"; + default: + return "Unknown"; + } } + function startRace(id) { return fetch(`${SERVER}/api/races/${id}/start`, { method: 'POST', @@ -355,9 +475,19 @@ function startRace(id) { .then(res => res.json()) .catch(err => console.log("Problem with getRace request::", err)) } - function accelerate(id) { - // POST request to `${SERVER}/api/races/${id}/accelerate` + fetch(`${SERVER}/api/races/${id}/accelerate`, {method: 'POST'}) + .then(response => { + if (!response.ok) { + throw new Error(`Failed to accelerate: ${response.status}`); + } + }) + .then(() => { + console.log('Acceleration successful'); + }) + .catch(error => { + console.error('Error accelerating race:', error); + }); // options parameter provided as defaultFetchOpts // no body or datatype needed for this request } From dc04a630091a7a9901ed7b160fdbca9ccd0d56ff Mon Sep 17 00:00:00 2001 From: zoz911 <164420754+zoz911@users.noreply.github.com> Date: Thu, 28 Mar 2024 21:22:09 +0200 Subject: [PATCH 2/4] Add files via upload fix some fetch bugs --- index.js | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 index.js diff --git a/index.js b/index.js new file mode 100644 index 00000000..e2fe6b76 --- /dev/null +++ b/index.js @@ -0,0 +1,516 @@ +// // PROVIDED CODE BELOW (LINES 1 - 80) DO NOT REMOVE + +// The store will hold all information needed globally +let store = { + track_id: undefined, + player_id: undefined, + race_id: undefined, +} + +// We need our javascript to wait until the DOM is loaded +document.addEventListener("DOMContentLoaded", function() { + onPageLoad() + setupClickHandlers() +}) + +async function onPageLoad() { + try { + getTracks() + .then(tracks => { + const html = renderTrackCards(tracks) + renderAt('#tracks', html) + }) + + getRacers() + .then((racers) => { + const html = renderRacerCars(racers) + renderAt('#racers', html) + }) + } catch(error) { + console.log("Problem getting tracks and racers ::", error.message) + console.error(error) + } +} + +function setupClickHandlers() { + document.addEventListener('click', function(event) { + const { target } = event + + // Race track form field + if (target.matches('.card.track')) { + handleSelectTrack(target) + } + + // Podracer form field + if (target.matches('.card.podracer')) { + handleSelectPodRacer(target) + } + + // Submit create race form + if (target.matches('#submit-create-race')) { + event.preventDefault() + + // start race + handleCreateRace() + } + + // Handle acceleration click + if (target.matches('#gas-peddle')) { + handleAccelerate() + } + + }, false) +} + +async function delay(ms) { + try { + return await new Promise(resolve => setTimeout(resolve, ms)); + } catch(error) { + console.log("an error shouldn't be possible here") + console.log(error) + } +} +// ^ PROVIDED CODE ^ DO NOT REMOVE + +// This async function controls the flow of the race, add the logic and error handling +async function handleCreateRace() { + // render starting UI + renderAt('#race', renderRaceStartView()) + + // TODO - Get player_id and track_id from the store + const player_id = store.player_id; + const track_id = store.track_id; + + // const race = TODO - invoke the API call to create the race, then save the result + const race = await createRace(player_id , track_id) + + + // TODO - update the store with the race id + // For the API to work properly, the race id should be race id - 1 + store.race_id = race.ID - 1; + + // The race has been created, now start the countdown + // TODO - call the async function runCountdown + runCountdown(); + + // TODO - call the async function startRace + startRace(); + // TODO - call the async function runRace + runRace() +} + +function runRace(raceID) { + return new Promise(resolve => { + // TODO - use Javascript's built in setInterval method to get race info every 500ms + const raceInterval = setInterval(async () => { + try { + const response = await fetch(`${SERVER}/api/races/${raceID}`) + + if (!response.ok) { + throw new Error(`Failed to get race info: ${response.status}`); + } + + const raceInfo = await response.json(); + + if (raceInfo.status === "in-progress") { + renderAt('#leaderBoard', raceProgress(raceInfo.positions)); + } + + if (raceInfo.status === "finished") { + clearInterval(raceInterval); + renderAt('#race', resultsView(raceInfo.positions)); + resolve(raceInfo); + } + } catch (error) { + console.error('there is an error', error); + } + }, 500); + }); + + /* + TODO - if the race info status property is "in-progress", update the leaderboard by calling: + + renderAt('#leaderBoard', raceProgress(res.positions)) + */ + + /* + TODO - if the race info status property is "finished", run the following: + + clearInterval(raceInterval) // to stop the interval from repeating + renderAt('#race', resultsView(res.positions)) // to render the results view + reslove(res) // resolve the promise + */ + // remember to add error handling for the Promise + // this part is done + // look up ^^ + } + + +async function runCountdown() { + try { + // Wait for the DOM to load + await delay(1000); + + let timer = 3; // Initial countdown value + + return new Promise(resolve => { + // TODO - use Javascript's built in setInterval method to count down once per second + const countdownInterval = setInterval(() => { + document.getElementById('big-numbers').innerHTML = --timer; + // run this DOM manipulation to decrement the countdown for the user + + // TODO - if the countdown is done, clear the interval, resolve the promise, and return + if (timer === 0) { + clearInterval(countdownInterval); + return resolve(); + } + }, 1000); // Run the interval every 1000 milliseconds (1 second) + }); + } catch (error) { + console.error(error); + } +} + + +function handleSelectPodRacer(target) { + console.log("selected a pod", target.id) + + // remove class selected from all racer options + const selected = document.querySelector('#racers .selected') + if (selected) { + selected.classList.remove('selected') + } + + // add class selected to current target + target.classList.add('selected') + + // TODO - save the selected racer ID to the store + store.player_id = target.id; // Update store.player_id instead of store.race_id +} + +function handleSelectTrack(target) { + console.log("selected a track", target.id) + + // remove class selected from all track options + const selected = document.querySelector('#tracks .selected') + if (selected) { + selected.classList.remove('selected') + } + + // add class selected to current target + target.classList.add('selected') + + // TODO - save the selected track id to the store + store.track_id = target.id; +} + + + // // HTML VIEWS ------------------------------------------------ + // // Provided code - do not remove + + function renderRacerCars(racers) { + if (!racers.length) { + return ` +

Loading Racers... + ` + } + + const results = racers.map(renderRacerCard).join('') + + return ` + + ` + } + + function renderRacerCard(racer) { + const { id, driver_name, top_speed, acceleration, handling } = racer + + return ` +
  • +

    ${driver_name}

    +

    ${top_speed}

    +

    ${acceleration}

    +

    ${handling}

    +
  • + ` + } + + function renderTrackCards(tracks) { + if (!tracks.length) { + return ` +

    Loading Tracks... + ` + } + + const results = tracks.map(renderTrackCard).join('') + + return ` + + ` + } + + function renderTrackCard(track) { + const { id, name } = track + + return ` +
  • +

    ${name}

    +
  • + ` + } + + function renderCountdown(count) { + return ` +

    Race Starts In...

    +

    ${count}

    + ` + } + + function renderRaceStartView(track, racers) { + return ` +
    +

    Race: ${track.name}

    +
    +
    +
    + ${renderCountdown(3)} +
    + +
    +

    Directions

    +

    Click the button as fast as you can to make your racer go faster!

    + +
    +
    + + ` + } + + function resultsView(positions) { + positions.sort((a, b) => (a.final_position > b.final_position) ? 1 : -1) + + return ` +
    +

    Race Results

    +
    +
    + ${raceProgress(positions)} + Start a new race +
    + ` + } + + function raceProgress(positions) { + let userPlayer = positions.find(e => e.id === store.player_id) + userPlayer.driver_name += " (you)" + + positions = positions.sort((a, b) => (a.segment > b.segment) ? -1 : 1) + let count = 1 + + const results = positions.map(p => { + return ` + + +

    ${count++} - ${p.driver_name}

    + + + ` + }) + + return ` +
    +

    Leaderboard

    +
    + ${results} +
    +
    + ` + } + + function renderAt(element, html) { + const node = document.querySelector(element) + + node.innerHTML = html + } + + // // ^ Provided code ^ do not remove + + + // // API CALLS ------------------------------------------------ + + const SERVER = 'http://localhost:3001' + + function defaultFetchOpts() { + return { + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': SERVER, + }, + } + } + + // // TODO - Make a fetch call (with error handling!) to each of the following API endpoints + + async function getTracks() { + // GET request to `${SERVER}/api/tracks` + try { + return await fetch(`${SERVER}/api/tracks`) + .then(result => { + if (!result.ok) { + throw new Error(`error: ${result.status}`); + } else { + return result.json(); + } + }) + .catch( + error => console.error(`there is an error: ${error}`) + ) + } catch (err) { + console.log('ERROR in getting tracks from server') + console.dir(err) + } + + } + +async function getRacers() { + try { + // GET request to `${SERVER}/api/cars` + const response = await fetch(`${SERVER}/api/cars`); + + if (!response.ok) { + throw new Error(`Failed to fetch racers: ${response.status}`); + } + + const racers = await response.json(); + return racers.map(racer => ({ + id: racer.id, + driver_name: racer.driver_name, + top_speed: racer.top_speed, + acceleration: racer.acceleration, + handling: racer.handling + })); + } catch (error) { + console.error(`Error fetching racers: ${error}`); + } +} + +function renderRacerCard(racer) { + const + { id, driver_name, top_speed, acceleration, handling } + = racer + + return ` +
  • +

    ${driver_name}

    +

    Top Speed: ${top_speed}

    +

    Acceleration: ${acceleration}

    +

    Handling: ${handling}

    +
  • + ` + +} + + + function createRace(player_id, track_id) { + player_id = parseInt(player_id) + track_id = parseInt(track_id) + const body = { player_id, track_id } + + return fetch(`${SERVER}/api/races`, { + method: 'POST', + ...defaultFetchOpts(), + dataType: 'jsonp', + body: JSON.stringify(body) + }) + .then(res => res.json()) + .catch(err => console.log("Problem with createRace request::", err)) + } + + async function getRace(id) { + // GET request to `${SERVER}/api/races/${id}` + try { + return await fetch(`${SERVER}/api/races/${id}`) + .then(result => { + if (!result.ok) { + throw new Error(`Error: ${result.status}`); + } + else { + return result.json(); + } + }) + .then(data => { + data.forEach(race => { + race.status = mapRaceStatus(race.status); + }); + console.log(data); + }) + .catch(error => { + console.error('Error fetching race:', error); + }); + } catch { console.error(`error getting race id=${id}:`) }; + + } + + function mapRaceStatus(status) { + switch (status) { + case "started": + return "Started"; + case "in-progress": + return "In Progress"; + case "finished": + return "Finished"; + default: + return "Unknown"; + } + } + + + async function startRace(id) { + return await fetch(`${SERVER}/api/races/${id}/start`, { + method: 'POST', + ...defaultFetchOpts(), + }) + .then(result => result.json()) + .catch(err => console.log("Problem with getRace request:", err)) + } + // Add event listener to the accelerate button +document.addEventListener('click', function(event) { + const { target } = event; + // Handle acceleration click + if (target.matches('#gas-peddle')) { + handleAccelerate(); + } +}); + +async function handleAccelerate() { + try { + if (!store.race_id) { + console.error("No race is currently ongoing."); + return; + } + await accelerate(store.race_id); + console.log("Acceleration successful"); + } catch (error) { + console.error("Error accelerating race:", error); + } +} + +function accelerate(id) { + return fetch(`${SERVER}/api/races/${id}/accelerate`, { method: 'POST' }) + .then(response => { + if (!response.ok) { + throw new Error(`Failed to accelerate: ${response.status}`); + } + }) + .then(() => { + console.log('Acceleration successful'); + }) + .catch(error => { + console.error('Error accelerating race:', error); + }); +} From 3aac054e60b77dec448443a8eeec10e2df8628a0 Mon Sep 17 00:00:00 2001 From: zoz911 <164420754+zoz911@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:25:28 +0200 Subject: [PATCH 3/4] edit some bugs --- src/client/assets/javascript/index.js | 498 ++++++++++++++------------ 1 file changed, 265 insertions(+), 233 deletions(-) diff --git a/src/client/assets/javascript/index.js b/src/client/assets/javascript/index.js index 1f2675ce..1e2ecbc6 100644 --- a/src/client/assets/javascript/index.js +++ b/src/client/assets/javascript/index.js @@ -1,4 +1,4 @@ -// PROVIDED CODE BELOW (LINES 1 - 80) DO NOT REMOVE +// // PROVIDED CODE BELOW (LINES 1 - 80) DO NOT REMOVE // The store will hold all information needed globally let store = { @@ -74,29 +74,33 @@ async function delay(ms) { // This async function controls the flow of the race, add the logic and error handling async function handleCreateRace() { - // render starting UI - renderAt('#race', renderRaceStartView()) + // render starting UI + renderAt('#race', renderRaceStartView(store.track_id , store.player_id)) - // TODO - Get player_id and track_id from the store - const player_id = store.player_id; - const track_id = store.track_id; - - // const race = TODO - invoke the API call to create the race, then save the result - const race = await createRace(player_id , track_id) - + try { + // Get player_id and track_id from the store + const player_id = store.player_id; + const track_id = store.track_id; - // TODO - update the store with the race id - // For the API to work properly, the race id should be race id - 1 - store.race_id = race.ID - 1; - - // The race has been created, now start the countdown - // TODO - call the async function runCountdown - runCountdown(); - - // TODO - call the async function startRace - startRace(); - // TODO - call the async function runRace - runRace() + // Invoke the API call to create the race, then save the result + const race = await createRace(player_id, track_id); + + // Update the store with the race id + store.race_id = race.ID - 1; + + // The race has been created, now start the countdown + // Call the async function runCountdown + runCountdown(); + + // Call the async function startRace + startRace(store.race_id); + + // Call the async function runRace + runRace(store.race_id); + return console.log(race.ID) + } catch (error) { + console.error("Error handling race creation:", error); + } } function runRace(raceID) { @@ -104,7 +108,7 @@ function runRace(raceID) { // TODO - use Javascript's built in setInterval method to get race info every 500ms const raceInterval = setInterval(async () => { try { - const response = await fetch(`${SERVER}/api/races/${raceID}`); + const response = await fetch(`${SERVER}/api/races/${raceID}`) if (!response.ok) { throw new Error(`Failed to get race info: ${response.status}`); @@ -121,9 +125,11 @@ function runRace(raceID) { renderAt('#race', resultsView(raceInfo.positions)); resolve(raceInfo); } - } catch (error) { - console.error('there is an error', error); - } + } + catch (err) { + console.error(err) + } + }, 500); }); @@ -162,7 +168,7 @@ async function runCountdown() { // TODO - if the countdown is done, clear the interval, resolve the promise, and return if (timer === 0) { clearInterval(countdownInterval); - resolve(); + return resolve(); } }, 1000); // Run the interval every 1000 milliseconds (1 second) }); @@ -173,64 +179,60 @@ async function runCountdown() { function handleSelectPodRacer(target) { - console.log("selected a pod", target.id) + console.log("selected a pod", target.id) - // remove class selected from all racer options - const selected = document.querySelector('#racers .selected') - if(selected) { - selected.classList.remove('selected') - } + // remove class selected from all racer options + const selected = document.querySelector('#racers .selected') + if (selected) { + selected.classList.remove('selected') + } - // add class selected to current target - target.classList.add('selected') + // add class selected to current target + target.classList.add('selected') - // TODO - save the selected racer to the store + // TODO - save the selected racer ID to the store + store.player_id = target.id; // Update store.player_id instead of store.race_id } -function handleSelectTrack(target) { - console.log("selected a track", target.id) - - // remove class selected from all track options - const selected = document.querySelector('#tracks .selected') - if(selected) { - selected.classList.remove('selected') - } +function handleSelectTrack(target_track) { + console.log("selected a track", target_track.id) - // add class selected to current target - target.classList.add('selected') + // remove class selected from all track options + const selected = document.querySelector('#tracks .selected') + if (selected) { + selected.classList.remove('selected') + } - // TODO - save the selected track id to the store - -} + // add class selected to current target + target_track.classList.add('selected') // <-- Corrected from 'target' to 'target_track' -function handleAccelerate() { - console.log("accelerate button clicked") - // TODO - Invoke the API call to accelerate + // Save the selected track id to the store + store.track_id = target_track.id; } -// HTML VIEWS ------------------------------------------------ -// Provided code - do not remove + // // HTML VIEWS ------------------------------------------------ + // // Provided code - do not remove -function renderRacerCars(racers) { - if (!racers.length) { - return ` + function renderRacerCars(racers) { + if (!racers.length) { + return `

    Loading Racers... ` - } + } - const results = racers.map(renderRacerCard).join('') + const results = racers.map(renderRacerCard).join('') - return ` + return ` ` -} + } -function renderRacerCard(racer) { - const { id, driver_name, top_speed, acceleration, handling } = racer + function renderRacerCard(racer) { + const { id, driver_name, top_speed, acceleration, handling } = racer - return ` + return `
  • ${driver_name}

    ${top_speed}

    @@ -238,43 +240,43 @@ function renderRacerCard(racer) {

    ${handling}

  • ` -} + } -function renderTrackCards(tracks) { - if (!tracks.length) { - return ` + function renderTrackCards(tracks) { + if (!tracks.length) { + return `

    Loading Tracks... ` - } + } - const results = tracks.map(renderTrackCard).join('') + const results = tracks.map(renderTrackCard).join('') - return ` + return ` ` -} + } -function renderTrackCard(track) { - const { id, name } = track + function renderTrackCard(track) { + const { id, name } = track - return ` + return `
  • ${name}

  • ` -} + } -function renderCountdown(count) { - return ` + function renderCountdown(count) { + return `

    Race Starts In...

    ${count}

    ` -} + } -function renderRaceStartView(track, racers) { - return ` + function renderRaceStartView(track, racers) { + return `

    Race: ${track.name}

    @@ -291,12 +293,12 @@ function renderRaceStartView(track, racers) { ` -} + } -function resultsView(positions) { - positions.sort((a, b) => (a.final_position > b.final_position) ? 1 : -1) + function resultsView(positions) { + positions.sort((a, b) => (a.final_position > b.final_position) ? 1 : -1) - return ` + return `

    Race Results

    @@ -305,189 +307,219 @@ function resultsView(positions) { Start a new race ` -} - -function raceProgress(positions) { - let userPlayer = positions.find(e => e.id === store.player_id) - userPlayer.driver_name += " (you)" + } - positions = positions.sort((a, b) => (a.segment > b.segment) ? -1 : 1) - let count = 1 + function raceProgress(positions) { + // Check if positions is undefined or empty + if (!positions || positions.length === 0) { + return "

    No race progress available

    "; + } - const results = positions.map(p => { - return ` - - -

    ${count++} - ${p.driver_name}

    - - - ` - }) + // Sort positions array based on segment + positions.sort((a, b) => (a.segment > b.segment) ? -1 : 1); + + // Initialize a counter for leaderboard position + let count = 1; + + // Map each position to HTML content + const results = positions.map(p => { + // Check if the current position object has the 'driver_name' property + if (!p || !p.driver_name) { + return "

    No driver name available

    "; + } + return ` + + +

    ${count++} - ${p.driver_name}

    + + + `; + }); - return ` -
    -

    Leaderboard

    -
    - ${results} -
    -
    - ` + // Construct the leaderboard HTML + const leaderboardHTML = ` +
    +

    Leaderboard

    +
    + ${results.join("")} +
    +
    + `; + + return leaderboardHTML; } -function renderAt(element, html) { - const node = document.querySelector(element) + function renderAt(element, html) { + const node = document.querySelector(element) - node.innerHTML = html -} + node.innerHTML = html + } -// ^ Provided code ^ do not remove + // // ^ Provided code ^ do not remove -// API CALLS ------------------------------------------------ + // // API CALLS ------------------------------------------------ -const SERVER = 'http://localhost:3001' + const SERVER = 'http://localhost:3001' -function defaultFetchOpts() { - return { - mode: 'cors', - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin' : SERVER, - }, + function defaultFetchOpts() { + return { + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': SERVER, + }, + } } -} -// TODO - Make a fetch call (with error handling!) to each of the following API endpoints + // // TODO - Make a fetch call (with error handling!) to each of the following API endpoints -function getTracks() { - // GET request to `${SERVER}/api/tracks` - fetch(`${SERVER}/api/tracks`) - .then(result => { - if (!result.ok) { - throw new error (`error: ${result.status}`); - } else { - return result.json(); - } - }) + async function getTracks() { + try { + const response = await fetch(`${SERVER}/api/tracks`); + if (!response.ok) { + throw new Error(`Failed to fetch tracks: ${response.status}`); + } + return await response.json(); + } catch (error) { + console.error("Error fetching tracks:", error); + } +} +async function getRacers() { + try { + // GET request to `${SERVER}/api/cars` + const response = await fetch(`${SERVER}/api/cars`); + + if (!response.ok) { + throw new Error(`Failed to fetch racers: ${response.status}`); + } + + const racers = await response.json(); + return racers.map(racer => ({ + id: racer.id, + driver_name: racer.driver_name, + top_speed: racer.top_speed, + acceleration: racer.acceleration, + handling: racer.handling + })); + } catch (error) { + console.error(`Error fetching racers: ${error}`); + } +} - .then(data => { - data.forEach(data => { - const track_id = data.tracks.id - const track_name = data.tracks.name - const track_segments = data.tracks.segments - }) - }) +function renderRacerCard(racer) { + const + { id, driver_name, top_speed, acceleration, handling } + = racer - .catch ( - error => console.error(`there is an error: ${error}`) - ) -} + return ` +
  • +

    ${driver_name}

    +

    Top Speed: ${top_speed}

    +

    Acceleration: ${acceleration}

    +

    Handiling: ${handling}

    +
  • + ` -function getRacers() { - // GET request to `${SERVER}/api/cars` - fetch(`${SERVER}/api/cars`) - .then( - result => { - if (!result.ok) { - console.error(`error: ${result.status}`) - } else { - return result.json() - } - } - ) - .then( - data => { - data.forEach(data => { - const car_id = data.cars.id - const car_driverName = data.cars.driver_name - const car_topSpeed = data.cars.top_speed - const car_acceleration = data.cars.acceleration - const car_handling = data.cars.handling - }) - } - ) - .catch (error => console.error(`there is an error: ${error}`)) - } + function createRace(player_id, track_id) { + player_id = parseInt(player_id) + track_id = parseInt(track_id) + const body = { player_id, track_id } + + return fetch(`${SERVER}/api/races`, { + method: 'POST', + ...defaultFetchOpts(), + dataType: 'jsonp', + body: JSON.stringify(body) + }) + .then(res => res.json()) + .catch(err => console.log("Problem with createRace request::", err)) + } - + async function getRace(id) { + // GET request to `${SERVER}/api/races/${id}` + try { + return await fetch(`${SERVER}/api/races/${id}`) + .then(result => { + if (!result.ok) { + throw new Error(`Error: ${result.status}`); + } + else { + return result.json(); + } + }) + .then(data => { + data.forEach(race => { + race.status = mapRaceStatus(race.status); + }); + console.log(data); + }) + .catch(error => { + console.error('Error fetching race:', error); + }); + } catch { console.error(`error getting race id=${id}:`) }; + } + function mapRaceStatus(status) { + switch (status) { + case "started": + return "Started"; + case "in-progress": + return "In Progress"; + case "finished": + return "Finished"; + default: + return "Unknown"; + } + } -function createRace(player_id, track_id) { - player_id = parseInt(player_id) - track_id = parseInt(track_id) - const body = { player_id, track_id } - - return fetch(`${SERVER}/api/races`, { - method: 'POST', - ...defaultFetchOpts(), - dataType: 'jsonp', - body: JSON.stringify(body) - }) - .then(res => res.json()) - .catch(err => console.log("Problem with createRace request::", err)) -} -function getRace(id) { - // GET request to `${SERVER}/api/races/${id}` - fetch(`${SERVER}/api/races/${id}`) - .then(result => { - if (!result.ok) { - throw new Error(`Error: ${result.status}`); - } - else { - return result.json(); - } - }) - .then(data => { - data.forEach(race => { - race.status = mapRaceStatus(race.status); - }); - console.log(data); + async function startRace(id) { + await fetch(`${SERVER}/api/races/${id}/start`, { + method: 'POST', + ...defaultFetchOpts(), }) - .catch(error => { - console.error('Error fetching race:', error); - }); -} - -function mapRaceStatus(status) { - switch (status) { - case "started": - return "Started"; - case "in-progress": - return "In Progress"; - case "finished": - return "Finished"; - default: - return "Unknown"; + .then(result => result.json()) + .catch(err => console.log("Problem with getRace request:", err)) } -} - + // Add event listener to the accelerate button +document.addEventListener('click', function(event) { + const { target } = event; + // Handle acceleration click + if (target.matches('#gas-peddle')) { + handleAccelerate(); + } +}); -function startRace(id) { - return fetch(`${SERVER}/api/races/${id}/start`, { - method: 'POST', - ...defaultFetchOpts(), - }) - .then(res => res.json()) - .catch(err => console.log("Problem with getRace request::", err)) +async function handleAccelerate() { + try { + console.log(`accelerate button clicked`) + if (!store.race_id) { + console.error("No race is currently ongoing."); + return; + } + await accelerate(store.race_id); + console.log("Acceleration successful"); + } catch (error) { + console.error("Error accelerating race:", error); + } } -function accelerate(id) { - fetch(`${SERVER}/api/races/${id}/accelerate`, {method: 'POST'}) - .then(response => { + +async function accelerate(id) { + await fetch(`${SERVER}/api/races/${id}/accelerate`, { method: 'POST' ,...defaultFetchOpts()}) + .then(response => { if (!response.ok) { throw new Error(`Failed to accelerate: ${response.status}`); } }) .then(() => { - console.log('Acceleration successful'); + console.log('Acceleration successful'); }) .catch(error => { console.error('Error accelerating race:', error); - }); - // options parameter provided as defaultFetchOpts - // no body or datatype needed for this request + }); } From 8d27974a3f6ab6b8a2c25daa725f1b8c18240fe6 Mon Sep 17 00:00:00 2001 From: Ziad <164420754+zoz911@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:27:28 +0200 Subject: [PATCH 4/4] Update index.js --- src/client/assets/javascript/index.js | 870 +++++++++++++------------- 1 file changed, 433 insertions(+), 437 deletions(-) diff --git a/src/client/assets/javascript/index.js b/src/client/assets/javascript/index.js index 1e2ecbc6..c31af211 100644 --- a/src/client/assets/javascript/index.js +++ b/src/client/assets/javascript/index.js @@ -1,525 +1,521 @@ -// // PROVIDED CODE BELOW (LINES 1 - 80) DO NOT REMOVE + // // PROVIDED CODE BELOW (LINES 1 - 80) DO NOT REMOVE -// The store will hold all information needed globally -let store = { - track_id: undefined, - player_id: undefined, - race_id: undefined, -} + // The store will hold all information needed globally + let store = { + track_id: undefined, + player_id: undefined, + race_id: undefined, + } -// We need our javascript to wait until the DOM is loaded -document.addEventListener("DOMContentLoaded", function() { - onPageLoad() - setupClickHandlers() -}) - -async function onPageLoad() { - try { - getTracks() - .then(tracks => { - const html = renderTrackCards(tracks) - renderAt('#tracks', html) - }) + // We need our javascript to wait until the DOM is loaded + document.addEventListener("DOMContentLoaded", function() { + onPageLoad() + setupClickHandlers() + }) - getRacers() - .then((racers) => { - const html = renderRacerCars(racers) - renderAt('#racers', html) - }) - } catch(error) { - console.log("Problem getting tracks and racers ::", error.message) - console.error(error) - } -} -function setupClickHandlers() { - document.addEventListener('click', function(event) { - const { target } = event + async function onPageLoad() { + try { + getTracks() + .then(tracks => { + const html = renderTrackCards(tracks) + renderAt('#tracks', html) + }) - // Race track form field - if (target.matches('.card.track')) { - handleSelectTrack(target) + getRacers() + .then((racers) => { + const html = renderRacerCars(racers) + renderAt('#racers', html) + }) + } catch(error) { + console.log("Problem getting tracks and racers ::", error.message) + console.error(error) } + } - // Podracer form field - if (target.matches('.card.podracer')) { - handleSelectPodRacer(target) - } + function setupClickHandlers() { + document.addEventListener('click', function(event) { + const { target } = event - // Submit create race form - if (target.matches('#submit-create-race')) { - event.preventDefault() - - // start race - handleCreateRace() - } + // Race track form field + if (target.matches('.card.track')) { + handleSelectTrack(target) + } - // Handle acceleration click - if (target.matches('#gas-peddle')) { - handleAccelerate() - } + // Podracer form field + if (target.matches('.card.podracer')) { + handleSelectPodRacer(target) + } - }, false) -} + // Submit create race form + if (target.matches('#submit-create-race')) { + event.preventDefault() + + // start race + handleCreateRace() + } + + // Handle acceleration click + if (target.matches('#gas-peddle')) { + handleAccelerate() + } -async function delay(ms) { - try { - return await new Promise(resolve => setTimeout(resolve, ms)); - } catch(error) { - console.log("an error shouldn't be possible here") - console.log(error) + }, false) } -} -// ^ PROVIDED CODE ^ DO NOT REMOVE -// This async function controls the flow of the race, add the logic and error handling -async function handleCreateRace() { - // render starting UI - renderAt('#race', renderRaceStartView(store.track_id , store.player_id)) + async function delay(ms) { + try { + return await new Promise(resolve => setTimeout(resolve, ms)); + } catch(error) { + console.log("an error shouldn't be possible here") + console.log(error) + } + } + // ^ PROVIDED CODE ^ DO NOT REMOVE + + // This async function controls the flow of the race, add the logic and error handling + async function handleCreateRace() { + // render starting UI + renderAt('#race', renderRaceStartView(store.track_id , store.player_id)) - try { - // Get player_id and track_id from the store - const player_id = store.player_id; - const track_id = store.track_id; + try { + // Get player_id and track_id from the store + const player_id = store.player_id; + const track_id = store.track_id; + const race = await createRace(player_id, track_id); - // Invoke the API call to create the race, then save the result - const race = await createRace(player_id, track_id); + store.race_id = race.ID - 1; - // Update the store with the race id - store.race_id = race.ID - 1; + await runCountdown(); - // The race has been created, now start the countdown - // Call the async function runCountdown - runCountdown(); + await startRace(store.race_id); - // Call the async function startRace - startRace(store.race_id); + await runRace(store.race_id); + return console.log(race.ID) + } catch (error) { + console.error("Error handling race creation:", error); + } + } - // Call the async function runRace - runRace(store.race_id); - return console.log(race.ID) - } catch (error) { - console.error("Error handling race creation:", error); - } -} + function runRace(raceID) { + return new Promise(resolve => { + // TODO - use Javascript's built in setInterval method to get race info every 500ms + const raceInterval = setInterval(async () => { + try { + const response = await fetch(`${SERVER}/api/races/${raceID}`); -function runRace(raceID) { - return new Promise(resolve => { - // TODO - use Javascript's built in setInterval method to get race info every 500ms - const raceInterval = setInterval(async () => { - try { - const response = await fetch(`${SERVER}/api/races/${raceID}`) + if (!response.ok) { + throw new Error(`Failed to get race info: ${response.status}`); + } - if (!response.ok) { - throw new Error(`Failed to get race info: ${response.status}`); - } + const raceInfo = await response.json(); - const raceInfo = await response.json(); + if (raceInfo.status === "in-progress") { + renderAt('#leaderBoard', raceProgress(raceInfo.positions)); + } - if (raceInfo.status === "in-progress") { - renderAt('#leaderBoard', raceProgress(raceInfo.positions)); - } + if (raceInfo.status === "finished") { + clearInterval(raceInterval); + renderAt('#race', resultsView(raceInfo.positions)); - if (raceInfo.status === "finished") { - clearInterval(raceInterval); - renderAt('#race', resultsView(raceInfo.positions)); - resolve(raceInfo); - } - } - catch (err) { - console.error(err) + + resolve(raceInfo); + } } + catch (err) { + console.error(err) + } - }, 500); - }); + }, 500); + }); - /* - TODO - if the race info status property is "in-progress", update the leaderboard by calling: + /* + TODO - if the race info status property is "in-progress", update the leaderboard by calling: - renderAt('#leaderBoard', raceProgress(res.positions)) - */ + renderAt('#leaderBoard', raceProgress(res.positions)) + */ - /* - TODO - if the race info status property is "finished", run the following: + /* + TODO - if the race info status property is "finished", run the following: - clearInterval(raceInterval) // to stop the interval from repeating - renderAt('#race', resultsView(res.positions)) // to render the results view - reslove(res) // resolve the promise - */ - // remember to add error handling for the Promise - // this part is done - // look up ^^ + clearInterval(raceInterval) // to stop the interval from repeating + renderAt('#race', resultsView(res.positions)) // to render the results view + reslove(res) // resolve the promise + */ + // remember to add error handling for the Promise + // this part is done + // look up ^^ + } + + + async function runCountdown() { + try { + // Wait for the DOM to load + await delay(1000); + + let timer = 3; // Initial countdown value + + return new Promise(resolve => { + // TODO - use Javascript's built in setInterval method to count down once per second + const countdownInterval = setInterval(() => { + document.getElementById('big-numbers').innerHTML = --timer; + // run this DOM manipulation to decrement the countdown for the user + + // TODO - if the countdown is done, clear the interval, resolve the promise, and return + if (timer === 0) { + clearInterval(countdownInterval); + return resolve(); + } + }, 1000); // Run the interval every 1000 milliseconds (1 second) + }); + } catch (error) { + console.error(error); + } } -async function runCountdown() { - try { - // Wait for the DOM to load - await delay(1000); - - let timer = 3; // Initial countdown value - - return new Promise(resolve => { - // TODO - use Javascript's built in setInterval method to count down once per second - const countdownInterval = setInterval(() => { - document.getElementById('big-numbers').innerHTML = --timer; - // run this DOM manipulation to decrement the countdown for the user - - // TODO - if the countdown is done, clear the interval, resolve the promise, and return - if (timer === 0) { - clearInterval(countdownInterval); - return resolve(); - } - }, 1000); // Run the interval every 1000 milliseconds (1 second) - }); - } catch (error) { - console.error(error); - } -} + function handleSelectPodRacer(target) { + console.log("selected a pod", target.id) -function handleSelectPodRacer(target) { - console.log("selected a pod", target.id) + // remove class selected from all racer options + const selected = document.querySelector('#racers .selected') + if (selected) { + selected.classList.remove('selected') + } - // remove class selected from all racer options - const selected = document.querySelector('#racers .selected') - if (selected) { - selected.classList.remove('selected') - } + // add class selected to current target + target.classList.add('selected') - // add class selected to current target - target.classList.add('selected') + // TODO - save the selected racer ID to the store + store.player_id = target.id; // Update store.player_id instead of store.race_id + } - // TODO - save the selected racer ID to the store - store.player_id = target.id; // Update store.player_id instead of store.race_id -} + function handleSelectTrack(target_track) { + console.log("selected a track", target_track.id) + + // remove class selected from all track options + const selected = document.querySelector('#tracks .selected') + if (selected) { + selected.classList.remove('selected') + } -function handleSelectTrack(target_track) { - console.log("selected a track", target_track.id) + // add class selected to current target + target_track.classList.add('selected') // <-- Corrected from 'target' to 'target_track' - // remove class selected from all track options - const selected = document.querySelector('#tracks .selected') - if (selected) { - selected.classList.remove('selected') - } + // Save the selected track id to the store + store.track_id = target_track.id; + } - // add class selected to current target - target_track.classList.add('selected') // <-- Corrected from 'target' to 'target_track' + // // HTML VIEWS ------------------------------------------------ + // // Provided code - do not remove - // Save the selected track id to the store - store.track_id = target_track.id; -} + function renderRacerCars(racers) { + if (!racers.length) { + return ` +

    Loading Racers... + ` + } - // // HTML VIEWS ------------------------------------------------ - // // Provided code - do not remove + const results = racers.map(renderRacerCard).join('') - function renderRacerCars(racers) { - if (!racers.length) { return ` -

    Loading Racers... + ` } - const results = racers.map(renderRacerCard).join('') + function renderRacerCard(racer) { + const { id, driver_name, top_speed, acceleration, handling } = racer - return ` - - ` - } + return ` +
  • +

    ${driver_name}

    +

    ${top_speed}

    +

    ${acceleration}

    +

    ${handling}

    +
  • + ` + } - function renderRacerCard(racer) { - const { id, driver_name, top_speed, acceleration, handling } = racer + function renderTrackCards(tracks) { + if (!tracks.length) { + return ` +

    Loading Tracks... + ` + } - return ` -
  • -

    ${driver_name}

    -

    ${top_speed}

    -

    ${acceleration}

    -

    ${handling}

    -
  • - ` - } + const results = tracks.map(renderTrackCard).join('') - function renderTrackCards(tracks) { - if (!tracks.length) { return ` -

    Loading Tracks... + ` } - const results = tracks.map(renderTrackCard).join('') + function renderTrackCard(track) { + const { id, name } = track - return ` - - ` - } + return ` +
  • +

    ${name}

    +
  • + ` + } + + function renderCountdown(count) { + return ` +

    Race Starts In...

    +

    ${count}

    + ` + } - function renderTrackCard(track) { - const { id, name } = track + function renderRaceStartView(track, racers) { + return ` +
    +

    Race: ${track.name}

    +
    +
    +
    + ${renderCountdown(3)} +
    + +
    +

    Directions

    +

    Click the button as fast as you can to make your racer go faster!

    + +
    +
    + + ` + } - return ` -
  • -

    ${name}

    -
  • - ` - } + function resultsView(positions) { + positions.sort((a, b) => (a.final_position > b.final_position) ? 1 : -1) - function renderCountdown(count) { - return ` -

    Race Starts In...

    -

    ${count}

    - ` - } + return ` +
    +

    Race Results

    +
    +
    + ${raceProgress(positions)} + Start a new race +
    + ` + } - function renderRaceStartView(track, racers) { - return ` -
    -

    Race: ${track.name}

    -
    -
    -
    - ${renderCountdown(3)} -
    - -
    -

    Directions

    -

    Click the button as fast as you can to make your racer go faster!

    - -
    -
    - - ` - } + function raceProgress(positions) { + // Check if positions is undefined or empty + if (!positions || positions.length === 0) { + return "

    No race progress available

    "; + } - function resultsView(positions) { - positions.sort((a, b) => (a.final_position > b.final_position) ? 1 : -1) + // Sort positions array based on segment + positions.sort((a, b) => (a.segment > b.segment) ? -1 : 1); - return ` -
    -

    Race Results

    -
    -
    - ${raceProgress(positions)} - Start a new race -
    - ` + // Initialize a counter for leaderboard position + let count = 1; + + // Map each position to HTML content + const results = positions.map(p => { + // Check if the current position object has the 'driver_name' property + if (!p || !p.driver_name) { + return "

    No driver name available

    "; + } + return ` + + +

    ${count++} - ${p.driver_name}

    + + + `; + }); + + // Construct the leaderboard HTML + const leaderboardHTML = ` +
    +

    Leaderboard

    +
    + ${results.join("")} +
    +
    + `; + + return leaderboardHTML; } - function raceProgress(positions) { - // Check if positions is undefined or empty - if (!positions || positions.length === 0) { - return "

    No race progress available

    "; - } - - // Sort positions array based on segment - positions.sort((a, b) => (a.segment > b.segment) ? -1 : 1); - - // Initialize a counter for leaderboard position - let count = 1; - - // Map each position to HTML content - const results = positions.map(p => { - // Check if the current position object has the 'driver_name' property - if (!p || !p.driver_name) { - return "

    No driver name available

    "; - } - return ` - - -

    ${count++} - ${p.driver_name}

    - - - `; - }); - - // Construct the leaderboard HTML - const leaderboardHTML = ` -
    -

    Leaderboard

    -
    - ${results.join("")} -
    -
    - `; - - return leaderboardHTML; -} + function renderAt(element, html) { + const node = document.querySelector(element) - function renderAt(element, html) { - const node = document.querySelector(element) + node.innerHTML = html + } - node.innerHTML = html - } + // // ^ Provided code ^ do not remove - // // ^ Provided code ^ do not remove + // // API CALLS ------------------------------------------------ - // // API CALLS ------------------------------------------------ + const SERVER = 'http://localhost:3001' + + function defaultFetchOpts() { + return { + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': SERVER, + }, + } + } - const SERVER = 'http://localhost:3001' + // // TODO - Make a fetch call (with error handling!) to each of the following API endpoints - function defaultFetchOpts() { - return { - mode: 'cors', - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': SERVER, - }, + async function getTracks() { + try { + const response = await fetch(`${SERVER}/api/tracks`); + if (!response.ok) { + throw new Error(`Failed to fetch tracks: ${response.status}`); + } + return await response.json(); + } catch (error) { + console.error("Error fetching tracks:", error); } } + async function getRacers() { + try { + // GET request to `${SERVER}/api/cars` + const response = await fetch(`${SERVER}/api/cars`); - // // TODO - Make a fetch call (with error handling!) to each of the following API endpoints - - async function getTracks() { - try { - const response = await fetch(`${SERVER}/api/tracks`); - if (!response.ok) { - throw new Error(`Failed to fetch tracks: ${response.status}`); - } - return await response.json(); - } catch (error) { - console.error("Error fetching tracks:", error); - } -} -async function getRacers() { - try { - // GET request to `${SERVER}/api/cars` - const response = await fetch(`${SERVER}/api/cars`); - - if (!response.ok) { - throw new Error(`Failed to fetch racers: ${response.status}`); - } - - const racers = await response.json(); - return racers.map(racer => ({ - id: racer.id, - driver_name: racer.driver_name, - top_speed: racer.top_speed, - acceleration: racer.acceleration, - handling: racer.handling - })); - } catch (error) { - console.error(`Error fetching racers: ${error}`); - } -} - -function renderRacerCard(racer) { - const - { id, driver_name, top_speed, acceleration, handling } - = racer + if (!response.ok) { + throw new Error(`Failed to fetch racers: ${response.status}`); + } - return ` -
  • -

    ${driver_name}

    -

    Top Speed: ${top_speed}

    -

    Acceleration: ${acceleration}

    -

    Handiling: ${handling}

    -
  • - ` + const racers = await response.json(); + return racers.map(racer => ({ + id: racer.id, + driver_name: racer.driver_name, + top_speed: racer.top_speed, + acceleration: racer.acceleration, + handling: racer.handling + })); + } catch (error) { + console.error(`Error fetching racers: ${error}`); + } + } -} + function renderRacerCard(racer) { + const + { id, driver_name, top_speed, acceleration, handling } + = racer + return ` +
  • +

    ${driver_name}

    +

    Top Speed: ${top_speed}

    +

    Acceleration: ${acceleration}

    +

    Handiling: ${handling}

    +
  • + ` - function createRace(player_id, track_id) { - player_id = parseInt(player_id) - track_id = parseInt(track_id) - const body = { player_id, track_id } - - return fetch(`${SERVER}/api/races`, { - method: 'POST', - ...defaultFetchOpts(), - dataType: 'jsonp', - body: JSON.stringify(body) - }) - .then(res => res.json()) - .catch(err => console.log("Problem with createRace request::", err)) } - async function getRace(id) { - // GET request to `${SERVER}/api/races/${id}` - try { - return await fetch(`${SERVER}/api/races/${id}`) - .then(result => { - if (!result.ok) { - throw new Error(`Error: ${result.status}`); - } - else { - return result.json(); - } - }) - .then(data => { - data.forEach(race => { - race.status = mapRaceStatus(race.status); - }); - console.log(data); - }) - .catch(error => { - console.error('Error fetching race:', error); - }); - } catch { console.error(`error getting race id=${id}:`) }; + + function createRace(player_id, track_id) { + player_id = parseInt(player_id) + track_id = parseInt(track_id) + const body = { player_id, track_id } + + return fetch(`${SERVER}/api/races`, { + method: 'POST', + ...defaultFetchOpts(), + dataType: 'jsonp', + body: JSON.stringify(body) + }) + .then(res => res.json()) + .catch(err => console.log("Problem with createRace request::", err)) +} - } +async function getRace(id) { + + try { + // GET request to `${SERVER}/api/races/${id}` + const response = await fetch(`${SERVER}/api/races/${id}`); + + if (!response.ok) { + throw new Error(`Failed to fetch race: ${response.status}`); + } + + const data = await response.json(); + + // Map race status + data.status = mapRaceStatus(data.status); + + + return data; + } catch (error) { + console.error(`Error fetching race id=${id}:`, error); + throw error; // Re-throw the error to handle it at a higher level if necessary + } + } + - function mapRaceStatus(status) { - switch (status) { - case "started": - return "Started"; - case "in-progress": - return "In Progress"; - case "finished": - return "Finished"; - default: - return "Unknown"; + function mapRaceStatus(status) { + switch (status) { + case "started": + return "Started"; + case "in-progress": + return "In Progress"; + case "finished": + return "Finished"; + default: + return "Unknown"; + } } - } - async function startRace(id) { - await fetch(`${SERVER}/api/races/${id}/start`, { - method: 'POST', - ...defaultFetchOpts(), - }) - .then(result => result.json()) - .catch(err => console.log("Problem with getRace request:", err)) + async function startRace(id) { + await fetch(`${SERVER}/api/races/${id}/start`, { + method: 'POST', + ...defaultFetchOpts(), + }) + .then(result => result.json()) + .catch(err => console.log("Problem with getRace request:", err)) + } + // Add event listener to the accelerate button + document.addEventListener('click', function(event) { + const { target } = event; + // Handle acceleration click + if (target.matches('#gas-peddle')) { + handleAccelerate(); + } + }); + + async function handleAccelerate() { + try { + console.log(`accelerate button clicked`) + if (!store.race_id) { + console.error("No race is currently ongoing."); + return; + } + await accelerate(store.race_id); + console.log("Acceleration successful"); + } catch (error) { + console.error("Error accelerating race:", error); + } } - // Add event listener to the accelerate button -document.addEventListener('click', function(event) { - const { target } = event; - // Handle acceleration click - if (target.matches('#gas-peddle')) { - handleAccelerate(); - } -}); - -async function handleAccelerate() { - try { - console.log(`accelerate button clicked`) - if (!store.race_id) { - console.error("No race is currently ongoing."); - return; - } - await accelerate(store.race_id); - console.log("Acceleration successful"); - } catch (error) { - console.error("Error accelerating race:", error); - } -} -async function accelerate(id) { - await fetch(`${SERVER}/api/races/${id}/accelerate`, { method: 'POST' ,...defaultFetchOpts()}) - .then(response => { - if (!response.ok) { - throw new Error(`Failed to accelerate: ${response.status}`); - } - }) - .then(() => { - console.log('Acceleration successful'); - }) - .catch(error => { - console.error('Error accelerating race:', error); - }); -} + async function accelerate(id) { + await fetch(`${SERVER}/api/races/${id}/accelerate`, { method: 'POST' ,...defaultFetchOpts()}) + .then(response => { + if (!response.ok) { + throw new Error(`Failed to accelerate: ${response.status}`); + } + }) + .then(() => { + console.log('Acceleration successful'); + }) + .catch(error => { + console.error('Error accelerating race:', error); + }); + }