Skip to content

Commit

Permalink
Merge branch 'main' of github.com:ChangePlusPlusVandy/PennsylvaniaWom…
Browse files Browse the repository at this point in the history
…enWork into grayson/MentorDashboard

Merge lines# the commit.
  • Loading branch information
graysonsmithh committed Dec 2, 2024
2 parents 78a348f + 515949a commit 4b08d16
Show file tree
Hide file tree
Showing 10 changed files with 898 additions and 387 deletions.
797 changes: 678 additions & 119 deletions api/package-lock.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "src/server.ts",
"scripts": {
"build": "tsc",
"start": "node src/index.ts",
"dev": "npx ts-node-dev --respawn --pretty --transpile-only src/server.ts",
"start": "npx ts-node src/server.ts",
"dev": "nodemon --watch 'src/**/*.ts' --exec 'npx ts-node src/server.ts'",
"test": "echo \"Error: no test specified\" && exit 1",
"prettier": "npx prettier --write .",
"format": "prettier --check ."
Expand All @@ -19,9 +19,9 @@
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"express-oauth2-jwt-bearer": "^1.6.0",
"mongodb": "^6.9.0",
"mongoose": "^8.4.1",
"sendgrid": "^5.2.3",
"ts-node-dev": "^2.0.0",
"uuid": "^10.0.0"
},
Expand All @@ -31,7 +31,9 @@
"@types/node": "^22.8.1",
"@types/uuid": "^10.0.0",
"body-parser": "^1.20.3",
"nodemon": "^3.1.7",
"prettier": "^3.3.3",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
53 changes: 51 additions & 2 deletions api/src/routes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ const userSchema = new mongoose.Schema({
menteeInfo: [String], // For mentors only
meetingSchedule: [String], // For mentees only
mentorData: String, // For mentees only
meetings: [
{
name: String, // title ??
notes: String,
createdAt: { type: Date, default: Date.now },
},
],
});

