Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ng clock view and working flow creator and working stage mode
Feat/extras
Feat/extras
Feat/extras
…lean up layout UI
many changes, UI and features
Added readmes and contributing.md
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThe PR updates docs and .gitignore, refactors admin pages to support multi-flow control and persisted broadcast history, converts flow editing to a client-side form with drag-and-drop and smart-sync, adds auth-aware landing redirects, and hardens Sidebar navigation with async room validation and stage-exit transitions. Changes
Sequence Diagram(s)sequenceDiagram
participant OrganizerUI as Organizer UI
participant ServerAPI as Server API
participant Backend as Backend (DB/state)
participant OtherClients as Connected Clients
OrganizerUI->>ServerAPI: POST /api/hackathons/:id/engine?action=PAUSE
ServerAPI->>Backend: update room state (PAUSE)
Backend-->>ServerAPI: confirm state updated
ServerAPI-->>OrganizerUI: 200 OK
Note right of ServerAPI: trigger SWR invalidation hooks
ServerAPI-->>OtherClients: (via polling/SSE) next poll returns PAUSED state
OtherClients->>OrganizerUI: localStorage update (broadcast history) / UI reflects new state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@Cyberbee-pro is attempting to deploy a commit to the githubcommunitysrm's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Actionable comments posted: 9
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
backend/controllers/authController.js (1)
40-52:⚠️ Potential issue | 🟠 MajorTwo issues: wrong Mongoose option and missing null check.
Mongoose option: Same issue as in
authService.js—returnDocument: 'after'is a MongoDB native driver option, not Mongoose. Use{ new: true }instead.Null dereference: If no user matches the provided
findOneAndUpdatereturnsnull. AccessingupdatedUser.activeRoomIdon line 48 will throw a runtime error.Proposed fix
const updateActiveRoom = async (req, res) => { try { const { email, roomId } = req.body; const updatedUser = await User.findOneAndUpdate( { email }, { activeRoomId: roomId || null }, - { returnDocument: 'after' } + { new: true } ); + if (!updatedUser) { + return res.status(404).json({ error: 'User not found.' }); + } res.status(200).json({ activeRoomId: updatedUser.activeRoomId }); } catch (err) { res.status(500).json({ error: err.message }); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/controllers/authController.js` around lines 40 - 52, In updateActiveRoom, fix two problems: replace the Mongo native option by passing { new: true } to User.findOneAndUpdate (instead of returnDocument: 'after') and add a null-check for the result (updatedUser) before reading updatedUser.activeRoomId; if updatedUser is null, return a 404 (or appropriate) response instead of dereferencing null, otherwise return the activeRoomId as before.hackclock/app/login/page.tsx (1)
256-275:⚠️ Potential issue | 🟡 MinorUse a real button for avatar selection.
These tiles are clickable
<div>s, so keyboard users can’t focus them or change the avatar without a mouse. Swapping them tobutton type="button"witharia-pressedkeeps the CREATE flow operable.🛠️ Suggested fix
- <div + <button key={index} + type="button" onClick={() => setSelectedAvatar(avatar)} className="w-12 h-12 rounded-lg cursor-pointer flex items-center justify-center overflow-hidden transition-all duration-200 border-2" + aria-pressed={selectedAvatar === avatar} style={{ backgroundColor: '#232323', borderColor: selectedAvatar === avatar ? '#FF2E9A' : 'rgba(255,255,255,0.06)', boxShadow: selectedAvatar === avatar ? '0 0 10px rgba(255,46,154,0.3)' : 'none' }} > @@ - </div> + </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/login/page.tsx` around lines 256 - 275, The avatar tiles are non-focusable divs; replace each clickable <div> with a semantic <button type="button"> while preserving existing classes, inline styles and the onClick that calls setSelectedAvatar(avatar); add aria-pressed={selectedAvatar === avatar} to reflect selection state and keep ImageIcon and the img onError handler unchanged, ensure the button has no default form submission behavior and retains the same visual role (cursor, border, boxShadow) so keyboard users can focus and toggle avatars via keyboard.backend/controllers/flowController.js (1)
100-103:⚠️ Potential issue | 🟡 MinorPotential null reference if
phaseEndTimeis unexpectedly null.If the room status is
RUNNINGbutphaseEndTimeisnulldue to data inconsistency,room.phaseEndTime.getTime()will throw aTypeError.🛡️ Suggested defensive check
if (action === 'PAUSE' && room.status === 'RUNNING') { + if (!room.phaseEndTime) { + return res.status(400).json({ error: "Cannot pause: phaseEndTime is not set." }); + } room.pausedRemainingMs = room.phaseEndTime.getTime() - Date.now(); room.phaseEndTime = null; room.status = 'PAUSED'; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/controllers/flowController.js` around lines 100 - 103, The PAUSE branch assumes room.phaseEndTime is a Date and calls getTime(), which can throw if phaseEndTime is null; update the action === 'PAUSE' handler to defensively check room.phaseEndTime before using it (e.g., if (room.phaseEndTime instanceof Date) compute room.pausedRemainingMs = room.phaseEndTime.getTime() - Date.now() else set pausedRemainingMs to 0 or a safe default), then null out room.phaseEndTime and set room.status = 'PAUSED' as before so room.pausedRemainingMs is always a defined number and no TypeError is thrown.
🟡 Minor comments (15)
CONTRIBUTING.md-162-167 (1)
162-167:⚠️ Potential issue | 🟡 MinorMarkdown links are incomplete and won't render as clickable.
The reference-style links on lines 164-166 lack link definitions, so they'll render as plain bracketed text (e.g.,
[README.md]) rather than clickable links.Proposed fix using inline links
If something in the codebase is unclear, start by checking: -- [README.md] -- [hackclock/README.md] -- [hackclock/BRAND-GUIDELINES.md] +- [README.md](README.md) +- [hackclock/README.md](hackclock/README.md) +- [hackclock/BRAND-GUIDELINES.md](hackclock/BRAND-GUIDELINES.md)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@CONTRIBUTING.md` around lines 162 - 167, Replace the bracketed reference-style link texts with actual Markdown links so they render as clickable; update the three items referencing README.md, hackclock/README.md, and hackclock/BRAND-GUIDELINES.md to use inline link syntax (e.g., [README.md](README.md)) or full relative paths (e.g., [hackclock/README.md](hackclock/README.md)) so the links become clickable in CONTRIBUTING.md.hackclock/README.md-5-5 (1)
5-5:⚠️ Potential issue | 🟡 MinorBroken link: absolute local path instead of relative path.
The link contains an absolute filesystem path (
/data/programing/GitHub/HackClock/hacktime/README.md) that won't work for other users. Use a relative path instead.Proposed fix
-For the full product overview and combined setup instructions, see the root [README](/data/programing/GitHub/HackClock/hacktime/README.md). +For the full product overview and combined setup instructions, see the root [README](../README.md).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/README.md` at line 5, The README link is using an absolute local path "/data/programing/GitHub/HackClock/hacktime/README.md" which breaks for others; update the Markdown link in hackclock/README.md (the text "[README](/data/programing/GitHub/HackClock/hacktime/README.md)") to a relative path such as "[README](../hacktime/README.md)" so it points to the repository's root README correctly for all users.backend/models/archiveSchema.js-12-19 (1)
12-19:⚠️ Potential issue | 🟡 MinorInconsistent hook options may leave gaps in mutation blocking.
Line 12 specifies
{ document: true, query: false }fordeleteOne, but lines 13-19 omit options entirely. Mongoose pre-hooks behave differently based on these options:
- Without options,
updateOne/replaceOneonly trigger for query middleware (e.g.,Model.updateOne()), not document middleware (e.g.,doc.updateOne()).For comprehensive protection, consider applying consistent options or explicitly handling both document and query contexts.
Suggested explicit options for all hooks
-ArchiveHackathonSchema.pre('deleteOne', { document: true, query: false }, blockArchiveMutations); -ArchiveHackathonSchema.pre('deleteMany', blockArchiveMutations); -ArchiveHackathonSchema.pre('findOneAndDelete', blockArchiveMutations); -ArchiveHackathonSchema.pre('findOneAndReplace', blockArchiveMutations); -ArchiveHackathonSchema.pre('findOneAndUpdate', blockArchiveMutations); -ArchiveHackathonSchema.pre('replaceOne', blockArchiveMutations); -ArchiveHackathonSchema.pre('updateOne', blockArchiveMutations); -ArchiveHackathonSchema.pre('updateMany', blockArchiveMutations); +// Document-level hooks +ArchiveHackathonSchema.pre('deleteOne', { document: true, query: false }, blockArchiveMutations); +ArchiveHackathonSchema.pre('updateOne', { document: true, query: false }, blockArchiveMutations); + +// Query-level hooks +ArchiveHackathonSchema.pre('deleteOne', { document: false, query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('deleteMany', { query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('findOneAndDelete', { query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('findOneAndReplace', { query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('findOneAndUpdate', { query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('replaceOne', { query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('updateOne', { document: false, query: true }, blockArchiveMutations); +ArchiveHackathonSchema.pre('updateMany', { query: true }, blockArchiveMutations);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/models/archiveSchema.js` around lines 12 - 19, The pre-hook registrations on ArchiveHackathonSchema use inconsistent options so some document vs query middleware cases may be missed; ensure blockArchiveMutations runs for both document and query contexts by registering each hook with explicit options (e.g., include { document: true, query: true } or add two registrations per hook) for the listed hooks: deleteOne, deleteMany, findOneAndDelete, findOneAndReplace, findOneAndUpdate, replaceOne, updateOne, updateMany (and keep the existing document-only registration for deleteOne if needed), so ArchiveHackathonSchema.pre(..., blockArchiveMutations) consistently covers both document and query invocations.README.md-31-32 (1)
31-32:⚠️ Potential issue | 🟡 MinorDeployment URLs are identical.
Both "Experimental" and "Production" point to
https://hackclock.vercel.app/. This appears inconsistent with lines 91-92 where Production useshttps://hacktime.vercel.app/.- Experimental: `https://hackclock.vercel.app/` -- Production: `https://hackclock.vercel.app/` +- Production: `https://hacktime.vercel.app/`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 31 - 32, Update README.md so the "Production" deployment URL is the correct one instead of duplicating the "Experimental" URL; replace the second occurrence of `https://hackclock.vercel.app/` under the "Production" label with `https://hacktime.vercel.app/` (ensure the "Experimental" line remains `https://hackclock.vercel.app/`) so the two entries match the intended deployment targets referenced later in the file.README.md-166-166 (1)
166-166:⚠️ Potential issue | 🟡 MinorInvalid license path.
The path
/data/programing/GitHub/HackClock/hacktime/LICENSElooks like a local filesystem path rather than a repository-relative path.-This project is licensed under the [MIT License](/data/programing/GitHub/HackClock/hacktime/LICENSE). +This project is licensed under the [MIT License](./LICENSE).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 166, The README contains an absolute local path to the license file; replace "/data/programing/GitHub/HackClock/hacktime/LICENSE" with a repository-relative path (e.g., "LICENSE" or "./LICENSE" or "/LICENSE") so the link points to the repo's license file; update the line in README.md that currently reads "This project is licensed under the [MIT License](/data/programing/GitHub/HackClock/hacktime/LICENSE)." to use the repo-relative path.hackclock/app/stage/page.tsx-14-15 (1)
14-15:⚠️ Potential issue | 🟡 MinorHarden redirect path construction with URL-segment encoding.
Line 15 interpolates
activeRoomIddirectly; encode it before composing the URL to avoid malformed/internal path issues from unexpected values.Suggested change
if (activeRoomId) { - redirect(`/room/${activeRoomId}/stage`); + redirect(`/room/${encodeURIComponent(String(activeRoomId))}/stage`); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/stage/page.tsx` around lines 14 - 15, The redirect constructs the path by interpolating activeRoomId directly into redirect(`/room/${activeRoomId}/stage`), which can produce malformed URLs; change the construction to encode the segment (use encodeURIComponent on activeRoomId) before composing the path so redirect receives a safe URL—update the call site that invokes redirect with the encoded value and ensure activeRoomId is passed through encodeURIComponent wherever similar path composition occurs.hackclock/app/(admin)/layout.tsx-8-9 (1)
8-9:⚠️ Potential issue | 🟡 MinorUnused imports:
NotificationPopoverandSettingsPopover.These components are imported but never used in the rendered JSX. The AI summary mentions they replaced previous header icons, but the current code doesn't render them.
Remove unused imports or add them to the header
If intentionally removed:
import Sidebar from "@/components/ui/Sidebar"; -import NotificationPopover from "@/components/ui/NotificationPopover"; -import SettingsPopover from "@/components/ui/SettingsPopover"; import { User, Menu, X } from "lucide-react";Or if they should be rendered in the desktop header (lines 66-80):
<div className="flex items-center gap-4" style={{ color: '#A0A0A0' }}> - + <NotificationPopover /> + <SettingsPopover /> <Link href="/profile" className="flex items-center gap-3 cursor-pointer group">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/layout.tsx around lines 8 - 9, The imports NotificationPopover and SettingsPopover are unused; either remove those two import lines from layout.tsx or re-introduce the components into the desktop header JSX (the header component that renders the right-side icons) by placing <NotificationPopover /> and <SettingsPopover /> in the header's desktop controls so they are actually rendered; ensure you reference the existing NotificationPopover and SettingsPopover symbols exactly and keep the import paths as-is if you add them back.hackclock/components/ui/NotificationPopover.tsx-39-42 (1)
39-42:⚠️ Potential issue | 🟡 Minor"Clear All Logs" button has no click handler.
The button is styled interactively but lacks an
onClickhandler, making it appear broken to users. Either add the handler or disable/hide the button until functionality is implemented.Proposed fix to disable or hide until implemented
- <button className="w-full text-[10px] font-bold uppercase tracking-widest transition-colors" style={{ color: '#FF2E9A' }}> + <button + className="w-full text-[10px] font-bold uppercase tracking-widest transition-colors disabled:opacity-50 disabled:cursor-not-allowed" + style={{ color: '#FF2E9A' }} + disabled + title="Coming soon" + > Clear All Logs </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/NotificationPopover.tsx` around lines 39 - 42, The "Clear All Logs" button in NotificationPopover is interactive but has no click handler; either wire it up or disable/hide it until implemented. Add an onClick prop (e.g., onClearAll or clearAllLogs) to the NotificationPopover component and attach it to the button with the label "Clear All Logs" so it invokes the existing log-clearing logic (or dispatches the appropriate action); alternatively, if no handler exists yet, mark the button disabled and add aria-disabled and visually-muted styles so it can't be interacted with. Ensure the change references the button element containing the text "Clear All Logs" and the NotificationPopover component API (prop name like onClearAll/clearAllLogs) so callers can provide the implementation.hackclock/app/layout.tsx-23-28 (1)
23-28:⚠️ Potential issue | 🟡 MinorRemove
suppressHydrationWarningunless there's a specific known hydration issue.The inline style (
color: '#E6E6E6') is static and matches the CSS token. AuthProvider is a simple SessionProvider wrapper with no DOM modifications. No theme detection, dark-mode logic, or prefers-color-scheme media queries were found in the root layout that would justify suppressing hydration warnings. Removing these props will help catch actual hydration bugs during development.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/layout.tsx` around lines 23 - 28, Remove the unnecessary suppression of React hydration warnings and the static inline color: delete the suppressHydrationWarning prop from the <html> and <body> elements and remove the inline style color ("#E6E6E6") in layout.tsx; rely on the existing CSS token / class (ibmPlexMono.variable and your global CSS) for the static color instead, since AuthProvider/SessionProvider does not perform DOM changes and there is no theme-detection logic that would justify suppressing hydration warnings.hackclock/app/login/page.tsx-34-37 (1)
34-37:⚠️ Potential issue | 🟡 MinorTrim and validate the guest inputs before joining.
roomId.toUpperCase()preserves leading/trailing whitespace, andteamNamecan still be whitespace-only. This path can send/persist invalid values that the shared join control already normalizes, so the login join flow may fail while the modal join flow succeeds.🛠️ Suggested fix
+ const normalizedRoomId = roomId.trim().toUpperCase(); + const normalizedTeamName = teamName.trim(); + if (!normalizedRoomId || !normalizedTeamName) { + setError('CONNECTION FAULT: Enter a valid team name and room ID.'); + setIsLoading(false); + return; + } + try { - const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${roomId.toUpperCase()}/join`, { + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${normalizedRoomId}/join`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ teamName }), + body: JSON.stringify({ teamName: normalizedTeamName }), }); @@ localStorage.setItem('hackclock_guest', JSON.stringify({ - teamName, - roomId: roomId.toUpperCase(), + teamName: normalizedTeamName, + roomId: normalizedRoomId, joinedAt: new Date().toISOString() })); // Route directly to the clock UI - router.push(`/room/${roomId.toUpperCase()}/clock`); + router.push(`/room/${normalizedRoomId}/clock`);Also applies to: 48-55
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/login/page.tsx` around lines 34 - 37, Trim and validate the guest inputs before calling the join endpoint: ensure you call .trim() on roomId and teamName, convert the trimmed roomId to uppercase (use roomId.trim().toUpperCase()) and replace the fetch body/header usage accordingly, and reject/return early (show error or prevent fetch) if the trimmed teamName is empty or roomId is empty so you don't send whitespace-only values; update both places where the fetch is used (the POST call using roomId.toUpperCase() and the other occurrence around lines 48-55) to use the trimmed/validated variables.hackclock/app/room/[id]/stage/page.tsx-27-37 (1)
27-37:⚠️ Potential issue | 🟡 MinorReset history when switching rooms, and guard bad local storage.
When the new
roomIdhas no saved entry, this effect leaves the previous room’s history in state.JSON.parseis also unguarded, so one malformedstage_history_*value will throw during mount.🛠️ Suggested fix
useEffect(() => { - if (roomId) { - const localHistory = localStorage.getItem(`stage_history_${roomId}`); - if (localHistory) { - const timeout = setTimeout(() => { - setHistory(JSON.parse(localHistory)); - }, 0); - return () => clearTimeout(timeout); - } - } + if (!roomId) { + setHistory([]); + return; + } + + const localHistory = localStorage.getItem(`stage_history_${roomId}`); + if (!localHistory) { + setHistory([]); + return; + } + + try { + setHistory(JSON.parse(localHistory)); + } catch { + localStorage.removeItem(`stage_history_${roomId}`); + setHistory([]); + } }, [roomId]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/stage/page.tsx around lines 27 - 37, The effect watching roomId leaves previous history when the new `stage_history_${roomId}` key is missing and will throw on malformed JSON; update the `useEffect` that reads `localStorage.getItem` to always reset state for a new `roomId` (e.g., call `setHistory([])` or an empty default) when no saved value exists, and wrap the `JSON.parse` in a try/catch to handle corrupt data (on catch set the same empty default); preserve the existing zero-delay timeout and its cleanup (clearTimeout) around the safe `setHistory` call so the async behavior remains consistent.hackclock/components/ui/JoinRoomControls.tsx-64-67 (1)
64-67:⚠️ Potential issue | 🟡 MinorSurface the server’s join error here too.
This shared control currently collapses every non-OK response to
"Room not found or unavailable.", so users lose actionable errors like ended, locked, or full rooms.🛠️ Suggested fix
if (!res.ok) { - setError("Room not found or unavailable."); + const data = await res.json().catch(() => null); + setError(data?.error || "Room not found or unavailable."); return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/JoinRoomControls.tsx` around lines 64 - 67, The non-OK branch in JoinRoomControls.tsx currently sets a generic error via setError("Room not found or unavailable."); update the handler that receives the fetch Response (res) to extract and surface the server-provided error (try await res.json() and/or res.text() to read an "error" or message field) and pass that into setError, falling back to the existing generic message if no server message exists; modify the code around the fetch/response handling in the join flow (the block that references res and calls setError) to prefer the server message while keeping the fallback.hackclock/app/globals.css-66-66 (1)
66-66:⚠️ Potential issue | 🟡 MinorRemove unnecessary quotes around font name.
Per Stylelint,
Inconsolatadoesn't require quotes as it's a single-word font family name without special characters.🔧 Suggested fix
- font-family: var(--font-mono), 'IBM Plex Mono', 'Inconsolata', monospace; + font-family: var(--font-mono), 'IBM Plex Mono', Inconsolata, monospace;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/globals.css` at line 66, The font-family declaration using font-family: var(--font-mono), 'IBM Plex Mono', 'Inconsolata', monospace; includes unnecessary quotes around the single-word font name Inconsolata; update the declaration in the CSS rule that contains font-family (referencing var(--font-mono) and 'IBM Plex Mono') by removing the quotes around Inconsolata so it becomes unquoted while keeping 'IBM Plex Mono' quoted (due to the space) and preserving the existing comma-separated order.backend/controllers/flowController.js-70-75 (1)
70-75:⚠️ Potential issue | 🟡 MinorFalsy values cannot be assigned due to
||fallback pattern.The
|| flow.fieldpattern prevents intentionally setting fields to falsy values like empty strings or0. If a user sends{ name: "" }, the name won't be cleared.🛠️ Suggested fix using nullish coalescing or explicit checks
- flow.name = name || flow.name; - flow.eventStartTime = eventStartTime || flow.eventStartTime; - flow.eventEndTime = eventEndTime || flow.eventEndTime; - flow.timezone = timezone || flow.timezone; - flow.branding = branding || flow.branding; - flow.phases = phases || flow.phases; + flow.name = name ?? flow.name; + flow.eventStartTime = eventStartTime ?? flow.eventStartTime; + flow.eventEndTime = eventEndTime ?? flow.eventEndTime; + flow.timezone = timezone ?? flow.timezone; + flow.branding = branding ?? flow.branding; + flow.phases = phases ?? flow.phases;Using
??(nullish coalescing) preserves the existing value only when the new value isnullorundefined, allowing empty strings and0to be set intentionally.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/controllers/flowController.js` around lines 70 - 75, The update logic in flowController.js uses the `||` fallback (e.g., `flow.name = name || flow.name`) which prevents assigning intentional falsy values (like "" or 0); replace these fallbacks with nullish checks so only `null` or `undefined` preserve the existing value—e.g., use the nullish coalescing equivalent for each assignment (`flow.name`, `flow.eventStartTime`, `flow.eventEndTime`, `flow.timezone`, `flow.branding`, `flow.phases`) or explicit checks (if value !== undefined) to allow empty strings and zeros to be saved.hackclock/app/room/[id]/clock/page.tsx-43-57 (1)
43-57:⚠️ Potential issue | 🟡 MinorAdd error handling for localStorage operations.
JSON.parseon line 49 can throw if the stored data is corrupted or invalid. Additionally,localStorageaccess can throw in private browsing mode or when storage quota is exceeded.🛡️ Suggested defensive approach
useEffect(() => { if (roomId) { - const localHistory = localStorage.getItem(`clock_history_${roomId}`); - const lastTS = localStorage.getItem(`last_broadcast_${roomId}`); - const timeout = setTimeout(() => { - if (localHistory) { - setHistory(JSON.parse(localHistory)); - } - if (lastTS) { - setLastAnnouncementTime(lastTS); - } - }, 0); - return () => clearTimeout(timeout); + try { + const localHistory = localStorage.getItem(`clock_history_${roomId}`); + const lastTS = localStorage.getItem(`last_broadcast_${roomId}`); + if (localHistory) { + setHistory(JSON.parse(localHistory)); + } + if (lastTS) { + setLastAnnouncementTime(lastTS); + } + } catch (e) { + console.warn('Failed to load broadcast history from localStorage:', e); + } } }, [roomId]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/clock/page.tsx around lines 43 - 57, The useEffect that reads localStorage (inside useEffect -> localHistory/lastTS handling) should guard against failures: wrap the localStorage.getItem and subsequent JSON.parse calls in a try/catch so any DOMException or parse error is caught; validate localHistory is a non-empty string before JSON.parse and on error fall back to a safe default (e.g., empty array) and still call setHistory/setLastAnnouncementTime as appropriate; ensure the timeout/clearTimeout logic remains unchanged and log or silently handle the error but do not let it throw from useEffect.
🧹 Nitpick comments (13)
hackclock/app/(admin)/join/page.tsx (1)
39-43: Consider using React state for focus styling instead of direct DOM mutation.The
onFocus/onBlurhandlers directly mutatee.target.style.borderColor, mixing imperative DOM manipulation with React's declarative model. This works but can be harder to maintain and doesn't integrate well with React's rendering cycle.Alternative using React state
export default function AdminJoinPage() { const router = useRouter(); const [roomId, setRoomId] = useState(''); + const [isFocused, setIsFocused] = useState(false); // ... in the input: className="w-full rounded-lg py-4 pl-12 pr-4 placeholder-[`#6B7280`] focus:outline-none transition-colors font-mono text-lg uppercase tracking-widest" - style={{ backgroundColor: '#0F0F10', border: '1px solid rgba(255,255,255,0.06)', color: '#E6E6E6' }} - onFocus={(e) => e.target.style.borderColor = 'rgba(255,46,154,0.4)'} - onBlur={(e) => e.target.style.borderColor = 'rgba(255,255,255,0.06)'} + style={{ + backgroundColor: '#0F0F10', + border: `1px solid ${isFocused ? 'rgba(255,46,154,0.4)' : 'rgba(255,255,255,0.06)'}`, + color: '#E6E6E6' + }} + onFocus={() => setIsFocused(true)} + onBlur={() => setIsFocused(false)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/join/page.tsx around lines 39 - 43, Replace the inline DOM mutation in the input's onFocus/onBlur handlers with React state: add a boolean state (e.g., isFocused via useState) in the component, change the onFocus to setIsFocused(true) and onBlur to setIsFocused(false), and derive the border color in the element's style or className conditionally based on isFocused (instead of e.target.style.borderColor). Update the input that currently uses onFocus={(e) => e.target.style.borderColor = ...} and onBlur={(e) => e.target.style.borderColor = ...} to use the new state-driven styling (keeps the rest of className and required intact).hackclock/app/api/auth/[...nextauth]/route.ts (2)
81-83: Empty string values for name/image won't update the token.The truthy checks
if (nextName)andif (nextImage)prevent updating to empty strings. If this is intentional (to avoid clearing values), consider adding a comment; otherwise use!== undefinedchecks.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/api/auth/`[...nextauth]/route.ts around lines 81 - 83, The conditionals using truthy checks on nextName and nextImage prevent setting authToken.name or authToken.picture to empty strings; change the guards in the route handler to check for !== undefined (e.g., if (nextName !== undefined) authToken.name = nextName; and similarly for nextImage) so explicit empty-string updates are allowed, and keep the nextActiveRoomId line as-is (or add a brief comment explaining intentional behavior if you want to preserve the current logic).
9-12: GitHubProvider with empty credentials may cause runtime issues.Using empty string fallbacks (
|| "") means GitHubProvider is always registered, even when GitHub OAuth isn't configured. This can cause confusing errors when users try to sign in with GitHub. Consider conditionally including the provider.Suggested approach
+const providers = []; + +if (process.env.GITHUB_ID && process.env.GITHUB_SECRET) { + providers.push( + GitHubProvider({ + clientId: process.env.GITHUB_ID, + clientSecret: process.env.GITHUB_SECRET, + }) + ); +} + +providers.push( + CredentialsProvider({ + // ... existing config + }) +); + export const authOptions: NextAuthOptions = { - providers: [ - GitHubProvider({ - clientId: process.env.GITHUB_ID || "", - clientSecret: process.env.GITHUB_SECRET || "", - }), - CredentialsProvider({ + providers,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/api/auth/`[...nextauth]/route.ts around lines 9 - 12, The code always registers GitHubProvider using empty-string fallbacks which can cause runtime sign-in errors; update the provider registration in route.ts to only include GitHubProvider when both process.env.GITHUB_ID and process.env.GITHUB_SECRET are truthy — check those env vars and conditionally push or spread GitHubProvider into the providers array (refer to GitHubProvider and the providers list in route.ts) so the provider is omitted entirely when not configured, and log or fail fast if you need explicit feedback in dev.hackclock/components/ui/HoldButton.tsx (1)
30-47: Potential stale closure issue withonCompletecallback.The
onCompletecallback is captured in the closure whenstartHoldingis called. If the parent component changesonCompletewhile the user is holding, the old callback will be invoked when the hold completes.Fix using a ref to always call the latest callback
+ const onCompleteRef = useRef(onComplete); + onCompleteRef.current = onComplete; + const startHolding = () => { setIsHolding(true); startTimeRef.current = Date.now(); setProgress(0); timerRef.current = setInterval(() => { const elapsed = Date.now() - startTimeRef.current; const newProgress = Math.min((elapsed / holdTime) * 100, 100); setProgress(newProgress); if (elapsed >= holdTime) { if (timerRef.current) clearInterval(timerRef.current); setIsHolding(false); setProgress(0); - onComplete(); + onCompleteRef.current(); } }, 10); };This is a minor edge case but worth considering for a reusable component.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/HoldButton.tsx` around lines 30 - 47, The startHolding interval closes over the onComplete prop and may call a stale callback; create a ref (e.g., onCompleteRef) to always hold the latest onComplete, update onCompleteRef.current inside a useEffect when onComplete changes, and replace calls to onComplete() inside startHolding's timer with onCompleteRef.current(), ensuring timerRef and startTimeRef logic and interval cleanup remain unchanged.hackclock/BRAND-GUIDELINES.md (1)
96-99: ASCII layout diagram triggers false-positive lint warnings.The bracketed text like
[ SIDE INFO ]and[ CTA ]is being misinterpreted by markdownlint as undefined reference links. This is a false positive since these are intentional ASCII art placeholders. You can either ignore the warnings or wrap the diagram in a code block.Optional fix: wrap in code block to silence linter
Grid-based card layout: -[ Header ] -[ BIG TIMER CARD ][ SIDE INFO ] -[ STATS ][ TEAM ][ CTA ] -[ FOOTER INFO ] +``` +[ Header ] +[ BIG TIMER CARD ][ SIDE INFO ] +[ STATS ][ TEAM ][ CTA ] +[ FOOTER INFO ] +```🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/BRAND-GUIDELINES.md` around lines 96 - 99, The ASCII layout block containing bracketed placeholders like `[ BIG TIMER CARD ]`, `[ SIDE INFO ]`, `[ CTA ]`, etc. is being parsed as reference links by markdownlint; fix it by wrapping the entire diagram in a fenced code block (add a line with ``` before the first bracketed line and another ``` after the last line) so the ASCII art is treated as code and the linter warnings stop.hackclock/app/(admin)/layout.tsx (1)
36-42: Consider usingnext/imagefor avatar images.Using native
<img>tags bypasses Next.js image optimization. For user avatars loaded from external sources (e.g., GitHub),next/imageprovides automatic optimization and lazy loading.Proposed change to use next/image
Import the component:
import Link from "next/link"; +import Image from "next/image";Then update the avatar rendering (in both mobile and desktop headers):
- <img src={session.user.image} alt="Avatar" className="w-full h-full object-cover" /> + <Image src={session.user.image} alt="Avatar" width={32} height={32} className="w-full h-full object-cover" />Note: You'll need to configure
next.config.jsto allow the image domains (e.g.,avatars.githubusercontent.comfor GitHub).Also applies to: 72-78
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/layout.tsx around lines 36 - 42, Replace the plain <img> usage for avatars with Next.js' Image component: import Image from 'next/image' at the top of layout.tsx, then in the avatar render branches (the block using session?.user?.image and the identical block referenced at lines 72-78) swap the <img src={session.user.image} ... /> for an <Image> with explicit width/height or fill + objectFit (so it preserves the rounded container), keep the alt text, and preserve the fallback to the User icon; also ensure external domains (e.g., avatars.githubusercontent.com) are added to next.config.js image.domains so Next/Image can load those remote avatars.hackclock/components/ui/Modal.tsx (2)
18-30: Consider stabilizingonClosereference to avoid effect re-runs.If the parent component passes a new
onClosefunction reference on each render (common with inline arrow functions), this effect will re-run, re-adding listeners unnecessarily. This isn't a bug but could cause subtle issues.Consider documenting that
onCloseshould be stable (wrapped inuseCallbackby the parent), or use a ref to hold the latest callback:+ const onCloseRef = useRef(onClose); + onCloseRef.current = onClose; + useEffect(() => { const handleEscape = (e: KeyboardEvent) => { - if (e.key === 'Escape') onClose(); + if (e.key === 'Escape') onCloseRef.current(); }; if (isOpen) { document.addEventListener('keydown', handleEscape); document.body.style.overflow = 'hidden'; } return () => { document.removeEventListener('keydown', handleEscape); document.body.style.overflow = 'unset'; }; - }, [isOpen, onClose]); + }, [isOpen]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/Modal.tsx` around lines 18 - 30, The effect in Modal uses onClose in its dependency array which causes re-runs when the parent supplies a new function; stabilize the callback by storing the latest onClose in a ref and using a stable handleEscape that reads from that ref so the effect only depends on isOpen (or document body mutation), e.g., create an onCloseRef that you update whenever onClose changes and have handleEscape call onCloseRef.current, then change the useEffect dependency to [isOpen] (or document visibility) — this keeps addEventListener/removeEventListener stable while still invoking the latest onClose.
34-46: Backdrop doesn't close modal on click.The overlay
divat line 35 doesn't have anonClickhandler. Users typically expect clicking outside the modal content to dismiss it. Currently, only the X button and Escape key close the modal.Proposed fix to add backdrop click-to-close
- <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-xl animate-in fade-in duration-300"> + <div + className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-xl animate-in fade-in duration-300" + onClick={onClose} + >The existing
e.stopPropagation()on the modal content (line 46) already prevents clicks inside from bubbling up.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/Modal.tsx` around lines 34 - 46, The overlay div returned by createPortal in the Modal component lacks an onClick to dismiss the modal; add an onClick handler on that outer div which calls the component's close handler (e.g., call the provided onClose prop or existing closeModal function used by the X button / Escape key) so clicks outside the modal content close it while keeping the inner div's onClick={(e) => e.stopPropagation()} intact; locate the Modal component (createPortal, modalRef) and wire the overlay's onClick to the same close logic the X button/Escape use.hackclock/components/ui/SettingsPopover.tsx (1)
22-26: Placeholder links detected — consider tracking or removing.
Stage PreferencesandTheme Configurationhavehref="#"which are non-functional placeholders. This is fine for initial implementation, but these should be wired up or removed before shipping.Would you like me to open an issue to track implementing these settings pages?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/SettingsPopover.tsx` around lines 22 - 26, The menuItems array contains placeholder href="#" entries for the items labeled "Stage Preferences" and "Theme Configuration"; update SettingsPopover by replacing those placeholders with actual routes (e.g., '/stage-preferences' and '/theme-configuration') or remove those menu entries if the pages aren't ready, and if keeping placeholders add a clear TODO comment and/or an issue-tracking tag so they’re implemented later; locate and modify the menuItems constant and the entries with icon: Monitor and icon: Palette to apply the chosen fix.backend/controllers/flowController.js (1)
35-42: Consider adding pagination for scalability.This endpoint returns all flows for an organizer without pagination. As the number of flows grows, this could cause performance issues and increased memory usage.
Additionally, passing
organizerSecretin the query string may cause it to be logged by proxies or web servers. Consider using a request header instead.♻️ Suggested pagination approach
const getAllFlows = async (req, res) => { try { - const { organizerSecret } = req.query; - if (!organizerSecret) return res.status(400).json({ error: "Missing organizerSecret." }); - const flows = await Hackathon.find({ organizerSecret }).sort({ createdAt: -1 }); - res.status(200).json(flows); + const organizerSecret = req.headers['x-organizer-secret'] || req.query.organizerSecret; + if (!organizerSecret) return res.status(400).json({ error: "Missing organizerSecret." }); + + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 20; + const skip = (page - 1) * limit; + + const [flows, total] = await Promise.all([ + Hackathon.find({ organizerSecret }).sort({ createdAt: -1 }).skip(skip).limit(limit), + Hackathon.countDocuments({ organizerSecret }) + ]); + + res.status(200).json({ flows, page, limit, total, totalPages: Math.ceil(total / limit) }); } catch (err) { res.status(500).json({ error: err.message }); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/controllers/flowController.js` around lines 35 - 42, The getAllFlows handler currently reads organizerSecret from req.query and returns all matching Hackathon documents; update it to read organizerSecret from a request header (e.g., req.headers['x-organizer-secret']) to avoid query-string exposure, validate it, and do not log it; add pagination by accepting page and pageSize (or limit/skip) from query or defaults, parse and enforce a max pageSize, then use Hackathon.find({ organizerSecret }).sort({ createdAt: -1 }).limit(pageSize).skip((page-1)*pageSize) and return the paged results plus metadata (total count, page, pageSize) so callers can paginate efficiently.hackclock/app/globals.css (1)
134-147: Consider using kebab-case for keyframe names per Stylelint conventions.The keyframe names
fadeIn,skeletonShimmer, andsubtlePulseviolate thekeyframes-name-patternrule expecting kebab-case.♻️ Suggested renaming
-@keyframes fadeIn { +@keyframes fade-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } -@keyframes skeletonShimmer { +@keyframes skeleton-shimmer { 0% { transform: translateX(0); } 100% { transform: translateX(320%); } } -@keyframes subtlePulse { +@keyframes subtle-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } .stagger-in > * { opacity: 0; - animation: fadeIn 0.5s var(--ease-out) forwards; + animation: fade-in 0.5s var(--ease-out) forwards; }Also update
.skeleton-highlightto referenceskeleton-shimmer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/globals.css` around lines 134 - 147, Keyframe names fadeIn, skeletonShimmer, and subtlePulse violate the Stylelint keyframes-name-pattern expecting kebab-case; rename them to kebab-case (e.g., fade-in, skeleton-shimmer, subtle-pulse) in the `@keyframes` declarations and update all references (notably the .skeleton-highlight rule that should reference skeleton-shimmer) and any usage in CSS/JS to match the new names to satisfy the linter.hackclock/app/room/[id]/clock/page.tsx (2)
117-153: Timer logic is functional but shares thesetTimeoutpattern concern.The countdown interval logic (lines 140-152) is correct. The
setTimeout(..., 0)wrappers for the paused/completed state updates (lines 121-128, 132-135) have the same complexity concern noted in the broadcast effect.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/clock/page.tsx around lines 117 - 153, The useEffect for updating the countdown uses unnecessary setTimeout(..., 0) wrappers for the paused/completed branches which add complexity; replace those branches to call setTimeLeft synchronously instead of scheduling a zero-delay timeout (remove the timeout variable, clearTimeout calls, and returned cleanup for those branches), leaving the RUNNING path intact with updateTimer, setInterval (timer) and return () => clearInterval(timer); keep references to eventData, setTimeLeft, updateTimer and timer when applying the change.
59-107: ExcessivesetTimeout(..., 0)usage is non-idiomatic and adds complexity.The broadcast effect wraps nearly every state update in
setTimeout(..., 0). This pattern defers execution to the next event loop tick but is unusual in React and adds significant complexity with multiple cleanup functions.If this was added to avoid React Strict Mode double-invocation or state batching issues, consider using refs or restructuring the logic instead. If there's a specific issue being worked around, it would be helpful to document it.
♻️ Simplified approach without setTimeout
useEffect(() => { if (!eventData || !roomId) return; const currentTS = eventData.announcementTimestamp; if (isInitialLoad) { if (!lastAnnouncementTime && currentTS) { - const timeout = setTimeout(() => { - setLastAnnouncementTime(currentTS); - localStorage.setItem(`last_broadcast_${roomId}`, currentTS); - }, 0); - return () => clearTimeout(timeout); + setLastAnnouncementTime(currentTS); + try { localStorage.setItem(`last_broadcast_${roomId}`, currentTS); } catch {} } - const timeout = setTimeout(() => { - setIsInitialLoad(false); - }, 0); - return () => clearTimeout(timeout); + setIsInitialLoad(false); + return; } if (currentTS && currentTS !== lastAnnouncementTime) { - const timestampTimeout = setTimeout(() => { - setLastAnnouncementTime(currentTS); - localStorage.setItem(`last_broadcast_${roomId}`, currentTS); - }, 0); + setLastAnnouncementTime(currentTS); + try { localStorage.setItem(`last_broadcast_${roomId}`, currentTS); } catch {} if (eventData.announcement) { - const historyTimeout = setTimeout(() => { - setHistory(prev => { - const newHistory = [eventData.announcement, ...prev.filter(h => h !== eventData.announcement)].slice(0, 10); - localStorage.setItem(`clock_history_${roomId}`, JSON.stringify(newHistory)); - return newHistory; - }); - }, 0); - + setHistory(prev => { + const newHistory = [eventData.announcement, ...prev.filter(h => h !== eventData.announcement)].slice(0, 10); + try { localStorage.setItem(`clock_history_${roomId}`, JSON.stringify(newHistory)); } catch {} + return newHistory; + }); announcementDurationRef.current = eventData.announcementDuration || 10; - const announcementTimeout = setTimeout(() => { - setShowAnnouncement(true); - }, 0); - return () => { - clearTimeout(timestampTimeout); - clearTimeout(historyTimeout); - clearTimeout(announcementTimeout); - }; + setShowAnnouncement(true); } - - return () => clearTimeout(timestampTimeout); } }, [eventData, isInitialLoad, lastAnnouncementTime, roomId]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/clock/page.tsx around lines 59 - 107, The effect in the broadcast logic (inside the useEffect that watches eventData, isInitialLoad, lastAnnouncementTime, roomId) overuses setTimeout(..., 0); remove those no-op deferrals and update state synchronously (call setLastAnnouncementTime, setIsInitialLoad, setHistory, setShowAnnouncement directly) while preserving the same control flow: handle the initial-load branch (use a ref like initialLoadRef if you need to avoid Strict Mode double-invoke), update localStorage immediately when you update state, set announcementDurationRef.current from eventData.announcementDuration, and only use/clear real timers for any non-zero delays; drop the multiple clearTimeout calls that correspond to removed timeouts. This keeps logic in functions/refs (e.g., announcementDurationRef, isInitialLoad handling) and eliminates the unnecessary setTimeout wrappers.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f91e7687-8592-4806-b617-c2e00268a318
⛔ Files ignored due to path filters (1)
backend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (44)
.gitignoreCONTRIBUTING.mdREADME.mdbackend/controllers/authController.jsbackend/controllers/flowController.jsbackend/lib/connectDB.jsbackend/models/archiveSchema.jsbackend/routes/hackathonRoutes.jsbackend/server.jsbackend/services/authService.jshackclock/BRAND-GUIDELINES.mdhackclock/README.mdhackclock/app/(admin)/dashboard/page.tsxhackclock/app/(admin)/flow/page.tsxhackclock/app/(admin)/join/page.tsxhackclock/app/(admin)/layout.tsxhackclock/app/(admin)/loading.tsxhackclock/app/(admin)/profile/page.tsxhackclock/app/(admin)/template.tsxhackclock/app/(public)/loading.tsxhackclock/app/(public)/template.tsxhackclock/app/api/auth/[...nextauth]/route.tshackclock/app/clock/page.tsxhackclock/app/globals.csshackclock/app/layout.tsxhackclock/app/loading.tsxhackclock/app/login/page.tsxhackclock/app/room/[id]/clock/page.tsxhackclock/app/room/[id]/loading.tsxhackclock/app/room/[id]/stage/page.tsxhackclock/app/room/[id]/template.tsxhackclock/app/stage/loading.tsxhackclock/app/stage/page.tsxhackclock/app/stage/template.tsxhackclock/app/template.tsxhackclock/components/AuthProvider.tsxhackclock/components/ui/HoldButton.tsxhackclock/components/ui/JoinRoomControls.tsxhackclock/components/ui/Modal.tsxhackclock/components/ui/NotificationPopover.tsxhackclock/components/ui/PageSkeletons.tsxhackclock/components/ui/SettingsPopover.tsxhackclock/components/ui/Sidebar.tsxhackclock/lib/min-delay.ts
| router.get('/', flowController.getAllFlows); | ||
| router.get('/:roomId', flowController.getRoomData); | ||
| router.put('/:roomId', flowController.updateFlow); | ||
| router.delete('/:roomId', flowController.deleteFlow); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FLOW_CTRL="$(fd -i 'flowController.js' | head -n1)"
echo "flow controller: ${FLOW_CTRL}"
# Inspect implementations and nearby auth checks for the newly wired handlers.
rg -n -C4 'getAllFlows|updateFlow|deleteFlow|organizerSecret|401|403|unauthor|forbid|timingSafeEqual' "${FLOW_CTRL}"Repository: SRM-IST-KTR/hacktime
Length of output: 4663
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the full flowController to search for getRoomData
FLOW_CTRL="backend/controllers/flowController.js"
# Search for getRoomData implementation
rg -n 'getRoomData' "${FLOW_CTRL}" -A 10
# Also check if there's any middleware in the routes file
fd -i 'hackathonRoutes.js' -exec cat -n {} \;Repository: SRM-IST-KTR/hacktime
Length of output: 867
🏁 Script executed:
#!/bin/bash
cat -n backend/routes/hackathonRoutes.jsRepository: SRM-IST-KTR/hacktime
Length of output: 680
Fix missing authorization on getRoomData and validate organizerSecret in getAllFlows.
getRoomData(line 7) lacks any authorization check and exposes the full hackathon object publicly for any roomId. Add organizer secret validation to matchupdateFlowanddeleteFlow.getAllFlows(line 6) extractsorganizerSecretfrom the query but does not validate it—only filters by it. Validate the secret against the stored value and return 403 if it does not match.updateFlowanddeleteFlowcorrectly enforce authorization with 403 responses.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@backend/routes/hackathonRoutes.js` around lines 6 - 9, Both endpoints need
explicit organizerSecret validation: in the handler used by router.get('/',
flowController.getAllFlows) ensure you extract organizerSecret from the query
and compare it against the stored organizerSecret for the hackathon before
returning results—if the provided secret is missing or does not match, respond
with 403; and in the handler used by router.get('/:roomId',
flowController.getRoomData) add the same authorization check (compare the
request's organizerSecret to the stored value for that room) and return 403 on
mismatch so getRoomData enforces the same protection as updateFlow and
deleteFlow.
| const engineControlExecution = async (roomId: string, action: 'PAUSE' | 'RESUME' | 'NEXT_PHASE' | 'STOP') => { | ||
| if (!userEmail) return; | ||
| try { | ||
| await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${activeRoomId}/state`, { | ||
| await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${roomId}/state`, { | ||
| method: 'PUT', headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ action, organizerSecret: userEmail }) | ||
| body: JSON.stringify({ action, organizerSecret: userEmail }) | ||
| }); | ||
| mutate(); | ||
| } catch (error) { alert("System Error: Could not connect to Master Node."); } | ||
| mutateAll(); | ||
| if (roomId === activeRoomId) mutateActive(); | ||
| if (action === 'STOP' && roomId === activeRoomId) { | ||
| await update({ activeRoomId: null }); | ||
| } | ||
| } catch { alert("System Error: Could not connect to Master Node."); } | ||
| }; | ||
|
|
||
| const deleteFlowExecution = async (roomId: string) => { | ||
| try { | ||
| await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${roomId}`, { | ||
| method: 'DELETE', headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ organizerSecret: userEmail }) | ||
| }); | ||
| mutateAll(); | ||
| if (roomId === activeRoomId) { | ||
| await update({ activeRoomId: null }); | ||
| mutateActive(); | ||
| } | ||
| } catch { alert("System Error: Deletion failed."); } |
There was a problem hiding this comment.
Check HTTP failures before updating local state.
All of these control paths treat any resolved fetch as success. A 4xx/5xx from the backend will still clear activeRoomId, append broadcast history, and revalidate as if the action succeeded, which can leave the dashboard out of sync with the real flow state.
Also applies to: 146-182
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/dashboard/page.tsx around lines 117 - 143, The fetch
handlers engineControlExecution and deleteFlowExecution currently treat any
resolved fetch as success; change both to check the HTTP response (e.g., if
(!response.ok) throw or handle error) before calling mutateAll(),
mutateActive(), or update({ activeRoomId: null }); on non-OK responses surface
the backend error (or a clear alert) and return early so local state is not
updated; apply the same response.ok check-and-early-return pattern to the other
similar control functions in this file (the block around lines 146-182) so state
updates only occur on successful HTTP responses.
| const syncDuration = () => { | ||
| if (phases.length === 0) return; | ||
| const newPhases = [...phases]; | ||
| // Find the longest phase (usually hacking) and adjust it | ||
| const hackIdx = newPhases.findIndex(p => p.name.toLowerCase().includes('hack') || p.name.toLowerCase().includes('build')) || 1; | ||
| const currentOthers = totalPhaseMinutes - (newPhases[hackIdx]?.durationMinutes || 0); | ||
| const newHackDuration = Math.max(1, scheduledMinutes - currentOthers); | ||
| newPhases[hackIdx] = { ...newPhases[hackIdx], durationMinutes: newHackDuration }; | ||
| setPhases(newPhases); | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
node - <<'JS'
console.log({
'0 || 1': 0 || 1,
'-1 || 1': -1 || 1,
'2 || 1': 2 || 1,
});
JSRepository: SRM-IST-KTR/hacktime
Length of output: 107
Fix the index fallback logic in syncDuration().
The expression findIndex(...) || 1 has a critical bug: it returns 1 when the match is at index 0 (because 0 is falsy), and returns -1 when there's no match (because -1 is truthy). This corrupts the phases array by either updating the wrong phase or creating a property at index -1.
Suggested fix
const newPhases = [...phases];
// Find the longest phase (usually hacking) and adjust it
- const hackIdx = newPhases.findIndex(p => p.name.toLowerCase().includes('hack') || p.name.toLowerCase().includes('build')) || 1;
+ const matchedIndex = newPhases.findIndex(
+ (p) => p.name.toLowerCase().includes('hack') || p.name.toLowerCase().includes('build')
+ );
+ const hackIdx = matchedIndex === -1 ? Math.min(1, newPhases.length - 1) : matchedIndex;
const currentOthers = totalPhaseMinutes - (newPhases[hackIdx]?.durationMinutes || 0);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/flow/page.tsx around lines 120 - 129, The fallback
logic in syncDuration() misuses "findIndex(...) || 1" which treats index 0 as
falsy and -1 as truthy; change it to capture the raw result (e.g., const idx =
newPhases.findIndex(...)) and then set hackIdx = idx === -1 ? 1 : idx, and
optionally guard that hackIdx is within bounds of newPhases before using it;
update references to hackIdx in syncDuration() accordingly so the correct phase
is adjusted.
| const fetcher = (url: string) => fetch(url).then((res) => res.json()); | ||
|
|
There was a problem hiding this comment.
Guard the SWR payload before calling .filter().
fetcher returns res.json() for every response. If this endpoint returns { error: ... } or any non-array payload, both hackathons?.filter(...) calls will throw and take down the profile page instead of falling back cleanly.
🛠️ Suggested fix
-const fetcher = (url: string) => fetch(url).then((res) => res.json());
+const fetcher = async (url: string) => {
+ const res = await fetch(url);
+ const data = await res.json().catch(() => null);
+ if (!res.ok || !Array.isArray(data)) {
+ throw new Error(data?.error || 'Failed to load hackathons');
+ }
+ return data as Hackathon[];
+};
@@
- const archived = hackathons?.filter(h => h.status === 'COMPLETED') || [];
- const active = hackathons?.filter(h => h.status === 'RUNNING' || h.status === 'PAUSED' || h.status === 'DRAFT') || [];
+ const safeHackathons = Array.isArray(hackathons) ? hackathons : [];
+ const archived = safeHackathons.filter(h => h.status === 'COMPLETED');
+ const active = safeHackathons.filter(h => h.status === 'RUNNING' || h.status === 'PAUSED' || h.status === 'DRAFT');Also applies to: 68-69
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/profile/page.tsx around lines 9 - 10, The fetcher
currently returns res.json() unguarded so downstream uses like
hackathons?.filter(...) will throw if the payload is not an array (e.g., {
error: ... }); update the code to validate the SWR payload before filtering by
either (a) making fetcher validate response.ok and return a predictable array on
success/failure (e.g., return [] on non-array/failed responses) or (b) guarding
each usage by replacing hackathons?.filter(...) with Array.isArray(hackathons) ?
hackathons.filter(...) : [] (apply this fix to both occurrences where
hackathons?.filter is used); reference fetcher and the hackathons?.filter calls
to locate and change the logic.
| const { data: hackathons } = useSWR<Hackathon[]>( | ||
| userEmail ? `${process.env.NEXT_PUBLIC_API_URL}/api/hackathons?organizerSecret=${userEmail}` : null, | ||
| fetcher | ||
| ); |
There was a problem hiding this comment.
Don’t put the organizer identity in the URL.
organizerSecret=${userEmail} leaks the organizer email into browser history, intermediary logs, and cache keys. This lookup should be authenticated from the session server-side or sent outside the query string.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/profile/page.tsx around lines 29 - 32, The request is
leaking organizer identity by including organizerSecret=${userEmail} in the
client-side URL; instead, remove that query param and fetch hackathons via an
authenticated server-side endpoint or include the organizer identity in request
headers/body from a secure API route. Update the useSWR call in page.tsx (the
useSWR/Hackathon[] hook that sets hackathons and uses fetcher) to call a
server-side API route (or server component) that derives the organizer from the
session, or send the organizer in a POST/Authorization header to a backend
endpoint that validates the session; ensure the frontend does not interpolate
userEmail into the query string and that the server-side handler uses session
data to filter hackathons.
| if (!eventData || eventData.error || !eventData.phases) { | ||
| return ( | ||
| <div className="flex flex-col min-h-screen items-center justify-center p-6" style={{ backgroundColor: '#0F0F10' }}> | ||
| <div className="glass rounded-[20px] p-12 md:p-16 max-w-xl w-full text-center shadow-2xl relative z-10 overflow-hidden" style={{ border: '1px solid rgba(255,255,255,0.06)' }}> | ||
| <div className="inline-flex p-5 rounded-[20px] mb-10 shadow-2xl" style={{ backgroundColor: 'rgba(244,63,94,0.06)', border: '1px solid rgba(244,63,94,0.15)' }}> | ||
| <X size={40} style={{ color: '#F43F5E' }} /> | ||
| </div> | ||
| <h1 className="text-4xl md:text-5xl font-semibold tracking-tight mb-6" style={{ color: '#E6E6E6' }}> | ||
| Hackathon Not Found | ||
| </h1> | ||
| <p className="text-lg font-medium leading-relaxed mb-12" style={{ color: '#A0A0A0' }}> | ||
| The stage endpoint you are attempting to access does not exist or has been decommissioned. | ||
| </p> | ||
| <Link | ||
| href="/dashboard" | ||
| className="px-8 py-4 rounded-[20px] font-bold text-xs uppercase tracking-[0.2em] transition-all shadow-xl active:scale-95 inline-flex items-center justify-center gap-2" | ||
| style={{ backgroundColor: '#CFFF04', color: '#0F0F10' }} | ||
| > | ||
| <Terminal size={16} /> Hub Terminal | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Don’t render the not-found screen while the first fetch is still loading.
!eventData is true before params resolves and while SWR is fetching, so this shows “Hackathon Not Found” on every normal load. Gate this behind a real loading state and only render the error view after a definitive missing/error response.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/room/`[id]/stage/page.tsx around lines 140 - 163, The not-found
UI is rendering while the initial SWR fetch or params resolution is still
in-flight because the current check uses !eventData; update the conditional to
first detect a real loading state (e.g., use the isValidating/isLoading flag
returned by your SWR hook or a params-ready boolean) and only render the error
view when loading is false and (eventData === null || eventData.error ||
!eventData.phases). Locate the code that reads eventData (and the SWR call that
returns isValidating/isLoading) and change the guard so the loading state
short-circuits to a spinner/placeholder instead of showing the "Hackathon Not
Found" screen. Ensure params resolution (params[id]) is also checked before
deciding the request failed.
| await minDelay(); | ||
| return children; |
There was a problem hiding this comment.
Root template introduces global forced latency.
Line 4 unconditionally delays rendering for the entire app. This creates avoidable UX slowdown in production; gate this to non-production (or remove at root and keep delay only where truly needed).
Suggested change
export default async function RootTemplate({ children }: { children: React.ReactNode }) {
- await minDelay();
+ if (process.env.NODE_ENV !== "production") {
+ await minDelay();
+ }
return children;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await minDelay(); | |
| return children; | |
| export default async function RootTemplate({ children }: { children: React.ReactNode }) { | |
| if (process.env.NODE_ENV !== "production") { | |
| await minDelay(); | |
| } | |
| return children; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/template.tsx` around lines 4 - 5, The root template in
hackclock/app/template.tsx unconditionally calls minDelay() before returning
children, introducing a global forced latency; change this by gating the delay
to non-production only (e.g., check NODE_ENV or a build-time flag) or remove it
from the root and apply minDelay() only in the specific component(s) that
require simulated latency. Locate the minDelay() invocation in the template
function and wrap it in a conditional (or move the call into the targeted
component(s)) so production builds skip the delay while development/test
environments still use it.
| const validateOrganizerRoom = async () => { | ||
| try { | ||
| const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hackathons/${sessionRoom}`); | ||
| if (cancelled) return; | ||
|
|
||
| if (!res.ok) { | ||
| setCurrentRoomId(null); | ||
| setIsGuest(false); | ||
| setGuestName(""); | ||
| if (lastClearedRoomRef.current !== sessionRoom) { | ||
| lastClearedRoomRef.current = sessionRoom; | ||
| await update({ activeRoomId: null }); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| const room = await res.json(); | ||
| if (cancelled) return; | ||
|
|
||
| if (room?.roomId && (room.status === 'RUNNING' || room.status === 'PAUSED') && !room.error) { | ||
| const timeout = setTimeout(() => { | ||
| if (cancelled) return; | ||
| setCurrentRoomId(room.roomId); | ||
| setIsGuest(false); | ||
| setGuestName(""); | ||
| }, 0); | ||
| return () => clearTimeout(timeout); | ||
| } | ||
|
|
||
| setCurrentRoomId(null); | ||
| setIsGuest(false); | ||
| setGuestName(""); | ||
| if (lastClearedRoomRef.current !== sessionRoom) { | ||
| lastClearedRoomRef.current = sessionRoom; | ||
| await update({ activeRoomId: null }); | ||
| } | ||
| } catch { | ||
| if (!cancelled) { | ||
| setCurrentRoomId(null); | ||
| setIsGuest(false); | ||
| setGuestName(""); | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
Don’t treat fetch exceptions as a disconnected room.
Both validation branches clear the room state in catch, but this effect only reruns when session changes. A temporary fetch/JSON failure during mount leaves the sidebar stuck in the offline state until remount even though the room is still active.
Also applies to: 94-131
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/components/ui/Sidebar.tsx` around lines 37 - 80, The
validateOrganizerRoom function currently treats any network/JSON exception as a
real "room disconnected" and clears state; instead, change the catch block so
transient fetch/parse errors do NOT clear the current room state: in the catch
for validateOrganizerRoom (and the identical logic in the other block around
lines 94-131), remove the calls to setCurrentRoomId(null), setIsGuest(false),
setGuestName("") and lastClearedRoomRef/update logic; instead just bail out or
log the error (and optionally schedule a retry) so the sidebar remains showing
the last-known active room until a non-OK response from fetch or explicit room
status indicates it should be cleared. Reference validateOrganizerRoom,
setCurrentRoomId, setIsGuest, setGuestName, lastClearedRoomRef, and update when
making the change.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
hackclock/app/room/[id]/clock/page.tsx (1)
29-40:⚠️ Potential issue | 🟠 MajorSeparate loading state from error state—don't show "Node Not Found" until the fetch conclusively fails.
Lines 29-31 resolve
roomIdafter mount, and SWR starts witheventData === undefinedduring the initial fetch. The guard at line 157 (if (!eventData || eventData.error || !eventData.phases)) renders the not-found screen immediately on load and on transient fetch failures, before you know whether the room exists. DestructureisLoadingandisValidatingfrom the SWR hook to distinguish between "still fetching" and "lookup failed," then only render the not-found UI once the fetch completes with no data.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/clock/page.tsx around lines 29 - 40, The current rendering treats eventData === undefined as a not-found error; update the useSWR call (where you currently read const { data: eventData } = useSWR(..., fetcher, ...)) to destructure loading/validation flags (e.g. const { data: eventData, isLoading, isValidating, error } = useSWR(...)) and change the guard that currently checks if (!eventData || eventData.error || !eventData.phases) so it only shows the "Node Not Found" UI after the fetch has completed and failed: i.e., wait until isLoading/isValidating are false and either error is set or data is definitively empty before rendering the not-found screen; keep the existing useEffect that sets roomId via params and continue using roomId as the SWR key.
♻️ Duplicate comments (3)
hackclock/app/(admin)/dashboard/page.tsx (2)
118-145:⚠️ Potential issue | 🟠 MajorHandle non-2xx responses before mutating session, SWR, or local history.
These control paths still treat any resolved
fetchas success. A 4xx/5xx will clearactiveRoomId, revalidate the dashboard, or append a broadcast to local storage even though the backend rejected the action. Checkresponse.ok, surface the backend error, and return early on failure.Also applies to: 147-183
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/dashboard/page.tsx around lines 118 - 145, In engineControlExecution and deleteFlowExecution, treat a non-2xx fetch as failure: after await fetch(...) inspect response.ok and if false read the error payload (await response.text() or JSON) and surface it (e.g., alert or throw) and return early so you do not call mutateAll(), mutateActive(), or update() on failure; only perform those mutations when response.ok is true. Ensure the catch block still handles network errors separately and that both functions return after handling a non-ok response to avoid proceeding with success-side state changes.
55-57:⚠️ Potential issue | 🟠 MajorKeep
organizerSecretout of the SWR URL.Putting the organizer email/secret in the query string exposes it in browser-visible URLs, caches, and access logs. Fetch organizer-scoped data through an authenticated route, or use a stable SWR key and supply identity outside the URL.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/dashboard/page.tsx around lines 55 - 57, The SWR key currently embeds organizerSecret via userEmail in useSWR (const { data: allFlows, mutate: mutateAll } = useSWR(..., fetcher)), which leaks sensitive info; change to a stable key (e.g., '/api/hackathons/organizer-flows' or ['hackathons','organizer-flows', userEmail? 'auth' : null]) and move the organizer identity off the URL by having fetcher send the user identity through an authenticated request (Authorization header, cookie, or POST body) to the server endpoint that returns organizer-scoped HackathonFlow[], updating the fetcher and the server route to read identity from headers/session rather than from the query string.hackclock/app/(admin)/flow/page.tsx (1)
123-130:⚠️ Potential issue | 🟠 MajorFix the
findIndex(...) || 1fallback before it rewrites the wrong phase.Line 127 still fails in both edge cases: a real match at index
0becomes1, and a miss returns-1, which is truthy, so the write lands onnewPhases[-1]instead of a real phase.Suggested fix
- const hackIdx = newPhases.findIndex(p => p.name.toLowerCase().includes('hack') || p.name.toLowerCase().includes('build')) || 1; + const matchedIndex = newPhases.findIndex( + (p) => p.name.toLowerCase().includes('hack') || p.name.toLowerCase().includes('build') + ); + const hackIdx = matchedIndex === -1 ? Math.min(1, newPhases.length - 1) : matchedIndex;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/`(admin)/flow/page.tsx around lines 123 - 130, The fallback using findIndex(...) || 1 is incorrect because an index of 0 becomes 1 and -1 (not found) is truthy; change the logic in syncDuration: store the result in a local (e.g., const foundIdx = newPhases.findIndex(...)), then set hackIdx = foundIdx === -1 ? Math.min(1, newPhases.length - 1) : foundIdx and ensure hackIdx is within bounds before writing to newPhases; this preserves a real match at index 0, avoids writing to newPhases[-1], and safely falls back to an existing phase.
🧹 Nitpick comments (3)
hackclock/components/ui/Sidebar.tsx (3)
267-268: Consider using CSS for hover states instead of inline event handlers.The
onMouseEnter/onMouseLeavehandlers for hover styles add complexity and potential for state sync issues. CSS:hoverpseudo-class would be simpler and more performant:/* In your CSS module or global styles */ .nav-link:not(.active):hover { color: `#E6E6E6`; background-color: rgba(255,255,255,0.04); }This is a minor enhancement that could be deferred.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/Sidebar.tsx` around lines 267 - 268, Replace the inline onMouseEnter/onMouseLeave handlers in the Sidebar component that conditionally style nav items (the handlers attached to elements using isActive) with a CSS-based hover rule; remove the two event handlers (onMouseEnter and onMouseLeave) from the element(s) and add a selector (e.g., .nav-link:not(.active):hover) in the component's stylesheet or CSS module to apply color `#E6E6E6` and background rgba(255,255,255,0.04) on hover while keeping the existing active styling logic (isActive and the .active class) intact.
175-180: Missing error handling on organizer disconnect API call.If the PUT request to clear the active room fails, the client continues to call
update({ activeRoomId: null })and closes the sidebar, but the backend may still have the room associated. This could cause state inconsistency on next login.🛡️ Suggested fix
// Disconnect Organizer - await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/auth/active-room`, { + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/auth/active-room`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: session?.user?.email, roomId: null }) }); + if (!res.ok) { + console.error('Failed to disconnect from room'); + // Optionally show user feedback + } await update({ activeRoomId: null });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/Sidebar.tsx` around lines 175 - 180, The PUT call that clears the active room (the fetch to `${process.env.NEXT_PUBLIC_API_URL}/api/auth/active-room`) lacks error handling and the client always calls update({ activeRoomId: null }) afterwards; wrap the network call in a try/catch, check response.ok (or inspect response status/body) and only call update({ activeRoomId: null }) and close the sidebar when the request succeeds, otherwise handle the failure by logging the error, surfacing a user-facing message or retrying as appropriate; update the error handling inside the Sidebar component around the existing fetch and the subsequent call to update so that failures do not desynchronize backend state.
192-205: Variable naming is misleading and timeout could queue multiple transitions.
shouldAnimateStageExitactually triggers animation when entering stage mode, not exiting. Consider renaming toshouldAnimateStageEntrance.Rapid clicks could queue multiple timeouts since
stageTransitionTimeoutRefis overwritten without clearing the previous one:🔧 Suggested fix
const handleNavClick = (href: string) => { - const shouldAnimateStageExit = href.startsWith('/room/') && href.endsWith('/stage') && pathname !== href; + const shouldAnimateStageEntrance = href.startsWith('/room/') && href.endsWith('/stage') && pathname !== href; - if (!shouldAnimateStageExit) { + if (!shouldAnimateStageEntrance) { onNavItemClick?.(); return; } setIsStageTransitioning(true); + if (stageTransitionTimeoutRef.current) { + window.clearTimeout(stageTransitionTimeoutRef.current); + } stageTransitionTimeoutRef.current = window.setTimeout(() => { router.push(href); onNavItemClick?.(); }, 220); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/components/ui/Sidebar.tsx` around lines 192 - 205, The nav click handler's boolean name is misleading and timeouts may stack: rename shouldAnimateStageExit to shouldAnimateStageEntrance (or similar) in handleNavClick to reflect that it triggers when entering a stage route, and before creating a new timeout clear any existing one via clearTimeout(stageTransitionTimeoutRef.current); then set stageTransitionTimeoutRef.current = window.setTimeout(...), and inside the timeout clear the ref (e.g., stageTransitionTimeoutRef.current = undefined) after calling router.push and onNavItemClick; keep the existing calls to setIsStageTransitioning(true) and router.push(href) but ensure only one pending timeout exists at a time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@hackclock/app/`(admin)/dashboard/page.tsx:
- Around line 55-59: The callsite uses useSWR to load allFlows (const { data:
allFlows, mutate: mutateAll } = useSWR(..., fetcher)) but downstream code
assumes allFlows is an array and calls .filter(), which will throw if the
fetcher returned an error object (e.g., getAllFlows returned { error: ... }).
Fix by guarding those derivations with Array.isArray(allFlows) before calling
.filter (or change fetcher/getAllFlows to throw on non-OK responses so SWR data
is never a non-array), and update the places that compute filtered lists (the
.filter usages referenced around active/archived derivations) to fallback to []
when Array.isArray is false.
- Around line 392-399: The numeric input for announcement duration allows
negative values because parseInt(e.target.value) || 5 treats negative numbers as
truthy; update the input to enforce min={1} and change the onChange handler used
with announcementDuration and setAnnouncementDuration to clamp the parsed value
to at least 1 (e.g. compute const v = Math.max(1, parseInt(e.target.value) || 0)
and pass v to setAnnouncementDuration) so the stored announcementDuration is
always >= 1 before any save or use in the overlay/progress animation.
In `@hackclock/app/`(admin)/flow/page.tsx:
- Around line 141-143: The FileReader onloadend callback closes over the current
formData and can overwrite concurrent edits; update the reader.onloadend
callback to use the functional updater form of setFormData so it merges into the
latest state (i.e., call setFormData(prev => ({ ...prev, logoUrl: reader.result
as string })) inside reader.onloadend) instead of referencing the outer formData
variable; keep the rest of the FileReader usage (new FileReader,
reader.readAsDataURL(file)) unchanged.
In `@hackclock/app/stage/page.tsx`:
- Around line 9-15: The redirect uses a session-derived activeRoomId directly;
validate and sanitize it before building the path: ensure activeRoomId is a
non-empty string (e.g. typeof activeRoomId === "string" &&
activeRoomId.trim().length > 0), optionally validate against an allowed pattern
(e.g. /^[A-Za-z0-9_-]+$/) and then use an encoded segment
(encodeURIComponent(activeRoomId)) when calling redirect(`/room/${...}/stage`)
so malformed or unexpected values from session.user.activeRoomId cannot produce
an unsafe path.
In `@hackclock/components/ui/Sidebar.tsx`:
- Around line 250-261: The onClick handler for the Link is missing the same
active-path check used in handleNavClick, so add the pathname !== href check to
the shouldAnimateStageExit condition (i.e., compute shouldAnimateStageExit as
item.name === 'Stage Mode' && item.href.startsWith('/room/') &&
item.href.endsWith('/stage') && pathname !== item.href) so the click
short-circuits only when navigating away from the current Stage Mode route and
matches handleNavClick's logic.
- Around line 116-125: The guest-join block currently only checks room?.roomId
and !room.error before setting state (setCurrentRoomId, setCurrentRoomName,
setIsGuest, setGuestName), allowing guests into COMPLETED rooms; update the
condition to mirror the organizer validation by also requiring an active status
(e.g., room.status === "RUNNING" || room.status === "PAUSED") before scheduling
the timeout and setting guest state, or if allowing COMPLETED rooms is
intentional, add a clear comment above the block explaining that behavior.
---
Outside diff comments:
In `@hackclock/app/room/`[id]/clock/page.tsx:
- Around line 29-40: The current rendering treats eventData === undefined as a
not-found error; update the useSWR call (where you currently read const { data:
eventData } = useSWR(..., fetcher, ...)) to destructure loading/validation flags
(e.g. const { data: eventData, isLoading, isValidating, error } = useSWR(...))
and change the guard that currently checks if (!eventData || eventData.error ||
!eventData.phases) so it only shows the "Node Not Found" UI after the fetch has
completed and failed: i.e., wait until isLoading/isValidating are false and
either error is set or data is definitively empty before rendering the not-found
screen; keep the existing useEffect that sets roomId via params and continue
using roomId as the SWR key.
---
Duplicate comments:
In `@hackclock/app/`(admin)/dashboard/page.tsx:
- Around line 118-145: In engineControlExecution and deleteFlowExecution, treat
a non-2xx fetch as failure: after await fetch(...) inspect response.ok and if
false read the error payload (await response.text() or JSON) and surface it
(e.g., alert or throw) and return early so you do not call mutateAll(),
mutateActive(), or update() on failure; only perform those mutations when
response.ok is true. Ensure the catch block still handles network errors
separately and that both functions return after handling a non-ok response to
avoid proceeding with success-side state changes.
- Around line 55-57: The SWR key currently embeds organizerSecret via userEmail
in useSWR (const { data: allFlows, mutate: mutateAll } = useSWR(..., fetcher)),
which leaks sensitive info; change to a stable key (e.g.,
'/api/hackathons/organizer-flows' or ['hackathons','organizer-flows', userEmail?
'auth' : null]) and move the organizer identity off the URL by having fetcher
send the user identity through an authenticated request (Authorization header,
cookie, or POST body) to the server endpoint that returns organizer-scoped
HackathonFlow[], updating the fetcher and the server route to read identity from
headers/session rather than from the query string.
In `@hackclock/app/`(admin)/flow/page.tsx:
- Around line 123-130: The fallback using findIndex(...) || 1 is incorrect
because an index of 0 becomes 1 and -1 (not found) is truthy; change the logic
in syncDuration: store the result in a local (e.g., const foundIdx =
newPhases.findIndex(...)), then set hackIdx = foundIdx === -1 ? Math.min(1,
newPhases.length - 1) : foundIdx and ensure hackIdx is within bounds before
writing to newPhases; this preserves a real match at index 0, avoids writing to
newPhases[-1], and safely falls back to an existing phase.
---
Nitpick comments:
In `@hackclock/components/ui/Sidebar.tsx`:
- Around line 267-268: Replace the inline onMouseEnter/onMouseLeave handlers in
the Sidebar component that conditionally style nav items (the handlers attached
to elements using isActive) with a CSS-based hover rule; remove the two event
handlers (onMouseEnter and onMouseLeave) from the element(s) and add a selector
(e.g., .nav-link:not(.active):hover) in the component's stylesheet or CSS module
to apply color `#E6E6E6` and background rgba(255,255,255,0.04) on hover while
keeping the existing active styling logic (isActive and the .active class)
intact.
- Around line 175-180: The PUT call that clears the active room (the fetch to
`${process.env.NEXT_PUBLIC_API_URL}/api/auth/active-room`) lacks error handling
and the client always calls update({ activeRoomId: null }) afterwards; wrap the
network call in a try/catch, check response.ok (or inspect response status/body)
and only call update({ activeRoomId: null }) and close the sidebar when the
request succeeds, otherwise handle the failure by logging the error, surfacing a
user-facing message or retrying as appropriate; update the error handling inside
the Sidebar component around the existing fetch and the subsequent call to
update so that failures do not desynchronize backend state.
- Around line 192-205: The nav click handler's boolean name is misleading and
timeouts may stack: rename shouldAnimateStageExit to shouldAnimateStageEntrance
(or similar) in handleNavClick to reflect that it triggers when entering a stage
route, and before creating a new timeout clear any existing one via
clearTimeout(stageTransitionTimeoutRef.current); then set
stageTransitionTimeoutRef.current = window.setTimeout(...), and inside the
timeout clear the ref (e.g., stageTransitionTimeoutRef.current = undefined)
after calling router.push and onNavItemClick; keep the existing calls to
setIsStageTransitioning(true) and router.push(href) but ensure only one pending
timeout exists at a time.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1714ef17-9905-42e0-acad-1601e33dd66c
📒 Files selected for processing (7)
hackclock/app/(admin)/dashboard/page.tsxhackclock/app/(admin)/flow/page.tsxhackclock/app/clock/page.tsxhackclock/app/room/[id]/clock/page.tsxhackclock/app/room/[id]/stage/page.tsxhackclock/app/stage/page.tsxhackclock/components/ui/Sidebar.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- hackclock/app/clock/page.tsx
- hackclock/app/room/[id]/stage/page.tsx
| const { data: allFlows, mutate: mutateAll } = useSWR<HackathonFlow[]>( | ||
| userEmail ? `${process.env.NEXT_PUBLIC_API_URL}/api/hackathons?organizerSecret=${userEmail}` : null, | ||
| fetcher, | ||
| { refreshInterval: 3000 } | ||
| ); |
There was a problem hiding this comment.
Guard allFlows before calling .filter().
getAllFlows returns { error: ... } on backend failures. If that JSON lands in allFlows, the filters below throw because the value is no longer an array. Either make the fetcher throw on non-OK responses or gate these derivations with Array.isArray(allFlows) first.
Suggested fix
- const activeFlows = allFlows?.filter((f) => f.status === 'RUNNING' || f.status === 'PAUSED') || [];
- const drafts = allFlows?.filter((f) => f.status === 'DRAFT') || [];
- const completed = allFlows?.filter((f) => f.status === 'COMPLETED') || [];
+ const flowList = Array.isArray(allFlows) ? allFlows : [];
+ const activeFlows = flowList.filter((f) => f.status === 'RUNNING' || f.status === 'PAUSED');
+ const drafts = flowList.filter((f) => f.status === 'DRAFT');
+ const completed = flowList.filter((f) => f.status === 'COMPLETED');Also applies to: 185-187
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/dashboard/page.tsx around lines 55 - 59, The callsite
uses useSWR to load allFlows (const { data: allFlows, mutate: mutateAll } =
useSWR(..., fetcher)) but downstream code assumes allFlows is an array and calls
.filter(), which will throw if the fetcher returned an error object (e.g.,
getAllFlows returned { error: ... }). Fix by guarding those derivations with
Array.isArray(allFlows) before calling .filter (or change fetcher/getAllFlows to
throw on non-OK responses so SWR data is never a non-array), and update the
places that compute filtered lists (the .filter usages referenced around
active/archived derivations) to fallback to [] when Array.isArray is false.
| <input | ||
| type="number" | ||
| value={announcementDuration} | ||
| onChange={(e) => setAnnouncementDuration(parseInt(e.target.value) || 5)} | ||
| className="w-24 rounded-[20px] py-4 pr-10 pl-4 text-center text-sm outline-none font-mono" | ||
| style={{ backgroundColor: 'rgba(15,15,16,0.6)', border: '1px solid rgba(255,255,255,0.04)', color: '#E6E6E6' }} | ||
| /> | ||
| <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[9px] font-bold pointer-events-none uppercase" style={{ color: '#6B7280' }}>Sec</span> |
There was a problem hiding this comment.
Clamp announcement duration to a positive value.
parseInt(e.target.value) || 5 lets negative numbers through because -1 is truthy. That means a user can send announcementDuration < 1, which makes the clock overlay dismiss immediately and leaves the progress animation with an invalid duration. Add min={1} and clamp before saving.
Suggested fix
<input
type="number"
+ min={1}
value={announcementDuration}
- onChange={(e) => setAnnouncementDuration(parseInt(e.target.value) || 5)}
+ onChange={(e) => {
+ const next = parseInt(e.target.value, 10);
+ setAnnouncementDuration(Number.isFinite(next) ? Math.max(1, next) : 5);
+ }}
className="w-24 rounded-[20px] py-4 pr-10 pl-4 text-center text-sm outline-none font-mono"
style={{ backgroundColor: 'rgba(15,15,16,0.6)', border: '1px solid rgba(255,255,255,0.04)', color: '#E6E6E6' }}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <input | |
| type="number" | |
| value={announcementDuration} | |
| onChange={(e) => setAnnouncementDuration(parseInt(e.target.value) || 5)} | |
| className="w-24 rounded-[20px] py-4 pr-10 pl-4 text-center text-sm outline-none font-mono" | |
| style={{ backgroundColor: 'rgba(15,15,16,0.6)', border: '1px solid rgba(255,255,255,0.04)', color: '#E6E6E6' }} | |
| /> | |
| <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[9px] font-bold pointer-events-none uppercase" style={{ color: '#6B7280' }}>Sec</span> | |
| <input | |
| type="number" | |
| min={1} | |
| value={announcementDuration} | |
| onChange={(e) => { | |
| const next = parseInt(e.target.value, 10); | |
| setAnnouncementDuration(Number.isFinite(next) ? Math.max(1, next) : 5); | |
| }} | |
| className="w-24 rounded-[20px] py-4 pr-10 pl-4 text-center text-sm outline-none font-mono" | |
| style={{ backgroundColor: 'rgba(15,15,16,0.6)', border: '1px solid rgba(255,255,255,0.04)', color: '#E6E6E6' }} | |
| /> | |
| <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[9px] font-bold pointer-events-none uppercase" style={{ color: '#6B7280' }}>Sec</span> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/dashboard/page.tsx around lines 392 - 399, The numeric
input for announcement duration allows negative values because
parseInt(e.target.value) || 5 treats negative numbers as truthy; update the
input to enforce min={1} and change the onChange handler used with
announcementDuration and setAnnouncementDuration to clamp the parsed value to at
least 1 (e.g. compute const v = Math.max(1, parseInt(e.target.value) || 0) and
pass v to setAnnouncementDuration) so the stored announcementDuration is always
>= 1 before any save or use in the overlay/progress animation.
| const reader = new FileReader(); | ||
| reader.onloadend = () => { | ||
| setFormData({ ...formData, logoUrl: reader.result as string }); | ||
| }; | ||
| reader.onloadend = () => setFormData({ ...formData, logoUrl: reader.result as string }); | ||
| reader.readAsDataURL(file); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "page.tsx" | rg "hackclock/app/\(admin\)/flow"Repository: SRM-IST-KTR/hacktime
Length of output: 99
🏁 Script executed:
cat -n "hackclock/app/(admin)/flow/page.tsx" | head -200Repository: SRM-IST-KTR/hacktime
Length of output: 9423
Use the functional updater pattern to avoid stale state closure in the FileReader callback.
onloadend is async. If the user edits another field before the file finishes reading, the closure over the old formData snapshot will replay and discard those changes. Use a functional updater instead:
Suggested fix
- reader.onloadend = () => setFormData({ ...formData, logoUrl: reader.result as string });
+ reader.onloadend = () => {
+ setFormData((prev) => ({ ...prev, logoUrl: reader.result as string }));
+ };📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const reader = new FileReader(); | |
| reader.onloadend = () => { | |
| setFormData({ ...formData, logoUrl: reader.result as string }); | |
| }; | |
| reader.onloadend = () => setFormData({ ...formData, logoUrl: reader.result as string }); | |
| reader.readAsDataURL(file); | |
| const reader = new FileReader(); | |
| reader.onloadend = () => { | |
| setFormData((prev) => ({ ...prev, logoUrl: reader.result as string })); | |
| }; | |
| reader.readAsDataURL(file); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/`(admin)/flow/page.tsx around lines 141 - 143, The FileReader
onloadend callback closes over the current formData and can overwrite concurrent
edits; update the reader.onloadend callback to use the functional updater form
of setFormData so it merges into the latest state (i.e., call setFormData(prev
=> ({ ...prev, logoUrl: reader.result as string })) inside reader.onloadend)
instead of referencing the outer formData variable; keep the rest of the
FileReader usage (new FileReader, reader.readAsDataURL(file)) unchanged.
| const activeRoomId = session?.user && "activeRoomId" in session.user | ||
| ? session.user.activeRoomId | ||
| : undefined; | ||
|
|
||
| // If user is authenticated and has an active room, direct them to that room's stage | ||
| if (activeRoomId) { | ||
| redirect(`/room/${activeRoomId}/stage`); |
There was a problem hiding this comment.
Harden redirect input before building the route path.
Line 15 interpolates a session-derived value directly into the URL path. Add a strict string check and encode the segment to avoid malformed redirects when activeRoomId is unexpected.
Suggested patch
- const activeRoomId = session?.user && "activeRoomId" in session.user
- ? session.user.activeRoomId
- : undefined;
+ const activeRoomId =
+ session?.user &&
+ "activeRoomId" in session.user &&
+ typeof session.user.activeRoomId === "string"
+ ? session.user.activeRoomId.trim()
+ : "";
// If user is authenticated and has an active room, direct them to that room's stage
if (activeRoomId) {
- redirect(`/room/${activeRoomId}/stage`);
+ redirect(`/room/${encodeURIComponent(activeRoomId)}/stage`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const activeRoomId = session?.user && "activeRoomId" in session.user | |
| ? session.user.activeRoomId | |
| : undefined; | |
| // If user is authenticated and has an active room, direct them to that room's stage | |
| if (activeRoomId) { | |
| redirect(`/room/${activeRoomId}/stage`); | |
| const activeRoomId = | |
| session?.user && | |
| "activeRoomId" in session.user && | |
| typeof session.user.activeRoomId === "string" | |
| ? session.user.activeRoomId.trim() | |
| : ""; | |
| // If user is authenticated and has an active room, direct them to that room's stage | |
| if (activeRoomId) { | |
| redirect(`/room/${encodeURIComponent(activeRoomId)}/stage`); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/app/stage/page.tsx` around lines 9 - 15, The redirect uses a
session-derived activeRoomId directly; validate and sanitize it before building
the path: ensure activeRoomId is a non-empty string (e.g. typeof activeRoomId
=== "string" && activeRoomId.trim().length > 0), optionally validate against an
allowed pattern (e.g. /^[A-Za-z0-9_-]+$/) and then use an encoded segment
(encodeURIComponent(activeRoomId)) when calling redirect(`/room/${...}/stage`)
so malformed or unexpected values from session.user.activeRoomId cannot produce
an unsafe path.
| if (room?.roomId && !room.error) { | ||
| const timeout = setTimeout(() => { | ||
| if (cancelled) return; | ||
| setCurrentRoomId(parsed.roomId); | ||
| setCurrentRoomName(room.name); | ||
| setIsGuest(true); | ||
| setGuestName(parsed.teamName || "Guest"); | ||
| }, 0); | ||
| return () => clearTimeout(timeout); | ||
| } |
There was a problem hiding this comment.
Guest rooms don't validate status.
Unlike organizer validation (line 58) which checks for RUNNING or PAUSED status, guest validation only checks that the room exists. This allows guests to connect to COMPLETED rooms, which may show stale data.
If this is intentional (e.g., to let guests view final results), consider adding a comment. Otherwise, align with organizer validation:
🔧 Suggested fix to add status check
- if (room?.roomId && !room.error) {
+ if (room?.roomId && ['RUNNING', 'PAUSED'].includes(room.status) && !room.error) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (room?.roomId && !room.error) { | |
| const timeout = setTimeout(() => { | |
| if (cancelled) return; | |
| setCurrentRoomId(parsed.roomId); | |
| setCurrentRoomName(room.name); | |
| setIsGuest(true); | |
| setGuestName(parsed.teamName || "Guest"); | |
| }, 0); | |
| return () => clearTimeout(timeout); | |
| } | |
| if (room?.roomId && ['RUNNING', 'PAUSED'].includes(room.status) && !room.error) { | |
| const timeout = setTimeout(() => { | |
| if (cancelled) return; | |
| setCurrentRoomId(parsed.roomId); | |
| setCurrentRoomName(room.name); | |
| setIsGuest(true); | |
| setGuestName(parsed.teamName || "Guest"); | |
| }, 0); | |
| return () => clearTimeout(timeout); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/components/ui/Sidebar.tsx` around lines 116 - 125, The guest-join
block currently only checks room?.roomId and !room.error before setting state
(setCurrentRoomId, setCurrentRoomName, setIsGuest, setGuestName), allowing
guests into COMPLETED rooms; update the condition to mirror the organizer
validation by also requiring an active status (e.g., room.status === "RUNNING"
|| room.status === "PAUSED") before scheduling the timeout and setting guest
state, or if allowing COMPLETED rooms is intentional, add a clear comment above
the block explaining that behavior.
| <Link | ||
| href={item.href} | ||
| onClick={(e) => { | ||
| const shouldAnimateStageExit = item.name === 'Stage Mode' && item.href.startsWith('/room/') && item.href.endsWith('/stage'); | ||
|
|
||
| if (shouldAnimateStageExit) { | ||
| e.preventDefault(); | ||
| handleNavClick(item.href); | ||
| return; | ||
| } | ||
| onNavItemClick?.(); | ||
| }} |
There was a problem hiding this comment.
Inconsistent condition between onClick and handleNavClick.
The onClick handler (line 253-254) doesn't include the pathname !== href check that handleNavClick has (line 193). This means clicking on the already-active Stage Mode link will still trigger the transition animation unnecessarily.
🔧 Suggested fix
onClick={(e) => {
- const shouldAnimateStageExit = item.name === 'Stage Mode' && item.href.startsWith('/room/') && item.href.endsWith('/stage');
+ const shouldAnimateStageEntrance = item.name === 'Stage Mode' && item.href.startsWith('/room/') && item.href.endsWith('/stage') && pathname !== item.href;
- if (shouldAnimateStageExit) {
+ if (shouldAnimateStageEntrance) {
e.preventDefault();
handleNavClick(item.href);
return;
}
onNavItemClick?.();
}}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Link | |
| href={item.href} | |
| onClick={(e) => { | |
| const shouldAnimateStageExit = item.name === 'Stage Mode' && item.href.startsWith('/room/') && item.href.endsWith('/stage'); | |
| if (shouldAnimateStageExit) { | |
| e.preventDefault(); | |
| handleNavClick(item.href); | |
| return; | |
| } | |
| onNavItemClick?.(); | |
| }} | |
| <Link | |
| href={item.href} | |
| onClick={(e) => { | |
| const shouldAnimateStageEntrance = item.name === 'Stage Mode' && item.href.startsWith('/room/') && item.href.endsWith('/stage') && pathname !== item.href; | |
| if (shouldAnimateStageEntrance) { | |
| e.preventDefault(); | |
| handleNavClick(item.href); | |
| return; | |
| } | |
| onNavItemClick?.(); | |
| }} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hackclock/components/ui/Sidebar.tsx` around lines 250 - 261, The onClick
handler for the Link is missing the same active-path check used in
handleNavClick, so add the pathname !== href check to the shouldAnimateStageExit
condition (i.e., compute shouldAnimateStageExit as item.name === 'Stage Mode' &&
item.href.startsWith('/room/') && item.href.endsWith('/stage') && pathname !==
item.href) so the click short-circuits only when navigating away from the
current Stage Mode route and matches handleNavClick's logic.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
hackclock/app/room/[id]/stage/page.tsx (1)
245-254:⚠️ Potential issue | 🟠 MajorConvert this control to a
<button>element for keyboard and assistive technology support.This
<div>withonClickis not keyboard-accessible or announced as interactive to screen readers, blocking keyboard and assistive-tech users from opening the history drawer.Suggested fix
- <div + <button + type="button" + aria-label="Open broadcast history" onClick={() => setShowHistory(true)} - className="w-40 md:w-80 flex items-center px-4 md:px-8 gap-3 md:gap-4 cursor-pointer transition-all group" + className="w-40 md:w-80 flex items-center px-4 md:px-8 gap-3 md:gap-4 cursor-pointer transition-all group border-0 text-left" style={{ backgroundColor: '#1C1C1C', borderRight: '1px solid rgba(255,255,255,0.04)' }} onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#232323'} onMouseLeave={(e) => e.currentTarget.style.backgroundColor = '#1C1C1C'} > <Megaphone size={16} className="md:size-[20px] transition-transform group-hover:scale-110" style={{ color: '#FF2E9A' }} /> <span className="text-[10px] md:text-sm font-bold tracking-[0.1em] md:tracking-[0.2em] uppercase truncate" style={{ color: '#E6E6E6' }}>{eventData.announcement || "SYSTEM NOMINAL"}</span> - </div> + </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hackclock/app/room/`[id]/stage/page.tsx around lines 245 - 254, Replace the interactive <div> with a semantic <button> so keyboard and screen-reader users can open the history drawer; keep the same className, inline styles, Megaphone icon and text (eventData.announcement || "SYSTEM NOMINAL"), set type="button", keep the onClick handler setShowHistory(true), and convert onMouseEnter/onMouseLeave to equivalent onFocus/onBlur (or keep both) to preserve hover/focus styling; also add an accessible label (e.g., aria-label="Open history") if the visible text may be truncated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@hackclock/app/room/`[id]/stage/page.tsx:
- Around line 245-254: Replace the interactive <div> with a semantic <button> so
keyboard and screen-reader users can open the history drawer; keep the same
className, inline styles, Megaphone icon and text (eventData.announcement ||
"SYSTEM NOMINAL"), set type="button", keep the onClick handler
setShowHistory(true), and convert onMouseEnter/onMouseLeave to equivalent
onFocus/onBlur (or keep both) to preserve hover/focus styling; also add an
accessible label (e.g., aria-label="Open history") if the visible text may be
truncated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: aafbf0df-93a7-4e37-a577-877c6b8f8569
📒 Files selected for processing (1)
hackclock/app/room/[id]/stage/page.tsx
* merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly * feat: Enhance metadata and layout for improved SEO and user experience (#15) - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly * feat: Enhance metadata and layout for improved SEO and user experience (#15) - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * seo (#17) * feat: Enhance metadata and layout for improved SEO and user experience - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * feat: Update favicon and enhance layout metadata for improved branding and SEO --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* seo update (#18) * merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly * feat: Enhance metadata and layout for improved SEO and user experience (#15) - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * seo (#17) * feat: Enhance metadata and layout for improved SEO and user experience - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * feat: Update favicon and enhance layout metadata for improved branding and SEO --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Install Vercel Web Analytics (#19) ## Vercel Web Analytics Installation Successfully installed and configured Vercel Web Analytics for the hackTime project. ### Changes Made **Modified Files:** - `hackclock/app/layout.tsx` - Added Analytics component to the root layout - `hackclock/package.json` - Added @vercel/analytics dependency (v2.0.1) - `hackclock/package-lock.json` - Updated lockfile with new dependency tree ### Implementation Details 1. **Documentation Reference:** Fetched the latest installation instructions from https://vercel.com/docs/analytics/quickstart to ensure up-to-date configuration. 2. **Framework Detection:** Identified this as a Next.js 16.2.1 App Router project using npm as the package manager. 3. **Package Installation:** Installed `@vercel/analytics` version 2.0.1 using npm. 4. **Configuration:** Following the official Next.js App Router instructions: - Imported `{ Analytics }` from `@vercel/analytics/next` in the root layout - Added `<Analytics />` component at the end of the `<body>` tag, after the main content - Preserved existing code structure including AuthProvider and all styling ### Verification Completed ✅ Build completed successfully with no errors ✅ Linter ran with no new errors introduced ✅ Analytics component properly integrated into the React component tree ✅ Lock file updated to maintain dependency consistency ### Next Steps To enable analytics tracking in production: 1. Deploy this code to Vercel 2. Enable Web Analytics in the Vercel dashboard (Analytics section) 3. Analytics will automatically start tracking page views and user interactions The Analytics component will work seamlessly in both development and production environments, with tracking only active when deployed to Vercel. Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
* merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly * feat: Enhance metadata and layout for improved SEO and user experience (#15) - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * seo (#17) * feat: Enhance metadata and layout for improved SEO and user experience - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * feat: Update favicon and enhance layout metadata for improved branding and SEO * seo update (#18) (#20) * seo update (#18) * merge stabe mvp to main repo (#10) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> * updated readme files (#11) * Added initial backend , frontend and mongo files * added initial backend frontend and mongo schema * Add Next.js frontend and root config files * added models and routes * added Admin > Dashboard Static UI * added Admin > Dashbord * Update CONTRIBUTING.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added login auth (next auth )and sessionized token system and flow creation page * added login auth (next auth )and sessionized token system and flow creation page * updated package.jsons * added profile making and updation feature and its working * Huge update - Working dashboard with enhanced security features working clock view and working flow creator and working stage mode * Fixed creashing issues and package.json errors * added brodcast feature * fixed all typescript errors and optimized for production * fixed all typescript errors and optimized for production * fixed server to show health check * Added proper vercel compatitability in backend * Fixed cors error * functional * feat: add admin schedule editing capabilities to the clock page and clean up layout UI * refactor: redesign profile page with SWR data fetching and updated UI components * ignnore this * Improve sidebar navigation and loading states * server fixed (hopefully) * initial Optimization * Git OAuth Fixed * Git OAuth Fixed(hopefully) * refactor: implement robust session room validation, responsive UI updates for stage standby, and fix NextAuth session update logic. * UI improvements as per saumya, and fix stale data problem * Added feat: save att hacathons to al h.... * clock fixed in stage mode * fixed account button dissapearing in smaller screens * Added readmes and contributing.md * update readmes and contributing.md * ui changes requested by saumya * refactor: remove redundant state and ref declarations in stage page --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Diptayan Jash <dj2037@srmist.edu.in> Co-authored-by: Diptayan Jash <djdiptayan1@gmail.com> * HackTime DB migration, Soft-Delete sync, and Terminal UI restoration (#13) * final pull * all hackathons save system to manage all past hackathons * all hackathons now update accordingly * feat: Enhance metadata and layout for improved SEO and user experience (#15) - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * seo (#17) * feat: Enhance metadata and layout for improved SEO and user experience - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * feat: Update favicon and enhance layout metadata for improved branding and SEO --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Install Vercel Web Analytics (#19) ## Vercel Web Analytics Installation Successfully installed and configured Vercel Web Analytics for the hackTime project. ### Changes Made **Modified Files:** - `hackclock/app/layout.tsx` - Added Analytics component to the root layout - `hackclock/package.json` - Added @vercel/analytics dependency (v2.0.1) - `hackclock/package-lock.json` - Updated lockfile with new dependency tree ### Implementation Details 1. **Documentation Reference:** Fetched the latest installation instructions from https://vercel.com/docs/analytics/quickstart to ensure up-to-date configuration. 2. **Framework Detection:** Identified this as a Next.js 16.2.1 App Router project using npm as the package manager. 3. **Package Installation:** Installed `@vercel/analytics` version 2.0.1 using npm. 4. **Configuration:** Following the official Next.js App Router instructions: - Imported `{ Analytics }` from `@vercel/analytics/next` in the root layout - Added `<Analytics />` component at the end of the `<body>` tag, after the main content - Preserved existing code structure including AuthProvider and all styling ### Verification Completed ✅ Build completed successfully with no errors ✅ Linter ran with no new errors introduced ✅ Analytics component properly integrated into the React component tree ✅ Lock file updated to maintain dependency consistency ### Next Steps To enable analytics tracking in production: 1. Deploy this code to Vercel 2. Enable Web Analytics in the Vercel dashboard (Analytics section) 3. Analytics will automatically start tracking page views and user interactions The Analytics component will work seamlessly in both development and production environments, with tracking only active when deployed to Vercel. Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> * stage responsiveness (#21) * feat: Enhance metadata and layout for improved SEO and user experience - Added metadata for the Clock page to improve search engine visibility. - Updated layout and metadata for the main application to reflect new branding and features. - Introduced a new Login layout with specific metadata for better indexing. - Enhanced the Login page with dynamic tab selection based on URL parameters. - Created a sitemap and robots.txt for better search engine crawling. - Added a new Room layout with appropriate metadata. - Improved the Stage page layout and metadata for clarity and SEO. - Added Open Graph and Twitter card images for better social media sharing. - Included new SVG and JPG images for Open Graph representation. * feat: Update favicon and enhance layout metadata for improved branding and SEO * style: Update layout and styling for improved responsiveness and user experience * feat: Update favicon and enhance layout metadata for improved branding and SEO --------- Co-authored-by: Shibraj Das <166467244+Cyberbee-pro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
docs: refresh README and contribution guides with deployment linksSummary by CodeRabbit
New Features
Documentation
Chores