diff --git a/package-lock.json b/package-lock.json
index 78daeff22..4ab9aedd6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "tessera",
"version": "0.0.0",
"dependencies": {
+ "@supabase/supabase-js": "^2.49.1",
"@tailwindcss/vite": "^4.0.9",
"axios": "^1.8.1",
"firebase": "^11.3.1",
@@ -2078,6 +2079,80 @@
"win32"
]
},
+ "node_modules/@supabase/auth-js": {
+ "version": "2.68.0",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.68.0.tgz",
+ "integrity": "sha512-odG7nb7aOmZPUXk6SwL2JchSsn36Ppx11i2yWMIc/meUO2B2HK9YwZHPK06utD9Ql9ke7JKDbwGin/8prHKxxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/functions-js": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.4.tgz",
+ "integrity": "sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/node-fetch": {
+ "version": "2.6.15",
+ "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
+ "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/@supabase/postgrest-js": {
+ "version": "1.19.2",
+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.19.2.tgz",
+ "integrity": "sha512-MXRbk4wpwhWl9IN6rIY1mR8uZCCG4MZAEji942ve6nMwIqnBgBnZhZlON6zTTs6fgveMnoCILpZv1+K91jN+ow==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/realtime-js": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.11.2.tgz",
+ "integrity": "sha512-u/XeuL2Y0QEhXSoIPZZwR6wMXgB+RQbJzG9VErA3VghVt7uRfSVsjeqd7m5GhX3JR6dM/WRmLbVR8URpDWG4+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14",
+ "@types/phoenix": "^1.5.4",
+ "@types/ws": "^8.5.10",
+ "ws": "^8.18.0"
+ }
+ },
+ "node_modules/@supabase/storage-js": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.7.1.tgz",
+ "integrity": "sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/supabase-js": {
+ "version": "2.49.1",
+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.49.1.tgz",
+ "integrity": "sha512-lKaptKQB5/juEF5+jzmBeZlz69MdHZuxf+0f50NwhL+IE//m4ZnOeWlsKRjjsM0fVayZiQKqLvYdBn0RLkhGiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/auth-js": "2.68.0",
+ "@supabase/functions-js": "2.4.4",
+ "@supabase/node-fetch": "2.6.15",
+ "@supabase/postgrest-js": "1.19.2",
+ "@supabase/realtime-js": "2.11.2",
+ "@supabase/storage-js": "2.7.1"
+ }
+ },
"node_modules/@tailwindcss/node": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.9.tgz",
@@ -2357,6 +2432,12 @@
"undici-types": "~6.20.0"
}
},
+ "node_modules/@types/phoenix": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz",
+ "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==",
+ "license": "MIT"
+ },
"node_modules/@types/react": {
"version": "19.0.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
@@ -2377,6 +2458,15 @@
"@types/react": "^19.0.0"
}
},
+ "node_modules/@types/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
@@ -4835,6 +4925,12 @@
"node": ">=8.0"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
"node_modules/ts-api-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
@@ -5474,6 +5570,12 @@
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
"license": "Apache-2.0"
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
@@ -5497,6 +5599,16 @@
"node": ">=0.8.0"
}
},
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5540,6 +5652,27 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index a6eecced8..8f02bcb4f 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "@supabase/supabase-js": "^2.49.1",
"@tailwindcss/vite": "^4.0.9",
"axios": "^1.8.1",
"firebase": "^11.3.1",
diff --git a/src/App.tsx b/src/App.tsx
index 00fbcc817..e88a556a8 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,37 +1,31 @@
import { useContext } from 'react';
import { BrowserRouter as Router, Route, Routes, } from 'react-router-dom';
import NavBar from './components/Navbar';
-
-import { UserContext } from './UserContext';
+import Register from './pages/Register';
+import Login from "./pages/Login";
+import PrivateRoute from "./components/PrivateRoute";
function App() {
- const userContext = useContext(UserContext);
- if (!userContext) {
- return
Error: UserContext is not provided
;
- }
- const { user, login, logout } = userContext;
+
+ // const { user, login, logout } = userContext;
return (
-
-
-
-
- {/*
- {user ? (
-
-
Welcome, {user.name}
-
-
- ) : (
-
- )}
-
*/}
-
+
+
+ } />
+ } />
+
+
+
+ }
+ />
-
+
+
);
}
diff --git a/src/UserContext.tsx b/src/UserContext.tsx
index a09306976..5e05c82d5 100644
--- a/src/UserContext.tsx
+++ b/src/UserContext.tsx
@@ -1,60 +1,60 @@
-import { createContext, useState, useEffect, ReactNode } from 'react';
-import { signInWithGoogle, signOutFromGoogle } from './firebaseConfig';
-
-interface User {
- id: string;
- name: string;
- email: string;
-}
-
-interface UserContextType {
- user: User | null;
- login: () => void;
- logout: () => void;
-}
-
-const UserContext = createContext(undefined);
-
-const UserProvider = ({ children }: { children: ReactNode }) => {
- const [user, setUser] = useState(null);
-
- useEffect(() => {
- const storedUser = localStorage.getItem('user');
- if (storedUser) {
- setUser(JSON.parse(storedUser));
- }
- }, []);
-
- const login = async () => {
- try {
- const result = await signInWithGoogle();
- const userData = {
- id: result.user.uid,
- name: result.user.displayName || '',
- email: result.user.email || ''
- };
- setUser(userData);
- localStorage.setItem('user', JSON.stringify(userData));
- } catch (error) {
- console.error('Error logging in with Google:', error);
- }
- };
-
- const logout = async () => {
- try {
- await signOutFromGoogle();
- setUser(null);
- localStorage.removeItem('user');
- } catch (error) {
- console.error('Error logging out:', error);
- }
- };
-
- return (
-
- {children}
-
- );
-};
-
-export { UserContext, UserProvider };
\ No newline at end of file
+// import { createContext, useState, useEffect, ReactNode } from 'react';
+
+
+// interface User {
+// id: string;
+// name: string;
+// email: string;
+// }
+
+// interface UserContextType {
+// user: User | null;
+// login: () => void;
+// logout: () => void;
+// }
+
+// const UserContext = createContext(undefined);
+
+// const UserProvider = ({ children }: { children: ReactNode }) => {
+// const [user, setUser] = useState(null);
+
+// useEffect(() => {
+// const storedUser = localStorage.getItem('user');
+// if (storedUser) {
+// setUser(JSON.parse(storedUser));
+// }
+// }, []);
+
+// const login = async () => {
+// try {
+// const result = await signInWithGoogle();
+// const userData = {
+// id: result.user.uid,
+// name: result.user.displayName || '',
+// email: result.user.email || ''
+// };
+// setUser(userData);
+// localStorage.setItem('user', JSON.stringify(userData));
+// } catch (error) {
+// console.error('Error logging in with Google:', error);
+// }
+// };
+
+// const logout = async () => {
+// try {
+// await signOutFromGoogle();
+// setUser(null);
+// localStorage.removeItem('user');
+// } catch (error) {
+// console.error('Error logging out:', error);
+// }
+// };
+
+// return (
+//
+// {children}
+//
+// );
+// };
+
+// export { UserContext, UserProvider };
\ No newline at end of file
diff --git a/src/assets/bird.jpeg b/src/assets/bird.jpeg
new file mode 100644
index 000000000..283bc40f9
Binary files /dev/null and b/src/assets/bird.jpeg differ
diff --git a/src/components/PrivateRoute.tsx b/src/components/PrivateRoute.tsx
new file mode 100644
index 000000000..630cbb5c2
--- /dev/null
+++ b/src/components/PrivateRoute.tsx
@@ -0,0 +1,26 @@
+import { JSX, useEffect, useState } from "react";
+import { Navigate } from "react-router-dom";
+import { supabase } from "../supabaseClient";
+
+function PrivateRoute({ children }: { children: JSX.Element }) {
+ const [authenticated, setAuthenticated] = useState(false);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const checkSession = async () => {
+ const { data: { user } } = await supabase.auth.getUser();
+ setAuthenticated(!!user);
+ setLoading(false);
+ };
+
+ checkSession();
+ }, []);
+
+ if (loading) {
+ return Loading...
;
+ }
+
+ return authenticated ? children : ;
+}
+
+export default PrivateRoute;
\ No newline at end of file
diff --git a/src/firebaseConfig.ts b/src/firebaseConfig.ts
deleted file mode 100644
index 5ac1555a2..000000000
--- a/src/firebaseConfig.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { initializeApp } from 'firebase/app';
-import { getAuth, GoogleAuthProvider, signInWithPopup, signOut } from 'firebase/auth';
-
-const firebaseConfig = {
- apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
- authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
- projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
- storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
- messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
- appId: import.meta.env.VITE_FIREBASE_APP_ID
-};
-
-const app = initializeApp(firebaseConfig);
-const auth = getAuth(app);
-const provider = new GoogleAuthProvider();
-
-const signInWithGoogle = () => {
- return signInWithPopup(auth, provider);
-};
-
-const signOutFromGoogle = () => {
- return signOut(auth);
-};
-
-export { auth, signInWithGoogle, signOutFromGoogle };
\ No newline at end of file
diff --git a/src/main.tsx b/src/main.tsx
index 0fbb6684b..12e8f1dd5 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -4,14 +4,16 @@ import './styles/index.css';
import './styles/App.css';
import './styles/styles.css';
import App from './App';
-import { UserProvider } from './UserContext';
+
+import Register from '../src/pages/Register';
+import { BrowserRouter } from 'react-router-dom';
createRoot(document.getElementById('root')!).render(
-
-
+ {/* */}
+
-
+
);
\ No newline at end of file
diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx
new file mode 100644
index 000000000..d378d96fe
--- /dev/null
+++ b/src/pages/Login.tsx
@@ -0,0 +1,61 @@
+import React, { useState } from "react";
+import { supabase } from "../supabaseClient";
+import { Link,useNavigate } from "react-router-dom";
+
+function Login() {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [message, setMessage] = useState("");
+ const navigate = useNavigate();
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+ setMessage("");
+
+ const { data, error } = await supabase.auth.signInWithPassword({
+ email: email,
+ password: password,
+ });
+
+ if (error) {
+ setMessage(error.message);
+ return;
+ }
+
+ if (data) {
+ navigate("/Home");
+ return null;
+ }
+
+ setEmail("");
+ setPassword("");
+ };
+
+ return (
+
+
Register
+
+ {message && {message}}
+
+ Don't have an account?
+ Create an Account.
+
+ );
+}
+
+export default Login
\ No newline at end of file
diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx
new file mode 100644
index 000000000..6ce91e69d
--- /dev/null
+++ b/src/pages/Register.tsx
@@ -0,0 +1,96 @@
+import React, { useState } from "react";
+import { supabase } from "../supabaseClient";
+import { Link } from "react-router-dom";
+import bird from "../assets/bird.jpeg"
+
+function Register() {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [message, setMessage] = useState("");
+ const [full_name,setName] = useState("");
+
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+ setMessage("");
+
+ const { data, error } = await supabase.auth.signUp({
+ email: email,
+ password: password,
+ options:{
+ data:{
+ full_name :full_name,
+
+ },
+ },
+
+ });
+
+ if (error) {
+ setMessage(error.message);
+ return;
+ }
+
+ if (data) {
+ setMessage("User account created!");
+ }
+
+ setEmail("");
+ setPassword("");
+ setName("");
+
+ };
+
+ return (
+
+
+
+

+
+
+
+
+
+ {message && {message}}
+
+ Already have an account?
+ Log in.
+
+
+
+ );
+}
+
+export default Register;
\ No newline at end of file
diff --git a/src/supabaseClient.ts b/src/supabaseClient.ts
new file mode 100644
index 000000000..f8a66f0f4
--- /dev/null
+++ b/src/supabaseClient.ts
@@ -0,0 +1,6 @@
+import { createClient } from "@supabase/supabase-js";
+
+const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL!;
+const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY!;
+
+export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);