Compare commits
+46
-27
@@ -12,7 +12,7 @@ export const useAdminState = () => {
|
|||||||
const [periods, setPeriods] = useState<Period[]>([]);
|
const [periods, setPeriods] = useState<Period[]>([]);
|
||||||
const [attendance, setAttendance] = useState<AttendanceDataMap>({});
|
const [attendance, setAttendance] = useState<AttendanceDataMap>({});
|
||||||
const [scheduleData, setScheduleData] = useState<any[]>([]);
|
const [scheduleData, setScheduleData] = useState<any[]>([]);
|
||||||
const [dailyLogs, setDailyLogs] = useState<Record<string, string>>({}); // NYTT
|
const [dailyLogs, setDailyLogs] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const [activePeriodId, setActivePeriodId] = useState<string>('');
|
const [activePeriodId, setActivePeriodId] = useState<string>('');
|
||||||
const [isLoadingData, setIsLoadingData] = useState<boolean>(true);
|
const [isLoadingData, setIsLoadingData] = useState<boolean>(true);
|
||||||
@@ -56,7 +56,6 @@ export const useAdminState = () => {
|
|||||||
return nextAttendance;
|
return nextAttendance;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NYTT: Hantera offfline-kö för dagböcker
|
|
||||||
const applyQueueToLogs = async (baseLogs: Record<string, string>) => {
|
const applyQueueToLogs = async (baseLogs: Record<string, string>) => {
|
||||||
const queue = await localforage.getItem<any[]>('sync-queue') || [];
|
const queue = await localforage.getItem<any[]>('sync-queue') || [];
|
||||||
const nextLogs = { ...baseLogs };
|
const nextLogs = { ...baseLogs };
|
||||||
@@ -85,20 +84,57 @@ export const useAdminState = () => {
|
|||||||
const refreshData = useCallback(async (isInitialLoad = false) => {
|
const refreshData = useCallback(async (isInitialLoad = false) => {
|
||||||
if (!isInitialLoad) setIsSyncing(true);
|
if (!isInitialLoad) setIsSyncing(true);
|
||||||
|
|
||||||
|
if (isInitialLoad) {
|
||||||
|
try {
|
||||||
|
const cachedSched = await localforage.getItem<any[]>('cachedScheduleData');
|
||||||
|
const cachedData = await localforage.getItem<any[]>('cachedAdminData');
|
||||||
|
const cachedLogs = await localforage.getItem<Record<string, string>>('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 = <T>(promise: Promise<T>, ms: number = 5000): Promise<T> => {
|
||||||
|
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 {
|
try {
|
||||||
if (navigator.onLine) await flushOfflineQueue();
|
if (navigator.onLine) await flushOfflineQueue();
|
||||||
|
|
||||||
const schedRes = await readJsonFile('schedule.json');
|
const schedRes = await withTimeout(readJsonFile('schedule.json'));
|
||||||
if (schedRes.success && schedRes.data) {
|
if (schedRes.success && schedRes.data) {
|
||||||
setScheduleData(schedRes.data);
|
setScheduleData(schedRes.data);
|
||||||
await localforage.setItem('cachedScheduleData', schedRes.data);
|
await localforage.setItem('cachedScheduleData', schedRes.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbPeriods = await getAdminData();
|
const dbPeriods = await withTimeout(getAdminData());
|
||||||
await localforage.setItem('cachedAdminData', dbPeriods);
|
await localforage.setItem('cachedAdminData', dbPeriods);
|
||||||
|
|
||||||
// NYTT: Ladda in loggarna
|
const dbLogs = await withTimeout(getDailyLogsDb());
|
||||||
const dbLogs = await getDailyLogsDb();
|
|
||||||
const mappedLogs: Record<string, string> = {};
|
const mappedLogs: Record<string, string> = {};
|
||||||
dbLogs.forEach((l: { date: string | number; content: string; }) => mappedLogs[l.date] = l.content);
|
dbLogs.forEach((l: { date: string | number; content: string; }) => mappedLogs[l.date] = l.content);
|
||||||
await localforage.setItem('cachedDailyLogs', mappedLogs);
|
await localforage.setItem('cachedDailyLogs', mappedLogs);
|
||||||
@@ -113,35 +149,20 @@ export const useAdminState = () => {
|
|||||||
setAttendance(finalAttendance);
|
setAttendance(finalAttendance);
|
||||||
setDailyLogs(finalLogs);
|
setDailyLogs(finalLogs);
|
||||||
|
|
||||||
if (isInitialLoad && loadedPeriods.length > 0) {
|
if (isInitialLoad && periods.length === 0 && loadedPeriods.length > 0) {
|
||||||
const today = toIsoDate(new Date());
|
const today = toIsoDate(new Date());
|
||||||
const activePeriods = loadedPeriods.filter(p => today >= p.startDate && today <= p.endDate);
|
const activePeriods = loadedPeriods.filter(p => today >= p.startDate && today <= p.endDate);
|
||||||
if (activePeriods.length > 0) setActivePeriodId(activePeriods[0].id);
|
if (activePeriods.length > 0) setActivePeriodId(activePeriods[0].id);
|
||||||
else setActivePeriodId(loadedPeriods[0].id);
|
else setActivePeriodId(loadedPeriods[0].id);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.warn("Nätverkstimeout eller offline - faller tillbaka på cache.", error);
|
||||||
setIsOffline(true);
|
setIsOffline(true);
|
||||||
const cachedSched = await localforage.getItem<any[]>('cachedScheduleData');
|
|
||||||
if (cachedSched) setScheduleData(cachedSched);
|
|
||||||
|
|
||||||
const cachedData = await localforage.getItem<any[]>('cachedAdminData');
|
|
||||||
if (cachedData) {
|
|
||||||
const { loadedPeriods, loadedAttendance } = mapDbDataToUI(cachedData);
|
|
||||||
const finalAttendance = await applyQueueToAttendance(loadedAttendance);
|
|
||||||
setPeriods(loadedPeriods);
|
|
||||||
setAttendance(finalAttendance);
|
|
||||||
|
|
||||||
const cachedLogs = await localforage.getItem<Record<string, string>>('cachedDailyLogs') || {};
|
|
||||||
const finalLogs = await applyQueueToLogs(cachedLogs);
|
|
||||||
setDailyLogs(finalLogs);
|
|
||||||
|
|
||||||
if (isInitialLoad && loadedPeriods.length > 0) setActivePeriodId(loadedPeriods[0].id);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingData(false);
|
setIsLoadingData(false);
|
||||||
setIsSyncing(false);
|
setIsSyncing(false);
|
||||||
}
|
}
|
||||||
}, [flushOfflineQueue]);
|
}, [flushOfflineQueue, periods.length]);
|
||||||
|
|
||||||
useEffect(() => { refreshData(true); }, [refreshData]);
|
useEffect(() => { refreshData(true); }, [refreshData]);
|
||||||
|
|
||||||
@@ -162,7 +183,6 @@ export const useAdminState = () => {
|
|||||||
const addToOfflineQueue = async (action: any) => {
|
const addToOfflineQueue = async (action: any) => {
|
||||||
const queue = await localforage.getItem<any[]>('sync-queue') || [];
|
const queue = await localforage.getItem<any[]>('sync-queue') || [];
|
||||||
|
|
||||||
// Undvik dubbletter för just detta datum och denna åtgärd
|
|
||||||
let filteredQueue = queue;
|
let filteredQueue = queue;
|
||||||
if (action.type === 'SET_DAILY_LOG') {
|
if (action.type === 'SET_DAILY_LOG') {
|
||||||
filteredQueue = queue.filter(q => !(q.type === 'SET_DAILY_LOG' && q.payload.date === action.payload.date));
|
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 } }); });
|
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) => {
|
const setDailyLog = async (date: string, content: string) => {
|
||||||
setDailyLogs(prev => ({ ...prev, [date]: content }));
|
setDailyLogs(prev => ({ ...prev, [date]: content }));
|
||||||
|
|
||||||
@@ -257,7 +276,7 @@ export const useAdminState = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
periods, attendance, activePeriodId, setActivePeriodId, isLoadingData, isOffline, isSyncing, scheduleData,
|
periods, attendance, activePeriodId, setActivePeriodId, isLoadingData, isOffline, isSyncing, scheduleData,
|
||||||
dailyLogs, setDailyLog, // <-- Expotera här
|
dailyLogs, setDailyLog,
|
||||||
createPeriod, deletePeriod, bulkAddYouth, removeYouth,
|
createPeriod, deletePeriod, bulkAddYouth, removeYouth,
|
||||||
setManualAttendance, bulkSetManualAttendance, addPendingAttendance, removeAttendanceEntry, refreshData
|
setManualAttendance, bulkSetManualAttendance, addPendingAttendance, removeAttendanceEntry, refreshData
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// prisma.config.ts
|
// prisma.config.ts
|
||||||
|
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import { defineConfig, env } from "prisma/config";
|
import { defineConfig } from "prisma/config";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
schema: "prisma/schema.prisma",
|
schema: "prisma/schema.prisma",
|
||||||
|
|||||||
Reference in New Issue
Block a user