# Project export: Maomorize

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Purrfect your memory skills & study habits with Maomorize!
- Devpost: https://devpost.com/software/maomorize
- GitHub: https://github.com/SimonZhao7/Maomorize
- Demo: https://main--elaborate-medovik-f46ce6.netlify.app/
- Video: https://www.youtube.com/embed/OENzaybdTEk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Varun Kanna (66 commits), Simon Zhao (42 commits), Debora Choi (6 commits)

## Devpost submission (written by the team)

### Inspiration

As the new year unfolds, our team found inspiration to develop a website dedicated to assisting UCSC students in unlocking their full academic potential.

### What it does

Maomorize, our dynamic and user-friendly website, utilizes the effective blurting study method to enhance memorization. We put in a lot of thought into our front end and made it efficient and fun for the user to use. We believe that our loading page is especially extravagant in the different elements we incorporate in it. Additionally, Maomorize incorporates AI functionality that provides valuable suggestions to improve users' notes. Users can easily log in or sign up through Google, upload their notes, and receive AI-generated suggestions for note enhancement. After the review, the notes are saved and marked as studied on a separate page. The upcoming study dates are seamlessly integrated for enhanced user convenience.

### How we built it

The website's dynamic UI was crafted using HTML, CSS, JavaScript, and React. The back-end logic and functionality were implemented with JavaScript and React to ensure smooth navigation and user flow. We established a custom domain using Netlify, where each git commit triggered a deploy and website update. Firebase was employed as our main method of data storage for our project. Additionally, it was used for handling the user experience of creating and saving user login information. The Open AI API was used to give note recommendations and suggestion study materials for the user. This integration allows users to schedule and receive timely reminders for revisiting specific topics or tasks, optimizing the learning process.

### Challenges we ran into

During development, we faced Git merge conflicts that inadvertently deleted some of the new edits in our files. To resolve this issue, we referred to past commits containing functional code. We also had difficulty using OAuth2.0 to authenticate users to access their calendars.

### Accomplishments we're proud of

We take pride in creating this unique website, aiming to help UCSC students achieve their academic goals in 2024. Our hack works as we expected it to and we achieved the goals that we set out to accomplish. However, this is always room for improvement and we recognize that many features can still be improvised upon in the future.

### What we learned

Our experience taught us how to have efficient time management through the breakdown of large tasks into more manageable components. Furthermore, the incorporation of a project manager allowed us to organize all tasks, ideas, and goals on a Google Doc. This allowed us to visualize objectives and allocate them seamlessly to each team member. This optimized approach contributed significantly to our project's success. Applicability Our project applies well to the Education, SlugHacks, and UI/UX projects. We believe our creativity allowed us to branch into multiple topics and made our project even more unique.

### What's next

We plan to implement additional features in the future using different APIs. One example would be highlighting sections of text for each AI suggestion so users can clearly tell where they need to improve. Another example would be an actual integration with Google Calendar to remind users to study no matter where they are.

## README (from the GitHub repository)

# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh


## Detected evidence (automated analysis)

Indexed codebase: 38 recognized source files, 180 KB.
- CSS (language) — detected in the code
- Firebase (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (48 of 48)

```
.eslintrc.cjs
.firebaserc
.gitignore
firebase.js
firebase.json
firestore.indexes.json
firestore.rules
index.html
package.json
public/_redirects
README.md
src/App.css
src/App.jsx
src/components/ActionButton/index.jsx
src/components/ActionButton/style.css
src/components/Navbar/index.jsx
src/components/Navbar/style.css
src/components/Spinner/index.jsx
src/components/Spinner/style.css
src/components/SuggestionCard/index.jsx
src/components/SuggestionCard/style.css
src/hooks/index.js
src/index.css
src/main.jsx
src/routes/Component/index.jsx
src/routes/Component/style.css
src/routes/Feedback/index.jsx
src/routes/Feedback/style.css
src/routes/Forgot/index.jsx
src/routes/Forgot/style.css
src/routes/Landing/index.jsx
src/routes/Landing/style.css
src/routes/Login/index.jsx
src/routes/Login/style.css
src/routes/Review/index.jsx
src/routes/Review/style.css
src/routes/SignUp/index.jsx
src/routes/SignUp/style.css
src/routes/Upload/index.jsx
src/routes/Upload/Upload.css
src/routes/View/index.jsx
src/routes/View/View.css
src/routes/ViewNote/index.jsx
src/routes/ViewNote/style.css
src/util/nextInterval.js
storage.rules
vercel.json
vite.config.js
```

### Dependencies

- package.json: @types/react@^18.2.43, @types/react-dom@^18.2.17, @vitejs/plugin-react@^4.2.1, date-fns@^3.3.0, dotenv@^16.3.2, eslint@^8.55.0, eslint-plugin-react@^7.33.2, eslint-plugin-react-hooks@^4.6.0, eslint-plugin-react-refresh@^0.4.5, firebase@^10.7.2, openai@^4.24.7, react@^18.2.0, react-dom@^18.2.0, react-icons@^5.0.1, react-router-dom@^6.21.3, sass@^1.70.0, vite@^5.0.8

### Recent commits (newest first)

- landing
- Duplicate orange cat
- Moved images
- Add _redirects
- Add vercel.json
- Merge branch 'main' of github.com:SimonZhao7/Maomorize
- Add Navbar update
- Merge pull request #46 from SimonZhao7/simon2
- Merge branch 'main' of github.com:SimonZhao7/Maomorize into simon2
- Fix styles
- Merge pull request #45 from SimonZhao7/simon2
- Merge branch 'main' of github.com:SimonZhao7/Maomorize into simon2
- Upload pdf dummy
- Merge pull request #44 from SimonZhao7/debora
- plzzz
- plz
- Add styles for view route
- Merge pull request #42 from SimonZhao7/varun
- Merge branch 'main' of https://github.com/SimonZhao7/Maomorize into varun
- Merge pull request #41 from SimonZhao7/varun

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "maomorize",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "date-fns": "^3.3.0",
    "dotenv": "^16.3.2",
    "firebase": "^10.7.2",
    "openai": "^4.24.7",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^5.0.1",
    "react-router-dom": "^6.21.3"
  },
  "devDependencies": {
    "@types/react": "^18.2.43",
    "@types/react-dom": "^18.2.17",
    "@vitejs/plugin-react": "^4.2.1",
    "eslint": "^8.55.0",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.5",
    "sass": "^1.70.0",
    "vite": "^5.0.8"
  }
}

