From 24d27121d169b155604b01e9707fb0ff096c2ede Mon Sep 17 00:00:00 2001 From: Carter Date: Thu, 3 Jul 2025 13:41:09 -0600 Subject: [PATCH] added signup callback page that runs an api call to finish signup --- src/app/main.tsx | 4 +- src/navigation/Router.tsx | 3 ++ src/pages/SignupCallback.tsx | 87 ++++++++++++++++++++++++++++++++++ src/providers/auth.tsx | 49 ++++++++++++------- src/providers/pond/userAPI.tsx | 20 +++++++- 5 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 src/pages/SignupCallback.tsx diff --git a/src/app/main.tsx b/src/app/main.tsx index e2acdd9..2d8615c 100644 --- a/src/app/main.tsx +++ b/src/app/main.tsx @@ -19,7 +19,7 @@ if ('serviceWorker' in navigator) { } createRoot(document.getElementById('root')!).render( - + // - , + // , ) diff --git a/src/navigation/Router.tsx b/src/navigation/Router.tsx index 29362ad..f6badb1 100644 --- a/src/navigation/Router.tsx +++ b/src/navigation/Router.tsx @@ -9,6 +9,7 @@ import { getWhitelabel } from "services/whiteLabel"; import Ventilation from "pages/VentEditor"; import { useGlobalState } from "providers"; import DeviceSupport from "pages/DeviceSupport"; +import SignupCallback from "pages/SignupCallback"; const DeviceHistory = lazy(() => import("pages/DeviceHistory")); const DevicePage = lazy(() => import("pages/Device")); @@ -302,6 +303,8 @@ export default function Router() { {/* Redirects */} } /> + {/* } /> */} + } /> {/* } /> */} {/* } /> */} {/* } /> */} diff --git a/src/pages/SignupCallback.tsx b/src/pages/SignupCallback.tsx new file mode 100644 index 0000000..78215f4 --- /dev/null +++ b/src/pages/SignupCallback.tsx @@ -0,0 +1,87 @@ +import { useDeviceAPI, useUserAPI } from "hooks"; +import PageContainer from "./PageContainer"; +import { useEffect, useState } from "react"; +import { Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Divider } from "@mui/material"; +import { useBinAPI, useTeamAPI } from "providers"; +import { CheckCircleOutline } from "@mui/icons-material"; +import { green } from "@mui/material/colors"; + +interface Props { + +} + +export default function SignupCallback (props: Props) { + const userAPI = useUserAPI(); + const teamAPI = useTeamAPI() + const deviceAPI = useDeviceAPI(); + const binAPI = useBinAPI(); + const [loading, setLoading] = useState(false) + const [signupDialogOpen, setSignupDialogOpen] = useState(true) + const [hasTeams, setHasTeams] = useState(false) + const [hasDevices, setHasDevices] = useState(false) + const [hasBins, setHasBins] = useState(false) + + const [doneBins, setDoneBins] = useState(false) + const [doneTeams, setDoneTeams] = useState(false) + const [doneDevices, setDoneDevices] = useState(false) + + useEffect(() => { + console.log(hasTeams) + }, [hasTeams]) + + useEffect(() => { + setLoading(true) + userAPI.completeSignup().then(resp => { + console.log(resp) + teamAPI.listTeams(1, 0).then(resp => { + setHasTeams(resp.data.teams.length > 0) + }).finally(() => setDoneTeams(true)) + deviceAPI.list(1, 0).then(resp => { + setHasDevices(resp.data.devices.length > 0) + }).finally(() => setDoneDevices(true)) + binAPI.listBins(1, 0).then(resp => { + setHasBins(resp.data.bins.length > 0) + }).finally(() => setDoneBins(true)) + }).finally(() => setLoading(false)) + }, []) + + const loadingComplete = () => { + return loading === false && doneBins && doneTeams && doneDevices + } + + const content = () => { + return ( + + { loadingComplete() ? + + : + + } + + {hasTeams && "Teams found!"} + {hasDevices && "Devices found!"} + {hasBins && "Bins found!"} + + + ) + } + + return ( + + + + Finishing Signup + + + { content() } + + {loadingComplete() && + + } + + + + ) +} \ No newline at end of file diff --git a/src/providers/auth.tsx b/src/providers/auth.tsx index 22ac76d..f7ee585 100644 --- a/src/providers/auth.tsx +++ b/src/providers/auth.tsx @@ -9,28 +9,30 @@ interface Props extends PropsWithChildren{ export default function AuthWrapper(props: Props) { const { children, setToken } = props; - const { isLoading, loginWithRedirect, isAuthenticated, getAccessTokenSilently } = useAuth0(); + const { isLoading, loginWithRedirect, isAuthenticated, getAccessTokenSilently, getIdTokenClaims } = useAuth0(); useEffect(() => { const url = new URL(window.location.href); - const isManualLoginPage = url.pathname.includes("/login"); + const options: RedirectLoginOptions = { + authorizationParams: {} // Initialize here + }; - if (isManualLoginPage) { - const options: RedirectLoginOptions = { - authorizationParams: {} // Initialize here - }; - + if (isManualLoginPage && options.authorizationParams) { + let parsed = queryString.parse(url.search); if (parsed.signup === "true") { - options.authorizationParams!.screen_hint = "signup"; - options.authorizationParams!.prompt = "login"; + options.authorizationParams.screen_hint = "signUp"; + // options.authorizationParams.m + // options.authorizationParams.prompt = "login"; } if (parsed.email && parsed.email !== "") { - options.authorizationParams!.login_hint = parsed.email.toString(); // prefill email + options.authorizationParams.login_hint = parsed.email.toString(); // prefill email } + + options.authorizationParams.redirect_uri = "http://localhost:5173/signupCallback" loginWithRedirect(options) @@ -40,15 +42,28 @@ export default function AuthWrapper(props: Props) { }, [isAuthenticated, loginWithRedirect, isLoading]); useEffect(() => { - if (isAuthenticated) getAccessTokenSilently().then(t => { - if (t.length < 1) { + const url = new URL(window.location.href); + const isSignupCallback = url.pathname.includes("/signupCallback"); + if (isAuthenticated) { + getAccessTokenSilently().then(t => { + if (t.length < 1) { + loginWithRedirect() + } + setToken(t) + }).catch(() => { + // No token, go back to login loginWithRedirect() + }) + if (isSignupCallback) { + console.log("IS SIGNUP") + getIdTokenClaims().then(id_claims => { + console.log(id_claims) + console.log(id_claims?.nickname) + if (id_claims) console.log(Object.keys(id_claims)) + }) } - setToken(t) - }).catch(() => { - // No token, go back to login - loginWithRedirect() - }) + + } }, [setToken, isAuthenticated]) return children; diff --git a/src/providers/pond/userAPI.tsx b/src/providers/pond/userAPI.tsx index 247f77c..21befb2 100644 --- a/src/providers/pond/userAPI.tsx +++ b/src/providers/pond/userAPI.tsx @@ -28,6 +28,7 @@ export interface IUserAPIContext { prefixSearch?: string, ) => Promise; listProfiles: () => Promise; + completeSignup: () => Promise; listObjectUsers: (scope: Scope) => Promise; updateObjectUsers: (scope: Scope, users: pond.IUser[]) => Promise; getUser: (id: string, scope?: Scope) => Promise; @@ -55,8 +56,22 @@ export const UserAPIContext = createContext({} as IUserAPIConte export default function UserProvider(props: PropsWithChildren) { const { children } = props; - const { get, put } = useHTTP(); - const [{ as }] = useGlobalState(); + const { get, put, post } = useHTTP(); + const [{ as, user }] = useGlobalState(); + + const completeSignup = (): Promise => { + return new Promise((resolve, reject) => { + let request = pond.CompleteSignupUserRequest.create(); + request.avatar = user.settings.avatar + request.email = user.settings.email + request.id = user.id() + request.name = user.name() + post(pondURL("/signups"), request).then(res => { + console.log(res) + resolve(pond.CompleteSignupUserResponse.create()) + }) + }) + } const listUsers = ( limit: number, @@ -234,6 +249,7 @@ export default function UserProvider(props: PropsWithChildren) { return (