Footer.jsx
1 import { AppBar, ThemeProvider, Toolbar, styled, useTheme } from "@mui/material"; 2 import React, { useState, useEffect } from "react"; 3 4 import { Paragraph } from "./Typography"; 5 import useSettings from "app/hooks/useSettings"; 6 import useAuth from "app/hooks/useAuth"; 7 import { topBarHeight } from "app/utils/constant"; 8 import { ToastContainer } from 'react-toastify'; 9 import 'react-toastify/dist/ReactToastify.css'; 10 import { useNavigate } from "react-router-dom"; 11 import { usePlatformCapabilities } from "app/contexts/PlatformContext"; 12 import api from "app/utils/api"; 13 14 const AppFooter = styled(Toolbar)(() => ({ 15 display: "flex", 16 alignItems: "center", 17 minHeight: topBarHeight, 18 "@media (max-width: 499px)": { 19 display: "table", 20 width: "100%", 21 minHeight: "auto", 22 padding: "1rem 0", 23 "& .container": { 24 flexDirection: "column !important", 25 "& a": { margin: "0 0 16px !important" } 26 } 27 } 28 })); 29 30 const FooterContent = styled("div")(() => ({ 31 width: "100%", 32 display: "flex", 33 alignItems: "center", 34 padding: "0px 1rem", 35 maxWidth: "1170px", 36 margin: "0 auto" 37 })); 38 39 export default function Footer() { 40 const theme = useTheme(); 41 const { settings } = useSettings(); 42 const { platformCapabilities } = usePlatformCapabilities(); 43 44 const footerTheme = settings.themes[settings.footer.theme] || theme; 45 46 const [version, setVersion] = useState(null); 47 const [updateInfo, setUpdateInfo] = useState(null); 48 const auth = useAuth(); 49 50 const navigate = useNavigate(); 51 const isAuthenticated = auth.isAuthenticated; 52 const token = auth.user?.token; 53 54 useEffect(() => { 55 if (!isAuthenticated) return; 56 57 const opts = { silent: true, credentials: "include" }; 58 59 api.get("/version", token, opts) 60 .then((d) => { if (d?.version) setVersion(d.version); }) 61 .catch(() => {}); 62 63 api.get("/version/check", token, opts) 64 .then((d) => { 65 if (d?.current) setVersion(d.current); 66 if (d?.update_available) setUpdateInfo(d); 67 }) 68 .catch(() => {}); 69 }, [isAuthenticated]); 70 71 return ( 72 <ThemeProvider theme={footerTheme}> 73 <ToastContainer 74 position="top-right" 75 autoClose={8000} 76 hideProgressBar={false} 77 newestOnTop={false} 78 closeOnClick 79 rtl={false} 80 pauseOnFocusLoss 81 draggable 82 pauseOnHover 83 theme="light" 84 /> 85 <AppBar color="primary" position="static" sx={{ zIndex: 96 }}> 86 <AppFooter> 87 <FooterContent style={{ textAlign: "center" }}> 88 <Paragraph alignItems="center" width={"100%"}> 89 {!platformCapabilities.hide_branding && ( 90 <> 91 Powered by <b><a href="https://github.com/apocas/restai">RESTai</a></b>, so many 'A's and 'I's, so little time... 92 <br /> 93 </> 94 )} 95 {(version) && <span style={{ fontSize: "0.7rem" }}>v{version}</span>} 96 {updateInfo && ( 97 <a 98 href={updateInfo.latest_url} 99 target="_blank" 100 rel="noopener noreferrer" 101 style={{ 102 marginLeft: 8, 103 fontSize: "0.65rem", 104 fontWeight: 600, 105 padding: "2px 8px", 106 borderRadius: 10, 107 backgroundColor: "rgba(99,102,241,0.15)", 108 color: "#6366f1", 109 textDecoration: "none", 110 }} 111 > 112 Update available: v{updateInfo.latest} 113 </a> 114 )} 115 </Paragraph> 116 </FooterContent> 117 </AppFooter> 118 </AppBar> 119 </ThemeProvider > 120 ); 121 }