Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions app/(pages)/(hackers)/_components/PrizeTracks/PrizeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import Image from 'next/image';
import { useState } from 'react';
import { ChevronDown } from 'lucide-react';
import { ChevronDown, ExternalLink } from 'lucide-react';

import Accordion from '@mui/material/Accordion';
import AccordionDetails from '@mui/material/AccordionDetails';
Expand All @@ -13,13 +13,15 @@ interface PrizeCardProps {
prizeImages: StaticImport[];
prizeNames: string[];
criteria: string;
criteriaLink?: string;
}

export default function PrizeCard({
name,
prizeImages,
prizeNames,
criteria,
criteriaLink,
}: PrizeCardProps) {
const [expanded, setExpanded] = useState<boolean>(false);

Expand Down Expand Up @@ -120,10 +122,21 @@ export default function PrizeCard({
</div>
</AccordionSummary>
<AccordionDetails sx={{ padding: '0px' }}>
<div className="flex items-center px-[5%] md:px-[2.5%] pb-[5%] md:pb-[3%]">
<div className="flex flex-col gap-3 px-[5%] md:px-[2.5%] pb-[5%] md:pb-[3%]">
<p className="text-sm md:text-base xl:text-xl font-normal leading-[125%] whitespace-pre-line">
{criteria || 'Check back in May!'}
</p>
{criteriaLink && (
<a
href={criteriaLink}
target="_blank"
rel="noopener noreferrer"
className="text-sm md:text-base xl:text-xl font-medium text-[#005271] underline cursor-pointer"
>
View full track details{' '}
<ExternalLink className="inline h-5 w-5 mb-0.5" />
</a>
)}
</div>
</AccordionDetails>
</Accordion>
Expand Down
3 changes: 2 additions & 1 deletion app/(pages)/(hackers)/_components/PrizeTracks/PrizeGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export default function PrizeGrid({ items }: { items: TrackData[] }) {
return (
<PrizeCard
key={item.name}
name={item.name}
name={item.displayName ?? item.name}
prizeNames={item.prizes}
prizeImages={item.images}
criteria={item.eligibility_criteria}
criteriaLink={item.eligibility_link}
/>
);
})}
Expand Down
3 changes: 2 additions & 1 deletion app/_data/db_validation_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"Best Use of Backboard",
"Best Use of Vultr",
"Best Use of MongoDB Atlas",
"Best Domain Name from GoDaddy Registry"
"Best Domain Name from GoDaddy Registry",
"Best use of Reconstruct"
]
}
41 changes: 29 additions & 12 deletions app/_data/tracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ import portableScreens from '@public/prizes/portableScreens.png';
import m5StackIotKit from '@public/prizes/m5StackIotKit.png';
import digitalGiftCard from '@public/prizes/digitalGiftCard.png';
import sonyHeadphones from '@public/prizes/sony_headphones.webp';
import datalab from '@public/prizes/datalab.png';
// import datalab from '@public/prizes/datalab.png';

