diff --git a/package-lock.json b/package-lock.json index ab361c3..836acc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.0", "dependencies": { "@auth0/auth0-react": "^2.2.4", + "axios": "^1.7.7", + "moment": "^2.30.1", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -1810,6 +1812,23 @@ "node": ">=12" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1974,6 +1993,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2045,6 +2076,15 @@ "dev": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.41", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", @@ -2513,6 +2553,40 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2834,6 +2908,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2847,6 +2942,15 @@ "node": "*" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3046,6 +3150,12 @@ "node": ">= 0.8.0" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 8c795b4..73fda9e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ }, "dependencies": { "@auth0/auth0-react": "^2.2.4", + "axios": "^1.7.7", + "moment": "^2.30.1", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/src/app/App.tsx b/src/app/App.tsx index ac7cc17..1e5a48f 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -5,10 +5,13 @@ import './App.css' import { Auth0Provider } from '@auth0/auth0-react' import { or } from '../utils/types' import AuthWrapper from '../providers/auth' -import LoginButton from '../providers/LoginButton' +import HTTPProvider from '../providers/http' +import { useUserAPI } from '../providers/pond/userAPI' +// import LoginButton from '../providers/LoginButton' function App() { const [count, setCount] = useState(0) + // const userAPI = useUserAPI(); let url: string | undefined = window.location.origin; let audience: string | undefined; @@ -34,29 +37,32 @@ function App() { redirect_uri: window.location.origin + "/callback" }} > - {/* */} - - - - - - - - - - Vite + React - - setCount((count) => count + 1)}> - count is {count} - - - The new Adaptive App + + + + {/* */} + + + + + + + + + Vite + React + + setCount((count) => count + 1)}> + count is {count} + + + The new Adaptive App + + + + Coming soon - - - Coming soon - - {/* */} + + ) diff --git a/src/providers/LoginButton.tsx b/src/providers/LoginButton.tsx new file mode 100644 index 0000000..de1f541 --- /dev/null +++ b/src/providers/LoginButton.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { useAuth0 } from '@auth0/auth0-react'; + +const LoginButton = () => { + const { loginWithRedirect } = useAuth0(); + + return ( + loginWithRedirect()}> + Log In + + ); +}; + +export default LoginButton; \ No newline at end of file diff --git a/src/providers/auth.tsx b/src/providers/auth.tsx new file mode 100644 index 0000000..01bf9af --- /dev/null +++ b/src/providers/auth.tsx @@ -0,0 +1,30 @@ +import { useAuth0 } from "@auth0/auth0-react"; +import { PropsWithChildren, useEffect } from "react"; + + +export default function AuthWrapper(props: PropsWithChildren<{}>) { + const { children } = props; + const { isLoading, loginWithRedirect, isAuthenticated, user } = useAuth0(); + + + useEffect(() => { + if (!isAuthenticated && !isLoading) { + loginWithRedirect(); + } + }, [isAuthenticated, loginWithRedirect]); + + useEffect(() => { + console.log(user) + console.log(user?.sub) + console.log(user?.picture) + + }, [user]) + + + + // if (isAuthenticated) return ( + // children + // ) + + return (children) +} \ No newline at end of file diff --git a/src/providers/http.tsx b/src/providers/http.tsx new file mode 100644 index 0000000..c82bd94 --- /dev/null +++ b/src/providers/http.tsx @@ -0,0 +1,128 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; +// import { useAuth } from "hooks"; +import moment from "moment"; +import { createContext, PropsWithChildren, useContext, useEffect, useState } from "react"; +// import BillingProvider from "./billing"; +// import GitlabProvider from "./gitlab"; +import PondProvider from "./pond/pond"; +// import SecurityProvider from "./security"; +import { useAuth0 } from "@auth0/auth0-react"; + +interface IHTTPContext { + get: (url: string, spreadOptions?: AxiosRequestConfig) => Promise>; + put: ( + url: string, + data?: any, + spreadOptions?: AxiosRequestConfig + ) => Promise>; + post: ( + url: string, + data?: any, + spreadOptions?: AxiosRequestConfig + ) => Promise>; + del: (url: string, spreadOptions?: AxiosRequestConfig) => Promise>; + options: (demo?: boolean) => AxiosRequestConfig; +} + +export const HTTPContext = createContext({} as IHTTPContext); + +export default function HTTPProvider(props: PropsWithChildren) { + const { children } = props; + const { isAuthenticated, /*token,*/ getAccessTokenSilently } = useAuth0(); + const [token, setToken] = useState(""); + + useEffect(() => { + if (isAuthenticated) getAccessTokenSilently().then(t => { + setToken(t) + }) + }, [setToken, isAuthenticated]) + + useEffect(() => { + console.log(token) + }, [token]) + + const defaultOptions = (demo: boolean = false) => { + if (demo || !isAuthenticated || !token) { + return { + headers: { + "Content-Type": "application/json" + } + }; + } + + return { + headers: { + Authorization: "Bearer " + token, + "Content-Type": "application/json" + } + }; + }; + + function get(url: string, spreadOptions?: AxiosRequestConfig): Promise> { + return axios.get(url, { ...defaultOptions(), ...spreadOptions }); + } + + function put( + url: string, + data?: any, + spreadOptions?: AxiosRequestConfig + ): Promise> { + return axios.put(url, data, { ...defaultOptions(), ...spreadOptions }); + } + + function post( + url: string, + data?: any, + spreadOptions?: AxiosRequestConfig + ): Promise> { + return axios.post(url, data, { ...defaultOptions(), ...spreadOptions }); + } + + function del(url: string, spreadOptions?: AxiosRequestConfig): Promise> { + return axios.delete(url, { ...defaultOptions(), ...spreadOptions }); + } + + return ( + + {/* */} + + {children} + {/* */} + {/* {children} */} + {/* */} + + {/* */} + + ); +} + +export const useHTTP = () => useContext(HTTPContext); + +//returns a string depending on the given start and end to be used in a url query +export function dateRange(start: any, end: any): string { + start = moment(start).toISOString(); + end = moment(end).toISOString(); + + var queryRange = ""; + if ( + typeof start !== "undefined" && + start !== null && + typeof end !== "undefined" && + end !== null + ) { + queryRange = "?start=" + start + "&end=" + end; + } else if (typeof start !== "undefined" && start !== null) { + queryRange = "?start=" + start; + } else if (typeof end !== "undefined" && end !== null) { + queryRange += "?end=" + end; + } + + return queryRange; +} diff --git a/src/providers/pond/pond.tsx b/src/providers/pond/pond.tsx new file mode 100644 index 0000000..95aea86 --- /dev/null +++ b/src/providers/pond/pond.tsx @@ -0,0 +1,26 @@ +import { PropsWithChildren } from "react"; +import UserProvider, { useUserAPI } from "./userAPI"; + +export const pondURL = (partial: string, demo: boolean = false): string => { + let url = process.env.REACT_APP_API_URL + (demo ? "/demo" : "") + partial; + // if (isStaging()) url = process.env.REACT_APP_STAGING_API_URL + (demo ? "/demo" : "") + partial; + return url; +}; + +// export const objectQueryParams = (scope: Scope) => { +// return "?" + scope.kind + "_id=" + scope.key; +// }; + +export default function PondProvider(props: PropsWithChildren) { + const { children } = props; + + return ( + + {children} + + ); +} + +export { + useUserAPI, +}; diff --git a/src/providers/pond/userAPI.tsx b/src/providers/pond/userAPI.tsx new file mode 100644 index 0000000..808a2ba --- /dev/null +++ b/src/providers/pond/userAPI.tsx @@ -0,0 +1,236 @@ +// import { useHTTP } from "hooks"; +// import { Scope, User } from "models"; +// import { pond } from "protobuf-ts/pond"; +import { createContext, PropsWithChildren, useContext } from "react"; +// import { objectQueryParams, pondURL } from "./pond"; +// import { or } from "utils"; +// import { useGlobalState } from "providers"; +import { AxiosResponse } from "axios"; +import { useHTTP } from "../http"; +import { pondURL } from "./pond"; + +// export interface ListUsersResponse { +// users: User[]; +// nextOffset: number; +// total: number; +// } +export interface IUserAPIContext { +// listUsers: ( +// limit: number, +// offset: number, +// order?: "asc" | "desc", +// by?: string, +// search?: string +// ) => Promise; +// listProfiles: () => Promise; +// listObjectUsers: (scope: Scope) => Promise; +// updateObjectUsers: (scope: Scope, users: pond.IUser[]) => Promise; + getUser: (id: string) => Promise; + // getUserWithTeam: ( + // id: string, + // team?: string, + // scope?: Scope + // ) => Promise>; + // getProfile: (id: string) => Promise; + // getUsers: (ids: string[]) => Promise; + // getProfiles: (ids: string[]) => Promise; + // getUserSettings: (userID: string) => Promise; + // updateUserSettings: (userID: string, body: pond.IUserSettings) => Promise; + // updateUserStatus: (userID: string, body: pond.IUserStatus) => Promise; + // updateUser: (id: string, body: pond.User) => Promise; + // getUserObjectHistory: ( + // id: string, + // objects: number[], + // start: string, + // end: string + // ) => Promise>; +} + +export const UserAPIContext = createContext({} as IUserAPIContext); + +export default function UserProvider(props: PropsWithChildren) { + const { children } = props; + const { get, put } = useHTTP(); + // const [{ as }] = useGlobalState(); + + // const listUsers = ( + // limit: number, + // offset: number, + // order?: "asc" | "desc", + // by?: string, + // search?: string + // ): Promise => { + // return new Promise((resolve, reject) => { + // get( + // pondURL( + // "/users?limit=" + + // limit + + // "&offset=" + + // offset + + // ("&order=" + (order ? order : "asc")) + + // ("&by=" + (by ? by : "name")) + + // (search ? "&search=" + search : "") + // ) + // ) + // .then((res: any) => { + // let users: User[] = []; + // if (res && res.data && res.data.users) { + // res.data.users.forEach((raw: any) => users.push(User.any(raw))); + // } + // resolve({ + // users: users, + // nextOffset: or(res.data.nextOffset, 0), + // total: or(res.data.total, 0) + // }); + // }) + // .catch((err: any) => reject(err)); + // }); + // }; + + // const listProfiles = (): Promise => { + // return new Promise((resolve, reject) => { + // get(pondURL("/profiles/")) + // .then((res: any) => { + // let profiles: pond.UserProfile[] = []; + // if (res && res.data && res.data.users) { + // res.data.users.forEach((raw: any) => profiles.push(pond.UserProfile.fromObject(raw))); + // } + // resolve(profiles); + // }) + // .catch((err: any) => reject(err)); + // }); + // }; + + // const listObjectUsers = (scope: Scope) => { + // let sql = "/" + scope.kind + "s/" + scope.key + "/users"; + // if (as) sql = sql + "?as=" + as; + // return get(pondURL(sql)); + // }; + + // const updateObjectUsers = (scope: Scope, users: pond.IUser[]) => { + // return put(pondURL("/users" + objectQueryParams(scope)), { users }); + // }; + + // const getUser = (id: string): Promise => { + const getUser = (id: string): Promise => { + let partial = "/users/" + id; + // if (scope) partial += "?kind=" + scope.kind + "&key=" + scope.key; + return new Promise(function(resolve, reject) { + get(pondURL(partial)) + .then((response: any) => resolve(response.data)) + .catch((error: any) => reject(error)); + }); + }; + + // const getUserWithTeam = ( + // id: string, + // team?: string, + // scope?: Scope + // ): Promise> => { + // let partial = "/userWithTeam/" + id; + // if (scope) partial += "?kind=" + scope.kind + "&key=" + scope.key; + // if (team) { + // if (partial.includes("?")) { + // partial += "&team=" + team; + // } else { + // partial += "?team=" + team; + // } + // } + // return new Promise(function(resolve, reject) { + // get(pondURL(partial)) + // .then((response: any) => resolve(response)) + // .catch((error: any) => reject(error)); + // }); + // }; + + // const getProfile = (id: string): Promise => { + // return new Promise((resolve, reject) => { + // get(pondURL("/profiles/" + id)) + // .then((res: any) => resolve(pond.UserProfile.fromObject(res.data))) + // .catch((err: any) => reject(err)); + // }); + // }; + + // const getUsers = (ids: string[]): Promise => { + // return new Promise((resolve, reject) => { + // get(pondURL("/users/?ids=" + ids.join(","))) + // .then((res: any) => { + // let users: User[] = []; + // if (res && res.data && res.data.users) { + // users = res.data.users.map((data: any) => User.any(data)); + // } + // resolve(users); + // }) + // .catch((err: any) => reject(err)); + // }); + // }; + + // const getProfiles = (ids: string[]): Promise => { + // return new Promise((resolve, reject) => { + // get(pondURL("/profiles/?ids=" + ids.join(","))) + // .then((res: any) => { + // let profiles: pond.UserProfile[] = []; + // if (res && res.data && res.data.users) { + // profiles = res.data.users.map((raw: any) => pond.UserProfile.fromObject(raw)); + // } + // resolve(profiles); + // }) + // .catch((err: any) => reject(err)); + // }); + // }; + + // const getUserSettings = (userID: string) => { + // return get(pondURL("/users/" + userID + "/settings")); + // }; + + // const updateUserSettings = (userID: string, body: pond.IUserSettings) => { + // return put(pondURL("/users/" + userID + "/settings"), body); + // }; + + // const updateUserStatus = (userID: string, body: pond.IUserStatus) => { + // return put(pondURL("/users/" + userID + "/status"), body); + // }; + + // const updateUser = (id: string, body: pond.User) => { + // return put(pondURL("/users/" + id), body); + // }; + + // const getUserObjectHistory = (id: string, objects: number[], start: string, end: string) => { + // return get( + // pondURL( + // "/users/" + + // id + + // "/objectHistories/?objects=" + + // objects.toString() + + // "&start=" + + // start + + // "&end=" + + // end + // ) + // ); + // }; + + return ( + + {children} + + ); +} + +export const useUserAPI = () => useContext(UserAPIContext);
- The new Adaptive App + + + + {/* */} + + + + + + + + + Vite + React + + setCount((count) => count + 1)}> + count is {count} + + + The new Adaptive App + + + + Coming soon -
+ The new Adaptive App +
+ Coming soon
- Coming soon -