// components/TopBar.ts import { createElement, navigateTo, isLoggedInUser } from '../utils/utils'; import { globalAPI, ApiResponse, ProfileResponseData } from '../api/api'; // Import API and types (now exported) export class TopBar { private container: HTMLElement; private profileDropdownVisible: boolean = false; private profileData: ProfileResponseData | null = null; constructor() { this.container = createElement('nav'); this.container.classList.add('top-bar', 'navbar', 'navbar-expand-lg', 'navbar-light', 'bg-darker', 'mb-3', 'px-4'); this.fetchProfileData(); } async fetchProfileData() { if (isLoggedInUser()) { try { const response: ApiResponse = await globalAPI.getProfile('mockUserId'); if (response.success && response.data) { this.profileData = response.data; this.render(); } else { console.error("Failed to fetch profile data"); } } catch (error) { console.error("Error fetching profile data:", error); } } } render(): HTMLElement { this.container.innerHTML = ''; const navbarBrand = createElement('a'); navbarBrand.classList.add('navbar-brand'); navbarBrand.href = '#/dashboard'; navbarBrand.textContent = 'LMS'; const navbarToggler = createElement('button'); navbarToggler.classList.add('navbar-toggler'); navbarToggler.type = 'button'; navbarToggler.setAttribute('data-bs-toggle', 'collapse'); navbarToggler.setAttribute('data-bs-target', '#navbarNav'); navbarToggler.setAttribute('aria-controls', 'navbarNav'); navbarToggler.setAttribute('aria-expanded', 'false'); navbarToggler.setAttribute('aria-label', 'Toggle navigation'); navbarToggler.innerHTML = ''; const navbarCollapse = createElement('div'); navbarCollapse.classList.add('collapse', 'navbar-collapse'); navbarCollapse.id = 'navbarNav'; const menuPages = createElement('ul'); menuPages.classList.add('navbar-nav', 'me-auto', 'mb-2', 'mb-lg-0'); const dashboardMenuItem = createElement('li'); dashboardMenuItem.classList.add('nav-item'); const dashboardLink = createElement('a'); dashboardLink.classList.add('nav-link'); dashboardLink.href = '#/dashboard'; dashboardLink.textContent = 'Dashboard'; dashboardMenuItem.appendChild(dashboardLink); menuPages.appendChild(dashboardMenuItem); const classroomsMenuItem = createElement('li'); classroomsMenuItem.classList.add('nav-item'); const classroomsLink = createElement('a'); classroomsLink.classList.add('nav-link'); classroomsLink.href = '#/classrooms'; classroomsLink.textContent = 'Classrooms'; classroomsMenuItem.appendChild(classroomsLink); menuPages.appendChild(classroomsMenuItem); const adminMenuItem = createElement('li'); adminMenuItem.classList.add('nav-item'); const adminLink = createElement('a'); adminLink.classList.add('nav-link'); adminLink.href = '#/admin'; adminLink.textContent = 'Admin'; adminMenuItem.appendChild(adminLink); menuPages.appendChild(adminMenuItem); const profileSection = createElement('div'); profileSection.classList.add('d-flex', 'align-items-center', 'ms-auto'); if (this.profileData) { const profileButton = createElement('button'); profileButton.classList.add('btn', 'btn-dark', 'dropdown-toggle'); profileButton.type = 'button'; profileButton.id = 'profileDropdownButton'; profileButton.setAttribute('data-bs-toggle', 'dropdown'); profileButton.setAttribute('aria-expanded', String(this.profileDropdownVisible)); const profileImage = createElement('img'); // Placeholder image, replace with actual profile picture logic profileImage.src = this.profileData.profilePicture || 'src/assets/vite.svg'; // Default placeholder if no picture profileImage.alt = 'Profile Picture'; profileImage.style.width = '30px'; profileImage.style.height = '30px'; profileImage.style.borderRadius = '50%'; profileImage.style.marginRight = '5px'; const fullNameSpan = createElement('span'); fullNameSpan.textContent = this.profileData.fullName; profileButton.appendChild(profileImage); profileButton.appendChild(fullNameSpan); const dropdownMenu = createElement('ul'); dropdownMenu.classList.add('dropdown-menu', 'dropdown-menu-end'); dropdownMenu.setAttribute('aria-labelledby', 'profileDropdownButton'); const userIdItem = createElement('li'); userIdItem.innerHTML = `ID: ${this.profileData.schoolId}`; dropdownMenu.appendChild(userIdItem); const divider = createElement('li'); divider.innerHTML = ''; dropdownMenu.appendChild(divider); const profileMenuItem = createElement('li'); const profileLink = createElement('a'); profileLink.classList.add('dropdown-item'); profileLink.href = '#/profile'; profileLink.textContent = 'Profile'; profileMenuItem.appendChild(profileLink); dropdownMenu.appendChild(profileMenuItem); const accountSettingsMenuItem = createElement('li'); const accountSettingsLink = createElement('a'); accountSettingsLink.classList.add('dropdown-item'); accountSettingsLink.href = '#/profile'; // Same profile page, modal will be triggered there accountSettingsLink.setAttribute('data-action', 'open-account-settings'); // Custom attribute to trigger modal accountSettingsLink.textContent = 'Account settings'; accountSettingsMenuItem.appendChild(accountSettingsLink); dropdownMenu.appendChild(accountSettingsMenuItem); const logoutMenuItem = createElement('li'); const logoutButton = createElement('button'); logoutButton.classList.add('dropdown-item'); logoutButton.textContent = 'Log out'; logoutButton.addEventListener('click', async () => { await globalAPI.logout(); navigateTo('/login'); // Redirect to login page after logout }); logoutMenuItem.appendChild(logoutButton); dropdownMenu.appendChild(logoutMenuItem); profileSection.appendChild(profileButton); profileSection.appendChild(dropdownMenu); } else { // Fallback if profile data is not loaded (or not logged in, though TopBar is for logged-in users) const loginLink = createElement('a'); loginLink.classList.add('btn', 'btn-primary'); loginLink.href = '#/login'; loginLink.textContent = 'Login'; profileSection.appendChild(loginLink); } navbarCollapse.appendChild(menuPages); navbarCollapse.appendChild(profileSection); this.container.appendChild(navbarBrand); this.container.appendChild(navbarToggler); this.container.appendChild(navbarCollapse); return this.container; } getContainer(): HTMLElement { return this.container; } }