From ebfbecd3d5470f2b4c88a1acabe26638d0205049 Mon Sep 17 00:00:00 2001 From: Vidwa De Seram Date: Thu, 4 Jan 2024 21:54:27 +0530 Subject: [PATCH] admin movie fetch and auth-done --- admin/package-lock.json | 39 ++++++ admin/package.json | 2 + admin/src/App.js | 176 ++++++++++++++++++++-------- admin/src/index.js | 18 +-- admin/src/pages/AllMovies.js | 133 +++++++++++---------- admin/src/pages/Login.js | 118 +++++++++++++------ admin/src/pages/auth/UserContext.js | 33 ++++++ 7 files changed, 361 insertions(+), 158 deletions(-) create mode 100644 admin/src/pages/auth/UserContext.js diff --git a/admin/package-lock.json b/admin/package-lock.json index 4a7e8b7..013ab6d 100644 --- a/admin/package-lock.json +++ b/admin/package-lock.json @@ -11,10 +11,12 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.6.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1", "react-scripts": "5.0.1", + "sweetalert2": "^11.10.2", "web-vitals": "^2.1.4" } }, @@ -5423,6 +5425,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz", + "integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -14634,6 +14659,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -16559,6 +16589,15 @@ "boolbase": "~1.0.0" } }, + "node_modules/sweetalert2": { + "version": "11.10.2", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.2.tgz", + "integrity": "sha512-BYlIxGw6OF9Rw2z1wlnh1U+fvHHkvtg4BGyimV9nZxQRGvCBfx9uonxgwuYpJuYqCtM+2W1KOm8iMIEb/2v7Hg==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/admin/package.json b/admin/package.json index b9a91d2..7fb0b6d 100644 --- a/admin/package.json +++ b/admin/package.json @@ -6,10 +6,12 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.6.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1", "react-scripts": "5.0.1", + "sweetalert2": "^11.10.2", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/admin/src/App.js b/admin/src/App.js index 8329d44..ede1746 100644 --- a/admin/src/App.js +++ b/admin/src/App.js @@ -1,66 +1,138 @@ -import React, { useState } from 'react'; -import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; -import Header from './components/Header'; -import Sidebar from './components/Sidebar'; -import Login from './pages/Login'; -import Movies from './pages/Movie'; -import MovieUpdate from './pages/MovieUpdate'; -import AddShowtime from './pages/AddShowtime'; -import UpdateShowtime from './pages/UpdateShowtime'; -import DeleteMovieForm from './pages/DeleteMovie'; -import DeleteShowtime from './pages/DeleteShowtime'; -import AddBooking from './pages/AddBooking'; -import UpdateBooking from './pages/UpdateBooking'; -import DeleteBooking from './pages/DeleteBooking'; -import Chat from './pages/Chat'; -import MovieGrid from './pages/AllMovies'; -import ShowtimeGrid from './pages/AllShowtimes'; -import BookingGrid from './pages/AllBookings'; -import RegisterPage from './pages/Signup'; +import React, { useState, useEffect, useContext } from "react"; +import { + BrowserRouter as Router, + Route, + Routes, + Navigate, +} from "react-router-dom"; + +import axios from "axios"; +import Swal from "sweetalert2"; + +import Header from "./components/Header"; +import Sidebar from "./components/Sidebar"; +import Login from "./pages/Login"; +import Movies from "./pages/Movie"; +import MovieUpdate from "./pages/MovieUpdate"; +import AddShowtime from "./pages/AddShowtime"; +import UpdateShowtime from "./pages/UpdateShowtime"; +import DeleteMovieForm from "./pages/DeleteMovie"; +import DeleteShowtime from "./pages/DeleteShowtime"; +import AddBooking from "./pages/AddBooking"; +import UpdateBooking from "./pages/UpdateBooking"; +import DeleteBooking from "./pages/DeleteBooking"; +import Chat from "./pages/Chat"; +import MovieGrid from "./pages/AllMovies"; +import ShowtimeGrid from "./pages/AllShowtimes"; +import BookingGrid from "./pages/AllBookings"; +import RegisterPage from "./pages/Signup"; + +import { UserContext } from "./pages/auth/UserContext"; // Import UserContext +import { UserProvider } from "./pages/auth/UserContext"; const App = () => { + const { updateUserData } = useContext(UserContext); // Use updateUserData from UserContext const [isLoggedIn, setIsLoggedIn] = useState(false); + const checkUserLoggedIn = async () => { + const token = localStorage.getItem("admin-token"); // Use a different token key for admin + if (token) { + try { + const profileResponse = await axios.get( + `${process.env.REACT_APP_API_PATH}/users/profile`, // API endpoint for admin profile + { + headers: { + Authorization: `Bearer ${token}`, // Use the token from localStorage + }, + } + ); + + if (profileResponse.data && profileResponse.data.type === "ADMIN") { + updateUserData(profileResponse.data); + setIsLoggedIn(true); + } else { + // Handle non-admin user + Swal.fire({ + title: "Access Denied", + text: "You are not authorized to access the admin panel.", + icon: "error", + confirmButtonText: "OK", + }); + localStorage.removeItem("admin-token"); // Optionally remove the token + setIsLoggedIn(false); + } + } catch (error) { + console.error("Error fetching admin data:", error); + Swal.fire({ + title: "Error", + text: "An error occurred while fetching user data.", + icon: "error", + confirmButtonText: "OK", + }); + } + } + }; + useEffect(() => { + checkUserLoggedIn(); + }, []); + const handleLogin = () => { setIsLoggedIn(true); }; + function ProtectedRoute({ children }) { + if (!isLoggedIn) { + console.log(isLoggedIn); + return ; + } + return children; + } return ( - - {isLoggedIn ? ( -
-
-
- -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + + + {isLoggedIn ? ( +
+
+
+ +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + +
-
- ) : ( - - } /> - } /> - } /> - - )} - + ) : ( + + } /> + } /> + } /> + + )} + + ); }; diff --git a/admin/src/index.js b/admin/src/index.js index d563c0f..766d3ca 100644 --- a/admin/src/index.js +++ b/admin/src/index.js @@ -1,14 +1,16 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; -const root = ReactDOM.createRoot(document.getElementById('root')); +import { UserProvider } from "./pages/auth/UserContext"; + +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + - + ); // If you want to start measuring performance in your app, pass a function diff --git a/admin/src/pages/AllMovies.js b/admin/src/pages/AllMovies.js index c8d9abc..0e156e6 100644 --- a/admin/src/pages/AllMovies.js +++ b/admin/src/pages/AllMovies.js @@ -1,74 +1,79 @@ -import React from 'react'; -import '../css/AllMovies.css'; // Ensure you have a MovieCard.css file in the same directory -import { Link } from 'react-router-dom'; - -const movies = [ - // JSON-like array of movie objects - { - "id": 1, - "title": "Wonka", - "coverImage": "/images/wonka.jpeg" - }, - { - "id": 2, - "title": "Marvels", - "coverImage": "/images/marvels1.jpg" - }, - { - "id": 3, - "title": "Migration", - "coverImage": "/images/migration.jpg" - }, - { - "id": 4, - "title": "Aquaman", - "coverImage": "/images/aquaman-cover-2.jpg" - } - // ... add more movie objects as needed -]; +import "../css/AllMovies.css"; // Ensure you have a MovieCard.css file in the same directory +import { Link } from "react-router-dom"; +import React, { useState, useEffect } from "react"; +import axios from "axios"; -const MovieCard = ({ movie }) => { - return ( -
- {movie.title} -
-

