Skip to content

Commit

Permalink
merged
Browse files Browse the repository at this point in the history
  • Loading branch information
rosewang01 committed Jun 23, 2024
2 parents 17c04a2 + 5232065 commit 97dc257
Show file tree
Hide file tree
Showing 55 changed files with 6,737 additions and 47,430 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn pre-commit
# yarn pre-commit
2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn pre-push
# yarn pre-push
1 change: 0 additions & 1 deletion .vscode/settings.json

This file was deleted.

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
432 changes: 80 additions & 352 deletions client/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@
"@mui/system": "^5.5.2",
"@reduxjs/toolkit": "^1.8.1",
"axios": "^1.1.2",
"html-to-text": "^9.0.0",
"jodit": "^3.23.1",
"jodit-react": "^1.3.27",
"jodit-react": "^1.3.31",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -55,6 +56,7 @@
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/html-to-text": "^8.1.1",
"@types/jest": "^29.1.2",
"@types/node": "^18.8.3",
"@types/react": "^18.0.21",
Expand Down
1 change: 0 additions & 1 deletion client/src/AdminDashboard/AdminDashboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { Typography, Grid } from '@mui/material';
import ScreenGrid from '../components/ScreenGrid';
// import UserTable from './QuestionTable';
import QuestionTable from './QuestionTable';

/**
Expand Down
51 changes: 13 additions & 38 deletions client/src/AdminDashboard/DeleteQuestionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,45 @@
import React, { useState } from 'react';
import Button from '@mui/material/Button';
import { Navigate, useNavigate } from 'react-router-dom';
import { deleteQuestion, deleteResource } from './api'; // change to deleteQuestion
import { deleteResource } from './api'; // change to deleteQuestion
import LoadingButton from '../components/buttons/LoadingButton';
import ConfirmationModal from '../components/ConfirmationModal';
import { IQuestion } from '../util/types/question';

interface DeleteQuestionButtonProps {
id: string;
isQuestion: boolean;
text: string;
removeRow: (question: string) => void;
question: IQuestion;
removeRow: (question: IQuestion) => void;
}

/**
* The button component which, when clicked, will delete the question from the database.
* If the user is not a valid question, button will be unclickable //this is kinda unnecessary lowkey
* @param id - id of the question to delete
* @param isQuestion - whether the question is valid
* @param text - the text of the question to delete
* @param question - the question to delete
* @param removeRow - a function which removes a row from the question table. This
* function is called upon successfully deletion of user from the database.
*/
function DeleteQuestionButton({
id,
isQuestion,
text,
question,
removeRow,
}: DeleteQuestionButtonProps) {
const navigate = useNavigate();

const [isLoading, setLoading] = useState(false);
async function handleDelete() {
setLoading(true);
if (true) {
// (await deleteQuestion(text)) {//if you comment this out it'll go to the login page but rn this never returns true bc theres no user created that it can delete
removeRow(text);
// go to new page just to check button functionality
navigate('/login');
} else {
setLoading(false);
}
}

async function handleDeleteResource() {
console.log('deleting resource');
console.log(id);
setLoading(true);
if (true) {
await deleteResource(id);
removeRow(text);
} else {
setLoading(false);
}
await deleteResource(id);
removeRow(question);
setLoading(false);
}
if (isLoading) {
return <LoadingButton />;
}
if (isQuestion) {
// valid question
if (question.isQuestion) {
return (
<ConfirmationModal
buttonText="Remove Question"
title="Are you sure you want to remove this question?"
body="This action is permanent. Question information will not be able to be recovered."
onConfirm={() => handleDelete()}
/>
<Button variant="outlined" disabled>
Delete Question
</Button>
);
}
// resource
Expand Down
76 changes: 25 additions & 51 deletions client/src/AdminDashboard/EditQuestionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,47 @@
import React, { useState } from 'react';
import Button from '@mui/material/Button';
import { Navigate, useNavigate } from 'react-router-dom';
import { editQuestion } from './api';
import { Navigate, useNavigate, Link } from 'react-router-dom';
import LoadingButton from '../components/buttons/LoadingButton';
import ConfirmationModal from '../components/ConfirmationModal';
import { IQuestion } from '../util/types/question';

interface EditQuestionButtonProps {
qID: string;
isQuestion: boolean;
text: string;
editRow: (qID: string, question: string, newText: string) => void;
question: IQuestion;
}

/**
* The button component which, when clicked, will edit the question from the database.
* If the user is not a valid question, button will be unclickable //this is kinda unnecessary lowkey
* @param isQuestion - whether the question is valid
* @param text - the text of the question to edit
* @param editRow - a function which edits a row from the question table. should be called after editing the user
* @param question - the question to edit
* data in the database if put data works right lol
*/
function EditQuestionButton({
qID,
isQuestion,
text,
editRow,
}: EditQuestionButtonProps) {
function EditQuestionButton({ question }: EditQuestionButtonProps) {
const navigate = useNavigate();

const questionVals = {
'63699fdbe0cca0b76f26576a': 'updated question text',
};
const answerVals = {
'6369a04ee0cca0b76f26576b': 'lalalala',
'6369a05ce0cca0b76f26576c': 'hehehehehe',
};

const [isLoading, setLoading] = useState(false);
async function handleEdit() {
setLoading(true);
// edit question needs to take in new text that user has typed in
if (await editQuestion(questionVals, answerVals)) {
// navigate('/newquestion'); // go to create new question page
// const newtext = newquestionpage.getData(); //this isnt real, but //click save in newquestion page; should return new text data
// editRow(text, newtext); //basically just deletes the row for now
// overwrite current row text
console.log('hi');
} else {
setLoading(false);
}
}
if (isLoading) {
return <LoadingButton />;
}
if (isQuestion) {
if (question.isQuestion) {
// valid question
return (
<ConfirmationModal
buttonText="Edit Question"
title="Are you sure you want to edit this question?"
body="This action is permanent. Question information will not be able to be recovered."
onConfirm={() => handleEdit()}
/>
<div>
<Link
to="/editQuestion"
state={{ question }}
style={{ textDecoration: 'none' }}
>
<Button variant="outlined">Edit Question</Button>
</Link>
</div>
);
}

return (
<Button variant="outlined" disabled>
Question is Invalid
</Button>
<div>
<Link
to="/editResource"
state={{ question }}
style={{ textDecoration: 'none' }}
>
<Button variant="outlined">Edit Resource</Button>
</Link>
</div>
);
}

Expand Down
Loading

0 comments on commit 97dc257

Please sign in to comment.