```

### src/main.jsx

```javascript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
```

### src/App.jsx

```javascript
import * as React from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Upload from "./routes/Upload";
import Review from "./routes/Review";
import Feedback from "./routes/Feedback";
import View from "./routes/View";
import Landing from "./routes/Landing";
import SignUp from "./routes/SignUp";
import Login from "./routes/Login";
import Forgot from "./routes/Forgot";
import Component from "./routes/Component";
import ViewNote from "./routes/ViewNote";
// Loaders
import { loader as feedbackLoader } from "./routes/Feedback";
import { loader as viewNoteLoader } from "./routes/ViewNote";
import { loader as reviewLoader } from "./routes/Review";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Landing />,
  },
  {
    path: "/upload",
    element: <Upload />,
  },
  {
    path: "/view",
    element: <View />,
  },
  {
    path: "/signup",
    element: <SignUp />,
  },
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "/review/:id",
    element: <Review />,
    loader: reviewLoader,
  },
  {
    path: "/forgot",
    element: <Forgot />,
  },
  {
    path: "/get-token",
    element: <Component />,
  },
  {
    path: "/feedback/:id",
    element: <Feedback />,
    loader: feedbackLoader,
  },
  {
    path: "/view/:id",
    element: <ViewNote />,
    loader: viewNoteLoader,
  },
]);

const App = () => {
  return <RouterProvider router={router} />;
};

export default App;

```

### src/components/Spinner/index.jsx

```javascript
import "./style.css";

const Spinner = ({ size, color }) => {
  return (
    <div
      className="spinner"
      style={{ width: `${size}px`, height: `${size}px`, borderTopColor: color }}
    >
      &nbsp;
    </div>
  );
};

export default Spinner;

```

### src/components/ActionButton/index.jsx

```javascript
import "./style.css";
import Spinner from "../Spinner";

const ActionButton = ({ onClick, label, loading }) => {
  return (
    <button className="action-btn" onClick={onClick} disabled={loading}>
      {loading ? <Spinner size={30} color="white" /> : label}
    </button>
  );
};

export default ActionButton;

```

### src/components/SuggestionCard/index.jsx

```javascript
import "./style.css";
// Icons
import { IoInformationCircle } from "react-icons/io5";
import { CgDanger } from "react-icons/cg";

const SuggestionCard = ({ suggestion }) => {
  return (
    <div className="wrapper">
      <p>{suggestion.suggestion}</p>
      <div className="pill-wrapper">
        <div
          className={`pill ${
            suggestion.quote != null ? "fix-info" : "missing-info"
          }`}
        >
          {suggestion.quote != null ? (
            <>
              <IoInformationCircle size={25} /> Suggestion
            </>
          ) : (
            <>
              <CgDanger size={25} /> Missing Info
            </>
          )}
        </div>
      </div>
    </div>
  );
};

export default SuggestionCard;

```

### src/routes/Component/index.jsx

```javascript
import "./style.css";
import { useEffect } from "react";
import { onAuthStateChanged } from "firebase/auth";
import { useNavigate, useSearchParams } from "react-router-dom";
import { auth } from "../../../firebase";

const Component = () => {
  const [queryParams, _] = useSearchParams();
  const navigate = useNavigate();

  useEffect(() => {
    const unsub = onAuthStateChanged(auth, async (user) => {
      if (user) {
        await fetch(
          `http://127.0.0.1:5001/maomorize-b2ccb/us-central1/accessToken?uid=${
            user.uid
          }&code=${queryParams.get("code")}`
        );
        navigate("/view");
      }
    });

    return () => unsub();
  }, []);

  return (
    <div>
      <h1>Component</h1>
    </div>
  );
};

