Gowrisankar Cursor commited on
Commit
e0122d1
·
1 Parent(s): 6c34734

Round project allocation display to half-hour increments.

Browse files

Shows hours per day as 4h or 3.5h instead of minute-level values on timeline bars and summaries.

Co-authored-by: Cursor <cursoragent@cursor.com>

frontend/src/components/projects/ProjectPlannerBlock.tsx CHANGED
@@ -5,6 +5,8 @@ import { ProjectAllocationTimeline } from "./ProjectAllocationTimeline";
5
  import { ProjectTimelineRow } from "../planner/ProjectTimelineRow";
6
  import {
7
  allocatedHoursInRange,
 
 
8
  visibleWeekdayCount,
9
  } from "../../planner/allocationTimeline";
10
  import type { Allocation, Person, Project } from "../../types";
@@ -55,7 +57,7 @@ export function ProjectPlannerBlock({
55
  }
56
  const capacity = Array.from(seen).reduce((sum, personId) => {
57
  const person = peopleById.get(personId);
58
- return sum + (person ? (person.weekly_capacity_hrs / 5) * weekdayCount : 0);
59
  }, 0);
60
  return { allocatedHours: allocated, capacityHours: capacity, developerCount: seen.size };
61
  }, [allocations, peopleById, dayDates, weekdayCount]);
@@ -63,9 +65,9 @@ export function ProjectPlannerBlock({
63
  const hoursPct = capacityHours > 0 ? Math.min(100, (allocatedHours / capacityHours) * 100) : 0;
64
  const hoursLabel =
65
  capacityHours > 0
66
- ? `${allocatedHours.toFixed(1)}h / ${capacityHours.toFixed(0)}h`
67
  : developerCount > 0
68
- ? `${allocatedHours.toFixed(1)}h allocated`
69
  : "No developers assigned";
70
 
71
  const roleGroups = useMemo(() => {
 
5
  import { ProjectTimelineRow } from "../planner/ProjectTimelineRow";
6
  import {
7
  allocatedHoursInRange,
8
+ formatHoursAmount,
9
+ roundToHalfHour,
10
  visibleWeekdayCount,
11
  } from "../../planner/allocationTimeline";
12
  import type { Allocation, Person, Project } from "../../types";
 
57
  }
58
  const capacity = Array.from(seen).reduce((sum, personId) => {
59
  const person = peopleById.get(personId);
60
+ return sum + (person ? roundToHalfHour(person.weekly_capacity_hrs / 5) * weekdayCount : 0);
61
  }, 0);
62
  return { allocatedHours: allocated, capacityHours: capacity, developerCount: seen.size };
63
  }, [allocations, peopleById, dayDates, weekdayCount]);
 
65
  const hoursPct = capacityHours > 0 ? Math.min(100, (allocatedHours / capacityHours) * 100) : 0;
66
  const hoursLabel =
67
  capacityHours > 0
68
+ ? `${formatHoursAmount(allocatedHours)} / ${formatHoursAmount(capacityHours)}`
69
  : developerCount > 0
70
+ ? `${formatHoursAmount(allocatedHours)} allocated`
71
  : "No developers assigned";
72
 
73
  const roleGroups = useMemo(() => {
frontend/src/planner/allocationTimeline.ts CHANGED
@@ -32,12 +32,22 @@ export function buildAllocationBarSegment(
32
 
33
  export { projectBarStyle };
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  export function formatHoursPerDay(allocationPct: number, weeklyCapacityHrs: number): string {
36
- const hrs = (allocationPct / 100) * weeklyCapacityHrs / 5;
37
- const hours = Math.floor(hrs);
38
- const minutes = Math.round((hrs - hours) * 60);
39
- if (minutes <= 0) return `${hours}h/day`;
40
- return `${hours}h ${minutes}m/day`;
41
  }
42
 
43
  export function visibleWeekdayCount(dayDates: Date[], startDate: string, endDate: string): number {
@@ -52,6 +62,6 @@ export function allocatedHoursInRange(
52
  weeklyCapacityHrs: number,
53
  weekdayCount: number,
54
  ): number {
55
- const daily = (allocationPct / 100) * (weeklyCapacityHrs / 5);
56
  return daily * weekdayCount;
57
  }
 
32
 
33
  export { projectBarStyle };
34
 
35
+ /** Round to nearest 30 minutes (0.5h). */
36
+ export function roundToHalfHour(hours: number): number {
37
+ return Math.round(hours * 2) / 2;
38
+ }
39
+
40
+ export function hoursPerDayFromAllocation(allocationPct: number, weeklyCapacityHrs: number): number {
41
+ return (allocationPct / 100) * weeklyCapacityHrs / 5;
42
+ }
43
+
44
+ export function formatHoursAmount(hours: number): string {
45
+ return `${roundToHalfHour(hours)}h`;
46
+ }
47
+
48
  export function formatHoursPerDay(allocationPct: number, weeklyCapacityHrs: number): string {
49
+ const daily = roundToHalfHour(hoursPerDayFromAllocation(allocationPct, weeklyCapacityHrs));
50
+ return `${formatHoursAmount(daily)}/day`;
 
 
 
51
  }
52
 
53
  export function visibleWeekdayCount(dayDates: Date[], startDate: string, endDate: string): number {
 
62
  weeklyCapacityHrs: number,
63
  weekdayCount: number,
64
  ): number {
65
+ const daily = roundToHalfHour(hoursPerDayFromAllocation(allocationPct, weeklyCapacityHrs));
66
  return daily * weekdayCount;
67
  }