From 6d5dd97cc40d200eae1dedb8d08f4790dedfd835 Mon Sep 17 00:00:00 2001 From: nkusikevin Date: Sat, 8 Mar 2025 12:26:02 +0200 Subject: [PATCH 1/2] added propel authentication --- package-lock.json | 46 +++++ package.json | 1 + src/App.tsx | 31 ++-- src/components/AuthComponents.tsx | 94 +++++++++++ src/components/Navbar.tsx | 117 ++++++------- src/components/ui/loader.tsx | 9 + src/index.css | 227 ++++++++++++++----------- src/pages/Dashboard.tsx | 92 +++++----- src/pages/Login.tsx | 261 +++++++++++++++------------- src/pages/Signup.tsx | 272 ++++++++++++++++-------------- 10 files changed, 689 insertions(+), 461 deletions(-) create mode 100644 src/components/AuthComponents.tsx create mode 100644 src/components/ui/loader.tsx diff --git a/package-lock.json b/package-lock.json index 1d73812..f0f85dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@hookform/resolvers": "^3.9.0", + "@propelauth/react": "^2.0.29", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-aspect-ratio": "^1.1.0", @@ -919,6 +920,27 @@ "node": ">=14" } }, + "node_modules/@propelauth/javascript": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@propelauth/javascript/-/javascript-2.0.20.tgz", + "integrity": "sha512-d9KYc0CS9qIOQjuQ9L/WdYvAp3aEPBOetr3YvC8mxwKmbTmpYWmLBtSeS24RE2QQ7TdwemBs2qOB6Kt/xkkeWw==", + "license": "MIT" + }, + "node_modules/@propelauth/react": { + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/@propelauth/react/-/react-2.0.29.tgz", + "integrity": "sha512-WO6zDcnMa1/DD/+ESOwLdmVPf6A3Pw1ekdmvOEMhqkeNCcZkf9dgFT6gF5wOKFnSsMPE23BuN4woKHxEXYQVhg==", + "license": "MIT", + "dependencies": { + "@propelauth/javascript": "^2.0.20", + "hoist-non-react-statics": "^3.3.2", + "utility-types": "^3.10.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", @@ -4741,6 +4763,21 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6862,6 +6899,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/vaul": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz", diff --git a/package.json b/package.json index 4de3b26..f3d6574 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@hookform/resolvers": "^3.9.0", + "@propelauth/react": "^2.0.29", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-aspect-ratio": "^1.1.0", diff --git a/src/App.tsx b/src/App.tsx index 3bb5277..8ff0580 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,26 +11,27 @@ import Login from "./pages/Login"; import Signup from "./pages/Signup"; import Dashboard from "./pages/Dashboard"; import NotFound from "./pages/NotFound"; +import { AuthProvider } from "@propelauth/react"; const queryClient = new QueryClient(); const App = () => ( - - - - - - - } /> - } /> - } /> - } /> - } /> - } /> - - - + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + + + + ); diff --git a/src/components/AuthComponents.tsx b/src/components/AuthComponents.tsx new file mode 100644 index 0000000..debb3e1 --- /dev/null +++ b/src/components/AuthComponents.tsx @@ -0,0 +1,94 @@ +import { useAuthInfo, useRedirectFunctions, WithLoggedInAuthInfoProps, withRequiredAuthInfo } from "@propelauth/react"; +import { Navigate } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { useLogoutFunction } from "@propelauth/react" +import { LogOut, User } from "lucide-react"; +import Loader from "./ui/loader"; + +// A component that redirects to the dashboard if logged in +export const RedirectIfLoggedIn = ({ children }: { children: React.ReactNode }) => { + const { isLoggedIn, loading } = useAuthInfo(); + + + + if (loading) { + return ; + } + + if (isLoggedIn) { + return ; + } + + return <>{children}; +}; + +// A component that requires authentication +export const ProtectedRoute = withRequiredAuthInfo( + ({ children, ...authProps }: { children: React.ReactNode } & WithLoggedInAuthInfoProps) => { + return <>{children}; + }, + { + // Custom component to show while loading + displayWhileLoading: , + // Custom component to show if not logged in + displayIfLoggedOut: + } +); + +// Login button component +export const LoginButton = () => { + const { redirectToLoginPage } = useRedirectFunctions(); + + return ( + + ); +}; + +// Signup button component +export const SignupButton = () => { + const { redirectToSignupPage } = useRedirectFunctions(); + + return ( + + ); +}; + +// Logout button component +export const LogoutButton = () => { + const logout = useLogoutFunction(); + + + return ( + + ); +}; + +// User profile component +export const UserProfile = withRequiredAuthInfo(({ user }) => { + return ( +
+
+ +
+
+

{user.email}

+

Premium Plan

+
+
+ ); +}); \ No newline at end of file diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 660eb83..955809f 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -5,12 +5,15 @@ import { Button } from "@/components/ui/button"; import { MoonIcon, SunIcon, MenuIcon, XIcon } from "lucide-react"; import { useTheme } from "@/hooks/use-theme"; import { useIsMobile } from "@/hooks/use-mobile"; +import { useAuthInfo } from "@propelauth/react"; +import { LoginButton, SignupButton, LogoutButton, UserProfile } from "@/components/AuthComponents"; const Navbar = () => { const { theme, setTheme } = useTheme(); const isMobile = useIsMobile(); const [isMenuOpen, setIsMenuOpen] = useState(false); const [scrolled, setScrolled] = useState(false); + const { isLoggedIn } = useAuthInfo(); useEffect(() => { const handleScroll = () => { @@ -34,30 +37,27 @@ const Navbar = () => { setIsMenuOpen(!isMenuOpen); }; - const navbarClasses = `fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${ - scrolled - ? "bg-background/80 backdrop-blur-md shadow-sm" - : "bg-transparent" - }`; + const navbarClasses = `fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${scrolled + ? "bg-background/80 backdrop-blur-md shadow-sm" + : "bg-transparent" + }`; return (