Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Check out the live version of the app here:
- **Styling**: Tailwind CSS and Material UI for utility-first styling
- **Deployment**: Vercel (for quick and easy deployment)
- **Icons**: FontAwesome for various UI icons
- **API**: OMDb API for movie data
- **Database**: Supabase

## 🏗️ Installation & Setup

Expand Down
1,914 changes: 727 additions & 1,187 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"@mui/icons-material": "^6.1.3",
"@mui/material": "^6.1.3",
"@mui/styled-engine-sc": "^6.1.3",
"@toolpad/core": "^0.7.0",
"@supabase/supabase-js": "^2.47.15",
"@toolpad/core": "^0.12.0",
"axios": "^1.7.7",
"prop-types": "^15.8.1",
"react": "^18.3.1",
Expand Down
30 changes: 29 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./components/Home";
import Login from "./components/Login";
import Signup from "./components/Signup";
import MyList from "./components/MyList";
import { BookmarkProvider } from "./components/BookMarkContext";
import InfoPage from "./components/InfoPage";
import { supabase } from "./components/supabaseClient";

function App() {
const [session, setSession] = useState(null);
const [movies, setMovies] = useState([]);
const [bookmarkedMovies, setBookmarkedMovies] = useState([]);

useEffect(() => {
// Check for an existing session
const storedSession = localStorage.getItem("supabase_session");

if (storedSession) {
setSession(JSON.parse(storedSession));
}

// Listen for auth changes
const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
if (session) {
localStorage.setItem("supabase_session", JSON.stringify(session));
setSession(session);
} else {
localStorage.removeItem("supabase_session");
setSession(null);
}
}
);

return () => {
authListener.subscription.unsubscribe();
};
}, []);

