/*
Navbar.js - ESP3D WebUI navigation bar file
Copyright (c) 2021 Luc Lebosse. All rights reserved.
Original code inspiration : 2021 Alexandre Aussourd
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
import { Fragment, ComponentChildren, TargetedMouseEvent } from "preact"
import { useState, useEffect, useRef } from "preact/hooks"
import { iconsFeather } from "../Images"
import { iconsTarget, AppLogo } from "../../targets"
import { Link } from "../Router"
import { T } from "../Translations"
import {
useSettingsContext,
useUiContext,
useModalsContext,
useRouterContext,
useUiContextFn,
} from "../../contexts"
import { useWebSocketService } from "../../hooks/useWebSocketService";
import { useHttpQueue } from "../../hooks"
import { espHttpURL } from "../Helpers"
import { showConfirmationModal } from "../Modal"
import {
Server,
Settings,
LogOut,
Trello,
ChevronDown,
Smartphone,
Maximize,
Minimize,
} from "preact-feather"
/*
* Local const
*
*/
interface NavLinkItem {
label: any
icon: any
href: string
id?: string
}
const defaultLinks: NavLinkItem[] = [
{
label: ,
icon: null,
href: "/about",
},
{
label: "S13",
icon: ,
href: "/dashboard",
id: "dashboardLink",
},
{
label: "S14",
icon: ,
href: "/settings",
id: "settingsLink",
},
]
// Utility to detect iOS/iPadOS
function isIOS(): boolean {
return /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.userAgent.includes("Macintosh") && "ontouchend" in document)
}
const Navbar = () => {
const { connectionSettings } = useSettingsContext()
const { uisettings } = useUiContext()
const { modals } = useModalsContext()
const { createNewRequest } = useHttpQueue()
const webSocketService = useWebSocketService();
const buttonExtraPage = useRef(null)
const menuExtraPage = useRef(null)
const iconsList: Record = { ...iconsTarget, ...iconsFeather }
const [textbutton, setTextButton] = useState(
)
const [hrefbutton, setHrefButton] = useState(undefined)
const [isFullscreen, setIsFullscreen] = useState(false)
/*
auto-scroll textarea into view if mobile keyboard is blocking textarea to prevent
page resize and navbar from snapping out of viewport due to using fixed heights
*/
window.visualViewport?.addEventListener("resize", () => {
window.scrollTo(0, 0);
});
const disconnectNow = () => {
const formData = new FormData()
formData.append("DISCONNECT", "YES")
createNewRequest(
espHttpURL("login"),
{ method: "POST", id: "login", body: formData },
{
onSuccess: (_result: string) => {
webSocketService.disconnect("sessiontimeout")
},
onFail: (_error: string) => {
webSocketService.disconnect("sessiontimeout")
},
}
)
}
const menuLinks: NavLinkItem[] = []
if (uisettings.current) {
if (uisettings.getValue("showextracontents")) {
const extraContents = uisettings.getValue("extracontents")
const extraPages = extraContents.reduce((acc: NavLinkItem[], curr: any) => {
const item = curr.value.reduce((accumulator: any, current: any) => {
accumulator[current.name] = current.initial
return accumulator
}, {})
if (item.target == "page") {
const pageIcon = iconsList[item.icon]
? iconsList[item.icon]
: ""
acc.push({
label: item.name,
icon: pageIcon,
href: `/#/extrapage/${ curr.id}`,
id: curr.id,
})
}
return acc
}, [])
menuLinks.push(...extraPages)
}
}
const onDisconnect = () => {
useUiContextFn.haptic()
showConfirmationModal({
modals,
title: T("S26"),
content: T("S152"),
button1: { cb: disconnectNow, text: T("S27") },
button2: { text: T("S28") },
})
}
const toggleFullscreen = () => {
useUiContextFn.haptic()
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().then(() => {
setIsFullscreen(true)
}).catch(err => {
console.log(`Error attempting to enable fullscreen: ${err.message}`)
})
} else {
if (document.exitFullscreen) {
document.exitFullscreen().then(() => {
setIsFullscreen(false)
})
}
}
}
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement)
}
document.addEventListener('fullscreenchange', handleFullscreenChange)
return () => {
document.removeEventListener('fullscreenchange', handleFullscreenChange)
}
}, [])
if (uisettings.current) {
return (
{defaultLinks &&
defaultLinks.map(({ label, icon, href, id }) => {
if (
href == "/informations" &&
!uisettings.getValue("showinformationpage")
)
return
return (
) => {
useUiContextFn.haptic()
if (buttonExtraPage.current)
buttonExtraPage.current.classList.remove(
"active"
)
}}
id={id}
className={
href == "/about"
? "navbar-brand logo no-box "
: connectionSettings.current
.FWTarget == 0 &&
href == "/dashboard"
? "d-none"
: "btn btn-link no-box feather-icon-container"
}
activeClassName="active"
href={href}
>
{icon}
)
})}
{menuLinks && menuLinks.length > 0 && (
{hrefbutton && (
{textbutton}
)}
)}
{!isIOS() && (
{isFullscreen ? : }
)}
)
}
return null
}
export { Navbar }