Create home page
This commit is contained in:
		
							
								
								
									
										56
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										56
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -11,10 +11,13 @@
 | 
				
			|||||||
        "@emotion/react": "^11.11.4",
 | 
					        "@emotion/react": "^11.11.4",
 | 
				
			||||||
        "@emotion/styled": "^11.11.5",
 | 
					        "@emotion/styled": "^11.11.5",
 | 
				
			||||||
        "@fontsource/roboto": "^5.0.13",
 | 
					        "@fontsource/roboto": "^5.0.13",
 | 
				
			||||||
 | 
					        "@mdi/js": "^7.4.47",
 | 
				
			||||||
 | 
					        "@mdi/react": "^1.6.1",
 | 
				
			||||||
        "@mui/icons-material": "^5.15.21",
 | 
					        "@mui/icons-material": "^5.15.21",
 | 
				
			||||||
        "@mui/material": "^5.15.21",
 | 
					        "@mui/material": "^5.15.21",
 | 
				
			||||||
        "react": "^18.3.1",
 | 
					        "react": "^18.3.1",
 | 
				
			||||||
        "react-dom": "^18.3.1"
 | 
					        "react-dom": "^18.3.1",
 | 
				
			||||||
 | 
					        "react-router-dom": "^6.24.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@types/react": "^18.3.3",
 | 
					        "@types/react": "^18.3.3",
 | 
				
			||||||
