import React, { useState, useEffect, useRef } from 'react'; import useStore from '@/AppBuilder/_stores/store'; import { SidebarItem } from './SidebarItem'; import cx from 'classnames'; import { shallow } from 'zustand/shallow'; import { DarkModeToggle } from '@/_components'; import Popover from '@/_ui/Popover'; // import { PageMenu } from './PageMenu'; import LeftSidebarInspector from './LeftSidebarInspector/LeftSidebarInspector'; import GlobalSettings from './GlobalSettings'; import '../../_styles/left-sidebar.scss'; import Debugger from './Debugger/Debugger'; import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; import { withEditionSpecificComponent } from '@/modules/common/helpers/withEditionSpecificComponent'; import { PageMenu } from '../RightSideBar/PageSettingsTab/PageMenu'; // TODO: remove passing refs to LeftSidebarItem and use state // TODO: need to add datasources to the sidebar. // TODO: add dark/light mode toggle // TODO: move popover and component selection to separate component // TODO: create usable header component that can accept page specific buttton as props/children export const BaseLeftSidebar = ({ darkMode = false, switchDarkMode, renderAISideBarTrigger = () => null, renderAIChat = () => null, isUserInZeroToOneFlow, }) => { const { moduleId, isModuleEditor, appType } = useModuleContext(); const [ pinned, selectedSidebarItem, setPinned, setSelectedSidebarItem, currentMode, queryPanelHeight, unreadErrorCount, resetUnreadErrorCount, toggleLeftSidebar, isSidebarOpen, isDraggingQueryPane, ] = useStore( (state) => [ state.isLeftSideBarPinned, state.selectedSidebarItem, state.setIsLeftSideBarPinned, state.setSelectedSidebarItem, state.modeStore.modules[moduleId].currentMode, state.queryPanel.queryPanelHeight, state.debugger.unreadErrorCount, state.debugger.resetUnreadErrorCount, state.toggleLeftSidebar, state.isSidebarOpen, state.queryPanel.isDraggingQueryPane, ], shallow ); const [popoverContentHeight, setPopoverContentHeight] = useState(queryPanelHeight); const sideBarBtnRefs = useRef({}); const handleSelectedSidebarItem = (item) => { if (item === 'debugger') resetUnreadErrorCount(); setSelectedSidebarItem(item); if (item === selectedSidebarItem && !pinned) { return toggleLeftSidebar(false); } if (!isSidebarOpen) toggleLeftSidebar(true); }; const setSideBarBtnRefs = (page) => (ref) => { sideBarBtnRefs.current[page] = ref; }; useEffect(() => { if (isUserInZeroToOneFlow) { setPopoverContentHeight(((window.innerHeight - 48) / window.innerHeight) * 100); return; } if (!isDraggingQueryPane) { setPopoverContentHeight( ((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100 ); } else { setPopoverContentHeight(100); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isUserInZeroToOneFlow, queryPanelHeight, isDraggingQueryPane]); const renderPopoverContent = () => { if (selectedSidebarItem === null || !isSidebarOpen) return null; switch (selectedSidebarItem) { case 'page': return ( ); case 'inspect': return ( ); case 'tooljetai': return renderAIChat({ darkMode, isUserInZeroToOneFlow }); // case 'datasource': // return ( // { // handleSelectedSidebarItem(null); // handlePin(false); // delete sideBarBtnRefs.current['datasource']; // }} // setPinned={handlePin} // pinned={pinned} // /> // ); case 'debugger': return ; // ); // case 'settings': // return ( // // ); case 'settings': return ( ); } }; // TODO: Move this logic to a wrapper component and show components based on the mode if (currentMode === 'view') { return null; } const renderCommonItems = () => { return ( <> handleSelectedSidebarItem('inspect')} darkMode={darkMode} icon="inspect" className={`left-sidebar-item left-sidebar-layout left-sidebar-inspector`} tip="Inspector" ref={setSideBarBtnRefs('inspect')} /> handleSelectedSidebarItem('debugger')} className={`left-sidebar-item left-sidebar-layout`} badge={true} count={unreadErrorCount} tip="Debugger" ref={setSideBarBtnRefs('debugger')} /> ); }; const renderLeftSidebarItems = () => { if (isModuleEditor) { return renderCommonItems(); } return ( <> {renderAISideBarTrigger({ selectedSidebarItem: selectedSidebarItem, onClick: () => handleSelectedSidebarItem('tooljetai'), darkMode: darkMode, icon: 'tooljetai', className: `left-sidebar-item left-sidebar-layout left-sidebar-page-selector`, tip: 'Build with AI', ref: setSideBarBtnRefs('tooljetai'), })} {!isUserInZeroToOneFlow && ( <> {renderCommonItems()} handleSelectedSidebarItem('settings')} className={`left-sidebar-item left-sidebar-layout`} badge={true} tip="Settings" ref={setSideBarBtnRefs('settings')} isModuleEditor={isModuleEditor} /> )} ); }; return (
{renderLeftSidebarItems()} { // if tooljetai is open don't close if (selectedSidebarItem === 'tooljetai') return; const isWithinSidebar = e.target.closest('.left-sidebar'); const isClickOnInspect = e.target.closest('.config-handle-inspect'); if (pinned || isWithinSidebar || isClickOnInspect) return; toggleLeftSidebar(false); }} open={isSidebarOpen} popoverContentClassName={`p-0 left-sidebar-scrollbar sidebar-h-100-popover ${selectedSidebarItem}`} side="right" popoverContent={renderPopoverContent()} popoverContentHeight={popoverContentHeight} />
{/*
*/}
); }; export const LeftSidebar = withEditionSpecificComponent(BaseLeftSidebar, 'AiBuilder');