diff --git a/.gitignore b/.gitignore index 2969bf68..ac48899b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ venv/ *.pyz *.pyw node_modules +frontend/src/assets/images/ \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 25e3d790..4281d9f8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,9 +11,10 @@ "dependencies": "^0.0.1", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", + "@heroicons/react": "^2.2.0", "@mui/icons-material": "^6.1.2", "@mui/material": "^6.1.2", - "@supabase/supabase-js": "^2.45.5", + "@supabase/supabase-js": "^2.46.1", "axios": "^1.7.7", "pdfjs-dist": "^4.7.76", "react": "^18.3.1", @@ -2485,6 +2486,14 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 9894ef85..e1407e11 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,9 +13,10 @@ "dependencies": { "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", + "@heroicons/react": "^2.2.0", "@mui/icons-material": "^6.1.2", "@mui/material": "^6.1.2", - "@supabase/supabase-js": "^2.45.5", + "@supabase/supabase-js": "^2.46.1", "axios": "^1.7.7", "dependencies": "^0.0.1", "pdfjs-dist": "^4.7.76", diff --git a/frontend/src/assets/images/ShopLogBooks.png b/frontend/src/assets/images/ShopLogBooks.png new file mode 100644 index 00000000..361ad31c Binary files /dev/null and b/frontend/src/assets/images/ShopLogBooks.png differ diff --git a/frontend/src/assets/images/logbooks.png b/frontend/src/assets/images/logbooks.png new file mode 100644 index 00000000..31c6b15f Binary files /dev/null and b/frontend/src/assets/images/logbooks.png differ diff --git a/frontend/src/assets/images/logo-small.png b/frontend/src/assets/images/logo-small.png new file mode 100644 index 00000000..aa03e209 Binary files /dev/null and b/frontend/src/assets/images/logo-small.png differ diff --git a/frontend/src/assets/images/logo.png b/frontend/src/assets/images/logo.png new file mode 100644 index 00000000..2f030bcb Binary files /dev/null and b/frontend/src/assets/images/logo.png differ diff --git a/frontend/src/components/Buttons/CLButtons.jsx b/frontend/src/components/Buttons/CLButtons.jsx new file mode 100644 index 00000000..515ae552 --- /dev/null +++ b/frontend/src/components/Buttons/CLButtons.jsx @@ -0,0 +1,68 @@ +const DEFAULT_HEIGHT = "54px"; +const DEFAULT_WIDTH = "fit-content"; +const DEFAULT_BORDER_RADIUS = "20px"; +const DEFAULT_ON_CLICK = () => {}; + +// PRIMARY specific styles +const PRIMARY_COLOR = "#F7FAFF"; +const PRIMARY_BACKGROUND_COLOR = "#244B94"; + +// SECONDARY specific styles +const SECONDARY_COLOR = "#4F607E"; +const SECONDARY_BACKGROUND_COLOR = "#F7FAFF"; +const SECONDARY_BORDER = "1px solid #9AB0E1"; + +/** + * PRIMARY variant of the clinical logging button. + * Should work out of the box for most use cases (with the exception of onClick which does nothing by default). + * The height and width are customizable if necessary. + */ +export const CLButtonPrimary = ({ + children, + height = DEFAULT_HEIGHT, + width = DEFAULT_WIDTH, + onClick = DEFAULT_ON_CLICK, +}) => { + return ( + + ); +}; + +/** + * SECONDARY variant of the clinical logging button. + * Should work out of the box for most use cases (with the exception of onClick which does nothing by default). + * The height and width are customizable if necessary. + */ +export const CLButtonSecondary = ({ + children, + height = DEFAULT_HEIGHT, + width = DEFAULT_WIDTH, + onClick = DEFAULT_ON_CLICK, +}) => { + return ( + + ); +}; diff --git a/frontend/src/components/Buttons/CreateNewLogButton.css b/frontend/src/components/Buttons/CreateNewLogButton.css deleted file mode 100644 index 3831f023..00000000 --- a/frontend/src/components/Buttons/CreateNewLogButton.css +++ /dev/null @@ -1,4 +0,0 @@ -.add-icon { - margin-right: 9px; - vertical-align: -6px; -} \ No newline at end of file diff --git a/frontend/src/components/Buttons/CreateNewLogButton.jsx b/frontend/src/components/Buttons/CreateNewLogButton.jsx deleted file mode 100644 index f39087fb..00000000 --- a/frontend/src/components/Buttons/CreateNewLogButton.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import AddIcon from "@mui/icons-material/Add"; -import { useNavigate } from "react-router-dom"; -import "./CreateNewLogButton.css"; - -export default function CreateNewLogButton({ variant }) { - const navigate = useNavigate(); - - const handleCreateNewLog = () => { - navigate("/newLog"); - }; - - return ( - - ); -} diff --git a/frontend/src/components/Buttons/HomeButton.jsx b/frontend/src/components/Buttons/HomeButton.jsx deleted file mode 100644 index f7a8e407..00000000 --- a/frontend/src/components/Buttons/HomeButton.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import { useNavigate } from "react-router-dom"; - -export default function HomeButton() { - const navigate = useNavigate(); - - const handleHomeClick = () => { - navigate("/dashboard"); - }; - - return ; -} diff --git a/frontend/src/components/Buttons/LogHistoryButton.css b/frontend/src/components/Buttons/LogHistoryButton.css deleted file mode 100644 index f9a21a14..00000000 --- a/frontend/src/components/Buttons/LogHistoryButton.css +++ /dev/null @@ -1,4 +0,0 @@ -.history-icon { - margin-right: 9px; - vertical-align: -6px; -} \ No newline at end of file diff --git a/frontend/src/components/Buttons/LogHistoryButton.jsx b/frontend/src/components/Buttons/LogHistoryButton.jsx deleted file mode 100644 index 84954962..00000000 --- a/frontend/src/components/Buttons/LogHistoryButton.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import { useNavigate } from "react-router-dom"; -import HistoryIcon from "@mui/icons-material/History"; -import "./LogHistoryButton.css"; - -export default function LogHistoryButton({ variant }) { - const navigate = useNavigate(); - - const handleViewHistory = () => { - navigate("/logHistory"); - }; - - return ( - - ); -} diff --git a/frontend/src/components/Buttons/SignInButton.css b/frontend/src/components/Buttons/SignInButton.css deleted file mode 100644 index 3caa433d..00000000 --- a/frontend/src/components/Buttons/SignInButton.css +++ /dev/null @@ -1,10 +0,0 @@ -.sign-in-button-container { - display: flex; - gap: 9px; - } - -.login-icon { - margin-left: 8px; - font-size: 1.2rem; - vertical-align: middle; -} \ No newline at end of file diff --git a/frontend/src/components/Buttons/SignInButton.jsx b/frontend/src/components/Buttons/SignInButton.jsx deleted file mode 100644 index 5ddb730a..00000000 --- a/frontend/src/components/Buttons/SignInButton.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useNavigate } from "react-router-dom"; -import LoginIcon from "@mui/icons-material/Login"; -import "./SignInButton.css"; - -export default function SignInButton() { - const navigate = useNavigate(); - - const handleSignInClick = () => { - navigate("/login"); - }; - - return ( -
- -
- ); -} diff --git a/frontend/src/components/Buttons/SignOutButton.css b/frontend/src/components/Buttons/SignOutButton.css deleted file mode 100644 index 6f6a4b22..00000000 --- a/frontend/src/components/Buttons/SignOutButton.css +++ /dev/null @@ -1,10 +0,0 @@ -.sign-out-button-container { - display: flex; - gap: 9px; - } - -.sign-out-icon { - margin-left: 8px; - font-size: 1.2rem; - vertical-align: middle; -} \ No newline at end of file diff --git a/frontend/src/components/Buttons/SignOutButton.jsx b/frontend/src/components/Buttons/SignOutButton.jsx deleted file mode 100644 index 65cd7b9b..00000000 --- a/frontend/src/components/Buttons/SignOutButton.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useAuth } from "../../contexts/AuthContext"; -import LogoutIcon from "@mui/icons-material/Logout"; -import "./SignOutButton.css"; - -export default function SignOutButton() { - const { logout } = useAuth(); - - const handleSignOutClick = async () => { - try { - await logout(); - } catch { - console.log("Failed to logout"); - } - }; - - return ( -
- -
- ); -} diff --git a/frontend/src/components/Buttons/SignUpButton.css b/frontend/src/components/Buttons/SignUpButton.css deleted file mode 100644 index 512fad28..00000000 --- a/frontend/src/components/Buttons/SignUpButton.css +++ /dev/null @@ -1,4 +0,0 @@ -.sign-up-button-container { - display: flex; - gap: 8px; -} \ No newline at end of file diff --git a/frontend/src/components/Buttons/SignUpButton.jsx b/frontend/src/components/Buttons/SignUpButton.jsx deleted file mode 100644 index 6be86bd7..00000000 --- a/frontend/src/components/Buttons/SignUpButton.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useNavigate } from "react-router-dom"; -import "./SignUpButton.css"; - -export default function SignUpButton() { - const navigate = useNavigate(); - - const handleSignUpClick = () => { - navigate("/signup"); - }; - return ( -
- -
- ); -} diff --git a/frontend/src/components/Navbar/Navbar.css b/frontend/src/components/Navbar/Navbar.css index 49db6121..d7e5b159 100644 --- a/frontend/src/components/Navbar/Navbar.css +++ b/frontend/src/components/Navbar/Navbar.css @@ -1,21 +1,108 @@ .navbar { display: flex; + flex-direction: column; + position: absolute; + top: 28%; + left: 30px; + height: 420px; + width: 65px; justify-content: space-between; align-items: center; - padding: 16px; - width: 100vw; - height: 80px; - background-color: #242424; - position: fixed; - top: 0; - left: 0; - right: 0; - border-bottom: 2px solid rgba(255, 255, 255, 0.3); -} - -.nav-buttons-container { +} + +.nav-button-container { + height: 305px; + width: 65px; + padding: 15px 0 15px 0; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + background-color: white; + border-radius: 30px; + box-shadow: 0px 0px 10px #CDD8F0; +} + +.nav-button { + background-color: transparent; +} + +.nav-button-icon-container { + height: 50px; + width: 50px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 25px; + color: #244B94; + background-color: #CDD8F0; + transition: all 0.2s ease; +} + +.nav-button-icon-container:hover { + background-color: #244B94; + color: #F7FAFF; + box-shadow: 0 4px 8px rgba(36, 75, 148, 0.4); +} + +.nav-button-icon-container-selected { + height: 50px; + width: 50px; display: flex; - gap: 8px; - margin-top: 10px; - margin-right: 30px; + justify-content: center; + align-items: center; + border-radius: 25px; + color: #F7FAFF; + background-color: #244B94; + box-shadow: 0 4px 8px rgba(36, 75, 148, 0.4); +} + +.nav-button-icon-container:hover { + background-color: #244B94; + color: white; +} + +.nav-button-text { + margin-top: 2px; + color: black; + font-weight: 400; + text-align: center; + transition: all 0.2s ease; + font-size: 11px; +} + +.nav-button-text-selected { + margin-top: 2px; + color: #244B94; + font-weight: bold; + text-align: center; + font-size: 11px; +} + +.logout-button { + height: 50px; + width: 50px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 25px; + color: #244B94; + background-color: white; + box-shadow: 0px 0px 10px #CDD8F0; + transition: all 0.2s ease; + border: none; /* Added to remove default button border */ + cursor: pointer; +} + +.logout-button:hover { + background-color: #244B94; + color: #F7FAFF; + box-shadow: 0 4px 8px rgba(36, 75, 148, 0.4); +} + +.icon { + height: 24px; + width: 24px; + color: inherit; + transition: color 0.2s ease; } \ No newline at end of file diff --git a/frontend/src/components/Navbar/Navbar.jsx b/frontend/src/components/Navbar/Navbar.jsx index 9666a7a4..dbabf415 100644 --- a/frontend/src/components/Navbar/Navbar.jsx +++ b/frontend/src/components/Navbar/Navbar.jsx @@ -1,51 +1,84 @@ -import Logo from "../Logo/Logo"; -import HomeButton from "../Buttons/HomeButton"; -import CreateNewLogButton from "../Buttons/CreateNewLogButton"; -import LogHistoryButton from "../Buttons/LogHistoryButton"; -import SignInButton from "../Buttons/SignInButton"; -import { useAuth } from "../../contexts/AuthContext"; +"use state"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; import "./Navbar.css"; -import SignOutButton from "../Buttons/SignOutButton"; - -export default function Navbar({ variant }) { - return ( -
- -
- ); -} - -function NavbarComponent({ variant }) { - return ( -
- - -
- ); -} +import { + HomeIcon, + BookOpenIcon, + ClockIcon, + ArrowLeftStartOnRectangleIcon, +} from "@heroicons/react/24/outline"; +import { useAuth } from "../../contexts/AuthContext"; -function NavButtons({ variant }) { - return ( -
- {variant === "homepage" ? ( - - ) : ( - <> - - - - - )} -
- ); -} +export default function Navbar() { + const [selected, setSelected] = useState("home"); + const { logout } = useAuth(); + const navigate = useNavigate(); -function Buttons() { - const { session } = useAuth(); + const handleClickLogout = async () => { + try { + await logout(); + navigate("/login"); + } catch (error) { + console.error("Logout failed:", error); + } + }; return ( -
- {session ? : } +
+
+ + + +
+
); } diff --git a/frontend/src/components/inputs/CLInputs.jsx b/frontend/src/components/inputs/CLInputs.jsx new file mode 100644 index 00000000..4b05745c --- /dev/null +++ b/frontend/src/components/inputs/CLInputs.jsx @@ -0,0 +1,29 @@ +import { DemoContainer } from "@mui/x-date-pickers/internals/demo"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import { DatePicker } from "@mui/x-date-pickers/DatePicker"; + +// const DEFAULT_HEIGHT = "67px" +// const DEFAULT_WIDTH = "100%" +// const DEFAULT_PADDING = "" +// const DEFAULT_BORDER = "" +// const DEFAULT_BORDER_RADIUS = "" +// const DEFAULT_BACKGROUND_COLOR = "transparent" + +export const CLTextInput = () => { + return ; +}; + +export const CLNumberInput = () => { + return ; +}; + +export const CLDatePicker = () => { + return ( + + + + + + ); +}; diff --git a/frontend/src/contexts/AuthContext.jsx b/frontend/src/contexts/AuthContext.jsx index a5ca34b7..72f2810b 100644 --- a/frontend/src/contexts/AuthContext.jsx +++ b/frontend/src/contexts/AuthContext.jsx @@ -4,83 +4,90 @@ import supabase from "../config/supabase"; const AuthContext = createContext(); export function useAuth() { - return useContext(AuthContext); + return useContext(AuthContext); } export function AuthProvider({ children }) { - const [session, setSession] = useState(); - const [loading, setLoading] = useState(true); + const [session, setSession] = useState(); + const [loading, setLoading] = useState(true); - async function register(firstName, lastName, email, password) { - const { user, error } = await supabase.auth.signUp({ - email: email, - password: password, - options: { - data: { - first_name: firstName, - last_name: lastName, - } - } - }); - if (error) { - throw error; - } - return user; - } + async function register(firstName, lastName, email, password) { + const { user, error } = await supabase.auth.signUp({ + email: email, + password: password, + options: { + data: { + first_name: firstName, + last_name: lastName, + }, + }, + }); + if (error) { + throw error; + } + return user; + } - async function login(email, password) { - const { data, error } = await supabase.auth.signInWithPassword({ - email: email, - password: password, - }); - if (error) { - throw error; - } - return data; - } + async function login(email, password) { + const { data, error } = await supabase.auth.signInWithPassword({ + email: email, + password: password, + }); + if (error) { + throw error; + } + return data; + } - async function logout() { - const { error } = await supabase.auth.signOut(); - if (error) { - console.log(error); - throw error; - } - } + async function logout() { + try { + const { error } = await supabase.auth.signOut(); + if (error) throw error; + setSession(null); + } catch (error) { + if (error.message === "Auth session missing!") { + setSession(null); + return; + } + console.error("Logout error:", error); + throw error; + } + } - useEffect(() => { - const { - data: { subscription }, - } = supabase.auth.onAuthStateChange((event, session) => { - if (event === "SIGNED_OUT") { - setSession(null); - } else if (session) { - setSession(session); - console.log("This is the session:", session); - } + useEffect(() => { + const { + data: { subscription }, + } = supabase.auth.onAuthStateChange((event, session) => { + if (event === "SIGNED_OUT") { + setSession(null); + } else if (session) { + setSession(session); + console.log("This is the session:", session); + } - setLoading(false); - }); - supabase.auth.getSession().then(({ data }) => { - if (data.session) { - setSession(data.session); - } - setLoading(false); - }); - return () => { - subscription.unsubscribe(); - }; - }, []); + setLoading(false); + }); + supabase.auth.getSession().then(({ data }) => { + if (data.session) { + setSession(data.session); + } + setLoading(false); + }); + return () => { + subscription.unsubscribe(); + }; + }, []); - const value = { - session, - login, - logout, - register, - }; + const value = { + session, + login, + logout, + register, + }; - return ( - - {!loading && children} - - ); + return ( + + {!loading && children} + + ); } diff --git a/frontend/src/index.css b/frontend/src/index.css index d7ff7205..5744195e 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -4,8 +4,8 @@ font-weight: 400; color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + color: #1E1E1E; + background-color: #F7FAFF; font-synthesis: none; text-rendering: optimizeLegibility; @@ -31,37 +31,9 @@ h1 { } button { - border-radius: 8px; border: 1px solid transparent; - padding: 0.6em 1.2em; font-size: 1em; font-weight: 500; font-family: inherit; - background-color: #1a1a1a; cursor: pointer; - transition: border-color 0.25s; -} - -button:hover { - border-color: #646cff; -} - -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - - a:hover { - color: #747bff; - } - - button { - background-color: #f9f9f9; - } } \ No newline at end of file diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 46329ed2..04a4f6da 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -4,30 +4,30 @@ import { ProtectedRoutes } from "./utils/ProtectedRoutes.jsx"; import { AuthProvider } from "./contexts/AuthContext.jsx"; import App from "./App.jsx"; import Login from "./pages/login/Login.jsx"; -import SignUp from "./pages/sign_up/SignUp.jsx"; import NotFound from "./pages/not_found/NotFound.jsx"; import Home from "./pages/Homepage.jsx"; -import Dashboard from "./pages/Dashboard.jsx"; +import Homepage from "./pages/Homepage.jsx"; import NewLog from "./pages/NewLog.jsx"; import LogHistory from "./pages/LogHistory.jsx"; import UploadPhotos from "./pages/UploadPhoto.jsx"; import ManualEdit from "./pages/ManualEdit.jsx"; import "./index.css"; +import LogCode from "./pages/LogCode.jsx"; createRoot(document.getElementById("root")).render( } /> - } /> - } /> }> } /> - } /> + } /> } /> } /> } /> } /> + } /> + } /> } /> diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx deleted file mode 100644 index 2156cd07..00000000 --- a/frontend/src/pages/Dashboard.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import Logo from "../components/Logo/Logo"; -import CreateNewLogButton from "../components/Buttons/CreateNewLogButton"; -import LogHistoryButton from "../components/Buttons/LogHistoryButton"; -import "./styles/Dashboard.css"; - -export default function Dashboard() { - return ( -
-
- -
-
- -
-
- ); -} - -function MainContent() { - return ( -
- - Convert handwritten clinical logs to a
- standardized Excel template with just a click of a button! -
-
- -
-
- ); -} - -function Buttons() { - return ( -
- - -
- ); -} diff --git a/frontend/src/pages/Homepage.jsx b/frontend/src/pages/Homepage.jsx index 82aabaf2..26eeed03 100644 --- a/frontend/src/pages/Homepage.jsx +++ b/frontend/src/pages/Homepage.jsx @@ -1,29 +1,189 @@ -import SignUpButton from "../components/Buttons/SignUpButton"; import Navbar from "../components/Navbar/Navbar"; +import { useState } from "react"; +import { + CLButtonPrimary, + CLButtonSecondary, +} from "../components/Buttons/CLButtons"; +import { useNavigate } from "react-router-dom"; +import { Link } from "react-router-dom"; +import LogbookImage from "../assets/images/logo-small.png"; +import LogBooks from "../assets/images/logbooks.png"; +import ShopLogBooks from "../assets/images/ShopLogBooks.png"; +import { TextField, InputAdornment } from "@mui/material"; +import { + UserCircleIcon, + BellIcon, + AdjustmentsHorizontalIcon, + MagnifyingGlassIcon, + ChevronRightIcon, + ClockIcon, +} from "@heroicons/react/24/outline"; +import "./styles/Homepage.css"; -const mainColour = "#646cff"; +export default function Homepage() { + return ( +
+ + + +
+ ); +} + +function MainContent() { + const navigate = useNavigate(); + const [setSelectedLog] = useState(null); + + const handleCreateNewLog = () => { + navigate("/uploadPhotos"); + }; + + const handleAddLogbook = () => { + navigate("/newLog"); + }; + + const handleViewHistory = () => { + navigate("/logHistory"); + }; -export default function Home() { return ( -
- - +
+
+

+ Welcome back, + Chewy! +

+
+ +
+
+
+

Get Started

+

+ Convert handwritten clinical logs to standardized excel templates + with just a click of a button! +

+
+ + Create New Log + + + Add Logbook + + + View Log History + +
+
+ + +
+ +
+
+

Log Books

+ +
+
+ Logbooks +
+ {[1, 2, 3].map((item, index) => ( +
setSelectedLog(index)} + > +
+ Adult Cardiac 2025 + 65% +
+
+
+
+
+ ))} +
+
+
+
); } -function CTASection() { +function TopNav() { + const [searchQuery, setSearchQuery] = useState(""); return ( -
-

- Welcome to
- FlowLeaflets -

-

- Detailed caselogs for patients you see, vital care for those in need, - globally -

- +
+ + FlowLeaflets Logo + +
); } diff --git a/frontend/src/pages/LogCode.jsx b/frontend/src/pages/LogCode.jsx new file mode 100644 index 00000000..6c498c8f --- /dev/null +++ b/frontend/src/pages/LogCode.jsx @@ -0,0 +1,110 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { TextField, InputAdornment, Tooltip } from "@mui/material"; +import { Article } from "@mui/icons-material"; +import Logo from "../assets/images/logo.png"; +import "./styles/LogCode.css"; + +const LogCode = () => { + const [setLogbookCode] = useState(""); + const [termsAccepted, setTermsAccepted] = useState(false); + const [loading, setLoading] = useState(false); + const navigate = useNavigate(); + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!termsAccepted) { + return alert("Please accept the terms and conditions"); + } + try { + navigate("/home"); + } catch { + alert("Something went wrong. Please try again."); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+
+

Logbook code entry

+

+ Please enter in your logbook code in order to finish registering + your account. +

+ +
+ + setLogbookCode(e.target.value)} + InputProps={{ + startAdornment: ( + +
+ + ), + }} + required + /> +
+ + + +
+ +
+ + +
+
+ +
+
+
+ Logo +
+
+
+
+
+ ); +}; + +export default LogCode; diff --git a/frontend/src/pages/login/Login.jsx b/frontend/src/pages/login/Login.jsx index 8045046a..1b51f4ef 100644 --- a/frontend/src/pages/login/Login.jsx +++ b/frontend/src/pages/login/Login.jsx @@ -1,63 +1,302 @@ -import { Link } from "react-router-dom"; -import { useState } from "react"; +import { useState, useEffect } from "react"; +import { Link, useNavigate } from "react-router-dom"; import { useAuth } from "../../contexts/AuthContext"; -import { useEffect } from "react"; -import { useNavigate } from "react-router-dom"; +import { TextField, InputAdornment, IconButton } from "@mui/material"; +import { + AccountCircle, + Lock, + Email, + Visibility, + VisibilityOff, +} from "@mui/icons-material"; +import Logo from "../../assets/images/logo.png"; +import "../styles/Login.css"; -export default function Login() { +const Login = () => { + const [isRightPanelActive, setIsRightPanelActive] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [name, setName] = useState(""); const [loading, setLoading] = useState(false); + const [showPassword, setShowPassword] = useState(false); + const [confirmPassword, setConfirmPassword] = useState(""); const navigate = useNavigate(); - const { session, login } = useAuth(); + const { session, login, register } = useAuth(); useEffect(() => { if (session) { - navigate("/dashboard"); + navigate("/home"); } }, [session, navigate]); - async function handleSubmit(e) { + const getFirstAndLastName = (fullName) => { + const names = fullName.trim().split(" "); + return { + firstName: names[0] || "", + lastName: names.slice(1).join(" ") || "", + }; + }; + + const handleSignUp = async (e) => { e.preventDefault(); + if (!checkValidEmail(email)) { + return alert("Please enter a valid email"); + } + + if (password !== confirmPassword) { + return alert("Passwords do not match"); + } + + const { firstName, lastName } = getFirstAndLastName(name); + + try { + setLoading(true); + await register(firstName, lastName, email, password); + setIsRightPanelActive(false); + } catch (error) { + if (error.code === "weak_password") { + alert( + "Password must contain:\n" + + "- At least 8 characters\n" + + "- At least one uppercase letter\n" + + "- At least one lowercase letter\n" + + "- At least one number\n" + + "- At least one special character (e.g., !@#$%^&*()_+-=[]{};:'\"|<>?,./`~)" + ); + } else { + alert(error.message); + } + } finally { + setLoading(false); + } + }; + + const handleSignIn = async (e) => { + e.preventDefault(); try { setLoading(true); await login(email, password); - navigate("/dashboard"); + navigate("/home"); } catch { alert("Failed to login: Email or Password Incorrect"); + } finally { + setLoading(false); } - setLoading(false); + }; + + function checkValidEmail(email) { + const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/; + return emailRegex.test(email); } return (
-

Login to Your Account

-
- - setEmail(e.target.value)} - required - /> - - setPassword(e.target.value)} - required - /> - -
- Don't have an Account? Register +
+
+
+

Welcome to Flow Leaflets!

+

Register your account

+ +
+ + setName(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + required + /> +
+ +
+ + setEmail(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + required + /> +
+ +
+ + setPassword(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + > + {showPassword ? : } + + + ), + }} + required + /> +
+ +
+ + setConfirmPassword(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + > + {showPassword ? : } + + + ), + }} + required + /> +
+ + + +
+ Already have an account? + setIsRightPanelActive(false)}> + Sign in + +
+
+
+
+
+

Welcome Back

+

Login to your account

+
+ + setEmail(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + }} + required + /> +
+
+ + setPassword(e.target.value)} + InputProps={{ + startAdornment: ( + + + + ), + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + > + {showPassword ? : } + + + ), + }} + required + /> +
+
+ Forgot password? +
+ +
+ Don’t have an account? + setIsRightPanelActive(true)}> + Sign up + +
+
+
+
+
+
+ Logo +
+
+ Logo +
+
+
+
); -} +}; + +export default Login; diff --git a/frontend/src/pages/sign_up/__tests__/SignUp.test.js b/frontend/src/pages/login/__tests__/SignUp.test.js similarity index 100% rename from frontend/src/pages/sign_up/__tests__/SignUp.test.js rename to frontend/src/pages/login/__tests__/SignUp.test.js diff --git a/frontend/src/pages/sign_up/SignUp.jsx b/frontend/src/pages/sign_up/SignUp.jsx deleted file mode 100644 index 6399c404..00000000 --- a/frontend/src/pages/sign_up/SignUp.jsx +++ /dev/null @@ -1,117 +0,0 @@ -import { Link } from "react-router-dom"; -import { useState } from "react"; -import { useAuth } from "../../contexts/AuthContext"; -import { useEffect } from "react"; -import { useNavigate } from "react-router-dom"; - -export default function SignUp() { - const [firstName, setFirstName] = useState(""); - const [lastName, setLastName] = useState(""); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const [loading, setLoading] = useState(false); - const navigate = useNavigate(); - const { session, register } = useAuth(); - - useEffect(() => { - if (session) { - navigate("/dashboard"); - } - }, [session, navigate]); - - async function handleSubmit(e) { - e.preventDefault(); - - if (!checkValidEmail(email)) { - return alert("Please enter a valid email"); - } else if (password !== confirmPassword) { - return alert("Passwords do not match"); - } - - try { - setLoading(true); - await register(firstName, lastName, email, password); - navigate("/dashboard"); - } catch (error) { - if (error.code === "weak_password") { - alert( - "Password must contain:\n" + - "- At least 8 characters\n" + - "- At least one uppercase letter\n" + - "- At least one lowercase letter\n" + - "- At least one number\n" + - "- At least one special character (e.g., !@#$%^&*()_+-=[]{};:'\"|<>?,./`~)" - ); - } else { - alert(error.message); - } - } - setLoading(false); - } - - return ( -
-

Register your account

-
- - setFirstName(e.target.value)} - required - /> - - setLastName(e.target.value)} - required - /> - - setEmail(e.target.value)} - required - /> - - setPassword(e.target.value)} - required - /> - - setConfirmPassword(e.target.value)} - required - /> - -
- Already have an account? Login -
- ); -} - -function checkValidEmail(email) { - const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/; - return emailRegex.test(email); -} diff --git a/frontend/src/pages/styles/Dashboard.css b/frontend/src/pages/styles/Dashboard.css deleted file mode 100644 index d2a593a5..00000000 --- a/frontend/src/pages/styles/Dashboard.css +++ /dev/null @@ -1,20 +0,0 @@ -.main-content-text { - font-size: 20px; - font-weight: 800; - margin-top: -100px; -} - -.main-content-buttons { - font-size: 17px; - display: flex; - flex-direction: column; - align-items: center; - margin-top: 30px; - gap: 10px; -} - -.buttons-container { - display: flex; - flex-direction: column; - gap: 10px; -} \ No newline at end of file diff --git a/frontend/src/pages/styles/Homepage.css b/frontend/src/pages/styles/Homepage.css index 73cb697c..d29251d8 100644 --- a/frontend/src/pages/styles/Homepage.css +++ b/frontend/src/pages/styles/Homepage.css @@ -1,16 +1,504 @@ -.cta-section { - display: flex; - flex-direction: column; - align-items: center; - margin-left: 64px; - margin-right: 64px; - margin-top: 200px; -} - -.cta-paragraph { - text-align: center; - font-size: 1.1rem; - color: #64748b; - width: 450px; - margin-top: -1rem; +body, html { + background: #F7FAFF; +} + +.page-container { + display: flex; + flex-direction: column; + height: 100vh; +} + +.top-nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.8rem 1.5rem; + width: 40px; + height: 40px; +} + +.nav-left { + display: flex; + align-items: center; + gap: 8px; + margin-left: auto; + margin-right: 200px; + margin-left: 50px; + position: relative; + z-index: 1; +} + +.nav-logo { + width: 70px; + height: 70px; +} + +.logo-link { + position: absolute; + top: 0.5rem; + left: 1.5rem; +} + +.nav-right { + display: flex; + align-items: center; + gap: 0.5rem; + margin-right: 1rem; + position: absolute; + top: 2rem; + right: 10%; +} + +/* Style the notification button */ +.notification-btn { + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem 0.8rem; + border: 1px solid #E5E7EB; + border-radius: 1rem; + cursor: pointer; + transition: all 0.2s ease-in-out; + box-shadow: 0px 0px 10px #e3e8f2; + backdrop-filter: blur(8px); + background: white; + width: 50px; + height: 40px; +} + +/* Style the profile button */ +.profile-btn { + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem 0.8rem; + border: 1px solid #E5E7EB; + border-radius: 1rem; + color: black; + cursor: pointer; + transition: all 0.2s ease-in-out; + box-shadow: 0px 0px 10px #e3e8f2; + backdrop-filter: blur(8px); + background: white; + width: 50px; + height: 40px; +} + +.notification-btn:hover, +.profile-btn:hover { + background: #E5E7EB; +} + +/* Style the icons */ +.notification-btn svg, +.profile-btn svg { + width: 30px; + height: 18px; +} + +/* Style the filter button */ +.filter-btn { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.8rem; + border: 1px solid #E5E7EB; + border-radius: 1rem; + background: white; + color: #2F3C50; + font-size: 14px; + cursor: pointer; + font-weight: 600; + transition: all 0.2s ease-in-out; + box-shadow: 0px 0px 10px #e3e8f2; + backdrop-filter: blur(8px); + height: 40px; +} + +.filter-btn:hover { + background: #F3F4F6; +} + +.MuiTextField-root { + width: 300px !important; + height: 40px !important; + background: #F3F4F6; + border-radius: 50px; + box-shadow: 0px 0px 10px #e3e8f2; + backdrop-filter: blur(8px); +} + +.MuiTextField-root .MuiInputBase-root { + height: 50px !important; + padding: 0 8px !important; + background: white; +} + +.MuiTextField-root .MuiInputBase-input { + padding: 8px 4px !important; + font-size: 13px !important; +} + +.MuiTextField-root .MuiInputAdornment-root { + height: 40px !important; + margin-right: 4px !important; +} + +.MuiTextField-root .MuiInputAdornment-root .icon { + width: 18px !important; + height: 18px !important; + color: #2F3C50; +} + +.filter-btn .icon, +.notification-btn .icon, +.profile-btn .icon, +.search-input .icon { + width: 20px; + height: 20px; + color: #2F3C50; +} + +.dashboard-container { + padding: 16px; + margin-left: 65px; + max-width: 1400px; +} + +.welcome-section { + position: absolute; + left: 230px; + top: 15%; + display: flex; + align-items: center; +} + +.welcome-text { + font-weight: 300; + font-size: 25px; +} + +.user-name { + font-weight: bold; + font-size: 25px; +} + +.content-grid { + display: grid; + grid-template-columns: 1fr 1.2fr; + gap: 24px; + margin-top: 11%; + height: auto; +} + +.logbooks-card { + background: white; + border-radius: 20px; + padding: 24px; + height: 500px; + width: 100%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} + +.get-started-card { + background: white; + border-radius: 20px; + padding: 30px 50px; + height: 280px; + width: 95%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} + +.get-started-card p { + color: #3c4049; + font-weight: 400; + margin-top: 13px; + text-align: left; + font-size: 14px; + margin-bottom: 16px; +} + +.get-started-card h2 { + font-size: 20px; + font-weight: 600; + color:#2F3C50; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.card-header h2 { + font-size: 20px; + margin-bottom: 8px; + margin-left: 30px; + color:#2F3C50; +} + +h2 { + font-size: 20px; + text-align: left; + color:#2F3C50; +} + +/* Button stack container */ +.button-stack { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + margin: auto 0; /* This will push the button stack to the vertical center */ + height: 60%; + margin-left: auto; + margin-right: auto; +} + +/* Individual buttons */ +.secondary-button { + width: 100%; + padding: 12px; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: white; + color: #1a1a1a; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; +} + +/* Primary button (Create New Log) */ +.primary-button { + width: 10%; + padding: 12px; + border: none; + border-radius: 8px; + background: #35478C; + color: white; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; +} + +.secondary-button:hover { + background: #f5f5f5; +} + +.view-more-btn { + padding: 6px 12px; + border-radius: 20px; + border: 1px solid #9AB0E1; + background: #F7FAFF; + color: #4F607E; + font-size: 15px; + font-weight: bold; + cursor: pointer; + margin-right: 30px; +} + +.progress-list { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-left: auto; + margin-right: auto; + gap: 16px; + width: 80%; +} + +.progress-item { + width: 100%; + padding: 12px; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.2s ease; + background-color: transparent; /* Default transparent background */ +} + +.progress-item:hover { + background-color: #E7EDF8; +} + +.progress-info { + display: flex; + justify-content: space-between; + margin-bottom: 6px; + font-size: 13px; +} + +.progress-bar { + height: 6px; + background: #E7EDF8; + border-radius: 4px; + overflow: hidden; +} + +.progress-fill { + height: 100%; + background: #244B94; + border-radius: 4px; +} + +.progress-item:hover .progress-bar { + background: #FBFCFE; +} + +.logbooks-image { + width: 100%; + max-width: 280px; + margin: 20px auto; + display: block; +} + +/* Bottom section container */ +.bottom-section { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 30px; + margin-top: 10px; + width: 95%; + grid-column: 1; + height: calc(500px - 280px - 24px); +} + +/* Shop Log Books card */ +.shop-books-card { + background: linear-gradient(232.43deg, #6C8BD3 9.4%, #244B94 90.17%); + border-radius: 30px; + padding: 20px; + color: white; + display: flex; + justify-content: space-between; + cursor: pointer; + height: 100%; + position: relative; + overflow: hidden; /* Important for containing the gradient and images */ + height: calc(500px - 280px - 24px); + transition: transform 0.2s ease; +} + +.shop-books-card:hover { + transform: translateY(-2px); /* Slight lift effect on hover */ +} + +.shop-books-card::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient( + circle at bottom, + rgba(255, 255, 255, 0) 30%, + rgba(255, 255, 255, 0.2) 100% + ); + pointer-events: none; +} + +.shop-books-card .chevron-icon { + width: 20px; /* Reduced from 20px */ + height: 20px; + color: white; /* Adjust color as needed */ + margin-top: 4px; +} + +.shop-books-content h3 { + font-weight: 600; + font-size: 17px; +} + +.shop-books-image { + position: absolute; + top: 40%; + right: 1px; + left: 1px; + width: 250px; /* Adjust size as needed */ + height: auto; + object-fit: contain; + z-index: 1; +} + +/* Recent Activity card */ +.recent-activity-card { + background: white; + border-radius: 30px; + padding: 20px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + height: calc(500px - 280px - 24px); + transition: transform 0.2s ease; +} + +.recent-activity-card:hover { + transform: translateY(-2px); +} + +.activity-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.activity-header .chevron-icon { + width: 20px; /* Reduced from 20px */ + height: 20px; + color: black; /* Adjust color as needed */ +} + +.activity-header h3 { + font-weight: 600; + font-size: 17px; + color:#2F3C50; +} + +.activity-list { + display: flex; + flex-direction: column; +} + +.activity-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 0; + margin-top: 5px; + border-bottom: 1px solid #f0f0f0; +} + +.activity-info { + display: flex; + gap: 3px; + color: #666; + font-size: 10px; +} + +.activity-info h2 { + font-weight: 500; + font-size: 10px; + color:#2F3C50; + opacity: 0.7; +} + +.activity-info h3 { + font-weight: 700; + font-size: 10px; + color:#2E4A8F; +} + +.activity-time { + margin-left: 17px; +} + +.activity-time h3 { + font-weight: 400; + font-size: 10px; + color: #A1B4DE; +} + +.time-icon { + color: #92a4cb; + width: 12px; + height: 12px; } \ No newline at end of file diff --git a/frontend/src/pages/styles/LogCode.css b/frontend/src/pages/styles/LogCode.css new file mode 100644 index 00000000..19b4b7ec --- /dev/null +++ b/frontend/src/pages/styles/LogCode.css @@ -0,0 +1,222 @@ +.logcode-page { + width: 100%; + min-height: 100vh; +} + +.logcode-page .container { + display: flex; + width: 100%; + min-height: 100vh; +} + +.form-description { + font-size: 1.2rem; + text-align: center; + color: #1d57b6; + font-weight: bold !important; +} + +/* Form Container - Left Side */ +.logcode-page .form-container { + width: 50%; + display: flex; + align-items: center; + justify-content: center; + background-color: white; + padding: 40px; + position: fixed; + left: 0; + height: 100%; +} + +.logcode-page form { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0 50px; + text-align: center; + width: 100%; + max-width: 480px; +} + +/* Overlay Container - Right Side */ +.logcode-page .overlay-container { + position: fixed; + top: 0; + left: 50%; + width: 50%; + height: 100%; + overflow: hidden; + z-index: 100; + background: #0B234A; +} + +.logcode-page .overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #0B234A; + background: -webkit-linear-gradient(180deg, #0B234A 0%, #162A5B 100%); + background: linear-gradient(35deg, #1d57b6 0%, #070e1e 100%); + background-repeat: no-repeat; + background-size: cover; + background-position: 0 0; + color: #FFFFFF; +} + +.logcode-page .overlay-panel { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0 40px; + text-align: center; + top: 0; + height: 100%; + width: 100%; + padding-top: 50px; +} + +.logcode-page .overlay-panel img { + width: 300px; + height: auto; +} + +/* Rest of your styles remain the same */ +.logcode-page h1 { + font-weight: bold; + margin: 0; + font-size: 2.5rem; + color: #000; + margin-bottom: 10px; +} + +.logcode-page h2 { + font-size: 1.1rem; + color: #4B5FD4; + margin-bottom: 30px; + font-weight: normal; +} + +.logcode-page .code-group { + width: 100%; + margin-bottom: 15px; +} + +.logcode-page label { + text-align: left; + display: block; + margin-bottom: 8px; + font-size: 0.9rem; + color: #333; +} + +.logcode-page .terms-group { + width: 100%; + margin: 15px 0; + text-align: left; +} + +.logcode-page .custom-checkbox-container { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; +} + +.logcode-page .custom-checkbox { + width: 18px; + height: 18px; + cursor: pointer; +} + +.logcode-page .terms-text { + font-size: 14px; + line-height: 1.4; +} + +.logcode-page .terms-text a { + color: #4B5FD4; + text-decoration: none; +} + +.logcode-page .help-text { + text-align: right; + width: 100%; +} + +.logcode-page .help-text a { + color: #6B7280; + text-decoration: none; + font-size: 0.9rem; +} + +.logcode-page .help-text a:hover { + color: #1d57b6; +} + +.logcode-page button { + border-radius: 50px; + background: linear-gradient(35deg, #1d57b6 0%, #070e1e 100%); + color: #FFFFFF; + font-size: 12px; + font-weight: bold; + padding: 12px 45px; + letter-spacing: 1px; + text-transform: uppercase; + transition: transform 80ms ease-in; + width: 100%; + margin-top: 15px; + border: none; +} + +.logcode-page button:active { + transform: scale(0.95); +} + +.logcode-page button:focus { + outline: none; +} + +/* TextField styling */ +.logcode-page .MuiTextField-root { + width: 100% !important; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-root { + border-radius: 50px; + background-color: #F8F9FA; + height: 48px; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-input { + color: #6B7280; + padding: 12px 18px; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-input::placeholder { + color: #9CA3AF; + opacity: 0.8; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-notchedOutline { + border-radius: 50px; + border: 1px solid #E5E7EB; +} + +.logcode-page .MuiTextField-root .MuiInputAdornment-root .MuiSvgIcon-root { + color: #9CA3AF; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline { + border-color: #E5E7EB; +} + +.logcode-page .MuiTextField-root .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline { + border-color: #E5E7EB; + border-width: 1px; +} diff --git a/frontend/src/pages/styles/Login.css b/frontend/src/pages/styles/Login.css new file mode 100644 index 00000000..ba48b070 --- /dev/null +++ b/frontend/src/pages/styles/Login.css @@ -0,0 +1,387 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, body { + background-color: #FFFFFF; /* White background */ + margin: 0; /* Remove any default margin */ + padding: 0; /* Remove any default padding */ + height: 100%; /* Ensure it covers the full page */ + width: 100%; + } + +h1 { + font-weight: bold; + margin: 0; + color: black; +} + +h2 { + font-size: 1.2rem; + text-align: center; + color: #3f51b5; +} + +p { + font-size: 14px; + font-weight: 100; + line-height: 20px; + letter-spacing: 0.5px; + margin: 20px 0 30px; + color: black; +} + +span { + color: black; + font-size: 1rem; +} + +a { + color: #333; + font-size: 14px; + text-decoration: none; + margin: 15px 0; +} + +form button[type="submit"] { + border-radius: 20px; + border: 1px solid #0B234A; + background: #16448f; + color: #FFFFFF; + font-size: 15px; + font-weight: bold; + padding: 12px 45px; + letter-spacing: 1px; + text-transform: uppercase; + transition: transform 80ms ease-in; + width: 400px; + height: 55px; +} + +form button[type="submit"]:active { + transform: scale(0.95); +} + +form button[type="submit"]:focus { + outline: none; +} + +form button[type="submit"].ghost { + background-color: transparent; + border-color: #FFFFFF; +} + +form { + background-color: #FFFFFF; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0 50px; + height: 100%; + text-align: center; +} + +input { + background-color: #eee; + border: none; + padding: 12px 15px; + margin: 8px 0; + width: 100%; +} + +.container { + background-color: #fff; + overflow: hidden; + margin: 0; + width: 1280px; + height: 931px; +} + +.form-container { + position: absolute; + top: 0; + height: 100%; + transition: all 0.7s ease-in-out; +} + +.form-container h2 { + color: #244B94; +} + +.sign-in-container { + left: 50%; + width: 50%; + z-index: 2; +} + +.container.right-panel-active .sign-in-container { + transform: translateX(-100%); +} + +.sign-up-container { + left: 50%; + width: 50%; + opacity: 0; + z-index: 1; +} + +.container.right-panel-active .sign-up-container { + transform: translateX(-100%); + opacity: 1; + z-index: 5; + animation: show 0.7s; +} + +@keyframes show { + 0%, 49.99% { + opacity: 0; + z-index: 1; + } + + 50%, 100% { + opacity: 1; + z-index: 5; + } +} + +.overlay-container { + position: absolute; + top: 0; + left: 0; + width: 50%; + height: 100%; + overflow: hidden; + transition: transform 0.6s ease-in-out; + z-index: 100; +} + +.container.right-panel-active .overlay-container { + transform: translateX(100%); +} + +.overlay { + background: #0B234A; /* Fallback solid color */ + background: -webkit-linear-gradient(180deg, #0B234A 0%, #162A5B 100%); /* For Chrome and Safari */ + background: linear-gradient(35deg, #1d57b6 0%, #070e1e 100%); /* Standard syntax */ + background-repeat: no-repeat; + background-size: cover; + background-position: 0 0; + color: #FFFFFF; + position: relative; + left: -100%; + height: 100%; + width: 200%; + transform: translateX(0); + transition: transform 0.6s ease-in-out; +} + + +.container.right-panel-active .overlay { + transform: translateX(50%); +} + +.overlay-panel { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0 40px; + text-align: center; + top: 0; + height: 100%; + width: 50%; + transform: translateX(0); + transition: transform 0.6s ease-in-out; + padding-top: 50px; +} + +.overlay-left { + transform: translateX(-20%); +} + +.container.right-panel-active .overlay-left { + transform: translateX(0); +} + +.overlay-right { + right: 0; + transform: translateX(0); +} + +.container.right-panel-active .overlay-right { + transform: translateX(20%); +} + +.social-container { + margin: 20px 0; +} + +.username-group { + margin-top: 3rem; + display: flex; + flex-direction: column; + } + + label { + font-size: 1.1rem; + color: #333; + margin-bottom: 0.3rem; + align-self: flex-start; +} + +.username-group .MuiTextField-root { + width: 400px !important; +} + + label { + font-size: 0.9rem; + color: #333; + margin-bottom: 0.3rem; + } + + .password-group .MuiTextField-root { + width: 400px !important; +} + + .forgot-password { + display: flex; + justify-content: flex-end; + margin-bottom: 1.5rem; + width: 400px; +} + +.forgot-password a { + color: #666; + text-decoration: none; + font-size: 0.9rem; +} + +.forgot-password a:hover { + color: #000; +} + + .signup-link { + margin-top: 1rem; + text-align: center; + font-size: 0.9rem; + } + + .signup-link a { + font-size: 1rem; + color: #3f51b5; + text-decoration: none; + font-weight: bold; + } + + .signup-link a:hover { + text-decoration: underline; + } + + .overlay-panel img { + width: 450px !important; + margin-bottom: 2rem; +} + +.sign-up-container .username-group { + margin-top: 3rem; + display: flex; + flex-direction: column; +} + +.sign-up-container .password-group { + margin-top: 1.2rem; + display: flex; + flex-direction: column; +} + +.password-group { + margin-top: 1.2rem; + display: flex; + flex-direction: column; +} + +.sign-up-container .email-group { + margin-top: 1.2rem; + display: flex; + flex-direction: column; + width: 400px; +} + +.email-group .MuiTextField-root { + width: 400px !important; +} + +.logo-container { + position: absolute; + top: 2rem; + left: 50%; + transform: translateX(-50%); + z-index: 101; +} + +.logo-container img { + width: 250px; +} + +/* TextField Container Styling */ +.MuiTextField-root { + width: 400px !important; +} + +/* Main TextField Styling */ +.MuiTextField-root .MuiOutlinedInput-root { + border-radius: 50px; + background-color: #fff; +} + +/* Input Field Styling */ +.MuiTextField-root .MuiOutlinedInput-input { + color: #6B7280; + padding: 15px 5px; +} + +/* Placeholder Text */ +.MuiTextField-root .MuiOutlinedInput-input::placeholder { + color: #9CA3AF; + opacity: 0.8; +} + +/* Border Styling */ +.MuiTextField-root .MuiOutlinedInput-notchedOutline { + border-radius: 20px; + border: 1px solid #E5E7EB; +} + +/* Focus State */ +.MuiTextField-root .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline { + border-color: #E5E7EB; + border-width: 1px; +} + +/* Icon Styling */ +.MuiTextField-root .MuiInputAdornment-root .MuiSvgIcon-root { + color: #9CA3AF; + font-size: 1.4rem;; +} + +.confirm-password-group { + margin-top: 1.2rem; + margin-bottom: 3rem; + display: flex; + flex-direction: column; +} + +.confirm-password-group .MuiTextField-root { + width: 400px !important; +} + +/* Label Styling */ +label { + color: #6B7280; + font-size: 0.9rem; + margin-bottom: 0.3rem; +} \ No newline at end of file diff --git a/frontend/src/utils/ProtectedRoutes.jsx b/frontend/src/utils/ProtectedRoutes.jsx index 78eecd6f..c48f7a1b 100644 --- a/frontend/src/utils/ProtectedRoutes.jsx +++ b/frontend/src/utils/ProtectedRoutes.jsx @@ -1,7 +1,7 @@ -import { Outlet, Navigate } from 'react-router-dom'; -import { useAuth } from '../contexts/AuthContext'; +import { Outlet, Navigate } from "react-router-dom"; +import { useAuth } from "../contexts/AuthContext"; export const ProtectedRoutes = () => { const { session } = useAuth(); - return session ? : ; -} \ No newline at end of file + return session ? : ; +};