{movie.title}

-
- - - - - - - - - -
-
+const MovieCard = ({ movie, isComingSoon }) => { + return ( +
+ {movie.title} +
+

{movie.title}

+ {isComingSoon &&

Coming Soon

} +
+ + + + + + + + +
- ); +
+
+ ); }; - const MovieGrid = () => { - return ( -
-
- - - - + const [currentMovies, setCurrentMovies] = useState([]); + const [upcomingMovies, setUpcomingMovies] = useState([]); - -
-
- {movies.map((movie, index) => ( - - ))} -
-
- ); + const fetchMovies = async (nowShowing) => { + try { + const adminToken = localStorage.getItem("admin-token"); + const response = await axios.get( + `${process.env.REACT_APP_API_PATH}/movies`, + { + params: { nowShowing }, + headers: { Authorization: `Bearer ${adminToken}` }, + } + ); + if (nowShowing) { + setCurrentMovies(response.data); + } else { + setUpcomingMovies(response.data); + } + } catch (error) { + console.error("Error fetching movies:", error); + } + }; + + useEffect(() => { + fetchMovies(true); // Fetch current movies + fetchMovies(false); // Fetch upcoming movies + }, []); + return ( +
+
+ + + + + +
+
+ {currentMovies.map((movie, index) => ( + + ))} + {upcomingMovies.map((movie, index) => ( + + ))} +
+
+ ); }; export default MovieGrid; diff --git a/admin/src/pages/Login.js b/admin/src/pages/Login.js index 9f46b2e..f5f89b6 100644 --- a/admin/src/pages/Login.js +++ b/admin/src/pages/Login.js @@ -1,43 +1,93 @@ -// Login.js -import React, { useState } from 'react'; -import '../css/Login.css'; // Import the CSS file -import { Link } from 'react-router-dom'; +import React, { useState, useContext } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import axios from "axios"; +import Swal from "sweetalert2"; -const Login = ({ onLogin }) => { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); +import { UserContext } from "./auth/UserContext"; - const handleSubmit = (event) => { - event.preventDefault(); - // Implement your login logic here - onLogin(); - }; +const Login = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const navigate = useNavigate(); + const { updateUserData } = useContext(UserContext); // Use the context to set user data - return ( -
-
-

Login

-
-
- setUsername(e.target.value)} /> -
-
-
- setPassword(e.target.value)} /> -
-
-
- -
+ const handleSubmit = async (event) => { + event.preventDefault(); + try { + // Authenticate user + const loginResponse = await axios.post( + `${process.env.REACT_APP_API_PATH}/auth/signin`, + { email: username, password } + ); + const token = loginResponse.data.accessToken; + // Fetch user profile + const profileResponse = await axios.get( + `${process.env.REACT_APP_API_PATH}/users/profile`, + { headers: { Authorization: `Bearer ${token}` } } + ); + console.log(profileResponse); + const userData = profileResponse.data; // User data from profile response - -

Register

- -
-
+ if (userData && userData.type === "ADMIN") { + localStorage.setItem("admin-token", token); // Store the token + updateUserData(userData); // Update user data in context + console.log(userData); + navigate("/movies-view"); // Navigate to the admin dashboard + } else { + Swal.fire({ + title: "Access Denied", + text: "You are not authorized to access the admin panel.", + icon: "error", + confirmButtonText: "OK", + }); + } + } catch (error) { + console.error("Login Error:", error); + Swal.fire({ + title: "Login Failed", + text: "Invalid username or password.", + icon: "error", + confirmButtonText: "OK", + }); + } + }; + return ( +
+
+

Login

+
+ +
+ setUsername(e.target.value)} + />
- ); +
+ +
+ setPassword(e.target.value)} + /> +
+
+
+ +
+ + +

Register

+ +
+
+
+ ); }; export default Login; diff --git a/admin/src/pages/auth/UserContext.js b/admin/src/pages/auth/UserContext.js new file mode 100644 index 0000000..05379e3 --- /dev/null +++ b/admin/src/pages/auth/UserContext.js @@ -0,0 +1,33 @@ +import React, { createContext, useContext, useState } from "react"; + +// Create Context +export const UserContext = createContext({ + userData: null, + setUserData: () => {}, +}); + +export const UserProvider = ({ children }) => { + const [userData, setUserData] = useState(null); + const [isLoading, setIsLoading] = useState(false); // Global loading state + + // Function to update user data + const updateUserData = (data) => { + setUserData(data); + }; + + // Function to set loading state + const setLoading = (loading) => { + setIsLoading(loading); + }; + + return ( + + {children} + + ); +}; + +// Custom hook to use UserContext +export const useUserContext = () => useContext(UserContext);