v0.9.26 added a admin tools

This commit is contained in:
2026-03-15 16:36:01 -04:00
parent 53d665cc6f
commit 7bc0d26cdd
17 changed files with 872 additions and 96 deletions

View File

@@ -13,6 +13,8 @@ import NewChatModal from '../components/NewChatModal.jsx';
import GlobalBar from '../components/GlobalBar.jsx';
import AboutModal from '../components/AboutModal.jsx';
import HelpModal from '../components/HelpModal.jsx';
import NavDrawer from '../components/NavDrawer.jsx';
import GroupManagerModal from '../components/GroupManagerModal.jsx';
import './Chat.css';
function urlBase64ToUint8Array(base64String) {
@@ -34,7 +36,9 @@ export default function Chat() {
const [activeGroupId, setActiveGroupId] = useState(null);
const [notifications, setNotifications] = useState([]);
const [unreadGroups, setUnreadGroups] = useState(new Map());
const [modal, setModal] = useState(null); // 'profile' | 'users' | 'settings' | 'newchat' | 'help'
const [modal, setModal] = useState(null); // 'profile' | 'users' | 'settings' | 'newchat' | 'help' | 'groupmanager'
const [drawerOpen, setDrawerOpen] = useState(false);
const [features, setFeatures] = useState({ branding: false, groupManager: false });
const [helpDismissed, setHelpDismissed] = useState(true); // true until status loaded
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
const [showSidebar, setShowSidebar] = useState(true);
@@ -65,6 +69,24 @@ export default function Chat() {
useEffect(() => { loadGroups(); }, [loadGroups]);
// Load feature flags on mount
useEffect(() => {
api.getSettings().then(({ settings }) => {
setFeatures({
branding: settings.feature_branding === 'true',
groupManager: settings.feature_group_manager === 'true',
});
}).catch(() => {});
const handler = () => api.getSettings().then(({ settings }) => {
setFeatures({
branding: settings.feature_branding === 'true',
groupManager: settings.feature_group_manager === 'true',
});
}).catch(() => {});
window.addEventListener('jama:settings-changed', handler);
return () => window.removeEventListener('jama:settings-changed', handler);
}, []);
// Register / refresh push subscription
useEffect(() => {
if (!('serviceWorker' in navigator) || !('PushManager' in window)) return;
@@ -303,7 +325,7 @@ export default function Chat() {
return (
<div className="chat-layout">
{/* Global top bar — spans full width on desktop, visible on mobile sidebar view */}
<GlobalBar isMobile={isMobile} showSidebar={showSidebar} />
<GlobalBar isMobile={isMobile} showSidebar={showSidebar} onBurger={() => setDrawerOpen(true)} />
<div className="chat-body">
{(!isMobile || showSidebar) && (
@@ -318,6 +340,8 @@ export default function Chat() {
onUsers={() => setModal('users')}
onSettings={() => setModal('settings')}
onBranding={() => setModal('branding')}
onGroupManager={() => setModal('groupmanager')}
features={features}
onGroupsUpdated={loadGroups}
isMobile={isMobile}
onAbout={() => setModal('about')}
@@ -337,10 +361,21 @@ export default function Chat() {
)}
</div>
<NavDrawer
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
onMessages={() => { setDrawerOpen(false); }}
onGroupManager={() => { setDrawerOpen(false); setModal('groupmanager'); }}
onBranding={() => { setDrawerOpen(false); setModal('branding'); }}
onSettings={() => { setDrawerOpen(false); setModal('settings'); }}
onUsers={() => { setDrawerOpen(false); setModal('users'); }}
features={features}
/>
{modal === 'profile' && <ProfileModal onClose={() => setModal(null)} />}
{modal === 'users' && <UserManagerModal onClose={() => setModal(null)} />}
{modal === 'settings' && <SettingsModal onClose={() => setModal(null)} />}
{modal === 'settings' && <SettingsModal onClose={() => setModal(null)} onFeaturesChanged={setFeatures} />}
{modal === 'branding' && <BrandingModal onClose={() => setModal(null)} />}
{modal === 'groupmanager' && <GroupManagerModal onClose={() => setModal(null)} />}
{modal === 'newchat' && <NewChatModal onClose={() => setModal(null)} onCreated={(g) => { loadGroups(); setModal(null); setActiveGroupId(g.id); }} />}
{modal === 'about' && <AboutModal onClose={() => setModal(null)} />}
{modal === 'help' && <HelpModal onClose={() => setModal(null)} dismissed={helpDismissed} />}