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
2 changes: 1 addition & 1 deletion __mocks__/tracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const uncategorizedTracks: Tracks = {
prizes: ['HackDavis Swag Bag'],
images: [],
eligibility_criteria:
'Awarded to the project with the most votes from our 2025 hackers. Vote for any project but your own!',
'Awarded to the project with the most votes from our 2026 hackers. Vote for any project but your own!',
},
'Best Hack for California GovOps Agency': {
name: 'Best Hack for California GovOps Agency',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function IndexHeroContentHacking() {
{' // creates for social good'}
</span>
</p>
<a href="https://hackdavis-2025.devpost.com/">
<a href="https://hackdavis-2026.devpost.com/">
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The year "2025" should be updated to "2026" in the displayed date text to match other year updates in this PR. This appears in multiple hero components but was only updated in the Devpost URL here. The date "APRIL 19-20 2025" is shown to users at line 31.

Copilot uses AI. Check for mistakes.
<button className={styles.submitButton}>
<p>SUBMIT!</p>
<GoArrowRight className={styles.submitArrow} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function SubmissionTips() {
/>
<div className={styles.devpost_submission}>
<Link
href="https://hackdavis-2025.devpost.com/"
href="https://hackdavis-2026.devpost.com/"
className={styles.button}
target="_blank"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
}
}

> h2 {
font-weight: bold;
h2 {
Comment thread
michelleyeoh marked this conversation as resolved.
font-weight: 700;
padding-bottom: 32px;
color: var(--text-dark);

Expand All @@ -54,7 +54,7 @@
background: none;
color: var(--background-secondary);
border-radius: 8px;
font-weight: 500;
font-weight: 600;
margin-right: 1%;
border: 1.5px solid var(--background-secondary);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,31 @@ export default function ClientTimeProtectedDisplay({
callback?: () => void;
children: React.ReactNode;
}) {
const { ok, loading, available, rollout, error, fetchAvailability } =
const { loading, available, rollout, error, fetchAvailability } =
useFeatureAvailability(featureId);
if (loading) {

// initial loading state
if (loading && !rollout) {
return 'loading...';
}

if (!ok) {
return JSON.stringify(error);
// error or no rollout info, then don't render 24 hr timer
if (error || !rollout) {
return <>{fallback}</>;
}

const handleTrigger = async () => {
await fetchAvailability(featureId, true);
callback?.();
};

if (!available) {
return (
<>
{fallback}
<TimeTriggerEntity
triggerTime={rollout.rollout_time}
callback={() => {
callback?.();
fetchAvailability(featureId);
}}
callback={handleTrigger}
/>
Comment thread
michelleyeoh marked this conversation as resolved.
</>
);
Expand All @@ -45,10 +50,7 @@ export default function ClientTimeProtectedDisplay({
{rollout.rollback_time && (
<TimeTriggerEntity
triggerTime={rollout.rollback_time}
callback={() => {
callback?.();
fetchAvailability(featureId);
}}
callback={handleTrigger}
/>
)}
</>
Expand Down
4 changes: 2 additions & 2 deletions app/(pages)/_globals/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "HackDavis Hub",
"description": "For all hackers and judges at HackDavis 2025",
"description": "For all hackers and judges at HackDavis 2026",
"icons": {
"icon": "/icons/icon.ico"
"icon": "/icons/icon-hd26.ico"
Comment thread
michelleyeoh marked this conversation as resolved.
}
}
44 changes: 30 additions & 14 deletions app/(pages)/_hooks/useFeatureAvailability.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
import checkFeatureAvailability from '@actions/rollouts/checkFeatureAvailability';
import { useEffect, useState } from 'react';
import { useEffect, useState, useCallback, useRef } from 'react';

export function useFeatureAvailability(featureId: string) {
const [loading, setLoading] = useState(true);
const [ok, setOk] = useState(true);
const [error, setError] = useState<string | null>(null);
const [available, setAvailable] = useState<any>(null);
const [available, setAvailable] = useState(false);
const [rollout, setRollout] = useState<any>(null);

const fetchAvailability = async (featureId: string) => {
setLoading(true);
const { ok, body, error } = await checkFeatureAvailability(featureId);
setOk(ok);
setAvailable(body?.available);
setRollout(body?.rollout);
setError(error);
setLoading(false);
};
const lastFetchedId = useRef<string | null>(null);

const fetchAvailability = useCallback(
async (id: string, force = false) => {
if (!force && lastFetchedId.current === id && rollout !== null) return;

setLoading(true);
setError(null);
try {
const { ok, body, error } = await checkFeatureAvailability(id);
if (ok && body) {
setAvailable(body.available);
setRollout(body.rollout);
lastFetchedId.current = id;
} else {
setError(error);
}
Comment thread
michelleyeoh marked this conversation as resolved.
} catch (err: any) {
console.error('Failed to fetch feature availability:', err);
setError(err instanceof Error ? err.message : String(err));
} finally {
setLoading(false);
}
},
[rollout]
Comment thread
michelleyeoh marked this conversation as resolved.
);
Comment on lines +34 to +35
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetchAvailability callback has rollout in its dependency array, which creates a circular dependency issue. When fetchAvailability is called and updates rollout, it causes fetchAvailability to be recreated (since it depends on rollout), which then triggers the useEffect on line 37-39 again (since it depends on fetchAvailability). This can lead to unnecessary re-fetches. Consider removing rollout from the dependency array or restructuring the logic to avoid this circular dependency.

Copilot uses AI. Check for mistakes.

useEffect(() => {
fetchAvailability(featureId);
}, [featureId]);
}, [featureId, fetchAvailability]);

return { ok, loading, available, rollout, error, fetchAvailability };
return { loading, available, rollout, error, fetchAvailability };
}
11 changes: 8 additions & 3 deletions app/(pages)/_hooks/useTimeTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import { useRouter } from 'next/navigation';

export function useTimeTrigger(triggerTime: number, callback: any) {
const timerRef = useRef<any>(null);
const callbackRef = useRef(callback);
const [triggered, setTriggered] = useState(false);
const router = useRouter();

useEffect(() => {
callbackRef.current = callback;
}, [callback]);

useEffect(() => {
const updateTimer = () => {
if (timerRef.current) {
Expand All @@ -18,7 +23,7 @@ export function useTimeTrigger(triggerTime: number, callback: any) {
return;
}
timerRef.current = setTimeout(async () => {
await callback?.();
await callbackRef.current?.();
router.refresh();
setTriggered(true);
}, timeToTrigger);
Expand All @@ -32,10 +37,10 @@ export function useTimeTrigger(triggerTime: number, callback: any) {
updateTimer();

return () => {
clearTimeout(timerRef.current);
if (timerRef.current) clearTimeout(timerRef.current);
window.removeEventListener('focus', onFocus);
};
}, [triggerTime, callback, router]);
}, [triggerTime, router]);

return { triggered };
}
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/icons/icon-hd26.ico
Binary file not shown.
Binary file removed public/icons/icon.ico
Binary file not shown.