diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd846cf --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Deployed Web App - https://cine-scope-ten.vercel.app/ diff --git a/backend/addComment.php b/backend/addComment.php index 9d41e0c..94f6d22 100644 --- a/backend/addComment.php +++ b/backend/addComment.php @@ -14,6 +14,7 @@ $data = json_decode(file_get_contents("php://input"), true); +// get user id, movie id, and comment content $user_id = $data["user_id"] ?? null; $movie_id = $data["movie_id"] ?? null; $content = $data["content"] ?? ''; diff --git a/backend/bookmark.php b/backend/bookmark.php index 5c687a2..7b1585b 100644 --- a/backend/bookmark.php +++ b/backend/bookmark.php @@ -6,23 +6,23 @@ require_once "db.php"; -// 1. Read raw input +// read input $rawInput = file_get_contents("php://input"); -// DEBUG LOG — write raw input to file for inspection +// debug log file_put_contents("debug_log.txt", $rawInput . PHP_EOL, FILE_APPEND); -// 2. Decode JSON +// decode JSON $data = json_decode($rawInput, true); -// 3. Check if valid JSON +// Check if JSON valid if (!is_array($data)) { http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); exit; } -// 4. Extract parameters +// extract user and movie $user_id = $data['user_id'] ?? null; $movie_id = $data['movie_id'] ?? null; @@ -33,14 +33,14 @@ exit; } -// 6. Check if already bookmarked +// Check if already bookmarked $stmt = $conn->prepare("SELECT id FROM lists WHERE user_id = ? AND movie_id = ?"); $stmt->bind_param("ii", $user_id, $movie_id); $stmt->execute(); $result = $stmt->get_result(); if ($result && $result->num_rows > 0) { - // 7. Already bookmarked → remove + // already bookmarked, remove $delete = $conn->prepare("DELETE FROM lists WHERE user_id = ? AND movie_id = ?"); $delete->bind_param("ii", $user_id, $movie_id); $success = $delete->execute(); @@ -51,7 +51,7 @@ ]); $delete->close(); } else { - // 8. Not bookmarked → insert + // not bookmarkedm, insert $insert = $conn->prepare("INSERT INTO lists (user_id, movie_id) VALUES (?, ?)"); $insert->bind_param("ii", $user_id, $movie_id); $success = $insert->execute(); diff --git a/backend/changePassword.php b/backend/changePassword.php index 9120ba2..8994d71 100644 --- a/backend/changePassword.php +++ b/backend/changePassword.php @@ -14,6 +14,7 @@ $data = json_decode(file_get_contents("php://input"), true); +// extract data $user_id = $data['user_id'] ?? ''; $current_password = $data['current_password'] ?? ''; $new_password = $data['new_password'] ?? ''; @@ -23,20 +24,20 @@ exit; } -// Get existing hashed password +// get existing hashed password $stmt = $conn->prepare("SELECT password FROM users WHERE id = ?"); $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); if ($row = $result->fetch_assoc()) { - // Validate current password + // validate current password if (!password_verify($current_password, $row['password'])) { echo json_encode(["error" => "Incorrect current password"]); exit; } - // Hash and update new password + // hash and update new password $new_hashed = password_hash($new_password, PASSWORD_DEFAULT); $updateStmt = $conn->prepare("UPDATE users SET password = ? WHERE id = ?"); $updateStmt->bind_param("si", $new_hashed, $user_id); diff --git a/backend/checkBookmark.php b/backend/checkBookmark.php index 9d13d59..32e4e18 100644 --- a/backend/checkBookmark.php +++ b/backend/checkBookmark.php @@ -2,13 +2,13 @@ header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json"); -// Include database connection require_once "db.php"; -// Get user_id and movie_id from GET request +// GET user_id and movie_id $user_id = $_GET['user_id'] ?? 0; $movie_id = $_GET['movie_id'] ?? 0; +// by default, bookmarked = false $response = ['bookmarked' => false]; if ($user_id && $movie_id) { @@ -17,6 +17,7 @@ $stmt->execute(); $result = $stmt->get_result(); + // if bookmarked, set bookmark as true if ($result && $result->num_rows > 0) { $response['bookmarked'] = true; } diff --git a/backend/getAverageRating.php b/backend/getAverageRating.php index e752939..0ba1f4d 100644 --- a/backend/getAverageRating.php +++ b/backend/getAverageRating.php @@ -13,11 +13,13 @@ exit; } +// sql search for the movie $stmt = $conn->prepare("SELECT AVG(score) AS average, COUNT(*) AS count FROM ratings WHERE movie_id = ?"); $stmt->bind_param("i", $movie_id); $stmt->execute(); $result = $stmt->get_result(); +// count = number of reviews in that movie if ($row = $result->fetch_assoc()) { echo json_encode([ "average" => round((float)$row['average'], 1), diff --git a/backend/getBookmarks.php b/backend/getBookmarks.php index 2d206a9..15abf54 100644 --- a/backend/getBookmarks.php +++ b/backend/getBookmarks.php @@ -1,4 +1,6 @@ get_result(); $bookmarks = []; +// retrieve bookmarked movies while ($row = $result->fetch_assoc()) { $bookmarks[] = $row; } diff --git a/backend/getComments.php b/backend/getComments.php index b08a734..621c1f1 100644 --- a/backend/getComments.php +++ b/backend/getComments.php @@ -13,6 +13,7 @@ exit; } +// select content(comments), and name of user $sql = "SELECT c.content, u.name FROM comments c JOIN users u ON c.user_id = u.id diff --git a/backend/getMovie.php b/backend/getMovie.php index 5815c5e..bcdb97f 100644 --- a/backend/getMovie.php +++ b/backend/getMovie.php @@ -1,4 +1,6 @@ prepare("SELECT * FROM movies WHERE id = ?"); $stmt->bind_param("i", $id); $stmt->execute(); diff --git a/backend/getMovies.php b/backend/getMovies.php index 91d8427..637c679 100644 --- a/backend/getMovies.php +++ b/backend/getMovies.php @@ -1,4 +1,6 @@ query($sql); diff --git a/backend/getPreference.php b/backend/getPreference.php index cb5eef3..ca967f8 100644 --- a/backend/getPreference.php +++ b/backend/getPreference.php @@ -8,6 +8,7 @@ $user_id = $_GET['user_id'] ?? 0; +// get user genre preference $stmt = $conn->prepare("SELECT genre_preference FROM users WHERE id = ?"); $stmt->bind_param("i", $user_id); $stmt->execute(); diff --git a/backend/getRating.php b/backend/getRating.php index 4c7ac9d..d0f04ed 100644 --- a/backend/getRating.php +++ b/backend/getRating.php @@ -6,6 +6,7 @@ require_once "db.php"; +// movie and user id as a foreign key of ratings $user_id = $_GET['user_id'] ?? 0; $movie_id = $_GET['movie_id'] ?? 0; @@ -14,6 +15,7 @@ exit; } +// get score of a certain movie by the user $stmt = $conn->prepare("SELECT score FROM ratings WHERE user_id = ? AND movie_id = ?"); $stmt->bind_param("ii", $user_id, $movie_id); $stmt->execute(); diff --git a/backend/getRecommended.php b/backend/getRecommended.php index 119afdf..bf34b55 100644 --- a/backend/getRecommended.php +++ b/backend/getRecommended.php @@ -1,4 +1,6 @@ "m.genre LIKE ?", $genre); $whereClause = implode(" OR ", $conditions); +// select movies that have the same genre as the ones in user preference and ordered by average rating $sql = " SELECT m.*, ROUND(AVG(r.score), 2) AS average_rating FROM movies m @@ -29,6 +33,7 @@ $stmt = $conn->prepare($sql); +// bind all genres $types = str_repeat("s", count($genre)); $params = array_map(fn($g) => "%$g%", $genre); $stmt->bind_param($types, ...$params); diff --git a/backend/getSearch.php b/backend/getSearch.php index 9d67f39..3d20f83 100644 --- a/backend/getSearch.php +++ b/backend/getSearch.php @@ -1,31 +1,38 @@ prepare("SELECT id, name, email FROM users WHERE id = ?"); $stmt->bind_param("i", $user_id); $stmt->execute(); diff --git a/backend/login.php b/backend/login.php index cc016fc..d3b7ab5 100644 --- a/backend/login.php +++ b/backend/login.php @@ -1,4 +1,6 @@ "Missing email or password"]); exit; @@ -24,6 +27,7 @@ $stmt->execute(); $result = $stmt->get_result(); +// if email not found if ($result->num_rows === 0) { echo json_encode(["error" => "User not found"]); exit; @@ -31,6 +35,7 @@ $user = $result->fetch_assoc(); +// check password with stored password using password_verify if (!password_verify($password, $user["password"])) { echo json_encode(["error" => "Incorrect password"]); exit; diff --git a/backend/removeFromList.php b/backend/removeFromList.php index 22c0643..eebd23d 100644 --- a/backend/removeFromList.php +++ b/backend/removeFromList.php @@ -1,10 +1,12 @@ prepare("UPDATE users SET genre_preference = ? WHERE id = ?"); $stmt->bind_param("si", $genre, $user_id); +// update genre_preference $success = $stmt->execute(); echo json_encode(["success" => $success]); diff --git a/frontend/app/account/page.tsx b/frontend/app/account/page.tsx index ab623a1..17978cd 100644 --- a/frontend/app/account/page.tsx +++ b/frontend/app/account/page.tsx @@ -5,7 +5,7 @@ import MovieCard from '@/components/MovieCard' import BookmarkCard from '@/components/BookmarkCard' -// Types +// provide type for the movie object type Movie = { id: number title: string @@ -38,17 +38,20 @@ export default function AccountPage() { if (id) { setUserId(parseInt(id)) + // fetch user data from the backend scripts fetch(`${BASE_URL}/getUser.php?id=${id}`) .then(res => res.json()) .then(data => { setEmail(data.email || '') setUsername(data.name || '') }) - + + // fetch bookmarks from the backend scripts fetch(`${BASE_URL}/getBookmarks.php?user_id=${id}`) .then(res => res.json()) .then(data => setBookmarks(data)) + // fetch genre preferences from the backend scripts fetch(`${BASE_URL}/getPreference.php?user_id=${id}`) .then(res => res.json()) .then(data => { @@ -65,11 +68,12 @@ export default function AccountPage() { ) } - // user genre preference + // save genre preferences to the backend scripts const handleGenreSave = async () => { if (!userId) return const genre_preference = selectedGenres.join(',') + const res = await fetch(`${BASE_URL}/updatePreference.php`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -115,6 +119,7 @@ export default function AccountPage() { { label: "Genre Preference", key: "preferences" }, { label: "Security", key: "security" }, ].map(tab => ( + // chekcs if the tab is selected and applies styles accordingly - - - {/* Delete Button OUTSIDE of Link */} - - ) } diff --git a/frontend/components/BookmarksTab.tsx b/frontend/components/BookmarksTab.tsx index 1d17d7a..83d7116 100644 --- a/frontend/components/BookmarksTab.tsx +++ b/frontend/components/BookmarksTab.tsx @@ -18,12 +18,14 @@ export default function BookmarksTab() { useEffect(() => { if (!userId) return + // Fetch bookmarks from the backend scripts fetch(`${BASE_URL}/getBookmarks.php?user_id=${userId}`) .then(res => res.json()) .then(data => setBookmarks(data)) .catch(err => console.error("Failed to load bookmarks", err)) }, [userId]) + // Function to handle removing a bookmark const handleRemove = async (movieId: number) => { try { await fetch(`${BASE_URL}/removeFromList.php`, { diff --git a/frontend/components/Comments.tsx b/frontend/components/Comments.tsx index 155ed6c..1928864 100644 --- a/frontend/components/Comments.tsx +++ b/frontend/components/Comments.tsx @@ -17,11 +17,13 @@ export default function Comments({ movieId }: Props) { const id = localStorage.getItem('user_id') setUserId(id) + // Fetch comments for the specific movie fetch(`${BASE_URL}/getComments.php?movie_id=${movieId}`) .then(res => res.json()) .then(data => setComments(data)) }, [movieId]) + // Function to handle posting a new comment const handlePost = async () => { if (!newComment.trim() || !userId) return @@ -37,6 +39,7 @@ export default function Comments({ movieId }: Props) { const data = await res.json() + // Check if the comment was successfully posted if (data.success) { setComments(prev => [{ name: "You", content: newComment }, ...prev]) setNewComment("") diff --git a/frontend/components/Header.tsx b/frontend/components/Header.tsx index 37156bb..b6e0c92 100644 --- a/frontend/components/Header.tsx +++ b/frontend/components/Header.tsx @@ -2,18 +2,21 @@ import Link from 'next/link' import { useEffect, useState } from 'react' -import { AiFillHome, AiOutlineSearch, AiOutlineUser } from 'react-icons/ai' -import { MdLogout} from 'react-icons/md' -import { GoHome} from 'react-icons/go' +import { AiFillHome, AiOutlineSearch, AiOutlineUser, AiOutlineMenu, AiOutlineClose } from 'react-icons/ai' +import { MdLogout } from 'react-icons/md' +import { GoHome } from 'react-icons/go' export default function Header() { const [isLoggedIn, setIsLoggedIn] = useState(false) + const [menuOpen, setMenuOpen] = useState(false) + // stores user login in localStorage useEffect(() => { const userId = localStorage.getItem('user_id') setIsLoggedIn(!!userId) }, []) + // handles user logout const handleLogout = () => { localStorage.removeItem('user_id') setIsLoggedIn(false) @@ -21,42 +24,81 @@ export default function Header() { } return ( -
+
+ -

