-
-
-
+
+
+
+
+
+ Showing {startRange}-{endRange} of{" "}
+ {logs.length} logs
+
-
+
);
-};
-
-export default LogHistory;
+}
diff --git a/frontend/src/pages/logbooks/Logbooks.css b/frontend/src/pages/logbooks/Logbooks.css
new file mode 100644
index 00000000..7d0fb5bf
--- /dev/null
+++ b/frontend/src/pages/logbooks/Logbooks.css
@@ -0,0 +1,14 @@
+/* Container Styles */
+.logbooks-container {
+ padding: 16px;
+ margin-left: 65px;
+ width: 90%;
+}
+
+.logbooks-grid {
+ margin-top: 10%;
+ height: auto;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 100px;
+}
diff --git a/frontend/src/pages/logbooks/Logbooks.jsx b/frontend/src/pages/logbooks/Logbooks.jsx
new file mode 100644
index 00000000..92f17d65
--- /dev/null
+++ b/frontend/src/pages/logbooks/Logbooks.jsx
@@ -0,0 +1,56 @@
+import { NavContentWrapper } from "../../components/NavContentWrapper/NavContentWrapper";
+import ContentHeader from "../../components/ContentHeader/ContentHeader";
+import LogbookCard from "../../components/Logbooks/LogbookCard";
+import AddLogbookCard from "../../components/Logbooks/AddLogbookCard";
+import "./Logbooks.css";
+
+/** Array of logbook data */
+const logbooks = [
+ {
+ title: "Cardiac Surgery - Nov.",
+ type: "Cardiac Surgery - Adult",
+ storage: "20",
+ created: "10-01-2024",
+ },
+ {
+ title: "Cardiac Cong. - Nov.",
+ type: "Cardiac Surgery - Congenital",
+ storage: "20",
+ created: "10-01-2024",
+ },
+ {
+ title: "Ophthalmology - Nov.",
+ type: "Ophthalmology",
+ storage: "20",
+ created: "10-01-2024",
+ },
+ {
+ title: "OB/GYN - Nov.",
+ type: "Obstetrics/Gynecology",
+ storage: "20",
+ created: "10-01-2024",
+ },
+ {
+ title: "General Surgery - Nov.",
+ type: "General Surgery",
+ storage: "20",
+ created: "10-01-2024",
+ },
+ // Add more logbooks as needed
+];
+
+export default function Logbooks() {
+ return (
+
+
+
+
+ {logbooks.map((book, index) => (
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/new_log/__tests__/NewLog.test.js b/frontend/src/pages/logbooks/__tests__/NewLog.test.js
similarity index 100%
rename from frontend/src/pages/new_log/__tests__/NewLog.test.js
rename to frontend/src/pages/logbooks/__tests__/NewLog.test.js
diff --git a/frontend/src/pages/login/Login.css b/frontend/src/pages/login/Login.css
new file mode 100644
index 00000000..1f528c89
--- /dev/null
+++ b/frontend/src/pages/login/Login.css
@@ -0,0 +1,435 @@
+/* General Styles */
+.signup-link span {
+ color: black;
+ font-size: 1rem;
+}
+
+form button[type="submit"] {
+ border-radius: 20px;
+ border: 1px solid #BAC1D0;
+ background: #16448f;
+ color: #F2F4F8;
+ 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: #F7FAFF;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ padding: 0 50px;
+ height: 100%;
+ text-align: center;
+}
+
+/* Input Styling */
+.sign-in-container input,
+.sign-up-container input,
+.name-group input {
+ background-color: #F7FAFF;
+ border: none;
+ padding: 12px 15px;
+ margin: 8px 0;
+ width: 100%;
+}
+
+.container {
+ background-color: #F7FAFF;
+ 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 h1 {
+ font-size: 2.5rem;
+ font-weight: bold;
+ margin: 0;
+ color: black;
+}
+
+.form-container h2 {
+ font-size: 1.2rem;
+ text-align: center;
+ color: #3f51b5;
+}
+
+.sign-in-container,
+.sign-up-container {
+ left: 50%;
+ width: 50%;
+ z-index: 2;
+}
+
+.sign-in-container h2,
+.sign-up-container h2 {
+ font-size: 1rem;
+ color: #244B94;
+ margin-top: 0;
+}
+
+.container.right-panel-active .sign-in-container {
+ transform: translateX(-100%);
+}
+
+.sign-up-container {
+ 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: linear-gradient(35deg, #1d57b6 0%, #070e1e 100%);
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: 0 0;
+ color: #F2F4F8;
+ 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: 50px 40px 0;
+ text-align: center;
+ top: 0;
+ height: 100%;
+ width: 50%;
+ transform: translateX(0);
+ transition: transform 0.6s ease-in-out;
+}
+
+.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,
+.password-group,
+.confirm-password-group {
+ margin-top: 0.7rem;
+ display: flex;
+ flex-direction: column;
+ width: 400px;
+}
+
+.email-group {
+ display: flex;
+ flex-direction: column;
+ width: 400px;
+}
+
+.confirm-password-group {
+ margin-bottom: 3rem;
+}
+
+.forgot-password {
+ display: flex;
+ justify-content: flex-end;
+ margin: 1rem 0 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;
+}
+
+.signup-link a {
+ font-size: 1rem;
+ color: #5D9EFF;
+ text-decoration: none;
+}
+
+.signup-link a:hover {
+ text-decoration: underline;
+}
+
+.overlay-panel img {
+ width: 450px !important;
+ margin-bottom: 2rem;
+}
+
+.logo-container {
+ position: absolute;
+ top: 2rem;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 101;
+}
+
+.logo-container img {
+ width: 250px;
+}
+
+/* TextField Container Styling */
+.form-container .MuiTextField-root {
+ width: 400px !important;
+}
+
+.institution-training-container .MuiTextField-root {
+ width: 100% !important;
+ height: 100% !important;
+}
+
+/* Main TextField Styling */
+.MuiTextField-root .MuiOutlinedInput-root {
+ border-radius: 50px;
+ background-color: #F7FAFF;
+}
+
+.MuiTextField-root .MuiOutlinedInput-input {
+ color: #6B7280;
+ padding: 10px 5px;
+ text-align: left;
+}
+
+.MuiTextField-root .MuiOutlinedInput-input::placeholder {
+ color: #C4C5C6;
+ opacity: 0.8;
+}
+
+.MuiTextField-root .MuiOutlinedInput-notchedOutline {
+ border-radius: 20px;
+ border: 1px solid #BAC1D0;
+}
+
+.MuiTextField-root .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline {
+ border-color: #BAC1D0;
+ border-width: 1px;
+}
+
+.MuiTextField-root .MuiInputAdornment-root .MuiSvgIcon-root {
+ color: #C4C5C6;
+ font-size: 1.4rem;
+}
+
+/* Name Group Styling */
+.name-group {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+ width: 400px;
+ margin-top: 1rem;
+}
+
+.name-group > div {
+ display: flex;
+ flex-direction: column;
+}
+
+.name-group input {
+ border-radius: 20px;
+ background-color: #F7FAFF;
+ color: #6B7280;
+ padding: 17px 20px;
+ border: 1px solid #BAC1D0;
+ width: 100%;
+ box-sizing: border-box;
+ font-size: 1rem;
+ text-align: left;
+}
+
+.name-group input::placeholder {
+ color: #C4C5C6;
+ opacity: 0.8;
+}
+
+.name-group input:hover {
+ border-color: #000;
+}
+
+/* Label Styling */
+.form-container label {
+ color: #4F607E;
+ font-size: 0.9rem;
+ margin-bottom: 0.3rem;
+ align-self: flex-start;
+ text-align: left;
+}
+
+.institution-training-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+ width: 400px;
+ margin: 1rem 0 2rem;
+}
+
+.institution-training-container > div {
+ display: flex;
+ flex-direction: column;
+}
+
+.institution-training-container .MuiOutlinedInput-input {
+ color: #6B7280;
+ padding: 7px 20px;
+ text-align: left;
+}
+
+/* Custom Select Styling */
+.institution-training-container .custom-select-container {
+ position: relative;
+ height: 100%;
+}
+
+.custom-select {
+ height: 70%;
+ padding-left: 20px;
+ padding-top: 14px;
+ border-radius: 20px;
+ background-color: #F7FAFF;
+ border: 1px solid #BAC1D0;
+ color: #C4C5C6;
+ cursor: pointer;
+ appearance: none;
+ text-align: left;
+}
+
+.custom-select:hover {
+ border-color: #000;
+}
+
+.custom-select-arrow {
+ position: absolute;
+ left: 85%;
+ top: 57%;
+ transform: translateY(-50%);
+ pointer-events: none;
+}
+
+.custom-select-options {
+ position: absolute;
+ left: 0;
+ right: 0;
+ background: white;
+ border: 1px solid #BAC1D0;
+ border-radius: 20px;
+ max-height: 200px;
+ width: 100%;
+ overflow-y: auto;
+ z-index: 1000;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ display: none;
+}
+
+.custom-select-options.open {
+ display: block;
+}
+
+.custom-select-option {
+ padding: 12px 20px;
+ cursor: pointer;
+ color: #6B7280;
+}
+
+.custom-select-option:hover {
+ background-color: #F2F4F8;
+}
+
+.custom-select-arrow svg {
+ width: 17px;
+ height: 17px;
+}
+
+.custom-select[data-empty="false"] {
+ color: #6B7280;
+}
diff --git a/frontend/src/pages/login/Login.jsx b/frontend/src/pages/login/Login.jsx
index ff249a1a..46a09f56 100644
--- a/frontend/src/pages/login/Login.jsx
+++ b/frontend/src/pages/login/Login.jsx
@@ -1,63 +1,373 @@
-import { Link } from "react-router-dom";
-import { useState } from "react";
+import { useState, useEffect, useRef } 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 "./Login.css";
+import { CLButtonPrimary } from "../../components/Buttons/CLButtons";
+import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
-export default function Login() {
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
+/** Reusable Password Field Component */
+const PasswordField = ({
+ id,
+ placeholder,
+ value,
+ onChange,
+ showPassword,
+ toggleShowPassword,
+}) => (
+
+
+
+ ),
+ endAdornment: (
+
+
+ {showPassword ? : }
+
+
+ ),
+ }}
+ required
+ />
+);
+
+const Login = () => {
+ /** State variables for sign-in form */
+ const [loginEmail, setLoginEmail] = useState("");
+ const [loginPassword, setLoginPassword] = useState("");
+ const [loginShowPassword, setLoginShowPassword] = useState(false);
+
+ /** State variables for sign-up form */
+ const [signupEmail, setSignupEmail] = useState("");
+ const [signupPassword, setSignupPassword] = useState("");
+ const [signupShowPassword, setSignupShowPassword] = useState(false);
+ const [firstName, setFirstName] = useState("");
+ const [lastName, setLastName] = useState("");
+ const [institution, setInstitution] = useState("");
+ const [stage, setStage] = useState("");
+
+ /** General state variables */
+ const [isRightPanelActive, setIsRightPanelActive] = useState(false);
const [loading, setLoading] = useState(false);
+ const [isSelectOpen, setIsSelectOpen] = useState(false);
+
const navigate = useNavigate();
- const { session, login } = useAuth();
+ const { session, login, register } = useAuth();
+ const selectRef = useRef(null);
+ /** Navigate to home if session exists */
useEffect(() => {
if (session) {
- navigate("/homepage");
+ navigate("/home");
}
}, [session, navigate]);
- async function handleSubmit(e) {
+ /** Handle click outside of custom select to close it */
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (selectRef.current && !selectRef.current.contains(event.target)) {
+ setIsSelectOpen(false);
+ }
+ };
+
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, []);
+
+ /** Sign-up form submission handler */
+ const handleSignUp = async (e) => {
e.preventDefault();
+ if (!checkValidEmail(signupEmail)) {
+ return alert("Please enter a valid email");
+ }
+
+ try {
+ setLoading(true);
+ await register(
+ firstName,
+ lastName,
+ signupEmail,
+ signupPassword,
+ institution,
+ stage
+ );
+ navigate("/logcode");
+ } 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);
+ }
+ };
+
+ /** Sign-in form submission handler */
+ const handleSignIn = async (e) => {
+ e.preventDefault();
try {
setLoading(true);
- await login(email, password);
- navigate("/homepage");
+ await login(loginEmail, loginPassword);
+ navigate("/home");
} catch {
alert("Failed to login: Email or Password Incorrect");
+ } finally {
+ setLoading(false);
}
- setLoading(false);
+ };
+
+ /** Email validation function */
+ function checkValidEmail(email) {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ return emailRegex.test(email);
}
return (
-
Login to Your Account
-
-
Don't have an Account? Register
+
+ {/* Sign Up Form */}
+
+
+ {/* Sign In Form */}
+
+
+ {/* Overlay Panels */}
+
+
+
+
+
+
+
+
+
+
+
);
-}
+};
+
+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/new_log/NewLog.css b/frontend/src/pages/new_log/NewLog.css
deleted file mode 100644
index 12708c0b..00000000
--- a/frontend/src/pages/new_log/NewLog.css
+++ /dev/null
@@ -1,20 +0,0 @@
-.cta-section {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- margin-left: 64px;
- margin-right: 64px;
- margin-top: 200px;
-}
-
-.buttons-container {
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-
-.add-icon {
- margin-right: 9px;
- vertical-align: -6px;
-}
\ No newline at end of file
diff --git a/frontend/src/pages/new_log/NewLog.jsx b/frontend/src/pages/new_log/NewLog.jsx
deleted file mode 100644
index 1f07f767..00000000
--- a/frontend/src/pages/new_log/NewLog.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { useNavigate } from "react-router-dom";
-import { NavContentWrapper } from "../../components/NavContentWrapper/NavContentWrapper";
-import ImageIcon from "@mui/icons-material/Image";
-import ModeIcon from "@mui/icons-material/Mode";
-import { CLButtonPrimary, CLButtonSecondary } from "../../components/Buttons/CLButtons";
-import "./NewLog.css";
-
-export default function NewLog() {
- return (
-
-
-
- );
-}
-
-function MainContent() {
- const navigate = useNavigate();
-
- const handleUploadPhoto = () => {
- navigate("/uploadPhotos");
- };
-
- const handleEnterManually = () => {
- navigate("/manualEdit");
- };
-
- return (
-
-
How would you like to create a new log?
-
-
-
- Upload Photo
-
-
-
- Enter Manually
-
-
-
- );
-}
diff --git a/frontend/src/pages/sign_up/SignUp.jsx b/frontend/src/pages/sign_up/SignUp.jsx
deleted file mode 100644
index 1dac43a7..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("/homepage");
- }
- }, [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("/homepage");
- } 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
-
- 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/upload_photo/UploadPhoto.css b/frontend/src/pages/upload_photo/UploadPhoto.css
index 29bf172f..1cb6e6af 100644
--- a/frontend/src/pages/upload_photo/UploadPhoto.css
+++ b/frontend/src/pages/upload_photo/UploadPhoto.css
@@ -1,107 +1,62 @@
-.nav-icon-left {
- margin-right: 3px;
- margin-left: -2px;
- vertical-align: -6px;
-}
-
-.nav-icon-right {
- vertical-align: -6px;
- margin-left: 10px;
- margin-right: -10px;
-}
-
-.upload-photos-container {
+/* Container */
+.upload-container {
+ background: transparent;
+ border-radius: 8px;
+ margin-top: 9%;
+ margin-left: 6%;
+ width: 90%;
+ }
+
+ /* Upload Controls */
+ .upload-controls {
display: flex;
- height: 100vh;
- width: 100vw;
- box-sizing: border-box;
- padding-left: 20px;
- margin-top: -40px;
-}
-
-.upload-box {
- flex: 1;
- max-width: 55vw;
- padding: 40px;
- border-right: 1px solid #555;
- display: flex;
- flex-direction: column;
-}
-
-.back-button {
- position: absolute;
- top: 20px;
- left: 20px;
- font-size: 1.2rem;
-}
-
-.navigation-buttons {
- display: flex;
- justify-content: space-between;
- margin-top: 0;
- margin-left: 80px;
- margin-right: 80px;
- font-size: 1.1rem;
-}
-
-.sidebar {
- width: 20%;
- display: flex;
- flex-direction: column;
align-items: center;
- gap: 0.5rem;
- height: 100vh;
- border-right: 1px solid #e5e7eb;
-}
-
-.nav-icon-left {
- margin-right: 3px;
- margin-left: -2px;
- vertical-align: -6px;
-}
-
-.nav-icon-right {
- vertical-align: -6px;
- margin-left: 10px;
- margin-right: -10px;
-}
-
-.upload-photos-container {
+ justify-content: center;
+ gap: 5rem;
+ margin-top: 2rem;
+ margin-right: 8%;
+ }
+
+ .control-button {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ border: none;
display: flex;
- height: 100vh;
- width: 100vw;
- box-sizing: border-box;
- padding-left: 20px;
- margin-top: -40px;
-}
-
-.upload-box {
- flex: 1;
- max-width: 55vw;
- padding: 40px;
- border-right: 1px solid #555;
- display: flex;
- flex-direction: column;
-}
-
-.back-button {
- position: absolute;
- top: 20px;
- left: 20px;
- font-size: 1.2rem;
-}
-
-.navigation-buttons {
- display: flex;
- justify-content: space-between;
- margin-top: 0;
- margin-left: 80px;
- margin-right: 80px;
- font-size: 1.1rem;
-}
-
-.preview-content {
- flex-grow: 1;
- margin-bottom: 50px;
- min-width: 0;
-}
\ No newline at end of file
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: background-color 0.2s;
+ }
+
+ .control-button.next {
+ background-color: #244B94;
+ }
+
+ .control-button.prev {
+ background-color: #868686;
+ }
+
+ .control-button .control-icon {
+ width: 20px;
+ height: 20px;
+ color: white;
+ }
+
+ /* Page Indicator */
+ .page-indicator {
+ font-size: 1rem;
+ color: #333333;
+ }
+
+ .page-indicator .current-page {
+ color: #64B2F6;
+ }
+
+ /* Fixed Transcribe Button */
+ .fixed-transcribe-button,
+ .transcribe-button-container {
+ position: fixed;
+ bottom: 32px;
+ right: 32px;
+ }
\ No newline at end of file
diff --git a/frontend/src/pages/upload_photo/UploadPhoto.jsx b/frontend/src/pages/upload_photo/UploadPhoto.jsx
index c3c0b2ca..24aae33e 100644
--- a/frontend/src/pages/upload_photo/UploadPhoto.jsx
+++ b/frontend/src/pages/upload_photo/UploadPhoto.jsx
@@ -1,71 +1,95 @@
-import { useState } from "react";
-import ArrowBackIcon from "@mui/icons-material/ArrowBack";
+import { useState, useEffect } from "react";
+import { NavContentWrapper } from "../../components/NavContentWrapper/NavContentWrapper";
+import ContentHeader from "../../components/ContentHeader/ContentHeader";
+import "./UploadPhoto.css";
import { useNavigate } from "react-router-dom";
-import UploadArea from "../../components/UploadPhoto/UploadArea";
import PreviewSection from "../../components/UploadPhoto/PreviewSection";
-import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
-import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos";
-import "./UploadPhoto.css";
+import UploadArea from "../../components/UploadPhoto/UploadArea";
+import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/solid";
-export default function UploadPhotos() {
- const [imageFiles, setImageFiles] = useState([]);
- const [isEditMode, setIsEditMode] = useState(false);
+export default function UploadPhoto() {
const navigate = useNavigate();
- const handleFileUpload = (file) => {
- if (file && file.type.startsWith("image/")) {
- const reader = new FileReader();
- reader.onload = function (e) {
- setImageFiles([
- ...imageFiles,
- { name: file.name, url: e.target.result },
- ]);
- };
- reader.readAsDataURL(file);
- } else {
- alert("Please upload a valid image file.");
- }
+ const handleTranscribe = () => {
+ navigate("/load-transcription");
};
- const handleRemoveImage = (index) => {
- const updatedImages = imageFiles.filter((_, i) => i !== index);
- setImageFiles(updatedImages);
- };
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+}
- const toggleEditMode = () => {
- setIsEditMode(!isEditMode);
+function MainContent({ handleTranscribe }) {
+ const [files, setFiles] = useState([]);
+ const [showPreview, setShowPreview] = useState(false);
+
+ /** Allowed file types */
+ const ALLOWED_FILE_TYPES = ["image/png", "image/jpeg"];
+
+ /** Handle files from input or drop */
+ const handleFiles = (newFiles) => {
+ const filesWithPreview = newFiles.map((file) => ({
+ ...file,
+ timestamp: Date.now(),
+ preview: URL.createObjectURL(file),
+ }));
+ setFiles((prev) => [...filesWithPreview, ...prev]); // Add new files to beginning
};
- const handleBack = () => {
- navigate("/newLog");
+ /** Toggle preview visibility */
+ const handlePreviewClick = () => {
+ setShowPreview((prev) => !prev);
};
+ /** Clean up object URLs when component unmounts or files change */
+ useEffect(() => {
+ return () => {
+ files.forEach((fileData) => {
+ if (fileData.preview) {
+ URL.revokeObjectURL(fileData.preview);
+ }
+ });
+ };
+ }, [files]);
+
return (
-
-
-
-
Upload Photos
-
-
-
-
-
-
+
+
-
+ )}
+
+
+
+
+
+
+ 1/1
+
+
+
);
}