diff --git a/client/package-lock.json b/client/package-lock.json index cfb2239..d92ff6c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,6 +11,9 @@ "@apollo/client": "^3.13.8", "@radix-ui/react-dialog": "^1.1.11", "graphql": "^16.11.0", + + "jwt-decode": "^4.0.0", + "lucide-react": "^0.503.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -2195,6 +2198,15 @@ "node": ">=6" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "dev": true, diff --git a/client/package.json b/client/package.json index d38b871..49c6805 100644 --- a/client/package.json +++ b/client/package.json @@ -13,6 +13,9 @@ "@apollo/client": "^3.13.8", "@radix-ui/react-dialog": "^1.1.11", "graphql": "^16.11.0", + + "jwt-decode": "^4.0.0", + "lucide-react": "^0.503.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/client/src/Utils/apolloClient.ts b/client/src/Utils/apolloClient.ts new file mode 100644 index 0000000..635742c --- /dev/null +++ b/client/src/Utils/apolloClient.ts @@ -0,0 +1,25 @@ +import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; +import { setContext } from '@apollo/client/link/context'; + +const httpLink = createHttpLink({ + uri: import.meta.env.VITE_API_URL + ? `${import.meta.env.VITE_API_URL}/graphql` + : '/graphql', +}); + +const authLink = setContext((_, { headers }) => { + const token = localStorage.getItem('id_token'); + return { + headers: { + ...headers, + authorization: token ? `Bearer ${token}` : '', + }, + }; +}); + +const client = new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache(), +}); + +export default client; \ No newline at end of file diff --git a/client/src/Utils/auth.ts b/client/src/Utils/auth.ts new file mode 100644 index 0000000..9eea949 --- /dev/null +++ b/client/src/Utils/auth.ts @@ -0,0 +1,52 @@ +import { jwtDecode } from 'jwt-decode'; + +interface UserToken { + name?: string; + exp: number; + _id?: string; + email?: string; + username?: string; +} + +// AuthService class to manage login/logout/token logic +class AuthService { + // Get user data from token + getProfile() { + return jwtDecode(this.getToken() || ''); + } + + // Check if user is logged in + loggedIn() { + const token = this.getToken(); + return !!token && !this.isTokenExpired(token); + } + + // Check if token is expired + isTokenExpired(token: string) { + try { + const decoded = jwtDecode(token); + return decoded.exp < Date.now() / 1000; + } catch (err) { + return true; + } + } + + // Get token from localStorage + getToken() { + return localStorage.getItem('id_token'); + } + + // Login - save token to localStorage + login(idToken: string) { + localStorage.setItem('id_token', idToken); + window.location.assign('/'); + } + + // Logout - remove token + logout() { + localStorage.removeItem('id_token'); + window.location.assign('/'); + } +} + +export default new AuthService(); \ No newline at end of file diff --git a/client/src/lib/utils.ts b/client/src/Utils/utils.ts similarity index 100% rename from client/src/lib/utils.ts rename to client/src/Utils/utils.ts diff --git a/client/src/components/ui/dialog.tsx b/client/src/components/ui/dialog.tsx index 620ea34..66e1d31 100644 --- a/client/src/components/ui/dialog.tsx +++ b/client/src/components/ui/dialog.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { X } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "@/Utils/utils"; const Dialog = DialogPrimitive.Root; const DialogTrigger = DialogPrimitive.Trigger;