import React from "react"
import { Menu, Avatar, Button } from "antd"
import { Translation } from "react-i18next"
import classnames from "classnames"
import config from "config"
import { Icons, createIconRender } from "components/Icons"
import sidebarItems from "schemas/routes.json"
import "./index.less"
const onClickHandlers = {
settings: (event) => {
window.app.openSettings()
},
}
const getSidebarComponents = () => {
const items = {}
sidebarItems.forEach((item, index) => {
if (!item.reachable) {
return
}
items[item.id] = {
...item,
index,
content: (
<>
{createIconRender(item.icon)} {item.title}
>
),
}
})
return items
}
const generateItems = () => {
const components = getSidebarComponents()
const itemsMap = []
const pathResolvers = {}
Object.keys(components).forEach((key, index) => {
const component = components[key]
if (typeof component.path !== "undefined") {
pathResolvers[component.id] = component.path
}
itemsMap.push(component)
})
return {
itemsMap,
pathResolvers,
}
}
export default class Sidebar extends React.Component {
constructor(props) {
super(props)
this.controller = window.app["SidebarController"] = {
toggleVisibility: this.toggleVisibility,
toggleElevation: this.toggleElevation,
toggleCollapse: this.toggleCollapse,
isVisible: () => this.state.visible,
isCollapsed: () => this.state.collapsed,
setCustomRender: this.setRender,
closeCustomRender: this.closeRender,
}
this.state = {
visible: false,
elevated: false,
collapsed: window.app.settings.get("collapseOnLooseFocus") ?? false,
pathResolvers: null,
menus: null,
customRenderTitle: null,
customRender: null,
}
// handle sidedrawer open/close
window.app.eventBus.on("sidedrawer.hasDrawers", () => {
this.toggleElevation(true)
})
window.app.eventBus.on("sidedrawer.noDrawers", () => {
this.toggleElevation(false)
})
}
collapseDebounce = null
componentDidMount = async () => {
await this.loadItems()
setTimeout(() => {
this.controller.toggleVisibility(true)
}, 100)
}
setRender = (render, options = {}) => {
if (!typeof render === "function") {
throw new Error("Render is required to be a function")
}
this.setState({
customRenderTitle:
{
options.icon && createIconRender(options.icon)
}
{
options.title &&
{t => t(options.title)}
}
,
customRender: React.createElement(render, {
...options.props ?? {},
close: this.closeRender,
})
})
}
closeRender = () => {
this.setState({
customRenderTitle: null,
customRender: null,
})
}
loadItems = async () => {
const generation = generateItems()
// update states
await this.setState({
menus: generation.itemsMap,
pathResolvers: generation.pathResolvers,
})
}
renderMenuItems(items) {
const handleRenderIcon = (icon) => {
if (typeof icon === "undefined") {
return null
}
return createIconRender(icon)
}
return items.map((item) => {
if (Array.isArray(item.children)) {
return
{t => t(item.title)}
}
{...item.props}
>
{this.renderMenuItems(item.children)}
}
return
{t => t(item.title ?? item.id)}
})
}
handleClick = (e) => {
if (e.item.props.override_event) {
return app.eventBus.emit(e.item.props.override_event, e.item.props.override_event_props)
}
if (typeof e.key === "undefined") {
window.app.eventBus.emit("invalidSidebarKey", e)
return false
}
if (typeof onClickHandlers[e.key] === "function") {
return onClickHandlers[e.key](e)
}
if (typeof this.state.pathResolvers === "object") {
if (typeof this.state.pathResolvers[e.key] !== "undefined") {
return window.app.setLocation(`/${this.state.pathResolvers[e.key]}`, 150)
}
}
return window.app.setLocation(`/${e.key}`, 150)
}
toggleCollapse = (to) => {
if (!this.state.editMode) {
this.setState({ collapsed: to ?? !this.state.collapsed })
}
}
toggleVisibility = (to) => {
this.setState({ visible: to ?? !this.state.visible })
}
toggleElevation = (to) => {
this.setState({ elevated: to ?? !this.state.elevated })
}
onMouseEnter = () => {
if (!this.state.visible) return
if (window.app.settings.is("collapseOnLooseFocus", false)) return
clearTimeout(this.collapseDebounce)
this.collapseDebounce = null
if (this.state.collapsed) {
this.toggleCollapse(false)
}
}
handleMouseLeave = () => {
if (!this.state.visible) return
if (window.app.settings.is("collapseOnLooseFocus", false)) return
if (!this.state.collapsed) {
this.collapseDebounce = setTimeout(() => { this.toggleCollapse(true) }, window.app.settings.get("autoCollapseDelay") ?? 500)
}
}
render() {
if (!this.state.menus) return null
return (
{
this.state.customRender &&
{
this.state.customRenderTitle ?? null
}
{this.state.customRender}
}
{
!this.state.customRender && <>
>
}
)
}
}