export default Component;

```

### src/routes/Forgot/index.jsx

```javascript
import "./style.css";
import { useState } from "react";
import { sendPasswordResetEmail } from "firebase/auth";
import { auth } from "../../../firebase"; // Assuming you have initialized Firebase in 'firebase.js' file
import { Link, useNavigate } from "react-router-dom";

const Forgot = () => {
  const [email, setEmail] = useState("");
  const navigate = useNavigate();

  const handleResetPassword = async () => {
    try {
      // Send password reset email
      await sendPasswordResetEmail(auth, email);

      console.log("Password reset email sent successfully!");
      // Provide user feedback or redirect them to a confirmation page
    } catch (error) {
      console.error("Error sending password reset email:", error.message);
    }
  };

  return (
    <div className="forgot-wrapper">
      <div className="forgot-container">
        <div>
          <label className="forgot-label" htmlFor="email">
            Email:
          </label>
          <input
            type="email"
            id="email"
            placeholder="Enter your email"
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>

        <button className="forgot-login-button" onClick={handleResetPassword}>
          Reset Password
        </button>

        <div className="forgot-login-button">
          <Link className="login-link" to="/login">
            Remember your password?
          </Link>
        </div>
        {/* <div className='login-form'>
				
				</div> */}
      </div>
      <div className="forgot-mao-background">&nbsp;</div>
    </div>
  );
};

export default Forgot;

```

### src/routes/Feedback/index.jsx

```javascript
import "../Review/style.css";
import "./style.css";
import { useLoaderData, useNavigate } from "react-router-dom";
// Components
import ActionButton from "../../components/ActionButton";
import Navbar from "../../components/Navbar";
import SuggestionCard from "../../components/SuggestionCard";
// Firebase
import { db } from "../../../firebase";
import { doc, getDoc } from "firebase/firestore";

export const loader = async ({ params: { id } }) => {
  const feedbackRef = doc(db, "feedback", id);
  const feedback = (await getDoc(feedbackRef)).data();
  const suggestions = await Promise.all(
    feedback.suggestions.map(async (id) => {
      return (await getDoc(doc(db, "suggestions", id))).data();
    })
  );

  return { feedback, suggestions };
};

const Feedback = () => {
  const { feedback, suggestions } = useLoaderData();
  const { blurt, suggestions: suggestionIds } = feedback;
  const navigate = useNavigate();

  return (
    <main>
      <Navbar />
      <section className="review_main">
        <textarea disabled={true} id="notebox" value={blurt}></textarea>
        <aside className="blurt-wrapper">
          <div className="blurt-suggest">
            <h1 className="blurt-header" id="blurt-mid-size">
              Review your blurt.
            </h1>
            <div className="suggestion-wrapper">
              {suggestions.map((s) => (
                <SuggestionCard key={s.id} suggestion={s} />
              ))}
            </div>
          </div>
          <ActionButton
            label={"Finish reviewing"}
            onClick={() => navigate("/view")}
          />
        </aside>
      </section>
    </main>
  );
};

export default Feedback;

```

### src/components/Navbar/index.jsx

```javascript
// Navbar.jsx
import React from "react";
import { Link } from "react-router-dom"; // Import Link from react-router-dom
import HomeIcon from "/src/assets/imgs/home_icon.png"; // Replace with the actual path to your home icon
import "./style.css";

const Navbar = () => {
  return (
    <nav className="navbar">
      <Link to="/View">
        <div className="home-button">Home</div>
        <div className="home-icon">
          <img src={HomeIcon} alt="Home" className="home-icon" />
        </div>
      </Link>

      <div className="plus-div"> + </div>
      <div className="plus-div2"> + </div>
      <div className="plus-div3"> + </div>

      <div className="dot-div"> . </div>
      <div className="dot-div2"> . </div>
      <div className="dot-div3"> . </div>

      <div className="ast-div"> * </div>
      <div className="ast-div2"> * </div>
      <div className="ast-div3"> * </div>

      <div>
        <img className="white-circle" src="/images/white-circle.png" />
      </div>
      <div>
        <img className="white-circle2" src="/images/white-circle.png" />
      </div>
      <div>
        <img className="white-circle3" src="/images/white-circle.png" />
      </div>

      <div>
        <img className="white-triangle" src="/images/white-triangle.png" />
      </div>
      <div>
        <img className="white-triangle2" src="/images/white-triangle.png" />
      </div>

      <div>
        <img className="down-triangle" src="/images/down-triangle.png" />
      </div>
      <div>
        <img className="down-triangle2" src="/images/down-triangle.png" />
      </div>

      <div>
        <img className="black-cat" src="/images/black-cat.png" />
      </div>

      <div>
        <img className="paw" src="/images/paw.png" />
      </div>
      <div>
        <img className="paw2" src="/images/paw.png" />
      </div>

      <div>
        <img className="orange-cat" src="/images/orange-cat.png" />
      </div>

      <div>
        <img className="spotted-cat" src="/images/spotted-cat.png" />
      </div>
    </nav>
  );
};

export default Navbar;

```

[24 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]