Passed
Pull Request — develop (#758)
by Kevin Van
08:17 queued 04:36
created

src/pages/game.tsx   B

Complexity

Total Complexity 45
Complexity/F 45

Size

Lines of Code 312
Function Count 1

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 45
eloc 274
mnd 44
bc 44
fnc 1
dl 0
loc 312
rs 8.8
bpm 44
cpm 45
noi 0
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A game.tsx ➔ getData 0 3 1

How to fix   Complexity   

Complexity

Complex classes like src/pages/game.tsx often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import axios from "axios"
2
import ReactFitText from "@kennethormandy/react-fittext"
3
import { useState, useEffect, Fragment } from "react"
4
import { useSiteMetaData } from "../hooks/use-site-metadata"
5
import iconBench from "../images/i_bench_2.png"
6
import iconCardRed from "../images/i_card_red.png"
7
import iconCardYellow from "../images/i_card_yellow.png"
8
import iconCardYellowRed from "../images/i_card_yellow_red.png"
9
import iconGoal from "../images/i_goal.png"
10
import iconStart from "../images/i_start.png"
11
import iconSubIn from "../images/i_sub_in.png"
12
import iconSubOut from "../images/i_sub_out.png"
13
import {
14
  MatchDetails,
15
  MatchDetailsEventItem,
16
  MatchDetailsLineupItem,
17
  MatchDetailsSubstituteItem,
18
  MatchDetailsSubstitutes,
19
} from "../Types/Match"
20
import { GamePageProps } from "../Types/PageProps"
21
import moment from "moment"
22
import "moment-timezone"
23
import "moment/locale/nl-be"
24
import React from "react"
25
import Layout from "../layouts"
26
import { Spinner } from "../components/Spinner"
27
import { Seo } from "../components/Seo"
28
import "./game.scss"
29
import { mapPsdStatus } from "../scripts/helper"
30
import LazyLoad from "react-lazyload"
31
import Icon from "../components/Icon"
32
import { MiniRanking } from "../components/MiniRanking"
33
const GamePage = ({ matchId }: GamePageProps) => {
34
  const { kcvvPsdApi } = useSiteMetaData()
35
  const [data, setData] = useState<MatchDetails>()
36
37
  useEffect(() => {
38
    async function getData() {
39
      const response = await axios.get(`${kcvvPsdApi}/match/${matchId}`)
40
      setData(response.data)
41
    }
42
    getData()
43
  }, [kcvvPsdApi, matchId])
44
45
  moment.tz.setDefault(`Europe/Brussels`)
46
  moment.locale(`nl-be`)
47
  moment.localeData(`nl-be`)
48
49
  if (matchId === null) {
50
    return (
51
      <Layout>
52
        <main className="page__wrapper">Geen match beschikbaar...</main>
53
      </Layout>
54
    )
55
  }
56
57
  if (data) {
58
    const { general, substitutes, lineup, events = [] } = data || {}
59
    const { home: homeLineup = [], away: awayLineup = [] } = lineup || {}
60
    const { home: homeSubs = [], away: awaySubs = [] } = substitutes || {}
61
62
    const matchTime = moment(general.date)
63
    const homeTeamId = general.homeClub?.id
64
65
    const ogImage = {
66
      src: general?.homeClub?.logo,
67
      width: 180,
68
      height: 180,
69
    }
70
71
    return (
72
      <Layout>
73
        <Seo
74
          title={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
75
            general.awayClub?.abbreviation || general?.awayClub?.name
76
          }`}
77
          description={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
78
            general.awayClub?.abbreviation || general?.awayClub?.name
79
          }`}
80
          path={`/game/${general?.id}`}
81
          image={ogImage}
82
        />
83
        <header className="game__header__wrapper full-width">
84
          <div className="game__header__inner">
85
            <div className="game__teams">
86
              <div className={`game__teams-inner`}>
87
                <LazyLoad debounce={false}>
88
                  <img src={general.homeClub?.logo} alt={general.homeClub?.name} title={general.homeClub?.name} />
89
                </LazyLoad>
90
              </div>
91
              {renderScore(general.goalsHomeTeam, general.goalsAwayTeam)}
92
              <div className={`game__teams-inner`}>
93
                <LazyLoad debounce={false}>
94
                  <img src={general.awayClub?.logo} alt={general.awayClub?.name} title={general.awayClub?.name} />
95
                </LazyLoad>
96
              </div>
97
            </div>
98
            <h1>
99
              <ReactFitText compressor={2.5}>{`${general.homeClub?.abbreviation || general.homeClub?.name} - ${
100
                general.awayClub?.abbreviation || general.awayClub?.name
101
              }`}</ReactFitText>
102
            </h1>
103
            <h4>{general.competitionType}</h4>
104
            <time dateTime={matchTime.format(`YYYY-MM-DD - H:mm`)}>{matchTime.format(`dddd DD MMMM YYYY - H:mm`)}</time>
105
            <br />
106
107
            {general.status !== 0 && (
108
              <span className={`game__status game__status--${general.status}`}>{mapPsdStatus(general.status)}</span>
109
            )}
110
111
            <br />
112
          </div>
113
        </header>
114
115
        <main className="page__wrapper">
116
          {(homeLineup.length !== 0 || awayLineup.length !== 0) && (
117
            <div className={`lineup__wrapper`}>
118
              <div className={`lineup__wrapper--home`}>
119
                <h3>{general.homeClub?.abbreviation || general.homeClub?.name}</h3>
120
                {homeLineup && renderLineup(homeLineup, homeSubs)}
121
              </div>
122
              <div className={`lineup__wrapper--away`}>
123
                <h3>{general.awayClub?.abbreviation || general.awayClub?.name}</h3>
124
                {awayLineup && renderLineup(awayLineup, awaySubs)}
125
              </div>
126
            </div>
127
          )}
128
        </main>
129
130
        <section className="page__wrapper">
131
          {events.length !== 0 && (
132
            <div className={`event__wrapper`}>
133
              <h3>Gebeurtenissen</h3>
134
              {events && renderEvents(events, homeTeamId)}
135
            </div>
136
          )}
137
138
          {general.competitionType === `Competitie` && (
139
            <MiniRanking
140
              teamId={general.homeTeamId || general.awayTeamId || 0}
141
              homeTeam={general.homeClub?.name}
142
              awayTeam={general.awayClub?.name}
143
            />
144
          )}
145
        </section>
146
      </Layout>
147
    )
148
  } else {
149
    return (
150
      <Layout>
151
        <Spinner />
152
      </Layout>
153
    )
154
  }
155
}
156
157
const renderScore = (resultHome?: number, resultAway?: number) => {
158
  return resultHome !== null && resultAway !== null ? (
159
    <div className={`game__details__vs game__details__vs--score`}>
160
      {renderScoreWithWinnerIndicator(resultHome || 0, resultAway || 0, `home`)}
161
      <span className={`match-details__divider`}>&nbsp;-&nbsp;</span>
162
      {renderScoreWithWinnerIndicator(resultAway || 0, resultHome || 0, `away`)}
163
    </div>
164
  ) : (
165
    <div className={`game__details__vs`}>VS</div>
166
  )
167
}
168
169
const renderScoreWithWinnerIndicator = (result1: number, result2: number, extraClass?: string) => {
170
  return result1 > result2 ? (
171
    <span className={`game__details__winner game__details__winner--${extraClass}`}>{result1}</span>
172
  ) : (
173
    <span className={`game__details__loser`}>{result1}</span>
174
  )
175
}
176
177
const renderLineup = (lineup: MatchDetailsLineupItem[], substitutes: MatchDetailsSubstituteItem[]) => {
178
  return (
179
    <Fragment>
180
      {renderLineupHeader()}
181
      {lineup.map((element, i) => renderLineupLine(i, element))}
182
      <hr />
183
      {substitutes.map((element, i) => renderSubLine(i, element))}
184
    </Fragment>
185
  )
186
}
187
188
const renderLineupHeader = () => {
189
  return (
190
    <div className={`lineup__header`}>
191
      <span className={`lineup__header__item lineup__item--status`}></span>
192
      <span className={`lineup__header__item lineup__item--number`}>#</span>
193
      <span className={`lineup__header__item lineup__item--name`}>Name</span>
194
      <span className={`lineup__header__item lineup__item--time`}>
195
        <Icon icon="fa-clock-o" />
196
      </span>
197
    </div>
198
  )
199
}
200
201
const renderLineupLine = (i: React.Key, element: MatchDetailsLineupItem) => {
202
  return (
203
    <div className={`lineup__row lineup__row--lineup`} key={i}>
204
      <span
205
        className={`lineup__row__item lineup__item--status`}
206
        style={{
207
          backgroundImage: `url(${element.changed ? iconSubOut : iconStart})`,
208
        }}
209
        title={`${element.changed ? `Basisspeler gewisseld` : `Basisspeler`}`}
210
      ></span>
211
      <span className={`lineup__row__item lineup__item--number`}>{element.number}</span>
212
      <span className={`lineup__row__item lineup__item--name`}>
213
        {element.playerName} {element.captain && `(C)`}
214
      </span>
215
      <span className={`lineup__row__item lineup__item--time`}>{element.minutesPlayed}'</span>
216
    </div>
217
  )
218
}
219
220
const renderSubLine = (i: React.Key, element: MatchDetailsSubstituteItem) => {
221
  return (
222
    <div className={`lineup__row lineup__row--substitute`} key={i}>
223
      <span
224
        className={`lineup__row__item lineup__item--status`}
225
        style={{
226
          backgroundImage: `url(${element.changed ? iconSubIn : iconBench})`,
227
        }}
228
        title={`${element.changed ? `Wisselspeler ingevallen` : `Wisselspeler`}`}
229
      ></span>
230
      <span className={`lineup__row__item lineup__item--number`}>{element.number}</span>
231
      <span className={`lineup__row__item lineup__item--name`}>{element.playerName}</span>
232
      <span className={`lineup__row__item lineup__item--time`}>{element.minutesPlayed}'</span>
233
    </div>
234
  )
235
}
236
237
const renderEvents = (events: MatchDetailsEventItem[], homeTeamId: number) => {
238
  return <Fragment>{events.map((element, i) => renderEventLine(i, element, homeTeamId))}</Fragment>
239
}
240
241
const renderEventLine = (i: React.Key, element: MatchDetailsEventItem, homeTeamId: number) => {
242
  const homeTeam = element.clubId == homeTeamId
243
  let actionIcon = null
244
  let actionMessage = ``
245
  let actionText = ``
246
247
  switch (element.action) {
248
    case `geel`:
249
      actionIcon = iconCardYellow
250
      actionText = `Gele kaart voor`
251
      actionMessage = `Gele kaart`
252
      break
253
    case `rood`:
254
      actionIcon = iconCardRed
255
      actionText = `Rode kaart voor`
256
      actionMessage = `Rode kaart`
257
      break
258
    case `tweedegeel`:
259
      actionIcon = iconCardYellowRed
260
      actionText = `Tweede gele kaart voor`
261
      actionMessage = `Tweede gele kaart`
262
      break
263
    case `doelpunt`:
264
      actionIcon = iconGoal
265
      actionText = `${element?.goalsHome} - ${element?.goalsAway} — Doelpunt gescoord door`
266
      actionMessage = `Doelpunt`
267
      break
268
    case `minuteOut`:
269
      actionIcon = iconSubOut
270
      actionText = `Speler uit:`
271
      actionMessage = `Wissel`
272
      break
273
    case `minuteIn`:
274
      actionIcon = iconSubIn
275
      actionText = `Speler in:`
276
      actionMessage = `Wissel`
277
      break
278
  }
279
280
  return (
281
    <div className={`event__row ${homeTeam ? `event__row--home` : `event__row--away`}`} key={i}>
282
      {homeTeam && (
283
        <span className={`event__row__item event__row__item--home lineup__item--name`}>
284
          {actionText} {element.playerName}
285
        </span>
286
      )}
287
      {homeTeam && (
288
        <span
289
          className={`event__row__item event__row__item--home lineup__item--action center`}
290
          style={{ backgroundImage: `url(${actionIcon})` }}
291
          title={actionMessage}
292
        ></span>
293
      )}
294
      <span className={`event__row__item lineup__item--time center`}>{element.minute}'</span>
295
      {homeTeam || (
296
        <span
297
          className={`event__row__item event__row__item--away lineup__item--action center`}
298
          style={{ backgroundImage: `url(${actionIcon})` }}
299
          title={actionMessage}
300
        ></span>
301
      )}
302
      {homeTeam || (
303
        <span className={`event__row__item event__row__item--away lineup__item--name`}>
304
          {actionText} {element.playerName}
305
        </span>
306
      )}
307
    </div>
308
  )
309
}
310
311
export default GamePage
312