test1 / src /App.jsx
huylaughmad's picture
Upload 37 files
17bca00 verified
Raw
History Blame Contribute Delete
7.32 kB
// src/App.jsx
import React, { useState, useEffect } from 'react';
import Sidebar from './components/Sidebar/Sidebar';
// import { auth, db, FieldValue } from './firebase-config.js'; // Không import trực tiếp auth, db nữa
import { generateAvatarUrl } from './utils';
import eventBus from '../public/js/utils/eventBus.js'; // Import eventBus
import { showModal, hideModal } from '../public/js/modal.js'; // Import modal functions
function App() {
const [currentUser, setCurrentUser] = useState(null);
const [loadingAuth, setLoadingAuth] = useState(true);
const [departments, setDepartments] = useState([]);
const [loadingDepartments, setLoadingDepartments] = useState(true);
const getInitialSection = () => {
const hash = window.location.hash.substring(1);
const validSections = ['dashboard-section', 'tasks-section', 'personnel-section', 'departments-section', 'reports-section', 'calendar-section', 'settings-section'];
return validSections.includes(hash) ? hash : 'dashboard-section';
};
const [activeSection, setActiveSection] = useState(getInitialSection());
const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);
// Listen for auth state changes from vanilla JS (via userManager and listeners.js)
useEffect(() => {
const unsubscribeUser = eventBus.subscribe('userDataUpdated', (userData) => {
console.log('App.jsx: Received userDataUpdated event from EventBus:', userData);
setCurrentUser(userData);
setLoadingAuth(false);
// If user is null, show login modal
if (!userData) {
showModal('loginModal');
// Ensure vanilla JS also handles hiding main content etc.
// Or: React handles it completely by not rendering main UI
} else {
hideModal('loginModal');
}
});
const unsubscribeDepartments = eventBus.subscribe('departmentsDataReady', (deptsData) => {
console.log('App.jsx: Received departmentsDataReady event from EventBus:', deptsData);
setDepartments(deptsData);
setLoadingDepartments(false);
});
// Set up reactBridge functions for vanilla JS to call
window.reactBridge = {
updateActiveSection: (sectionId) => {
console.log("App.jsx: reactBridge.updateActiveSection called with", sectionId);
setActiveSection(sectionId);
},
setMobileMenuOpen: (isOpen) => {
console.log("App.jsx: reactBridge.setMobileMenuOpen called with", isOpen);
setMobileMenuOpen(isOpen);
}
// userData and departmentData are now passed via EventBus, not directly via reactBridge
};
console.log("App.jsx: Bridge functions attached to window.reactBridge");
return () => {
unsubscribeUser();
unsubscribeDepartments();
delete window.reactBridge; // Clean up bridge on unmount
};
}, []);
// Sync active section with URL hash
useEffect(() => {
if (currentUser) {
window.location.hash = activeSection;
}
}, [activeSection, currentUser]);
// Handle hashchange from browser (back/forward)
useEffect(() => {
const handleHashChange = () => {
const hash = window.location.hash.substring(1);
if (hash && hash !== activeSection) {
setActiveSection(hash);
}
};
window.addEventListener('hashchange', handleHashChange);
return () => {
window.removeEventListener('hashchange', handleHashChange);
};
}, [activeSection]);
const handleNavigate = (sectionId) => {
setActiveSection(sectionId);
// This will trigger the useEffect above to update window.location.hash
// And vanillaNavigate (in listeners.js) will listen to hashchange
if (window.innerWidth < 768) { // Close sidebar on mobile after navigation
setMobileMenuOpen(false);
}
};
const handleLogout = () => {
// This will be handled by the vanilla JS auth.js via the logout button in the header
// userManager.js will then publish 'userLoggedOut' which App.jsx will listen to.
// You can optionally add a direct call to auth.signOut() here if you want React to initiate logout.
// For now, let's keep the vanilla JS button as the initiator.
console.log("App.jsx: Logout button clicked, vanilla JS should handle this.");
};
// Render logic
if (loadingAuth || (currentUser && loadingDepartments)) {
return (
<div className="flex-1 flex items-center justify-center h-screen">
<p>Đang tải ứng dụng...</p>
</div>
);
}
if (!currentUser) {
// When not logged in, only render the login modal (which is part of vanilla HTML)
// The main content area (main-content) will be display:none by vanilla JS.
return (
<div className="flex-1 flex flex-col items-center justify-center p-6">
{/* Content hidden or login form shown by vanilla JS */}
{/* <h1 className="text-2xl font-bold mb-4">Vui lòng đăng nhập</h1> */}
{/* The login modal is rendered by vanilla JS, so no React component for it here */}
</div>
);
}
return (
<div className="flex h-screen">
<Sidebar
initialUser={currentUser}
initialDepartments={departments}
initialActiveSection={activeSection}
onNavigate={handleNavigate}
isMobileMenuOpen={isMobileMenuOpen}
setMobileMenuOpen={setMobileMenuOpen}
/>
{/* Main content area, controlled by vanilla JS for now, but React header can be here */}
<div className="flex-1 flex flex-col overflow-hidden">
{/* Header is part of HTML, but React can manage its logout button etc. */}
{/* For now, the logout button in HTML is handled by vanilla JS */}
<header className="bg-white shadow h-16 flex items-center justify-between px-6 md:hidden">
{/* The mobile menu button for small screens */}
<button
className="text-gray-500 focus:outline-none"
onClick={() => setMobileMenuOpen(true)}
>
<i className="fas fa-bars text-xl"></i>
</button>
<div className="flex-1"></div>
<div>
{/* This logout button is part of HTML, handled by vanilla JS */}
{/* <button
onClick={handleLogout}
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
>
Đăng xuất
</button> */}
</div>
</header>
<main className="flex-1 overflow-x-hidden overflow-y-auto bg-gray-100">
{/* Nội dung chính sẽ được quản lý bởi JavaScript thuần thông qua class 'active' */}
{/* Chúng ta chỉ cần đảm bảo các phần tử content-section tồn tại trong index.html */}
{/* Và JavaScript thuần (listeners.js) sẽ thêm/bỏ class 'active' */}
{/* Không cần render lại nội dung ở đây bằng React trừ khi chuyển hoàn toàn section đó sang React */}
{/* Ví dụ, bạn có thể render:
{activeSection === 'dashboard-section' && <DashboardComponent />}
nhưng điều đó sẽ là bước tiếp theo của việc chuyển đổi từng section */}
</main>
</div>
</div>
);
}
export default App;