Player.tsx ➔ getData   F
last analyzed

Complexity

Conditions 15

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 4
rs 2.9998
c 0
b 0
f 0
cc 15

How to fix   Complexity   

Complexity

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