From 8aae8bf312e2f1331add281fabcb4d237d986413 Mon Sep 17 00:00:00 2001 From: Ryan Fernandes Date: Wed, 9 Apr 2025 00:55:17 -0400 Subject: [PATCH 1/8] y/labs tutorial video for professors (#29) --- client/src/components/accounts/YoutubeVideo.tsx | 9 +++++++++ client/src/pages/account.tsx | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 client/src/components/accounts/YoutubeVideo.tsx diff --git a/client/src/components/accounts/YoutubeVideo.tsx b/client/src/components/accounts/YoutubeVideo.tsx new file mode 100644 index 0000000..feece32 --- /dev/null +++ b/client/src/components/accounts/YoutubeVideo.tsx @@ -0,0 +1,9 @@ +function YoutubeVideo() { + return ( +
+ +
+ ) +} + +export default YoutubeVideo; \ No newline at end of file diff --git a/client/src/pages/account.tsx b/client/src/pages/account.tsx index 98b0363..d4d4175 100644 --- a/client/src/pages/account.tsx +++ b/client/src/pages/account.tsx @@ -10,6 +10,7 @@ import PulseLoader from "react-spinners/PulseLoader"; import { useContext } from "react"; import UserContext from "../contexts/UserContext"; import CreateButton from "../components/accounts/CreateButton"; +import YoutubeVideo from "../components/accounts/YoutubeVideo"; const Account = () => { const [ownListings, setOwnListings] = useState([]); @@ -297,6 +298,16 @@ const Account = () => { ) : (

No listings found.

)} + + {user && (user.userType === "professor" || user.userType === "faculty" || user.userType === "admin") && ( + <> +
+

Learn y/labs!

+
+ +
+ + )} {/* Modal */} {selectedListing && ( From eea5bcd9211a5c3669a1712a91f4027b65d6b141 Mon Sep 17 00:00:00 2001 From: Ryan Fernandes Date: Fri, 18 Apr 2025 00:07:31 -0400 Subject: [PATCH 2/8] Form changes - added ability to add collaborators (tested sharing), reordered form options, added stars, changed defaults, info text (#31) --- .../ListingForm/FormFields/ArrayInput.tsx | 9 +++- .../FormFields/DepartmentInput.tsx | 13 +++++- .../ListingForm/FormFields/HiringStatus.tsx | 2 +- .../components/accounts/ListingForm/index.tsx | 44 +++++++++++++++---- .../accounts/ListingForm/utils/validation.ts | 20 +++++++++ client/src/utils/apiCleaner.ts | 2 +- 6 files changed, 77 insertions(+), 13 deletions(-) diff --git a/client/src/components/accounts/ListingForm/FormFields/ArrayInput.tsx b/client/src/components/accounts/ListingForm/FormFields/ArrayInput.tsx index 94b68ec..5b4deff 100644 --- a/client/src/components/accounts/ListingForm/FormFields/ArrayInput.tsx +++ b/client/src/components/accounts/ListingForm/FormFields/ArrayInput.tsx @@ -13,6 +13,7 @@ interface ArrayInputProps { type?: string; permanentValue?: string; onValidate?: (newArray: string[]) => void; + infoText?: string; } const ArrayInput = ({ @@ -26,7 +27,8 @@ const ArrayInput = ({ error, type = "text", permanentValue, - onValidate + onValidate, + infoText }: ArrayInputProps) => { const inputRef = useRef(null); const [showTooltip, setShowTooltip] = useState(false); @@ -133,6 +135,11 @@ const ArrayInput = ({ + {infoText && ( +
+ {infoText} +
+ )}
{renderItems()}
diff --git a/client/src/components/accounts/ListingForm/FormFields/DepartmentInput.tsx b/client/src/components/accounts/ListingForm/FormFields/DepartmentInput.tsx index 4059fb6..c45b490 100644 --- a/client/src/components/accounts/ListingForm/FormFields/DepartmentInput.tsx +++ b/client/src/components/accounts/ListingForm/FormFields/DepartmentInput.tsx @@ -96,8 +96,19 @@ const DepartmentInput = ({ return (
+
+ Don't see your department? Let us know{" "} + + here + +
{departments.map((department, index) => ( {/* Button/display */} diff --git a/client/src/components/accounts/ListingForm/index.tsx b/client/src/components/accounts/ListingForm/index.tsx index d0e7b99..ce60fbd 100644 --- a/client/src/components/accounts/ListingForm/index.tsx +++ b/client/src/components/accounts/ListingForm/index.tsx @@ -11,8 +11,10 @@ import ArrayInput from './FormFields/ArrayInput'; import DepartmentInput from './FormFields/DepartmentInput'; import HiringStatus from './FormFields/HiringStatus'; import { validateTitle, validateDescription, validateEstablished, - validateProfessors, validateEmails, validateWebsites } from './utils/validation'; + validateProfessors, validateEmails, validateWebsites, validateProfessorIds } from './utils/validation'; import { createListing } from '../../../utils/apiCleaner'; +import { useContext } from "react"; +import UserContext from "../../../contexts/UserContext"; interface ListingFormProps { listing: NewListing; @@ -30,6 +32,7 @@ const ListingForm = ({ listing, isCreated, onLoad, onCancel, onSave, onCreate }: const [ownerName, setOwnerName] = useState(`${listing.ownerFirstName} ${listing.ownerLastName}`); const [departments, setDepartments] = useState([...listing.departments]); const [availableDepartments, setAvailableDepartments] = useState([]); + const [professorIds, setProfessorIds] = useState([...listing.professorIds]); const [emails, setEmails] = useState([...listing.emails]); const [ownerEmail, setOwnerEmail] = useState(listing.ownerEmail); const [websites, setWebsites] = useState(listing.websites ? [...listing.websites] : []); @@ -39,12 +42,16 @@ const ListingForm = ({ listing, isCreated, onLoad, onCancel, onSave, onCreate }: const [hiringStatus, setHiringStatus] = useState(listing.hiringStatus); const [archived, setArchived] = useState(listing.archived); const [loading, setLoading] = useState(true); + + const { user } = useContext(UserContext); + const isOwner = user && (user.netId === listing.ownerId); // Form errors const [errors, setErrors] = useState<{ title?: string; description?: string; established?: string; + professorIds?: string; professorNames?: string; emails?: string; websites?: string; @@ -120,6 +127,7 @@ const ListingForm = ({ listing, isCreated, onLoad, onCancel, onSave, onCreate }: description: validateDescription(description), established: validateEstablished(established), professorNames: validateProfessors([ownerName, ...professorNames]), + professorIds: validateProfessorIds(professorIds), emails: validateEmails([ownerEmail, ...emails]), websites: validateWebsites(websites) }; @@ -137,6 +145,7 @@ const ListingForm = ({ listing, isCreated, onLoad, onCancel, onSave, onCreate }: const updatedListing: NewListing = { ...listing, title, + professorIds, professorNames, departments, emails, @@ -179,7 +188,6 @@ const ListingForm = ({ listing, isCreated, onLoad, onCancel, onSave, onCreate }: const handleCancel = () => { - console.log("CANCELLED LOL") if (isCreated) { swal({ title: "Delete Listing", @@ -244,7 +252,7 @@ const handleCancel = () => {
{