diff --git a/package.json b/package.json index 73ad90d..f79d13e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@fullcalendar/interaction": "5.10.0", "@fullcalendar/react": "5.10.0", "@fullcalendar/timegrid": "5.10.0", - "@kingsrook/qqq-frontend-core": "1.0.6", + "@kingsrook/qqq-frontend-core": "1.0.7", "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", diff --git a/src/App.tsx b/src/App.tsx index 2a64679..19baa15 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -38,9 +38,7 @@ import {useMaterialUIController, setMiniSidenav, setOpenConfigurator} from "cont // Images import nfLogo from "assets/images/nutrifresh_one_icon_white.png"; import {Md5} from "ts-md5/dist/md5"; -import AuthenticationButton from "qqq/components/buttons/AuthenticationButton"; import {useCookies} from "react-cookie"; -import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import EntityCreate from "./qqq/pages/entity-create"; import EntityList from "./qqq/pages/entity-list"; import EntityView from "./qqq/pages/entity-view"; @@ -49,7 +47,6 @@ import ProcessRun from "./qqq/pages/process-run"; import MDAvatar from "./components/MDAvatar"; import ProfileOverview from "./layouts/pages/profile/profile-overview"; import Settings from "./layouts/pages/account/settings"; -import SignInBasic from "./layouts/authentication/sign-in/basic"; import Analytics from "./layouts/dashboards/analytics"; import Sales from "./layouts/dashboards/sales"; import QClient from "./qqq/utils/QClient"; @@ -86,14 +83,14 @@ function getStaticRoutes() ]; } -const SESSION_ID_COOKIE_NAME = "sessionId"; +export const SESSION_ID_COOKIE_NAME = "sessionId"; LicenseInfo.setLicenseKey(process.env.REACT_APP_MATERIAL_UI_LICENSE_KEY); export default function App() { const [, setCookie] = useCookies([SESSION_ID_COOKIE_NAME]); const { - user, getAccessTokenSilently, getIdTokenClaims, logout, + user, getAccessTokenSilently, getIdTokenClaims, logout, loginWithRedirect, } = useAuth0(); const [loadingToken, setLoadingToken] = useState(false); const [isFullyAuthenticated, setIsFullyAuthenticated] = useState(false); @@ -110,7 +107,7 @@ export default function App() try { console.log("Loading token..."); - const accessToken = await getAccessTokenSilently(); + await getAccessTokenSilently(); const idToken = await getIdTokenClaims(); setCookie(SESSION_ID_COOKIE_NAME, idToken.__raw, {path: "/"}); setIsFullyAuthenticated(true); @@ -131,8 +128,6 @@ export default function App() layout, openConfigurator, sidenavColor, - transparentSidenav, - whiteSidenav, darkMode, } = controller; const [onMouseEnter, setOnMouseEnter] = useState(false); @@ -156,8 +151,7 @@ export default function App() { try { - console.log("ok now loading qqq things"); - const metaData = await QClient.loadMetaData(); + const metaData = await QClient.getInstance().loadMetaData(); // get the keys sorted const keys = [...metaData.tables.keys()].sort((a, b): number => @@ -203,12 +197,6 @@ export default function App() route: "/pages/account/settings", component: , }, - { - name: "Logout", - key: "logout", - route: "/authentication/sign-in/basic", - component: , - }, ], }; @@ -294,27 +282,6 @@ export default function App() }, ); - const authButton = ( - - - - ); - const configsButton = ( {configsButton} - {authButton} )} diff --git a/src/HandleAuthorizationError.tsx b/src/HandleAuthorizationError.tsx new file mode 100644 index 0000000..99468c9 --- /dev/null +++ b/src/HandleAuthorizationError.tsx @@ -0,0 +1,29 @@ +import React, { + useState, + useEffect, + JSXElementConstructor, + Key, + ReactElement, +} from "react"; +import {SESSION_ID_COOKIE_NAME} from "App"; +import {useCookies} from "react-cookie"; +import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; + +interface Props +{ + errorMessage?: string; +} + +export default function HandleAuthorizationError({errorMessage}: Props) +{ + const [, , removeCookie] = useCookies([SESSION_ID_COOKIE_NAME]); + + useEffect(() => + { + removeCookie(SESSION_ID_COOKIE_NAME, {path: "/"}); + }); + + return ( +
{errorMessage}
+ ); +} diff --git a/src/examples/Sidenav/index.tsx b/src/examples/Sidenav/index.tsx index c6efb07..a756d09 100644 --- a/src/examples/Sidenav/index.tsx +++ b/src/examples/Sidenav/index.tsx @@ -44,6 +44,7 @@ import { setTransparentSidenav, setWhiteSidenav, } from "context"; +import AuthenticationButton from "qqq/components/Buttons/AuthenticationButton"; // Declaring props types for Sidenav interface Props { @@ -314,6 +315,7 @@ function Sidenav({ color, brand, brandName, routes, ...rest }: Props): JSX.Eleme } /> {renderRoutes} + ); } diff --git a/src/index.tsx b/src/index.tsx index 69ff9d7..4f978af 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,5 @@ import ReactDOM from "react-dom"; -import {BrowserRouter, useNavigate} from "react-router-dom"; +import {BrowserRouter, useNavigate, useSearchParams} from "react-router-dom"; import {Auth0Provider} from "@auth0/auth0-react"; import App from "App"; @@ -8,39 +8,39 @@ import {MaterialUIControllerProvider} from "context"; import "./qqq/styles/qqq-override-styles.css"; import ProtectedRoute from "qqq/auth0/protected-route"; import React from "react"; +import HandleAuthorizationError from "HandleAuthorizationError"; // Auth0 params from env const domain = process.env.REACT_APP_AUTH0_DOMAIN; const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID; -/* -ReactDOM.render( - - - - - , - document.getElementById("root"), -); - */ - -console.log("what"); - // @ts-ignore function Auth0ProviderWithRedirectCallback({children, ...props}) { const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + // @ts-ignore const onRedirectCallback = (appState) => { navigate((appState && appState.returnTo) || window.location.pathname); }; - return ( - // @ts-ignore - - {children} - - ); + if (searchParams.get("error")) + { + return ( + // @ts-ignore + + ); + } + else + { + return ( + // @ts-ignore + + {children} + + ); + } } ReactDOM.render( @@ -57,5 +57,3 @@ ReactDOM.render( , document.getElementById("root"), ); - -export * from "components/MDButton"; diff --git a/src/qqq/components/buttons/AuthenticationButton/index.tsx b/src/qqq/components/Buttons/AuthenticationButton/index.tsx similarity index 100% rename from src/qqq/components/buttons/AuthenticationButton/index.tsx rename to src/qqq/components/Buttons/AuthenticationButton/index.tsx diff --git a/src/qqq/components/EntityForm/index.tsx b/src/qqq/components/EntityForm/index.tsx index 41d8a3f..693b2a3 100644 --- a/src/qqq/components/EntityForm/index.tsx +++ b/src/qqq/components/EntityForm/index.tsx @@ -21,6 +21,7 @@ import {Alert} from "@mui/material"; import MDBox from "components/MDBox"; import MDTypography from "components/MDTypography"; import MDButton from "../../../components/MDButton"; +import QClient from "qqq/utils/QClient"; // Declaring props types for EntityForm interface Props @@ -30,7 +31,7 @@ interface Props function EntityForm({id}: Props): JSX.Element { - const qController = new QController(""); + const qController = QClient.getInstance(); const {tableName} = useParams(); const [validations, setValidations] = useState({}); diff --git a/src/qqq/components/Navbar/index.tsx b/src/qqq/components/Navbar/index.tsx index 38606b7..4653d27 100644 --- a/src/qqq/components/Navbar/index.tsx +++ b/src/qqq/components/Navbar/index.tsx @@ -38,7 +38,6 @@ import { } from "context"; // qqq -import AuthenticationButton from "qqq/components/buttons/AuthenticationButton"; // Declaring prop types for Navbar interface Props @@ -159,14 +158,6 @@ function Navbar({absolute, light, isMini}: Props): JSX.Element
- - { /* - - - account_circle - - - */ } { - const newTableMetaData = await QClient.loadTableMetaData(tableName); + const newTableMetaData = await qController.loadTableMetaData(tableName); setTableMetaData(newTableMetaData); if (columnSortModel.length === 0) { @@ -206,14 +207,14 @@ function EntityList({table}: Props): JSX.Element const qFilter = buildQFilter(); - const count = await QClient.count(tableName, qFilter); + const count = await qController.count(tableName, qFilter); setTotalRecords(count); setButtonText(`new ${newTableMetaData.label}`); setTableLabel(newTableMetaData.label); const columns = [] as GridColDef[]; - const results = await QClient.query( + const results = await qController.query( tableName, qFilter, rowsPerPage, @@ -362,7 +363,7 @@ function EntityList({table}: Props): JSX.Element setTableState(tableName); setFilterModel(null); setFiltersMenu(null); - const metaData = await QClient.loadMetaData(); + const metaData = await qController.loadMetaData(); setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName)); diff --git a/src/qqq/pages/entity-view/components/ViewContents/index.tsx b/src/qqq/pages/entity-view/components/ViewContents/index.tsx index ff1db94..8470b5c 100644 --- a/src/qqq/pages/entity-view/components/ViewContents/index.tsx +++ b/src/qqq/pages/entity-view/components/ViewContents/index.tsx @@ -38,8 +38,9 @@ import Icon from "@mui/material/Icon"; import MDAlert from "components/MDAlert"; import MDButton from "../../../../../components/MDButton"; import QProcessUtils from "../../../../utils/QProcessUtils"; +import QClient from "qqq/utils/QClient"; -const qController = new QController(""); +const qController = QClient.getInstance(); // Declaring props types for ViewForm interface Props diff --git a/src/qqq/utils/QClient.ts b/src/qqq/utils/QClient.ts index a8153cb..960595d 100644 --- a/src/qqq/utils/QClient.ts +++ b/src/qqq/utils/QClient.ts @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QController} from "@kingsrook/qqq-frontend-core/lib/controllers/QController"; -import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter"; +import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException"; +import {useAuth0} from "@auth0/auth0-react"; /******************************************************************************* ** client wrapper of qqq backend @@ -31,40 +31,25 @@ class QClient { private static qController: QController; + private static handleException(exception: QException) + { + console.log(`Caught Exception: ${JSON.stringify(exception)}`); + const {logout} = useAuth0(); + if (exception.status === "401") + { + logout(); + } + } + public static getInstance() { if (this.qController == null) { - this.qController = new QController(""); + this.qController = new QController("", this.handleException); } return this.qController; } - - public static loadTableMetaData(tableName: string) - { - return this.getInstance().loadTableMetaData(tableName); - } - - public static loadMetaData() - { - return this.getInstance().loadMetaData(); - } - - public static query(tableName: string, filter: QQueryFilter, limit: number, skip: number) - { - return this.getInstance() - .query(tableName, filter, limit, skip) - .catch((error) => - { - throw error; - }); - } - - public static count(tableName: string, filter: QQueryFilter) - { - return this.getInstance().count(tableName, filter); - } } export default QClient;