You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.3 KiB
155 lines
4.3 KiB
import { useState, useEffect, useCallback, useRef } from 'react'; |
|
import { |
|
getDailyLimit, |
|
getDailyLimitSync, |
|
getTimeUsedToday, |
|
getRemainingTimeToday, |
|
isLimitReached, |
|
addTimeSpent |
|
} from '../services/timeLimitService'; |
|
|
|
interface UseTimeLimitReturn { |
|
dailyLimit: number; |
|
timeUsed: number; |
|
remainingTime: number; |
|
limitReached: boolean; |
|
startTracking: () => void; |
|
stopTracking: () => void; |
|
isTracking: boolean; |
|
} |
|
|
|
/** |
|
* Hook to manage video time limits |
|
* Tracks time spent watching videos and enforces daily limits |
|
*/ |
|
export function useTimeLimit(): UseTimeLimitReturn { |
|
const [dailyLimit, setDailyLimit] = useState(getDailyLimitSync()); |
|
const [timeUsed, setTimeUsed] = useState(getTimeUsedToday()); |
|
const [remainingTime, setRemainingTime] = useState(getRemainingTimeToday()); |
|
const [limitReached, setLimitReached] = useState(isLimitReached()); |
|
const [isTracking, setIsTracking] = useState(false); |
|
|
|
const trackingIntervalRef = useRef<NodeJS.Timeout | null>(null); |
|
const startTimeRef = useRef<number | null>(null); |
|
const lastUpdateRef = useRef<number>(Date.now()); |
|
|
|
// Update state from localStorage and cached server limit |
|
const updateState = useCallback(() => { |
|
setDailyLimit(getDailyLimitSync()); |
|
setTimeUsed(getTimeUsedToday()); |
|
setRemainingTime(getRemainingTimeToday()); |
|
setLimitReached(isLimitReached()); |
|
}, []); |
|
|
|
// Fetch limit from server on mount |
|
useEffect(() => { |
|
getDailyLimit().then(limit => { |
|
setDailyLimit(limit); |
|
// Immediately recalculate limitReached with the correct server limit |
|
updateState(); |
|
}); |
|
}, [updateState]); |
|
|
|
// Start tracking time |
|
const startTracking = useCallback(() => { |
|
if (limitReached) { |
|
return; // Don't start if limit already reached |
|
} |
|
|
|
if (trackingIntervalRef.current) { |
|
return; // Already tracking |
|
} |
|
|
|
startTimeRef.current = Date.now(); |
|
lastUpdateRef.current = Date.now(); |
|
setIsTracking(true); |
|
|
|
// Update every 5 seconds |
|
trackingIntervalRef.current = setInterval(() => { |
|
if (startTimeRef.current) { |
|
const now = Date.now(); |
|
const secondsElapsed = (now - lastUpdateRef.current) / 1000; |
|
lastUpdateRef.current = now; |
|
|
|
// Add time spent |
|
addTimeSpent(secondsElapsed); |
|
|
|
// Update state |
|
updateState(); |
|
|
|
// Check if limit reached during tracking |
|
if (isLimitReached()) { |
|
// Stop tracking if limit reached |
|
if (trackingIntervalRef.current) { |
|
clearInterval(trackingIntervalRef.current); |
|
trackingIntervalRef.current = null; |
|
} |
|
if (startTimeRef.current && lastUpdateRef.current) { |
|
const secondsElapsed = (Date.now() - lastUpdateRef.current) / 1000; |
|
if (secondsElapsed > 0) { |
|
addTimeSpent(secondsElapsed); |
|
} |
|
startTimeRef.current = null; |
|
} |
|
setIsTracking(false); |
|
updateState(); |
|
} |
|
} |
|
}, 5000); |
|
}, [limitReached, updateState]); |
|
|
|
// Stop tracking time |
|
const stopTracking = useCallback(() => { |
|
if (trackingIntervalRef.current) { |
|
clearInterval(trackingIntervalRef.current); |
|
trackingIntervalRef.current = null; |
|
} |
|
|
|
// Add any remaining time |
|
if (startTimeRef.current && lastUpdateRef.current) { |
|
const secondsElapsed = (Date.now() - lastUpdateRef.current) / 1000; |
|
if (secondsElapsed > 0) { |
|
addTimeSpent(secondsElapsed); |
|
} |
|
startTimeRef.current = null; |
|
} |
|
|
|
setIsTracking(false); |
|
updateState(); |
|
}, [updateState]); |
|
|
|
// Cleanup on unmount |
|
useEffect(() => { |
|
return () => { |
|
if (trackingIntervalRef.current) { |
|
clearInterval(trackingIntervalRef.current); |
|
} |
|
// Save any remaining time before unmount |
|
if (startTimeRef.current && lastUpdateRef.current) { |
|
const secondsElapsed = (Date.now() - lastUpdateRef.current) / 1000; |
|
if (secondsElapsed > 0) { |
|
addTimeSpent(secondsElapsed); |
|
} |
|
} |
|
}; |
|
}, []); |
|
|
|
// Update state periodically to catch external changes |
|
useEffect(() => { |
|
const interval = setInterval(() => { |
|
updateState(); |
|
}, 10000); // Check every 10 seconds |
|
|
|
return () => clearInterval(interval); |
|
}, [updateState]); |
|
|
|
return { |
|
dailyLimit, |
|
timeUsed, |
|
remainingTime, |
|
limitReached, |
|
startTracking, |
|
stopTracking, |
|
isTracking |
|
}; |
|
}
|
|
|