Skip to content

Feature/session wide algorithm#36

Open
Psangs1 wants to merge 47 commits into
mainfrom
feature/session-wide-algorithm
Open

Feature/session wide algorithm#36
Psangs1 wants to merge 47 commits into
mainfrom
feature/session-wide-algorithm

Conversation

@Psangs1

@Psangs1 Psangs1 commented Sep 28, 2025

Copy link
Copy Markdown
Collaborator

Created the initial scheduling algorithm to assign days off and nights off for employees, and added extra fields to the StaffSessionAttendee type to store nights off and days off.

Summary by CodeRabbit

  • New Features

    • Implemented session scheduling with automatic day-off and night-shift assignment capabilities
    • Added role-based navigation filtering to display relevant menu options per user
  • Refactor

    • Standardized date handling throughout scheduling system
  • Style

    • Updated navigation styling and removed unused code

@coderabbitai

coderabbitai Bot commented Sep 28, 2025

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1bd717be-2745-4774-b15a-a0cbddcf7763

📥 Commits

Reviewing files that changed from the base of the PR and between 1028ff4 and ae15a0a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx
  • src/components/Navbar.tsx
  • src/components/NightScheduleTable.tsx
  • src/data/firestore/freeplays.ts
  • src/data/firestore/nightSchedules.ts
  • src/features/scheduling/generation/SessionScheduler.ts
  • src/features/scheduling/generation/generateDaysOffSchedule.ts
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
💤 Files with no reviewable changes (1)
  • src/features/scheduling/generation/SessionScheduler.ts
✅ Files skipped from review due to trivial changes (3)
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx

📝 Walkthrough

Walkthrough

Implements generateDaysOffSchedule with counselor role partitioning, bunk grouping, and week-based day assignment. Migrates Firestore date fields in freeplays and nightSchedules from raw strings to moment(...).startOf('day') objects. Updates NightScheduleTable and generateFreeplaySchedule to consume Moment-typed dates. Adds role-based navbar link filtering. Deletes emulator test data files and sets storage rules to deny all access.

Changes

Days-Off Scheduling & Moment Type Migration

Layer / File(s) Summary
Firestore date conversion to Moment
src/data/firestore/freeplays.ts, src/data/firestore/nightSchedules.ts, src/features/scheduling/generation/generateFreeplaySchedule.ts
fromFirestore in both Firestore modules now converts the document id to moment(...).startOf('day') instead of returning the raw string. GenerateFreeplayScheduleRequest.date is updated from string to Moment.
generateDaysOffSchedule new module
src/features/scheduling/generation/generateDaysOffSchedule.ts
New module partitions counselors by STAFF/ADMIN role, groups staff by bunk, groups days off by week number with boundary trimming, shuffles per-week assignment order, and fills daysOffByCounselorId via rotating index. Returns a DaysOffSchedule.
NightScheduleTable Moment adaptation
src/components/NightScheduleTable.tsx
Imports Moment type, changes NightScheduleTableRow.date from string to Moment, and formats the date via .format("YYYY-MM-DD") before computing the DAY column number.

Navbar RBAC & Minor Cleanup

Layer / File(s) Summary
Navbar role-based filtering and label update
src/components/Navbar.tsx
Extracts role from auth.role, filters navbarLinks to entries whose roles include the user's current role, updates the container background CSS class, and replaces the span label with a Mantine Text component.
LoginPage and accountManagement cosmetic cleanup
src/app/LoginPage.tsx, functions/src/features/accountManagement.ts
Removes unused default React import from LoginPage; inserts a blank line in checkAllowlist; both are non-functional changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Hack4Impact-UMD/camp-starfish#254: Introduces the DaysOffSchedule type, Firestore collection helpers, useDaysOffSchedule hook, and NightScheduleTable wiring that this PR's generateDaysOffSchedule and Moment migration build directly on top of.

Suggested labels

feature

Suggested reviewers

  • nkanchinadam

Poem

🐇 Hoppity-hop through the schedule we go,
Moments replace strings — no more raw date woe!
Bunks get their nights off, counselors their days,
Role-filtered nav links now light up the ways.
The rules say "if false," the old data's long gone —
A cleaner codebase to keep hopping on! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Feature/session wide algorithm' is vague and generic, using non-descriptive terms that don't clearly convey what the actual changeset accomplishes. Consider a more specific title like 'Implement scheduling algorithm for days off and night shifts' or 'Add session-wide employee scheduling logic' to better describe the main changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/session-wide-algorithm

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0a9704 and 974f949.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • src/features/sessionWideAlgorithm.ts (1 hunks)
  • src/types/sessionTypes.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/sessionWideAlgorithm.ts (1)
src/types/sessionTypes.ts (2)
  • Session (4-15)
  • StaffSessionAttendee (39-45)

Comment thread src/features/sessionWideAlgorithm.ts Outdated
Comment thread src/features/sessionWideAlgorithm.ts Outdated
Comment thread src/features/sessionWideAlgorithm.ts Outdated
Comment thread src/features/sessionWideAlgorithm.ts Outdated

@eshavignesh123 eshavignesh123 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi Parth! Could you pull from main when you get a chance? We added a bunch of updates to sessionTypes, so refactoring your code based on that would be super helpful! We also added a new file, SessionScheduler.ts, to keep all our session-wide algorithms, so could you move your functions there as well? Thanks!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/features/scheduling/SessionScheduler.ts (1)

29-30: Use a named constant for milliseconds per day.

The magic number 86400000 (milliseconds in a day) reduces readability.

Apply this diff:

+    const MS_PER_DAY = 86400000;
     const numDays =
-      Math.floor((endDate.getTime() - startDate.getTime()) / 86400000) + 1;
+      Math.floor((endDate.getTime() - startDate.getTime()) / MS_PER_DAY) + 1;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 974f949 and da2baeb.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • src/features/scheduling/SessionScheduler.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/scheduling/SessionScheduler.ts (1)
src/types/sessionTypes.ts (3)
  • SessionID (11-11)
  • StaffAttendeeID (35-35)
  • NightShiftID (49-49)
🔇 Additional comments (2)
src/features/scheduling/SessionScheduler.ts (2)

70-76: Boundary condition: date comparison at half-point may be ambiguous.

Lines 71 and 75 use <= and > to split the schedule at the half-point. If halfPointDate exactly matches a day off, it's counted in the first half. Verify this is the intended behavior.


136-145: Major: Program counselor consecutive days off eligibility logic is unclear and requires clarification.

The logic at lines 137-145 checks whether a program counselor has any two consecutive days off anywhere during the session. However, the intent is ambiguous:

  • Currently, the code creates one shift assignment per bunk for the entire session (not per night), making the consecutive days off check questionable in context.
  • The logic returns eligible = false if the employee has ANY consecutive days off during the session, but it's unclear why consecutive days off (versus any days off) affects session-wide night shift eligibility.
  • The boundary checks (prev <= endDate) are incomplete—they don't verify the dates fall within the session's startDate to endDate range.

