UNPKG

powerhouse-rp-toolkit

Version:

Renaissance Periodization Training Toolkit for PowerHouseATX

1,443 lines (1,238 loc) 61.4 kB
import { debugLog } from "../utils/debug.js"; import { initNavigation } from "./navigation.js"; /* Maps module functions onto window so legacy inline onclick="" handlers keep working */ import { beginnerPreset, intermediatePreset, advancedPreset, customConfiguration, saveVolumeLandmarks, setupMesocycle, showRIRSchedule, generateWeeklyProgram, smartExerciseSelection, riskAssessment, runWeeklyAutoProgression, nextWeek, processWeeklyAdjustments, weeklyIntelligenceReport, predictDeloadTiming, plateauAnalysis, startWorkoutHandler, logSetHandler, undoLastSetHandler, finishWorkoutHandler, btnOptimizeFrequency, btnProcessWithRPAlgorithms, btnAutoProgressWeekly, btnGenerateMesocycle, btnExportProgram, analyzeDeloadNeedHandler, initializeAtMEVHandler, initializeIntelligenceHandler, optimizeVolumeLandmarksHandler, adaptiveRIRRecommendationsHandler, exportAllDataHandler, exportChartHandler, createBackupHandler, autoBackupHandler, importDataHandler, exportFeedbackHandler, } from "./buttonHandlers.js"; import { initChart, updateChart, addVolumeLandmarks, resetChart, exportChartImage, } from "./chartManager.js"; import { scoreStimulus, setProgressionAlgorithm, getVolumeProgression, analyzeDeloadNeed, autoSetIncrement, processWeeklyVolumeProgression, } from "../calculators/unified.js"; import { calculateTargetRIR, validateEffortLevel, getScheduledRIR, processWeeklyLoadAdjustments, getLoadProgression, simulateWeeklyRIRFeedback, } from "../algorithms/effort.js"; import { analyzeFrequency, calculateOptimalFrequency, isHighFatigue, } from "../calculators/unified.js"; import { validateLoad, validateSets, validateMesocycleLength, } from "../algorithms/validation.js"; import trainingState from "../core/trainingState.js"; /* ----- expose key objects ----- */ window.trainingState = trainingState; /* ----- UI utility functions ----- */ function hideGuide() { document.getElementById("quickStartGuide").style.display = "none"; } window.hideGuide = hideGuide; /* ----- expose chart functions ----- */ window.updateChart = updateChart; window.resetWeeklyData = resetChart; window.showVolumeLandmarks = addVolumeLandmarks; window.exportSummary = exportChartImage; /* ----- expose section toggle (enhanced with display:none) ----- */ window.toggleSection = function (sectionId) { // Simple legacy fallback: if element exists directly, just toggle hidden class const directElement = document.getElementById(sectionId); if (directElement && !document.getElementById(sectionId + "-content")) { directElement.classList.toggle("hidden"); return; } // Complex case: handle structured sections with animations const content = document.getElementById(sectionId + "-content"); if (!content) return; // Neither direct element nor structured section found const banner = content.previousElementSibling; const icon = banner?.querySelector(".expand-icon"); const opening = !content.classList.contains("expanded"); // ------- EXPAND ------- if (opening) { content.style.display = "block"; // back in flow // allow next paint, then add class so CSS transition plays requestAnimationFrame(() => { content.classList.add("expanded"); banner.classList.add("expanded"); // Update icon rotation if (icon) { icon.style.transform = "rotate(180deg)"; } postHeight(); // send new tall height }); } // ------- COLLAPSE ------- else { content.classList.remove("expanded"); // start transition banner.classList.remove("expanded"); // Update icon rotation if (icon) { icon.style.transform = "rotate(0deg)"; } // when transition ends hide element to drop layout height content.addEventListener("transitionend", function handler() { content.style.display = "none"; content.removeEventListener("transitionend", handler); postHeight(); // send shorter height }); } // helper sends current height to parent iframe function postHeight() { if (!window.parent || window.parent === window) return; try { const h = document.documentElement.getBoundingClientRect().height; window.parent.postMessage({ phxHeight: h }, "*"); } catch (err) { console.debug("Frame messaging error:", err.message); } } }; /* ----- expose RP algorithm functions ----- */ window.scoreStimulus = scoreStimulus; window.setProgressionAlgorithm = setProgressionAlgorithm; window.getVolumeProgression = getVolumeProgression; window.analyzeDeloadNeed = analyzeDeloadNeed; window.autoSetIncrement = autoSetIncrement; window.processWeeklyVolumeProgression = processWeeklyVolumeProgression; window.calculateTargetRIR = calculateTargetRIR; window.validateEffortLevel = validateEffortLevel; window.getScheduledRIR = getScheduledRIR; window.processWeeklyLoadAdjustments = processWeeklyLoadAdjustments; window.getLoadProgression = getLoadProgression; window.simulateWeeklyRIRFeedback = simulateWeeklyRIRFeedback; window.analyzeFrequency = analyzeFrequency; window.calculateOptimalFrequency = calculateOptimalFrequency; window.isHighFatigue = isHighFatigue; window.validateLoad = validateLoad; window.validateSets = validateSets; window.validateMesocycleLength = validateMesocycleLength; /* ----- expose advanced intelligence functions ----- */ import { optimizeVolumeLandmarks, predictDeloadTiming as analyticsDeloadPredictor, adaptiveRIRRecommendations, detectTrainingPlateaus, } from "../algorithms/analytics.js"; import { selectOptimalExercises, generateWeeklyProgram as generateProgram, } from "../algorithms/exerciseSelection.js"; import { liveMonitor } from "../algorithms/livePerformance.js"; import { advancedIntelligence } from "../algorithms/intelligenceHub.js"; /* ----- expose next-generation features ----- */ import { dataVisualizer } from "../algorithms/dataVisualization.js"; import { wellnessSystem } from "../algorithms/wellnessIntegration.js"; import { periodizationSystem } from "../algorithms/periodizationSystem.js"; /* ----- expose new utility features ----- */ import { dataExportManager } from "../utils/dataExport.js"; import { userFeedbackManager } from "../utils/userFeedback.js"; import { performanceManager } from "../utils/performance.js"; window.optimizeVolumeLandmarks = optimizeVolumeLandmarks; window.predictDeloadTiming = analyticsDeloadPredictor; window.adaptiveRIRRecommendations = adaptiveRIRRecommendations; window.detectTrainingPlateaus = detectTrainingPlateaus; window.selectOptimalExercises = selectOptimalExercises; window.generateWeeklyProgram = generateProgram; window.dataVisualizer = dataVisualizer; window.wellnessSystem = wellnessSystem; window.periodizationSystem = periodizationSystem; window.liveMonitor = liveMonitor; window.advancedIntelligence = advancedIntelligence; /* ----- expose new utility systems ----- */ window.dataExportManager = dataExportManager; window.userFeedbackManager = userFeedbackManager; window.performanceManager = performanceManager; /* ----- main UI handlers for buttons ----- */ window.submitFeedback = function () { const muscle = document.getElementById("muscleSelect").value; const mmc = parseInt(document.getElementById("mmc").value, 10); const pump = parseInt(document.getElementById("pump").value, 10); const workload = parseInt(document.getElementById("dis").value, 10); const soreness = parseInt(document.getElementById("sore").value, 10); const actualRIR = document.getElementById("actualRIR").value; const perfRadio = document.querySelector('input[name="perf"]:checked'); const performance = perfRadio ? parseInt(perfRadio.value, 10) : 2; // Validate inputs if (!muscle || isNaN(mmc) || isNaN(pump) || isNaN(workload)) { alert("Please fill in all required fields"); return; } // Process with RP algorithms const stimulusResult = scoreStimulus({ mmc, pump, disruption: workload }); const progressionResult = setProgressionAlgorithm(soreness, performance); const volumeProgression = getVolumeProgression(muscle, { stimulus: { mmc, pump, disruption: workload }, soreness, performance, hasIllness: false, }); // Validate RIR if provided let rirValidation = null; if (actualRIR) { rirValidation = validateEffortLevel(parseFloat(actualRIR)); } // Apply changes if (progressionResult.setChange !== -99) { trainingState.addSets(muscle, progressionResult.setChange); } // Display results const output = document.getElementById("mevOut"); let html = ` <div class="feedback-results"> <div class="main-recommendation"> <h4>${muscle} Recommendation</h4> <p class="advice">${volumeProgression.advice}</p> <p class="sets-info"> ${volumeProgression.currentSets} → ${volumeProgression.projectedSets} sets ${volumeProgression.setChange !== 0 ? `(${volumeProgression.setChange > 0 ? "+" : ""}${volumeProgression.setChange})` : ""} </p> </div> <div class="algorithm-details"> <div> <strong>Stimulus:</strong> ${stimulusResult.score}/9 <span class="stimulus-${stimulusResult.action}">(${stimulusResult.action.replace("_", " ")})</span> </div> <div> <strong>Volume Status:</strong> ${volumeProgression.volumeStatus} </div> <div> <strong>RP Progression:</strong> ${progressionResult.advice} </div> </div> </div> `; if (rirValidation) { html += ` <div class="rir-feedback ${rirValidation.urgency}"> <strong>RIR Check:</strong> ${rirValidation.feedback}<br> <em>${rirValidation.recommendation}</em> </div> `; } if (volumeProgression.deloadRecommended) { html += ` <div class="deload-warning"> ⚠️ <strong>Deload Recommended</strong> </div> `; } output.innerHTML = html; output.className = "result success active"; updateChart(); }; window.analyzeDeload = function () { const halfMuscles = document.getElementById("halfMuscles").checked; const mrvBreach = document.getElementById("mrvBreach").checked; const illness = document.getElementById("illness").checked; const lowMotivation = document.getElementById("lowMotivation").checked; const analysis = analyzeDeloadNeed(); // Override with manual inputs if (halfMuscles) analysis.reasons.push("Most muscles need recovery (manual check)"); if (mrvBreach) analysis.reasons.push("Hit MRV twice consecutively (manual check)"); if (illness) analysis.reasons.push("Illness/injury present"); if (lowMotivation) analysis.reasons.push("Low motivation levels"); const shouldDeload = analysis.shouldDeload || halfMuscles || mrvBreach || illness || lowMotivation; const output = document.getElementById("deloadOut"); if (shouldDeload) { output.innerHTML = ` <strong>Deload Recommended</strong><br> Reasons: ${analysis.reasons.join(", ")}<br> <em>Take 1 week at 50% volume and 50% of normal load</em> `; output.className = "result warning active"; // Offer to start deload setTimeout(() => { if ( confirm( "Start deload phase now? This will reduce all muscle volumes to 50% of MEV and loads to 50% of normal.", ) ) { trainingState.startDeload(); updateChart(); } }, 1000); } else { output.innerHTML = "No deload needed - continue current program"; output.className = "result success active"; } }; window.analyzeFrequency = function () { const soreDays = parseInt(document.getElementById("soreDays").value, 10); const sessionGap = parseInt(document.getElementById("sessionGap").value, 10); const trainingAge = document.getElementById("trainingAge").value; const muscle = document.getElementById("muscleSelect").value; const analysis = analyzeFrequency(soreDays, sessionGap, muscle); const optimal = calculateOptimalFrequency(muscle, { trainingAge, currentVolume: trainingState.currentWeekSets[muscle], }); const output = document.getElementById("freqOut"); output.innerHTML = ` <strong>${analysis.recommendation}</strong><br> Current: ${sessionGap} days between sessions<br> Recovery: ${soreDays} days<br> Optimal frequency: ${optimal.recommendedFrequency}x/week (${optimal.setsPerSession} sets/session) `; const type = analysis.urgency === "high" ? "warning" : analysis.urgency === "medium" ? "warning" : "success"; output.className = `result ${type} active`; }; window.saveLandmarks = function () { const muscle = document.getElementById("landmarkMuscle").value; const mv = parseInt(document.getElementById("mv").value, 10); const mev = parseInt(document.getElementById("mev").value, 10); const mav = parseInt(document.getElementById("mav").value, 10); const mrv = parseInt(document.getElementById("mrv").value, 10); // Validate relationships if (mv > mev || mev > mav || mav > mrv) { alert("Invalid landmark relationship (MV ≤ MEV ≤ MAV ≤ MRV)"); return; } trainingState.updateVolumeLandmarks(muscle, { MV: mv, MEV: mev, MAV: mav, MRV: mrv, }); updateChart(); const output = document.getElementById("volumeOut"); output.innerHTML = `Landmarks saved for ${muscle}: MV:${mv}, MEV:${mev}, MAV:${mav}, MRV:${mrv}`; output.className = "result success active"; }; window.setupMeso = function () { const length = parseInt(document.getElementById("mesoLength").value, 10); const week = parseInt(document.getElementById("currentWeekNum").value, 10); const goal = document.getElementById("trainingGoal").value; const validation = validateMesocycleLength(length, goal); if (!validation.isValid) { alert(validation.warning); return; } trainingState.mesoLen = length; trainingState.weekNo = week; trainingState.saveState(); const output = document.getElementById("mesoOut"); output.innerHTML = ` Mesocycle configured: ${length} weeks for ${goal}<br> Currently week ${week} (Target RIR: ${trainingState.getTargetRIR().toFixed(1)})<br> ${validation.recommendation} `; output.className = "result success active"; }; /* ----- week progression helpers ----- */ window.advanceToNextWeek = function () { trainingState.nextWeek(); updateChart(); updateAllDisplays(); const summary = trainingState.getStateSummary(); const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut"); output.innerHTML = ` <div class="auto-progression-result"> <h4>📅 Advanced to Week ${summary.week}</h4> <div class="progression-details"> <div>Week: ${summary.week} of ${summary.meso}</div> <div>Block: ${summary.block}</div> <div>Target RIR: ${summary.targetRIR.toFixed(1)}</div> <div>Phase: ${summary.currentPhase}</div> </div> </div> `; output.className = "result success active"; debugLog("Advanced to next week:", summary); }; /* ----- initialization helpers ----- */ window.initializeAllMusclesAtMEV = function () { const muscles = Object.keys(trainingState.volumeLandmarks); muscles.forEach((muscle) => { trainingState.initializeMuscleAtMEV(muscle); }); updateChart(); const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut"); output.innerHTML = ` <div class="auto-progression-result"> <h4>🎯 All muscles initialized at MEV</h4> <div class="progression-details"> ${muscles .map( (muscle) => `<div>${muscle}: ${trainingState.volumeLandmarks[muscle].MEV} sets (MEV)</div>`, ) .join("")} </div> </div> `; output.className = "result success active"; debugLog("All muscles initialized at MEV"); }; /* ----- auto-volume progression demo function ----- */ window.runAutoVolumeProgression = function () { // Demo: simulate weekly feedback for all muscles const weeklyFeedback = {}; const muscles = Object.keys(trainingState.volumeLandmarks); muscles.forEach((muscle) => { const currentSets = trainingState.getWeeklySets(muscle); const landmarks = trainingState.volumeLandmarks[muscle]; const volumeStatus = trainingState.getVolumeStatus(muscle); // Generate adaptive feedback based on volume status let stimulus, soreness, perf; if (volumeStatus === "under-minimum" || volumeStatus === "maintenance") { // Low volume = good recovery, potentially low stimulus stimulus = Math.floor(Math.random() * 4) + 2; // 2-5 (moderate to low) soreness = Math.floor(Math.random() * 2); // 0-1 (low) perf = Math.floor(Math.random() * 2) + 1; // 1-2 (same to better) } else if (volumeStatus === "optimal") { // Optimal volume = moderate stimulus, manageable fatigue stimulus = Math.floor(Math.random() * 3) + 4; // 4-6 (moderate) soreness = Math.floor(Math.random() * 2) + 1; // 1-2 (mild to moderate) perf = Math.floor(Math.random() * 2) + 1; // 1-2 (same to better) } else if (volumeStatus === "high") { // High volume = good stimulus but building fatigue stimulus = Math.floor(Math.random() * 3) + 5; // 5-7 (moderate to high) soreness = Math.floor(Math.random() * 2) + 1; // 1-2 (mild to moderate) perf = Math.floor(Math.random() * 3); // 0-2 (worse to better) } else { // maximum // At MRV = high fatigue, may need recovery stimulus = Math.floor(Math.random() * 4) + 4; // 4-7 (variable) soreness = Math.floor(Math.random() * 2) + 2; // 2-3 (moderate to high) perf = Math.floor(Math.random() * 2); // 0-1 (worse to same) } // Generate enhanced fatigue indicators let jointAche = 0; let perfChange = 0; let lastLoad = 100; // Default baseline // Higher volume status = more likely to have joint issues and performance drops if (volumeStatus === "maximum") { jointAche = Math.floor(Math.random() * 3) + 1; // 1-3 (mild to pain) perfChange = Math.random() > 0.6 ? -1 : 0; // 40% chance of performance drop lastLoad = 95; // Simulate strength drop } else if (volumeStatus === "high") { jointAche = Math.floor(Math.random() * 2); // 0-1 (none to mild) perfChange = Math.random() > 0.8 ? -1 : Math.random() > 0.5 ? 0 : 1; // Mixed performance lastLoad = 98; // Slight strength drop } else { jointAche = Math.floor(Math.random() * 2); // 0-1 (none to mild) perfChange = Math.random() > 0.7 ? 1 : 0; // 30% chance of PR lastLoad = 102; // Strength increase } weeklyFeedback[muscle] = { stimulus, soreness, perf, jointAche, perfChange, lastLoad, pump: Math.floor(stimulus / 3), // Derive pump from stimulus disruption: Math.floor(stimulus / 3), // Derive workload from stimulus recoverySession: soreness >= 3 || (volumeStatus === "maximum" && Math.random() < 0.3), }; }); // Process auto-progression const result = processWeeklyVolumeProgression(weeklyFeedback, trainingState); // Update chart updateChart(); // Show notification const message = result.deloadTriggered ? `🛑 ${result.recommendation} (${result.mrvHits} muscles at MRV)` : `📈 Auto-progression complete (+${Object.values(result.progressionLog).reduce((sum, log) => sum + log.increment, 0)} total sets)`; const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut") || document.createElement("div"); const progressionDetails = Object.entries(result.progressionLog) .map( ([muscle, log]) => `<div>${muscle}: ${log.previousSets} → ${log.currentSets} sets (${log.reason})</div>`, ) .join(""); output.innerHTML = ` <div class="auto-progression-result"> <h4>${message}</h4> <div class="progression-details"> ${progressionDetails} </div> </div> `; output.className = result.deloadTriggered ? "result warning active" : "result success active"; debugLog("Auto-progression result:", result); }; /* ----- RIR Schedule & Load Feedback Functions ----- */ window.runWeeklyLoadAdjustments = function () { const muscles = Object.keys(trainingState.volumeLandmarks); const currentWeek = trainingState.weekNo; // Simulate weekly RIR feedback const weeklyRIRFeedback = simulateWeeklyRIRFeedback(muscles, currentWeek); // Process load adjustments const adjustmentResult = processWeeklyLoadAdjustments(weeklyRIRFeedback); // Update display const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut") || document.createElement("div"); const adjustmentDetails = Object.entries(adjustmentResult.adjustments) .map( ([muscle, adj]) => `<div class="load-adjustment ${adj.urgency}"> <strong>${muscle}:</strong> ${adj.loadAdjustment > 0 ? "+" : ""}${adj.loadAdjustment.toFixed(1)}% (${adj.currentRIR.toFixed(1)} vs ${adj.targetRIR.toFixed(1)} RIR) <div class="adjustment-reason">${adj.reason}</div> </div>`, ) .join(""); output.innerHTML = ` <div class="auto-progression-result"> <h4>⚖️ Weekly Load Adjustments - Week ${adjustmentResult.week}</h4> <div class="rir-summary"> <div>Target RIR: ${adjustmentResult.targetRIR.toFixed(1)}</div> <div>Muscles Adjusted: ${adjustmentResult.summary.musclesAdjusted}/${adjustmentResult.summary.totalMuscles}</div> <div>Avg Load Change: ${adjustmentResult.summary.avgLoadChange > 0 ? "+" : ""}${adjustmentResult.summary.avgLoadChange.toFixed(1)}%</div> </div> <div class="load-adjustments"> ${adjustmentDetails} </div> </div> `; output.className = "result success active"; debugLog("Weekly load adjustments:", adjustmentResult); }; window.showNextWeekLoadProgression = function () { const muscles = Object.keys(trainingState.volumeLandmarks); const progressions = []; muscles.forEach((muscle) => { // Simulate session history for the muscle const sessionHistory = { averageRIR: getScheduledRIR(trainingState.weekNo, trainingState.mesoLen) + (Math.random() * 2 - 1), }; const progression = getLoadProgression(muscle, sessionHistory); progressions.push(progression); }); const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut") || document.createElement("div"); const progressionDetails = progressions .map( (prog) => `<div class="load-progression"> <strong>${prog.muscle}:</strong> ${prog.loadIncrease > 0 ? "+" : ""}${prog.loadIncrease}% (${prog.currentRIR.toFixed(1)} → ${prog.nextRIR.toFixed(1)} RIR) <div class="progression-recommendation">${prog.recommendation}</div> </div>`, ) .join(""); const nextWeek = trainingState.weekNo + 1; const nextRIR = getScheduledRIR(nextWeek, trainingState.mesoLen); output.innerHTML = ` <div class="auto-progression-result"> <h4>📈 Load Progression for Week ${nextWeek}</h4> <div class="rir-summary"> <div>Next Week Target RIR: ${nextRIR.toFixed(1)}</div> <div>Total Muscles: ${progressions.length}</div> <div>Avg Load Increase: +${(progressions.reduce((sum, p) => sum + p.loadIncrease, 0) / progressions.length).toFixed(1)}%</div> </div> <div class="load-progressions"> ${progressionDetails} </div> </div> `; output.className = "result success active"; debugLog("Next week load progressions:", progressions); }; window.showRIRSchedule = function () { const mesoLength = trainingState.mesoLen; const currentWeek = trainingState.weekNo; const schedule = []; for (let week = 1; week <= mesoLength; week++) { const scheduledRIR = getScheduledRIR(week, mesoLength); const isCurrent = week === currentWeek; schedule.push({ week, rir: scheduledRIR, isCurrent, intensity: scheduledRIR >= 2.5 ? "Low" : scheduledRIR >= 2.0 ? "Moderate" : scheduledRIR >= 1.0 ? "High" : "Maximum", }); } const output = document.getElementById("autoVolumeOut") || document.getElementById("volumeOut") || document.createElement("div"); const scheduleDisplay = schedule .map( (item) => `<div class="rir-week ${item.isCurrent ? "current-week" : ""}"> <strong>Week ${item.week}:</strong> ${item.rir.toFixed(1)} RIR (${item.intensity}) ${item.isCurrent ? " ← Current" : ""} </div>`, ) .join(""); output.innerHTML = ` <div class="auto-progression-result"> <h4>📅 RIR Schedule - ${mesoLength} Week Mesocycle</h4> <div class="rir-schedule"> ${scheduleDisplay} </div> <div class="schedule-notes"> <div>• Scheduled progression follows RP guidelines</div> <div>• Lower RIR = Higher intensity (closer to failure)</div> <div>• Deload after final week</div> </div> </div> `; output.className = "result success active"; debugLog("RIR Schedule:", schedule); }; /* ----- Advanced Intelligence UI Functions ----- */ // Live Performance Monitoring let sessionActive = false; let currentSetNumber = 0; window.startLiveSession = function () { const exercise = document.getElementById("liveExercise").value; const muscle = document.getElementById("liveMuscle").value; const plannedSets = parseInt(document.getElementById("plannedSets").value); const targetRIR = trainingState.getTargetRIR(); const result = liveMonitor.startSession({ muscle: muscle, exercise: exercise, plannedSets: plannedSets, targetRIR: targetRIR, }); sessionActive = true; currentSetNumber = 0; // Update UI document.getElementById("startSessionBtn").style.display = "none"; document.getElementById("logSetBtn").style.display = "inline-block"; document.getElementById("endSessionBtn").style.display = "inline-block"; document.getElementById("liveMonitor").style.display = "block"; const output = document.getElementById("liveMonitorOut"); output.innerHTML = `<strong>🎮 Live Session Started!</strong><br>${result.message}<br><br>Target RIR: ${targetRIR}<br>Planned Sets: ${plannedSets}`; output.className = "result success active"; }; window.logTrainingSet = function () { if (!sessionActive) { alert("Please start a session first!"); return; } currentSetNumber++; // Simulate realistic set data (in real app, this would come from user input) const setData = { weight: 80 + (Math.random() * 10 - 5), // 75-85kg range reps: 8 + Math.floor(Math.random() * 3), // 8-10 reps rir: 1.5 + Math.random() * 1, // 1.5-2.5 RIR rpe: null, techniqueRating: 7 + Math.floor(Math.random() * 3), // 7-9 rating notes: `Set ${currentSetNumber} - simulated`, }; const result = liveMonitor.logSet(setData); // Update live display updateLiveDisplay({ sessionProgress: liveMonitor.getSessionProgress(), setInfo: { rir: setData.rir }, }); // Show feedback showSetFeedback(result); }; window.endLiveSession = function () { if (!sessionActive) { alert("No active session to end!"); return; } const summary = liveMonitor.endSession(); sessionActive = false; currentSetNumber = 0; // Update UI document.getElementById("startSessionBtn").style.display = "inline-block"; document.getElementById("logSetBtn").style.display = "none"; document.getElementById("endSessionBtn").style.display = "none"; document.getElementById("liveMonitor").style.display = "none"; showSessionSummary(summary); }; function updateLiveDisplay(data) { if (data.sessionProgress) { document.getElementById("currentSet").textContent = data.sessionProgress.completedSets; document.getElementById("sessionProgress").textContent = Math.round(data.sessionProgress.progressPercentage) + "%"; document.getElementById("totalLoad").textContent = data.sessionProgress.totalLoad; } if (data.setInfo) { document.getElementById("currentRIR").textContent = data.setInfo.rir.toFixed(1); } } function showSetFeedback(data) { const output = document.getElementById("liveMonitorOut"); output.className = `result ${data.feedback.type} active`; let html = `<strong>Set ${currentSetNumber} Feedback:</strong><br>`; html += `${data.feedback.message}<br><br>`; if (data.nextSetRecommendations.rationale.length > 0) { html += `<strong>Next Set Recommendations:</strong><br>`; html += `Weight: ${data.nextSetRecommendations.weight}kg<br>`; html += `Rest: ${data.nextSetRecommendations.rest}<br>`; html += `Strategy: ${data.nextSetRecommendations.strategy}<br>`; html += `Rationale: ${data.nextSetRecommendations.rationale.join(", ")}<br>`; } output.innerHTML = html; } function showSessionSummary(data) { const output = document.getElementById("liveMonitorOut"); output.className = "result success active"; let html = `<strong>🎯 Session Complete!</strong><br><br>`; html += `<strong>Performance Grade:</strong> ${data.performance.targetAchievement.grade}<br>`; html += `<strong>Consistency Rating:</strong> ${data.performance.consistency.rating}<br>`; html += `<strong>Total Load:</strong> ${data.progress.totalLoad}<br>`; html += `<strong>Duration:</strong> ${data.progress.duration} minutes<br><br>`; if (data.recommendations.length > 0) { html += `<strong>Recommendations:</strong><br>`; data.recommendations.forEach((rec) => { html += `• ${rec.message}<br>`; }); } output.innerHTML = html; } // Intelligence Hub Functions window.initializeIntelligence = function () { const output = document.getElementById("intelligenceOut"); output.innerHTML = '<div class="loading"></div> Initializing Advanced Training Intelligence...'; output.className = "result active"; setTimeout(() => { const result = advancedIntelligence.initialize(); let html = "<strong>🧠 Intelligence System Initialized!</strong><br><br>"; html += `<strong>Analytics:</strong> ${result.analytics ? "✅ Enabled" : "❌ Disabled (need more data)"}<br>`; html += `<strong>Exercise Selection:</strong> ${result.exerciseSelection ? "✅ Enabled" : "❌ Disabled"}<br>`; html += `<strong>Live Monitoring:</strong> ${result.liveMonitoring ? "✅ Enabled" : "❌ Disabled"}<br><br>`; html += `<strong>Status:</strong> ${result.message}`; // Update status indicators document.getElementById("analyticsStatus").textContent = result.analytics ? "✅" : "❌"; document.getElementById("exerciseStatus").textContent = result.exerciseSelection ? "✅" : "❌"; document.getElementById("liveStatus").textContent = result.liveMonitoring ? "✅" : "❌"; document.getElementById("hubStatus").textContent = "✅"; output.className = "result success active"; output.innerHTML = html; }, 1500); }; window.getWeeklyIntelligence = function () { const output = document.getElementById("intelligenceOut"); output.innerHTML = '<div class="loading"></div> Generating weekly intelligence report...'; output.className = "result active"; setTimeout(() => { const intelligence = advancedIntelligence.getWeeklyIntelligence(); let html = "<strong>📈 Weekly Intelligence Report</strong><br><br>"; html += `<strong>Week:</strong> ${intelligence.week}, Block: ${intelligence.block}<br><br>`; if (intelligence.recommendations.length > 0) { html += "<strong>🎯 Recommendations:</strong><br>"; intelligence.recommendations.forEach((rec) => { html += `• [${rec.urgency.toUpperCase()}] ${rec.message}<br>`; }); html += "<br>"; } if (intelligence.optimizations.length > 0) { html += "<strong>🔧 Available Optimizations:</strong><br>"; intelligence.optimizations.forEach((opt) => { html += `• ${opt.type}: ${opt.recommendation || opt.muscle}<br>`; }); html += "<br>"; } if (intelligence.riskAssessment) { html += `<strong>⚠️ Risk Level:</strong> ${intelligence.riskAssessment.riskLevel.toUpperCase()}<br>`; html += `<strong>Risk Score:</strong> ${intelligence.riskAssessment.riskScore}/100<br>`; } // Show in intelligence panel document.getElementById("intelligencePanel").style.display = "block"; document.getElementById("intelligenceContent").innerHTML = ` <div class="recommendation"> <strong>📊 Current Assessment</strong><br> Week ${intelligence.week} analysis shows ${intelligence.recommendations.length} active recommendations and ${intelligence.optimizations.length} optimization opportunities. </div> `; output.className = "result success active"; output.innerHTML = html; }, 2000); }; window.getOptimalExercises = function () { const output = document.getElementById("intelligenceOut"); output.innerHTML = '<div class="loading"></div> Analyzing optimal exercises for current training state...'; output.className = "result active"; setTimeout(() => { const muscle = "Chest"; // Example muscle const exercises = selectOptimalExercises(muscle, { availableEquipment: ["barbell", "dumbbells", "cables"], trainingGoal: "hypertrophy", experienceLevel: "intermediate", fatigueLevel: 4, timeConstraint: "moderate", }); let html = "<strong>💡 Smart Exercise Recommendations</strong><br><br>"; html += `<strong>For ${muscle}:</strong><br>`; exercises.slice(0, 3).forEach((exercise, index) => { html += `${index + 1}. <strong>${exercise.name}</strong> (Score: ${exercise.score.toFixed(1)})<br>`; html += ` Sets: ${exercise.sets}, Reps: ${exercise.repRange[0]}-${exercise.repRange[1]}<br>`; html += ` ${exercise.reasoning}<br><br>`; }); output.className = "result success active"; output.innerHTML = html; }, 1500); }; window.assessTrainingRisk = function () { const output = document.getElementById("intelligenceOut"); output.innerHTML = '<div class="loading"></div> Assessing training risk factors...'; output.className = "result active"; setTimeout(() => { const riskAssessment = advancedIntelligence.assessTrainingRisk(); let html = "<strong>⚠️ Training Risk Assessment</strong><br><br>"; html += `<strong>Risk Score:</strong> ${riskAssessment.riskScore}/100<br>`; html += `<strong>Risk Level:</strong> ${riskAssessment.riskLevel.toUpperCase()}<br><br>`; if (riskAssessment.riskFactors.length > 0) { html += "<strong>Risk Factors:</strong><br>"; riskAssessment.riskFactors.forEach((factor) => { html += `• ${factor}<br>`; }); html += "<br>"; } if (riskAssessment.recommendations.length > 0) { html += "<strong>Recommendations:</strong><br>"; riskAssessment.recommendations.forEach((rec) => { html += `• ${rec}<br>`; }); } const urgency = riskAssessment.riskLevel === "low" ? "success" : riskAssessment.riskLevel === "moderate" ? "warning" : "error"; output.className = `result ${urgency} active`; output.innerHTML = html; }, 2000); }; // Analytics Functions window.optimizeVolumeLandmarks = function () { const output = document.getElementById("analyticsOut"); output.innerHTML = '<div class="loading"></div> Analyzing historical data for volume optimization...'; output.className = "result active"; setTimeout(() => { // Mock historical data for demo const mockHistoricalData = [ { sets: 8, avgStimulus: 7, avgFatigue: 2, performanceChange: 1 }, { sets: 10, avgStimulus: 8, avgFatigue: 3, performanceChange: 1 }, { sets: 12, avgStimulus: 8, avgFatigue: 4, performanceChange: 0 }, { sets: 14, avgStimulus: 7, avgFatigue: 6, performanceChange: -1 }, ]; const optimized = optimizeVolumeLandmarks("Chest", mockHistoricalData); let html = "<strong>📊 Volume Landmark Optimization Results:</strong><br><br>"; html += `<strong>Optimized Landmarks for Chest:</strong><br>`; html += `MEV: ${optimized.MEV} sets<br>`; html += `MAV: ${optimized.MAV} sets<br>`; html += `MRV: ${optimized.MRV} sets<br><br>`; html += `<strong>Confidence:</strong> ${optimized.confidence}%<br>`; output.className = "result success active"; output.innerHTML = html; }, 2000); }; window.predictDeloadTiming = function () { const output = document.getElementById("analyticsOut"); output.innerHTML = '<div class="loading"></div> Analyzing fatigue patterns and performance trends...'; output.className = "result active"; setTimeout(() => { const mockMetrics = { weeklyFatigueScore: [3, 4, 6, 7], performanceTrend: [85, 82, 78, 75], volumeProgression: [40, 44, 48, 52], motivationLevel: 6, sleepQuality: 7, }; const prediction = analyticsDeloadPredictor(mockMetrics); let html = "<strong>🔮 Deload Prediction Analysis:</strong><br><br>"; html += `<strong>Weeks Until Deload:</strong> ${prediction.weeksUntilDeload}<br>`; html += `<strong>Confidence:</strong> ${prediction.confidence}%<br>`; html += `<strong>Primary Indicator:</strong> ${prediction.primaryIndicator}<br>`; html += `<strong>Recommended Action:</strong> ${prediction.recommendedAction}<br>`; const urgency = prediction.weeksUntilDeload <= 2 ? "warning" : "success"; output.className = `result ${urgency} active`; output.innerHTML = html; }, 2500); }; window.detectPlateaus = function () { const output = document.getElementById("analyticsOut"); output.innerHTML = '<div class="loading"></div> Analyzing training plateaus and stagnation patterns...'; output.className = "result active"; setTimeout(() => { const mockTrainingData = { weeklyPerformance: [85, 84, 83, 83, 82, 82], weeklyVolume: [45, 47, 48, 48, 48, 48], weeklyIntensity: [7, 7.5, 8, 8, 8, 8], weeklyFatigue: [3, 4, 5, 6, 7, 8], }; const plateauAnalysis = detectTrainingPlateaus(mockTrainingData); let html = "<strong>📈 Plateau Detection Results:</strong><br><br>"; if (plateauAnalysis.plateauDetected) { html += `<strong>🚨 Plateau Detected:</strong> ${plateauAnalysis.plateauType}<br>`; html += `<strong>Urgency Level:</strong> ${plateauAnalysis.urgency}<br><br>`; html += `<strong>💡 Recommended Interventions:</strong><br>`; plateauAnalysis.interventions.forEach((intervention) => { html += `• ${intervention}<br>`; }); output.className = "result warning active"; } else { html += `<strong>✅ No Plateau Detected</strong><br>`; html += `Training progression appears healthy.<br><br>`; html += `Continue current program with monitoring.`; output.className = "result success active"; } output.innerHTML = html; }, 2000); }; window.getAdaptiveRIR = function () { const output = document.getElementById("analyticsOut"); output.innerHTML = '<div class="loading"></div> Analyzing RIR patterns for personalized recommendations...'; output.className = "result active"; setTimeout(() => { const mockRIRHistory = [ { actualRIR: 2.5, targetRIR: 2, nextDayFatigue: 3, recoveryDays: 2 }, { actualRIR: 1.5, targetRIR: 1, nextDayFatigue: 4, recoveryDays: 3 }, { actualRIR: 3, targetRIR: 2, nextDayFatigue: 2, recoveryDays: 1 }, ]; const adaptiveRIR = adaptiveRIRRecommendations("Chest", mockRIRHistory); let html = "<strong>🎛️ Adaptive RIR Recommendations:</strong><br><br>"; html += `<strong>Recommended RIR:</strong> ${adaptiveRIR.recommendedRIR}<br>`; html += `<strong>Confidence:</strong> ${adaptiveRIR.confidence}%<br>`; html += `<strong>Reasoning:</strong> ${adaptiveRIR.reasoning}<br><br>`; html += `<strong>Personalization Notes:</strong><br>`; adaptiveRIR.personalizedFactors.forEach((factor) => { html += `• ${factor}<br>`; }); output.className = "result success active"; output.innerHTML = html; }, 1500); }; // Program Generator Function window.generateWeeklyProgram = function () { const output = document.getElementById("programOut"); output.innerHTML = '<div class="loading"></div> Generating intelligent weekly program...'; output.className = "result active"; setTimeout(() => { const days = parseInt(document.getElementById("programDays").value); const split = document.getElementById("programSplit").value; const sessionTime = parseInt(document.getElementById("sessionTime").value); const experience = document.getElementById("experienceLevel").value; const program = generateProgram({ daysPerWeek: days, splitType: split, experienceLevel: experience, timePerSession: sessionTime, }); let html = "<strong>📋 Generated Weekly Program:</strong><br><br>"; html += `<strong>Split Type:</strong> ${program.splitType}<br>`; html += `<strong>Days Per Week:</strong> ${program.daysPerWeek}<br><br>`; program.sessions.forEach((session) => { html += `<strong>Day ${session.day}: ${session.name}</strong><br>`; session.exercises.forEach((exercise) => { html += `• ${exercise.exercise} - ${exercise.sets} sets x ${exercise.reps[0]}-${exercise.reps[1]} reps<br>`; }); html += "<br>"; }); output.className = "result success active"; output.innerHTML = html; }, 2000); }; /* ----- new utility system functions ----- */ // Data Export Functions window.exportAllData = function (format = "json") { const result = dataExportManager.exportAllData(format, { includePersonalData: true, includeAnalytics: true, includeWellness: true, }); if (result.success) { debugLog(`✅ Data exported successfully: ${result.filename}`); showSystemMessage( `📤 Data exported: ${result.filename} (${(result.size / 1024).toFixed(1)}KB)`, "success", ); } else { console.error("❌ Export failed:", result.error); showSystemMessage(`❌ Export failed: ${result.error}`, "error"); } }; window.createBackup = function () { const result = dataExportManager.createAutoBackup(); if (result.success) { debugLog("✅ Backup created:", result.backupKey); showSystemMessage( `💾 Backup created successfully (${result.dataPoints} data points)`, "success", ); } else { console.error("❌ Backup failed:", result.error); showSystemMessage(`❌ Backup failed: ${result.error}`, "error"); } }; window.viewBackups = function () { const backups = dataExportManager.getAvailableBackups(); let html = "<strong>📦 Available Backups:</strong><br><br>"; if (backups.length === 0) { html += "<p>No backups available. Create your first backup!</p>"; } else { backups.forEach((backup) => { const date = new Date(backup.date).toLocaleString(); const size = (backup.size / 1024).toFixed(1); html += `<div style="margin: 10px 0; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 8px;">`; html += `<strong>📅 ${date}</strong><br>`; html += `📊 ${backup.dataPoints} data points | 💾 ${size}KB<br>`; html += `<button onclick="restoreBackup('${backup.key}')" style="margin-top: 5px; padding: 5px 10px; background: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer;">Restore</button>`; html += `</div>`; }); } const output = document.getElementById("backupResults") || createSystemOutput("backupResults"); output.innerHTML = html; output.className = "result active"; }; window.restoreBackup = function (backupKey) { if (confirm("⚠️ This will overwrite your current data. Are you sure?")) { const result = dataExportManager.restoreFromBackup(backupKey); if (result.success) { showSystemMessage( "✅ Backup restored successfully! Refreshing page...", "success", ); setTimeout(() => location.reload(), 2000); } else { showSystemMessage(`❌ Restore failed: ${result.error}`, "error"); } } }; // Performance Functions window.getPerformanceReport = function () { const report = performanceManager.generatePerformanceReport(); let html = "<strong>⚡ Performance Report:</strong><br><br>"; html += `<strong>📊 Load Performance:</strong><br>`; html += `• Average Load Time: ${Math.round(report.performance.averageLoadTime)}ms<br>`; html += `• 95th Percentile: ${Math.round(report.performance.loadTimeP95)}ms<br><br>`; html += `<strong>💾 Memory Usage:</strong><br>`; html += `• Current: ${report.memory.currentUsage.toFixed(1)}MB<br>`; html += `• Peak: ${report.memory.peakUsage.toFixed(1)}MB<br><br>`; html += `<strong>🖱️ Interactions:</strong><br>`; html += `• Total: ${report.interactions.totalInteractions}<br>`; html += `• Average Delay: ${Math.round(report.interactions.averageDelay)}ms<br><br>`; if (report.recommendations.length > 0) { html += `<strong>💡 Recommendations:</strong><br>`; report.recommendations.forEach((rec) => { const priority = rec.priority === "high" ? "🔴" : rec.priority === "medium" ? "🟡" : "🟢"; html += `${priority} ${rec.message}<br>`; }); } const output = document.getElementById("performanceResults") || createSystemOutput("performanceResults"); output.innerHTML = html; output.className = "result active"; }; window.clearPerformanceData = function () { if (confirm("Clear all performance monitoring data?")) { performanceManager.clearOldMetrics(); localStorage.removeItem("performance-issues"); showSystemMessage("🧹 Performance data cleared", "success"); } }; // User Feedback Functions window.openFeedbackWidget = function () { userFeedbackManager.openFeedbackPanel(); }; window.getUserAnalytics = function () { const analytics = userFeedbackManager.generateAnalyticsDashboard(); let html = "<strong>📈 Usage Analytics:</strong><br><br>"; html += `<strong>📱 Usage Stats:</strong><br>`; html += `• Total Sessions: ${analytics.usage.totalSessions}<br>`; html += `• Average Duration: ${analytics.usage.averageSessionDuration} minutes<br>`; html += `• Features Used: ${analytics.usage.featuresUsed}<br>`; html += `• Most Used: ${analytics.usage.mostUsedFeature}<br><br>`; if (analytics.feedback.totalFeedback > 0) { html += `<strong>💬 Feedback Summary:</strong><br>`; html += `• Total Feedback: ${analytics.feedback.totalFeedback}<br>`; html += `• Average Rating: ${analytics.feedback.averageRating}/5 ⭐<br><br>`; } if (analytics.insights.length > 0) { html += `<strong>💡 Insights:</strong><br>`; analytics.insights.forEach((insight) => { const icon = insight.type === "milestone" ? "🎉" : insight.type === "satisfaction" ? "⭐" : insight.type === "advanced" ? "🧠" : "💡"; html += `${icon} ${insight.message}<br>`; }); } const output = document.getElementById("analyticsResults") || createSystemOutput("analyticsResults"); output.innerHTML = html; output.className = "result active"; }; window.processWithRPAlgorithms = function () { debugLog("🧠 Processing with RP algorithms..."); if (!trainingState.currentExercise) { alert("Please select an exercise first"); return; } const exercise = trainingState.currentExercise; const currentVolume = trainingState.exerciseProgress[exercise]?.weeklyVolume || 0; const targetRIR = window.calculateTargetRIR?.( trainingState.currentWeek, trainingState.mesocycleLength, ) || 2; // Apply RP algorithm logic const recommendation = { sets: Math.ceil(currentVolume / 3), // Rough estimate reps: 8, load: "75-85% 1RM", rir: targetRIR, notes: `RP algorithm suggests ${targetRIR} RIR for week ${trainingState.currentWeek}`, }; // Update UI with recommendations const output = document.getElementById("output") || document.getElementById("liveSessionData"); if (output) { output.innerHTML += ` <div class="rp-recommendation"> <h4>RP Algorithm Recommendation</h4> <p><strong>Exercise:</strong> ${exercise}</p> <p><strong>Sets:</strong> ${recommendation.sets}</p> <p><strong>Reps:</strong> ${recommendation.reps}</p> <p><strong>Load:</strong> ${recommendation.load}</p> <p><strong>Target RIR:</strong> ${recommendation.rir}</p> <p><strong>Notes:</strong> ${recommendation.notes}</p> </div> `; } alert( `RP Algorithm recommendation: ${recommendation.sets} sets of ${recommendation.reps} reps at ${recommendation.load} with ${recommendation.rir} RIR`, ); }; /* ----- Authentication handlers removed import { signIn, signUp, signOut, onAuth, supa } from "../core/db.js"; const authEmail = document.getElementById("authEmail"); const authPass = document.getElementById("authPass"); function setAuthLoading(isLoading) { const spinner = document.getElementById("authSpinner"); const btnLogin = document.getElementById("btnLogin"); const btnSignUp = document.getElementById("btnSignUp"); if (!spinner || !btnLogin || !btnSignUp) return; spinner.style.display = isLoading ? "inline" : "none"; btnLogin.disabled = isLoading; btnSignUp.disabled = isLoading; } window.handleSignIn = async function () { const email = authEmail.value.trim(); const pass = authPass.value; setAuthLoading(true); const { error, data } = await signIn(email, pass); setAuthLoading(false); if (error) return alert(error.message); const modal = document.getElementById("authModal"); debugLog("signIn authModal:", mo