Skip to content

Commit

Permalink
done with transforming data of bookings and detailedbookings
Browse files Browse the repository at this point in the history
  • Loading branch information
MariaBonde committed Jan 10, 2025
1 parent bd7b2f4 commit ea0d5b7
Show file tree
Hide file tree
Showing 8 changed files with 604 additions and 96 deletions.
134 changes: 130 additions & 4 deletions frontend/mockdata/mockData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BookingType,
CompetenceReadModel,
ConsultantReadModel,
Degree,
Expand All @@ -16,7 +17,7 @@ const MockWeeklyBookingReadModel: WeeklyBookingReadModel = {
totalSellableTime: 0,
totalBillable: 0,
totalOffered: 0,
totalVacationHours: 0,
totalVacationHours: 10,
totalExcludableAbsence: 0,
totalNotStartedOrQuit: 0,
};
Expand Down Expand Up @@ -78,11 +79,11 @@ export const MockConsultants: ConsultantReadModel[] = [
department: { id: "mydepartment", name: "My Department" },
bookings: [
{
year: 2023,
weekNumber: 10,
year: 2025,
weekNumber: 14,
dateString: "",
bookingModel: MockWeeklyBookingReadModel,
sortableWeek: 202310,
sortableWeek: 202514,
},
],
yearsOfExperience: 23,
Expand All @@ -99,6 +100,131 @@ export const MockConsultants: ConsultantReadModel[] = [
mockForecast6,
],
},
{
id: 2,
name: "2test Consultant",
email: "[email protected]",
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,
},
},
],
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 },
],
},
],
isOccupied: true,
graduationYear: 2010,
degree: Degree.Bachelor,
forecasts: [
mockForecast1,
mockForecast2,
mockForecast3,
mockForecast4,
mockForecast5,
mockForecast6,
],
},
];

