Source: 06-focus.js

/* ── Emergency Mode ── */

/**
 * True while the focus/emergency overlay is visible.
 * @type {boolean}
 */
let emergencyMode = false;

/**
 * Renders the checkpoint list inside the focus-mode overlay for the currently
 * active task. Hides the wrapper if the task has no checkpoints.
 * Each checkpoint cycles through three states on click: false → 'partial' → true.
 */
function renderEmergencyCps() {
  const wrap = document.getElementById('emergencyCpsWrap');
  const el = document.getElementById('emergencyCps');
  if (!wrap || !el) return;
  const entry = activeTimer ? entries.find((e) => e.id === activeTimer.entryId) : null;
  const todayKey = dk(new Date());
  const task = entry ? planTasks.find((t) => t.text === entry.text && t.date === todayKey) : null;
  const cps = task && Array.isArray(task.checkpoints) ? task.checkpoints : [];
  if (!cps.length) {
    wrap.style.display = 'none';
    return;
  }
  wrap.style.display = '';
  el.innerHTML = cps
    .map((cp, i) => {
      const isDone = cp.done === true;
      const isPartial = cp.done === 'partial';
      const stateClass = isDone ? ' cp-done' : isPartial ? ' cp-partial' : '';
      const symbol = isDone ? '✓' : isPartial ? '–' : '';
      return `<div class="emergency-cp-row">
        <div class="emergency-cp-check${stateClass}" data-tid="${task.id}" data-cidx="${i}">${symbol}</div>
        <span class="emergency-cp-text${stateClass}">${escHtml(cp.text)}</span>
      </div>`;
    })
    .join('');
  el.querySelectorAll('.emergency-cp-check').forEach((box) => {
    box.addEventListener('click', () => {
      const t = planTasks.find((t) => t.id === box.dataset.tid);
      if (!t || !t.checkpoints) return;
      const cur = t.checkpoints[parseInt(box.dataset.cidx)].done;
      t.checkpoints[parseInt(box.dataset.cidx)].done =
        cur === false ? 'partial' : cur === 'partial' ? true : false;
      savePlan();
      renderEmergencyCps();
      renderPlan();
    });
  });
}

/**
 * Activates focus/emergency mode: hides the main UI, shows the overlay,
 * moves the pomodoro section into the overlay, and focuses the next-action input.
 * The previously saved next-action note is restored if one exists for the active entry.
 */
function enterEmergency() {
  emergencyMode = true;
  document.body.classList.add('emergency');
  const entry = activeTimer ? entries.find((e) => e.id === activeTimer.entryId) : null;
  document.getElementById('emergencyTask').textContent = entry
    ? entry.text
    : 'No active task — start one first';
  // Restore any saved next action
  const saved = entry ? localStorage.getItem('wl_emergency_next_' + entry.id) || '' : '';
  document.getElementById('emergencyNext').value = saved;
  document.getElementById('emergencyNext').focus();
  renderEmergencyCps();
  // Move pomo below exit button
  document.getElementById('emergencyScreen').appendChild(document.querySelector('.pomo-section'));
}

/**
 * Deactivates focus/emergency mode: restores the main UI, saves the next-action
 * note, moves the pomodoro section back to its normal position, and auto-expands
 * the active task's checkpoint list so the user can pick up where they left off.
 */
function exitEmergency() {
  emergencyMode = false;
  document.body.classList.remove('emergency');
  // Save the next action note
  const entry = activeTimer ? entries.find((e) => e.id === activeTimer.entryId) : null;
  const note = document.getElementById('emergencyNext').value.trim();
  if (entry && note) localStorage.setItem('wl_emergency_next_' + entry.id, note);
  else if (entry) localStorage.removeItem('wl_emergency_next_' + entry.id);
  // Move pomo back to its original position after the Today's Flow section
  const anchor = document.getElementById('todayFlowSection');
  const pomo = document.querySelector('.pomo-section');
  if (anchor && anchor.parentNode && pomo) {
    anchor.parentNode.insertBefore(pomo, anchor.nextSibling);
  }
  // Auto-expand checkpoints for the active task so user can pick up where they left off
  if (entry) {
    const activeTask = planTasks.find(
      (t) =>
        t.text.toLowerCase() === entry.text.toLowerCase() &&
        Array.isArray(t.checkpoints) &&
        t.checkpoints.length > 0
    );
    if (activeTask) _cpOpenIds.add(activeTask.id);
  }
  renderPlan();
}

document.getElementById('emergencyBtn').addEventListener('click', () => {
  emergencyMode ? exitEmergency() : enterEmergency();
});
document.getElementById('emergencyExit').addEventListener('click', exitEmergency);
// Escape key exits emergency mode
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape' && emergencyMode) exitEmergency();
});

/* ── Transition handoff note ── */

/**
 * Shows the handoff-note text field in the timer bar so the user can record
 * what a future self (or colleague) should know before picking this task up again.
 */
function showHandoffInput() {
  document.getElementById('timerHandoff').classList.add('show');
  document.getElementById('timerHandoffLbl').classList.add('show');
  document.getElementById('timerHandoff').focus();
}

/** Hides and clears the handoff-note text field. */
function hideHandoffInput() {
  document.getElementById('timerHandoff').classList.remove('show');
  document.getElementById('timerHandoffLbl').classList.remove('show');
  document.getElementById('timerHandoff').value = '';
}

/**
 * Retrieves the stored handoff note for a given entry text.
 * The lookup is case-insensitive and trims whitespace.
 * @param {string} entryText - The entry text to look up.
 * @returns {string|null} The stored note, or null if none exists.
 */
function getHandoffNote(entryText) {
  try {
    const notes = JSON.parse(localStorage.getItem('wl_handoff') || '{}');
    return notes[entryText.toLowerCase().trim()] || null;
  } catch (e) {
    return null;
  }
}

/**
 * Persists a handoff note for a given entry text.
 * Pass an empty string or falsy value to delete the stored note.
 * The key is stored case-insensitively.
 * @param {string} entryText - The entry text to associate the note with.
 * @param {string} note - The note to save; falsy removes the stored note.
 */
function saveHandoffNote(entryText, note) {
  try {
    const notes = JSON.parse(localStorage.getItem('wl_handoff') || '{}');
    if (note) notes[entryText.toLowerCase().trim()] = note;
    else delete notes[entryText.toLowerCase().trim()];
    localStorage.setItem('wl_handoff', JSON.stringify(notes));
  } catch (e) {
    wlLog.warn('saveHandoffNote: failed to persist handoff note', e);
  }
}

// When stop is clicked: show handoff input, save note on confirm
document.getElementById('timerStop').removeEventListener('click', stopTimer);
document.getElementById('timerStop').addEventListener('click', () => {
  const handoffEl = document.getElementById('timerHandoff');
  if (!handoffEl.classList.contains('show')) {
    // First click — show handoff input
    showHandoffInput();
    document.getElementById('timerStop').textContent = 'done ✓';
  } else {
    // Second click — save note and stop
    const entry = activeTimer ? entries.find((e) => e.id === activeTimer.entryId) : null;
    const note = handoffEl.value.trim();
    if (entry) saveHandoffNote(entry.text, note);
    hideHandoffInput();
    document.getElementById('timerStop').textContent = 'stop';
    if (emergencyMode) exitEmergency();
    stopTimer();
  }
});
// Enter key on handoff input also confirms
document.getElementById('timerHandoff').addEventListener('keydown', (e) => {
  if (e.key === 'Enter') document.getElementById('timerStop').click();
  if (e.key === 'Escape') {
    hideHandoffInput();
    document.getElementById('timerStop').textContent = 'stop';
  }
});