1 directories, 28 files

tinai

Home / testing / ai / tinai
import Api from './api.js';
import Storage from './storage.js';

class Users {

	#api;
	#storage;
	
	loginForm;
	usernameInput;
	passcodeInput;
	loginButton;
	errorMessageDiv;
	logoutButton;

	// Admin Panel Elements
	userTableContainer;
	userIdInput;
	adminUsernameInput;
	adminPasscodeInput;
	adminNameInput;
	adminEmailInput;
	adminCheckbox;
	saveUserButton;
	clearUserFormButton;
	adminForm;
	addFundsForm;
	addFundsUserIdInput;
	addFundsAmountInput;
	globalSummaryContainer;

	constructor() {
		this.loadTheme();
		this.#api = new Api();
		this.#storage = new Storage();
		
		this.init_elements();
		this.init_interactions();
		this.checkAdminStatusAndLoadUsers();
	}
	
	init_elements() {
		this.loginForm = document.getElementById('login-form');
		this.usernameInput = document.getElementById('username');
		this.passcodeInput = document.getElementById('passcode');
		this.loginButton = document.getElementById('login-button');
		this.errorMessageDiv = document.getElementById('login-error-message');
		this.logoutButton = document.getElementById('id-btn-logout');

		// Admin Panel Elements
		this.userTableContainer = document.getElementById('id-div-user-table-container');
		this.userIdInput = document.getElementById('id-user-id');
		this.adminUsernameInput = document.getElementById('id-username');
		this.adminPasscodeInput = document.getElementById('id-passcode');
		this.adminNameInput = document.getElementById('id-name');
		this.adminEmailInput = document.getElementById('id-email');
		this.adminCheckbox = document.getElementById('id-admin');
		this.saveUserButton = document.getElementById('id-btn-save-user');
		this.clearUserFormButton = document.getElementById('id-btn-clear-user-form');
		this.adminForm = document.getElementById('id-form-admin-options');
		this.addFundsForm = document.getElementById('id-form-add-funds');
		this.addFundsUserIdInput = document.getElementById('id-add-funds-user-id');
		this.addFundsAmountInput = document.getElementById('id-add-funds-amount');
		this.globalSummaryContainer = document.getElementById('id-div-global-summary-container');
	}
	
	init_interactions() {
		if (this.loginForm) {
			this.loginForm.addEventListener('submit', (event) => {
				event.preventDefault();
				this.handle_login();
			});
		}
		if (this.logoutButton) {
			this.logoutButton.addEventListener('click', (event) => {
				event.preventDefault();
				this.handle_logout();
			});
		}

		// Admin Panel Interactions
		if (this.saveUserButton) {
			this.saveUserButton.addEventListener('click', (event) => {
				event.preventDefault();
				this.handleAddOrUpdateUser();
			});
		}
		if (this.clearUserFormButton) {
			this.clearUserFormButton.addEventListener('click', () => {
				this.clearUserForm();
			});
		}
		if (this.addFundsForm) {
			this.addFundsForm.addEventListener('submit', (event) => {
				event.preventDefault();
				this.handleAddFunds();
			});
		}

		const btnAppOptions = document.getElementById('btn-app-options');
		if (btnAppOptions) {
			btnAppOptions.addEventListener('click', () => {
				this.toggleAdminFormVisibility(true);
				this.checkAdminStatusAndLoadUsers();
			});
		}

		const btnConvOptions = document.getElementById('id-btn-conversation-options');
		if (btnConvOptions) {
			btnConvOptions.addEventListener('click', () => this.toggleAdminFormVisibility(false));
		}

		const btnCloseOptions = document.getElementById('btn-options-close');
		if (btnCloseOptions) {
			btnCloseOptions.addEventListener('click', () => this.toggleAdminFormVisibility(false));
		}
	}

	toggleAdminFormVisibility(show) {
		if (this.adminForm) {
			this.adminForm.style.display = show ? 'block' : 'none';
		}
	}
	
	handle_login() {
		const username = this.usernameInput.value;
		const passcode = this.passcodeInput.value;

		this.errorMessageDiv.textContent = '';

		this.login(username, passcode,
			(response) => {
				if (response.session_guid) {
					window.location.reload();
				} else {
					this.errorMessageDiv.textContent = response.error || 'Login failed. Please check your credentials.';
				}
			},
			(error) => {
				console.error('Login API error:', error);
				this.errorMessageDiv.textContent = 'An error occurred during login. Please try again later.';
			}
		);
	}

