Skip to content
Snippets Groups Projects
Commit 9661aacf authored by hannahl8's avatar hannahl8
Browse files

update lab on OpeningsPopupForm.tsx to be the professors lab rather than having them select it

Update click tabs in header/footer refreshes content
update confetti and updated message on confirmation page
parent b04d060f
No related branches found
No related tags found
No related merge requests found
Pipeline #10829 canceled
......@@ -9,6 +9,7 @@ Installs in the project:
4. Run `npm install formik --save` to install formik
5. Run `npm install yup --save` to install yup
6. Run `npm install react-confetti` to install confetti
7. Run `npm i --save-dev @types/canvas-confetti` to install types for confetti
# React + TypeScript + Vite
......
......@@ -13,6 +13,7 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@types/axios": "^0.14.0",
"axios": "^1.7.2",
"canvas-confetti": "^1.9.3",
"formik": "^2.4.6",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
......@@ -21,6 +22,7 @@
"yup": "^1.4.0"
},
"devDependencies": {
"@types/canvas-confetti": "^1.6.4",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
......@@ -1398,6 +1400,13 @@
"@babel/types": "^7.20.7"
}
},
"node_modules/@types/canvas-confetti": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.6.4.tgz",
"integrity": "sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
......@@ -1850,6 +1859,16 @@
],
"license": "CC-BY-4.0"
},
"node_modules/canvas-confetti": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz",
"integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==",
"license": "ISC",
"funding": {
"type": "donate",
"url": "https://www.paypal.me/kirilvatev"
}
},
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
......
......@@ -15,6 +15,7 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@types/axios": "^0.14.0",
"axios": "^1.7.2",
"canvas-confetti": "^1.9.3",
"formik": "^2.4.6",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
......@@ -23,6 +24,7 @@
"yup": "^1.4.0"
},
"devDependencies": {
"@types/canvas-confetti": "^1.6.4",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
......
......@@ -10,6 +10,8 @@ import {
import {useUserContext} from "../contexts/UserContext.tsx";
import {useStudentUserContext} from "../contexts/StudentUserContext.tsx";
import {useProfessorUserContext} from "../contexts/ProfessorUserContext.tsx";
import {useOpeningsContext} from "../contexts/OpeningsContext.tsx";
import {useDiscussionContext} from "../contexts/DiscussionContext.tsx";
export default function AppFooter() {
const {token, role} = useUserContext();
......@@ -23,6 +25,16 @@ export default function AppFooter() {
fullName = `${professor?.firstName} ${professor?.lastName}`;
}
const {refreshOpenings} = useOpeningsContext();
function handleOpeningsClick() {
refreshOpenings();
}
const {refreshDiscussions} = useDiscussionContext();
function handleDiscussionsClick() {
refreshDiscussions("");
}
return (
<footer className="container">
<section className="links">
......@@ -31,8 +43,8 @@ export default function AppFooter() {
) : (
<>
<Link to={labsPagePath}>LABS</Link> | <Link
to={openingsPagePath}>OPENINGS</Link> | <Link
to={discussionPagePath}>DISCUSSION</Link> | <Link
to={openingsPagePath} onClick={handleOpeningsClick}>OPENINGS</Link> | <Link
to={discussionPagePath} onClick={handleDiscussionsClick}>DISCUSSION</Link> | <Link
to={`${profilePagePath}/${role}/${fullName}`}>PROFILE</Link>
</>
)}
......
......@@ -12,6 +12,8 @@ import {
import {useUserContext} from "../contexts/UserContext.tsx";
import {useStudentUserContext} from "../contexts/StudentUserContext.tsx";
import {useProfessorUserContext} from "../contexts/ProfessorUserContext.tsx";
import {useOpeningsContext} from "../contexts/OpeningsContext.tsx";
import {useDiscussionContext} from "../contexts/DiscussionContext.tsx";
export default function AppHeader() {
const {token, setToken, role, setRole, setEmail} = useUserContext();
......@@ -31,6 +33,16 @@ export default function AppHeader() {
setEmail(NO_EMAIL);
};
const {refreshOpenings} = useOpeningsContext();
function handleOpeningsClick() {
refreshOpenings();
}
const {refreshDiscussions} = useDiscussionContext();
function handleDiscussionsClick() {
refreshDiscussions("");
}
return (
<header className="header container">
......@@ -52,8 +64,8 @@ export default function AppHeader() {
{(token !== NO_TOKEN) && (role === STUDENT_ROLE || role === PROFESSOR_ROLE || role === ADMIN_ROLE) &&
<>
<NavLink to={labsPagePath}><i className="fa-solid fa-flask"></i> LABS</NavLink>
<NavLink to={openingsPagePath}><i className="fa-solid fa-door-open"></i> OPENINGS</NavLink>
<NavLink to={discussionPagePath}><i className="fa-solid fa-comments"></i> DISCUSSION</NavLink>
<NavLink to={openingsPagePath} onClick={handleOpeningsClick}><i className="fa-solid fa-door-open"></i> OPENINGS</NavLink>
<NavLink to={discussionPagePath} onClick={handleDiscussionsClick}><i className="fa-solid fa-comments"></i> DISCUSSION</NavLink>
</>
}
{/*Professors and Students see a PROFILE page*/}
......
import {object, string, ValidationError} from "yup";
import {useResearchLabContext} from "../contexts/ResearchLabContext.tsx";
import {Form, Formik, FormikHelpers} from "formik";
import TextInput from "./form/TextInput.tsx";
import {SelectInput} from "./form/SelectInput.tsx";
import './PopupForm.css';
import React from "react";
import {RadioInput} from "./form/RadioInput.tsx";
......@@ -35,7 +33,6 @@ const initialValues: FormData = {
const OpeningsPopupForm: React.FC<FormPopupProps> = ({onClose, onCreate}) => {
const {professor} = useProfessorUserContext();
const {labs} = useResearchLabContext();
const validationSchema = object({
name: string()
......@@ -47,12 +44,7 @@ const OpeningsPopupForm: React.FC<FormPopupProps> = ({onClose, onCreate}) => {
.required("The Opening type is required."),
url: string()
.required("The URL to the opening is required.")
.url("Please enter a valid URL."),
labName: string()
.required("You can only add an opening for your lab!")
.test('is-professor-lab', 'You can only add an opening for your lab!', function (value) {
return value === professor?.lab?.name;
})
.url("Please enter a valid URL.")
})
const handleSubmit = async (
......@@ -63,14 +55,13 @@ const OpeningsPopupForm: React.FC<FormPopupProps> = ({onClose, onCreate}) => {
if (result instanceof ValidationError) {
actions.setSubmitting(false);
} else {
const selectedLab = labs.find(lab => lab.name === values.labName)
if (professor) {
const sendingData = {
name: values.name,
description: values.description,
type: values.type,
url: values.url,
labName: selectedLab ? selectedLab.name : '',
labName: professor.lab.name,
professor: professor
}
onCreate(sendingData);
......@@ -102,9 +93,9 @@ const OpeningsPopupForm: React.FC<FormPopupProps> = ({onClose, onCreate}) => {
<RadioInput label="Paid" name="type" value="Paid"/>
<RadioInput label="Volunteer" name="type" value="Volunteer"/>
</div>
<TextInput label="URL to Apply" name="url"/>
<SelectInput label="Research Lab:" name="labName" options={labs} valueKey="name"></SelectInput>
<TextInput label="Research Lab" name="labName" disabled={true}
value={professor?.lab?.name || ''}/>
<button type="submit" className="primary-button">CREATE</button>
</Form>
</Formik>
......
import React from 'react';
import { Field, ErrorMessage } from 'formik';
import {Field, ErrorMessage} from 'formik';
interface TextInputProps {
label: string;
name: string;
type?: string;
disabled?: boolean;
value?: string;
}
export const TextInput: React.FC<TextInputProps> = ({ label, name, type = 'text' }) => {
export const TextInput: React.FC<TextInputProps> = ({label, name, type = 'text', disabled = false, value}) => {
return (
<>
<div>
<label htmlFor={name}>{label}:</label>
{type === 'textarea' ? (
<Field as="textarea" name={name} />
) : (
<Field type={type} name={name} />
)}
</div>
<ErrorMessage className="field-error" name={name} component="span" />
<div>
<label htmlFor={name}>{label}:</label>
{type === 'textarea' ? (
<Field as="textarea" name={name} disabled={disabled} value={value}/>
) : (
<Field type={type} name={name} disabled={disabled} value={value}/>
)}
</div>
<ErrorMessage className="field-error" name={name} component="span"/>
</>
);
};
......
import { useEffect, useState } from 'react';
import Confetti from 'react-confetti';
import { useNavigate } from 'react-router-dom';
import {useEffect, useState} from 'react';
import confetti from "canvas-confetti";
import {Link, useNavigate} from 'react-router-dom';
import {loginPagePath} from "../utils.ts";
export default function SignUpConfirmationPage() {
const navigate = useNavigate();
......@@ -21,16 +22,55 @@ export default function SignUpConfirmationPage() {
return () => clearInterval(timer);
}, [navigate, countdown]);
useEffect(() => {
const duration = 30 * 1000; // 10 seconds
const end = Date.now() + duration;
const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim();
const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--secondary-color').trim();
const tertiaryColor = getComputedStyle(document.documentElement).getPropertyValue('--tertiary-color').trim();
let animationFrameId: number;
const frame = () => {
confetti({
particleCount: 3,
angle: 60,
spread: 55,
origin: {x: 0},
colors: [primaryColor, secondaryColor, tertiaryColor]
});
confetti({
particleCount: 3,
angle: 120,
spread: 55,
origin: {x: 1},
colors: [primaryColor, secondaryColor, tertiaryColor]
});
if (Date.now() < end) {
animationFrameId = requestAnimationFrame(frame);
}
};
frame();
return () => {
cancelAnimationFrame(animationFrameId);
};
}, []);
return (
<div className='signup-confirmation-page center-content'>
<Confetti/>
<h1>Thank you for signing up with VT Research Connect!</h1>
<img src="/site-images/logo.png"
alt="VT Research Connect Logo"
style={{width: '150px', margin: '0 auto', display: 'block'}}/>
<h1>An email confirmation link has been sent to your email.</h1>
<h1>You must confirm the link in your email before signing in.</h1>
<h1>You will be redirected to the login page in {countdown} seconds.</h1>
<h1>Please check your Junk or Spam folders if the email isn't in your Inbox!</h1>
<h1>You will be redirected to the <Link to={loginPagePath} className="tertiary-button-other">Login
Page</Link> in {countdown} seconds.</h1>
</div>
);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment