tc-agent / static /js /modules /user-manager.js
togitoon's picture
Initial
bf5f290
/**
* User Manager Module
* Handles user registration, preferences, and status management
*/
class UserManager {
constructor(apiClient, uiComponents) {
this.apiClient = apiClient;
this.ui = uiComponents;
this.currentUser = null;
}
/**
* Check if user exists and load their preferences
* @param {string} email - User email
* @param {boolean} showLoading - Whether to show loading indicator
*/
async loadUserByEmail(email, showLoading = false) {
try {
if (showLoading) {
this.ui.showLoading('Loading user data...');
}
const user = await this.apiClient.getUserByEmail(email);
if (user) {
this.currentUser = user;
return user;
}
return null;
} catch (error) {
console.log('User not found or error loading user:', error.message);
return null;
} finally {
if (showLoading) {
this.ui.hideLoading();
}
}
}
/**
* Register a new user or update existing user
* @param {string} email - User email
* @param {string} preferences - User preferences
*/
async registerOrUpdateUser(email, preferences) {
try {
// Check if user exists first
const existingUser = await this.loadUserByEmail(email);
let result;
let message;
if (existingUser) {
// Update existing user
result = await this.apiClient.updateUserPreferences(email, preferences);
message = 'Preferences updated successfully!';
} else {
// Register new user
result = await this.apiClient.registerUser(email, preferences);
message = 'User registered successfully!';
}
if (result.success) {
this.currentUser = result.user;
this.ui.showSuccessMessage(message);
return result;
} else {
throw new Error(result.message || 'Failed to register/update user');
}
} catch (error) {
this.ui.showError(`Failed to register/update user: ${error.message}`);
throw error;
}
}
/**
* Toggle user active status
* @param {string} email - User email
* @param {boolean} active - Active status
*/
async toggleUserActive(email, active) {
try {
const result = await this.apiClient.toggleUserActive(email, active);
if (result.success) {
const action = active ? 'activated' : 'deactivated';
this.ui.showSuccessMessage(`Notifications ${action} successfully!`);
// Update current user if it matches
if (this.currentUser && this.currentUser.email === email) {
this.currentUser.active = active;
}
return result;
} else {
throw new Error(result.message || 'Failed to toggle user status');
}
} catch (error) {
this.ui.showError(`Failed to toggle user status: ${error.message}`);
throw error;
}
}
/**
* Deactivate user notifications
* @param {string} email - User email
*/
async deactivateUser(email) {
const confirmed = confirm(`Are you sure you want to deactivate daily notifications for ${email}?`);
if (!confirmed) return false;
return await this.toggleUserActive(email, false);
}
/**
* Reactivate user notifications
* @param {string} email - User email
*/
async reactivateUser(email) {
return await this.toggleUserActive(email, true);
}
/**
* Get current user data
*/
getCurrentUser() {
return this.currentUser;
}
/**
* Check if current user is active
*/
isCurrentUserActive() {
return this.currentUser && this.currentUser.active;
}
/**
* Clear current user data
*/
clearCurrentUser() {
this.currentUser = null;
}
/**
* Validate email format
* @param {string} email - Email to validate
*/
validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
/**
* Auto-fill user preferences if they exist
* @param {string} email - User email
* @param {HTMLElement} preferencesInput - Preferences input field
*/
async autoFillPreferences(email, preferencesInput) {
if (!email || !this.validateEmail(email)) {
return;
}
const user = await this.loadUserByEmail(email);
if (user && user.preferences_text && !preferencesInput.value.trim()) {
preferencesInput.value = user.preferences_text;
// Auto-resize textarea if it has this functionality
if (preferencesInput.style) {
preferencesInput.style.height = 'auto';
preferencesInput.style.height = preferencesInput.scrollHeight + 'px';
}
}
return user;
}
/**
* Create user status display for forms
* @param {Object} user - User object
* @param {Function} deactivateCallback - Callback for deactivate action
* @param {Function} reactivateCallback - Callback for reactivate action
*/
createUserStatusDisplay(user, deactivateCallback, reactivateCallback) {
const statusContainer = document.createElement('div');
statusContainer.id = 'userStatusDisplay';
statusContainer.style.cssText = `
margin-top: 1rem;
padding: 1rem;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid var(--success-color);
`;
const isActive = user.active;
const statusText = isActive ? 'Scheduled' : 'Inactive';
const statusColor = isActive ? 'var(--success-color)' : 'var(--warning-color)';
statusContainer.innerHTML = `
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 1rem;">
<div style="display: flex; align-items: center; gap: 0.5rem;">
<i class="fas fa-${isActive ? 'check-circle' : 'pause-circle'}" style="color: ${statusColor};"></i>
<span style="font-weight: 500;">Daily notifications: <span style="color: ${statusColor};">${statusText}</span></span>
</div>
<div style="display: flex; gap: 0.5rem;">
${isActive ? `
<button type="button" class="btn btn-success btn-sm" style="pointer-events: none;">
<i class="fas fa-check"></i> Scheduled
</button>
<button type="button" class="btn btn-danger btn-sm" id="deactivateFromForm">
<i class="fas fa-times"></i> Deactivate
</button>
` : `
<button type="button" class="btn btn-primary btn-sm" id="reactivateFromForm">
<i class="fas fa-play"></i> Reactivate
</button>
`}
</div>
</div>
`;
// Add event listeners
const deactivateBtn = statusContainer.querySelector('#deactivateFromForm');
const reactivateBtn = statusContainer.querySelector('#reactivateFromForm');
if (deactivateBtn) {
deactivateBtn.addEventListener('click', deactivateCallback);
}
if (reactivateBtn) {
reactivateBtn.addEventListener('click', reactivateCallback);
}
return statusContainer;
}
/**
* Remove user status display
*/
removeUserStatusDisplay() {
const statusDisplay = document.getElementById('userStatusDisplay');
if (statusDisplay) {
statusDisplay.remove();
}
}
}