Бэкэнд
app.ts
import { mySqlConnect } from "./utils/mySqlConnect"
const NUM_GAMES = 50
const app = express()
app.use(cors())
const db = mysql.createConnection(mySqlConnect)
db.connect(function (err) {
if (err) {
console.error("failed connection:" + err.stack)
return
}
console.log("Connected.")
})
app.get("/api/games", (req, res) => {
const teamId = req.query.team_id
const offset = req.query.offset
let sql = ` SELECT * FROM games
WHERE team = '${teamId}'
ORDER BY date DESC
LIMIT ${NUM_GAMES} OFFSET ${offset}
`
db.query(sql, (err, results) => {
if (err) throw err
const response = results.map((game: { payload: string }) => JSON.parse(game.payload))
res.send(response)
})
})
mySqlConnect.ts
import * as dotenv from "dotenv"
dotenv.config()
const config = {
host: process.env.HOSTNAME,
user: process.env.USERNAME,
password: process.env.PASSWORD,
port: process.envPORT,
database: process.env.DB_NAME,
}
type RemoveUndefinedFields<T> = {
[P in keyof T]: Exclude<T[P], undefined>
}
export const mysqlConnect = config as RemoveUndefinedFields<typeof config>
Внешний интерфейс
App.js
const App = () => {
return (
<div>
<GlobalStyle />
<NavBar />
<Games />
</div>
)
}
Games.tsx
const OFFSET_GAMES = 10
const TEAM_ID = "team_id_here"
const Games = () => {
const [games, setGames] = useState<Game[]>([])
const [numFetches, setNumFetches] = useState(OFFSET_GAMES)
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
setIsLoading(prev => !prev)
fetch(`https://localhost:3402/api/games/?team_id=${TEAM_ID}&offset=${numFetches}`)
.then((res) => res.json())
.then((res) => {
setGames((prevGames) => [...prevGames, ...res])
setIsLoading(prev => !prev)
})
}, [numFetches])
const fetchGames = () => setNumFetches((prev) => prev + OFFSET_GAMES)
const displayGames = () => {
const datesShown: string[] = []
return games.map(game => {
const date = parseDate(game.date)
let showDate = true
if (datesShown.includes(date)) {
showDate = false
} else {
datesShown.push(date)
}
return (
<>
{showDate && <Date date={date}/>}
<Game
id={game.id}
game_type={game.game_type}
date={game.date}
observations={game.observations}
/>
</>
)
})
}
return (
<div>
{games.length ? (
<GamesContainer>
{displayGames()}
<Button
text="Load more games"
onClick={fetchGames}
isLoading={isLoading}
/>
</GamesContainer>
) : null}
{(!games.length || isLoading) && <Loader text={"Loading games..."} />}
</div>
)
}
GameCard.tsx
export type Game = {
id: string
game_type: string
date: string
observations?: string[] | undefined
}
const GameCard: React.FC<Game> = ({
id,
game_type,
date,
observations,
}) => {
const gameMap = new Map(Object.entries(gameDictionary))
return (
<GameCardContainer key={id}>
<h3>{parseDate(date)}</h3>
<h4>{gameMap.get(game_type)}</h4>
{observations?.map((obs) => (
<h5>{obs}</h5>
))}
</GameCardContainer>
)
}
gameDictionary.ts
export const gameDictionary = {
football: "Football match, the derby!",
basketball: "Basketball game. Looking for MJ?",
tennis: "Nadal X Federer? Tennis match!",
}
