Приложение TypeScript, React и Node для получения данных об играх из базы данных и отображения их во внешнем интерфейсе

Бэкэнд

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!",
}

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *