Skip to content

Commit

Permalink
up to date with main
Browse files Browse the repository at this point in the history
  • Loading branch information
rosewang01 committed May 22, 2024
2 parents 131b4eb + 1f874e0 commit d20d8c9
Show file tree
Hide file tree
Showing 26 changed files with 179 additions and 379 deletions.
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# Boilerplate

This is a simple boilerplate designed to serve as robust template for quickly starting development on a [Typescript](https://www.typescriptlang.org) based [MERN](https://www.mongodb.com/mern-stack) web application.
This is a web app built for Abuse and Sexual Assault Prevention, a student organization at Penn, as a resource tree for all sexual violence resources at Penn. This is a [Typescript](https://www.typescriptlang.org) based [MERN](https://www.mongodb.com/mern-stack) web application.

## Features

- Session based authentication with [Passport](https://www.passportjs.org)
- Emailing for account verification and resetting password with [SendGrid](https://sendgrid.com)
- Admin functionality for viewing/deleting/promoting other users
- Clean authentication pages built with [Material UI](https://mui.com)
- In memory database testing with [Jest](https://jestjs.io) and [Supertest](https://www.npmjs.com/package/supertest)
- [AirBnb Typescript styling](https://github.com/airbnb/javascript) with [Prettier](https://prettier.io) and [ESLint](https://eslint.org)
- [Husky](https://typicode.github.io/husky/#/) and [lint-staged](https://github.com/okonet/lint-staged) for checking linting on commits
- [GitHub Actions](https://docs.github.com/en/actions) for ensuring linting + tests pass on pushes
- Admin portal with ability to change resources, questions, and answers
- Rich text editor for answer and question changes
- Tree-based data structure in backend
- Private and secure user experience that does not track user data
- Back and Next buttons, as well as ability to see other resources if different answers were selected
- Dictionary and side help bar for unkown terms, filtered based on the words in the question/answer/resource

## Required tools

Expand Down
2 changes: 1 addition & 1 deletion client/src/AdminDashboard/AdminDashboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Typography, Grid } from '@mui/material';
import { Typography, Grid, AppBar } from '@mui/material';
import ScreenGrid from '../components/ScreenGrid';
// import UserTable from './QuestionTable';
import QuestionTable from './QuestionTable';
Expand Down
2 changes: 2 additions & 0 deletions client/src/AdminDashboard/EditQuestionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ function EditQuestionButton({
text: '2x edited answer text 1',
resultantQuestionId: '63751d7cc26b48cf7f1d9724',
resourceContent: '',
resourceLink: '',
};
const tempAnswer2: IAnswer = {
_id: '6369a04ee0cca0b76f26576b',
text: '2x edited answer text 2',
resultantQuestionId: '63751d7cc26b48cf7f1d9724',
resourceContent: '',
resourceLink: '',
};
const tempQuestion: IQuestion = {
_id: '63699fdbe0cca0b76f26576a',
Expand Down
25 changes: 10 additions & 15 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function App() {
<Routes>
{/* Routes accessed only if user is not authenticated */}
<Route element={<UnauthenticatedRoutesWrapper />}>
<Route path="/login" element={<QuestionPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
<Route
path="/verify-account/:token"
Expand All @@ -62,23 +62,20 @@ function App() {
path="/reset-password/:token"
element={<ResetPasswordPage />}
/>
{/* <Route element={<AdminRoutesWrapper />}> */}
<Route path="/users" element={<AdminDashboardPage />} />
{/* </Route> */}
<Route path="/editResource" element={<EditResource />} />
<Route path="/editQuestion" element={<EditQuestion />} />
<Route path="/home" element={<HomePage />} />
<Route path="/question" element={<QuestionPage />} />
</Route>
{/* Routes accessed only if user is authenticated */}
{/* <Route element={<AdminRoutesWrapper />}> */}
<Route element={<ProtectedRoutesWrapper />}>
{/* <Route path="/users" element={<AdminDashboardPage />} /> */}
<Route
path="/admin-dashboard"
element={<AdminDashboardPage />}
/>
<Route path="/users" element={<AdminDashboardPage />} />
<Route path="/editResource" element={<EditResource />} />
<Route path="/editQuestion" element={<EditQuestion />} />
</Route>

{/* Route which redirects to a different page depending on if the user is an authenticated or not by utilizing the DynamicRedirect component */}
<Route
path="/admin-dashboard"
element={<AdminDashboardPage />}
/>
{/* Route which redirects to a different page depending on if the user is an authenticated or not by utilizing the DynamicRedirect component */}
<Route
path="/"
Expand All @@ -89,9 +86,7 @@ function App() {
/>
}
/>
<Route path="/home" element={<HomePage />} />
<Route path="/about" element={<AboutThisProjectPage />} />
<Route path="/question" element={<QuestionPage />} />

{/* Route which is accessed if no other route is matched */}
<Route path="*" element={<NotFoundPage />} />
Expand Down
6 changes: 3 additions & 3 deletions client/src/Authentication/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function LoginPage() {
<FormCol>
<Grid item container justifyContent="center">
<Typography variant="h2" textAlign="center">
Log In
Administrator Log In
</Typography>
</Grid>
<Grid item width="1">
Expand Down Expand Up @@ -177,11 +177,11 @@ function LoginPage() {
Forgot password?
</Link>
</Grid>
<Grid item>
{/* <Grid item>
<Link component={RouterLink} to="/register">
Sign up
</Link>
</Grid>
</Grid> */}
</FormRow>
</FormCol>
</FormGrid>
Expand Down
14 changes: 11 additions & 3 deletions client/src/Home/AboutThisProjectPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ function AboutThisProjectPage() {
direction="row"
justifyContent="space-between"
alignItems="flex-start"
height="100%"
height="100vh"
fit-content="100%"
>
<Grid item width="100%">
<NavBar />
</Grid>

<Grid item width="100%" padding={2} justifyContent="flex-start">
<Grid item width="100%" justifyContent="flex-start">
<Typography variant="h3" fontWeight="bold" textAlign="center">
Guide to Interpersonal Resources at Penn
</Typography>
Expand Down Expand Up @@ -130,7 +130,15 @@ function AboutThisProjectPage() {
</Box>
</Grid>
</Grid>
<Grid item width="100%" alignItems="flex-end" padding={0} spacing={0}>
<Grid
item
width="100%"
alignItems="flex-end"
padding={0}
spacing={0}
position="fixed"
bottom={0}
>
<Footer />
</Grid>
</Grid>
Expand Down
32 changes: 15 additions & 17 deletions client/src/Question/QuestionPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-underscore-dangle */
import React, { useEffect, useState } from 'react';
import { Box } from '@mui/material';
import { Box, CircularProgress } from '@mui/material';
import ScreenGrid from '../components/ScreenGrid';
import QuestionComponent from './QuestionComponent';
import ResourceComponent from './ResourceComponent';
Expand All @@ -10,7 +10,6 @@ import SidebarComponent from '../components/sidebar/SidebarComponent';
import BackButton from './Components/BackButton';
import NextButton from './Components/NextButton';
import StartOverButton from './Components/StartOverButton';
import PopupWarning from '../components/PopupWarning';

/**
* This page is the source of truth for all the state driven interactions of the question system.
Expand All @@ -21,18 +20,9 @@ import PopupWarning from '../components/PopupWarning';
* It also stores an array of "allQuestions" which will be used to handle to "back" functionality
*/
function QuestionPage() {
const initialQuestion = '637ea16cf9860ef25c72e639';
const [currentQuestion, setCurrentQuestion] = useState({
_id: 'Placeholder',
text: '',
isQuestion: true,
resultantAnswers: [],
} as IQuestion);

// const allQuestions: string[] = [initialQuestion];
const [currentQuestion, setCurrentQuestion] = useState({} as IQuestion);
const [questionIndex, setQuestionIndex] = useState(0);
const [allQuestions, setAllQuestions] = useState<string[]>([initialQuestion]);
// const [allAnswers, setAllAnswers] = useState<string[]>([]);
const [allQuestions, setAllQuestions] = useState<string[]>([]);

// Helper functions
const appendQuestion = (value: string) => {
Expand Down Expand Up @@ -109,10 +99,11 @@ function QuestionPage() {
};

useEffect(() => {
if (initialQuestion != null) {
getNextFromID(initialQuestion);
if (allQuestions.length === 0) {
getNextFromID('1');
appendQuestion('1');
}
}, [initialQuestion]);
}, [allQuestions]);

let leftButton = <div />;
if (questionIndex !== 0) {
Expand All @@ -132,6 +123,14 @@ function QuestionPage() {
rightButton = <StartOverButton />;
}

if (!currentQuestion.text) {
return (
<ScreenGrid>
<CircularProgress />
</ScreenGrid>
);
}

if (currentQuestion.isQuestion) {
return (
<ScreenGrid>
Expand Down Expand Up @@ -163,7 +162,6 @@ function QuestionPage() {
{rightButton}
</ScreenGrid>
);
// }
}

export default QuestionPage;
2 changes: 2 additions & 0 deletions client/src/Question/ResourceComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ function ResourceComponent(props: ResourceComponentProps) {
</Typography>
</Grid>
{question.resultantAnswers.map((answer) => {
console.log(answer.resourceContent);
return (
<Grid item margin="auto" marginTop="1%">
<ResourceDropdown
title={answer.text}
content={answer.resourceContent}
link={answer.resourceLink}
/>
</Grid>
);
Expand Down
21 changes: 0 additions & 21 deletions client/src/Question/ResourcePage.tsx

This file was deleted.

7 changes: 4 additions & 3 deletions client/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Box, Button, Stack } from '@mui/material';
import ArrowForward from '@mui/icons-material/ArrowForward';

export default function Footer() {
const params = window.location.pathname;
const isAbout = params === '/about';
return (
<div>
<Stack
Expand All @@ -21,14 +23,13 @@ export default function Footer() {
alt="Penn Logo"
src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Shield_of_the_University_of_Pennsylvania.svg/1200px-Shield_of_the_University_of_Pennsylvania.svg.png"
/>

<Button
color="primary"
size="medium"
endIcon={<ArrowForward />}
href="/about"
href={isAbout ? '/question' : '/about'}
>
About This Project
{isAbout ? 'Ask a Question' : 'About This Project'}
</Button>
</Stack>
</div>
Expand Down
35 changes: 26 additions & 9 deletions client/src/components/ResourceDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useState } from 'react';
import Card from '@mui/material/Card';
import CardHeader from '@mui/material/CardHeader';
import CardContent from '@mui/material/CardContent';
import Container from '@mui/material/Container';
import IconButton from '@mui/material/IconButton';
import Collapse from '@mui/material/Collapse';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
Expand All @@ -13,12 +12,13 @@ import HTMLMapper from './HTMLMapper';

interface ResourceDropdownProps {
title: string;
content: string;
content: string | undefined;
link: string | undefined;
}

export default function ResourceDropdown(props: ResourceDropdownProps) {
const [open, setOpen] = useState(false);
const { title, content } = props;
const { title, content, link } = props;
return (
<Card
sx={{
Expand Down Expand Up @@ -47,13 +47,30 @@ export default function ResourceDropdown(props: ResourceDropdownProps) {
<Collapse in={open} timeout="auto" unmountOnExit>
<CardContent>
<Typography>
<HTMLMapper text={content} />
{content ? <HTMLMapper text={content} /> : ''}
</Typography>
<Grid container justifyContent="flex-end">
<Button variant="text" size="medium">
Learn More
</Button>
</Grid>
{link ? (
<Grid container justifyContent="flex-end">
<Button
variant="text"
size="medium"
onClick={() => {
const newWindow = window.open(
link,
'_blank',
'noopener,noreferrer',
);
if (newWindow) {
newWindow.opener = null;
}
}}
>
Learn More
</Button>
</Grid>
) : (
<div />
)}
</CardContent>
</Collapse>
</div>
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/sidebar/SidebarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default function SidebarContent(props: SidebarProps) {
<div>
<Toolbar />
<List>
<ListItem>
<h1>Definitions</h1>
</ListItem>
{definitions.map((definition) => (
<ListItem>
<SidebarContentItem
Expand Down
5 changes: 3 additions & 2 deletions client/src/util/types/answer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
export interface IAnswer {
_id: string;
text: string;
resourceContent: string;
resultantQuestionId: string;
resourceLink: string | undefined;
resourceContent: string | undefined;
resultantQuestionId: string | undefined;
}
3 changes: 1 addition & 2 deletions server/src/controllers/admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ const getAllQuestions = async (
};

/**
* Upgrade a user to an admin. The email of the user is expected to be in the request body.
* Upon success, return 200 OK status code.
* Edits the text of a question in the database. The new text is expected to be in the request body.
*/
const editQuestionText = async (
req: express.Request,
Expand Down
Loading

0 comments on commit d20d8c9

Please sign in to comment.