Passed
Push — master ( 7aa1e4...a37cc0 )
by Kevin Van
05:30
created

src/pages/game.tsx   B

Complexity

Total Complexity 45
Complexity/F 45

Size

Lines of Code 305
Function Count 1

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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