Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added cache expiry time, fixes stale cache issue for logos #241

Merged
merged 10 commits into from
Nov 20, 2024
3 changes: 3 additions & 0 deletions .github/workflows/firebase-hosting-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Install Firebase CLI
run: npm install -g firebase-tools

- name: Build
run: npm run build

Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/firebase-hosting-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Install Firebase CLI
run: npm install -g firebase-tools
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: '${{ secrets.GITHUB_TOKEN }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_MATCH_VIEWING_DASHBOARD }}'
projectId: match-viewing-dashboard
env:
FIREBASE_CLI_EXPERIMENTS: webframeworks
FIREBASE_CLI_EXPERIMENTS: webframeworks
Empty file.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ yarn-error.log*
.env.production.local

# Firebase cache
.firebase/
.firebase/

.vscode/launch.json
16 changes: 0 additions & 16 deletions .vscode/launch.json

This file was deleted.

17 changes: 8 additions & 9 deletions app/components/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@ const Dashboard = () => {
// }, [formattedMatches])

// Fuzzy search
const fuse = useMemo(
() =>
new Fuse(formattedMatches, {
keys: searchableProperties,
threshold: 0.3
}),
[formattedMatches]
)
const fuse = useMemo(() => {
if (!formattedMatches.length) return null
return new Fuse(formattedMatches, {
keys: searchableProperties,
threshold: 0.3
})
}, [formattedMatches])

const filteredMatchSets = useMemo(() => {
if (!searchTerm) return []
if (!searchTerm || !fuse) return []
const result = fuse.search(searchTerm).map((result) => {
const match = result.item
return `${match.matchDate}#${match.teams.opponentTeam}`
Expand Down
60 changes: 31 additions & 29 deletions app/components/DataProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,35 +89,39 @@ export const DataProvider = ({ children }) => {
[fetchMatches, matches]
)

const createMatch = useCallback(
async (collectionName, newMatchData) => {
try {
const newMatch = {
id: 'temp-id',
collection: collectionName,
...newMatchData
}

setMatches((prevMatches) => [...prevMatches, newMatch])

const colRef = collection(db, collectionName)
await addDoc(colRef, newMatchData)

await fetchMatches()
} catch (err) {
setError(err)
console.error('Error creating new match:', err)
const createMatch = useCallback(async (collectionName, newMatchData) => {
try {
const newMatch = {
id: 'temp-id',
collection: collectionName,
...newMatchData
}
},
[fetchMatches]
)
setMatches((prevMatches) => [...prevMatches, newMatch])

// Actual Firestore addition
const colRef = collection(db, collectionName)
await addDoc(colRef, newMatchData)
await fetchMatches()
} catch (err) {
setError(err)
console.error('Error creating new match:', err)
}
}, [])

const fetchLogos = useCallback(async () => {
// Cache expiry time, currently 24 hours
const CACHE_EXPIRY_MS = 24 * 60 * 60 * 1000
const storedLogos = localStorage.getItem('teamLogos')
if (storedLogos) {
setLogos(JSON.parse(storedLogos))
setLogosLoading(false)
return
const storedTimeStamp = localStorage.getItem('teamLogosTimestamp')

if (storedLogos && storedTimeStamp) {
// check if cache expired
const cacheAge = Date.now() - parseInt(storedTimeStamp, 10)
if (cacheAge < CACHE_EXPIRY_MS) {
setLogos(JSON.parse(storedLogos))
setLogosLoading(false)
return
}
}

setLogosLoading(true)
Expand All @@ -132,6 +136,7 @@ export const DataProvider = ({ children }) => {

setLogos(logosMap)
localStorage.setItem('teamLogos', JSON.stringify(logosMap))
localStorage.setItem('teamLogosTimestamp', Date.now().toString())
} catch (err) {
setLogosError(err)
console.error('Error fetching team logos:', err)
Expand Down Expand Up @@ -172,9 +177,6 @@ export const useData = () => {
const { matches, logos, loading, error, refresh, updateMatch, createMatch } =
context

useEffect(() => {
refresh()
}, [refresh])

// Optionally keep `refresh` available for manual use in components
return { matches, logos, loading, error, refresh, updateMatch, createMatch }
}
67 changes: 1 addition & 66 deletions app/services/upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,6 @@ import {
} from 'firebase/firestore'
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage' // Import storage functions
import { db, storage } from '../services/initializeFirebase.js' // Ensure storage is exported from initializeFirebase.js
import { useData } from '../components/DataProvider.js' // Import the hook

async function useUploadMatch(
sets,
videoId,
pointsJson,
pdfFile,
teams,
players,
matchDate,
singles,
matchDetails,
collectionName
) {
// Use the createMatch function from the useMatchData hook
const { createMatch } = useData()
if (
!sets ||
!videoId ||
!teams ||
!players ||
!matchDate ||
!singles ||
!matchDetails ||
!collectionName
) {
console.error('All fields are required.')
return // Exit the function if any field is empty
}

try {
let pdfUrl = null
if (pdfFile) {
// First, upload the PDF to Firebase Storage
const pdfRef = ref(storage, `match-pdfs/${pdfFile.name}`)
const snapshot = await uploadBytes(pdfRef, pdfFile)
pdfUrl = await getDownloadURL(snapshot.ref)
}

// untagged matches
let published = true
if (pointsJson === null) published = false

// matchName: P1 T1 vs. P2 T2
const matchName = `${players.client.firstName} ${players.client.lastName} ${teams.clientTeam} vs. ${players.opponent.firstName} ${players.opponent.lastName} ${teams.opponentTeam}`

await createMatch(collectionName, {
name: matchName,
videoId,
sets,
pdfUrl,
matchDate,
teams,
players,
published,
singles,
matchDetails,
points: pointsJson || []
})

console.log('Match Document uploaded successfully.')
} catch (e) {
console.error('Error uploading Match Document: ', e)
}
}

async function uploadTeam(teamName, logoFile) {
if (!teamName || !logoFile) {
Expand Down Expand Up @@ -179,4 +114,4 @@ async function uploadPlayer(
}
}

export { useUploadMatch, uploadTeam, uploadPlayer }
export { uploadTeam, uploadPlayer }
Loading