diff --git a/app/admin/useAdminState.ts b/app/admin/useAdminState.ts index eb72a77..4718efc 100644 --- a/app/admin/useAdminState.ts +++ b/app/admin/useAdminState.ts @@ -12,7 +12,7 @@ export const useAdminState = () => { const [periods, setPeriods] = useState([]); const [attendance, setAttendance] = useState({}); const [scheduleData, setScheduleData] = useState([]); - const [dailyLogs, setDailyLogs] = useState>({}); // NYTT + const [dailyLogs, setDailyLogs] = useState>({}); const [activePeriodId, setActivePeriodId] = useState(''); const [isLoadingData, setIsLoadingData] = useState(true); @@ -56,7 +56,6 @@ export const useAdminState = () => { return nextAttendance; }; - // NYTT: Hantera offfline-kö för dagböcker const applyQueueToLogs = async (baseLogs: Record) => { const queue = await localforage.getItem('sync-queue') || []; const nextLogs = { ...baseLogs }; @@ -85,20 +84,57 @@ export const useAdminState = () => { const refreshData = useCallback(async (isInitialLoad = false) => { if (!isInitialLoad) setIsSyncing(true); + if (isInitialLoad) { + try { + const cachedSched = await localforage.getItem('cachedScheduleData'); + const cachedData = await localforage.getItem('cachedAdminData'); + const cachedLogs = await localforage.getItem>('cachedDailyLogs'); + + if (cachedData) { + const { loadedPeriods, loadedAttendance } = mapDbDataToUI(cachedData); + const finalAttendance = await applyQueueToAttendance(loadedAttendance); + const finalLogs = await applyQueueToLogs(cachedLogs || {}); + + if (cachedSched) setScheduleData(cachedSched); + setPeriods(loadedPeriods); + setAttendance(finalAttendance); + setDailyLogs(finalLogs); + + if (loadedPeriods.length > 0) { + const today = toIsoDate(new Date()); + const activePeriods = loadedPeriods.filter(p => today >= p.startDate && today <= p.endDate); + if (activePeriods.length > 0) setActivePeriodId(activePeriods[0].id); + else setActivePeriodId(loadedPeriods[0].id); + } + setIsLoadingData(false); + } + } catch (e) { + console.warn("Kunde inte ladda lokal cache", e); + } + } + + const withTimeout = (promise: Promise, ms: number = 5000): Promise => { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => reject(new Error('NETWORK_TIMEOUT')), ms); + promise + .then(val => { clearTimeout(timer); resolve(val); }) + .catch(err => { clearTimeout(timer); reject(err); }); + }); + }; + try { if (navigator.onLine) await flushOfflineQueue(); - const schedRes = await readJsonFile('schedule.json'); + const schedRes = await withTimeout(readJsonFile('schedule.json')); if (schedRes.success && schedRes.data) { setScheduleData(schedRes.data); await localforage.setItem('cachedScheduleData', schedRes.data); } - const dbPeriods = await getAdminData(); + const dbPeriods = await withTimeout(getAdminData()); await localforage.setItem('cachedAdminData', dbPeriods); - // NYTT: Ladda in loggarna - const dbLogs = await getDailyLogsDb(); + const dbLogs = await withTimeout(getDailyLogsDb()); const mappedLogs: Record = {}; dbLogs.forEach((l: { date: string | number; content: string; }) => mappedLogs[l.date] = l.content); await localforage.setItem('cachedDailyLogs', mappedLogs); @@ -113,35 +149,20 @@ export const useAdminState = () => { setAttendance(finalAttendance); setDailyLogs(finalLogs); - if (isInitialLoad && loadedPeriods.length > 0) { + if (isInitialLoad && periods.length === 0 && loadedPeriods.length > 0) { const today = toIsoDate(new Date()); const activePeriods = loadedPeriods.filter(p => today >= p.startDate && today <= p.endDate); if (activePeriods.length > 0) setActivePeriodId(activePeriods[0].id); else setActivePeriodId(loadedPeriods[0].id); } } catch (error) { + console.warn("Nätverkstimeout eller offline - faller tillbaka på cache.", error); setIsOffline(true); - const cachedSched = await localforage.getItem('cachedScheduleData'); - if (cachedSched) setScheduleData(cachedSched); - - const cachedData = await localforage.getItem('cachedAdminData'); - if (cachedData) { - const { loadedPeriods, loadedAttendance } = mapDbDataToUI(cachedData); - const finalAttendance = await applyQueueToAttendance(loadedAttendance); - setPeriods(loadedPeriods); - setAttendance(finalAttendance); - - const cachedLogs = await localforage.getItem>('cachedDailyLogs') || {}; - const finalLogs = await applyQueueToLogs(cachedLogs); - setDailyLogs(finalLogs); - - if (isInitialLoad && loadedPeriods.length > 0) setActivePeriodId(loadedPeriods[0].id); - } } finally { setIsLoadingData(false); setIsSyncing(false); } - }, [flushOfflineQueue]); + }, [flushOfflineQueue, periods.length]); useEffect(() => { refreshData(true); }, [refreshData]); @@ -162,7 +183,6 @@ export const useAdminState = () => { const addToOfflineQueue = async (action: any) => { const queue = await localforage.getItem('sync-queue') || []; - // Undvik dubbletter för just detta datum och denna åtgärd let filteredQueue = queue; if (action.type === 'SET_DAILY_LOG') { filteredQueue = queue.filter(q => !(q.type === 'SET_DAILY_LOG' && q.payload.date === action.payload.date)); @@ -242,7 +262,6 @@ export const useAdminState = () => { else await removeAttendanceDb(date, youthId, shiftId).catch(async () => { await addToOfflineQueue({ type: 'REMOVE_ATTENDANCE', payload: { date, youthId, shiftId } }); }); }; - // NYTT: Funktion för att spara dagbok lokalt och i databasen const setDailyLog = async (date: string, content: string) => { setDailyLogs(prev => ({ ...prev, [date]: content })); @@ -257,7 +276,7 @@ export const useAdminState = () => { return { periods, attendance, activePeriodId, setActivePeriodId, isLoadingData, isOffline, isSyncing, scheduleData, - dailyLogs, setDailyLog, // <-- Expotera här + dailyLogs, setDailyLog, createPeriod, deletePeriod, bulkAddYouth, removeYouth, setManualAttendance, bulkSetManualAttendance, addPendingAttendance, removeAttendanceEntry, refreshData };