return (
<>
<BookmarkProvider>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import MyList from "./MyList";
import Login from "./Login";
import Mainpage from "./MainPage";
import Signup from "./Signup";
import { supabase } from "./supabaseClient";

// Width of the sidebar drawer
const drawerWidth = 240;
Expand Down Expand Up @@ -149,11 +150,14 @@ function Home({ movies, setMovies, bookmarkedMovies, setBookmarkedMovies }) {
};

// Logs out the user clearing from localStorage
const handleLogout = () => {
const handleLogout = async () => {
await supabase.auth.signOut();
localStorage.removeItem("supabase_session");
localStorage.removeItem("loggedInUser");
setLoggedInUser(null);
setActiveContent("home");
setLogoutDialogOpen(false);
window.location.reload();
};

// Opens the logout confirmation dialog
Expand Down
71 changes: 51 additions & 20 deletions src/components/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {
Snackbar,
Alert,
} from "@mui/material";
import { supabase } from "./supabaseClient";

// login component handles user login functionality
const Login = ({ setActiveContent, setLoggedInUser }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState("");
Expand All @@ -32,47 +34,53 @@ const Login = ({ setActiveContent, setLoggedInUser }) => {
};

// function to handle form submission
const handleSubmit = (event) => {
const handleSubmit = async (event) => {
event.preventDefault();

// retrieve users from local storage
const storedUsers = localStorage.getItem("users");
const usersArray = storedUsers ? JSON.parse(storedUsers) : [];
try {
// Attempt to sign in with Supabase
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});

// check if the entered email matches an existing user
const existingUser = usersArray.find((user) => user.email === email);
if (error) {
throw new Error(error.message);
}

// if user exists store the user in local storage
if (existingUser) {
// Store user data
localStorage.setItem(
"loggedInUser",
JSON.stringify({
email: existingUser.email,
username: existingUser.username,
email: data.user.email,
username: data.user.user_metadata.username,
})
);

// update loggedin user state
// Update logged-in user state
setLoggedInUser({
email: existingUser.email,
username: existingUser.username,
email: data.user.email,
username: data.user.user_metadata.username,
});

// display success snackbar message
setSnackbarMessage(`Welcome back, ${existingUser.username}!`);
localStorage.setItem("supabase_session", JSON.stringify(data.session));

// Display success snackbar message
setSnackbarMessage(`Welcome back, ${data.user.user_metadata.username}!`);
setSnackbarSeverity("success");
setSnackbarOpen(true);
setActiveContent("home");
setEmail("");
} else {
// if user is not found, show an error message
setSnackbarMessage("User not found. Please sign up.");
setPassword(""); // Clear password after successful login
} catch (err) {
// Show error message if authentication fails
setSnackbarMessage(err.message);
setSnackbarSeverity("error");
setSnackbarOpen(true);
}
};

// function to handle closing of the snackbar
// Function to handle closing of the snackbar
const handleCloseSnackbar = () => {
setSnackbarOpen(false);
};
Expand Down Expand Up @@ -128,6 +136,29 @@ const Login = ({ setActiveContent, setLoggedInUser }) => {
},
}}
/>
<TextField
margin="normal"
required
fullWidth
id="password"
label="Password"
type="password"
name="password"
autoComplete="password"
autoFocus
value={password}
onChange={(e) => setPassword(e.target.value)}
sx={{
"& .MuiOutlinedInput-root": {
"&.Mui-focused fieldset": {
borderColor: "#f44336",
},
},
"& .MuiInputLabel-root.Mui-focused": {
color: "#f44336",
},
}}
/>
{/* form elements */}
<Box
sx={{
Expand Down Expand Up @@ -188,7 +219,7 @@ const Login = ({ setActiveContent, setLoggedInUser }) => {
variant="body2"
sx={{ color: "#9e9e9e", textAlign: isMobile ? "center" : "right" }}
>
Don't have an account?{" "}
Don&apos;t have an account?{" "}
<span
onClick={handleSignupClick}
style={{
Expand Down
83 changes: 80 additions & 3 deletions src/components/Signup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {
Snackbar,
Alert,
} from "@mui/material";
import { supabase } from "./supabaseClient";

const Signup = ({ setActiveContent }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const isMobile = useMediaQuery(theme.breakpoints.down("sm", "mobile","xs"));

const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState("");
const [snackbarSeverity, setSnackbarSeverity] = useState("success");
Expand All @@ -32,9 +34,60 @@ const Signup = ({ setActiveContent }) => {
};

// Function to handle form submission
const handleSubmit = (event) => {
const handleSubmit = async (event) => {
event.preventDefault();

// Check if email is already taken
const { data: existingUsers, error: fetchError } = await supabase
.from("users")
.select("email")
.eq("email", email);

if (fetchError) {
setSnackbarMessage("An error occurred. Please try again.");
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}

if (existingUsers.length > 0) {
setSnackbarMessage("Email is already registered.");
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}

// Create new user using Supabase authentication
const { user, error: signupError } = await supabase.auth.signUp({
email,
password,
options: {
data: {
display_name: username
},
},
});

if (signupError) {
setSnackbarMessage(signupError.message);
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}

// Insert additional user data (e.g., username) into Supabase database
const { data, error: insertError } = await supabase
.from("users")
.insert([{ email, username }]);
console.log('Data:', data);
console.log('Error:', insertError);

if (insertError) {
setSnackbarMessage("Failed to save user data.");
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}
const storedUsers = localStorage.getItem("users");
const usersArray = storedUsers ? JSON.parse(storedUsers) : [];

Expand All @@ -48,14 +101,15 @@ const Signup = ({ setActiveContent }) => {
return;
}

const newUser = { username, email };
const newUser = { username, email, password};

usersArray.push(newUser);

localStorage.setItem("users", JSON.stringify(usersArray));

setUsername("");
setEmail("");
setPassword("");

// Show success Snackbar
setSnackbarMessage("Registration successful!");
Expand Down Expand Up @@ -120,6 +174,7 @@ const Signup = ({ setActiveContent }) => {
/>
<TextField
margin="normal"
type="email"
required
fullWidth
id="email"
Expand All @@ -139,6 +194,28 @@ const Signup = ({ setActiveContent }) => {
},
}}
/>
<TextField
margin="normal"
type="password"
required
fullWidth
id="password"
label="Password"
name="password"
autoComplete="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
sx={{
"& .MuiOutlinedInput-root": {
"&.Mui-focused fieldset": {
borderColor: "#f44336",
},
},
"& .MuiInputLabel-root.Mui-focused": {
color: "#f44336",
},
}}
/>
<Button
type="submit"
fullWidth
Expand Down
6 changes: 6 additions & 0 deletions src/components/supabaseClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = 'https://ypyemcpdfhndpwcivcdj.supabase.co'; // Replace with your Supabase URL
const supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlweWVtY3BkZmhuZHB3Y2l2Y2RqIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzcwNDkyMzUsImV4cCI6MjA1MjYyNTIzNX0.M6zOlo8RfHxK7VE2FR0O98dpTGC2HlhBgvrExRIvk90'; // Replace with your Supabase anon key

export const supabase = createClient(supabaseUrl, supabaseAnonKey);