Given the architectural issue mentioned in your review (single-shift-per-bunk for entire session), this eligibility logic needs clarification alongside the overall night shift structure. Consider:

  1. Should night shifts be assigned per-night rather than per-session?
  2. If per-night, should eligibility check whether the counselor has a day off immediately before or after that specific night?
  3. If per-session, what is the business rule for consecutive days off affecting overall eligibility?

Comment thread src/features/scheduling/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/SessionScheduler.ts Outdated
Comment on lines +66 to +83
const firstHalf = dayIndex <= Math.floor(numDays / 2);
const halfPointDate = new Date(startDate);
halfPointDate.setDate(startDate.getDate() + Math.floor(numDays / 2));

const hasDayOffInFirstHalf = randomEmployee.daysOff.some(
(d) => new Date(d).getTime() <= halfPointDate.getTime()
);

const hasDayOffInSecondHalf = randomEmployee.daysOff.some(
(d) => new Date(d).getTime() > halfPointDate.getTime()
);

if (
(firstHalf && hasDayOffInFirstHalf) ||
(!firstHalf && hasDayOffInSecondHalf)
) {
continue;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Half-schedule logic may not guarantee one day off per half.

The current logic prevents assigning two days off in the same half but doesn't ensure both halves receive a day off. An employee could get both days off in one half if they're selected twice before the half switches, or end up with only one day off total.

Consider revising the algorithm to:

  1. First assign one day off in the first half to each employee, then
  2. Assign the second day off in the second half to each employee.

This ensures the constraint is met deterministically rather than relying on random chance.

🤖 Prompt for AI Agents
In src/features/scheduling/SessionScheduler.ts around lines 66–83 the current
check only blocks assigning a second day-off in the same half but doesn’t
guarantee each employee gets exactly one day-off in each half; change the
algorithm to a deterministic two-phase assignment: first iterate employees and
assign one day-off inside the first half (pick a random available date within
first half that doesn’t conflict with existing constraints), mark it, then
iterate again and assign the second day-off inside the second half (pick a
random available date within second half); if no valid date exists in the target
half, implement a clear fallback (e.g., try nearest valid date in that half or
log/fail the employee assignment) to preserve constraints and avoid leaving
employees with zero or two days in the same half.

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/SessionScheduler.ts Outdated
…es, and fixed bugs in the assign nights off function such as not assigning 4 employees per bunk a night off

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (6)
src/features/scheduling/SessionScheduler.ts (6)

63-65: Random selection bug has been fixed.

The previous critical issue where the code randomly selected from the full employees array instead of employeeChoices has been corrected. The code now properly builds an array from the eligible employee set and selects randomly from it.


144-145: Typo has been corrected.

The previous typo "progrma" has been fixed to programCounselor.


159-159: Typos have been corrected.

The previous typos "counsoler" and "choosen" have been fixed to "counselor" and "chosen".


74-91: Half-schedule logic still doesn't guarantee one day off per half.

The algorithm prevents assigning two days off in the same half but doesn't ensure each employee receives exactly one day off in each half. An employee could end up with both days in one half (if selected before reaching that half's limit) or only one day total.

Consider a deterministic two-phase approach:

  1. First pass: Assign one day off in the first half to each employee
  2. Second pass: Assign one day off in the second half to each employee

This ensures the constraint is met reliably rather than depending on random selection order.


94-94: Input mutation creates side effects.

The method directly mutates the employees parameter by pushing to randomEmployee.daysOff. This creates side effects that may surprise callers and complicates testing.

Consider either:

  1. Clearly documenting this mutation behavior in a comment above the method, or
  2. Returning a map of employee IDs to assigned days off and letting the caller apply updates

111-168: Critical: Night shift assignment is still incomplete.

The method creates only one NightShiftID object per bunk for the entire session (lines 128-135) rather than creating shifts for each night. For a multi-day session, this leaves all nights except one without coverage.

Expected behavior:

  1. Loop through each night of the session (use a date iterator from startDate to endDate)
  2. For each night, assign eligible counselors per bunk
  3. Rotate counselors across nights to distribute the workload
  4. Check day-off eligibility for the specific night being assigned

Current implementation would require substantial refactoring to assign shifts per night rather than per session.

🧹 Nitpick comments (3)
src/features/scheduling/SessionScheduler.ts (3)

3-8: Consider using Fisher-Yates for better performance.

The current shuffle works correctly but has O(n log n) complexity due to sorting. For better performance with large employee lists, consider an in-place Fisher-Yates shuffle:

 function shuffleArray<T>(arr: T[]): T[] {
-  return arr
-    .map(value => ({ value, sort: Math.random() }))
-    .sort((a, b) => a.sort - b.sort)
-    .map(({ value }) => value);
+  const shuffled = [...arr];
+  for (let i = shuffled.length - 1; i > 0; i--) {
+    const j = Math.floor(Math.random() * (i + 1));
+    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
+  }
+  return shuffled;
 }

146-154: Clarify or simplify the date boundary checks in eligibility logic.

The eligibility check verifies that a program counselor doesn't have adjacent days off, but the prev <= endDate and next <= endDate conditions (lines 152-153) appear redundant. If employee.daysOff only contains dates within the session range, checking whether computed adjacent dates fall within endDate shouldn't be necessary for correctness.

Consider simplifying to:

         const eligible = !employee.daysOff.some((day) => {
           const dayDate = new Date(day);
           const prev = new Date(dayDate);
           prev.setDate(prev.getDate() - 1);
           const next = new Date(dayDate);
           next.setDate(next.getDate() + 1);
-          return prev <= endDate && employee.daysOff.includes(toISODate(prev)) ||
-            next <= endDate && employee.daysOff.includes(toISODate(next));
+          return employee.daysOff.includes(toISODate(prev)) ||
+            employee.daysOff.includes(toISODate(next));
         });

If the boundary check serves a specific purpose, please add a comment explaining why.


120-120: Consider hoisting toISODate helper to reduce duplication.

The toISODate helper is defined inside assignNightShifts, but assignDaysOff (line 42) uses inline toISOString().split("T")[0] for the same purpose. Hoisting this helper to the module level would improve consistency and reduce duplication.

