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

src/templates/Player.tsx   B

Complexity

Total Complexity 48
Complexity/F 48

Size

Lines of Code 403
Function Count 1

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 48
eloc 319
mnd 47
bc 47
fnc 1
dl 0
loc 403
bpm 47
cpm 48
noi 0
c 0
b 0
f 0
rs 8.5599

1 Function

Rating   Name   Duplication   Size   Complexity  
F Player.tsx ➔ getData 0 4 15

How to fix   Complexity   

Complexity

Complex classes like src/templates/Player.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 { graphql, Link } from "gatsby"
3
import { GatsbyImage, getSrc, StaticImage } from "gatsby-plugin-image"
4
import React, { useEffect, useState } from "react"
5
import { Card } from "../components/Card"
6
import Icon from "../components/Icon"
7
import { Seo } from "../components/Seo"
8
import { useSiteMetaData } from "../hooks/use-site-metadata"
9
import Layout from "../layouts"
10
import moment from "moment"
11
import "moment-timezone"
12
import "moment/locale/nl-be"
13
import { mapPositionCode } from "../scripts/helper"
14
import {
15
  PlayerQuery,
16
  PlayerStatsDataObject,
17
  PlayerStatsDataResponseObject,
18
  PlayerStatsReportsResponseObject,
19
} from "../Types/Player"
20
import "./Player.scss"
21
import iconCardRed from "../images/i_card_red.png"
22
import iconCardYellow from "../images/i_card_yellow.png"
23
import iconCleansheet from "../images/i_cleansheet.png"
24
import iconGoal from "../images/i_goal.png"
25
import RelatedNews from "../components/RelatedNews"
26
27
const Player = ({ data: { nodePlayer } }: PlayerQuery) => {
28
  const cleanBody =
29
    (nodePlayer?.body &&
30
      nodePlayer?.body?.processed?.replaceAll(`/sites/default/`, `${process.env.GATSBY_API_DOMAIN}/sites/default/`)) ||
31
    ``
32
  const picture = nodePlayer?.relationships?.field_image?.localFile?.childImageSharp?.gatsbyImageData && (
33
    <GatsbyImage
34
      image={nodePlayer?.relationships?.field_image?.localFile?.childImageSharp?.gatsbyImageData}
35
      alt={`${nodePlayer.field_firstname} ${nodePlayer.field_lastname}`}
36
    />
37
  )
38
39
  const [data, setData] = useState<PlayerStatsDataObject>()
40
  const [loading, setLoading] = useState<boolean>(true)
41
  const { kcvvPsdApi } = useSiteMetaData()
42
  const playerId = nodePlayer.field_vv_id
43
44
  useEffect(() => {
45
    async function getData() {
46
      const response = await axios.get(`${kcvvPsdApi}/stats/player/${playerId}`)
47
      setData(response.data)
48
      setLoading(false)
49
    }
50
    getData()
51
  }, [kcvvPsdApi, playerId])
52
53
  const team = nodePlayer.relationships?.node__team || []
54
  const articles = nodePlayer.relationships?.node__article || []
55
56
  return (
57
    <Layout>
58
      <div className="player__details__top">
59
        <header className="page_header__wrapper player__header__wrapper">
60
          <div className="page_header page_header--max player__header">
61
            <div className="player__header__inner">
62
              <div className="player__header__inner_text">
63
                <h1 className={`player__detail__name`}>
64
                  <span className={`player__detail__name_first`}>{nodePlayer.field_firstname}</span>
65
                  <span className={`player__detail__name_last`}>{nodePlayer.field_lastname}</span>
66
                </h1>
67
                <p className={`player__detail__shirt_number`} aria-hidden="true">
68
                  {nodePlayer?.field_shirtnumber || ``}
69
                </p>
70
              </div>
71
              <div className="player__header__inner_image">
72
                {picture || (
73
                  <StaticImage
74
                    src={`../images/kcvv-player-bg.png`}
75
                    alt={`${nodePlayer.field_firstname} ${nodePlayer.field_lastname}`}
76
                    placeholder={`tracedSVG`}
77
                  />
78
                )}
79
              </div>
80
            </div>
81
          </div>
82
        </header>
83
        {!loading && renderStats(data?.playerStatistics || [], nodePlayer.field_position || ``)}
84
      </div>
85
      <main className="player__details__middle">
86
        {renderMeta(nodePlayer)}
87
        {cleanBody && <div dangerouslySetInnerHTML={{ __html: cleanBody }} className="player__details__intro" />}
88
      </main>
89
90
      <footer className="player__details__bottom">
91
        {renderPlayerStatsFull(data?.playerStatistics || [])}
92
        {renderPlayerGamesFull(data?.gameReports || [])}
93
      </footer>
94
95
      {(team || articles) && (
96
        <aside className="player__details__related_news page__wrapper">
97
          <RelatedNews items={[...team, ...articles]} limit={6} />
98
        </aside>
99
      )}
100
101
      {/* <PlayerDetail player={nodePlayer} /> */}
102
    </Layout>
103
  )
104
}
105
106
export const Head = ({ data: { nodePlayer } }: PlayerQuery) => {
107
  const pathUrl = nodePlayer?.path?.alias || ``
108
  const heroImage = nodePlayer?.relationships?.field_image?.localFile?.childImageSharp?.gatsbyImageData
109
110
  const ogImage = heroImage && {
111
    src: getSrc(heroImage) || ``,
112
    width: heroImage.width,
113
    height: heroImage.height,
114
  }
115
  return (
116
    <Seo
117
      title={nodePlayer?.title || ``}
118
      path={pathUrl}
119
      image={ogImage}
120
      description={nodePlayer?.title + ` - (ex-)speler van KCVV Elewijt`}
121
    />
122
  )
123
}
124
125
export default Player
126
127
const renderStats = (playerStatistics: PlayerStatsDataResponseObject[], playerPosition = ``) => (
128
  <aside className="player__stats">
129
    <section className="player__stats__item">
130
      <div className="player__stats__item__number">
131
        {playerStatistics.reduce((a, b) => a + (b?.gamesPlayed || 0), 0) || `0`}
132
      </div>
133
      <div className="player__stats__item__label">Wedstrijden</div>
134
    </section>
135
    {(playerPosition === `k` || playerPosition === `d`) && (
136
      <section className="player__stats__item">
137
        <div className="player__stats__item__number">
138
          {playerStatistics.reduce((a, b) => a + (b?.cleanSheets || 0), 0) || `0`}
139
        </div>
140
        <div className="player__stats__item__label">Cleansheets</div>
141
      </section>
142
    )}
143
    <section className="player__stats__item">
144
      <div className="player__stats__item__number">
145
        {playerStatistics.reduce((a, b) => a + (b?.goals || 0), 0) || `0`}
146
      </div>
147
      <div className="player__stats__item__label">Doelpunten</div>
148
    </section>
149
    <section className="player__stats__item">
150
      <div className="player__stats__item__number">
151
        {playerStatistics.reduce((a, b) => a + (b?.yellowCards || 0), 0) || `0`}
152
      </div>
153
      <div className="player__stats__item__label">Gele kaarten</div>
154
    </section>
155
    <section className="player__stats__item">
156
      <div className="player__stats__item__number">
157
        {playerStatistics.reduce((a, b) => a + (b?.redCards || 0), 0) || `0`}
158
      </div>
159
      <div className="player__stats__item__label">Rode kaarten</div>
160
    </section>
161
  </aside>
162
)
163
164
const renderMeta = (nodePlayer: Queries.node__player) => {
165
  const currentlyPlaying = !nodePlayer.field_date_leave
166
  return (
167
    <div className="player__details__meta">
168
      <div className="player__details__meta__item player__details__meta__item--birthdate">
169
        <span className="player__details__meta__item__label">Geboortedatum</span>
170
        <span className="player__details__meta__item__data">{nodePlayer.field_birth_date || `Onbekend`}</span>
171
      </div>
172
      <div className="player__details__meta__item player__details__meta__item--position">
173
        <span className="player__details__meta__item__data">{mapPositionCode(nodePlayer.field_position || ``)}</span>
174
        <span className="player__details__meta__item__label">
175
          {nodePlayer?.relationships?.node__team && (
176
            <Link to={nodePlayer?.relationships?.node__team[0]?.path?.alias || ``}>
177
              {nodePlayer?.relationships?.node__team[0]?.title}
178
            </Link>
179
          )}
180
        </span>
181
      </div>
182
      <div className="player__details__meta__item player__details__meta__item--joindate">
183
        <span className="player__details__meta__item__label">
184
          {currentlyPlaying && `Speler bij KCVV sinds`}
185
          {!currentlyPlaying && `Speler tussen`}
186
        </span>
187
        <span className="player__details__meta__item__data">
188
          {nodePlayer.field_join_date || `Onbekend`}
189
          {!currentlyPlaying && (
190
            <>
191
              <span className={`text--regular`}> en </span> {nodePlayer.field_date_leave}
192
            </>
193
          )}
194
        </span>
195
      </div>
196
    </div>
197
  )
198
}
199
200
const renderPlayerStatsFull = (playerStatistics: PlayerStatsDataResponseObject[]) => {
201
  return (
202
    <Card title="Statistieken" className={`player__stats__stats`} hasTable={true}>
203
      <table className={`player__stats__stats__table`}>
204
        <thead>
205
          <tr>
206
            <th className={`table__column__string`}>Team</th>
207
            <th className={`table__column__number show-for-medium`}>
208
              <span title="Wedstrijden gespeeld">P</span>
209
            </th>
210
            <th className={`table__column__number`}>
211
              <span title="Wedstrijden gewonnen">W</span>
212
            </th>
213
            <th className={`table__column__number`}>
214
              <span title="Wedstrijden gelijkgespeeld">D</span>
215
            </th>
216
            <th className={`table__column__number`}>
217
              <span title="Wedstrijden verloren">L</span>
218
            </th>
219
            <th className={`table__column__number`}>
220
              <img src={iconCardYellow} title="Gele kaart" alt="Gele kaart" className="table__header__icon" />
221
            </th>
222
            <th className={`table__column__number`}>
223
              <img src={iconCardRed} title="Rode kaart" alt="Rode kaart" className="table__header__icon" />
224
            </th>
225
            <th className={`table__column__number`}>
226
              <img
227
                src={iconGoal}
228
                title="Doelpunt(en) gescoord"
229
                alt="Doelpunt(en) gescoord"
230
                className="table__header__icon"
231
              />
232
            </th>
233
            <th className={`table__column__number  show-for-medium`}>
234
              <img src={iconCleansheet} title="Cleansheets" alt="Cleansheets" className="table__header__icon" />
235
            </th>
236
            <th className={`table__column__number`}>
237
              <span title="Minuten gespeeld">
238
                <Icon icon="fa-clock-o" />
239
              </span>
240
            </th>
241
          </tr>
242
        </thead>
243
        <tbody>
244
          {playerStatistics.map(function (stats) {
245
            return (
246
              <tr>
247
                <td className={`table__column__string`}>{stats?.team?.replace(`Voetbal : `, ``)}</td>
248
                <td className={`table__column__number show-for-medium`}>{stats.gamesPlayed}</td>
249
                <td className={`table__column__number`}>{stats.gamesWon}</td>
250
                <td className={`table__column__number`}>{stats.gamesEqual}</td>
251
                <td className={`table__column__number`}>{stats.gamesLost}</td>
252
                <td className={`table__column__number`}>{stats.yellowCards}</td>
253
                <td className={`table__column__number`}>{stats.redCards}</td>
254
                <td className={`table__column__number`}>{stats.goals}</td>
255
                <td className={`table__column__number show-for-medium`}>{stats.cleanSheets}</td>
256
                <td className={`table__column__number`}>{stats.minutes}'</td>
257
              </tr>
258
            )
259
          })}
260
        </tbody>
261
      </table>
262
    </Card>
263
  )
264
}
265
266
const renderPlayerGamesFull = (gameReports: PlayerStatsReportsResponseObject[]) => {
267
  return (
268
    <Card className={`player__stats__games`} title="Wedstrijden" hasTable={true}>
269
      <table className={`player__stats__games__table responsive-card-table`}>
270
        <thead>
271
          <tr>
272
            <th className={`table__column__string`}>Team</th>
273
            <th className={`table__column__string`}>Type</th>
274
            <th className={`table__column__string`}>Datum</th>
275
            <th className={`table__column__number`}>
276
              <span title="Thuis/uit">H/A</span>
277
            </th>
278
            <th className={`table__column__string table__column__score`}>Score</th>
279
            <th className={`table__column__string`}>Tegenstander</th>
280
            <th className={`table__column__number`}>
281
              <img src={iconCardYellow} title="Gele kaart" alt="Gele kaart" className="table__header__icon" />
282
            </th>
283
            <th className={`table__column__number`}>
284
              <img src={iconCardRed} title="Rode kaart" alt="Rode kaart" className="table__header__icon" />
285
            </th>
286
            <th className={`table__column__number`}>
287
              <img src={iconGoal} title="Doelpunten gescoord" alt="Rode kaart" className="table__header__icon" />
288
            </th>
289
            <th className={`table__column__number`}>
290
              <span title="Minuten gespeeld">
291
                <Icon icon="fa-clock-o" />
292
              </span>
293
            </th>
294
          </tr>
295
        </thead>
296
        <tbody>
297
          {gameReports.map(function (game) {
298
            return (
299
              <tr>
300
                <td data-label="Team" className={`table__column__string`}>
301
                  {game.team?.replace(`Voetbal : `, ``)}
302
                </td>
303
                <td data-label="Type" className={`table__column__string`}>
304
                  {game.competition}
305
                </td>
306
                <td data-label="Datum" className={`table__column__string`}>
307
                  {moment(game.date).format(`DD/MM/YYYY`)}
308
                </td>
309
                <td data-label="Thuis/uit" className={`table__column__number`}>
310
                  {game.home ? (
311
                    <span className={`player__stats__games__home`} title="Thuiswedstrijd">
312
                      <Icon icon="fa-home" alt="Thuiswedstrijd" />
313
                    </span>
314
                  ) : (
315
                    <span className={`player__stats__games__away`} title="Uitwedstrijd">
316
                      <Icon icon="fa-bus" alt="Uitwedstrijd" />
317
                    </span>
318
                  )}
319
                </td>
320
                <td data-label="Score" className={`table__column__string table__column__score`}>
321
                  {game.goalsHomeTeam}&nbsp;-&nbsp;{game.goalsAwayTeam}
322
                </td>
323
                <td data-label="Tegenstander" className={`table__column__string`}>
324
                  {game.opponent}
325
                </td>
326
                <td data-label="Gele kaart(en)" className={`table__column__number`}>
327
                  {game.yellowCards}
328
                </td>
329
                <td data-label="Rode kaart(en)" className={`table__column__number`}>
330
                  {game.redCards}
331
                </td>
332
                <td data-label="Doelpunten" className={`table__column__number`}>
333
                  {game.goals}
334
                </td>
335
                <td data-label="Speeltijd" className={`table__column__number`}>
336
                  {game.minutesPlayed}'
337
                </td>
338
              </tr>
339
            )
340
          })}
341
        </tbody>
342
      </table>
343
    </Card>
344
  )
345
}
346
347
export const query = graphql`
348
  query PlayerQuery($slug: String!) {
349
    nodePlayer(path: { alias: { eq: $slug } }) {
350
      path {
351
        alias
352
      }
353
      body {
354
        processed
355
      }
356
      title
357
      field_join_date
358
      field_date_leave
359
      field_lastname
360
      field_position
361
      field_firstname
362
      field_birth_date
363
      field_shirtnumber
364
      field_vv_id
365
      relationships {
366
        node__article {
367
          title
368
          timestamp: created(formatString: "x")
369
          path {
370
            alias
371
          }
372
          relationships {
373
            field_media_article_image {
374
              ...ArticleImage
375
            }
376
          }
377
        }
378
        node__team {
379
          title
380
          relationships {
381
            field_media_article_image {
382
              ...ArticleImage
383
            }
384
          }
385
          path {
386
            alias
387
          }
388
        }
389
        field_image {
390
          localFile {
391
            ...KCVVFluid480
392
          }
393
        }
394
        field_image_celebrate {
395
          localFile {
396
            ...KCVVFixedPlayerTeaserShare
397
          }
398
        }
399
      }
400
    }
401
  }
402
`
403