/** * ds-user-settings.js * User settings page component * Manages user profile, preferences, integrations, and account settings * MVP3: Full integration with backend API and user-store */ import { useUserStore } from '../../stores/user-store.js'; export default class DSUserSettings extends HTMLElement { constructor() { super(); this.userStore = useUserStore(); this.activeTab = 'profile'; this.isLoading = false; this.formChanges = {}; } connectedCallback() { this.render(); this.setupEventListeners(); this.subscribeToUserStore(); } subscribeToUserStore() { this.unsubscribe = this.userStore.subscribe(() => { this.updateUI(); }); } render() { const user = this.userStore.getCurrentUser(); const displayName = this.userStore.getDisplayName(); const avatar = this.userStore.getAvatar(); this.innerHTML = `
Avatar

${displayName}

${user?.email || 'Not logged in'}

Profile Settings

${user?.role || 'User'} (Read-only)
`; } setupEventListeners() { // Tab switching this.querySelectorAll('.settings-tab').forEach(btn => { btn.addEventListener('click', (e) => { this.switchTab(e.target.closest('button').dataset.tab); }); }); // Profile tab const saveProfileBtn = this.querySelector('#save-profile-btn'); if (saveProfileBtn) { saveProfileBtn.addEventListener('click', () => this.saveProfile()); } // Preferences tab const savePreferencesBtn = this.querySelector('#save-preferences-btn'); if (savePreferencesBtn) { savePreferencesBtn.addEventListener('click', () => this.savePreferences()); } // Integration save buttons this.querySelectorAll('.integration-save-btn').forEach(btn => { btn.addEventListener('click', (e) => { const service = e.target.dataset.service; const apiKeyInput = this.querySelector(`#${service}-api-key`) || this.querySelector(`#${service}-webhook`); const apiKey = apiKeyInput?.value || ''; this.saveIntegration(service, apiKey); }); }); // Logout button const logoutBtn = this.querySelector('#logout-btn'); if (logoutBtn) { logoutBtn.addEventListener('click', () => this.logout()); } // Change password button const changePasswordBtn = this.querySelector('#change-password-btn'); if (changePasswordBtn) { changePasswordBtn.addEventListener('click', () => this.showChangePasswordDialog()); } } switchTab(tabName) { this.activeTab = tabName; // Hide all tabs this.querySelectorAll('.settings-content').forEach(tab => { tab.style.display = 'none'; }); // Show selected tab const selectedTab = this.querySelector(`#${tabName}-tab`); if (selectedTab) { selectedTab.style.display = 'block'; } // Update tab styling this.querySelectorAll('.settings-tab').forEach(btn => { const isActive = btn.dataset.tab === tabName; btn.style.borderBottomColor = isActive ? 'var(--vscode-accent)' : 'transparent'; btn.style.color = isActive ? 'var(--vscode-text)' : 'var(--vscode-text-dim)'; }); } async saveProfile() { const name = this.querySelector('#profile-name')?.value || ''; const email = this.querySelector('#profile-email')?.value || ''; const bio = this.querySelector('#profile-bio')?.value || ''; try { await this.userStore.updateProfile({ name, email, bio }); this.showNotification('Profile saved successfully', 'success'); } catch (error) { this.showNotification('Failed to save profile', 'error'); console.error(error); } } savePreferences() { const theme = this.querySelector('input[name="theme"]:checked')?.value || 'dark'; const language = this.querySelector('#pref-language')?.value || 'en'; const notifications = this.querySelector('#pref-notifications')?.checked || false; this.userStore.updatePreferences({ theme, language, notifications: { enabled: notifications, email: this.querySelector('#pref-email-notifications')?.checked || false, desktop: this.querySelector('#pref-desktop-notifications')?.checked || false } }); this.showNotification('Preferences saved', 'success'); } saveIntegration(service, apiKey) { if (!apiKey) { this.userStore.removeIntegration(service); this.showNotification(`${service} integration removed`, 'success'); } else { const metadata = {}; if (service === 'jira') { metadata.projectKey = this.querySelector('#jira-project-key')?.value || ''; } this.userStore.setIntegration(service, apiKey, metadata); this.showNotification(`${service} integration saved`, 'success'); } this.updateIntegrationStatus(); } updateIntegrationStatus() { const integrations = this.userStore.getIntegrations(); ['figma', 'github', 'jira', 'slack'].forEach(service => { const status = this.querySelector(`#${service}-status`); if (status) { if (integrations[service]?.enabled) { status.style.display = 'inline-block'; status.style.background = '#4CAF50'; status.textContent = 'Connected'; } else { status.style.display = 'none'; } } }); } updateUI() { // Update display when user state changes const user = this.userStore.getCurrentUser(); const displayName = this.userStore.getDisplayName(); // Re-render component this.render(); this.setupEventListeners(); } showChangePasswordDialog() { // Placeholder for password change dialog // In a real implementation, this would show a modal dialog alert('Change password functionality would be implemented here.\n\nIn production, this would show a modal with current password and new password fields.'); } showNotification(message, type = 'info') { const notificationEl = document.createElement('div'); notificationEl.style.cssText = ` position: fixed; bottom: 24px; right: 24px; padding: 12px 16px; background: ${type === 'success' ? '#4CAF50' : type === 'error' ? '#F44336' : '#0066CC'}; color: white; border-radius: 4px; font-size: 12px; font-weight: 500; z-index: 1000; animation: slideInUp 0.3s ease-out; `; notificationEl.textContent = message; document.body.appendChild(notificationEl); setTimeout(() => { notificationEl.style.animation = 'slideOutDown 0.3s ease-in'; setTimeout(() => notificationEl.remove(), 300); }, 3000); } disconnectedCallback() { if (this.unsubscribe) { this.unsubscribe(); } } } customElements.define('ds-user-settings', DSUserSettings);