+function toISODate(date: Date): string {
+  return date.toISOString().split("T")[0];
+}
+
 export class SessionScheduler {

Then update line 42 in assignDaysOff:

-      const dateStr = currentDate.toISOString().split("T")[0];
+      const dateStr = toISODate(currentDate);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da2baeb and fa4ff29.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/features/scheduling/FreeplayScheduler.ts (1 hunks)
  • src/features/scheduling/SessionScheduler.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/scheduling/SessionScheduler.ts (1)
src/types/sessionTypes.ts (3)
  • SessionID (11-11)
  • StaffAttendeeID (35-35)
  • NightShiftID (49-49)
🔇 Additional comments (2)
src/features/scheduling/FreeplayScheduler.ts (1)

26-27: LGTM!

The lint directive appropriately suppresses warnings for the unused parameter in this stub method. The explanatory comment provides helpful context.

package.json (1)

25-25: Verify or remove unused sharp dependency
No imports or invocations of sharp were found in the codebase; remove it from package.json if it isn’t actually used.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/types/sessionTypes.ts (1)

62-62: LGTM! Consider adding a JSDoc comment for clarity.

The addition of the hasDaysOff boolean field to CommonSection is well-typed and appropriately named. This flag appears to control whether the scheduling algorithm should assign days off during this section.

Consider adding a brief JSDoc comment to clarify when this flag should be set:

+  /**
+   * Indicates whether staff/admin should have days off assigned during this section.
+   */
   hasDaysOff: boolean;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa4ff29 and 573adef.

📒 Files selected for processing (1)
  • src/types/sessionTypes.ts (1 hunks)

@nkanchinadam nkanchinadam left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall, a good structure of the functions and got overall logic down. Main things to change are:

  • Use moment library instead of Date objects
  • Don't make assumptions about the session length when assigning Days Off
  • Make sure to assign all Staff & Admins
  • Use helper functions to abstract out the logic & make it more readable


const employeeChoices = new Set(employees);

const startDate = new Date(session.startDate);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

instead of using the built-in JS Date class, which is annoying & difficult to work with, import the moment library and do all datetime calculations with that

const currentDate = new Date(startDate);

for (let dayIndex = 1; dayIndex <= numDays; dayIndex++) {
const dateStr = currentDate.toISOString().split("T")[0];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

you could probably extract this logic into a helper function to make it more readable

const dateStr = currentDate.toISOString().split("T")[0];

// Skip restricted days (first, 13th, and 14th)
if (dayIndex === 1 || dayIndex === 13 || dayIndex === 14) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't hardcode the days that shouldn't have anyone with a Day Off since they could change if Camp Starfish changes the length of the session they do, which they do throughout the year with shorter sessions as well as experimenting with different sessinon lengths. I realize that there's no real way to tell if a day should have anyone scheduled for a Day Off on it, so I just pushed a hasDaysOff field to the Section type in sessionTypes.ts.

}

// Move to next day
currentDate.setDate(currentDate.getDate() + 1);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since you're doing a for loop, you can just calculate the current date from the index of the loop instead of keeping track of it separately

if (randomEmployee.daysOff.includes(dateStr)) continue;

// Checks if employee has a day off in the first half of schedule
const firstHalf = dayIndex <= Math.floor(numDays / 2);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similar to earlier comment about not hardcoding sessions, the only rule about Days Off is that each staff & admin legally has to have 1 Day Off every 7 days of camp, so divide up the timeframe into weeks & round down for partial weeks and then assign Days Off for each week. It would probably also be helpful to create a helper function that handles a single week to simplify the logic.


assignDaysOff(): SessionScheduler { return this; }
assignDaysOff(session: SessionID, employees: StaffAttendeeID[]): SessionScheduler {
const MAX_STAFF_OFF_PER_DAY = 2;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Unsure where the number 2 came from, but every staff & admin member needs to have a Day Off every week, so you can calculate the number off each day by doing (numStaff + numAdmin) / numDays


// Keep track of attempts to avoid infinite loops
let attempts = 0;
const maxAttempts = numEmployees * 2;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't really get how assigning the staff & admin could fail, so modify the logic to ensure that everyone gets assigned since we don't the user to try generating a schedule only to encounter failures randomly

) {
attempts++;

const choices = Array.from(employeeChoices);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

When choosing employees to assign, assign Program Counselors first and then everyone else since Program Counselors can't have a Day Off on a day where they're supposed to lead an activity. Try to assign them to Jamboree days since Program Counselor duties only apply to Bundles.

Additionally, try to ensure that of the people who have a Day Off on a given day, they're all from different bunks, so no bunk has too few counselors for the night.

const shift: NightShiftID = {
id: `night-${bunkNumber}-${session.id}`,
sessionId: session.id,
[bunkNumber]: {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

NightShiftID is a type intended for 1 night of and would contain the info for each bunk that night. [bunkId: number]: ... means that the type is a map where you can have multiple keys (the bunk numbers), so only create 1 of these objects per night and store the data in that single object.


for (const employee of selected) {
// employee is a program counselor, check if they have day off before or after
if (employee.programCounselor) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This condition doesn't only apply to Program Counselors, it applies to all staff. The only thing related to Program Counselors in these functions is assigning their Days Off to be during Jamborees.

…r being assigned off on jamboree days, assigning more evenly throughout bunks, and assigning a night shift object per night rather than per bunk

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 573adef and 8862067.

📒 Files selected for processing (1)
  • src/features/scheduling/SessionScheduler.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/scheduling/SessionScheduler.ts (1)
src/types/sessionTypes.ts (5)
  • SectionID (55-55)
  • StaffAttendeeID (35-35)
  • AdminAttendeeID (41-41)
  • SessionID (11-11)
  • NightShiftID (49-49)

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
@nkanchinadam nkanchinadam force-pushed the main branch 2 times, most recently from a884ab9 to 974f469 Compare December 2, 2025 05:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/features/scheduling/generation/SessionScheduler.ts`:
- Around line 55-69: In isJamboreeDay (private method in SessionScheduler)
remove the unused local variable dateStr that is declared as const dateStr =
this.toISODate(date); so that the function no longer defines an unused variable
and the linter error is resolved; simply delete that line and ensure the rest of
isJamboreeDay (including references to date, section.startDate, section.endDate
and section.type) remains unchanged.
- Around line 1-3: The import list in SessionScheduler.ts includes an unused
type NightShift which causes an ESLint unused import error; remove NightShift
from the import statement that currently reads "import { StaffAttendeeID,
AdminAttendeeID, NightShiftID, SessionID, SectionID, NightShift } from
"@/types/sessionTypes"; so update that import to exclude NightShift (leaving
StaffAttendeeID, AdminAttendeeID, NightShiftID, SessionID, SectionID) and run
lint/TS build to confirm there are no remaining references to the NightShift
symbol.
♻️ Duplicate comments (2)
src/features/scheduling/generation/SessionScheduler.ts (2)

30-38: Include the session end date in getDateRange.

The loop currently excludes endDate, which drops the final day (and yields an empty range for single-day sessions). Also flips let to const to satisfy lint.

✅ Proposed fix
-    let fromDate = startDate
-    let toDate = endDate
-    let diff = toDate.diff(fromDate, "day")
-    let range = []
-    for (let i = 0; i < diff; i++) {
+    const fromDate = startDate
+    const toDate = endDate
+    const diff = toDate.diff(fromDate, "day")
+    const range = []
+    for (let i = 0; i <= diff; i++) {
       range.push(moment(startDate).add(i, "day"))
     }

204-227: Reset the day-off pool per week (not per session).

employeesNeedingDayOff and MAX_STAFF_OFF_PER_DAY are global for the whole session, so multi‑week sessions give each person only one day off total. The week windows also overlap because currDate.add(6, "day") advances only 6 days. Recompute the pool and cap per week and advance by 7 days.

✅ Proposed fix
-    const NUM_WEEKS = Math.ceil(end.diff(start, "week", true));
-    const NUM_DAYS = (end.diff(start, "day")) + 1
-    const MAX_STAFF_OFF_PER_DAY = Math.ceil(employees.length / NUM_DAYS);
-    const employeesNeedingDayOff = new Set(employees);
-
-    let currDate = start;
     // Need a future implementation for this date range to only include dates that allow for a day off.
     const sessionDateRange: Set<Moment> = new Set(this.getDateRange(start, end))
-
-    for (let i = 0; i < NUM_WEEKS; i++) {
-      if (currDate.clone().add(1, "week").isBefore(end)) {
-        this.assignDaysOffForWeek(currDate, currDate.clone().add(6, "day"), sessionDateRange, employees, employeesNeedingDayOff, MAX_STAFF_OFF_PER_DAY)
-        currDate.add(6, "day")
-      }
-      else {
-        this.assignDaysOffForWeek(currDate, end, sessionDateRange, employees, employeesNeedingDayOff, MAX_STAFF_OFF_PER_DAY)
-        currDate = end
-      }
-
-    }
+    let weekStart = start.clone()
+    while (weekStart.isSameOrBefore(end)) {
+      const weekEnd = moment.min(weekStart.clone().add(6, "day"), end)
+      const daysInWeek = weekEnd.diff(weekStart, "day") + 1
+      const maxStaffOffPerDay = Math.ceil(employees.length / daysInWeek)
+      const employeesNeedingDayOff = new Set(employees)
+
+      this.assignDaysOffForWeek(
+        weekStart,
+        weekEnd,
+        sessionDateRange,
+        employees,
+        employeesNeedingDayOff,
+        maxStaffOffPerDay
+      )
+      weekStart.add(7, "day")
+    }

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Fix all issues with AI agents
In `@src/app/LoginPage.tsx`:
- Around line 37-45: The catch in generateTestData incorrectly sets a sign-in
message; change it to handle errors from generateSession by catching the error
(catch (err)) and calling setError with a message like "An error occurred while
generating test data. Please try again." and optionally log the actual error via
console.error(err) to aid debugging; update references in generateTestData and
ensure setError usage is consistent.
- Around line 81-88: Remove or hide the debug "Generate Test" button from the
production LoginPage: locate the button using the generateTestData function and
MicrosoftIcon in LoginPage.tsx and either delete it or wrap its JSX in a
condition that only renders in development (e.g., check process.env.NODE_ENV ===
'development'); if you keep it for dev use, replace the MicrosoftIcon with a
neutral dev icon and modify generateTestData to provide user-visible feedback
(toast or inline message) instead of only console.log, and ensure this
functionality is moved to an admin/dev-only route if it needs to exist
long-term.

In `@src/features/scheduling/generation/SessionScheduler.ts`:
- Line 125: The variable remainingWF in SessionScheduler.ts (declared as const
remainingWF = shuffledWF.filter(e => !selectedWFWindow1.includes(e) &&
!selectedWFWindow2.includes(e));) is unused; remove this declaration to fix the
pipeline by deleting the remainingWF assignment (or if its intent was to be used
later, instead integrate it where needed—e.g., replace any placeholder logic
that should reference remainingWF with this filtered array). Ensure references
to shuffledWF, selectedWFWindow1 and selectedWFWindow2 remain unchanged.
- Around line 114-116: The local variable otherEmployees created by
employees.filter(...) in SessionScheduler (the expression "const otherEmployees
= employees.filter(e => !('programCounselor' in e && e.programCounselor))") is
unused; remove that declaration or rename it to _otherEmployees if you intend to
keep it for future use to silence the linter/pipeline. Edit the
SessionScheduler.ts occurrence to either delete the const otherEmployees = ...
line or change its name to _otherEmployees so the variable is no longer flagged
as unused.
- Around line 138-146: The loop mutates the shared maxStaffOffPerDay causing it
to stay Infinity for subsequent employees; inside the window-1 and window-2
loops in SessionScheduler.ts, compute a per-employee local limit (e.g., let
perEmployeeMax = (dates.length === 1) ? Infinity : maxStaffOffPerDay) and pass
that perEmployeeMax into assignOneDayOff instead of mutating the outer
maxStaffOffPerDay; ensure you do the same pattern in the window2 loop so the
global cap isn't permanently changed.
- Around line 1-7: Remove the erroneous/unused imports in SessionScheduler.ts:
delete the faulty imports of da (from "@faker-js/faker/."), w (from
"@faker-js/faker/dist/airline-CLphikKp"), em (from "@mantine/core") and max
(from "moment"), and also remove the unused type NightShift from the import list
(keeping only used symbols like StaffAttendeeID, AdminAttendeeID, NightShiftID,
SessionID, SectionID, Moment, and moment); ensure no references to the removed
symbols remain elsewhere in SessionScheduler.ts and run the type-check/lint to
confirm pipeline errors are resolved.

In `@src/features/scheduling/test/generateEmulatorData.tsx`:
- Around line 495-513: The function parameter blockID is unused; either remove
it from the signature or rename it to _blockID to silence the unused-parameter
error — update generateBunkJamboActivities accordingly and apply the same change
to generateNonBunkJamboActivities so their signatures remain consistent with
callers/types.
- Around line 1-6: The import statement in generateEmulatorData.tsx includes
unused symbols causing pipeline failures; remove Freeplay and
SchedulingSectionID from the named import list (the import that currently lists
CamperAttendeeID, StaffAttendeeID, AdminAttendeeID, AgeGroup, SectionSchedule,
BundleActivityWithAssignments, SectionPreferences, BunkID,
BunkJamboreeActivityWithAssignments, NonBunkJamboreeActivityWithAssignments,
Freeplay, PostID, SectionID, SessionID, NightShiftID, ProgramAreaID,
SchedulingSectionID, FreeplayID) so only used types remain imported.
- Line 739: The local variable campers assigned from
generateCampers(TOTAL_CAMPERS, TOTAL_BUNKS) is unused; either remove the
declaration or rename it to _campers (prefix underscore) to silence the
unused-variable warning, or if generateCampers is being removed altogether,
delete this line; update the area around the generateCampers call in
generateEmulatorData.tsx so no unused symbol remains.
- Around line 349-352: The code sets schedule.alternatePeriodsOff["RH"] twice in
generateEmulatorData (variable schedule of type SectionSchedule<'BUNK-JAMBO'>);
remove the duplicate assignment so alternatePeriodsOff["RH"] is only initialized
once (leave a single schedule.alternatePeriodsOff["RH"] = [] and delete the
redundant repeated line).
- Around line 130-192: The function generateNonoLists is defined but never used,
causing linting and pipeline issues. To fix this, either remove the
generateNonoLists function if it is not needed, or export it to make it
available externally, or prefix its name with an underscore (e.g.,
_generateNonoLists) if you intend to keep it for future use. Apply the same fix
to other unused functions in the file such as generateYesyesLists and
generateBunks.
🧹 Nitpick comments (3)
src/features/scheduling/test/generateEmulatorData.tsx (2)

608-731: Remove large blocks of commented-out code.

Over 120 lines of commented-out code should be removed. Version control preserves history if these implementations are needed later. Keeping them makes the file harder to maintain and navigate.

If these functions are planned for near-term use, consider keeping them but marking with // TODO: comments explaining the plan, or moving to a separate file.


1-12: Consider renaming file from .tsx to .ts.

This file contains no JSX/React components - it's pure TypeScript logic. Using .tsx extension is misleading and may cause unnecessary JSX parsing overhead.

src/features/scheduling/generation/SessionScheduler.ts (1)

186-186: Use const with clone pattern for clarity.

ESLint flags this because currDate is never reassigned. While moment.add() mutates in place (so let technically works), using const with explicit reassignment is clearer:

Proposed fix
-    let currDate = startDate;
+    let currDate = startDate.clone();

     // Create a night bunk object for each night
     while (currDate.isSameOrBefore(endDate)) {
       // ... shift logic ...
       this.nightShifts.push(shift);
-      currDate.add(1, "day");
+      currDate = currDate.clone().add(1, "day");
     }

Or simply suppress the lint warning with a comment if mutation is intentional.

Comment thread src/app/LoginPage.tsx Outdated
Comment thread src/app/LoginPage.tsx Outdated
Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/test/generateEmulatorData.tsx Outdated
Comment thread src/features/scheduling/test/generateEmulatorData.tsx Outdated
Comment thread src/features/scheduling/test/generateEmulatorData.tsx Outdated
Comment thread src/features/scheduling/test/generateEmulatorData.tsx Outdated
Comment thread src/features/scheduling/test/generateEmulatorData.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/features/scheduling/generation/SessionScheduler.ts`:
- Around line 73-81: The current logic in SessionScheduler.ts skips bunk checks
when maxStaffOffPerDay === Infinity, which can let multiple employees from the
same bunk take the same day off; change the condition around the bunk check so
the bunkConflict check (using 'bunk' in employee, allEmployees, employee.bunk,
and employee.daysOff.includes(date)) always runs regardless of
maxStaffOffPerDay, and if a bunkConflict is detected either skip assigning that
day-off or implement a fallback assignment path that searches for an alternative
employee/date rather than bypassing the constraint entirely; ensure the code in
the loop that currently contains "if ('bunk' in employee && maxStaffOffPerDay
!== Infinity) { ... }" is refactored to always evaluate bunk constraints and
handle failures gracefully.
- Line 187: The variable currDate in SessionScheduler.ts is never reassigned so
change its declaration from let to const to satisfy the prefer-const rule; keep
using currDate with moment.add() (which mutates the moment instance) so no other
code changes are needed—update the declaration where currDate is defined (near
startDate usage) to const currDate.
♻️ Duplicate comments (2)
src/features/scheduling/generation/SessionScheduler.ts (2)

137-140: Use a local variable instead of mutating maxStaffOffPerDay.

While the recalculation at line 131 resets the value each iteration, the mutation pattern is still error-prone. Using a local variable as suggested in a previous review would be cleaner.

Proposed fix
       for (const employee of employees) {
-        maxStaffOffPerDay = Math.ceil(employees.length / window1.length);
         const dates =
           'programCounselor' in employee && jamboreeWindow1.has(employee)
             ? window1.filter(d => this.isJamboreeISO(d, this.sections))
             : window1;

-        if (dates.length === 1){
-          // set maxStaffOffPerDay to Infinity
-          maxStaffOffPerDay = Infinity;
-        };
+        const effectiveMax = dates.length === 1
+          ? Infinity
+          : Math.ceil(employees.length / window1.length);

-        if (!this.assignOneDayOff(employee, dates, dayCounts, employees, maxStaffOffPerDay)) {
+        if (!this.assignOneDayOff(employee, dates, dayCounts, employees, effectiveMax)) {
           console.warn(`Failed to assign window-1 day off for ${employee.id}`);
         }
       }

Apply the same pattern to the window2 loop (lines 148-164).


1-7: Remove unused and erroneous imports to fix pipeline failures.

The pipeline is still failing due to unused imports: NightShift, da, w, em, and max. These appear to be accidental auto-imports and must be removed.

Proposed fix
-import { StaffAttendeeID, AdminAttendeeID, NightShiftID, SessionID, SectionID, NightShift } from "@/types/sessionTypes";
-import { da } from "@faker-js/faker/.";
-import { w } from "@faker-js/faker/dist/airline-CLphikKp";
-import { em } from "@mantine/core";
-import { max } from "moment";
-import { Moment } from "moment";
-import moment from "moment";
+import { StaffAttendeeID, AdminAttendeeID, NightShiftID, SessionID, SectionID } from "@/types/sessionTypes";
+import moment, { Moment } from "moment";
🧹 Nitpick comments (3)
src/features/scheduling/generation/SessionScheduler.ts (3)

100-102: Hardcoded scheduling windows reduce flexibility.

The windows are hardcoded to days 2-6 and 7-12 relative to session start, with a comment noting this is temporary. Consider deriving these windows dynamically from the session's actual duration to handle sessions of varying lengths.


203-207: Extract magic number for night shift staff count.

The value 4 for the number of employees selected per bunk per night is unexplained. Consider extracting this as a named constant for clarity and easier configuration.

Proposed fix
+const NIGHT_SHIFT_STAFF_PER_BUNK = 4;
+
 export class SessionScheduler {
   // ... existing code ...

         const shuffled = this.shuffleArray(employeesInBunk);
-        const selected = shuffled.slice(0, 4);
+        const selected = shuffled.slice(0, NIGHT_SHIFT_STAFF_PER_BUNK);

96-171: Note: Method mutates employee objects directly.

assignDaysOff modifies employee.daysOff arrays in place rather than returning new data. This is a side-effect pattern that callers should be aware of. Consider documenting this behavior or returning a map of assignments for a more functional approach.

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated
Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/scheduling/generation/SessionScheduler.ts`:
- Around line 200-227: The on‑duty split logic under‑allocates because it uses
"length + 1 < PER_SPLIT" and `selected` is never reassigned; change `selected`
to a const array and fix the condition to compare the current count directly
(e.g., use "shift[bunkNumber].counselorsOnDuty.length < PER_SPLIT") or
explicitly enforce a cap (introduce a MAX_ON_DUTY constant if the intent is to
"pick 4 employees") before pushing into shift[bunkNumber].counselorsOnDuty;
ensure fallback pushes go to shift[bunkNumber].nightBunkDuty, and keep all other
checks (daysOff via this.toISO(currDate), prevDate, nextDate) the same while
referencing employeesInBunk, PER_SPLIT, selected, and the shift[...] arrays to
locate the change.
♻️ Duplicate comments (7)
src/features/scheduling/generation/SessionScheduler.ts (2)

1-1: Remove unused NightShift import to unblock lint.

NightShift isn’t referenced in this file and fails the lint/build pipeline.

🧹 Proposed fix
-import { StaffAttendeeID, AdminAttendeeID, NightShiftID, SessionID, SectionID, NightShift } from "@/types/sessionTypes";
+import { StaffAttendeeID, AdminAttendeeID, NightShiftID, SessionID, SectionID } from "@/types/sessionTypes";

68-77: Always enforce bunk conflicts, even when caps are lifted.

When maxStaffOffPerDay is Infinity, the bunk constraint is skipped, allowing same‑bunk counselors to take the same day off.

🔒 Proposed fix
-      if ('bunk' in employee && maxStaffOffPerDay !== Infinity) {
+      if ('bunk' in employee) {
         const bunkConflict = allEmployees.some(e =>
           'bunk' in e &&
           e.bunk === employee.bunk &&
           e.daysOff.includes(date)
         );

         if (bunkConflict) continue;
       }
src/features/scheduling/test/generateEmulatorData.tsx (5)

1-6: Remove unused Freeplay and SchedulingSectionID imports.

Both are unused and currently fail lint.

🧹 Proposed fix
-import { CamperAttendeeID, StaffAttendeeID, AdminAttendeeID, AgeGroup, SectionSchedule, BundleActivityWithAssignments, 
- SectionPreferences, BunkID, BunkJamboreeActivityWithAssignments,NonBunkJamboreeActivityWithAssignments, Freeplay, 
-  PostID, SectionID, SessionID, NightShiftID, 
-  ProgramAreaID,
-  SchedulingSectionID,
-  FreeplayID} from "@/types/sessionTypes";
+import { CamperAttendeeID, StaffAttendeeID, AdminAttendeeID, AgeGroup, SectionSchedule, BundleActivityWithAssignments, 
+  SectionPreferences, BunkID, BunkJamboreeActivityWithAssignments, NonBunkJamboreeActivityWithAssignments,
+  PostID, SectionID, SessionID, NightShiftID,
+  ProgramAreaID,
+  FreeplayID } from "@/types/sessionTypes";

130-261: Unused list/bunk helpers trip lint.

generateNonoLists, generateYesyesLists, and generateBunks are never called (only referenced in commented code). Remove, export, or prefix with _ to satisfy lint.


317-593: Unused schedule helpers + duplicate alternatePeriodsOff init.

generateBundleBlockSchedule, generateBunkJamboBlockSchedule, generateNonBunkJamboBlockSchedule, generateFreeplayBlockSchedule, generateBlockIDs, generatePosts, and generatePrefs are unused and fail lint. Also, schedule.alternatePeriodsOff["RH"] is set twice in generateBunkJamboBlockSchedule.

🧹 Proposed fix (duplicate init)
-  schedule.alternatePeriodsOff["RH"] = []
-
-  schedule.alternatePeriodsOff["RH"] = []
+  schedule.alternatePeriodsOff["RH"] = []

483-521: Silence unused blockID parameters.

blockID isn’t used in either jamboree activity generator and fails lint.

🧹 Proposed fix
-function generateBunkJamboActivities(totalActivities: number, blockID: string): BunkJamboreeActivityWithAssignments[] {
+function generateBunkJamboActivities(totalActivities: number, _blockID: string): BunkJamboreeActivityWithAssignments[] {
@@
-function generateNonBunkJamboActivities(totalActivities: number, blockID: string): NonBunkJamboreeActivityWithAssignments[] {
+function generateNonBunkJamboActivities(totalActivities: number, _blockID: string): NonBunkJamboreeActivityWithAssignments[] {

727-729: Remove unused campers variable in generateSession.

campers is unused and fails lint.

🧹 Proposed fix
-  const campers: CamperAttendeeID[] = generateCampers(TOTAL_CAMPERS, TOTAL_BUNKS);

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/scheduling/generation/SessionScheduler.ts`:
- Around line 95-159: The fixed windows (window1/window2 created via
getDateStringsInRange) can extend past the session end causing out‑of‑range
dates and window2.length === 0 which leads to division by zero and Infinity for
maxStaffOffPerDay; clamp each window to the session end (e.g., compute end-bound
when calling getDateStringsInRange or trim the returned arrays against the
session end/last valid date) and skip a pass when a window is empty (if
window1.length===0 or window2.length===0, do not run the corresponding
for-loop), and also guard before computing maxStaffOffPerDay to avoid dividing
by zero (only compute Math.ceil(employees.length / window.length) when
window.length>0); apply the same guards to the jamboree filtering that uses
isJamboreeISO and to calls to assignOneDayOff so you never pass empty date
arrays.
♻️ Duplicate comments (2)
src/features/scheduling/generation/SessionScheduler.ts (2)

62-76: Always enforce the bunk constraint—even when using an Infinity cap.

Right now the bunk check is skipped when maxStaffOffPerDay === Infinity, which can schedule multiple counselors from the same bunk off on the same day and break coverage. This is the same risk previously flagged and still present.

✅ Proposed fix
-      if ('bunk' in employee && maxStaffOffPerDay !== Infinity) {
+      if ('bunk' in employee) {
         const bunkConflict = allEmployees.some(e =>
           'bunk' in e &&
           e.bunk === employee.bunk &&
           e.daysOff.includes(date)
         );

         if (bunkConflict) continue;
       }

201-224: Fix on‑duty split off‑by‑one.

length + 1 < PER_SPLIT under‑allocates on‑duty staff. For example, when PER_SPLIT is 1, no one can ever be placed on duty. This was previously flagged and is still present.

✅ Proposed fix
-          if (!hasAdjacentDayOff && shift[bunkNumber].counselorsOnDuty.length + 1 < PER_SPLIT ) {
+          if (!hasAdjacentDayOff && shift[bunkNumber].counselorsOnDuty.length < PER_SPLIT) {
             shift[bunkNumber].counselorsOnDuty.push(employee.id);
             selected.push(employee);
           }

Comment thread src/features/scheduling/generation/SessionScheduler.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Navbar.tsx`:
- Around line 68-70: The Link component pointing to "/profile" contains only the
MdAccountCircle icon with no accessible text or label. Add an aria-label
attribute to the Link element to provide a descriptive accessible name for
screen readers, such as "Profile" or "Go to profile", so users with assistive
technologies can understand the link's purpose.
- Around line 57-59: The Text component's className attribute on line 57 uses
the Tailwind class `font-Lato` with an uppercase L, which differs from the
correct lowercase usage `font-lato` elsewhere in the component (line 52). Since
Tailwind class names are case-sensitive, this causes the font style to not be
applied correctly. Change the className from `font-Lato` to `font-lato` in the
Text component to ensure consistency and proper styling.

In `@src/components/NightScheduleTable.tsx`:
- Around line 171-173: The bunks array at line 171-173 is being built using
map() which creates sequential indices (0..n), but the code at lines 207-211
reads this array using actual bunk numbers as indices (e.g.,
row.bunks[bunkNum]). This mismatch causes undefined values when bunk numbers are
not sequential. Instead of using map() to create an array with sequential
indices, restructure the bunks construction to use actual bunk numbers as keys,
so that when accessed at lines 207-211 by bunkNum, the correct staff member is
retrieved for each bunk column.

In `@src/data/firestore/freeplays.ts`:
- Around line 3-8: Update import statements to use the `@/`* alias for all
internal src/ imports to comply with project conventions. In
src/data/firestore/freeplays.ts (lines 3-8), replace all relative imports
starting with ./ (such as ./types/documents, ./types/collections,
./types/queries, and ./firestoreClientOperations) with their `@/data/firestore/`
equivalents (for example, `@/data/firestore/types/documents`). Apply the same
transformation to src/data/firestore/nightSchedules.ts (lines 3-19), converting
all relative imports of types and firestoreClientOperations to use the
`@/data/firestore/` path alias instead.

In `@src/features/scheduling/generation/generateDaysOffSchedule.ts`:
- Line 5: Replace `moment` with `dayjs` across all four affected files to
consolidate on the standard date library and reduce bundle size. In
`src/features/scheduling/generation/generateDaysOffSchedule.ts` (line 5),
replace the `Moment` import with a `Dayjs` import and update the
`daysOffInSession` parameter type in `GenerateDaysOffScheduleRequest` to use
`Dayjs` instead of `Moment`. In `src/data/firestore/freeplays.ts` (line 7),
replace the `Moment` import with `Dayjs` and update the
`moment(snapshot.ref.id).startOf('day')` call to use `dayjs()` instead, also
updating any parameter types that use `Moment` to use `Dayjs`. In
`src/data/firestore/nightSchedules.ts` (line 18), perform the same replacements:
swap the `Moment` import for `Dayjs`, convert
`moment(snapshot.ref.id).startOf('day')` to use `dayjs()`, and update parameter
types from `Moment` to `Dayjs`. In `src/components/NightScheduleTable.tsx` (line
18), replace the `Moment` type import with `Dayjs` and convert any `moment()`
function calls to `dayjs()`.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1bd717be-2745-4774-b15a-a0cbddcf7763

📥 Commits

Reviewing files that changed from the base of the PR and between 1028ff4 and ae15a0a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx
  • src/components/Navbar.tsx
  • src/components/NightScheduleTable.tsx
  • src/data/firestore/freeplays.ts
  • src/data/firestore/nightSchedules.ts
  • src/features/scheduling/generation/SessionScheduler.ts
  • src/features/scheduling/generation/generateDaysOffSchedule.ts
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
💤 Files with no reviewable changes (1)
  • src/features/scheduling/generation/SessionScheduler.ts
✅ Files skipped from review due to trivial changes (3)
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Navbar.tsx`:
- Around line 68-70: The Link component pointing to "/profile" contains only the
MdAccountCircle icon with no accessible text or label. Add an aria-label
attribute to the Link element to provide a descriptive accessible name for
screen readers, such as "Profile" or "Go to profile", so users with assistive
technologies can understand the link's purpose.
- Around line 57-59: The Text component's className attribute on line 57 uses
the Tailwind class `font-Lato` with an uppercase L, which differs from the
correct lowercase usage `font-lato` elsewhere in the component (line 52). Since
Tailwind class names are case-sensitive, this causes the font style to not be
applied correctly. Change the className from `font-Lato` to `font-lato` in the
Text component to ensure consistency and proper styling.

In `@src/components/NightScheduleTable.tsx`:
- Around line 171-173: The bunks array at line 171-173 is being built using
map() which creates sequential indices (0..n), but the code at lines 207-211
reads this array using actual bunk numbers as indices (e.g.,
row.bunks[bunkNum]). This mismatch causes undefined values when bunk numbers are
not sequential. Instead of using map() to create an array with sequential
indices, restructure the bunks construction to use actual bunk numbers as keys,
so that when accessed at lines 207-211 by bunkNum, the correct staff member is
retrieved for each bunk column.

In `@src/data/firestore/freeplays.ts`:
- Around line 3-8: Update import statements to use the `@/`* alias for all
internal src/ imports to comply with project conventions. In
src/data/firestore/freeplays.ts (lines 3-8), replace all relative imports
starting with ./ (such as ./types/documents, ./types/collections,
./types/queries, and ./firestoreClientOperations) with their `@/data/firestore/`
equivalents (for example, `@/data/firestore/types/documents`). Apply the same
transformation to src/data/firestore/nightSchedules.ts (lines 3-19), converting
all relative imports of types and firestoreClientOperations to use the
`@/data/firestore/` path alias instead.

In `@src/features/scheduling/generation/generateDaysOffSchedule.ts`:
- Line 5: Replace `moment` with `dayjs` across all four affected files to
consolidate on the standard date library and reduce bundle size. In
`src/features/scheduling/generation/generateDaysOffSchedule.ts` (line 5),
replace the `Moment` import with a `Dayjs` import and update the
`daysOffInSession` parameter type in `GenerateDaysOffScheduleRequest` to use
`Dayjs` instead of `Moment`. In `src/data/firestore/freeplays.ts` (line 7),
replace the `Moment` import with `Dayjs` and update the
`moment(snapshot.ref.id).startOf('day')` call to use `dayjs()` instead, also
updating any parameter types that use `Moment` to use `Dayjs`. In
`src/data/firestore/nightSchedules.ts` (line 18), perform the same replacements:
swap the `Moment` import for `Dayjs`, convert
`moment(snapshot.ref.id).startOf('day')` to use `dayjs()`, and update parameter
types from `Moment` to `Dayjs`. In `src/components/NightScheduleTable.tsx` (line
18), replace the `Moment` type import with `Dayjs` and convert any `moment()`
function calls to `dayjs()`.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1bd717be-2745-4774-b15a-a0cbddcf7763

📥 Commits

Reviewing files that changed from the base of the PR and between 1028ff4 and ae15a0a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx
  • src/components/Navbar.tsx
  • src/components/NightScheduleTable.tsx
  • src/data/firestore/freeplays.ts
  • src/data/firestore/nightSchedules.ts
  • src/features/scheduling/generation/SessionScheduler.ts
  • src/features/scheduling/generation/generateDaysOffSchedule.ts
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
💤 Files with no reviewable changes (1)
  • src/features/scheduling/generation/SessionScheduler.ts
✅ Files skipped from review due to trivial changes (3)
  • src/features/scheduling/generation/generateFreeplaySchedule.ts
  • functions/src/features/accountManagement.ts
  • src/app/LoginPage.tsx
🛑 Comments failed to post (5)
src/components/Navbar.tsx (2)

57-59: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix Tailwind font class casing for navbar text.

Line 57 uses font-Lato, but elsewhere in this component the class is font-lato (Line 52). Tailwind class names are case-sensitive, so this likely drops the intended font style.

Suggested fix
-                <Text className="cursor-pointer font-Lato font-bold">
+                <Text className="cursor-pointer font-lato font-bold">
                   {item.name}
                 </Text>
📝 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.

                <Text className="cursor-pointer font-lato font-bold">
                  {item.name}
                </Text>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Navbar.tsx` around lines 57 - 59, The Text component's
className attribute on line 57 uses the Tailwind class `font-Lato` with an
uppercase L, which differs from the correct lowercase usage `font-lato`
elsewhere in the component (line 52). Since Tailwind class names are
case-sensitive, this causes the font style to not be applied correctly. Change
the className from `font-Lato` to `font-lato` in the Text component to ensure
consistency and proper styling.

68-70: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add an accessible name to the icon-only profile link.

Line 69 renders only an icon inside the link, so screen readers may announce an unlabeled link.

Suggested fix
-          <Link href="/profile">
+          <Link href="/profile" aria-label="Profile">
             <MdAccountCircle size={50} color="gray" />
           </Link>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Navbar.tsx` around lines 68 - 70, The Link component pointing
to "/profile" contains only the MdAccountCircle icon with no accessible text or
label. Add an aria-label attribute to the Link element to provide a descriptive
accessible name for screen readers, such as "Profile" or "Go to profile", so
users with assistive technologies can understand the link's purpose.
src/components/NightScheduleTable.tsx (1)

171-173: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bunk-to-staff mapping is indexed incorrectly.

At Line 171, bunks is built with map() (array indices 0..n), but at Line 207 it is read by actual bunk numbers (row.bunks[bunkNum]). This misaligns staff with bunk columns and can return undefined for valid bunks.

Suggested fix
-        const row: NightScheduleTableRow = {
+        const row: NightScheduleTableRow = {
           date: nightShift.date,
           position: position,
-          bunks: bunkNums.map((bunkNum) =>
-            getStaffForPosition(nightShift, bunkNum, position),
-          ),
+          bunks: Object.fromEntries(
+            bunkNums.map((bunkNum) => [
+              bunkNum,
+              getStaffForPosition(nightShift, bunkNum, position),
+            ]),
+          ) as Record<number, StaffAttendee[]>,
         };

Also applies to: 207-211

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/NightScheduleTable.tsx` around lines 171 - 173, The bunks
array at line 171-173 is being built using map() which creates sequential
indices (0..n), but the code at lines 207-211 reads this array using actual bunk
numbers as indices (e.g., row.bunks[bunkNum]). This mismatch causes undefined
values when bunk numbers are not sequential. Instead of using map() to create an
array with sequential indices, restructure the bunks construction to use actual
bunk numbers as keys, so that when accessed at lines 207-211 by bunkNum, the
correct staff member is retrieved for each bunk column.
src/data/firestore/freeplays.ts (1)

3-8: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use @/* alias for internal src/ imports in Firestore modules.

Both files use relative imports for modules that live under src/, which breaks the project’s import convention and risks lint/config drift.

  • src/data/firestore/freeplays.ts#L3-L8: convert ./types/* and ./firestoreClientOperations imports to @/data/firestore/....
  • src/data/firestore/nightSchedules.ts#L3-L19: convert ./types/* and ./firestoreClientOperations imports to @/data/firestore/....

As per coding guidelines, "Use the @/* alias for all imports under src/... TypeScript configuration uses the @/* path alias... All imports must use this alias."

📍 Affects 2 files
  • src/data/firestore/freeplays.ts#L3-L8 (this comment)
  • src/data/firestore/nightSchedules.ts#L3-L19
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/data/firestore/freeplays.ts` around lines 3 - 8, Update import statements
to use the `@/`* alias for all internal src/ imports to comply with project
conventions. In src/data/firestore/freeplays.ts (lines 3-8), replace all
relative imports starting with ./ (such as ./types/documents,
./types/collections, ./types/queries, and ./firestoreClientOperations) with
their `@/data/firestore/` equivalents (for example,
`@/data/firestore/types/documents`). Apply the same transformation to
src/data/firestore/nightSchedules.ts (lines 3-19), converting all relative
imports of types and firestoreClientOperations to use the `@/data/firestore/` path
alias instead.

Source: Coding guidelines

src/features/scheduling/generation/generateDaysOffSchedule.ts (1)

5-5: ⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify date-library consistency in src/
rg -n --type=ts --type=tsx 'from ["'\'']moment["'\'']|\\bmoment\\(' src
rg -n --type=ts --type=tsx 'from ["'\'']dayjs["'\'']|\\bdayjs\\(' src

Repository: Hack4Impact-UMD/camp-starfish

Length of output: 299


🏁 Script executed:

#!/bin/bash
# Search for moment imports
echo "=== Moment imports ==="
rg -n "from ['\"]moment['\"]" src --type ts --type tsx

echo -e "\n=== Dayjs imports ==="
rg -n "from ['\"]dayjs['\"]" src --type ts --type tsx

echo -e "\n=== Direct moment() calls ==="
rg -n "\bmoment\(" src --type ts --type tsx | head -20

echo -e "\n=== Direct dayjs() calls ==="
rg -n "\bdayjs\(" src --type ts --type tsx | head -20

Repository: Hack4Impact-UMD/camp-starfish

Length of output: 310


🏁 Script executed:

#!/bin/bash
# Search without file type filters
echo "=== Moment imports in src ==="
rg "from ['\"]moment['\"]" src 2>/dev/null || echo "No matches"

echo -e "\n=== Dayjs imports in src ==="
rg "from ['\"]dayjs['\"]" src 2>/dev/null || echo "No matches"

echo -e "\n=== Check the 4 specific files ==="
echo "File 1: src/features/scheduling/generation/generateDaysOffSchedule.ts"
head -20 src/features/scheduling/generation/generateDaysOffSchedule.ts

echo -e "\nFile 2: src/data/firestore/freeplays.ts"
head -30 src/data/firestore/freeplays.ts

echo -e "\nFile 3: src/data/firestore/nightSchedules.ts"
head -30 src/data/firestore/nightSchedules.ts

echo -e "\nFile 4: src/components/NightScheduleTable.tsx"
head -30 src/components/NightScheduleTable.tsx

Repository: Hack4Impact-UMD/camp-starfish

Length of output: 8537


Replace Moment usage with dayjs across the scheduling path.

This PR adds moment usage to the scheduling generation and data modules, which conflicts with the codebase's targeted date-library standard. Per coding guidelines, the codebase should "Consolidate on dayjs for date manipulation instead of using both dayjs and moment. Remove moment dependencies to reduce bundle size."

  • src/features/scheduling/generation/generateDaysOffSchedule.ts: Replace Moment type with Dayjs for the daysOffInSession parameter in GenerateDaysOffScheduleRequest.
  • src/data/firestore/freeplays.ts: Replace moment(snapshot.ref.id).startOf('day') and Moment parameter types with dayjs equivalents.
  • src/data/firestore/nightSchedules.ts: Replace moment(snapshot.ref.id).startOf('day') and Moment parameter types with dayjs equivalents.
  • src/components/NightScheduleTable.tsx: Replace Moment type imports and any moment() calls with dayjs.
📍 Affects 4 files
  • src/features/scheduling/generation/generateDaysOffSchedule.ts#L5-L5 (this comment)
  • src/data/firestore/freeplays.ts#L7-L7
  • src/data/firestore/nightSchedules.ts#L18-L18
  • src/components/NightScheduleTable.tsx#L18-L18
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/scheduling/generation/generateDaysOffSchedule.ts` at line 5,
Replace `moment` with `dayjs` across all four affected files to consolidate on
the standard date library and reduce bundle size. In
`src/features/scheduling/generation/generateDaysOffSchedule.ts` (line 5),
replace the `Moment` import with a `Dayjs` import and update the
`daysOffInSession` parameter type in `GenerateDaysOffScheduleRequest` to use
`Dayjs` instead of `Moment`. In `src/data/firestore/freeplays.ts` (line 7),
replace the `Moment` import with `Dayjs` and update the
`moment(snapshot.ref.id).startOf('day')` call to use `dayjs()` instead, also
updating any parameter types that use `Moment` to use `Dayjs`. In
`src/data/firestore/nightSchedules.ts` (line 18), perform the same replacements:
swap the `Moment` import for `Dayjs`, convert
`moment(snapshot.ref.id).startOf('day')` to use `dayjs()`, and update parameter
types from `Moment` to `Dayjs`. In `src/components/NightScheduleTable.tsx` (line
18), replace the `Moment` type import with `Dayjs` and convert any `moment()`
function calls to `dayjs()`.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants