Skip to content
Open
33 changes: 3 additions & 30 deletions client/package-lock.json

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

8 changes: 5 additions & 3 deletions client/src/components/dsa-theory/algo/InputEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { Shuffle } from "lucide-react";

interface Preset {
Expand Down Expand Up @@ -28,11 +28,13 @@ export function InputEditor({
monospace = true,
}: InputEditorProps) {
const [draft, setDraft] = useState(value);
const [prevValue, setPrevValue] = useState(value);

// Sync local draft when parent updates value externally (random/preset).
useEffect(() => {
if (value !== prevValue) {
setPrevValue(value);
setDraft(value);
}, [value]);
}

return (
<div className="flex flex-col gap-2">
Expand Down
1 change: 1 addition & 0 deletions client/src/components/dsa-theory/primitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export function InlineCode({ children }: ChildrenProps) {
* Theme tokens for inline-styled elements (SVG charts, dynamic colors).
* Prefer Tailwind classes wherever possible; use these only for runtime style props.
*/
// eslint-disable-next-line react-refresh/only-export-components
export const THEME = {
accent: "#a3e635", // lime-400
accentSoft: "#ecfccb", // lime-100
Expand Down
10 changes: 5 additions & 5 deletions client/src/components/ui/shape-landing-hero.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { motion, AnimatePresence, useAnimation, useMotionValue, useReducedMotion } from "framer-motion";
import { Link } from "react-router";
import { useEffect, useState, useRef } from "react";
import { useEffect, useState, useRef, useCallback } from "react";
import NumberFlow from "@number-flow/react";
import { ArrowRight, Play, Star } from "lucide-react";
import { useAuthStore } from "@/lib/auth.store";
Expand Down Expand Up @@ -248,7 +248,7 @@ function WinsMarquee() {
const shouldReduceMotion = useReducedMotion();
const [isDragging, setIsDragging] = useState(false);

const startAnimation = () => {
const startAnimation = useCallback(() => {
if (shouldReduceMotion || isDragging) return;

controls.start({
Expand All @@ -259,11 +259,11 @@ function WinsMarquee() {
ease: "linear",
},
});
};
}, [shouldReduceMotion, isDragging, controls]);

useEffect( () => {
startAnimation();
}, [shouldReduceMotion, isDragging]);
}, [startAnimation]);

// Pause animation when tab is not active and resume when active again
useEffect(() => {
Expand All @@ -290,7 +290,7 @@ function WinsMarquee() {
handleVisibilityChange,
);
};
}, [controls, shouldReduceMotion, isDragging]);
}, [controls, shouldReduceMotion, isDragging, startAnimation]);

const mouseEnter = () => {
controls.stop();
Expand Down
79 changes: 35 additions & 44 deletions client/src/hooks/useInterviewCountdown.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,35 @@
import { useEffect, useState, useCallback } from "react";

export function useInterviewCountdown(targetDate: string) {
const calculate = useCallback(() => {
const difference =
new Date(targetDate).getTime() - Date.now();

if (difference <= 0) {
return null;
}

return {
days: Math.floor(
difference / (1000 * 60 * 60 * 24)
),
hours: Math.floor(
(difference / (1000 * 60 * 60)) % 24
),
minutes: Math.floor(
(difference / (1000 * 60)) % 60
),
};
}, [targetDate]);

const [timeLeft, setTimeLeft] = useState(() => calculate());

useEffect(() => {
setTimeLeft(calculate());

const interval = setInterval(() => {
const updated = calculate();

setTimeLeft(updated);

if (!updated) {
clearInterval(interval);
}
}, 1000);

return () => clearInterval(interval);
}, [calculate]);

return timeLeft;
}
import { useEffect, useState } from "react";

function calculateDifference(targetDate: string) {
const difference = new Date(targetDate).getTime() - Date.now();

if (difference <= 0) {
return null;
}

return {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / (1000 * 60)) % 60),
};
}

export function useInterviewCountdown(targetDate: string) {
const [timeLeft, setTimeLeft] = useState(() => calculateDifference(targetDate));

useEffect(() => {
setTimeLeft(calculateDifference(targetDate));

const interval = setInterval(() => {
const updated = calculateDifference(targetDate);
setTimeLeft(updated);
if (!updated) {
clearInterval(interval);
}
}, 1000);

return () => clearInterval(interval);
}, [targetDate]);

return timeLeft;
}
1 change: 1 addition & 0 deletions client/src/lib/query-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const queryKeys = {
detail: (slug: string) => ["gsoc", "detail", slug] as const,
stats: () => ["gsoc", "stats"] as const,
repos: (slug: string) => ["gsoc", "repos", slug] as const,
topOrgs: () => ["gsoc", "top-orgs"] as const,
},

// YC Companies
Expand Down
3 changes: 3 additions & 0 deletions client/src/module/student/dsa/DsaTopicDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,9 @@ export default function DsaTopicDetailPage() {
)}
</div>
</div>
);
}

export const DsaProblemCard = React.memo(function DsaProblemCard({
problem,
pIdx,
Expand Down
2 changes: 2 additions & 0 deletions client/src/module/student/grants/GrantsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ function getDeadlineCountdown(deadline?: string | null) {
if (daysRemaining === 0) return "Ends today";
if (daysRemaining === 1) return "1 day left";
return `${daysRemaining} days left`;
}

function getDeadlineBadge(deadline: string) {
const now = new Date();
const endDate = new Date(deadline);
Expand Down
Loading
Loading