const User = mongoose.model("User", userSchema);
Expand All @@ -39,6 +46,7 @@ router.post("/create-user", async (req: any, res: any) => {
menteeInfo,
meetingSchedule,
mentorData,
meetings,
} = req.body;

if (!firstName || !lastName || !username || !email || !role) {
Expand All @@ -56,6 +64,7 @@ router.post("/create-user", async (req: any, res: any) => {
menteeInfo: role === "mentor" ? menteeInfo : undefined,
meetingSchedule: role === "mentee" ? meetingSchedule : undefined,
mentorData: role === "mentee" ? mentorData : undefined,
meetings: meetings || [],
});

try {
Expand Down Expand Up @@ -91,14 +100,19 @@ router.post("/send-email", async (req: any, res: any) => {
throw new Error("SendGrid API key or test email is missing");
}

const { email, name } = req.body;
const { email, name, role } = req.body;

sgMail.setApiKey(SENDGRID_API_KEY);

const templateId =
role.toLowerCase().trim() === "mentor"
? "d-1694192e437348e2a0517103acae3f00"
: "d-7e26b82cf8624bafa4077b6ed73b52bf";

await sgMail.send({
to: email,
from: SEND_GRID_TEST_EMAIL,
templateId: "d-7e26b82cf8624bafa4077b6ed73b52bf",
templateId: templateId,
dynamicTemplateData: {
name: name,
},
Expand All @@ -110,4 +124,39 @@ router.post("/send-email", async (req: any, res: any) => {
}
});

// Route to add a meeting
router.post("/add-meeting", async (req, res) => {
const { username, meeting, notes } = req.body;

// Validate required fields
if (!username || !meeting || !notes) {
return res.status(400).json({ message: "Missing required fields" });
}

try {
// Find the user by username
console.log("Searching for user with username:", username);
const user = await User.findOne({ username });

if (!user) {
console.error(`User not found for username: ${username}`);
return res.status(404).json({ message: "User not found" });
}

// Add the meeting to the user's meetings array
user.meetings.push({ name: meeting, notes });

// Save the updated user document
await user.save();

console.log("Meeting added successfully for username:", username);
return res
.status(200)
.json({ message: "Meeting added successfully", user });
} catch (error) {
console.error("Error adding meeting:", error);
return res.status(500).json({ message: "Error adding meeting", error });
}
});

export default router;
60 changes: 15 additions & 45 deletions api/src/routes/workshop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import mongoose from "mongoose";
import dbConnect from "../config/db"; // Import the dbConnect function
// import { validateAccessToken } from "../controllers/auth0-middleware";

import { createWorkshop, getWorkshop } from "../controllers/workshopController";

const router = express.Router();

// TODO: Add auth0 middleware
Expand All @@ -13,65 +11,37 @@ const router = express.Router();
// Call the dbConnect function to connect to MongoDB
dbConnect();

// Workshop schema definition (name and S3 bucket ID)
const workshopIDSchema = new mongoose.Schema({
name: String,
s3ID: String,
// Workshop schema definition (name (required by user), description (required by user), and S3 bucket ID (not required as user input))
const workshopSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: true },
s3id: { type: String, required: false },
});

const Workshop = mongoose.model("WorkshopID", workshopIDSchema);
const Workshop = mongoose.model("Workshop", workshopSchema);

// Route to create a new workshop
router.post("/create-workshop", async (req: any, res: any) => {
const { name, s3id } = req.body;
const { name, description, s3id } = req.body;

if (!name || !s3id) {
if (!name || !description) {
return res.status(400).json({ message: "Missing required fields" });
}

// Create a new workshop
const newWorkshop = new Workshop({
name,
s3id,
});

try {
// Create a new workshop with
const newWorkshop = new Workshop({ name, description, s3id });
const savedWorkshop = await newWorkshop.save();

// Success:
res.status(201).json({
message: "Workshop created successfully",
WorkshopID: savedWorkshop,
workshop: savedWorkshop,
});
} catch (error) {
res.status(401).json({ message: "Failed to create workshop", error });
console.error("Error saving workshop:", error);
res.status(500).json({ message: "Failed to create workshop", error });
}
});

// router.post("/workshops", createWorkshop)
// router.get('/workshops/:id', getWorkshop);
router.get(
"/workshops/:id",
async (req: express.Request, res: express.Response) => {
await getWorkshop(req, res);
},
);

router.post("/testId/:id", async (req: any, res: any) => {
res
.status(200)
.json({ message: "Workshop test successful", id: req.params.id });
});

// POPULATE VERSION (if details of mentor/mentee objects are needed on the frontend like name or picture)

// import express from 'express';
// import { createWorkshop, getWorkshop } from '../controllers/workshopController';

// const router = express.Router();

// router.post('/workshops', createWorkshop);
// router.get('/workshops/:id', getWorkshop);

// export default router;

export default router;
// NO POPULATE VERSION
17 changes: 5 additions & 12 deletions api/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,18 @@ dotenv.config({ path: path.resolve(__dirname, "../.env") });
import express from "express";
import bodyParser from "body-parser";
import connectDB from "./config/db";
import { errorHandler } from "./controllers/auth0-errors";
import { notFoundHandler } from "./controllers/auth0-notFound";
import * as routes from "./routes/index";

var cors = require("cors");

const app = express();
app.use(cors());
app.use(cors({ origin: "http://localhost:3000" })); // Connect to the frontend PORT 3000
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use("/user", routes.user);
app.use("/workshop", routes.workshop);

connectDB();

app.use(notFoundHandler);
app.use(errorHandler);
import * as routes from "./routes/index";
app.use("/user", routes.user);
app.use("/api", routes.workshop); // New workshop route

app.listen(process.env.PORT || 8000, () =>
console.log(`Server running on port ${process.env.PORT || 8000}`),
);
app.listen(process.env.PORT || 8000, () => console.log("Server running..."));
2 changes: 1 addition & 1 deletion app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ function App(): ReactElement {
);
}

export default App;
export default App;
4 changes: 2 additions & 2 deletions app/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ const Navbar = (): ReactElement => {
<div
className="Navbar-body-link Margin-left--20"
onClick={() => {
navigate("/mentee")
navigate("/mentee");
}}
>
Mentee
</div>
<div
className="Navbar-body-link Margin-left--20"
onClick={() => {
navigate("/create-workshop")
navigate("/create-workshop");
}}
>
Create Workshop
Expand Down
61 changes: 46 additions & 15 deletions app/src/pages/CreateMeeting.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,48 @@
import React, { useState } from "react";
import { Formik, Form, Field, FieldArray } from "formik";
import React from "react";
import { Formik, Form, Field } from "formik";
import Navbar from "../components/Navbar";
import * as Yup from "yup";
import { api } from "../api"; // Ensure this points to your configured API instance

const initialValues = {
meeting: "",
notes: "",
};

// Validation schema using Yup
const validationSchema = Yup.object().shape({
meeting: Yup.string().required("Meeting name is required"),
notes: Yup.string().required("Meeting notes are required"),
});

const CreateMeeting = () => {
const initialValues = {
meeting: "",
notes: "",
};
const validationSchema = Yup.object().shape({
meeting: Yup.string().required("Please enter a meeting name"),
notes: Yup.string().required("Please enter meeting notes"),
});
const handleSubmit = (values: any) => {
console.log(values);
const handleSubmit = async (
values: any,
{ setSubmitting, resetForm }: any,
) => {
setSubmitting(true);
try {
const payload = {
username: "sample-username", // TODO: Replace with the logged-in user's username
meeting: values.meeting,
notes: values.notes,
};

console.log("Submitting payload:", payload); // Debugging log

await api.post("/user/add-meeting", payload);

alert("Meeting added successfully!");

resetForm(); // Clear the form after successful submission
} catch (error) {
console.error("Error adding meeting:", error);
alert("Failed to add meeting. Please try again.");
} finally {
setSubmitting(false);
}
};

return (
<>
<Navbar />
Expand All @@ -24,10 +52,10 @@ const CreateMeeting = () => {
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({ values, errors, touched, isSubmitting }) => (
{({ errors, touched, isSubmitting }) => (
<Form>
<div className="Form-group">
<label htmlFor="name">Meeting Name</label>
<label htmlFor="meeting">Meeting Name</label>
<Field
type="text"
name="meeting"
Expand All @@ -38,6 +66,7 @@ const CreateMeeting = () => {
<div className="Form-error">{errors.meeting}</div>
)}
</div>

<div className="Form-group">
<label htmlFor="notes">Notes</label>
<Field
Expand All @@ -50,11 +79,13 @@ const CreateMeeting = () => {
<div className="Form-error">{errors.notes}</div>
)}
</div>

<button
type="submit"
className="Button Button-color--dark-1000 Width--100"
disabled={isSubmitting}
>
Create Meeting
{isSubmitting ? "Submitting..." : "Create Meeting"}
</button>
</Form>
)}
Expand Down
Loading

0 comments on commit 4b08d16

Please sign in to comment.