Mass UI Updates

This commit is contained in:
2025-12-15 14:54:29 -06:00
parent cf1ffac9ee
commit 13bb6542bc
11 changed files with 3060 additions and 121 deletions
+267
View File
@@ -0,0 +1,267 @@
// User preferences management
// Stores preferences in the users collection PRISM column as JSON
// Uses "Job-Pages" key to avoid conflicts with other applications
/**
* Get user preferences from PRISM column
*/
async function getUserPreferences() {
try {
const user = pb.authStore.model;
if (!user) {
return getDefaultPreferences();
}
// Get current user record
const userRecord = await pb.collection('users').getOne(user.id);
// Parse PRISM JSON if it exists
let prism = {};
if (userRecord.PRISM) {
try {
prism = typeof userRecord.PRISM === 'string'
? JSON.parse(userRecord.PRISM)
: userRecord.PRISM;
} catch (e) {
console.warn('Error parsing PRISM data:', e);
prism = {};
}
}
// Get Job-Pages preferences (isolated from other apps)
const jobPagesPrefs = prism['Job-Pages'] || {};
// Merge with defaults
return {
darkMode: jobPagesPrefs.darkMode ?? false,
defaultView: jobPagesPrefs.defaultView ?? 'table'
};
} catch (error) {
console.error('Error loading preferences:', error);
return getDefaultPreferences();
}
}
/**
* Get default preferences
*/
function getDefaultPreferences() {
return {
darkMode: false,
defaultView: 'table'
};
}
/**
* Save user preferences to PRISM column
*/
async function saveUserPreferences(preferences) {
try {
const user = pb.authStore.model;
if (!user) {
throw new Error('User not authenticated');
}
// Get current user record
const userRecord = await pb.collection('users').getOne(user.id);
// Parse existing PRISM JSON
let prism = {};
if (userRecord.PRISM) {
try {
prism = typeof userRecord.PRISM === 'string'
? JSON.parse(userRecord.PRISM)
: userRecord.PRISM;
} catch (e) {
console.warn('Error parsing PRISM data:', e);
prism = {};
}
}
// Update only Job-Pages preferences (preserve other app data)
prism['Job-Pages'] = {
darkMode: preferences.darkMode,
defaultView: preferences.defaultView
};
// Save back to PRISM column
await pb.collection('users').update(user.id, {
PRISM: JSON.stringify(prism)
});
return true;
} catch (error) {
console.error('Error saving preferences:', error);
throw error;
}
}
/**
* Apply dark mode to the page
*/
function applyDarkMode(enabled) {
const html = document.documentElement;
if (enabled) {
html.classList.add('dark');
localStorage.setItem('darkMode', 'true');
} else {
html.classList.remove('dark');
localStorage.setItem('darkMode', 'false');
}
}
/**
* Initialize dark mode from preferences
*/
async function initializeDarkMode() {
try {
const preferences = await getUserPreferences();
applyDarkMode(preferences.darkMode);
} catch (error) {
console.error('Error initializing dark mode:', error);
}
}
/**
* Update view option visual state
*/
function updateViewOptionVisuals() {
const selectedView = document.querySelector('input[name="defaultView"]:checked')?.value || 'table';
const options = document.querySelectorAll('.view-option');
options.forEach(option => {
const input = option.querySelector('input[type="radio"]');
const icon = option.querySelector('.view-icon');
const title = option.querySelector('.view-title');
const isSelected = input.value === selectedView;
if (isSelected) {
option.classList.add('border-indigo-500', 'bg-indigo-50/50', 'shadow-md');
option.classList.remove('border-white/30', 'bg-white/40');
if (icon) icon.classList.add('text-indigo-600');
if (icon) icon.classList.remove('text-gray-400');
if (title) title.classList.add('text-indigo-600');
if (title) title.classList.remove('text-gray-900');
} else {
option.classList.remove('border-indigo-500', 'bg-indigo-50/50', 'shadow-md');
option.classList.add('border-white/30', 'bg-white/40');
if (icon) icon.classList.remove('text-indigo-600');
if (icon) icon.classList.add('text-gray-400');
if (title) title.classList.remove('text-indigo-600');
if (title) title.classList.add('text-gray-900');
}
});
}
/**
* Load preferences and populate form
*/
async function loadPreferences() {
try {
const preferences = await getUserPreferences();
// Set dark mode toggle
const darkModeToggle = document.getElementById('darkModeToggle');
if (darkModeToggle) {
darkModeToggle.checked = preferences.darkMode;
applyDarkMode(preferences.darkMode);
}
// Set default view radio buttons
const viewTable = document.getElementById('viewTable');
const viewCard = document.getElementById('viewCard');
if (viewTable && viewCard) {
if (preferences.defaultView === 'table') {
viewTable.checked = true;
} else {
viewCard.checked = true;
}
// Update visual state
updateViewOptionVisuals();
}
// Add change listeners to radio buttons
const radioButtons = document.querySelectorAll('input[name="defaultView"]');
radioButtons.forEach(radio => {
radio.addEventListener('change', updateViewOptionVisuals);
});
} catch (error) {
console.error('Error loading preferences:', error);
}
}
/**
* Save preferences from form
*/
async function savePreferences() {
try {
const darkMode = document.getElementById('darkModeToggle').checked;
const defaultView = document.querySelector('input[name="defaultView"]:checked')?.value || 'table';
const preferences = {
darkMode: darkMode,
defaultView: defaultView
};
await saveUserPreferences(preferences);
applyDarkMode(darkMode);
showMessage('Preferences saved successfully', 'success');
} catch (error) {
console.error('Error saving preferences:', error);
showMessage('Error saving preferences: ' + (error.message || 'Unknown error'), 'error');
}
}
/**
* Show message to user
*/
function showMessage(message, type = 'success') {
const container = document.getElementById('messageContainer');
if (!container) return;
const bgColor = type === 'success'
? 'bg-green-50 border-green-200 text-green-700'
: 'bg-red-50 border-red-200 text-red-700';
container.innerHTML = `
<div class="${bgColor} border px-4 py-3 rounded-xl text-sm backdrop-blur-sm">
${message}
</div>
`;
// Auto-hide after 5 seconds
setTimeout(() => {
container.innerHTML = '';
}, 5000);
}
// Form submission handler
if (typeof document !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('preferencesForm');
if (form) {
form.addEventListener('submit', async (e) => {
e.preventDefault();
await savePreferences();
});
}
// Dark mode toggle change handler
const darkModeToggle = document.getElementById('darkModeToggle');
if (darkModeToggle) {
darkModeToggle.addEventListener('change', (e) => {
applyDarkMode(e.target.checked);
});
}
});
}
// Make functions globally accessible
if (typeof window !== 'undefined') {
window.getUserPreferences = getUserPreferences;
window.saveUserPreferences = saveUserPreferences;
window.initializeDarkMode = initializeDarkMode;
window.loadPreferences = loadPreferences;
window.savePreferences = savePreferences;
}