Files
parcer/src/components/dashboard/NavBar.tsx

601 lines
20 KiB
TypeScript
Raw Normal View History

import { useTranslation } from "react-i18next";
2024-12-09 00:54:39 +05:30
import React, { useState, useContext, useEffect } from 'react';
2024-09-25 20:27:56 +05:30
import axios from 'axios';
2024-06-24 22:34:54 +05:30
import styled from "styled-components";
import { stopRecording } from "../../api/recording";
import { useGlobalInfoStore } from "../../context/globalInfo";
2025-01-28 22:10:08 +05:30
import {
IconButton,
Menu,
MenuItem,
Typography,
Chip,
Button,
Modal,
Tabs,
Tab,
Box,
Snackbar,
Tooltip
} from "@mui/material";
import {
AccountCircle,
Logout,
Clear,
YouTube,
X,
2025-01-30 19:54:19 +05:30
GitHub,
2025-01-28 22:10:08 +05:30
Update,
Close,
Language,
Description,
LightMode,
DarkMode
} from "@mui/icons-material";
2024-10-21 01:12:06 +05:30
import { useNavigate } from 'react-router-dom';
2024-09-25 20:27:56 +05:30
import { AuthContext } from '../../context/auth';
2025-01-09 20:07:42 +05:30
import { SaveRecording } from '../recorder/SaveRecording';
2025-01-09 19:58:42 +05:30
import DiscordIcon from '../icons/DiscordIcon';
2024-11-01 08:25:33 +05:30
import { apiUrl } from '../../apiConfig';
2024-11-03 21:18:17 +05:30
import MaxunLogo from "../../assets/maxunlogo.png";
2024-11-07 00:46:47 +05:30
import { useThemeMode } from '../../context/theme-provider';
2024-12-06 04:56:31 +05:30
import packageJson from "../../../package.json"
2024-06-24 22:34:54 +05:30
interface NavBarProps {
recordingName: string;
isRecording: boolean;
}
2024-12-07 22:20:17 +05:30
export const NavBar: React.FC<NavBarProps> = ({
recordingName,
isRecording,
}) => {
const { notify, browserId, setBrowserId } = useGlobalInfoStore();
2024-09-25 20:27:56 +05:30
const { state, dispatch } = useContext(AuthContext);
const { user } = state;
2024-10-28 19:06:43 +05:30
const navigate = useNavigate();
2024-11-07 00:46:47 +05:30
const { darkMode, toggleTheme } = useThemeMode();
2024-12-21 18:34:55 +05:30
const { t, i18n } = useTranslation();
2024-10-28 19:07:08 +05:30
2024-10-28 19:06:43 +05:30
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
2024-12-07 22:20:17 +05:30
const [langAnchorEl, setLangAnchorEl] = useState<null | HTMLElement>(null);
2024-10-11 04:57:48 +05:30
const currentVersion = packageJson.version;
2024-12-08 21:08:20 +05:30
const [open, setOpen] = useState(false);
2024-12-09 00:54:39 +05:30
const [latestVersion, setLatestVersion] = useState<string | null>(null);
2024-12-08 21:08:20 +05:30
const [tab, setTab] = useState(0);
2024-12-09 00:54:39 +05:30
const [isUpdateAvailable, setIsUpdateAvailable] = useState(false);
2024-12-08 21:08:20 +05:30
2024-12-09 00:54:39 +05:30
const fetchLatestVersion = async (): Promise<string | null> => {
2024-12-08 21:08:20 +05:30
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
2024-12-09 00:54:39 +05:30
return version;
2024-12-08 21:08:20 +05:30
} catch (error) {
console.error("Failed to fetch latest version:", error);
return null;
2024-12-08 21:08:20 +05:30
}
};
const handleUpdateOpen = () => {
2024-12-08 21:08:20 +05:30
setOpen(true);
fetchLatestVersion();
};
const handleUpdateClose = () => {
2024-12-08 21:08:20 +05:30
setOpen(false);
setTab(0); // Reset tab to the first tab
};
const handleUpdateTabChange = (event: React.SyntheticEvent, newValue: number) => {
2024-12-08 21:08:20 +05:30
setTab(newValue);
};
2024-10-28 19:06:43 +05:30
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
2024-10-11 04:48:25 +05:30
2024-12-07 22:20:17 +05:30
const handleLangMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setLangAnchorEl(event.currentTarget);
};
2024-10-28 19:06:43 +05:30
const handleMenuClose = () => {
setAnchorEl(null);
2024-12-07 22:20:17 +05:30
setLangAnchorEl(null);
2024-10-28 19:06:43 +05:30
};
2024-06-24 22:34:54 +05:30
2024-09-25 20:27:56 +05:30
const logout = async () => {
2025-02-15 12:18:17 +05:30
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");
}
2024-09-25 20:27:56 +05:30
};
2024-09-10 02:49:30 +05:30
const goToMainMenu = async () => {
2024-06-24 22:34:54 +05:30
if (browserId) {
await stopRecording(browserId);
notify("warning", t('browser_recording.notifications.terminated'));
2024-06-24 22:34:54 +05:30
setBrowserId(null);
}
2024-12-07 22:20:17 +05:30
navigate("/");
};
const changeLanguage = (lang: string) => {
i18n.changeLanguage(lang);
localStorage.setItem("language", lang);
2024-06-24 22:34:54 +05:30
};
2025-01-08 13:09:00 +05:30
const renderThemeToggle = () => (
2025-01-09 15:11:01 +05:30
<Tooltip title="Toggle Mode">
2025-01-09 15:37:53 +05:30
<IconButton
onClick={toggleTheme}
2025-01-08 13:09:00 +05:30
sx={{
color: darkMode ? '#ffffff' : '#0000008A',
2025-01-08 13:09:00 +05:30
'&:hover': {
2025-06-27 17:35:36 +05:30
background: 'inherit'
2025-01-08 13:09:00 +05:30
}
}}
>
2025-01-18 20:51:22 +05:30
{darkMode ? <LightMode /> : <DarkMode />}
2025-01-08 13:09:00 +05:30
</IconButton>
</Tooltip>
);
2024-11-24 00:49:39 +05:30
2024-12-09 00:54:39 +05:30
useEffect(() => {
const checkForUpdates = async () => {
const latestVersion = await fetchLatestVersion();
setLatestVersion(latestVersion);
2024-12-09 00:54:39 +05:30
if (latestVersion && latestVersion !== currentVersion) {
setIsUpdateAvailable(true);
2024-12-09 00:54:39 +05:30
}
};
checkForUpdates();
}, []);
2024-06-24 22:34:54 +05:30
return (
2024-12-21 18:23:59 +05:30
<>
2024-12-21 18:46:43 +05:30
{isUpdateAvailable && (
<Snackbar
open={isUpdateAvailable}
onClose={() => setIsUpdateAvailable(false)}
message={
2024-12-21 19:24:47 +05:30
`${t('navbar.upgrade.modal.new_version_available', { version: latestVersion })} ${t('navbar.upgrade.modal.view_updates')}`
2024-12-21 18:46:43 +05:30
}
action={
<>
<Button
color="primary"
size="small"
onClick={handleUpdateOpen}
style={{
backgroundColor: '#ff00c3',
color: 'white',
fontWeight: 'bold',
textTransform: 'none',
marginRight: '8px',
borderRadius: '5px',
}}
>
2024-12-21 19:24:47 +05:30
{t('navbar.upgrade.button')}
2024-12-21 18:46:43 +05:30
</Button>
<IconButton
size="small"
aria-label="close"
color="inherit"
onClick={() => setIsUpdateAvailable(false)}
style={{ color: 'black' }}
>
<Close />
</IconButton>
</>
}
ContentProps={{
sx: {
background: "white",
color: "black",
}
}}
/>
)}
2025-01-08 12:50:46 +05:30
<NavBarWrapper mode={darkMode ? 'dark' : 'light'}>
2024-12-09 00:54:55 +05:30
<div style={{
display: 'flex',
justifyContent: 'flex-start',
2025-02-21 15:52:55 +05:30
cursor: 'pointer'
2025-02-21 15:53:37 +05:30
}}
2025-02-21 15:53:45 +05:30
onClick={() => navigate('/')}>
2024-12-09 00:54:55 +05:30
<img src={MaxunLogo} width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} />
2025-01-08 13:03:02 +05:30
<div style={{ padding: '11px' }}><ProjectName mode={darkMode ? 'dark' : 'light'}>{t('navbar.project_name')}</ProjectName></div>
2024-12-09 00:54:55 +05:30
<Chip
label={`${currentVersion}`}
color="primary"
variant="outlined"
sx={{ marginTop: '10px' }}
/>
2024-12-07 22:20:17 +05:30
</div>
2024-12-09 00:54:55 +05:30
{
user ? (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
{!isRecording ? (
<>
2025-02-05 22:35:19 +05:30
<IconButton onClick={handleUpdateOpen} sx={{
2025-02-05 22:36:30 +05:30
display: 'flex',
alignItems: 'center',
borderRadius: '5px',
padding: '8px',
2025-02-05 22:39:51 +05:30
marginRight: '20px',
2024-12-08 20:42:24 +05:30
}}>
2025-02-05 22:38:41 +05:30
<Update sx={{ marginRight: '5px' }} />
2025-02-05 22:38:29 +05:30
<Typography variant="body1">{t('navbar.upgrade.button')}</Typography>
2025-02-05 22:35:19 +05:30
</IconButton>
2024-12-09 00:54:55 +05:30
<Modal open={open} onClose={handleUpdateClose}>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
2025-07-21 19:55:24 +05:30
width: 700,
2024-12-09 00:54:55 +05:30
bgcolor: "background.paper",
boxShadow: 24,
p: 4,
borderRadius: 2,
}}
>
{latestVersion === null ? (
<Typography>Checking for updates...</Typography>
) : currentVersion === latestVersion ? (
<Typography variant="h6" textAlign="center">
2024-12-21 19:24:47 +05:30
{t('navbar.upgrade.modal.up_to_date')}
2024-12-09 00:54:55 +05:30
</Typography>
) : (
<>
<Typography variant="body1" textAlign="left" sx={{ marginLeft: '30px' }}>
2024-12-21 19:24:47 +05:30
{t('navbar.upgrade.modal.new_version_available', { version: latestVersion })}
2024-12-09 00:54:55 +05:30
<br />
2024-12-21 19:24:47 +05:30
{t('navbar.upgrade.modal.view_updates')}
2024-12-09 00:54:55 +05:30
<a href="https://github.com/getmaxun/maxun/releases/" target="_blank" style={{ textDecoration: 'none' }}>{' '}here.</a>
</Typography>
<Tabs
value={tab}
onChange={handleUpdateTabChange}
2025-07-21 19:56:20 +05:30
sx={{ marginTop: 2, marginBottom: 2, marginLeft: '30px' }}
2024-12-09 00:54:55 +05:30
>
2024-12-21 19:24:47 +05:30
<Tab label={t('navbar.upgrade.modal.tabs.manual_setup')} />
<Tab label={t('navbar.upgrade.modal.tabs.docker_setup')} />
2024-12-09 00:54:55 +05:30
</Tabs>
{tab === 0 && (
<Box sx={{ marginLeft: '30px', background: '#cfd0d1', padding: 1, borderRadius: 3 }}>
<code style={{ color: 'black' }}>
<p>Run the commands below</p>
2024-12-20 17:44:10 +05:30
# cd to project directory (eg: maxun)
<br />
cd maxun
<br />
<br />
2024-12-09 00:54:55 +05:30
# pull latest changes
<br />
git pull origin master
<br />
<br />
# install dependencies
<br />
npm install
<br />
<br />
# start maxun
<br />
npm run start
</code>
</Box>
)}
{tab === 1 && (
<Box sx={{ marginLeft: '30px', background: '#cfd0d1', padding: 1, borderRadius: 3 }}>
<code style={{ color: 'black' }}>
<p>Run the commands below</p>
2024-12-20 17:44:39 +05:30
# cd to project directory (eg: maxun)
<br />
cd maxun
<br />
<br />
2024-12-20 17:45:49 +05:30
# stop the working containers
<br />
docker-compose down
<br />
<br />
2024-12-09 00:54:55 +05:30
# pull latest docker images
<br />
docker-compose pull
<br />
<br />
# start maxun
<br />
docker-compose up -d
</code>
</Box>
)}
</>
)}
</Box>
</Modal>
2025-01-30 18:20:27 +05:30
{/* <iframe
src="https://ghbtns.com/github-btn.html?user=getmaxun&repo=maxun&type=star&count=true&size=large"
// frameBorder="0"
// scrolling="0"
// width="170"
// height="30"
// title="GitHub">
// </iframe>*/}
2024-12-09 00:54:55 +05:30
<IconButton onClick={handleMenuOpen} sx={{
display: 'flex',
alignItems: 'center',
borderRadius: '5px',
padding: '8px',
marginRight: '10px',
2025-06-27 17:36:26 +05:30
'&:hover': {
background: 'inherit'
}
2024-12-08 20:29:53 +05:30
}}>
2024-12-09 00:54:55 +05:30
<AccountCircle sx={{ marginRight: '5px' }} />
<Typography variant="body1">{user.email}</Typography>
</IconButton>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
2024-12-09 00:54:55 +05:30
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
2024-12-09 00:54:55 +05:30
}}
PaperProps={{ sx: { width: '180px' } }}
>
<MenuItem onClick={() => { handleMenuClose(); logout(); }}>
2024-12-21 19:24:47 +05:30
<Logout sx={{ marginRight: '5px' }} /> {t('navbar.menu_items.logout')}
2024-12-09 00:54:55 +05:30
</MenuItem>
2025-01-30 19:59:35 +05:30
<MenuItem onClick={handleLangMenuOpen}>
<Language sx={{ marginRight: '5px' }} /> {t('navbar.menu_items.language')}
</MenuItem>
2025-01-30 20:00:32 +05:30
<hr />
2025-01-30 19:56:20 +05:30
<MenuItem onClick={() => {
window.open('https://github.com/getmaxun/maxun', '_blank');
}}>
2025-01-30 19:57:06 +05:30
<GitHub sx={{ marginRight: '5px' }} /> GitHub
2025-01-30 19:56:20 +05:30
</MenuItem>
2024-12-09 00:54:55 +05:30
<MenuItem onClick={() => {
window.open('https://discord.gg/5GbPjBUkws', '_blank');
}}>
<DiscordIcon sx={{ marginRight: '5px' }} /> Discord
</MenuItem>
<MenuItem onClick={() => {
window.open('https://www.youtube.com/@MaxunOSS/videos?ref=app', '_blank');
}}>
<YouTube sx={{ marginRight: '5px' }} /> YouTube
</MenuItem>
<MenuItem onClick={() => {
window.open('https://x.com/maxun_io?ref=app', '_blank');
}}>
2025-01-01 23:54:28 +05:30
<X sx={{ marginRight: '5px' }} /> Twitter (X)
2024-12-09 00:54:55 +05:30
</MenuItem>
2024-12-21 18:56:43 +05:30
<Menu
anchorEl={langAnchorEl}
open={Boolean(langAnchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
2024-12-21 18:56:43 +05:30
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
2024-12-21 18:56:43 +05:30
}}
>
<MenuItem
onClick={() => {
changeLanguage("en");
handleMenuClose();
}}
>
English
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("es");
handleMenuClose();
}}
>
Español
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("ja");
handleMenuClose();
}}
>
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("zh");
handleMenuClose();
}}
>
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("de");
handleMenuClose();
}}
>
Deutsch
</MenuItem>
2025-01-09 21:46:52 +05:30
<MenuItem
onClick={() => {
window.open('https://docs.maxun.dev/development/i18n', '_blank');
2025-01-09 21:46:52 +05:30
handleMenuClose();
}}
>
Add Language
</MenuItem>
2024-12-21 18:56:43 +05:30
</Menu>
</Menu>
2025-01-08 13:09:00 +05:30
{renderThemeToggle()}
</>
) : (
<>
<IconButton onClick={goToMainMenu} sx={{
borderRadius: '5px',
padding: '8px',
background: 'red',
color: 'white',
marginRight: '10px',
'&:hover': { color: 'white', backgroundColor: 'red' }
}}>
<Clear sx={{ marginRight: '5px' }} />
2024-12-21 19:24:47 +05:30
{t('navbar.recording.discard')}
</IconButton>
<SaveRecording fileName={recordingName} />
</>
)}
2024-12-21 18:35:08 +05:30
</div>
) : (
2025-01-08 19:58:50 +05:30
<NavBarRight>
<IconButton
2025-01-09 15:37:53 +05:30
onClick={handleLangMenuOpen}
sx={{
display: "flex",
alignItems: "center",
borderRadius: "5px",
padding: "8px",
marginRight: "8px",
}}
>
<Language sx={{ marginRight: '5px' }} /><Typography variant="body1">{t("Language")}</Typography>
</IconButton>
2024-12-21 18:35:08 +05:30
<Menu
anchorEl={langAnchorEl}
open={Boolean(langAnchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
2024-12-21 18:35:08 +05:30
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
2024-12-21 18:35:08 +05:30
}}
>
<MenuItem
onClick={() => {
changeLanguage("en");
handleMenuClose();
}}
>
English
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("es");
handleMenuClose();
}}
>
Español
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("ja");
handleMenuClose();
}}
>
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("zh");
handleMenuClose();
}}
>
</MenuItem>
2024-12-21 18:42:11 +05:30
<MenuItem
onClick={() => {
changeLanguage("de");
handleMenuClose();
}}
>
Deutsch
</MenuItem>
2025-01-09 21:46:52 +05:30
<MenuItem
2025-01-09 21:47:05 +05:30
onClick={() => {
window.open('https://docs.maxun.dev/development/i18n', '_blank');
2025-01-09 21:47:05 +05:30
handleMenuClose();
}}
>
Add Language
</MenuItem>
2025-01-08 19:58:50 +05:30
</Menu>
{renderThemeToggle()}
</NavBarRight>
2024-12-21 18:35:08 +05:30
)}
2024-12-09 00:54:55 +05:30
</NavBarWrapper>
2024-12-09 00:54:39 +05:30
</>
2024-06-24 22:34:54 +05:30
);
};
2024-11-07 00:46:47 +05:30
const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>`
2024-06-24 22:34:54 +05:30
grid-area: navbar;
2024-11-07 00:46:47 +05:30
background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')};
2024-12-07 22:20:17 +05:30
padding: 5px;
2024-06-24 22:34:54 +05:30
display: flex;
justify-content: space-between;
2024-11-07 00:46:47 +05:30
border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#333' : '#e0e0e0')};
2024-06-24 22:34:54 +05:30
`;
2024-11-07 00:46:47 +05:30
const ProjectName = styled.b<{ mode: 'light' | 'dark' }>`
2025-01-08 19:58:50 +05:30
color: ${({ mode }) => (mode === 'dark' ? '#ffffff' : '#3f4853')};
2024-06-24 22:34:54 +05:30
font-size: 1.3em;
`;
2024-11-24 00:49:39 +05:30
2025-01-08 19:58:50 +05:30
const NavBarRight = styled.div`
2024-11-24 00:49:39 +05:30
display: flex;
align-items: center;
justify-content: flex-end;
2025-01-08 19:58:50 +05:30
margin-left: auto;
2025-06-27 17:35:15 +05:30
`;