Merging completed Ch. 11 #2

Merged
JMR-dev merged 7 commits from testbranch1 into master 2022-02-18 15:15:18 +00:00
10 changed files with 519 additions and 9 deletions
+2
View File
@@ -21,3 +21,5 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
projectnotes.md*
+16
View File
@@ -2,6 +2,10 @@ import React from "react"
import { Route } from "react-router-dom" import { Route } from "react-router-dom"
import { EventList } from "./game/EventList.js" import { EventList } from "./game/EventList.js"
import { GameList } from "./game/GameList.js" import { GameList } from "./game/GameList.js"
import { GameForm } from "./game/GameForm.js"
import { EventForm } from "./game/EventForm.js"
import { UpdateEvent } from "./game/UpdateEvent.js"
import { UpdateGame} from "./game/UpdateGame.js"
export const ApplicationViews = () => { export const ApplicationViews = () => {
return <> return <>
<main style={{ <main style={{
@@ -13,6 +17,18 @@ export const ApplicationViews = () => {
</Route> </Route>
<Route exact path="/"> <Route exact path="/">
<EventList /> <EventList />
</Route>
<Route exact path = "/games/new" >
<GameForm />
</Route>
<Route exact path = "/events/new" >
<EventForm />
</Route>
<Route exact path= "/events/update/:id(\d+)">
<UpdateEvent />
</Route>
<Route exact path= "/games/update/:id(\d+)">
<UpdateGame />
</Route> </Route>
</main> </main>
</> </>
+66
View File
@@ -0,0 +1,66 @@
import React, { useState, useEffect } from "react"
import { useHistory } from 'react-router-dom'
export const EventForm = () => {
const history = useHistory()
const [eventTypes, setEventTypes] = useState([])
/*
Since the input fields are bound to the values of
the properties of this state variable, you need to
provide some default values.
*/
const [currentEvent, setCurrentEvent] = useState({
skillLevel: 1,
Description: "",
date: "",
time: "",
game_id: 1,
organizer_id: 1
})
useEffect(() => {
// TODO: Get the event types, then set the state
}, [])
const changeEventState = (domEvent) => {
// TODO: Complete the onChange function
}
return (
<form className="eventForm">
<h2 className="eventForm__title">Register New Event</h2>
<fieldset>
<div className="form-group">
<label htmlFor="title">Title: </label>
<input type="text" name="title" required autoFocus className="form-control"
value={currentEvent.title}
onChange={changeEventState}
/>
</div>
</fieldset>
{/* TODO: create the rest of the input fields */}
<button type="submit"
onClick={evt => {
// Prevent form from being submitted
evt.preventDefault()
const event = {
maker: currentEvent.maker,
title: currentEvent.title,
numberOfPlayers: parseInt(currentEvent.numberOfPlayers),
skillLevel: parseInt(currentEvent.skillLevel),
eventTypeId: parseInt(currentEvent.eventTypeId)
}
// Send POST request to your API
createEvent(event)
.then(() => history.push("/events"))
}}
className="btn btn-primary">Create</button>
</form>
)
}
+36 -8
View File
@@ -1,23 +1,51 @@
import React, { useEffect, useState } from "react" import React, { useEffect, useState, } from "react"
import { getEvents } from "./EventManager.js" import { getEvents, } from "./EventManager.js"
import { UpdateEvent } from "./UpdateEvent.js"
import { useHistory } from "react-router-dom/cjs/react-router-dom.min"
export const EventList = (props) => { export const EventList = (props) => {
const [ events, setEvents ] = useState([]) const [ events, setEvents ] = useState([])
const history = useHistory()
useEffect(() => { useEffect(() => {
getEvents().then(data => setEvents(data)) getEvents().then(data => setEvents(data))
}, []) }, [])
return ( return (
<article className="events">
<article className="events">
<button
className="btn btn-2 btn-sep icon-create"
onClick={
() => {
history.push(
{ pathname: "/events/new" }
)
}
}
>Register New Event
</button>
{ {
events.map(event => { events.map(
return <section key={`event--${event.id}`} className="event"> event => {
return(
<>
<section key={`event--${event.id}`} className="event">
<button onClick={()=> history.push(`./events/update/${event.id}`) }>Update Event</button>
<div className="event__description">{event.description}</div> <div className="event__description">{event.description}</div>
<div className="event__date">The event is happening on {event.date} at {event.time}.</div> <div className="event__date">The event is happening on {event.date} at {event.time}.</div>
</section> </section>
}) </>
} )
}
)
}
</article> </article>
) )
} }
+37
View File
@@ -5,4 +5,41 @@ export const getEvents = () => {
} }
}) })
.then(response => response.json()) .then(response => response.json())
}
export const getEventById = (id) => {
return fetch(`http://localhost:8000/events/${id}`, {
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`
}
})
.then(response => response.json())
}
export const putEvents = (editedEvent) => {
return fetch(`http://localhost:8000/events/${editedEvent.id}`, {
method: "PUT",
body: JSON.stringify(
editedEvent
),
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`,
"Content-Type": "Application/json"
}
}
)
.then(response => {response => {
return response.json()
}
}
)
}
export const createEvent = (event) => {
return fetch("http://localhost:8000/events", {
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`
}
})
.then(response => response.json())
} }
+66
View File
@@ -0,0 +1,66 @@
import React, { useState, useEffect } from "react"
import { useHistory } from 'react-router-dom'
import { createGame, getGameTypes } from './GameManager.js'
export const GameForm = () => {
const history = useHistory()
const [gameTypes, setGameTypes] = useState([])
/*
Since the input fields are bound to the values of
the properties of this state variable, you need to
provide some default values.
*/
const [currentGame, setCurrentGame] = useState({
skillLevel: 1,
numberOfPlayers: 0,
title: "",
maker: "",
gameTypeId: 0
})
useEffect(() => {
// TODO: Get the game types, then set the state
}, [])
const changeGameState = (domEvent) => {
// TODO: Complete the onChange function
}
return (
<form className="gameForm">
<h2 className="gameForm__title">Register New Game</h2>
<fieldset>
<div className="form-group">
<label htmlFor="title">Title: </label>
<input type="text" name="title" required autoFocus className="form-control"
value={currentGame.title}
onChange={changeGameState}
/>
</div>
</fieldset>
{/* TODO: create the rest of the input fields */}
<button type="submit"
onClick={evt => {
// Prevent form from being submitted
evt.preventDefault()
const game = {
maker: currentGame.maker,
title: currentGame.title,
numberOfPlayers: parseInt(currentGame.numberOfPlayers),
skillLevel: parseInt(currentGame.skillLevel),
gameTypeId: parseInt(currentGame.gameTypeId)
}
// Send POST request to your API
createGame(game)
.then(() => history.push("/games"))
}}
className="btn btn-primary">Create</button>
</form>
)
}
+20 -1
View File
@@ -1,18 +1,36 @@
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react"
import { getGames } from "./GameManager.js" import { getGames } from "./GameManager.js"
import {useHistory } from "react-router-dom"
import { UpdateEvent } from "./UpdateEvent.js"
export const GameList = (props) => { export const GameList = (props) => {
const [ games, setGames ] = useState([]) const [ games, setGames ] = useState([])
const history = useHistory()
useEffect(() => { useEffect(() => {
getGames().then(data => setGames(data)) getGames().then(data => setGames(data))
}, []) },
[]
)
return ( return (
<>
<article className="games"> <article className="games">
<button className="btn btn-2 btn-sep icon-create"
onClick={
() => {
history.push(
{ pathname: "/games/new" }
)
}
}
>Register New Game</button>
{ {
games.map(game => { games.map(game => {
return <section key={`game--${game.id}`} className="game"> return <section key={`game--${game.id}`} className="game">
<button onClick={()=> history.push(`./games/update/${game.id}`) }>Update Game</button>
<div className="game__title">{game.title} by {game.maker}</div> <div className="game__title">{game.title} by {game.maker}</div>
<div className="game__players">{game.number_of_players} players needed</div> <div className="game__players">{game.number_of_players} players needed</div>
<div className="game__skillLevel">Skill level is {game.skill_level}</div> <div className="game__skillLevel">Skill level is {game.skill_level}</div>
@@ -20,5 +38,6 @@ export const GameList = (props) => {
}) })
} }
</article> </article>
</>
) )
} }
+41
View File
@@ -5,4 +5,45 @@ export const getGames = () => {
} }
}) })
.then(response => response.json()) .then(response => response.json())
}
export const getGameById = (id) => {
return fetch(`http://localhost:8000/games/${id}`, {
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`
}
})
.then(response => response.json())
}
export const createGame = (game) => {
return fetch("http://localhost:8000/games", {
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`
}
})
.then(response => response.json())
}
export const getGameTypes = () => {
return fetch("http://localhost:8000/gametypes", {
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`
}
})
.then(response => response.json())
}
export const putGames = (editedGame) => {
return fetch(`http://localhost:8000/games/${editedGame.id}`, {
method: "PUT",
body: JSON.stringify(
editedGame
),
headers:{
"Authorization": `Token ${localStorage.getItem("lu_token")}`,
"Content-Type": "Application/json"
}
}
)
} }
+117
View File
@@ -0,0 +1,117 @@
import react, { useState, useEffect, } from "react";
import { useParams, useHistory } from "react-router-dom/cjs/react-router-dom.min";
import { getGames } from "./GameManager";
import { putEvents } from "./EventManager";
import { getEvents, getEventById } from "./EventManager";
// getGames is imported to allow the select to display a list of games
export const UpdateEvent = (props) => {
const [ gameList, setGameList] = useState([])
const [ eventList, setEventList] = useState([])
const [ eventToEdit, setEventToEdit ] = useState({})
let { id } = useParams()
const history = useHistory()
useEffect(() => {
getGames().then(data => setGameList(data))
getEvents().then(data => setEventList(data))
getEventById(id).then(data =>
{
setEventToEdit(data)
}
)
},
[]
)
// Still need to write out this form and figure out controlled/uncontrolled input for it. Event pk value needs to be passed to the form as props if I'm understanding this correctly
const eventupdateform = () => {
return(
<>
<h2>Update Event</h2>
<form id="editeventform">
<label for="description">Event Description</label>
<input type="text" id="description" value={eventToEdit.description} onChange=
{
(e)=>
{
const copy = {...eventToEdit}
copy.description = e.target.value
setEventToEdit(copy)
}
}
>
</input>
<label for="games">Select Game</label>
<select name="games" form_id="editeventform"
/* Set game via parsing the gameId as the indicator to select the correct game for the event*/
onChange={(e)=>
{
const copy = {...eventToEdit}
copy.game_id = e.target.value
setEventToEdit(copy)}
}>
<option value={""} selected disabled>Change Game from {eventToEdit.game?.title}</option>
{ gameList.map(
(gameList) => <option value={gameList.id}>{gameList.title}</option>
)
}
</select>
<label for="date">Updated Event Date</label>
<input type="date" id="eventdate" value={eventToEdit.date}
onChange={
(e)=>
{
const copy = {...eventToEdit}
copy.date = e.target.value
setEventToEdit(copy)
}
}
>
</input>
<label for="time">Updated Event Time</label>
<input type="time" id="time" value={eventToEdit.time} onChange={(e)=>
{
const copy = {...eventToEdit}
copy.time = e.target.value
setEventToEdit(copy)}
}
>
</input>
<input type="submit"
onClick={
(e)=>
{
e.preventDefault()
putEvents(eventToEdit)
history.push("/")
}
}
>
</input>
</form>
</>
)
}
return(
eventupdateform()
)
}
+118
View File
@@ -0,0 +1,118 @@
import react, { useState, useEffect, } from "react";
import { useParams, useHistory } from "react-router-dom/cjs/react-router-dom.min";
import { getGames, getGameById, getGameTypes, putGames } from "./GameManager";
// getGames is imported to allow the select to display a list of games
export const UpdateGame = (props) => {
const [ gameList, setGameList] = useState([])
const [ gameToEdit, setGameToEdit ] = useState({})
const [gametypes, setGameTypes ] = useState([])
let { id } = useParams()
const history = useHistory()
useEffect(() => {
getGames().then(data => setGameList(data))
getGameTypes().then(data=> setGameTypes(data))
getGameById(id).then(data =>
{
data.game_type = data.game_type.id
setGameToEdit(data)
}
)
},
[]
)
const gameupdateform = () => {
return(
<>
<h2>Update Game</h2>
<form id="editgameform">
<label for="title">Game Title</label>
<input type="textearea" id="title" value={gameToEdit.title} onChange=
{
(e)=>
{
const copy = {...gameToEdit}
copy.title = e.target.value
setGameToEdit(copy)
}
}
/>
<label for="maker">Maker</label>
<input type="text" id="maker" value={gameToEdit.maker} onChange= {
(e)=>
{
const copy = {...gameToEdit}
copy.maker = e.target.value
setGameToEdit(copy)
}
} />
<label for="numberofplayers">Update number of players allowed</label>
<input type="number" id="numberofplayers" value={gameToEdit.number_of_players}
onChange={(e)=>
{
const copy = {...gameToEdit}
copy.number_of_players = e.target.value
setGameToEdit(copy)}
}
/>
<label for="skillevel">Update required skill level</label>
<input type="number" id="skilllevel" value={gameToEdit.skill_level}
onChange={(e)=>
{
const copy = {...gameToEdit}
copy.skill_level = e.target.value
setGameToEdit(copy)}
}
/>
<label for="gametype">Select Game</label>
<select name="gametype" form_id="editgameform"
/* Why is the nested information on game_type_id not returning from the API? What server side problem is causing this to be inaccessible?*/
onChange={(e)=>
{
const copy = {...gameToEdit}
copy.game_type = e.target.value
setGameToEdit(copy)}
}>
{ gametypes.map(
(gametypes) => <option value={gametypes.id} selected={gameToEdit.game_type === gametypes.id}>{gametypes.label}</option>
)
}
</select>
<input type="submit"
onClick={
(e)=>
{
e.preventDefault()
putGames(gameToEdit)
history.push("/")
}
}
/>
</form>
</>
)
}
return(
gameupdateform()
)
}