diff --git a/.env b/.env index 9eeb008..644f252 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -VITE_API_URL=http://127.0.0.1:8000 \ No newline at end of file +VITE_API_URL=https://gallery.steve-dekart.xyz \ No newline at end of file diff --git a/src/api/authApi.ts b/src/api/authApi.ts index c0f9108..9d30f41 100644 --- a/src/api/authApi.ts +++ b/src/api/authApi.ts @@ -1,18 +1,18 @@ import { type LoginPayload, type LoginResponse, - type MeResponse, + type User, } from "../components/shared/types/AuthTypes"; import axiosInstance from "./axiosInstance"; export const loginRequest = async (data: LoginPayload) => { - const res = await axiosInstance.post("/api/auth/login", data); + const res = await axiosInstance.post("/api/auth/login/", data); return res.data; }; export const fetchMe = async () => { - const res = await axiosInstance.get("/api/auth/me"); - return res.data.user; + const res = await axiosInstance.get("/api/auth/me/"); + return res.data; }; diff --git a/src/api/axiosInstance.ts b/src/api/axiosInstance.ts index 6a38bbd..ed6bde1 100644 --- a/src/api/axiosInstance.ts +++ b/src/api/axiosInstance.ts @@ -10,7 +10,7 @@ const axiosInstance = axios.create({ axiosInstance.interceptors.request.use( (config) => { const token = localStorage.getItem("access_token"); - if (token) config.headers.Authorization = `Bearer ${token}`; + if (token) config.headers.Authorization = `Token ${token}`; return config; }, diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 745d692..710dcbf 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -11,10 +11,13 @@ import MenuItem from "@mui/material/MenuItem"; import { useNavigate } from "react-router-dom"; import { Container } from "@mui/material"; -import CameraIcon from '@mui/icons-material/Camera'; +import CameraIcon from "@mui/icons-material/Camera"; +import appColors from "../../utils/colors"; +import { useAuth } from "../../context/AuthContext"; function Header() { const navigate = useNavigate(); + const { user } = useAuth(); const [anchorElNav, setAnchorElNav] = React.useState( null @@ -31,7 +34,7 @@ function Header() { const goToAdmin = () => navigate("/admin"); return ( - + @@ -74,7 +77,7 @@ function Header() { onClose={handleCloseNavMenu} sx={{ display: { xs: "block", md: "none" } }} > - + {!user && ( { handleCloseNavMenu(); @@ -83,9 +86,10 @@ function Header() { > Login - - - + )} + + + {user && ( { handleCloseNavMenu(); @@ -94,20 +98,19 @@ function Header() { > Profile - - { - handleCloseNavMenu(); - goToAdmin(); - }} - > - - Admin Dashboard - - - - + )} + {user && user.is_superuser && ( + { + handleCloseNavMenu(); + goToAdmin(); + }} + > + Admin Dashboard + + )} + @@ -132,33 +135,32 @@ function Header() { - + {!user && ( - + )} - - <> - - - - - - + {user && ( + + )} + + {user?.is_superuser && ( + + )} diff --git a/src/components/shared/types/AuthTypes.ts b/src/components/shared/types/AuthTypes.ts index 4211b00..53ed3f2 100644 --- a/src/components/shared/types/AuthTypes.ts +++ b/src/components/shared/types/AuthTypes.ts @@ -18,7 +18,7 @@ export interface LoginResponse { } export interface LoginPayload { - email: string; + username: string; password: string; } diff --git a/src/pages/LoginPage/LoginPage.tsx b/src/pages/LoginPage/LoginPage.tsx new file mode 100644 index 0000000..6fd0966 --- /dev/null +++ b/src/pages/LoginPage/LoginPage.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from "react"; +import { useAuth } from "../../context/AuthContext"; + +import { Box, Button, Container, TextField, Typography } from "@mui/material"; +import { useNavigate } from "react-router-dom"; +import appColors from "../../utils/colors"; + + +const LoginPage = () => { + const { login, user } = useAuth(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const navigate = useNavigate(); + + useEffect(() => { + if (user) { + navigate("/"); + } + }, [user, navigate]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + await login({ username, password }); + }; + + return ( + + + + Login + +
+ setUsername(e.target.value)} + fullWidth + margin="normal" + required + /> + setPassword(e.target.value)} + fullWidth + margin="normal" + required + /> + + +
+
+ ); +}; + +export default LoginPage; diff --git a/src/pages/ProfilePage/ProfilePage.tsx b/src/pages/ProfilePage/ProfilePage.tsx new file mode 100644 index 0000000..8c47aa0 --- /dev/null +++ b/src/pages/ProfilePage/ProfilePage.tsx @@ -0,0 +1,57 @@ +import { Box, Button, Container, Typography } from "@mui/material"; +import { useAuth } from "../../context/AuthContext"; +import { useNavigate } from "react-router-dom"; +import appColors from "../../utils/colors"; +import { useEffect } from "react"; +import { toast } from "react-toastify"; + +const ProfilePage = () => { + const { user, logout, isLoading } = useAuth(); + const navigate = useNavigate(); + + useEffect(() => { + if (!isLoading && !user) { + toast.error("You must be logged in to view your profile"); + navigate("/login"); + } + }, []); + + return ( + + + + Profile + + + Username: {user?.username} + + + E-mail: {user?.email} + + + Index: {user?.school_index} + + + Status: {user?.is_superuser ? "Admin" : "User"} + + + + + + + ); +}; + +export default ProfilePage; diff --git a/src/router/router.tsx b/src/router/router.tsx index d7571bd..98e3190 100644 --- a/src/router/router.tsx +++ b/src/router/router.tsx @@ -1,6 +1,8 @@ import { createBrowserRouter } from "react-router-dom"; import MainLayout from "../MainLayout/MainLayout"; import { Container } from "@mui/material"; +import LoginPage from "../pages/LoginPage/LoginPage"; +import ProfilePage from "../pages/ProfilePage/ProfilePage"; const router = createBrowserRouter([ { @@ -10,6 +12,14 @@ const router = createBrowserRouter([ { index: true, element: index page + }, + { + path: "/login", + element: + }, + { + path: "/profile", + element: } ]} ]) diff --git a/src/utils/colors.ts b/src/utils/colors.ts new file mode 100644 index 0000000..b0806ac --- /dev/null +++ b/src/utils/colors.ts @@ -0,0 +1,8 @@ +export const appColors = { + secondary: '#B3CDE0', + bg: '#FFFFFF', + primary: '#011F4B', + tertiary: '#EDF2FA', +}; + +export default appColors; \ No newline at end of file