	handle_logout() {
		this.logout(
			(response) => {
				if(response.success){
					window.location.reload();
				}
			},
			(error) => {
				console.error('Logout API error:', error);
			}
		);
	}

	login(username, passcode, on_success, on_failure) {
		let data = {
			'action': 'login',
			'username': username,
			'passcode': passcode,
			'location_id': this.#storage.get_location_id()
		};
		this.#api.post(data, on_success, on_failure, 'users');
	}

	logout(on_success, on_failure) {
		let data = {
			'action': 'logout',
			'location_id': this.#storage.get_location_id()
		};
		this.#api.post(data, on_success, on_failure, 'users');
	}

	checkAdminStatusAndLoadUsers() {
		this.#api.post({'action': 'session'}, (response) => {
			if (response.isLoggedIn && response.isAdmin) {
				this.loadUsers();
				this.loadGlobalSummary();
			}
		}, (error) => {
			console.error('Session check API error:', error);
		}, 'users');
	}

	loadUsers() {
		this.#api.post({'action': 'get_all_users'}, (response) => {
			if (response.success) {
				this.renderUserTable(response.users);
			} else {
				console.error('Failed to load users:', response.error);
			}
		}, (error) => {
			console.error('Get all users API error:', error);
		}, 'users');
	}

	renderUserTable(users) {
		if (!this.userTableContainer) return;

		let tableHtml = `
			<table border="1" width="100%">
				<thead>
					<tr>
						<th>ID</th>
						<th>Username</th>
						<th>Name</th>
						<th>Email</th>
						<th>Admin</th>
						<th>Budget</th>
						<th>Spent</th>
						<th>Profit</th>
						<th>Actions</th>
					</tr>
				</thead>
				<tbody>
		`;
		users.forEach(user => {
			tableHtml += `
				<tr data-user-id="${user.id}">
					<td>${user.id}</td>
					<td>${user.username}</td>
					<td>${user.name || ''}</td>
					<td>${user.email || ''}</td>
					<td>${user.admin == 1 ? 'Yes' : 'No'}</td>
					<td>${user.lifetime_budget || 0}</td>
					<td>${user.lifetime_spend || 0}</td>
					<td>${user.lifetime_profit || 0}</td>
					<td>
						<button class="btn-edit-user" data-id="${user.id}">Edit</button>
						<button class="btn-delete-user" data-id="${user.id}">Delete</button>
						<button class="btn-add-funds" data-id="${user.id}">Add Funds</button>
					</td>
				</tr>
			`;
		});
		tableHtml += `
				</tbody>
			</table>
		`;
		this.userTableContainer.innerHTML = tableHtml;

		this.userTableContainer.querySelectorAll('.btn-edit-user').forEach(button => {
			button.addEventListener('click', (event) => this.editUser(event.target.dataset.id));
		});
		this.userTableContainer.querySelectorAll('.btn-delete-user').forEach(button => {
			button.addEventListener('click', (event) => this.deleteUser(event.target.dataset.id));
		});
		this.userTableContainer.querySelectorAll('.btn-add-funds').forEach(button => {
			button.addEventListener('click', (event) => this.showAddFundsForm(event.target.dataset.id));
		});
	}

	editUser(userId) {
		this.#api.post({'action': 'get_user_by_id', 'id': userId}, (response) => {
			if (response.success && response.user) {
				const user = response.user;
				this.userIdInput.value = user.id;
				this.adminUsernameInput.value = user.username;
				this.adminPasscodeInput.value = ''; // Passcode is not retrieved for security
				this.adminNameInput.value = user.name || '';
				this.adminEmailInput.value = user.email || '';
				this.adminCheckbox.checked = user.admin == 1;
			} else {
				console.error('Failed to get user details:', response.error);
			}
		}, (error) => {
			console.error('Get user by ID API error:', error);
		}, 'users');
	}

	handleAddOrUpdateUser() {
		const id = this.userIdInput.value || null;
		const username = this.adminUsernameInput.value;
		const passcode = this.adminPasscodeInput.value;
		const name = this.adminNameInput.value;
		const email = this.adminEmailInput.value;
		const admin = this.adminCheckbox.checked;

		if (!username) {
			alert('Username is required.');
			return;
		}

		if (!id && !passcode) { // Passcode is required only for new users
			alert('Passcode is required for new users.');
			return;
		}

		const data = {
			'action': 'add_or_update_user',
			'id': id,
			'username': username,
			'name': name,
			'email': email,
			'admin': admin
		};

		if (passcode) { // Only add passcode to data if it's not empty
			data.passcode = passcode;
		}

		this.#api.post(data, (response) => {
			if (response.success) {
				alert(response.message);
				this.clearUserForm();
				this.loadUsers();
			} else {
				alert('Error: ' + response.error);
			}
		}, (error) => {
			console.error('Add/Update user API error:', error);
			alert('An error occurred while saving the user.');
		}, 'users');
	}

	deleteUser(userId) {
		if (!confirm('Are you sure you want to delete this user?')) {
			return;
		}

		this.#api.post({'action': 'delete_user', 'id': userId}, (response) => {
			if (response.success) {
				alert(response.message);
				this.loadUsers();
			} else {
				alert('Error: ' + response.error);
			}
		}, (error) => {
			console.error('Delete user API error:', error);
			alert('An error occurred while deleting the user.');
		}, 'users');
	}

	clearUserForm() {
		this.userIdInput.value = '';
		this.adminUsernameInput.value = '';
		this.adminPasscodeInput.value = '';
		this.adminNameInput.value = '';
		this.adminEmailInput.value = '';
		this.adminCheckbox.checked = false;
	}

	showAddFundsForm(userId) {
		this.addFundsUserIdInput.value = userId;
		this.addFundsForm.style.display = 'block';
	}

	handleAddFunds() {
		const userId = this.addFundsUserIdInput.value;
		const amount = this.addFundsAmountInput.value;

		if (!amount) {
			alert('Amount is required.');
			return;
		}

		this.#api.post({
			'action': 'add_funds',
			'id': userId,
			'amount': amount
		}, (response) => {
			if (response.success) {
				alert(response.message);
				this.addFundsForm.style.display = 'none';
				this.addFundsAmountInput.value = '';
				this.loadUsers();
				this.loadGlobalSummary();
			} else {
				alert('Error: ' + response.error);
			}
		}, (error) => {
			console.error('Add funds API error:', error);
			alert('An error occurred while adding funds.');
		}, 'users');
	}

	loadGlobalSummary() {
		this.#api.post({'action': 'get_global_budget_summary'}, (response) => {
			if (response.success) {
				this.renderGlobalSummary(response.summary);
			} else {
				console.error('Failed to load global summary:', response.error);
			}
		}, (error) => {
			console.error('Get global summary API error:', error);
		}, 'users');
	}

	renderGlobalSummary(summary) {
		if (!this.globalSummaryContainer) return;

		this.globalSummaryContainer.innerHTML = `
			<h3>Global Budget Summary</h3>
			<p>Total Budget: ${summary.total_budget}</p>
			<p>Total Spent: ${summary.total_spend}</p>
			<p>Total Profit: ${summary.total_profit}</p>
		`;
	}

	loadTheme() {
		const KEY_APP_CONFIG = 'APP_CONFIG';
		const KEY_CONFIG_THEME = 'THEME';
		const config = JSON.parse(localStorage.getItem(KEY_APP_CONFIG) || '{}');
		let theme = (config && config[KEY_CONFIG_THEME]) ? config[KEY_CONFIG_THEME] : 'theme_dark';
		const themes = ['theme_dark', 'theme_light'];
		if (!themes.includes(theme)) {
			theme = 'theme_dark';
		}

		const required_hrefs = [
			'dynamic.php?s=base&t=' + theme,
			'dynamic.php?s=style&t=' + theme
		];

		const existing_links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
		const current_hrefs = existing_links.map(link => link.getAttribute('href'));

		const is_already_applied = required_hrefs.every(href => current_hrefs.includes(href));

		if (!is_already_applied) {
			const old_links = existing_links.filter(link => {
				const href = link.getAttribute('href') || '';
				return href.includes('dynamic.php?s=');
			});

			let loaded_count = 0;
			const on_link_load = () => {
				loaded_count++;
				if (loaded_count === required_hrefs.length) {
					old_links.forEach(link => link.remove());
					this.fadeOutLoader();
				}
			};

			required_hrefs.forEach(href => {
				let link = document.createElement('link');
				link.rel = 'stylesheet';
				link.href = href;
				link.onload = on_link_load;
				link.onerror = on_link_load;
				document.head.appendChild(link);
			});
		} else {
			this.fadeOutLoader();
		}
	}

	fadeOutLoader() {
		const loader = document.querySelector('.page-loader');
		if (loader) {
			loader.style.opacity = '0';
			setTimeout(() => {
				loader.style.display = 'none';
			}, 500);
		}
	}
}

export default Users;
🌐
users.js ×
Type: Web, text/plain
12.40 Kilobytes
Last Modified 2026-04-25 02:57:22
⬇ Download File