Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
# LabConnect-Frontend
# Welcome to LabConnect (Frontend)
Team: Rafael Cenzano, Sagar Sahu, Will Broadwell

React frontend for the [Labconnect project](https://labconnect.cs.rpi.edu/).
This README is meant to serve as documentation for users and developers to explore the LabConnect application on their down device. Below you will find detailed setup instructions as well as more information about the product and its intended purpose, as well as some important links and guides. Enjoy!

All open-source contributions for LabConnect can be found at the following link: https://github.com/LabConnect-RCOS.

## What's LabConnect?
LabConnect is a platform dedicated to bridging the gap between students and research opportunities. We aim to make it easier for students to find meaningful lab/research work while helping professors connect with passionate individuals through a convenient, all-in-one application. Our team is hard at work, and we will provide updates on our progress so keep an eye out for announcements! Currently, we're putting some final touches on our product and hope to release it university-wide in the upcoming fall semester.

If you're interested in learning more about the team at RCOS or are thinking about joining LabConnect or any branch of RCOS, please check out the new website here to learn more about existing projects and areas of interest: https://new.rcos.io/.

## Some New Stuff
This semester, our team has made a lot of progress in finetuning the application and correctly syncing the backend and frontend. A few of the new contributions made are:
1. A brand new, remade UI catered towards students
2. Convenient features and toggles, such as dark mode, to accommodate for different user preferences
3. Revamped opportunities and listing pages
4. Functioning backend with PostgreSQL database for departments, professors, and opportunities
5. Advances filtering for facotrs like hours, pay/credit, supervisor, subject, etc...

## Setup

Clone repo
To clone the repository:
```bash
$ git clone https://github.com/LabConnect-RCOS/LabConnect-Frontend.git
```

Install dependencies
To install dependencies:
```bash
npm install
```

## Developement

Running the application should be very simple. Use one of the commands below:
```bash
npm start
```
OR
```bash
npm run dev
```

## Production

You can use the docker images in the packages that are created on all commits to the main branch or build with the commands below and serve the files through your own prefered methods.
You can also use the docker images in the packages that are created on all commits to the main branch or build with the commands below and serve the files through your own prefered methods:

```bash
npm run build
```

## Troubleshooting
If you encounter any bugs or issues in your experience, double check the spelling of your commands and consider force-quitting the application by entering `^C` in both the backend and frontend terminals. Then restart the application, and ensure that all connections and dependencies are installed and working, as decribed above.

Please don't hesitate to reach out with additional concerns or comments. We value your feedback in making LabConnect the best product it can be.

### Thank you so much for checking out LabConnect!
72 changes: 67 additions & 5 deletions src/shared/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useRef, useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { FaEnvelope } from "react-icons/fa";
import darkLogo from "../../images/LabConnect_Logo2-removebg-preview.png";
import SEO from "../components/SEO.tsx";

Expand All @@ -24,21 +25,32 @@ const Home = () => {
document.documentElement.classList.contains("dark")
);

// Inbox popup state & ref
const [showInbox, setShowInbox] = useState(false);
const inboxRef = useRef<HTMLDivElement>(null);

// Mock notifications
const notifications = [
{ id: 1, text: "Biology Department posted new research positions.", time: "2h ago" },
{ id: 2, text: "Your application to Quantum Lab was accepted!", time: "1d ago" },
{ id: 3, text: "Reminder: Update your profile by April 30th.", time: "3d ago" },
];

// Preload the dark logo to ensure it's cached.
useEffect(() => {
const preloadImg = new Image();
preloadImg.src = darkLogo;
}, []);

// Use a faster polling interval (50ms) to check if the "dark" class is present
// Poll for dark‑mode changes
useEffect(() => {
const intervalId = setInterval(() => {
setIsDarkMode(document.documentElement.classList.contains("dark"));
}, 50);
return () => clearInterval(intervalId);
}, []);

// Scroll event to update "Return to Top" button visibility and position.
// Scroll event for Return to Top button
useEffect(() => {
const handleScroll = () => {
setShowReturnToTop(window.scrollY > 100);
Expand All @@ -57,6 +69,21 @@ const Home = () => {
return () => window.removeEventListener("scroll", handleScroll);
}, []);

// Click‑outside handler for Inbox popup
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (
showInbox &&
inboxRef.current &&
!inboxRef.current.contains(e.target as Node)
) {
setShowInbox(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [showInbox]);

const handleContactChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
Expand All @@ -82,9 +109,44 @@ const Home = () => {

{/* Welcome Section */}
<section className="home-general text-center w-full relative">
{/* Inbox label + button locked top‑right */}
<div
ref={inboxRef}
className="absolute top-4 right-4 flex items-center space-x-2 z-50"
>
<span className={`text-gray-800 dark:text-gray-200 font-medium ${showInbox ? "underline" : ""}`}>
View Inbox
</span>
<button
onClick={() => setShowInbox((v) => !v)}
className="p-2 bg-white dark:bg-gray-800 rounded-full shadow hover:shadow-lg focus:outline-none border-2 border-black dark:border-white"
>
<FaEnvelope className="text-xl text-gray-700 dark:text-gray-200" />
</button>

{showInbox && (
<div className="absolute top-full right-0 mt-2 w-64 bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden">
<div className="px-4 py-2 border-b border-gray-200 dark:border-gray-700">
<strong className="text-gray-800 dark:text-gray-100">Inbox</strong>
</div>
{notifications.map((n) => (
<div
key={n.id}
className="px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer flex justify-between items-center"
>
<span className="text-sm text-gray-800 dark:text-gray-200">
{n.text}
</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
{n.time}
</span>
</div>
))}
</div>
)}
</div>

<div className="img-center pt-4">
{/* The image source now switches instantaneously.
Inline style disables any default transition. */}
<img
src={isDarkMode ? darkLogo : darkLogo}
alt="LabConnect"
Expand Down Expand Up @@ -387,4 +449,4 @@ const Home = () => {
);
};

export default Home;
export default Home;