import { useTranslation } from "react-i18next"; import React, { useState, useContext, useEffect } from 'react'; import axios from 'axios'; import styled from "styled-components"; import { stopRecording } from "../../api/recording"; import { useGlobalInfoStore } from "../../context/globalInfo"; import { IconButton, Menu, MenuItem, Typography, Chip, Button, Modal, Tabs, Tab, Box, Snackbar, Tooltip } from "@mui/material"; import { AccountCircle, Logout, Clear, YouTube, X, GitHub, Update, Close, Language, Description, LightMode, DarkMode } from "@mui/icons-material"; import { useNavigate } from 'react-router-dom'; import { AuthContext } from '../../context/auth'; import { SaveRecording } from '../recorder/SaveRecording'; import DiscordIcon from '../icons/DiscordIcon'; import { apiUrl } from '../../apiConfig'; import MaxunLogo from "../../assets/maxunlogo.png"; import { useThemeMode } from '../../context/theme-provider'; import packageJson from "../../../package.json" interface NavBarProps { recordingName: string; isRecording: boolean; } export const NavBar: React.FC = ({ recordingName, isRecording, }) => { const { notify, browserId, setBrowserId } = useGlobalInfoStore(); const { state, dispatch } = useContext(AuthContext); const { user } = state; const navigate = useNavigate(); const { darkMode, toggleTheme } = useThemeMode(); const { t, i18n } = useTranslation(); const [anchorEl, setAnchorEl] = useState(null); const [langAnchorEl, setLangAnchorEl] = useState(null); const currentVersion = packageJson.version; const [open, setOpen] = useState(false); const [latestVersion, setLatestVersion] = useState(null); const [tab, setTab] = useState(0); const [isUpdateAvailable, setIsUpdateAvailable] = useState(false); const fetchLatestVersion = async (): Promise => { try { const response = await fetch("https://api.github.com/repos/getmaxun/maxun/releases/latest"); const data = await response.json(); const version = data.tag_name.replace(/^v/, ""); // Remove 'v' prefix return version; } catch (error) { console.error("Failed to fetch latest version:", error); return null; } }; const handleUpdateOpen = () => { setOpen(true); fetchLatestVersion(); }; const handleUpdateClose = () => { setOpen(false); setTab(0); // Reset tab to the first tab }; const handleUpdateTabChange = (event: React.SyntheticEvent, newValue: number) => { setTab(newValue); }; const handleMenuOpen = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; const handleLangMenuOpen = (event: React.MouseEvent) => { setLangAnchorEl(event.currentTarget); }; const handleMenuClose = () => { setAnchorEl(null); setLangAnchorEl(null); }; const logout = async () => { try { const { data } = await axios.get(`${apiUrl}/auth/logout`); if (data.ok) { dispatch({ type: "LOGOUT" }); window.localStorage.removeItem("user"); notify('success', t('navbar.notifications.success.logout')); navigate("/login"); } } catch (error: any) { const status = error.response?.status; let errorKey = 'unknown'; switch (status) { case 401: errorKey = 'unauthorized'; break; case 500: errorKey = 'server'; break; default: if (error.message?.includes('Network Error')) { errorKey = 'network'; } } notify( 'error', t(`navbar.notifications.errors.logout.${errorKey}`, { error: error.response?.data?.message || error.message }) ); navigate("/login"); } }; const goToMainMenu = async () => { if (browserId) { await stopRecording(browserId); notify("warning", t('browser_recording.notifications.terminated')); setBrowserId(null); } navigate("/"); }; const changeLanguage = (lang: string) => { i18n.changeLanguage(lang); localStorage.setItem("language", lang); }; const renderThemeToggle = () => ( {darkMode ? : } ); useEffect(() => { const checkForUpdates = async () => { const latestVersion = await fetchLatestVersion(); setLatestVersion(latestVersion); if (latestVersion && latestVersion !== currentVersion) { setIsUpdateAvailable(true); } }; checkForUpdates(); }, []); return ( <> {isUpdateAvailable && ( setIsUpdateAvailable(false)} message={ `${t('navbar.upgrade.modal.new_version_available', { version: latestVersion })} ${t('navbar.upgrade.modal.view_updates')}` } action={ <> setIsUpdateAvailable(false)} style={{ color: 'black' }} > } ContentProps={{ sx: { background: "white", color: "black", } }} /> )}
navigate('/')}>
{t('navbar.project_name')}
{ user ? (
{!isRecording ? ( <> {t('navbar.upgrade.button')} {latestVersion === null ? ( Checking for updates... ) : currentVersion === latestVersion ? ( {t('navbar.upgrade.modal.up_to_date')} ) : ( <> {t('navbar.upgrade.modal.new_version_available', { version: latestVersion })}
{t('navbar.upgrade.modal.view_updates')} {' '}here.
{tab === 0 && (

Run the commands below

# cd to project directory (eg: maxun)
cd maxun

# pull latest changes
git pull origin master

# install dependencies
npm install

# start maxun
npm run start
)} {tab === 1 && (

Run the commands below

# cd to project directory (eg: maxun)
cd maxun

# stop the working containers
docker-compose down

# Remove existing backend and frontend images
docker rmi getmaxun/maxun-frontend:latest getmaxun/maxun-backend:latest

# pull latest docker images
docker-compose pull backend frontend

# start maxun
docker-compose up -d
)} )}
{/* */} {user.email} { handleMenuClose(); logout(); }}> {t('navbar.menu_items.logout')} {t('navbar.menu_items.language')}
{ window.open('https://github.com/getmaxun/maxun', '_blank'); }}> GitHub { window.open('https://discord.gg/5GbPjBUkws', '_blank'); }}> Discord { window.open('https://www.youtube.com/@MaxunOSS/videos?ref=app', '_blank'); }}> YouTube { window.open('https://x.com/maxun_io?ref=app', '_blank'); }}> Twitter (X) { changeLanguage("en"); handleMenuClose(); }} > English { changeLanguage("es"); handleMenuClose(); }} > Español { changeLanguage("ja"); handleMenuClose(); }} > 日本語 { changeLanguage("zh"); handleMenuClose(); }} > 中文 { changeLanguage("de"); handleMenuClose(); }} > Deutsch { window.open('https://docs.maxun.dev/development/i18n', '_blank'); handleMenuClose(); }} > Add Language
{renderThemeToggle()} ) : ( <> {t('navbar.recording.discard')} )}
) : ( {t("Language")} { changeLanguage("en"); handleMenuClose(); }} > English { changeLanguage("es"); handleMenuClose(); }} > Español { changeLanguage("ja"); handleMenuClose(); }} > 日本語 { changeLanguage("zh"); handleMenuClose(); }} > 中文 { changeLanguage("de"); handleMenuClose(); }} > Deutsch { window.open('https://docs.maxun.dev/development/i18n', '_blank'); handleMenuClose(); }} > Add Language {renderThemeToggle()} )}
); }; const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>` grid-area: navbar; background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')}; padding: 5px; display: flex; justify-content: space-between; border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#333' : '#e0e0e0')}; `; const ProjectName = styled.b<{ mode: 'light' | 'dark' }>` color: ${({ mode }) => (mode === 'dark' ? '#ffffff' : '#3f4853')}; font-size: 1.3em; `; const NavBarRight = styled.div` display: flex; align-items: center; justify-content: flex-end; margin-left: auto; `;