// ========================================== // CLOUDPRIME FRONTEND COMPONENT SYSTEM // ========================================== /** * Core Application Class */ class CloudPrimeApp { constructor() { this.config = { apiBaseUrl: '/api/v1', wsUrl: 'wss://yourserver.com/ws', theme: localStorage.getItem('cp_theme') || 'light' }; this.state = { user: null, isAuthenticated: false, currentView: 'public', notifications: [] }; this.components = {}; this.init(); } async init() { await this.loadConfig(); this.initializeTheme(); this.registerComponents(); this.setupEventListeners(); this.checkAuthentication(); } async loadConfig() { try { const response = await fetch(`${this.config.apiBaseUrl}/config`); const config = await response.json(); this.config = { ...this.config, ...config }; } catch (error) { console.error('Failed to load config:', error); } } registerComponents() { this.components = { navbar: new NavbarComponent(this), hero: new HeroComponent(this), services: new ServicesComponent(this), pricing: new PricingComponent(this), connectivity: new ConnectivityComponent(this), footer: new FooterComponent(this), chatbot: new ChatbotComponent(this), admin: new AdminDashboard(this) }; } initializeTheme() { document.body.setAttribute('data-bs-theme', this.config.theme); this.updateThemeIcon(); } toggleTheme() { const newTheme = this.config.theme === 'light' ? 'dark' : 'light'; this.config.theme = newTheme; localStorage.setItem('cp_theme', newTheme); document.body.setAttribute('data-bs-theme', newTheme); this.updateThemeIcon(); } updateThemeIcon() { const icons = document.querySelectorAll('#theme-icon'); icons.forEach(icon => { icon.className = this.config.theme === 'dark' ? 'bi bi-sun-fill' : 'bi bi-moon-stars-fill'; }); } switchView(view) { this.state.currentView = view; const publicEl = document.getElementById('public_site'); const adminEl = document.getElementById('admin_dashboard'); if (view === 'admin') { if (!this.state.isAuthenticated) { this.showLoginModal(); return; } publicEl.classList.add('d-none'); adminEl.classList.remove('d-none'); this.components.admin.init(); } else { publicEl.classList.remove('d-none'); adminEl.classList.add('d-none'); } } async checkAuthentication() { try { const token = localStorage.getItem('cp_auth_token'); if (!token) return; const response = await fetch(`${this.config.apiBaseUrl}/auth/verify`, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { this.state.user = await response.json(); this.state.isAuthenticated = true; } } catch (error) { console.error('Auth check failed:', error); } } showLoginModal() { const modal = new LoginModal(this); modal.show(); } setupEventListeners() { // Global event delegation document.addEventListener('click', (e) => { if (e.target.matches('[data-action]')) { const action = e.target.dataset.action; this.handleAction(action, e.target); } }); // Theme toggle document.addEventListener('click', (e) => { if (e.target.closest('.theme-toggle')) { this.toggleTheme(); } }); } handleAction(action, element) { const actions = { 'switch-to-admin': () => this.switchView('admin'), 'switch-to-public': () => this.switchView('public'), 'logout': () => this.logout(), 'open-chatbot': () => this.components.chatbot.toggle() }; if (actions[action]) { actions[action](); } } async logout() { localStorage.removeItem('cp_auth_token'); this.state.isAuthenticated = false; this.state.user = null; this.switchView('public'); this.showToast('Logged out successfully', 'success'); } showToast(message, type = 'info') { const toast = document.createElement('div'); toast.className = `toast align-items-center text-white bg-${type} border-0`; toast.innerHTML = `
${message}
`; const container = document.getElementById('toast-container') || this.createToastContainer(); container.appendChild(toast); const bsToast = new bootstrap.Toast(toast); bsToast.show(); toast.addEventListener('hidden.bs.toast', () => toast.remove()); } createToastContainer() { const container = document.createElement('div'); container.id = 'toast-container'; container.className = 'position-fixed bottom-0 end-0 p-3'; container.style.zIndex = '11000'; document.body.appendChild(container); return container; } } /** * Base Component Class */ class BaseComponent { constructor(app) { this.app = app; this.element = null; } render() { throw new Error('render() must be implemented'); } update() { if (this.element) { this.render(); } } destroy() { if (this.element) { this.element.remove(); this.element = null; } } } /** * Hero Component with Typing Effect */ class HeroComponent extends BaseComponent { constructor(app) { super(app); this.typingTexts = [ 'Intelligent Tech', 'Smart Solutions', 'AI-Powered Tools', 'Cloud Innovation' ]; this.currentIndex = 0; this.isDeleting = false; this.charIndex = 0; this.initTypingEffect(); } initTypingEffect() { const element = document.getElementById('typing-text'); if (!element) return; this.element = element; this.typeEffect(); } typeEffect() { const currentText = this.typingTexts[this.currentIndex]; const displayText = this.isDeleting ? currentText.substring(0, this.charIndex--) : currentText.substring(0, this.charIndex++); if (this.element) { this.element.textContent = displayText; if (!this.isDeleting && this.charIndex === currentText.length + 1) { this.isDeleting = true; setTimeout(() => this.typeEffect(), 2000); } else if (this.isDeleting && this.charIndex === 0) { this.isDeleting = false; this.currentIndex = (this.currentIndex + 1) % this.typingTexts.length; setTimeout(() => this.typeEffect(), 500); } else { setTimeout(() => this.typeEffect(), this.isDeleting ? 50 : 100); } } } } /** * Connectivity Checker Component */ class ConnectivityComponent extends BaseComponent { constructor(app) { super(app); this.setupChecker(); } setupChecker() { const form = document.querySelector('#connectivity form'); if (!form) return; form.addEventListener('submit', (e) => { e.preventDefault(); this.checkAvailability(new FormData(e.target)); }); } async checkAvailability(formData) { const address = formData.get('address') || document.querySelector('#connectivity input[type="text"]')?.value; if (!address) { this.app.showToast('Please enter an address', 'warning'); return; } this.app.showToast('Checking coverage...', 'info'); try { const response = await fetch(`${this.app.config.apiBaseUrl}/connectivity/check`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }); const data = await response.json(); if (data.success) { this.showResults(data.results); } else { this.app.showToast('No coverage found at this location', 'warning'); } } catch (error) { this.app.showToast('Failed to check coverage. Please try again.', 'danger'); } } showResults(results) { const message = ` Coverage Available!
Fibre: ${results.fibre ? '✓ Available' : '✗ Not available'}
LTE: ${results.lte ? '✓ Available' : '✗ Not available'}
5G: ${results.fiveG ? '✓ Available' : '✗ Not available'} `; this.app.showToast(message, 'success'); } } /** * Login Modal Component */ class LoginModal { constructor(app) { this.app = app; this.modal = null; this.create(); } create() { const modalHtml = ` `; const container = document.createElement('div'); container.innerHTML = modalHtml; document.body.appendChild(container.firstElementChild); this.modal = new bootstrap.Modal(document.getElementById('loginModal')); this.setupForm(); } setupForm() { const form = document.getElementById('loginForm'); form.addEventListener('submit', async (e) => { e.preventDefault(); await this.handleLogin(new FormData(e.target)); }); } async handleLogin(formData) { const errorEl = document.getElementById('loginError'); errorEl.classList.add('d-none'); try { const response = await fetch(`${this.app.config.apiBaseUrl}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: formData.get('username'), password: formData.get('password') }) }); const data = await response.json(); if (response.ok) { localStorage.setItem('cp_auth_token', data.token); this.app.state.user = data.user; this.app.state.isAuthenticated = true; this.modal.hide(); this.app.switchView('admin'); this.app.showToast('Login successful!', 'success'); } else { errorEl.textContent = data.message || 'Invalid credentials'; errorEl.classList.remove('d-none'); } } catch (error) { errorEl.textContent = 'Connection error. Please try again.'; errorEl.classList.remove('d-none'); } } show() { this.modal.show(); } } /** * API Service Layer */ class APIService { constructor(baseUrl) { this.baseUrl = baseUrl; } async request(endpoint, options = {}) { const token = localStorage.getItem('cp_auth_token'); const headers = { 'Content-Type': 'application/json', ...(token && { 'Authorization': `Bearer ${token}` }), ...options.headers }; try { const response = await fetch(`${this.baseUrl}${endpoint}`, { ...options, headers }); if (response.status === 401) { localStorage.removeItem('cp_auth_token'); window.location.reload(); return; } return await response.json(); } catch (error) { console.error('API Request failed:', error); throw error; } } get(endpoint) { return this.request(endpoint); } post(endpoint, data) { return this.request(endpoint, { method: 'POST', body: JSON.stringify(data) }); } put(endpoint, data) { return this.request(endpoint, { method: 'PUT', body: JSON.stringify(data) }); } delete(endpoint) { return this.request(endpoint, { method: 'DELETE' }); } } // Initialize App on DOM Ready let app; document.addEventListener('DOMContentLoaded', () => { app = new CloudPrimeApp(); window.CloudPrime = app; // Expose globally for debugging }); // Export for module usage if (typeof module !== 'undefined' && module.exports) { module.exports = { CloudPrimeApp, APIService }; }