Date: Sat, 14 Jun 2025 00:16:01 -0700
Subject: [PATCH 32/33] README reality env example updates
---
README.md | 12 ++++++------
backend/.env.example | 5 +++--
backend/README.md | 9 +++------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index 9f3a4cf..8e27d50 100644
--- a/README.md
+++ b/README.md
@@ -18,28 +18,28 @@ EmailEssence is a sophisticated email management solution that leverages artific
### Feature Complete (FC) Features
- 🎨 Customizable dashboard with modular components
- 🔍 Advanced keyword analysis and topic identification
-- 💻 Cross-platform desktop support via Electron
- 🔄 Incremental email fetching for large inboxes
- 🎯 Smart email prioritization
- 🛠️ Enhanced user preferences and settings
+### Future Features
+- 💻 Cross-platform desktop support via Electron
+
## Technical Stack
### Frontend
- React - Modern UI framework
-- Remix - Full-stack web framework
-- Electron - Desktop application framework
-- JavaScript - Type-safe development
+- Vite - Frontend tooling and build server
+- JavaScript - Core language for the frontend
### Backend
- Python - Core backend services
- FastAPI - High-performance API framework
- MongoDB - Flexible document database
- Redis - High-performance caching
-- OpenRouter - AI-powered email processing
+- Flexible AI provider support (OpenAI, Google, OpenRouter)
### Infrastructure
-- Express.js - Web server and middleware
- OAuth 2.0 - Secure authentication
- IMAP - Email protocol support
diff --git a/backend/.env.example b/backend/.env.example
index b1fbbe4..2459087 100644
--- a/backend/.env.example
+++ b/backend/.env.example
@@ -9,9 +9,10 @@ GOOGLE_CLIENT_SECRET=google_client_secret
MONGO_URI=mongodb+srv://:@emailsummarization.1coye.mongodb.net/?retryWrites=true&w=majority&appName=EmailSummarization
# API keys
-OPENAI_API_KEY=openai_api_key
+OPEN_ROUTER_API_KEY=openrouter_api_key
+#OPENAI_API_KEY=openai_api_key
#DEEPSEEK_API_KEY=deepseek_api_key
-GOOGLE_API_KEY=google_api_key
+#GOOGLE_API_KEY=google_api_key
# Summarizer Settings
# SUMMARIZER_PROVIDER=openai
diff --git a/backend/README.md b/backend/README.md
index 2751cd2..175c5d7 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -23,9 +23,9 @@ For local development without Docker, use one of the provided setup scripts:
#### On Windows:
-```bash
+```ps1
# Run the setup script to create a virtual environment and install dependencies
-.\setup.bat
+.\\setup.ps1
```
These scripts will:
@@ -134,7 +134,7 @@ For Render deployments, environment variables are configured through the Render
- `google_client_secret`
- `email_account`
- `mongo_uri`
- - `openai_api_key`
+ - `openrouter_api_key`
- Any optional variables you wish to override
This separates your development environment configuration from your production deployment, following security best practices.
@@ -152,9 +152,6 @@ For CI/CD environments, use the CI setup scripts:
```bash
# Unix/Linux/macOS
./setup-ci.sh
-
-# Windows
-.\setup-ci.bat
```
## Troubleshooting
From a506d9326874fba828261fd817b85044f0765087 Mon Sep 17 00:00:00 2001
From: emmamelkumian <147114444+emmamelkumian@users.noreply.github.com>
Date: Sat, 14 Jun 2025 00:26:35 -0700
Subject: [PATCH 33/33] Comments (#133)
* settings JSDOC comments
* contact comments
* comments for loading
* comments for privacy and terms
* error and home comments
* settings and home css sectioning
* main comments and sectioning
* router
* client JSDoc
* reducer JSDOC
* Dashboard JSDOCS
* miniview JSDOCS
* auth JSDOCs
* email.jsx JSDOCs
* emailDisplay JSDOCs
* inbox JSDOCs
---
frontend/src/authentication/authenticate.js | 36 ++++++-
frontend/src/components/client/client.jsx | 31 ++++++
.../components/client/dashboard/dashboard.jsx | 31 +++++-
.../components/client/dashboard/miniview.jsx | 44 +++++++++
.../src/components/client/inbox/Email.jsx | 6 ++
.../components/client/inbox/emailDisplay.jsx | 37 ++++++-
.../src/components/client/inbox/inbox.jsx | 60 +++++++++--
frontend/src/components/client/reducers.jsx | 21 ++++
.../components/client/settings/settings.css | 13 ++-
.../components/client/settings/settings.jsx | 99 +++++++++++++++----
frontend/src/components/login/Error.jsx | 3 +-
frontend/src/components/login/Home.css | 16 +--
frontend/src/components/login/Home.jsx | 1 +
frontend/src/components/login/Loading.jsx | 10 +-
frontend/src/components/login/contact.jsx | 4 +-
frontend/src/components/login/privacy.jsx | 4 +-
frontend/src/components/login/terms.jsx | 4 +-
frontend/src/components/router/Router.jsx | 10 ++
frontend/src/emails/emailHandler.js | 86 +++++++++++++++-
frontend/src/main.css | 12 +--
frontend/src/main.jsx | 5 +-
21 files changed, 474 insertions(+), 59 deletions(-)
diff --git a/frontend/src/authentication/authenticate.js b/frontend/src/authentication/authenticate.js
index 20e0b1e..d847d2b 100644
--- a/frontend/src/authentication/authenticate.js
+++ b/frontend/src/authentication/authenticate.js
@@ -1,11 +1,24 @@
import { baseUrl, retrieveUserData } from "../emails/emailHandler";
+
+/**
+ * Initiates the OAuth authentication flow by redirecting to the backend login endpoint.
+ * Sets the redirect URI to the /loading route.
+ * @async
+ * @returns {void}
+ */
export const authenticate = async () => {
// Check for auth hash and render OAuthCallback if present
const redirect_uri = `${window.location.origin}/loading`;
window.location.href = `${baseUrl}/auth/login?redirect_uri=${redirect_uri}`;
};
-// When Reach loading component call this function
+/**
+ * Handles the OAuth callback after authentication.
+ * Parses the auth state from the URL hash, verifies authentication, and stores the token.
+ * Navigates to the error page if authentication fails.
+ * @async
+ * @returns {Promise}
+ */
export const handleOAuthCallback = async () => {
const hash = window.location.hash;
if (hash && hash.startsWith("#auth=")) {
@@ -30,6 +43,13 @@ export const handleOAuthCallback = async () => {
}
};
+/**
+ * Stores the authentication token and retrieves user data.
+ * Navigates to the error page if authentication fails.
+ * @async
+ * @param {string} token - The authentication token.
+ * @returns {Promise}
+ */
export const handleAuthenticate = async (token) => {
try {
localStorage.setItem("auth_token", token);
@@ -39,6 +59,14 @@ export const handleAuthenticate = async (token) => {
}
};
+
+/**
+ * Handles authentication errors by logging out, storing the error message,
+ * and redirecting to the error page.
+ * @async
+ * @param {Error|string} error - The error object or message.
+ * @returns {Promise}
+ */
const handleAuthError = async (error) => {
console.error("Auth flow error:", error);
localStorage.removeItem("auth_token");
@@ -46,6 +74,12 @@ const handleAuthError = async (error) => {
window.location.href = "/error"; // go to error page
};
+/**
+ * Checks the authentication status of the provided token by querying the backend.
+ * @async
+ * @param {string} token - The authentication token.
+ * @returns {Promise} True if authenticated, false otherwise.
+ */
export const checkAuthStatus = async (token) => {
const option = {
method: "GET",
diff --git a/frontend/src/components/client/client.jsx b/frontend/src/components/client/client.jsx
index 2003788..2c3e302 100644
--- a/frontend/src/components/client/client.jsx
+++ b/frontend/src/components/client/client.jsx
@@ -9,6 +9,14 @@ import { clientReducer, userPreferencesReducer } from "./reducers";
import { Settings } from "./settings/settings";
import SideBar from "./sidebar/sidebar";
+/**
+ * Main client component for authenticated user experience.
+ * Handles sidebar, routing, user preferences, and periodic email fetching.
+ * @param {Object} props
+ * @param {Array} props.emailsByDate - List of emails grouped by date.
+ * @param {Object} props.defaultUserPreferences - Default user preferences.
+ * @returns {JSX.Element}
+ */
function Client({
emailsByDate,
defaultUserPreferences = {
@@ -27,6 +35,10 @@ function Client({
defaultUserPreferences
);
+ /**
+ * Sets up an interval to fetch new emails based on user preference.
+ * @returns {void}
+ */
useEffect(() => {
const clock = setInterval(async () => {
try {
@@ -38,12 +50,14 @@ function Client({
return () => clearInterval(clock);
}, [userPreferences.emailFetchInterval]);
+ // Dynamically update sidebar width
const root = document.querySelector(":root");
root.style.setProperty(
"--sidebar-width",
`calc(${client.expandedSideBar ? "70px + 5vw" : "30px + 2vw"})`
);
+ /** Handles logo click to toggle sidebar expansion. */
const handleLogoClick = () => {
dispatchClient({
type: "logoClick",
@@ -51,6 +65,10 @@ function Client({
});
};
+ /**
+ * Handles navigation between client pages.
+ * @param {string} pageName - The page route to navigate to.
+ */
const handlePageChange = (pageName) => {
const toChange = import.meta.env.MODE === "test" ? "/client" : null;
if (toChange) {
@@ -60,6 +78,7 @@ function Client({
}
};
+ /** Toggles the summaries-in-inbox user preference. */
const handleToggleSummariesInInbox = () => {
dispatchUserPreferences({
type: "isChecked",
@@ -67,6 +86,10 @@ function Client({
});
};
+ /**
+ * Sets the email fetch interval user preference.
+ * @param {number} interval - Interval in seconds.
+ */
const handleSetEmailFetchInterval = (interval) => {
dispatchUserPreferences({
type: "emailFetchInterval",
@@ -74,6 +97,10 @@ function Client({
});
};
+ /**
+ * Sets the theme user preference.
+ * @param {string} theme - Theme name ("light", "system", "dark").
+ */
const handleSetTheme = (theme) => {
dispatchUserPreferences({
type: "theme",
@@ -81,6 +108,10 @@ function Client({
});
};
+ /**
+ * Sets the currently selected email.
+ * @param {Email} email - The email object to set as current.
+ */
const handleSetCurEmail = (email) => {
dispatchClient({
type: "emailChange",
diff --git a/frontend/src/components/client/dashboard/dashboard.jsx b/frontend/src/components/client/dashboard/dashboard.jsx
index b96b3e7..05744bc 100644
--- a/frontend/src/components/client/dashboard/dashboard.jsx
+++ b/frontend/src/components/client/dashboard/dashboard.jsx
@@ -1,9 +1,18 @@
+import PropTypes from "prop-types";
import ViewIcon from "../../../assets/ViewIcon";
import { getTop5 } from "../../../emails/emailHandler";
-import MiniViewPanel from "./miniview";
-import PropTypes from "prop-types";
import "./dashboard.css";
+import MiniViewPanel from "./miniview";
+/**
+ * Dashboard component for the client.
+ * Displays the weighted email list and the mini view panel.
+ * @param {Object} props
+ * @param {Array} props.emailList - List of emails.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @returns {JSX.Element}
+ */
function Dashboard({ emailList, handlePageChange, setCurEmail }) {
return (
@@ -21,6 +30,15 @@ function Dashboard({ emailList, handlePageChange, setCurEmail }) {
);
}
+/**
+ * Renders a list of the top 5 weighted emails.
+ * @const {JSX.Element} WEList - Returns an array of WEListEmail components for the top 5 emails.
+ * @param {Object} props
+ * @param {Array
} props.emailList - List of emails.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @returns {JSX.Element}
+ */
function WeightedEmailList({ emailList, setCurEmail, handlePageChange }) {
const emails = () => {
const WEList = getTop5(emailList);
@@ -40,6 +58,15 @@ function WeightedEmailList({ emailList, setCurEmail, handlePageChange }) {
return {emails()}
;
}
+/**
+ * Renders a single weighted email entry with summary and view icon.
+ * @const {JSX.Element} summary - Renders the summary for the email, or a loading placeholder if not available.
+ * @param {Object} props
+ * @param {Email} props.email - The email object.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @returns {JSX.Element}
+ */
function WEListEmail({ email, setCurEmail, handlePageChange }) {
const summary = () => {
let returnBlock;
diff --git a/frontend/src/components/client/dashboard/miniview.jsx b/frontend/src/components/client/dashboard/miniview.jsx
index 9e516a1..58ab40e 100644
--- a/frontend/src/components/client/dashboard/miniview.jsx
+++ b/frontend/src/components/client/dashboard/miniview.jsx
@@ -6,6 +6,15 @@ import InboxIcon from "../../../assets/InboxArrow";
import { emailsPerPage } from "../../../assets/constants";
import "./miniview.css";
+/**
+ * MiniViewPanel component for the client dashboard.
+ * Displays a list of emails in a compact view with an option to expand to the full inbox.
+ * @param {Object} props
+ * @param {Array} props.emailList - List of emails.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @returns {JSX.Element}
+ */
function MiniViewPanel({ emailList, handlePageChange, setCurEmail }) {
return (
@@ -19,6 +28,12 @@ function MiniViewPanel({ emailList, handlePageChange, setCurEmail }) {
);
}
+/**
+ * Renders the headfor the mini view
+ * @param {Object} props
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @returns {JSX.Element}
+ */
function MiniViewHead({ handlePageChange }) {
return (
@@ -39,6 +54,14 @@ function MiniViewHead({ handlePageChange }) {
);
}
+/**
+ * Displays a scrollable list of emails, loading more as the user scrolls.
+ * @param {Object} props
+ * @param {Array
} props.emailList - List of emails.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @returns {JSX.Element}
+ */
function MiniViewBody({ emailList, setCurEmail, handlePageChange }) {
const [pages, setPages] = useState(1);
const ref = useRef(null);
@@ -48,6 +71,10 @@ function MiniViewBody({ emailList, setCurEmail, handlePageChange }) {
: emailList.length;
const hasUnloadedEmails = maxEmails < emailList.length;
+
+ /**
+ * Handles the scroll event to load more emails when the user scrolls to the bottom.
+ */
const handleScroll = () => {
const fullyScrolled =
Math.abs(
@@ -64,6 +91,10 @@ function MiniViewBody({ emailList, setCurEmail, handlePageChange }) {
handleScroll();
}, [pages]); // Fixes minimum for large screens, but runs effect after every load which is unnecessary
+ /**
+ * Renders the list of MiniViewEmail components up to maxEmails.
+ * @returns {JSX.Element[]}
+ */
const emails = () => {
const returnBlock = [];
for (let i = 0; i < maxEmails; i++) {
@@ -85,6 +116,14 @@ function MiniViewBody({ emailList, setCurEmail, handlePageChange }) {
);
}
+/**
+ * Renders a single email entry in the mini view.
+ * @param {Object} props
+ * @param {Email} props.email - The email object.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @param {Function} props.handlePageChange - Function to change the client page.
+ * @returns {JSX.Element}
+ */
function MiniViewEmail({ email, setCurEmail, handlePageChange }) {
return (
{
return sender.slice(0, sender.indexOf("<"));
};
diff --git a/frontend/src/components/client/inbox/Email.jsx b/frontend/src/components/client/inbox/Email.jsx
index a0621b3..afcaf2c 100644
--- a/frontend/src/components/client/inbox/Email.jsx
+++ b/frontend/src/components/client/inbox/Email.jsx
@@ -1,5 +1,11 @@
import PropTypes from "prop-types";
+/**
+ * Renders the email body, using inner HTML if present.
+ * @param {Object} props
+ * @param {Email} props.email - The email object to display.
+ * @returns {JSX.Element}
+ */
export function Email({ email }) {
return (
<>
diff --git a/frontend/src/components/client/inbox/emailDisplay.jsx b/frontend/src/components/client/inbox/emailDisplay.jsx
index 146cf64..72c5823 100644
--- a/frontend/src/components/client/inbox/emailDisplay.jsx
+++ b/frontend/src/components/client/inbox/emailDisplay.jsx
@@ -3,10 +3,16 @@ import PropTypes from "prop-types";
import { useEffect, useState } from "react";
import ReactDom from "react-dom";
import ReaderViewIcon from "../../../assets/ReaderView";
-import Email from "./Email";
import { getReaderView } from "../../../emails/emailHandler";
+import Email from "./Email";
import "./emailDisplay.css";
+/**
+ * Displays the currently selected email with header, body, and reader view option.
+ * @param {Object} props
+ * @param {Email} props.curEmail - The currently selected email object.
+ * @returns {JSX.Element}
+ */
function EmailDisplay({
curEmail = {
user_id: 1,
@@ -40,10 +46,21 @@ function EmailDisplay({
);
}
+/**
+ * Fetches and displays a simplified, readable version of the email.
+ * @param {Object} props
+ * @param {Email} props.curEmail - The currently selected email object.
+ * @returns {JSX.Element}
+ */
function ReaderView({ curEmail }) {
const [text, setText] = useState("Loading ...");
const [displaying, setDisplaying] = useState(false);
+ /**
+ * Toggles the display of the reader view and fetches content if opening.
+ * @async
+ * @returns {Promise
}
+ */
async function displayReaderView() {
setDisplaying(!displaying);
if (!displaying) {
@@ -87,6 +104,14 @@ function ReaderView({ curEmail }) {
);
}
+/**
+ * Renders a modal overlay for displaying content or a loading spinner.
+ * @param {Object} props
+ * @param {boolean} props.isLoading - Whether to show the loading spinner.
+ * @param {Function} props.handleClose - Function to close the popup.
+ * @param {React.ReactNode} props.children - Content to display in the popup.
+ * @returns {JSX.Element}
+ */
function PopUp({ isLoading, handleClose, children }) {
return ReactDom.createPortal(
isLoading ? (
@@ -108,10 +133,20 @@ function PopUp({ isLoading, handleClose, children }) {
);
}
+/**
+ * Formats a date array as MM/DD/YYYY.
+ * @param {Array} date - [year, month, day]
+ * @returns {string} Formatted date string.
+ */
const formatDate = (date) => {
return `${date[1]}/${date[2]}/${date[0]}`;
};
+/**
+ * Extracts the sender's name from the sender string.
+ * @param {string} sender - The sender string
+ * @returns {string} The sender's name.
+ */
const getSenderName = (sender) => {
return sender.slice(0, sender.indexOf("<"));
};
diff --git a/frontend/src/components/client/inbox/inbox.jsx b/frontend/src/components/client/inbox/inbox.jsx
index b2030f5..82df1bf 100644
--- a/frontend/src/components/client/inbox/inbox.jsx
+++ b/frontend/src/components/client/inbox/inbox.jsx
@@ -2,11 +2,20 @@ import PropTypes from "prop-types";
import { useEffect, useRef, useState } from "react";
import ArrowIcon from "../../../assets/InboxArrow";
import { emailsPerPage } from "../../../assets/constants";
-import EmailDisplay from "./emailDisplay";
import { getPageSummaries } from "../../../emails/emailHandler";
+import EmailDisplay from "./emailDisplay";
import "./emailEntry.css";
import "./emailList.css";
+/**
+ * Inbox component displays the email list and the selected email.
+ * @param {Object} props
+ * @param {boolean} props.displaySummaries - Whether to show summaries.
+ * @param {Array} props.emailList - List of emails.
+ * @param {Function} props.setCurEmail - Function to set the current email.
+ * @param {Email} props.curEmail - The currently selected email.
+ * @returns {JSX.Element}
+ */
function Inbox({ displaySummaries, emailList, setCurEmail, curEmail }) {
return (
@@ -21,7 +30,20 @@ function Inbox({ displaySummaries, emailList, setCurEmail, curEmail }) {
);
}
+/**
+ * Renders a single email entry in the inbox list.
+ * @param {Object} props
+ * @param {boolean} props.displaySummary - Whether to show the summary.
+ * @param {Email} props.email - The email object.
+ * @param {Function} props.onClick - Function to select this email.
+ * @param {boolean} props.selected - Whether this email is currently selected.
+ * @returns {JSX.Element}
+ */
function EmailEntry({ displaySummary, email, onClick, selected }) {
+ /**
+ * Renders the summary for the email, or a loading placeholder if not available.
+ * @returns {JSX.Element}
+ */
const summary = () => {
let returnBlock;
if (email.summary_text.length > 0) {
@@ -34,9 +56,8 @@ function EmailEntry({ displaySummary, email, onClick, selected }) {
const date = getDate(email.received_at);
return (
@@ -58,6 +79,15 @@ function EmailEntry({ displaySummary, email, onClick, selected }) {
);
}
+/**
+ * Renders the list of emails in the inbox, with infinite scroll and summary fetching.
+ * @param {Object} props
+ * @param {boolean} props.displaySummaries - Whether to show summaries.
+ * @param {Array
} props.emailList - List of emails.
+ * @param {Email} props.curEmail - The currently selected email.
+ * @param {Function} props.onClick - Function to select an email.
+ * @returns {JSX.Element}
+ */
function InboxEmailList({ displaySummaries, emailList, curEmail, onClick }) {
const [pages, setPages] = useState(1);
const ref = useRef(null);
@@ -67,13 +97,16 @@ function InboxEmailList({ displaySummaries, emailList, curEmail, onClick }) {
: emailList.length;
const hasUnloadedEmails = maxEmails < emailList.length;
+ /**
+ * Handles scroll event to load more emails when scrolled to the bottom.
+ */
const handleScroll = () => {
// add external summary call
const fullyScrolled =
Math.abs(
ref.current.scrollHeight -
- ref.current.clientHeight -
- ref.current.scrollTop
+ ref.current.clientHeight -
+ ref.current.scrollTop
) <= 1;
if (fullyScrolled && hasUnloadedEmails) {
setPages(pages + 1);
@@ -85,6 +118,11 @@ function InboxEmailList({ displaySummaries, emailList, curEmail, onClick }) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pages]); // Fixes minimum for large screens, but runs effect after every load which is unnecessary
+ /**
+ * Renders the list of EmailEntry components up to maxEmails.
+ * Fetches summaries for emails that need them.
+ * @returns {JSX.Element[]}
+ */
const emails = () => {
const returnBlock = [];
const needsSummary = [];
@@ -143,10 +181,20 @@ InboxEmailList.propTypes = {
onClick: PropTypes.func,
};
+/**
+ * Formats a date array as MM/DD/YYYY.
+ * @param {Array} date - [year, month, day]
+ * @returns {string} Formatted date string.
+ */
const getDate = (date) => {
return `${date[1]}/${date[2]}/${date[0]}`;
};
+/**
+ * Extracts the sender's name from the sender string.
+ * @param {string} sender - The sender string, e.g., "John Doe "
+ * @returns {string} The sender's name.
+ */
const getSenderName = (sender) => {
return sender.slice(0, sender.indexOf("<"));
};
diff --git a/frontend/src/components/client/reducers.jsx b/frontend/src/components/client/reducers.jsx
index 4b62cc5..8f84861 100644
--- a/frontend/src/components/client/reducers.jsx
+++ b/frontend/src/components/client/reducers.jsx
@@ -1,5 +1,15 @@
import { saveUserPreferences } from "./settings/settings";
+/**
+ * Reducer for client state (sidebar, current page, current email).
+ * @param {Object} client - Current client state.
+ * @param {Object} action - Action to perform.
+ * @param {string} action.type - Type of action ("logoClick", "pageChange", "emailChange").
+ * @param {boolean} [action.state] - Sidebar expansion state (for "logoClick").
+ * @param {string} [action.page] - Page name (for "pageChange").
+ * @param {Object} [action.email] - Email object (for "emailChange").
+ * @returns {Object} New client state.
+ */
export function clientReducer(client, action) {
switch (action.type) {
case "logoClick": {
@@ -23,6 +33,17 @@ export function clientReducer(client, action) {
}
}
+/**
+ * Reducer for user preferences state.
+ * Updates and saves user preferences based on the action type.
+ * @param {Object} userPreferences - Current user preferences state.
+ * @param {Object} action - Action to perform.
+ * @param {string} action.type - Type of action ("isChecked", "emailFetchInterval", "theme").
+ * @param {boolean} [action.isChecked] - Toggle summaries in inbox (for "isChecked").
+ * @param {number} [action.emailFetchInterval] - Email fetch interval (for "emailFetchInterval").
+ * @param {string} [action.theme] - Theme name (for "theme").
+ * @returns {Object} New user preferences state.
+ */
export function userPreferencesReducer(userPreferences, action) {
// Call to get user preferences to the update preferences base on the reducer action
switch (action.type) {
diff --git a/frontend/src/components/client/settings/settings.css b/frontend/src/components/client/settings/settings.css
index 912c386..74fd41c 100644
--- a/frontend/src/components/client/settings/settings.css
+++ b/frontend/src/components/client/settings/settings.css
@@ -7,6 +7,7 @@ body {
background-color: var(--color-background);
}
+/* ---------------------------Settings--------------------------------- */
.settings {
width: 100%;
height: 100%;
@@ -31,6 +32,7 @@ body {
position: relative;
}
+/* ------------------------------Headings-------------------------------- */
h2 {
margin-right: 20px;
color: var(--color-text);
@@ -40,7 +42,7 @@ h2 {
line-height: normal;
}
-/* The switch - the box around the slider */
+/* -----------------------------Settings Switch-------------------------- */
.settings .switch {
margin-left: auto;
position: relative;
@@ -49,7 +51,6 @@ h2 {
height: 20px;
}
-/* Hide default HTML checkbox */
.settings .switch input {
opacity: 0;
width: 0;
@@ -82,12 +83,12 @@ h2 {
border-radius: 50%;
}
-/* When the checkbox is checked, add a background color */
+/* Checked state for switch */
.switch input:checked+.toggle {
background-color: var(--color-toggle-border);
}
-/* Move the slider when the checkbox is checked */
+/* Move the slider when checked */
.switch input:checked+.toggle:before {
transform: translateX(calc(1rem + 0.5vw));
left: 75%;
@@ -103,6 +104,7 @@ h2 {
border-radius: 50%;
}
+/* --------------------------Email Fetch Interval-------------------------- */
.email-fetch-interval {
display: flex;
flex-direction: column;
@@ -180,7 +182,7 @@ h2 {
color: var(--color-slider-thumb);
}
-/* Theme Toggle Styles */
+/* ---------------------------Theme Toggle-------------------------- */
.theme-toggle-group {
margin-left: auto;
display: flex;
@@ -221,6 +223,7 @@ h2 {
outline-offset: 2px;
}
+/* -----------------------Logout and Delete Buttons------------------------ */
.settings-account-actions {
position: absolute;
right: 2rem;
diff --git a/frontend/src/components/client/settings/settings.jsx b/frontend/src/components/client/settings/settings.jsx
index fd09261..0e9898c 100644
--- a/frontend/src/components/client/settings/settings.jsx
+++ b/frontend/src/components/client/settings/settings.jsx
@@ -2,6 +2,17 @@ import { useEffect, useState } from "react";
import { baseUrl } from "../../../emails/emailHandler";
import "./settings.css";
+/**
+ * Settings component for managing user preferences
+ * @param {Object} param0 - Component props
+ * @param {boolean} param0.isChecked - Indicates whether summaries are enabled
+ * @param {function} param0.handleToggleSummariesInInbox - Callback to toggle summaries
+ * @param {number} param0.emailFetchInterval - Current email fetch interval
+ * @param {function} param0.handleSetEmailFetchInterval - Callback to set email fetch interval
+ * @param {string} param0.theme - Current theme
+ * @param {function} param0.handleSetTheme - Callback to set theme
+ * @returns {JSX.Element}
+ */
export function Settings({
isChecked,
handleToggleSummariesInInbox,
@@ -15,10 +26,15 @@ export function Settings({
window.location.href = "/login";
};
- const handleDeleteAccount = async() => {
- //confirm if the user wants to delete their account
+ /**
+ * Deletes the user account after confirmation, removes all user info from the database,
+ * and redirects to the login page.
+ * @async
+ * @returns {Promise}
+ */
+ const handleDeleteAccount = async () => {
if (!window.confirm("Are you sure you want to delete your EmailEssence Account? \nThis will remove all information associated with your gmail account from our server and lead to longer loading times when you log back in next time.")) return;
- try{
+ try {
const profile = await fetchUserProfile();
const userId = profile.google_id
await deleteUserById(userId);
@@ -31,8 +47,14 @@ export function Settings({
};
}
+
+ /**
+ * Custom hook to detect system theme preference
+ * This hook listens for changes in the user's system theme preference
+ * and updates the state accordingly.
+ * @returns {boolean} isDarkTheme - true if the system theme is dark, false otherwise
+ */
const isDarkTheme = useSystemTheme();
- // useEffect that sets the dark mode class when the theme is set to system
useEffect(() => {
if (theme === "system") {
if (isDarkTheme) {
@@ -63,7 +85,7 @@ export function Settings({
);
}
-// component that renders the summary toggle switch for enabling/disabling summaries in the inbox
+/* Component that renders the summary toggle switch for enabling/disabling summaries in the inbox */
export function SummariesInInbox({ isChecked, onToggle }) {
return (
@@ -76,7 +98,7 @@ export function SummariesInInbox({ isChecked, onToggle }) {
);
}
-// component that renders the email fetch interval slider
+/* Component that renders the email fetch interval slider */
export function EmailFetchInterval({
emailFetchInterval,
onSetEmailFetchInterval,
@@ -101,11 +123,14 @@ export function EmailFetchInterval({
);
}
-// component that renders the buttons to switch between different themes
+/**
+ * Component that renders the theme switcher buttons
+ * @param {string} theme - The current theme
+ * @param {function} onSetTheme - Callback function to handle theme changes
+ * @returns {JSX.Element}
+ */
export function Theme({ theme, onSetTheme }) {
- const themes = ["light", "system", "dark"]; //array of themes
-
- //function to handle theme change between light and dark through the buttons
+ const themes = ["light", "system", "dark"];
const handleThemeChange = (setTheme) => {
onSetTheme(setTheme);
if (setTheme === "dark") {
@@ -123,14 +148,13 @@ export function Theme({ theme, onSetTheme }) {
}
}
};
-
return (
Theme
- {themes.map(
+ {themes.map( //renders the theme buttons
(
- t //renders the theme buttons
+ t
) => (