Files
gym-bro/frontend/js/state.js
T
2026-09-30 02:25:03 +03:00

69 lines
2.1 KiB
JavaScript

const STORAGE_KEY = 'gym_tracker_v6';
export const state = {
workouts: [],
exerciseRef: [],
bodyMetrics: [],
// Справочники с бэкенда
workoutTypes: [],
metricTypes: [],
clients: [],
expandedWorkoutId: null,
expandedExerciseId: null,
nextId: 1,
// Режимы: 'personal' (по умолчанию) или 'trainer'
mode: 'personal',
currentClientId: null, // В личном режиме null, в режиме тренера - ID клиента
};
export function loadState() {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
try {
const parsed = JSON.parse(saved);
// Объединяем, чтобы не потерять новые поля при обновлении версии
Object.assign(state, parsed);
if (!state.workoutTypes) state.workoutTypes = [];
if (!state.metricTypes) state.metricTypes = [];
if (!state.clients) state.clients = [];
if (!state.mode) state.mode = 'personal';
} catch (e) {
console.error('Failed to load state', e);
}
}
}
export function saveState() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
updateSyncStatus();
}
export function genId() {
return (state.nextId++).toString();
}
// Генерация UUID v4 для sync_id (идемпотентность на бэкенде)
export function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
export function updateSyncStatus() {
const dirty = state.workouts.filter(w => !w.synced);
const el = document.getElementById('sync-status');
if (!el) return;
if (dirty.length === 0) {
el.textContent = '● Всё синхронизировано';
el.className = 'sync-status synced';
} else {
el.textContent = `● ${dirty.length} не сохран.`;
el.className = 'sync-status pending';
}
}