feat: duplicate detection + mark-as-duplicate, lt-toggle preferences in settings

- Dependencies tab: auto-loads potential duplicates via /api/check_duplicates.php
  on first activation; shows 'Mark duplicate' button per result which POSTs to
  ticket_dependencies with type=duplicates and refreshes the dependencies list
- Settings modal: replaced checkboxes with lt-toggle switches for
  notifications_enabled and sound_effects; loads current user prefs on modal open
  and saves via /api/user_preferences.php on SAVE button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 17:25:58 -04:00
parent 3c29c6ee6f
commit c15defc09b
2 changed files with 125 additions and 0 deletions
+60
View File
@@ -702,6 +702,13 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
</div>
</div>
<!-- Potential Duplicates (loaded on first tab activation) -->
<div class="lt-frame lt-mb-md" id="potentialDupsFrame" style="display:none">
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
<div class="lt-section-header lt-text-amber">Potential Duplicates</div>
<div class="lt-section-body" id="potentialDupsList" aria-live="polite"></div>
</div>
<div class="lt-frame lt-mb-md">
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
<div class="lt-section-header">Current Dependencies</div>
@@ -833,6 +840,31 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
</div>
</div>
</div>
<div class="settings-section">
<h4 class="lt-subsection-header">Preferences</h4>
<div class="lt-kv-grid">
<div class="lt-kv-row">
<span class="lt-kv-label" id="settingNotifLabel">Notifications</span>
<span class="lt-kv-value">
<label class="lt-toggle" aria-labelledby="settingNotifLabel">
<input type="checkbox" id="settingNotificationsEnabled" checked>
<span class="lt-toggle-track"><span class="lt-toggle-thumb"></span></span>
<span class="lt-toggle-label lt-text-xs">Receive in-app notifications</span>
</label>
</span>
</div>
<div class="lt-kv-row">
<span class="lt-kv-label" id="settingSoundLabel">Sound effects</span>
<span class="lt-kv-value">
<label class="lt-toggle" aria-labelledby="settingSoundLabel">
<input type="checkbox" id="settingSoundEffects">
<span class="lt-toggle-track"><span class="lt-toggle-thumb"></span></span>
<span class="lt-toggle-label lt-text-xs">UI sound feedback</span>
</label>
</span>
</div>
</div>
</div>
<div class="settings-section">
<h4 class="lt-subsection-header">Keyboard Shortcuts</h4>
<div class="shortcuts-list lt-text-xs">
@@ -1028,9 +1060,37 @@ document.addEventListener('DOMContentLoaded', function () {
}
// Settings save/cancel
// Load user preference toggles on settings modal open
(function() {
fetch('/api/user_preferences.php', { credentials: 'same-origin' })
.then(function(r) { return r.json(); })
.then(function(d) {
if (!d.success || !d.preferences) return;
var notifEl = document.getElementById('settingNotificationsEnabled');
var soundEl = document.getElementById('settingSoundEffects');
if (notifEl && d.preferences.notifications_enabled !== undefined)
notifEl.checked = d.preferences.notifications_enabled == '1' || d.preferences.notifications_enabled === true;
if (soundEl && d.preferences.sound_effects !== undefined)
soundEl.checked = d.preferences.sound_effects == '1' || d.preferences.sound_effects === true;
}).catch(function() {});
})();
var saveSettingsBtn = document.getElementById('saveSettingsBtn');
if (saveSettingsBtn) {
saveSettingsBtn.addEventListener('click', function () {
// Save lt-toggle preferences
var notifEl = document.getElementById('settingNotificationsEnabled');
var soundEl = document.getElementById('settingSoundEffects');
var prefsToSave = {};
if (notifEl) prefsToSave.notifications_enabled = notifEl.checked ? '1' : '0';
if (soundEl) prefsToSave.sound_effects = soundEl.checked ? '1' : '0';
if (Object.keys(prefsToSave).length) {
fetch('/api/user_preferences.php', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': window.CSRF_TOKEN || '' },
body: JSON.stringify({ preferences: prefsToSave })
}).catch(function() {});
}
if (typeof saveSettings === 'function') saveSettings();
});
}