diff --git a/frontend/mockdata/mockData.ts b/frontend/mockdata/mockData.ts index 80ef4c8d..d3b9feee 100644 --- a/frontend/mockdata/mockData.ts +++ b/frontend/mockdata/mockData.ts @@ -1,9 +1,11 @@ import { + BookedHoursPerWeek, BookingType, CompetenceReadModel, ConsultantReadModel, Degree, DepartmentReadModel, + DetailedBooking, EngagementPerCustomerReadModel, Forecast, OrganisationReadModel, @@ -70,6 +72,369 @@ const mockForecast6: Forecast = { valueAddedManually: 10, }; +export const MockDepartments: DepartmentReadModel[] = [ + { + id: "myDepartment", + name: "My Department", + }, +]; + +export const MockOrganisations: OrganisationReadModel[] = [ + { + name: "My Organisation", + urlKey: "my-org", + }, +]; + +export const MockEngagements: EngagementPerCustomerReadModel[] = [ + { + customerId: 1, + customerName: "TestCustomer", + engagements: [], + isActive: false, + }, +]; + +export const MockCompetences: CompetenceReadModel[] = [ + { + id: "development", + name: "Utvikling", + }, +]; +const mockDetailedBookings: DetailedBooking[] = [ + { + bookingDetails: { + projectName: "Elbil", + type: BookingType.Booking, + customerName: "Bil", + projectId: 1001, + isBillable: true, + endDateAgreement: "2025-05-08T00:00:00", + }, + hours: [ + { week: 202502, hours: 37.5 }, + { week: 202503, hours: 37.5 }, + { week: 202504, hours: 37.5 }, + { week: 202505, hours: 37.5 }, + { week: 202506, hours: 30 }, + { week: 202507, hours: 22.5 }, + { week: 202508, hours: 37.5 }, + { week: 202509, hours: 37.5 }, + { week: 202510, hours: 37.5 }, + { week: 202511, hours: 30 }, + { week: 202512, hours: 30 }, + { week: 202513, hours: 30 }, + { week: 202514, hours: 37.5 }, + { week: 202515, hours: 37.5 }, + { week: 202516, hours: 22.5 }, + { week: 202517, hours: 30 }, + { week: 202518, hours: 30 }, + ], + }, + { + bookingDetails: { + projectName: "Nye nettsider", + type: BookingType.Offer, + customerName: "Åkerblå", + projectId: 208, + isBillable: false, + endDateAgreement: "2024-11-29T00:00:00", + }, + hours: [ + { week: 202502, hours: 0 }, + { week: 202503, hours: 0 }, + { week: 202504, hours: 0 }, + { week: 202505, hours: 0 }, + { week: 202506, hours: 0 }, + { week: 202507, hours: 0 }, + { week: 202508, hours: 0 }, + { week: 202509, hours: 0 }, + { week: 202510, hours: 0 }, + { week: 202511, hours: 7.5 }, + { week: 202512, hours: 7.5 }, + { week: 202513, hours: 7.5 }, + { week: 202514, hours: 0 }, + { week: 202515, hours: 0 }, + { week: 202516, hours: 0 }, + { week: 202517, hours: 0 }, + { week: 202518, hours: 0 }, + ], + }, +]; +const mockBookings: BookedHoursPerWeek[] = [ + { + year: 2025, + weekNumber: 2, + sortableWeek: 202502, + dateString: "06.01 - 10.01", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 3, + sortableWeek: 202503, + dateString: "13.01 - 17.01", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 4, + sortableWeek: 202504, + dateString: "20.01 - 24.01", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 5, + sortableWeek: 202505, + dateString: "27.01 - 31.01", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 6, + sortableWeek: 202506, + dateString: "03.02 - 07.02", + bookingModel: { + totalBillable: 30, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 7.5, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 7, + sortableWeek: 202507, + dateString: "10.02 - 14.02", + bookingModel: { + totalBillable: 22.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 15, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 8, + sortableWeek: 202508, + dateString: "17.02 - 21.02", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 9, + sortableWeek: 202509, + dateString: "24.02 - 28.02", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 10, + sortableWeek: 202510, + dateString: "03.03 - 07.03", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 11, + sortableWeek: 202511, + dateString: "10.03 - 14.03", + bookingModel: { + totalBillable: 30, + totalOffered: 7.5, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 7.5, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 12, + sortableWeek: 202512, + dateString: "17.03 - 21.03", + bookingModel: { + totalBillable: 30, + totalOffered: 7.5, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 7.5, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 13, + sortableWeek: 202513, + dateString: "24.03 - 28.03", + bookingModel: { + totalBillable: 30, + totalOffered: 7.5, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 7.5, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 14, + sortableWeek: 202514, + dateString: "31.03 - 04.04", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 15, + sortableWeek: 202515, + dateString: "07.04 - 11.04", + bookingModel: { + totalBillable: 37.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 0, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 16, + sortableWeek: 202516, + dateString: "14.04 - 18.04", + bookingModel: { + totalBillable: 22.5, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 15, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, + { + year: 2025, + weekNumber: 17, + sortableWeek: 202517, + dateString: "21.04 - 25.04", + bookingModel: { + totalBillable: 30, + totalOffered: 0, + totalPlannedAbsences: 0, + totalExcludableAbsence: 0, + totalSellableTime: 0, + totalHolidayHours: 7.5, + totalVacationHours: 0, + totalOverbooking: 0, + totalNotStartedOrQuit: 0, + }, + }, +]; export const MockConsultants: ConsultantReadModel[] = [ { id: 1, @@ -138,113 +503,9 @@ export const MockConsultantsForForecast: ConsultantReadModel[] = [ email: "test2@company.io", competences: [{ id: "development", name: "Utvikling" }], department: { id: "mydepartment", name: "My Department" }, - bookings: [ - { - year: 2025, - weekNumber: 3, - sortableWeek: 202503, - dateString: "13.01 - 17.01", - bookingModel: { - totalBillable: 0, - totalOffered: 7.5, - totalPlannedAbsences: 0, - totalExcludableAbsence: 0, - totalSellableTime: 7.5, - totalHolidayHours: 0, - totalVacationHours: 0, - totalOverbooking: 0, - totalNotStartedOrQuit: 0, - }, - }, - { - year: 2025, - weekNumber: 4, - sortableWeek: 202504, - dateString: "20.01 - 24.01", - bookingModel: { - totalBillable: 20, - totalOffered: 0, - totalPlannedAbsences: 0, - totalExcludableAbsence: 0, - totalSellableTime: 0, - totalHolidayHours: 0, - totalVacationHours: 0, - totalOverbooking: 0, - totalNotStartedOrQuit: 0, - }, - }, - { - year: 2025, - weekNumber: 5, - sortableWeek: 202505, - dateString: "27.01 - 31.01", - bookingModel: { - totalBillable: 20, - totalOffered: 0, - totalPlannedAbsences: 0, - totalExcludableAbsence: 0, - totalSellableTime: 0, - totalHolidayHours: 0, - totalVacationHours: 0, - totalOverbooking: 0, - totalNotStartedOrQuit: 0, - }, - }, - { - year: 2025, - weekNumber: 6, - sortableWeek: 202506, - dateString: "03.02 - 07.02", - bookingModel: { - totalBillable: 20, - totalOffered: 0, - totalPlannedAbsences: 0, - totalExcludableAbsence: 0, - totalSellableTime: 37.5, - totalHolidayHours: 0, - totalVacationHours: 0, - totalOverbooking: 0, - totalNotStartedOrQuit: 0, - }, - }, - ], + bookings: mockBookings, yearsOfExperience: 23, - detailedBooking: [ - { - bookingDetails: { - projectName: "Design", - type: BookingType.Booking, - customerName: "Aion", - projectId: 185, - isBillable: true, - endDateAgreement: null, - }, - hours: [ - { week: 202503, hours: 10 }, - { week: 202504, hours: 5 }, - { week: 202505, hours: 15 }, - { week: 202506, hours: 37 }, - ], - }, - { - bookingDetails: { - projectName: "Nye nettsider", - type: BookingType.Booking, - customerName: "Åkerblå", - projectId: 208, - isBillable: true, - endDateAgreement: "2024-11-29T00:00:00", - }, - hours: [ - { week: 202503, hours: 10 }, - { week: 202504, hours: 5 }, - { week: 202505, hours: 15 }, - { week: 202506, hours: 37 }, - { week: 202507, hours: 37 }, - { week: 202514, hours: 37 }, - ], - }, - ], + detailedBooking: mockDetailedBookings, isOccupied: true, graduationYear: 2010, degree: Degree.Bachelor, @@ -258,33 +519,3 @@ export const MockConsultantsForForecast: ConsultantReadModel[] = [ ], }, ]; - -export const MockDepartments: DepartmentReadModel[] = [ - { - id: "myDepartment", - name: "My Department", - }, -]; - -export const MockOrganisations: OrganisationReadModel[] = [ - { - name: "My Organisation", - urlKey: "my-org", - }, -]; - -export const MockEngagements: EngagementPerCustomerReadModel[] = [ - { - customerId: 1, - customerName: "TestCustomer", - engagements: [], - isActive: false, - }, -]; - -export const MockCompetences: CompetenceReadModel[] = [ - { - id: "development", - name: "Utvikling", - }, -]; diff --git a/frontend/src/components/Forecast/HoveredMonth.tsx b/frontend/src/components/Forecast/HoveredMonth.tsx index 02aea063..0ddbeebe 100644 --- a/frontend/src/components/Forecast/HoveredMonth.tsx +++ b/frontend/src/components/Forecast/HoveredMonth.tsx @@ -42,13 +42,14 @@ export function HoveredMonth(props: { const detailedBookings = transformDetailedBookingToMonthlyData( consultant.detailedBooking, ); - const nonZeroHoursDetailedBookings = detailedBookings.filter( (d) => !isMonthBookingZeroHours(d, hoveredRowMonth), ); const freeTime = bookings.find((b) => b.month == hoveredRowMonth) ?.bookingModel.totalSellableTime; + console.log("freeTime", freeTime); + console.log(consultant.bookings); if (freeTime && freeTime > 0) { nonZeroHoursDetailedBookings.push({ bookingDetails: { @@ -62,8 +63,8 @@ export function HoveredMonth(props: { { month: hoveredRowMonth, hours: - consultant.bookings.find((b) => b.weekNumber == hoveredRowMonth) - ?.bookingModel.totalSellableTime || 0, + bookings.find((b) => b.month == hoveredRowMonth)?.bookingModel + .totalSellableTime || 0, }, ], }); diff --git a/frontend/src/components/Forecast/TransformWeekDataToMonth.ts b/frontend/src/components/Forecast/TransformWeekDataToMonth.ts index fb44e651..e1bdc10f 100644 --- a/frontend/src/components/Forecast/TransformWeekDataToMonth.ts +++ b/frontend/src/components/Forecast/TransformWeekDataToMonth.ts @@ -8,10 +8,9 @@ import { WeeklyBookingReadModel, } from "@/api-types"; import { getMonthOfWeek, weekToWeekType } from "./WeekToMonthConverter"; -import { add } from "lodash"; function round2Decimals(num: number) { - return Math.round(num * 100) / 100; + return Math.round(num * 2) / 2; } function transformToMonthlyData(weeklyData: BookedHoursPerWeek[]) { const monthlyData: { [key: string]: BookedHoursPerMonth } = {}; @@ -118,7 +117,7 @@ function transformDetailedBookingToMonthlyData( hours: 0, }; } - monthlyHours[monthLabel].hours += hours * distribution; + monthlyHours[monthLabel].hours += round2Decimals(hours * distribution); } hours.forEach((weekhour) => { const { week, hours } = weekhour; @@ -137,12 +136,11 @@ function transformDetailedBookingToMonthlyData( monthDistribution.secondMonth }` : null; - const primaryDistribution = round2Decimals( - monthDistribution.distribution / 100, - ); + const primaryDistribution = monthDistribution.distribution / 100; const secondaryDistribution = secondaryMonthKey - ? round2Decimals((100 - monthDistribution.distribution) / 100) + ? (100 - monthDistribution.distribution) / 100 : 0; + addToMonthlyHours(primaryMonthKey, hours, primaryDistribution); if (secondaryMonthKey) { addToMonthlyHours(secondaryMonthKey, hours, secondaryDistribution); diff --git a/frontend/src/components/Staffing/ConsultantRow.tsx b/frontend/src/components/Staffing/ConsultantRow.tsx index c8926955..e800c062 100644 --- a/frontend/src/components/Staffing/ConsultantRow.tsx +++ b/frontend/src/components/Staffing/ConsultantRow.tsx @@ -26,6 +26,10 @@ export default function ConsultantRows({ consultant: ConsultantReadModel; numWorkHours: number; }) { + if (consultant.bookings.length > 0 && consultant.name.startsWith("Adrian")) { + console.log("detailedBooking", consultant.detailedBooking); + console.log("bookings", consultant.bookings); + } const [currentConsultant, setCurrentConsultant] = useState(consultant); const [isListElementVisible, setIsListElementVisible] = useState(false);