Files
thetool/public/mobile/shared/offlineSettings.js
2026-01-27 10:35:15 +01:00

251 lines
6.0 KiB
JavaScript

/**
* Offline mode settings management
*
* Stores settings in localStorage following the existing pattern
* used by theme and movement_settings.
*/
const STORAGE_KEY = 'workorder_offline';
// Default settings
const defaultSettings = {
enabled: false,
autoSync: true,
lastSyncTimestamp: null,
deviceId: null // Generated on first enable
};
// In-memory cache of settings
let cachedSettings = null;
/**
* Generate a unique device ID using crypto API
*/
function generateDeviceId() {
if (crypto.randomUUID) {
return crypto.randomUUID();
}
// Fallback for older browsers
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Load settings from localStorage
*/
export function loadOfflineSettings() {
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
cachedSettings = { ...defaultSettings, ...JSON.parse(saved) };
} else {
cachedSettings = { ...defaultSettings };
}
} catch (error) {
console.error('[OfflineSettings] Failed to load settings:', error);
cachedSettings = { ...defaultSettings };
}
return cachedSettings;
}
/**
* Save settings to localStorage
*/
export function saveOfflineSettings(settings) {
try {
cachedSettings = { ...cachedSettings, ...settings };
localStorage.setItem(STORAGE_KEY, JSON.stringify(cachedSettings));
return true;
} catch (error) {
console.error('[OfflineSettings] Failed to save settings:', error);
return false;
}
}
/**
* Get current settings (from cache or load)
*/
export function getOfflineSettings() {
if (!cachedSettings) {
loadOfflineSettings();
}
return { ...cachedSettings };
}
/**
* Check if offline mode is enabled
*/
export function isOfflineModeEnabled() {
const settings = getOfflineSettings();
return settings.enabled === true;
}
/**
* Check if auto-sync is enabled
*/
export function isAutoSyncEnabled() {
const settings = getOfflineSettings();
return settings.autoSync === true;
}
/**
* Enable offline mode
* Generates device ID if not exists
*/
export function enableOfflineMode() {
const settings = getOfflineSettings();
if (!settings.deviceId) {
settings.deviceId = generateDeviceId();
}
settings.enabled = true;
return saveOfflineSettings(settings);
}
/**
* Disable offline mode
* Does NOT clear cached data (user must do that explicitly)
*/
export function disableOfflineMode() {
return saveOfflineSettings({ enabled: false });
}
/**
* Toggle offline mode
*/
export function toggleOfflineMode() {
if (isOfflineModeEnabled()) {
return disableOfflineMode();
} else {
return enableOfflineMode();
}
}
/**
* Set auto-sync preference
*/
export function setAutoSync(enabled) {
return saveOfflineSettings({ autoSync: enabled });
}
/**
* Get device ID (generates if needed)
*/
export function getDeviceId() {
const settings = getOfflineSettings();
if (!settings.deviceId) {
settings.deviceId = generateDeviceId();
saveOfflineSettings(settings);
}
return settings.deviceId;
}
/**
* Update last sync timestamp
*/
export function updateLastSyncTimestamp() {
return saveOfflineSettings({ lastSyncTimestamp: Date.now() });
}
/**
* Get last sync timestamp
*/
export function getLastSyncTimestamp() {
const settings = getOfflineSettings();
return settings.lastSyncTimestamp;
}
/**
* Get last sync as human-readable string
*/
export function getLastSyncText() {
const timestamp = getLastSyncTimestamp();
if (!timestamp) {
return 'Nie synchronisiert';
}
const now = Date.now();
const diff = now - timestamp;
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) {
return 'Gerade eben';
} else if (minutes < 60) {
return `Vor ${minutes} Minute${minutes === 1 ? '' : 'n'}`;
} else if (hours < 24) {
return `Vor ${hours} Stunde${hours === 1 ? '' : 'n'}`;
} else {
return `Vor ${days} Tag${days === 1 ? '' : 'en'}`;
}
}
/**
* Get data freshness level based on last sync
* Returns: 'fresh' (<1h), 'stale' (1-24h), 'old' (>24h)
*/
export function getDataFreshness() {
const timestamp = getLastSyncTimestamp();
if (!timestamp) {
return 'unknown';
}
const now = Date.now();
const diff = now - timestamp;
const hours = diff / 3600000;
if (hours < 1) {
return 'fresh'; // Green
} else if (hours < 24) {
return 'stale'; // Yellow
} else {
return 'old'; // Red
}
}
/**
* Clear all offline settings (for logout)
*/
export function clearOfflineSettings() {
try {
localStorage.removeItem(STORAGE_KEY);
cachedSettings = null;
return true;
} catch (error) {
console.error('[OfflineSettings] Failed to clear settings:', error);
return false;
}
}
// Reactive state for Vue components
export const offlineSettingsState = {
get enabled() { return isOfflineModeEnabled(); },
get autoSync() { return isAutoSyncEnabled(); },
get lastSync() { return getLastSyncTimestamp(); },
get lastSyncText() { return getLastSyncText(); },
get freshness() { return getDataFreshness(); },
get deviceId() { return getDeviceId(); }
};
export default {
load: loadOfflineSettings,
save: saveOfflineSettings,
get: getOfflineSettings,
isEnabled: isOfflineModeEnabled,
isAutoSyncEnabled,
enable: enableOfflineMode,
disable: disableOfflineMode,
toggle: toggleOfflineMode,
setAutoSync,
getDeviceId,
updateLastSync: updateLastSyncTimestamp,
getLastSync: getLastSyncTimestamp,
getLastSyncText,
getFreshness: getDataFreshness,
clear: clearOfflineSettings,
state: offlineSettingsState
};