From 1e9939f991b1967256785a5eb64fc99c59f38855 Mon Sep 17 00:00:00 2001
From: Martin Cai
Date: Wed, 1 Oct 2025 20:07:55 -0400
Subject: [PATCH 1/3] random fixes
* fix background on login screen
* update more images + remove mlh checkboxes
* bug: add back notion link to pre-hackathon workshops
* hide sidebar on mobile on back
* fix some validation for "other" options for some question types (#737)
* fix some validation for "other" options for some question types
* sike there was more
---------
Co-authored-by: ErpingS
Co-authored-by: Erping <111095333+ErpingS@users.noreply.github.com>
Co-authored-by: trisha <82386753+tdanielles@users.noreply.github.com>
---
src/components/ApplicationDashboard.jsx | 13 ++++++++--
.../ApplicationForm/ReviewCards.jsx | 24 ++++++++++++-------
.../ApplicationQuestions/MultipleChoice.jsx | 2 +-
src/components/Sidebar.jsx | 10 +++++++-
src/containers/Landing/index.jsx | 2 +-
src/pages/Application/Confirmation.jsx | 1 -
src/utility/Validation.js | 8 ++++++-
7 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/src/components/ApplicationDashboard.jsx b/src/components/ApplicationDashboard.jsx
index 760989e3..5de01688 100644
--- a/src/components/ApplicationDashboard.jsx
+++ b/src/components/ApplicationDashboard.jsx
@@ -229,8 +229,17 @@ export const hackerStatuses = (relevantDates, hackerName = null, activeHackathon
{relevantDates?.offWaitlistNotify} if we find a spot for you, so please check your email
then!
- We are currently at full capacity, but everyone is welcome to attend our pre-hackathon
- workshops.
+ We are currently at full capacity, but everyone is welcome to attend our{' '}
+
+ pre-hackathon workshops
+
+ .
>
),
},
diff --git a/src/components/ApplicationForm/ReviewCards.jsx b/src/components/ApplicationForm/ReviewCards.jsx
index a564f97e..2e7c6b0b 100644
--- a/src/components/ApplicationForm/ReviewCards.jsx
+++ b/src/components/ApplicationForm/ReviewCards.jsx
@@ -226,7 +226,9 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
heading={question.title}
data={
formInputs.basicInfo[question.formInput] === 'other' ||
- formInputs.basicInfo[question.formInput] === 'Other'
+ formInputs.basicInfo[question.formInput] === 'Other' ||
+ formInputs.basicInfo[question.formInput] === 'Other (Please specify)' ||
+ formInputs.basicInfo[question.formInput] === 'Prefer to self-describe'
? formInputs.basicInfo[toOtherCamelCase(question.formInput)]
: formInputs.basicInfo[question.formInput]
}
@@ -259,7 +261,9 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
heading={question.title}
data={
formInputs.skills[question.formInput] === 'other' ||
- formInputs.skills[question.formInput] === 'Other'
+ formInputs.skills[question.formInput] === 'Other' ||
+ formInputs.skills[question.formInput] === 'Other (Please specify)' ||
+ formInputs.skills[question.formInput] === 'Prefer to self-describe'
? formInputs.skills[toOtherCamelCase(question.formInput)]
: formInputs.skills[question.formInput]
}
@@ -292,7 +296,9 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
heading={question.title}
data={
formInputs.questionnaire[question.formInput] === 'other' ||
- formInputs.questionnaire[question.formInput] === 'Other'
+ formInputs.questionnaire[question.formInput] === 'Other' ||
+ formInputs.questionnaire[question.formInput] === 'Other (Please specify)' ||
+ formInputs.questionnaire[question.formInput] === 'Prefer to self-describe'
? formInputs.questionnaire[toCamelCase(question.formInput)]
: formInputs.questionnaire[question.formInput]
}
@@ -310,13 +316,13 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
Terms & conditions
-
+ {/*
š¤
{' '}
{copyText[activeHackathon].hackathonNameShort} is an MLH partner event. The following 3
checkboxes are for this partnership.
-
+
*/}
{
.
-
@@ -370,8 +376,8 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
{' '}
-
- */}
+ {/*
@@ -384,7 +390,7 @@ const ReviewCards = ({ formInputs, handleEdit, onChange }) => {
I authorize MLH to send me occasional emails about relevant events, career
opportunities, and community announcements.
-
+ */}
{activeHackathon === 'cmd-f' && (
diff --git a/src/components/ApplicationQuestions/MultipleChoice.jsx b/src/components/ApplicationQuestions/MultipleChoice.jsx
index ed7cf5d3..25ff1f78 100644
--- a/src/components/ApplicationQuestions/MultipleChoice.jsx
+++ b/src/components/ApplicationQuestions/MultipleChoice.jsx
@@ -29,7 +29,7 @@ const MultipleChoice = ({ refs, errors, formInputs, onChange, question }) => {
{...(refs ? { customRef: refs[`${question.formInput}Ref`] } : {})}
/>
))}
- {(formInputs[question.formInput] === 'Other' ||
+ {(formInputs[question.formInput] === 'Other (Please specify)' ||
formInputs[question.formInput] === 'Prefer to self-describe') && (
-
+ {
+ if (showMobileSidebar) {
+ e.preventDefault()
+ hideSidebarCallback()
+ }
+ }}
+ >
ā BACK
diff --git a/src/containers/Landing/index.jsx b/src/containers/Landing/index.jsx
index 9205ed8a..edf969bc 100644
--- a/src/containers/Landing/index.jsx
+++ b/src/containers/Landing/index.jsx
@@ -64,7 +64,7 @@ const StyledBanner = styled(Banner)`
const BackgroundContainer = styled.img`
height: ${p => (p.hasHeader ? '80%' : '100%')};
width: 100vw;
- object-fit: contain;
+ object-fit: cover;
${p => (!p.hasHeader ? 'object-position: center top;' : '')}
z-index: -1;
position: fixed;
diff --git a/src/pages/Application/Confirmation.jsx b/src/pages/Application/Confirmation.jsx
index 2669a4bf..9028c498 100644
--- a/src/pages/Application/Confirmation.jsx
+++ b/src/pages/Application/Confirmation.jsx
@@ -12,7 +12,6 @@ const Confirmation = () => {
heading="Thanks for Applying!"
description="Stay tuned as we assess your application. Expect to hear from us soon."
showFooter
- hasHeader
showAltBackground
>
diff --git a/src/utility/Validation.js b/src/utility/Validation.js
index faabc6d1..f95e7d59 100644
--- a/src/utility/Validation.js
+++ b/src/utility/Validation.js
@@ -175,7 +175,13 @@ export const validateFormSection = (change, section, fields) => {
(typeof value === 'object' && Object.values(value).includes(true))
) {
// check for other
- if (value.other === true || value === 'Other') {
+ if (
+ value.other === true ||
+ value === 'Other' ||
+ value === 'Other (Please specify)' ||
+ value === 'Prefer to self-describe' ||
+ value === 'other'
+ ) {
if (
!(toOtherCamelCase(key) in change) ||
!validateStringNotEmpty(change[toOtherCamelCase(key)])
From 558a1ef3fa2513995e3715077e367ceb4d206b45 Mon Sep 17 00:00:00 2001
From: trisha <82386753+tdanielles@users.noreply.github.com>
Date: Wed, 1 Oct 2025 18:00:08 -0700
Subject: [PATCH 2/3] selector screen update (#739)
* fix background on login screen
* update more images + remove mlh checkboxes
* bug: add back notion link to pre-hackathon workshops
* hide sidebar on mobile on back
* fix some validation for "other" options for some question types (#737)
* fix some validation for "other" options for some question types
* sike there was more
* update selection screen for hc (#736)
---------
Co-authored-by: martincai8
Co-authored-by: ErpingS
Co-authored-by: Erping <111095333+ErpingS@users.noreply.github.com>
---
src/pages/HackathonSelection.jsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/pages/HackathonSelection.jsx b/src/pages/HackathonSelection.jsx
index 08cbef64..5c48fab6 100644
--- a/src/pages/HackathonSelection.jsx
+++ b/src/pages/HackathonSelection.jsx
@@ -13,7 +13,7 @@ import nwplus_icon from '../assets/nwplus_icon.svg'
import HackathonCard from '../components/HackathonCard'
// one of 'HackCamp', 'nwHacks', 'cmd-f', or null (when we're done for the year)
-const UP_NEXT_HACKATHON_NAME = null
+const UP_NEXT_HACKATHON_NAME = 'HackCamp'
const HackathonSelectionContainer = styled.div`
display: flex;
@@ -119,7 +119,6 @@ export default function HackathonSelection() {
buttonHoverColor={'linear-gradient(90deg, #00DBCE 0%, #00D88A 100%)'}
applicationDeadline={applicationData.deadlines.hackcamp}
applicationOpen={applicationData.openStatuses.hackcamp}
- visitWebsite
/>
Date: Sun, 26 Oct 2025 00:46:25 -0700
Subject: [PATCH 3/3] [HC 2025] dev -> main (#747)
* update charity submission blurb to dynamically pull hackathon name
* [HC2025] update charities (#745)
* update charity submission blurb to dynamically pull hackathon name
* update charities for hackcamp 2025
* fix notion link to public version
* [HC 2025] Add superlative prize submission (#746)
* update charity submission blurb to dynamically pull hackathon name
* add superlative prize submission (hacker view)
* add superlative prize submission (admin view)
---
.../Judging/Admin/SuperlativeSubmissions.jsx | 82 +++++++++++++++++++
src/components/Judging/SubmissionForm.jsx | 65 +++++++++++----
src/containers/JudgingPanel.jsx | 40 ++++++++-
src/utility/firebase.js | 12 +++
4 files changed, 183 insertions(+), 16 deletions(-)
create mode 100644 src/components/Judging/Admin/SuperlativeSubmissions.jsx
diff --git a/src/components/Judging/Admin/SuperlativeSubmissions.jsx b/src/components/Judging/Admin/SuperlativeSubmissions.jsx
new file mode 100644
index 00000000..2f29e308
--- /dev/null
+++ b/src/components/Judging/Admin/SuperlativeSubmissions.jsx
@@ -0,0 +1,82 @@
+import React from 'react'
+import styled from 'styled-components'
+import { StyledCSVLink } from '../../../containers/JudgingPanel'
+import Accordion from '../../Accordion'
+import { CardLike } from '../../Common'
+import { Button } from '../../Input'
+import { H1 } from '../../Typography'
+import { useHackathon } from '../../../utility/HackathonProvider'
+
+const SuperlativePrize = styled.div`
+ ${CardLike};
+ padding: 0.25em 0.5em;
+ margin: 0.5em;
+`
+
+const EntriesList = styled.ul`
+ color: ${p => p.theme.colors.foreground};
+ margin-top: 0;
+ cursor: default;
+`
+
+const LinkContainer = styled.div`
+ padding: 0.5em;
+`
+
+const SuperlativeSubmissions = ({ superlativePrizes }) => {
+ const { activeHackathon } = useHackathon()
+ const getCsvFriendlyData = projects => {
+ const formattedProjects = projects.map(project => {
+ const portalLink = window.location.origin // to support local development as well
+ const projectInfo = {
+ 'Title': project.title,
+ 'Link': `${portalLink}/app/${activeHackathon}/projects/${project.id}`,
+ 'Devpost': project.links.devpost,
+ 'Charity choice': project.charityChoice,
+ }
+ project.teamMembers.forEach((member, index) => {
+ projectInfo[`Member ${index + 1} Name`] = member.name
+ projectInfo[`Member ${index + 1} Email`] = member.email
+ projectInfo[`Member ${index + 1} Discord`] = member.discord
+ })
+ return projectInfo
+ })
+ return formattedProjects
+ }
+
+ return (
+
+
Projects by Superlative Prizes
+ {Object.keys(superlativePrizes).map(
+ (prize, i) =>
+ superlativePrizes[prize].length > 0 && (
+
+
+
+ {superlativePrizes[prize].map((submission, i) => (
+
+ {submission.title}{' '}
+ {submission.draftStatus === 'public' ? 'Published (Submitted)' : 'Draft Only'}
+
+ ))}
+
+
+
+
+ Download CSV
+
+
+
+
+
+ )
+ )}
+
+ )
+}
+
+export default SuperlativeSubmissions
diff --git a/src/components/Judging/SubmissionForm.jsx b/src/components/Judging/SubmissionForm.jsx
index e003eca2..6701912e 100644
--- a/src/components/Judging/SubmissionForm.jsx
+++ b/src/components/Judging/SubmissionForm.jsx
@@ -7,12 +7,13 @@ import {
validateURL,
validateYoutubeURL,
} from '../../utility/Validation'
-import { getSponsorPrizes } from '../../utility/firebase'
+import { getSponsorPrizes, getSuperlativePrizes } from '../../utility/firebase'
import { findElement } from '../../utility/utilities'
import { Button, Dropdown, Select, TextArea, TextInput } from '../Input'
import Toast from '../Toast'
import { A, ErrorMessage, H1, H3, Label, P, ErrorSpan as Required } from '../Typography'
import { useHackathon } from '../../utility/HackathonProvider'
+import { copyText } from '../../utility/Constants'
const FormSection = styled.div`
display: flex;
@@ -69,16 +70,16 @@ const ButtonContainer = styled.div`
const charities = [
{
- value: 'BC Childrenās Hospital',
- label: 'BC Childrenās Hospital',
+ value: 'AMS Food Bank',
+ label: 'AMS Food Bank',
},
{
- value: 'Alzheimer Society of Canada',
- label: 'Alzheimer Society of Canada',
+ value: 'GiveInternet.Org',
+ label: 'GiveInternet.Org',
},
{
- value: 'Nature Trust of British Columbia',
- label: 'Nature Trust of British Columbia',
+ value: 'Michael Cuccione Foundation',
+ label: 'Michael Cuccione Foundation',
},
]
@@ -130,18 +131,27 @@ const SubmissionForm = ({
const [members, setMembers] = useState(project.teamMembers || defaultMembers)
const [links, setLinks] = useState(project.links || {})
const [sponsorPrizes, setSponsorPrizes] = useState([])
+ const [superlativePrizes, setSuperlativePrizes] = useState([
+ 'Most Accessible Design',
+ 'Future Startup',
+ 'Best Pitch',
+ 'Best Hack for Social Good',
+ ])
const [mentorNomination, setMentorNomination] = useState(project.mentorNomination || '')
const [charityChoice, setCharityChoice] = useState(project.charityChoice || '')
const [selectedPrizes, setSelectedPrizes] = useState(project.sponsorPrizes || [])
+ const [superlativeSelectedPrizes, setSuperlativeSelectedPrizes] = useState(
+ project.superlativePrizes || []
+ )
const [draftStatus, setDraftStatus] = useState(project.draftStatus || 'draft')
const [errors, setErrors] = useState({})
const { dbHackathonName } = useHackathon()
- // Fetch list of sponsor prizes from Firebase
+ // Fetch list of sponsor and superlative prizes from Firebase
useEffect(() => {
async function getPrizes() {
- const prizes = await getSponsorPrizes(dbHackathonName)
- setSponsorPrizes(prizes)
+ const sponsorPrizes = await getSponsorPrizes(dbHackathonName)
+ setSponsorPrizes(sponsorPrizes)
}
getPrizes()
}, [dbHackathonName])
@@ -155,6 +165,7 @@ const SubmissionForm = ({
setMentorNomination(project.mentorNomination || '')
setCharityChoice(project.charityChoice || '')
setSelectedPrizes(project.sponsorPrizes || [])
+ setSuperlativeSelectedPrizes(project.superlativePrizes || [])
setDraftStatus(project.draftStatus || 'draft')
const newArray = project.teamMembers ? [...project.teamMembers] : []
@@ -168,6 +179,8 @@ const SubmissionForm = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [project])
+ const { activeHackathon } = useHackathon()
+
const updateMember = (index, field, value) => {
const newMembers = [...members]
newMembers[index][field] = value
@@ -271,6 +284,7 @@ const SubmissionForm = ({
teamMembers: filteredMembers,
links,
sponsorPrizes: selectedPrizes,
+ superlativePrizes: superlativeSelectedPrizes,
charityChoice,
mentorNomination,
uid: project.uid,
@@ -360,17 +374,18 @@ const SubmissionForm = ({
- Every project submitted at HackCamp 2024, regardless of completion, will be eligible for
- a $5 donation to the charity of your choice from a curated list by the HackCamp team!
- This is done so as to emphasize HackCamp's mission of focusing on the learning and
- growth aspect of hackathons!
+ Every project submitted at {copyText[activeHackathon].hackathonName}, regardless of
+ completion, will be eligible for a $5 donation to the charity of your choice from a
+ curated list by the {copyText[activeHackathon].hackathonNameShort} team! This is done so
+ as to emphasize {copyText[activeHackathon].hackathonNameShort}'s mission of focusing on
+ the learning and growth aspect of hackathons!
Click
here
@@ -407,6 +422,26 @@ const SubmissionForm = ({
)}
+ {superlativePrizes && (
+
+ Superlative Prizes
+
+ {superlativePrizes.map(prize => {
+ return (
+
+ setSuperlativeSelectedPrizes(prev => (prev.includes(prize) ? [] : [prize]))
+ }
+ />
+ )
+ })}
+
+
+ )}
Add up to 4 team members
diff --git a/src/containers/JudgingPanel.jsx b/src/containers/JudgingPanel.jsx
index 82829f2f..453a20f8 100644
--- a/src/containers/JudgingPanel.jsx
+++ b/src/containers/JudgingPanel.jsx
@@ -5,11 +5,17 @@ import styled from 'styled-components'
import { Card } from '../components/Common'
import { Button, ToggleSwitch } from '../components/Input'
import SponsorSubmissions from '../components/Judging/Admin/SponsorSubmissions'
+import SuperlativeSubmissions from '../components/Judging/Admin/SuperlativeSubmissions'
import { GradeTable, ProjectGradeTable } from '../components/Judging/Admin/Table'
import ProgressBar from '../components/ProgressBar'
import { H1, H3, P } from '../components/Typography'
import { JUDGING_RUBRIC, PROJECTS_TO_JUDGE_COUNT, calculateGrade } from '../utility/Constants'
-import { getSponsorPrizes, projectsRef, submitGrade } from '../utility/firebase'
+import {
+ getSponsorPrizes,
+ getSuperlativePrizes,
+ projectsRef,
+ submitGrade,
+} from '../utility/firebase'
import { useHackathon } from '../utility/HackathonProvider'
const Columns = styled.div`
@@ -181,6 +187,7 @@ const getGradedProjects = async (dropOutliers = 2, dbHackathonName) => {
const JudgingPanel = () => {
const [sponsorPrizes, setSponsorPrizes] = useState([])
+ const [superlativePrizes, setSuperlativePrizes] = useState([])
const [gradedProjects, setGradedProjects] = useState([])
const [CSVProjectData, setCSVProjectData] = useState([])
const [grades, setGrades] = useState([]) // Individual "grade" objects
@@ -240,6 +247,35 @@ const JudgingPanel = () => {
return prizesToProjectsMap
}
+ const parseSuperlativePrizes = async dbHackathonName => {
+ const superlativePrizes = (await getSuperlativePrizes(dbHackathonName)) || []
+ const projects = (await getProjectData(dbHackathonName)) || []
+
+ const prizesToProjectsMap = {}
+
+ for (let i = 0; i < superlativePrizes.length; i++) {
+ prizesToProjectsMap[superlativePrizes[i]] = []
+ }
+
+ for (let i = 0; i < projects.length; i++) {
+ const project = projects[i]
+
+ // if a project added superlative prize consideration
+ if (project.superlativePrizes && project.superlativePrizes.length > 0) {
+ // for each superlative prize consideration, add this project to the map of projects
+ for (let j = 0; j < project.superlativePrizes.length; j++) {
+ let currentProjectsOfPrize = JSON.parse(
+ JSON.stringify(prizesToProjectsMap[project.superlativePrizes[j]])
+ )
+ currentProjectsOfPrize.push(project)
+ prizesToProjectsMap[project.superlativePrizes[j]] = currentProjectsOfPrize
+ }
+ }
+ }
+
+ return prizesToProjectsMap
+ }
+
const setProjectsAndStats = async () => {
setLoading(true)
setGradedProjects(await getGradedProjects(2, dbHackathonName))
@@ -254,6 +290,7 @@ const JudgingPanel = () => {
const getProjectsByPrizes = async () => {
setSponsorPrizes(await parseSponsorPrizes(dbHackathonName))
+ setSuperlativePrizes(await parseSuperlativePrizes(dbHackathonName))
}
// const [firstTimeStats, setFirstTimeStats] = useState(null)
@@ -342,6 +379,7 @@ const JudgingPanel = () => {
))} */}
+
Grades
{percentageAssigned}% of projects assigned
diff --git a/src/utility/firebase.js b/src/utility/firebase.js
index 146db3aa..62546d9a 100644
--- a/src/utility/firebase.js
+++ b/src/utility/firebase.js
@@ -197,6 +197,18 @@ export const getSponsorPrizes = dbHackathonName => {
})
}
+// Fetch list of superlative prizes
+export const getSuperlativePrizes = dbHackathonName => {
+ return db
+ .collection(DB_COLLECTION)
+ .doc(dbHackathonName)
+ .get()
+ .then(querySnapshot => {
+ console.log('Superlative Prizes:', querySnapshot.data().superlativePrizes)
+ return querySnapshot.data().superlativePrizes
+ })
+}
+
export const createProject = (author, data, dbHackathonName) => {
return projectsRef(dbHackathonName).add({
...data,