export const MockDepartments: DepartmentReadModel[] = [
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ export interface BookedHoursPerWeek {
dateString: string;
bookingModel: WeeklyBookingReadModel;
}

export interface BookedHoursPerMonth {
month: number;
year: number;
bookingModel: WeeklyBookingReadModel;
}
export interface BookingDetails {
/** @minLength 1 */
projectName: string;
Expand Down Expand Up @@ -133,6 +137,11 @@ export interface DetailedBooking {
hours: WeeklyHours[];
}

export interface MonthlyDetailedBooking {
bookingDetails: BookingDetails;
hours: MonthlyHours[];
}

export interface EngagementPerCustomerReadModel {
/** @format int32 */
customerId: number;
Expand Down Expand Up @@ -299,6 +308,11 @@ export interface WeeklyHours {
hours: number;
}

export interface MonthlyHours {
month: number;
hours: number;
}

export interface CustomersWithProjectsReadModel {
customerId: number;
customerName: string;
Expand Down
23 changes: 22 additions & 1 deletion frontend/src/components/Forecast/ForecastRows.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
"use client";
import { ConsultantReadModel, ProjectWithCustomerModel } from "@/api-types";
import {
BookedHoursPerWeek,
ConsultantReadModel,
ProjectWithCustomerModel,
WeeklyBookingReadModel,
} from "@/api-types";
import React, { useContext, useEffect, useState } from "react";
import { AlertCircle, CheckCircle, ChevronDown, Plus } from "react-feather";
import { DetailedBookingRows } from "@/components/Staffing/DetailedBookingRows";
Expand All @@ -17,6 +22,16 @@ import { DateTime } from "luxon";
import Image from "next/image";
import { INTERNAL_CUSTOMER_NAME } from "../Staffing/helpers/utils";
import { MonthCell } from "./MonthCell";
import {
getMonthOfWeek,
MonthDistributionOfWeek,
weekToWeekType,
} from "./WeekToMonthConverter";
import { Month } from "date-fns";
import {
bookingForMonth,
transformToMonthlyData,
} from "./TransformWeekDataToMonth";

export default function ForecastRows({
consultant,
Expand Down Expand Up @@ -68,6 +83,7 @@ export default function ForecastRows({
} = useModal({
closeOnBackdropClick: false,
});
const bookingsPerMonth = transformToMonthlyData(consultant.bookings);

const [selectedProjectId, setSelectedProjectId] = useState<
number | undefined
Expand Down Expand Up @@ -211,6 +227,11 @@ export default function ForecastRows({
</td>
{currentConsultant.forecasts?.map((b, index) => (
<MonthCell
bookedHoursPerMonth={bookingForMonth(
bookingsPerMonth,
b.month,
b.year,
)}
key={index}
hasBeenEdited={b.hasBeenChanged}
forecastValue={b.forecastValue + b.valueAddedManually}
Expand Down
132 changes: 132 additions & 0 deletions frontend/src/components/Forecast/HoveredMonth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {
BookingType,
ConsultantReadModel,
MonthlyDetailedBooking,
} from "@/api-types";
import {
getColorByStaffingType,
getIconByBookingType,
} from "@/components/Staffing/helpers/utils";
import React from "react";
import {
transformDetailedBookingToMonthlyData,
transformToMonthlyData,
} from "./TransformWeekDataToMonth";
function isMonthBookingZeroHours(
detailedBooking: MonthlyDetailedBooking,
hoveredRowMonth: number,
): boolean {
return (
detailedBooking.hours.filter(
(monthHours) =>
monthHours.month % 100 == hoveredRowMonth && monthHours.hours != 0,
).length == 0
);
}
export function HoveredMonth(props: {
hoveredRowMonth: number;
consultant: ConsultantReadModel;
isLastCol: boolean;
isSecondLastCol: boolean;
columnCount: number;
}) {
const {
hoveredRowMonth: hoveredRowMonth,
consultant,
isLastCol,
isSecondLastCol,
columnCount,
} = props;

const bookings = transformToMonthlyData(consultant.bookings);
const detailedBookings = transformDetailedBookingToMonthlyData(
consultant.detailedBooking,
);

const nonZeroHoursDetailedBookings = detailedBookings.filter(
(d) => !isMonthBookingZeroHours(d, hoveredRowMonth),
);

const freeTime = bookings.find((b) => b.month == hoveredRowMonth)
?.bookingModel.totalSellableTime;
if (freeTime && freeTime > 0) {
nonZeroHoursDetailedBookings.push({
bookingDetails: {
type: BookingType.Available,
projectName: "",
customerName: "Ledig Tid",
projectId: 0,
isBillable: false,
},
hours: [
{
month: hoveredRowMonth,
hours:
consultant.bookings.find((b) => b.weekNumber == hoveredRowMonth)
?.bookingModel.totalSellableTime || 0,
},
],
});
}

return (
<>
<div
className={`rounded-lg bg-white gap-3 min-w-[222px] p-3 shadow-xl absolute bottom-full mb-2 flex flex-col z-20 pointer-events-none ${
isLastCol || (isSecondLastCol && columnCount >= 26)
? "right-0 "
: "left-1/2 -translate-x-1/2"
} ${nonZeroHoursDetailedBookings.length == 0 && "hidden"}`}
>
{nonZeroHoursDetailedBookings.map((detailedBooking, index) => (
<div
key={index}
className={`flex flex-row gap-2 justify-between items-center
${
index < nonZeroHoursDetailedBookings.length - 1 &&
"pb-3 border-b border-black/10"
}`}
>
<div className="flex flex-row gap-2 items-center">
<div
className={`h-8 w-8 flex justify-center align-middle items-center rounded ${getColorByStaffingType(
detailedBooking.bookingDetails.type,
)}`}
>
{getIconByBookingType(detailedBooking.bookingDetails.type, 16)}
</div>
<div className="flex flex-col">
<p
className={`xsmall text-black/75 ${
!(
detailedBooking.bookingDetails.type ==
BookingType.Offer ||
detailedBooking.bookingDetails.type == BookingType.Booking
) && "hidden"
}`}
>
{detailedBooking.bookingDetails.projectName}
</p>
<p className="small text-black whitespace-nowrap">
{detailedBooking.bookingDetails.customerName}
</p>
</div>
</div>
<p className="small text-black/75">
{
detailedBooking.hours.find(
(hour) => hour.month % 100 == hoveredRowMonth,
)?.hours
}
</p>
</div>
))}
</div>
<div
className={`absolute bottom-full mb-[2px] left-1/2 -translate-x-1/2 flex items-center z-50 w-0 h-0 border-l-[8px] border-l-transparent border-t-[8px] border-t-white border-r-[8px] border-r-transparent pointer-events-none ${
nonZeroHoursDetailedBookings.length == 0 && "hidden"
}`}
></div>
</>
);
}
Loading

0 comments on commit ea0d5b7

Please sign in to comment.