/ frontend / src / app / components / Footer.jsx
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  }