@vixoniccom/footbal-score 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/src/App.tsx +114 -49
- package/src/helpers/getFixture.ts +2 -7
- package/build/index.html +0 -1
- package/build/main.js +0 -2
- package/build/main.js.LICENSE.txt +0 -59
- package/build/test/downloads/4a9bcc4e-f398-4317-9f0f-afa8bcef1a4f.png +0 -0
- package/build/test/downloads/7953953c-7029-4730-ae4d-cff4abd5288f.ttf +0 -0
- package/build/test/downloads/Roboto-Bold.ttf +0 -0
- package/build/test/downloads/Spring in May.ttf +0 -0
- package/build/test/downloads/c705a739-312e-4334-9231-e73a05e9d382.ttf +0 -0
- package/build/test/downloads/cumples.png +0 -0
- package/build/test/downloads/d1093778-f3c9-42c8-9b07-9f8736390aeb/Foto prueba.jpg +0 -0
- package/build/test/downloads/d1093778-f3c9-42c8-9b07-9f8736390aeb/foto1.jpg +0 -0
- package/build/test/downloads/d1093778-f3c9-42c8-9b07-9f8736390aeb.zip +0 -0
- package/build/test/downloads/fondopasto.jpg +0 -0
- package/build/test/parameters.json +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.4.2](https://github.com/Vixonic/store-football-score/compare/v1.4.2-dev.0...v1.4.2) (2026-06-13)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* load request when start match ([8b68820](https://github.com/Vixonic/store-football-score/commit/8b688204b15130642d9085838beeda75984435ff))
|
|
11
|
+
|
|
12
|
+
### [1.4.2-dev.0](https://github.com/Vixonic/store-football-score/compare/v1.4.1...v1.4.2-dev.0) (2026-06-13)
|
|
13
|
+
|
|
5
14
|
### [1.4.1](https://github.com/Vixonic/store-football-score/compare/v1.4.1-dev.0...v1.4.1) (2026-06-11)
|
|
6
15
|
|
|
7
16
|
|
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react'
|
|
2
2
|
import localforage from 'localforage'
|
|
3
|
-
import moment from 'moment'
|
|
4
3
|
import { FontLoader, FormattedText, Table } from './components'
|
|
5
4
|
import { getFixture } from './helpers/getFixture'
|
|
6
5
|
|
|
@@ -9,74 +8,140 @@ export type Props = {
|
|
|
9
8
|
start: boolean
|
|
10
9
|
}
|
|
11
10
|
|
|
11
|
+
const LIVE_STATUSES = ['1H', 'HT', '2H', 'P', 'ET', 'BT', 'LIVE', 'INT']
|
|
12
|
+
const PRE_MATCH_MS = 5 * 60 * 1000
|
|
13
|
+
|
|
14
|
+
localforage.config({ name: 'request_api_football' })
|
|
15
|
+
|
|
16
|
+
const log = (msg: string, ...args: any[]) =>
|
|
17
|
+
console.log(`[⚽ football-score ${new Date().toLocaleTimeString()}]`, msg, ...args)
|
|
18
|
+
|
|
19
|
+
// Returns the timestamp (ms) when the next fetch should happen based on fixture states.
|
|
20
|
+
// Persisted in localStorage so re-mounts don't reset the schedule.
|
|
21
|
+
function computeNextFetchTime(fixtures: any[], pollIntervalMs: number): number {
|
|
22
|
+
const now = Date.now()
|
|
23
|
+
|
|
24
|
+
const liveMatches = fixtures.filter(f => LIVE_STATUSES.includes(f.fixture?.status?.short))
|
|
25
|
+
if (liveMatches.length > 0) {
|
|
26
|
+
const next = new Date(now + pollIntervalMs)
|
|
27
|
+
log(`🟢 ${liveMatches.length} partido(s) en vivo → próximo fetch en ${next.toLocaleTimeString()} (${pollIntervalMs / 1000}s)`)
|
|
28
|
+
return now + pollIntervalMs
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const nextMatchAt = fixtures
|
|
32
|
+
.filter(f => f.fixture?.status?.short === 'NS')
|
|
33
|
+
.map(f => new Date(f.fixture.date).getTime())
|
|
34
|
+
.filter(t => t > now)
|
|
35
|
+
.sort((a, b) => a - b)[0]
|
|
36
|
+
|
|
37
|
+
if (nextMatchAt !== undefined) {
|
|
38
|
+
const wakeUp = nextMatchAt - PRE_MATCH_MS
|
|
39
|
+
if (wakeUp <= now) {
|
|
40
|
+
const next = new Date(now + pollIntervalMs)
|
|
41
|
+
log(`🟡 Dentro de ventana pre-partido → próximo fetch en ${next.toLocaleTimeString()}`)
|
|
42
|
+
return now + pollIntervalMs
|
|
43
|
+
}
|
|
44
|
+
log(`⏰ Próximo partido: ${new Date(nextMatchAt).toLocaleTimeString()} → fetch a las ${new Date(wakeUp).toLocaleTimeString()} (10 min antes)`)
|
|
45
|
+
return wakeUp
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const tomorrow = new Date()
|
|
49
|
+
tomorrow.setDate(tomorrow.getDate() + 1)
|
|
50
|
+
tomorrow.setHours(0, 15, 0, 0)
|
|
51
|
+
log(`💤 Sin partidos pendientes → próximo check: ${tomorrow.toLocaleString()}`)
|
|
52
|
+
return tomorrow.getTime()
|
|
53
|
+
}
|
|
54
|
+
|
|
12
55
|
export const App: React.FunctionComponent<Props> = ({ data, start }) => {
|
|
13
56
|
const [dataFixture, setDataFixture] = useState<any[]>([])
|
|
14
57
|
const [leagueState, setLeagueState] = useState<string>('')
|
|
15
58
|
const { parameters, downloadsPath } = data
|
|
16
|
-
const { backgroundImage, padding, msj0 = '',
|
|
59
|
+
const { backgroundImage, padding, msj0 = '', league = '9' } = parameters
|
|
17
60
|
const backgroundImageState = backgroundImage?.filename
|
|
18
61
|
? `url("${downloadsPath}/${backgroundImage.filename}")`
|
|
19
62
|
: ''
|
|
20
63
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (momentLocalStorage == undefined || (isWithinSchedule && momentLocalStorage > updateTime!)) {
|
|
35
|
-
const dataRequest = await getFixture(league, parameters.matchesYesterday, parameters.matchesTomorrow)
|
|
36
|
-
setDataLocal(dataRequest)
|
|
37
|
-
setDataFixture(dataRequest)
|
|
38
|
-
} else {
|
|
39
|
-
setDataFixture(dataLocal.data)
|
|
64
|
+
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
65
|
+
// Refs keep the timeout callback from closing over stale props
|
|
66
|
+
const leagueRef = useRef(league)
|
|
67
|
+
const paramsRef = useRef(parameters)
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
leagueRef.current = league
|
|
70
|
+
paramsRef.current = parameters
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const clearSchedule = () => {
|
|
74
|
+
if (timeoutRef.current !== null) {
|
|
75
|
+
clearTimeout(timeoutRef.current)
|
|
76
|
+
timeoutRef.current = null
|
|
40
77
|
}
|
|
41
78
|
}
|
|
42
79
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
getData()
|
|
47
|
-
}
|
|
48
|
-
}, [data])
|
|
80
|
+
const fetchAndSchedule = async () => {
|
|
81
|
+
const { matchesYesterday, matchesTomorrow, updateTime: ut = 300000 } = paramsRef.current
|
|
82
|
+
const cached: any = await localforage.getItem('football-score')
|
|
49
83
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
84
|
+
log(`🔄 Fetching fixtures (liga ${leagueRef.current})...`)
|
|
85
|
+
let fixtures: any[]
|
|
86
|
+
try {
|
|
87
|
+
fixtures = await getFixture(leagueRef.current, matchesYesterday, matchesTomorrow)
|
|
88
|
+
log(`✅ ${fixtures.length} fixture(s) recibidos`)
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error('[football-score] API error:', err)
|
|
91
|
+
fixtures = cached?.data ?? []
|
|
92
|
+
log(`❌ API falló → usando cache (${fixtures.length} fixtures)`)
|
|
55
93
|
}
|
|
56
|
-
}, [league])
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const interval = setInterval(() => {
|
|
61
|
-
getData()
|
|
62
|
-
}, updateTime)
|
|
63
|
-
return () => clearInterval(interval)
|
|
64
|
-
}, [updateTime, data])
|
|
65
|
-
|
|
66
|
-
const setDataLocal = async (data: any) => {
|
|
67
|
-
localforage.config({ name: 'request_api_football' })
|
|
95
|
+
const nextFetchTime = computeNextFetchTime(fixtures, ut)
|
|
96
|
+
|
|
68
97
|
try {
|
|
69
|
-
await localforage.setItem('football-score', { date: Date.now(), data })
|
|
98
|
+
await localforage.setItem('football-score', { date: Date.now(), data: fixtures, nextFetchTime })
|
|
70
99
|
} catch (err) {
|
|
71
|
-
console.
|
|
100
|
+
console.error('[football-score] localStorage write error', err)
|
|
72
101
|
}
|
|
102
|
+
|
|
103
|
+
setDataFixture(fixtures)
|
|
104
|
+
|
|
105
|
+
clearSchedule()
|
|
106
|
+
timeoutRef.current = setTimeout(fetchAndSchedule, Math.max(0, nextFetchTime - Date.now()))
|
|
73
107
|
}
|
|
74
108
|
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
109
|
+
const init = async () => {
|
|
110
|
+
const cached: any = await localforage.getItem('football-score')
|
|
111
|
+
const now = Date.now()
|
|
112
|
+
|
|
113
|
+
if (!cached?.data) {
|
|
114
|
+
log(`🆕 Sin cache → fetch inmediato`)
|
|
115
|
+
fetchAndSchedule()
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
setDataFixture(cached.data)
|
|
120
|
+
|
|
121
|
+
if (!cached.nextFetchTime || cached.nextFetchTime <= now) {
|
|
122
|
+
log(`🔁 Mount check: nextFetchTime ya pasó (${cached.nextFetchTime ? new Date(cached.nextFetchTime).toLocaleTimeString() : 'null'}) → fetch inmediato`)
|
|
123
|
+
fetchAndSchedule()
|
|
124
|
+
} else {
|
|
125
|
+
const mins = Math.round((cached.nextFetchTime - now) / 60000)
|
|
126
|
+
log(`💾 Mount check: usando cache → próximo fetch en ${new Date(cached.nextFetchTime).toLocaleTimeString()} (~${mins} min)`)
|
|
127
|
+
}
|
|
78
128
|
}
|
|
79
129
|
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (!start) return
|
|
132
|
+
setLeagueState(league)
|
|
133
|
+
init()
|
|
134
|
+
return clearSchedule
|
|
135
|
+
}, [data])
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (leagueState === '' || leagueState === league) return
|
|
139
|
+
setLeagueState(league)
|
|
140
|
+
clearSchedule()
|
|
141
|
+
localforage.clear()
|
|
142
|
+
fetchAndSchedule()
|
|
143
|
+
}, [league])
|
|
144
|
+
|
|
80
145
|
return (
|
|
81
146
|
dataFixture.length > 0 ?
|
|
82
147
|
<div style={{
|
|
@@ -27,11 +27,6 @@ export const getFixture = async (league: string, yesterday?: boolean, tomorrow?:
|
|
|
27
27
|
headers: { 'X-RapidAPI-Key': FOOTBALL_API_KEY, 'X-RapidAPI-Host': FOOTBALL_API_HOST },
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return response.data.response
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.error(error)
|
|
35
|
-
return []
|
|
36
|
-
}
|
|
30
|
+
const response = await axios.request(options)
|
|
31
|
+
return response.data.response
|
|
37
32
|
}
|
package/build/index.html
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<!doctype html><html lang="en" style="position:absolute;height:100%;width:100%;overflow:hidden"><head><title></title><meta charset="utf-8"/></head><body style="margin:0;overflow:hidden"><div id="root" style="position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden"></div><script src="./main.js"></script></body></html>
|