@@ -1138,6 +1141,19 @@
 | 
				
			|||||||
        "@jridgewell/sourcemap-codec": "^1.4.14"
 | 
					        "@jridgewell/sourcemap-codec": "^1.4.14"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@mdi/js": {
 | 
				
			||||||
 | 
					      "version": "7.4.47",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@mdi/react": {
 | 
				
			||||||
 | 
					      "version": "1.6.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@mdi/react/-/react-1.6.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-4qZeDcluDFGFTWkHs86VOlHkm6gnKaMql13/gpIcUQ8kzxHgpj31NuCkD8abECVfbULJ3shc7Yt4HJ6Wu6SN4w==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "prop-types": "^15.7.2"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@mui/base": {
 | 
					    "node_modules/@mui/base": {
 | 
				
			||||||
      "version": "5.0.0-beta.40",
 | 
					      "version": "5.0.0-beta.40",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz",
 | 
				
			||||||
@@ -1427,6 +1443,14 @@
 | 
				
			|||||||
        "url": "https://opencollective.com/popperjs"
 | 
					        "url": "https://opencollective.com/popperjs"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@remix-run/router": {
 | 
				
			||||||
 | 
					      "version": "1.17.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-2D6XaHEVvkCn682XBnipbJjgZUU7xjLtA4dGJRBVUKpEaDYOZMENZoZjAOSb7qirxt5RupjzZxz4fK2FO+EFPw==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=14.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@rollup/rollup-android-arm-eabi": {
 | 
					    "node_modules/@rollup/rollup-android-arm-eabi": {
 | 
				
			||||||
      "version": "4.18.0",
 | 
					      "version": "4.18.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
 | 
				
			||||||
@@ -3449,6 +3473,36 @@
 | 
				
			|||||||
        "node": ">=0.10.0"
 | 
					        "node": ">=0.10.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/react-router": {
 | 
				
			||||||
 | 
					      "version": "6.24.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-sQrgJ5bXk7vbcC4BxQxeNa5UmboFm35we1AFK0VvQaz9g0LzxEIuLOhHIoZ8rnu9BO21ishGeL9no1WB76W/eg==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@remix-run/router": "1.17.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=14.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": ">=16.8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/react-router-dom": {
 | 
				
			||||||
 | 
					      "version": "6.24.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-960sKuau6/yEwS8e+NVEidYQb1hNjAYM327gjEyXlc6r3Skf2vtwuJ2l7lssdegD2YjoKG5l8MsVyeTDlVeY8g==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@remix-run/router": "1.17.0",
 | 
				
			||||||
 | 
					        "react-router": "6.24.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=14.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": ">=16.8",
 | 
				
			||||||
 | 
					        "react-dom": ">=16.8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/react-transition-group": {
 | 
					    "node_modules/react-transition-group": {
 | 
				
			||||||
      "version": "4.4.5",
 | 
					      "version": "4.4.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,13 @@
 | 
				
			|||||||
    "@emotion/react": "^11.11.4",
 | 
					    "@emotion/react": "^11.11.4",
 | 
				
			||||||
    "@emotion/styled": "^11.11.5",
 | 
					    "@emotion/styled": "^11.11.5",
 | 
				
			||||||
    "@fontsource/roboto": "^5.0.13",
 | 
					    "@fontsource/roboto": "^5.0.13",
 | 
				
			||||||
 | 
					    "@mdi/js": "^7.4.47",
 | 
				
			||||||
 | 
					    "@mdi/react": "^1.6.1",
 | 
				
			||||||
    "@mui/icons-material": "^5.15.21",
 | 
					    "@mui/icons-material": "^5.15.21",
 | 
				
			||||||
    "@mui/material": "^5.15.21",
 | 
					    "@mui/material": "^5.15.21",
 | 
				
			||||||
    "react": "^18.3.1",
 | 
					    "react": "^18.3.1",
 | 
				
			||||||
    "react-dom": "^18.3.1"
 | 
					    "react-dom": "^18.3.1",
 | 
				
			||||||
 | 
					    "react-router-dom": "^6.24.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/react": "^18.3.3",
 | 
					    "@types/react": "^18.3.3",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,29 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Route,
 | 
				
			||||||
 | 
					  RouterProvider,
 | 
				
			||||||
 | 
					  createBrowserRouter,
 | 
				
			||||||
 | 
					  createRoutesFromElements,
 | 
				
			||||||
 | 
					} from "react-router-dom";
 | 
				
			||||||
import { AuthApi } from "./api/AuthApi";
 | 
					import { AuthApi } from "./api/AuthApi";
 | 
				
			||||||
import { ServerApi } from "./api/ServerApi";
 | 
					import { ServerApi } from "./api/ServerApi";
 | 
				
			||||||
import { LoginRoute } from "./routes/LoginRoute";
 | 
					import { LoginRoute } from "./routes/LoginRoute";
 | 
				
			||||||
 | 
					import { NotFoundRoute } from "./routes/NotFoundRoute";
 | 
				
			||||||
 | 
					import { HomeRoute } from "./routes/HomeRoute";
 | 
				
			||||||
 | 
					import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function App() {
 | 
					export function App() {
 | 
				
			||||||
  if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
 | 
					  if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
 | 
				
			||||||
    return <LoginRoute />;
 | 
					    return <LoginRoute />;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return <>logged in todo</>;
 | 
					  const router = createBrowserRouter(
 | 
				
			||||||
 | 
					    createRoutesFromElements(
 | 
				
			||||||
 | 
					      <Route path="*" element={<BaseAuthenticatedPage />}>
 | 
				
			||||||
 | 
					        <Route path="" element={<HomeRoute />} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <Route path="*" element={<NotFoundRoute />} />
 | 
				
			||||||
 | 
					      </Route>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <RouterProvider router={router} />;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { APIClient } from "./ApiClient";
 | 
					import { APIClient } from "./ApiClient";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface AuthInfo {
 | 
					export interface AuthInfo {
 | 
				
			||||||
  name: string;
 | 
					  id: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TokenStateKey = "auth-state";
 | 
					const TokenStateKey = "auth-state";
 | 
				
			||||||
@@ -60,11 +60,15 @@ export class AuthApi {
 | 
				
			|||||||
   * Sign out
 | 
					   * Sign out
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static async SignOut(): Promise<void> {
 | 
					  static async SignOut(): Promise<void> {
 | 
				
			||||||
    await APIClient.exec({
 | 
					 | 
				
			||||||
      uri: "/auth/sign_out",
 | 
					 | 
				
			||||||
      method: "GET",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.UnsetAuthenticated();
 | 
					    this.UnsetAuthenticated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        uri: "/auth/sign_out",
 | 
				
			||||||
 | 
					        method: "GET",
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      window.location.href = "/";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								central_frontend/src/routes/HomeRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								central_frontend/src/routes/HomeRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					export function HomeRoute(): React.ReactElement {
 | 
				
			||||||
 | 
					  return <>home authenticated todo</>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								central_frontend/src/routes/NotFoundRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								central_frontend/src/routes/NotFoundRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { Button } from "@mui/material";
 | 
				
			||||||
 | 
					import { RouterLink } from "../widgets/RouterLink";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function NotFoundRoute(): React.ReactElement {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      style={{
 | 
				
			||||||
 | 
					        textAlign: "center",
 | 
				
			||||||
 | 
					        flex: "1",
 | 
				
			||||||
 | 
					        display: "flex",
 | 
				
			||||||
 | 
					        flexDirection: "column",
 | 
				
			||||||
 | 
					        justifyContent: "center",
 | 
				
			||||||
 | 
					        alignItems: "center",
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <h1>404 Not found</h1>
 | 
				
			||||||
 | 
					      <p>The page you requested was not found!</p>
 | 
				
			||||||
 | 
					      <RouterLink to="/">
 | 
				
			||||||
 | 
					        <Button>Go back home</Button>
 | 
				
			||||||
 | 
					      </RouterLink>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								central_frontend/src/widgets/BaseAuthenticatedPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								central_frontend/src/widgets/BaseAuthenticatedPage.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import { Box, Button } from "@mui/material";
 | 
				
			||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { Outlet } from "react-router-dom";
 | 
				
			||||||
 | 
					import { AuthApi, AuthInfo } from "../api/AuthApi";
 | 
				
			||||||
 | 
					import { AsyncWidget } from "./AsyncWidget";
 | 
				
			||||||
 | 
					import { SolarEnergyAppBar } from "./SolarEnergyAppBar";
 | 
				
			||||||
 | 
					import { SolarEnergyNavList } from "./SolarEnergyNavList";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface AuthInfoContext {
 | 
				
			||||||
 | 
					  info: AuthInfo;
 | 
				
			||||||
 | 
					  reloadAuthInfo: () => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AuthInfoContextK = React.createContext<AuthInfoContext | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function BaseAuthenticatedPage(): React.ReactElement {
 | 
				
			||||||
 | 
					  const [authInfo, setAuthInfo] = React.useState<null | AuthInfo>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const signOut = () => {
 | 
				
			||||||
 | 
					    AuthApi.SignOut();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const load = async () => {
 | 
				
			||||||
 | 
					    setAuthInfo(await AuthApi.GetAuthInfo());
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <AsyncWidget
 | 
				
			||||||
 | 
					      loadKey="1"
 | 
				
			||||||
 | 
					      load={load}
 | 
				
			||||||
 | 
					      errMsg="Failed to load user information!"
 | 
				
			||||||
 | 
					      errAdditionalElement={() => (
 | 
				
			||||||
 | 
					        <>
 | 
				
			||||||
 | 
					          <Button onClick={signOut}>Sign out</Button>
 | 
				
			||||||
 | 
					        </>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      build={() => (
 | 
				
			||||||
 | 
					        <AuthInfoContextK.Provider
 | 
				
			||||||
 | 
					          value={{
 | 
				
			||||||
 | 
					            info: authInfo!,
 | 
				
			||||||
 | 
					            reloadAuthInfo: load,
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Box
 | 
				
			||||||
 | 
					            component="div"
 | 
				
			||||||
 | 
					            sx={{
 | 
				
			||||||
 | 
					              minHeight: "100vh",
 | 
				
			||||||
 | 
					              display: "flex",
 | 
				
			||||||
 | 
					              flexDirection: "column",
 | 
				
			||||||
 | 
					              backgroundColor: (theme) =>
 | 
				
			||||||
 | 
					                theme.palette.mode === "light"
 | 
				
			||||||
 | 
					                  ? theme.palette.grey[100]
 | 
				
			||||||
 | 
					                  : theme.palette.grey[900],
 | 
				
			||||||
 | 
					              color: (theme) =>
 | 
				
			||||||
 | 
					                theme.palette.mode === "light"
 | 
				
			||||||
 | 
					                  ? theme.palette.grey[900]
 | 
				
			||||||
 | 
					                  : theme.palette.grey[100],
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <SolarEnergyAppBar onSignOut={signOut} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <Box
 | 
				
			||||||
 | 
					              sx={{
 | 
				
			||||||
 | 
					                display: "flex",
 | 
				
			||||||
 | 
					                flex: "2",
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <SolarEnergyNavList />
 | 
				
			||||||
 | 
					              <div style={{ flex: 1, display: "flex" }}>
 | 
				
			||||||
 | 
					                <Outlet />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </Box>
 | 
				
			||||||
 | 
					          </Box>
 | 
				
			||||||
 | 
					        </AuthInfoContextK.Provider>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useAuthInfo(): AuthInfoContext {
 | 
				
			||||||
 | 
					  return React.useContext(AuthInfoContextK)!;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								central_frontend/src/widgets/DarkThemeButton.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								central_frontend/src/widgets/DarkThemeButton.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import Brightness7Icon from "@mui/icons-material/Brightness7";
 | 
				
			||||||
 | 
					import DarkModeIcon from "@mui/icons-material/DarkMode";
 | 
				
			||||||
 | 
					import { IconButton, Tooltip } from "@mui/material";
 | 
				
			||||||
 | 
					import { useDarkTheme } from "../hooks/context_providers/DarkThemeProvider";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function DarkThemeButton(): React.ReactElement {
 | 
				
			||||||
 | 
					  const darkTheme = useDarkTheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Tooltip title="Activer / désactiver le mode sombre">
 | 
				
			||||||
 | 
					      <IconButton
 | 
				
			||||||
 | 
					        onClick={() => darkTheme.setEnabled(!darkTheme.enabled)}
 | 
				
			||||||
 | 
					        style={{ color: "inherit" }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {!darkTheme.enabled ? <DarkModeIcon /> : <Brightness7Icon />}
 | 
				
			||||||
 | 
					      </IconButton>
 | 
				
			||||||
 | 
					    </Tooltip>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								central_frontend/src/widgets/RouterLink.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								central_frontend/src/widgets/RouterLink.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import { PropsWithChildren } from "react";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RouterLink(
 | 
				
			||||||
 | 
					  p: PropsWithChildren<{ to: string; target?: React.HTMLAttributeAnchorTarget }>
 | 
				
			||||||
 | 
					): React.ReactElement {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Link
 | 
				
			||||||
 | 
					      to={p.to}
 | 
				
			||||||
 | 
					      target={p.target}
 | 
				
			||||||
 | 
					      style={{ color: "inherit", textDecoration: "inherit" }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {p.children}
 | 
				
			||||||
 | 
					    </Link>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										85
									
								
								central_frontend/src/widgets/SolarEnergyAppBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								central_frontend/src/widgets/SolarEnergyAppBar.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					import { mdiWhiteBalanceSunny } from "@mdi/js";
 | 
				
			||||||
 | 
					import Icon from "@mdi/react";
 | 
				
			||||||
 | 
					import SettingsIcon from "@mui/icons-material/Settings";
 | 
				
			||||||
 | 
					import { Button } from "@mui/material";
 | 
				
			||||||
 | 
					import AppBar from "@mui/material/AppBar";
 | 
				
			||||||
 | 
					import Menu from "@mui/material/Menu";
 | 
				
			||||||
 | 
					import MenuItem from "@mui/material/MenuItem";
 | 
				
			||||||
 | 
					import Toolbar from "@mui/material/Toolbar";
 | 
				
			||||||
 | 
					import Typography from "@mui/material/Typography";
 | 
				
			||||||
 | 
					import * as React from "react";
 | 
				
			||||||
 | 
					import { useAuthInfo } from "./BaseAuthenticatedPage";
 | 
				
			||||||
 | 
					import { DarkThemeButton } from "./DarkThemeButton";
 | 
				
			||||||
 | 
					import { RouterLink } from "./RouterLink";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function SolarEnergyAppBar(p: {
 | 
				
			||||||
 | 
					  onSignOut: () => void;
 | 
				
			||||||
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  const authInfo = useAuthInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
 | 
				
			||||||
 | 
					  const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
 | 
				
			||||||
 | 
					    setAnchorEl(event.currentTarget);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCloseMenu = () => {
 | 
				
			||||||
 | 
					    setAnchorEl(null);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const signOut = () => {
 | 
				
			||||||
 | 
					    handleCloseMenu();
 | 
				
			||||||
 | 
					    p.onSignOut();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <AppBar position="sticky">
 | 
				
			||||||
 | 
					      <Toolbar>
 | 
				
			||||||
 | 
					        <Icon
 | 
				
			||||||
 | 
					          path={mdiWhiteBalanceSunny}
 | 
				
			||||||
 | 
					          size={1}
 | 
				
			||||||
 | 
					          style={{ marginRight: "1rem" }}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
 | 
				
			||||||
 | 
					          <RouterLink to="/">Solar Energy</RouterLink>
 | 
				
			||||||
 | 
					        </Typography>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <DarkThemeButton />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <Button size="large" color="inherit">
 | 
				
			||||||
 | 
					            {authInfo!.info.id}
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <Button
 | 
				
			||||||
 | 
					            size="large"
 | 
				
			||||||
 | 
					            aria-label="account of current user"
 | 
				
			||||||
 | 
					            aria-controls="menu-appbar"
 | 
				
			||||||
 | 
					            aria-haspopup="true"
 | 
				
			||||||
 | 
					            onClick={handleMenu}
 | 
				
			||||||
 | 
					            color="inherit"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <SettingsIcon />
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					          <Menu
 | 
				
			||||||
 | 
					            id="menu-appbar"
 | 
				
			||||||
 | 
					            anchorEl={anchorEl}
 | 
				
			||||||
 | 
					            anchorOrigin={{
 | 
				
			||||||
 | 
					              vertical: "top",
 | 
				
			||||||
 | 
					              horizontal: "right",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            keepMounted
 | 
				
			||||||
 | 
					            transformOrigin={{
 | 
				
			||||||
 | 
					              vertical: "top",
 | 
				
			||||||
 | 
					              horizontal: "right",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            open={Boolean(anchorEl)}
 | 
				
			||||||
 | 
					            onClose={handleCloseMenu}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <MenuItem onClick={signOut}>Déconnexion</MenuItem>
 | 
				
			||||||
 | 
					          </Menu>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </Toolbar>
 | 
				
			||||||
 | 
					    </AppBar>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								central_frontend/src/widgets/SolarEnergyNavList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								central_frontend/src/widgets/SolarEnergyNavList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  mdiAccountMultiple,
 | 
				
			||||||
 | 
					  mdiAccountMusic,
 | 
				
			||||||
 | 
					  mdiAlbum,
 | 
				
			||||||
 | 
					  mdiApi,
 | 
				
			||||||
 | 
					  mdiChartLine,
 | 
				
			||||||
 | 
					  mdiCog,
 | 
				
			||||||
 | 
					  mdiHome,
 | 
				
			||||||
 | 
					  mdiInbox,
 | 
				
			||||||
 | 
					  mdiMusic,
 | 
				
			||||||
 | 
					} from "@mdi/js";
 | 
				
			||||||
 | 
					import Icon from "@mdi/react";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  List,
 | 
				
			||||||
 | 
					  ListItemButton,
 | 
				
			||||||
 | 
					  ListItemIcon,
 | 
				
			||||||
 | 
					  ListItemSecondaryAction,
 | 
				
			||||||
 | 
					  ListItemText,
 | 
				
			||||||
 | 
					  ListSubheader,
 | 
				
			||||||
 | 
					} from "@mui/material";
 | 
				
			||||||
 | 
					import { useLocation } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useAuthInfo } from "./BaseAuthenticatedPage";
 | 
				
			||||||
 | 
					import { RouterLink } from "./RouterLink";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function SolarEnergyNavList(): React.ReactElement {
 | 
				
			||||||
 | 
					  const user = useAuthInfo().info;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <List
 | 
				
			||||||
 | 
					      dense
 | 
				
			||||||
 | 
					      component="nav"
 | 
				
			||||||
 | 
					      sx={{
 | 
				
			||||||
 | 
					        minWidth: "200px",
 | 
				
			||||||
 | 
					        backgroundColor: "background.paper",
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <NavLink label="Home" uri="/" icon={<Icon path={mdiHome} size={1} />} />
 | 
				
			||||||
 | 
					    </List>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function NavLink(p: {
 | 
				
			||||||
 | 
					  icon: React.ReactElement;
 | 
				
			||||||
 | 
					  uri: string;
 | 
				
			||||||
 | 
					  label: string;
 | 
				
			||||||
 | 
					  secondaryAction?: React.ReactElement;
 | 
				
			||||||
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <RouterLink to={p.uri}>
 | 
				
			||||||
 | 
					      <ListItemButton selected={p.uri === location.pathname}>
 | 
				
			||||||
 | 
					        <ListItemIcon>{p.icon}</ListItemIcon>
 | 
				
			||||||
 | 
					        <ListItemText primary={p.label} />
 | 
				
			||||||
 | 
					        {p.secondaryAction && (
 | 
				
			||||||
 | 
					          <ListItemSecondaryAction>{p.secondaryAction}</ListItemSecondaryAction>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      </ListItemButton>
 | 
				
			||||||
 | 
					    </RouterLink>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user