interface TrackData {
name: string;
displayName?: string;
filter: string[];
prizes: string[];
images: StaticImport[];
eligibility_criteria: string;
eligibility_link?: string;
domain?: string;
domainDisplayName?: string;
scoring_criteria?: {
Expand Down Expand Up @@ -402,6 +404,7 @@ const optedHDTracks: Tracks = {
const nonHDTracks: Tracks = {
'Best AI/ML Hack': {
name: 'Best AI/ML Hack',
displayName: 'Best AI/ML Hack (Sponsored by Anthropic)',
filter: ['Sponsor', 'Technical'],
prizes: ['$750 in Claude API credits'],
images: [claudeLogo],
Expand Down Expand Up @@ -438,11 +441,12 @@ const nonHDTracks: Tracks = {
},
'Best UI/UX Design': {
name: 'Best UI/UX Design',
displayName: 'Best UI/UX Design (Sponsored by Figma)',
filter: ['Sponsor', 'Design'],
prizes: ['Sony WH-1000XM5 Wireless Noise-Canceling Headphones'],
images: [sonyHeadphones],
eligibility_criteria:
'Project includes beautiful design and intuitive web experiences that bring joy to users. Shows that the project is not only functional but also delightful, demonstrates wireframing in Figma, responsive design and promotes intuitive user experiences.\n\nSponsored by Figma.',
'Project uses Figma to create beautiful design and intuitive web experiences that bring joy to users. Shows that the project is not only functional but also delightful, demonstrates wireframing in Figma, responsive design and promotes intuitive user experiences.\n\nSponsored by Figma.',
domain: 'design',
domainDisplayName: 'UI/UX Design',
scoring_criteria: [
Expand Down Expand Up @@ -474,12 +478,33 @@ const nonHDTracks: Tracks = {
},
'Best Use of DAC Materials': {
name: 'Best Use of DAC Materials',
displayName: 'Best Use of DAC Materials (Sponsored by Davis Autonomy Club)',
filter: ['Sponsor', 'Technical'],
prizes: ['$10,000 Daytona infrastructure credits'],
images: [daytona],
eligibility_criteria:
"Project must incorporate one or more of DAC's materials with a vision-based AI pipeline, implementing and/or configuring concepts such as Vision-Language Models (VLMs) or Vision-Language-Action Models (VLAs) to connect real-world visual perception to physical robotic behavior.\n\nSponsored by the Davis Autonomy Club.",
},
// 'Best Open Data Hack': {
// name: 'Best Open Data Hack',
// displayName: 'Best Open Data Hack (Sponsored by DataLab)',
// filter: ['Sponsor', 'Technical'],
// prizes: ['DataLab Internship'],
// images: [datalab],
// eligibility_criteria:
// "Teams must identify a question or topic that, when addressed, produces an insight or product that promotes social good for the UC Davis community. To qualify for this challenge, you must find and use one or more Open and Publicly Accessible Datasets to complete your hack. Finding and appropriately using the right data to address your question or topic is one of the biggest hurdles in data science.\n\nYou must follow the guidelines provided at the link below to be eligible for this track.\n\nWinners receive:\n• The Spotlight: Your visualization will be professionally printed and permanently displayed in the DataLab at Shields Library.\n• An invitation to present your work at DataLab's talk series.\n• A spot in DataLab's summer mentored Internship Program (non-paid) to jumpstart your career, where you'll work alongside expert data scientists to level up your portfolio.\n\nSponsored by DataLab.",
// eligibility_link:
// 'https://docs.google.com/document/d/143apy8JsrJ4VYwxiI-bu2kNPAyL-1f2FweM9gpgXZFM/edit?tab=t.0',
// },
'Best use of Reconstruct': {
name: 'Best use of Reconstruct',
displayName: 'Best use of Reconstruct (Sponsored by Reconstruct)',
filter: ['Sponsor', 'Technical'],
prizes: ['$125 Visa Gift Card per team member'],
images: [digitalGiftCard],
eligibility_criteria:
'Most creative use of Rescontruct in their project. Project must use Reconstruct in a prominant and efficient way to qualify for this prize track.\n\nSponsored by Reconstruct.',
},
"Best Hack for Women's Center": {
name: "Best Hack for Women's Center",
filter: ['Non-Profit'],
Expand All @@ -488,14 +513,6 @@ const nonHDTracks: Tracks = {
eligibility_criteria:
'Projects must create a digital system to track donations as they come in and go out. Wellspring is looking for a straightforward, easy-to-use digital tool that helps staff and volunteers quickly log donated items, track how they are distributed, and generate basic reports when needed.',
},
'Best Open Data Hack': {
name: 'Best Open Data Hack',
filter: ['Sponsor', 'Technical'],
prizes: ['DataLab Internship'],
images: [datalab],
eligibility_criteria:
"Teams must identify a question or topic that, when addressed, produces an insight or product that promotes social good for the UC Davis community. To qualify for this challenge, you must find and use one or more Open and Publicly Accessible Datasets to complete your hack. Finding and appropriately using the right data to address your question or topic is one of the biggest hurdles in data science.\n\nThe Spotlight:\n• Your visualization will be professionally printed and permanently displayed in the DataLab at Shields Library.\n• An invitation to present your work at DataLab's talk series.\n• A spot in DataLab's summer mentored Internship Program (non-paid) to jumpstart your career, where you'll work alongside expert data scientists to level up your portfolio.\n\nSponsored by DataLab.",
},
// 'Best Hack for ASUCD Pantry': {
// name: 'Best Hack for ASUCD Pantry',
// filter: 'Non-Profit',
Expand Down Expand Up @@ -534,7 +551,7 @@ const nonHDTracks: Tracks = {
prizes: ['Tile Essentials Pack'],
images: [tileEssentialsPack],
eligibility_criteria:
"Every AI model API is stateless by default. That means your app forgets everything the second a session ends. State management should be the first step of any AI build, regardless of what LLM you are using, and Backboard gives you that for free. But Backboard is not just state management. It is a single, unified API built on the world's #1 AI memory that gives you everything you need in one place: long-term memory, RAG, embeddings, tool calls, model routing across 17,000+ LLMs, and persistent context that stays alive across every page refresh, session, and user. No stitching together five different services. One API. One integration. Built on the best memory in AI.\n\nHere's just a small list of things Backboard can make possible for your AI app!\n\n• AI-powered Travel Guide: Remembers allergies and preferences from past trips.\n• Personalized Fitness Coach: Adjusts workouts based on progress and injury history.\n• Smart Home Controller: Learns routines over time to anticipate lighting and climate preferences!\n\nUse Backboard to build a seamless, persistent user experience without the usual infrastructure headache! Each winning team member will receive a Tiles Essentials Pack because, just like AI, we all need an occasional reminder of where things are!\n\nJudged by MLH.",
"Every AI model API is stateless by default. That means your app forgets everything the second a session ends. State management should be the first step of any AI build, regardless of what LLM you are using, and Backboard gives you that for free. But Backboard is not just state management. It is a single, unified API built on the world's #1 AI memory that gives you everything you need in one place: long-term memory, RAG, embeddings, tool calls, model routing across 17,000+ LLMs, and persistent context that stays alive across every page refresh, session, and user. No stitching together five different services. One API. One integration. Built on the best memory in AI.\n\nHere's just a small list of things Backboard can make possible for your AI app!\n• AI-powered Travel Guide: Remembers allergies and preferences from past trips.\n• Personalized Fitness Coach: Adjusts workouts based on progress and injury history.\n• Smart Home Controller: Learns routines over time to anticipate lighting and climate preferences!\n\nUse Backboard to build a seamless, persistent user experience without the usual infrastructure headache! Each winning team member will receive a Tiles Essentials Pack because, just like AI, we all need an occasional reminder of where things are!\n\nJudged by MLH.",
},
'Best Use of Vultr': {
name: 'Best Use of Vultr',
Expand All @@ -558,7 +575,7 @@ const nonHDTracks: Tracks = {
prizes: ['Digital Gift Card'],
images: [digitalGiftCard],
eligibility_criteria:
'GoDaddy Registry is giving you everything you need to be the best hacker no matter where you are. Register your domain name with GoDaddy Registry for a chance to win some amazing prizes! \n\nJudged by MLH.',
'GoDaddy Registry is giving you everything you need to be the best hacker no matter where you are. Register your domain name with GoDaddy Registry for a chance to win some amazing prizes!\n\nJudged by MLH.',
},
};

Expand Down
109 changes: 109 additions & 0 deletions migrations/20260506000000-add-2026-tracks.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import fs from 'fs';
import path from 'path';

const dataPath = path.resolve(
process.cwd(),
'app/_data/db_validation_data.json'
);
const data = JSON.parse(fs.readFileSync(dataPath, 'utf8'));
const tracks = [...new Set(data.tracks)];

// Track list as of commit 52684b55 (2025 tracks)
const previousTracks = [
'Best Hack for Social Good',
'Best Beginner Hack',
'Best Interdisciplinary Hack',
'Most Creative Hack',
'Best Hack for Social Justice',
'Best Hardware Hack',
'Most Technically Challenging Hack',
'Best Open Data Hack',
'Best AI/ML Hack',
'Best UI/UX Design',
'Best User Research',
'Best Statistical Model',
'Best Medical Hack',
'Best Entrepreneurship Hack',
"Hacker's Choice Award",
'Best Hack for California GovOps Agency',
'Best Hack for NAMI Yolo',
'Best Hack for Fourth and Hope',
'Best Use of Cerebras API',
'Best Use of Vectara',
'Best Use of Gemini API',
'Best Use of MongoDB Atlas',
'Best .Tech Domain Name',
'Best Use of Auth0',
'Best Use of Snowflake API',
'Best Assistive Technology',
];

const teamsSchema = (trackList) => ({
$jsonSchema: {
bsonType: 'object',
title: 'Teams Object Validation',
required: ['teamNumber', 'tableNumber', 'name', 'tracks', 'active'],
properties: {
_id: {
bsonType: 'objectId',
description: '_id must be an ObjectId',
},
teamNumber: {
bsonType: 'int',
description: 'teamNumber must be an integer',
},
tableNumber: {
bsonType: 'int',
description: 'tableNumber must be an integer',
},
name: {
bsonType: 'string',
description: 'name must be a string',
},
tracks: {
bsonType: 'array',
items: {
enum: trackList,
description: 'track must be one of the valid tracks',
},
description: 'tracks must be an array of strings',
},
reports: {
bsonType: 'array',
items: {
bsonType: 'object',
required: ['timestamp', 'judge_id'],
properties: {
timestamp: {
bsonType: 'number',
description: 'Timestamp in milliseconds since epoch',
},
judge_id: {
bsonType: 'string',
description: 'ID of the judge',
},
},
},
},
active: {
bsonType: 'bool',
description: 'active must be a boolean',
},
},
additionalProperties: false,
},
});

export const up = async (db) => {
await db.command({
collMod: 'teams',
validator: teamsSchema(tracks),
});
};

export const down = async (db) => {
await db.command({
collMod: 'teams',
validator: teamsSchema(previousTracks),
});
};
Loading