CINESCOPE

+

+ CINESCOPE +

- -
+ + {/* mobile menu open */} + {menuOpen && ( +
+ setMenuOpen(false)} className="block text-white"> + Home + + setMenuOpen(false)} className="block text-white"> + Search + + {!isLoggedIn ? ( + setMenuOpen(false)} className="block text-white"> + Sign Up + + ) : ( + <> + setMenuOpen(false)} className="block text-white"> + Account + + + + )} +
+ )}
) } diff --git a/frontend/components/MovieCard.tsx b/frontend/components/MovieCard.tsx index a35679f..d706013 100644 --- a/frontend/components/MovieCard.tsx +++ b/frontend/components/MovieCard.tsx @@ -14,6 +14,7 @@ type Props = { export default function MovieCard({ id, title, release_date }: Props) { const [posterPath, setPosterPath] = useState(null) + // Fetch poster path from TMDb API useEffect(() => { const fetchPoster = async () => { const apiKey = process.env.NEXT_PUBLIC_TMDB_KEY diff --git a/frontend/components/RatingStars.tsx b/frontend/components/RatingStars.tsx index c643e31..9d92c8e 100644 --- a/frontend/components/RatingStars.tsx +++ b/frontend/components/RatingStars.tsx @@ -16,14 +16,16 @@ export default function RatingStars({ movieId, userId, readonly = false }: Props const [hovered, setHovered] = useState(null) useEffect(() => { - if (readonly || !userId) return - + if (!userId) return + + // fetching the rating from the backend scripts fetch(`${BASE_URL}/getRating.php?user_id=${userId}&movie_id=${movieId}`) .then(res => res.json()) .then(data => setRating(data.score || 0)) .catch(err => console.error("Error fetching rating:", err)) - }, [movieId, userId, readonly]) + }, [movieId, userId]) + // Function to handle rating const handleRating = async (score: number) => { if (readonly || !userId) return