Skip to content

Commit

Permalink
fix: include space hierarchy when checking collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
joonatank committed Oct 31, 2024
1 parent 655bb62 commit d9eda9b
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 123 deletions.
1 change: 1 addition & 0 deletions apps/ui/components/reservation-unit/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ describe("getNextAvailableTime", () => {
},
reservableTimes,
activeApplicationRounds: activeApplicationRounds ?? [],
blockingReservations: [],
};
}

Expand Down
5 changes: 5 additions & 0 deletions apps/ui/components/reservation-unit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
startOfDay,
} from "date-fns";
import type {
BlockingReservationFieldsFragment,
ReservationUnitNode,
ReservationUnitPageQuery,
} from "@gql/gql-types";
Expand Down Expand Up @@ -63,6 +64,7 @@ type AvailableTimesProps = {
reservationUnit: QueryT;
reservableTimes: ReservableMap;
activeApplicationRounds: readonly RoundPeriod[];
blockingReservations: readonly BlockingReservationFieldsFragment[];
fromStartOfDay?: boolean;
};

Expand All @@ -74,6 +76,7 @@ function getAvailableTimesForDay({
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
}: AvailableTimesProps): string[] {
if (!reservationUnit) {
return [];
Expand All @@ -89,6 +92,7 @@ function getAvailableTimesForDay({
reservationUnit,
activeApplicationRounds,
durationValue: duration,
blockingReservations,
})
.map((n) => {
const [slotHours, slotMinutes] = n.label.split(":").map(Number);
Expand All @@ -105,6 +109,7 @@ function getAvailableTimesForDay({
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
});

return isReservable && !isBefore(startDate, startTime) ? n.label : null;
Expand Down
42 changes: 18 additions & 24 deletions apps/ui/components/reservation/EditStep0.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { breakpoints } from "common/src/common/style";
import type { PendingReservation } from "@/modules/types";
import type {
BlockingReservationFieldsFragment,
ReservationQuery,
ReservationUnitPageQuery,
} from "@gql/gql-types";
Expand All @@ -9,7 +10,6 @@ import { Button, IconArrowRight, IconCross } from "hds-react";
import React from "react";
import { useTranslation } from "next-i18next";
import styled from "styled-components";
import { filterNonNullable } from "common/src/helpers";
import {
canReservationTimeBeChanged,
convertFormToFocustimeSlot,
Expand Down Expand Up @@ -48,6 +48,7 @@ type Props = {
reservationUnit: ReservationUnitNodeT;
reservationForm: UseFormReturn<PendingReservationFormType>;
activeApplicationRounds: readonly RoundPeriod[];
blockingReservations: readonly BlockingReservationFieldsFragment[];
nextStep: () => void;
apiBaseUrl: string;
isLoading: boolean;
Expand Down Expand Up @@ -103,29 +104,14 @@ const PinkBox = styled.div`
}
`;

/// To check availability for the reservation.
/// The check functions use the reservationUnit instead of a list of other reservations
/// so have to do some questionable edits.
function getWithoutThisReservation(
reservationUnit: ReservationUnitNodeT,
reservation: ReservationNodeT
): ReservationUnitNodeT {
const otherReservations = filterNonNullable(
reservationUnit?.reservations?.filter((n) => n?.pk !== reservation.pk)
);
return {
...reservationUnit,
reservations: otherReservations,
};
}

export function EditStep0({
reservation,
reservationUnit,
activeApplicationRounds,
reservationForm,
nextStep,
isLoading,
blockingReservations: blockingReservationsOrig,
}: Props): JSX.Element {
const { t, i18n } = useTranslation();

Expand All @@ -139,14 +125,17 @@ export function EditStep0({

const reservableTimes = useReservableTimes(reservationUnit);

const resUnit = getWithoutThisReservation(reservationUnit, reservation);
const blockingReservations = blockingReservationsOrig.filter(
(r) => r.pk !== reservation.pk
);

const submitReservation = (data: PendingReservationFormType) => {
const slot = convertFormToFocustimeSlot({
data,
reservationUnit: resUnit,
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
});
if (!slot.isReservable) {
return;
Expand All @@ -173,8 +162,9 @@ export function EditStep0({
reservation,
newReservation,
reservableTimes,
reservationUnit: resUnit,
reservationUnit,
activeApplicationRounds,
blockingReservations,
});

if (isNewReservationValid) {
Expand All @@ -191,25 +181,28 @@ export function EditStep0({
const durationOptions = getDurationOptions(reservationUnit, t);
const focusSlot = convertFormToFocustimeSlot({
data: watch(),
reservationUnit: resUnit,
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
});
const startingTimeOptions = getPossibleTimesForDay({
reservableTimes,
interval: reservationUnit?.reservationStartInterval,
date: fromUIDate(watch("date") ?? "") ?? new Date(),
reservationUnit: resUnit,
reservationUnit,
activeApplicationRounds,
durationValue,
blockingReservations,
});

const nextAvailableTime = getNextAvailableTime({
start: focusDate,
reservableTimes,
duration: durationValue,
reservationUnit: resUnit,
reservationUnit,
activeApplicationRounds,
blockingReservations,
});

const lang = convertLanguageCode(i18n.language);
Expand Down Expand Up @@ -245,13 +238,14 @@ export function EditStep0({
/>
<StyledCalendarWrapper>
<ReservationTimePicker
reservationUnit={resUnit}
reservationUnit={reservationUnit}
reservableTimes={reservableTimes}
activeApplicationRounds={activeApplicationRounds}
reservationForm={reservationForm}
isReservationQuotaReached={false}
startingTimeOptions={startingTimeOptions}
submitReservation={submitReservation}
blockingReservations={blockingReservations}
/>
</StyledCalendarWrapper>
<form
Expand Down
15 changes: 11 additions & 4 deletions apps/ui/components/reservation/ReservationTimePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Children, useEffect, useMemo, useState } from "react";
import classNames from "classnames";
import {
BlockingReservationFieldsFragment,
ReservationNode,
ReservationTypeChoice,
ReservationUnitPageQuery,
Expand Down Expand Up @@ -105,6 +106,7 @@ type Props = {
reservationUnit: NonNullable<ReservationUnitPageQuery["reservationUnit"]>;
reservableTimes: ReservableMap;
activeApplicationRounds: readonly RoundPeriod[];
blockingReservations: readonly BlockingReservationFieldsFragment[];
reservationForm: UseFormReturn<PendingReservationFormType>;
isReservationQuotaReached: boolean;
submitReservation: (d: PendingReservationFormType) => void;
Expand Down Expand Up @@ -147,18 +149,18 @@ function useSlotPropGetter({
function useCalendarEventChange({
reservationUnit,
focusSlot,
blockingReservations,
}: Pick<Props, "reservationUnit"> & {
focusSlot: ReturnType<typeof convertFormToFocustimeSlot>;
blockingReservations: readonly BlockingReservationFieldsFragment[];
}): Array<CalendarEventBuffer | CalendarEvent<ReservationNode>> {
const { t } = useTranslation();
// TODO this doesn't optimize anything
// any change in the event will cause a full recalculation
const calendarEvents: Array<
CalendarEventBuffer | CalendarEvent<ReservationNode>
> = useMemo(() => {
const existingReservations = filterNonNullable(
reservationUnit.reservations
);
const existingReservations = blockingReservations;

const shouldDisplayFocusSlot = focusSlot.isReservable;

Expand Down Expand Up @@ -214,7 +216,7 @@ function useCalendarEventChange({
...(pendingReservation != null ? [pendingReservation] : []),
]),
];
}, [reservationUnit, t, focusSlot]);
}, [reservationUnit, t, focusSlot, blockingReservations]);

return calendarEvents;
}
Expand All @@ -228,6 +230,7 @@ export function ReservationTimePicker({
loginAndSubmitButton,
submitReservation,
startingTimeOptions,
blockingReservations,
}: Props) {
const { t, i18n } = useTranslation();
const [calendarViewType, setCalendarViewType] = useState<WeekOptions>("week");
Expand All @@ -248,11 +251,13 @@ export function ReservationTimePicker({
reservationUnit,
activeApplicationRounds,
reservableTimes,
blockingReservations,
});

const calendarEvents = useCalendarEventChange({
reservationUnit,
focusSlot,
blockingReservations,
});
const slotPropGetter = useSlotPropGetter({
reservableTimes,
Expand Down Expand Up @@ -294,6 +299,7 @@ export function ReservationTimePicker({
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
});

if (!isReservable) {
Expand Down Expand Up @@ -351,6 +357,7 @@ export function ReservationTimePicker({
reservationUnit,
reservableTimes,
activeApplicationRounds,
blockingReservations,
});
if (!isReservable) {
return false;
Expand Down
30 changes: 0 additions & 30 deletions apps/ui/gql/gql-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6515,19 +6515,6 @@ export type IsReservableFieldsFragment = {
reservationsMinDaysBefore?: number | null;
reservationBegins?: string | null;
reservationEnds?: string | null;
reservations?: Array<{
pk?: number | null;
id: string;
state?: ReservationStateChoice | null;
isBlocked?: boolean | null;
begin: string;
end: string;
numPersons?: number | null;
calendarUrl?: string | null;
bufferTimeBefore: number;
bufferTimeAfter: number;
affectedReservationUnits?: Array<number | null> | null;
}> | null;
reservableTimeSpans?: Array<{
startDatetime?: string | null;
endDatetime?: string | null;
Expand Down Expand Up @@ -6626,19 +6613,6 @@ export type ReservationUnitPageQuery = {
nameSv?: string | null;
};
}>;
reservations?: Array<{
pk?: number | null;
id: string;
state?: ReservationStateChoice | null;
isBlocked?: boolean | null;
begin: string;
end: string;
numPersons?: number | null;
calendarUrl?: string | null;
bufferTimeBefore: number;
bufferTimeAfter: number;
affectedReservationUnits?: Array<number | null> | null;
}> | null;
reservableTimeSpans?: Array<{
startDatetime?: string | null;
endDatetime?: string | null;
Expand Down Expand Up @@ -8001,9 +7975,6 @@ export const BlockingReservationFieldsFragmentDoc = gql`
`;
export const IsReservableFieldsFragmentDoc = gql`
fragment IsReservableFields on ReservationUnitNode {
reservations(state: $state) {
...BlockingReservationFields
}
bufferTimeBefore
bufferTimeAfter
reservableTimeSpans(startDate: $beginDate, endDate: $endDate) {
Expand All @@ -8018,7 +7989,6 @@ export const IsReservableFieldsFragmentDoc = gql`
reservationBegins
reservationEnds
}
${BlockingReservationFieldsFragmentDoc}
`;
export const ReservationUnitNameFieldsFragmentDoc = gql`
fragment ReservationUnitNameFields on ReservationUnitNode {
Expand Down
4 changes: 3 additions & 1 deletion apps/ui/modules/__tests__/reservable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
isStartTimeValid,
} from "../reservable";
import {
BlockingReservationFieldsFragment,
type IsReservableFieldsFragment,
ReservationStartInterval,
ReservationStateChoice,
Expand Down Expand Up @@ -322,7 +323,7 @@ describe("isRangeReservable", () => {
bufferTimeBefore?: number;
bufferTimeAfter?: number;
reservableTimes?: ReservableMap;
reservations?: IsReservableFieldsFragment["reservations"];
reservations?: BlockingReservationFieldsFragment[];
interval?: ReservationStartInterval;
maxReservationDuration?: IsReservableFieldsFragment["maxReservationDuration"];
minReservationDuration?: IsReservableFieldsFragment["minReservationDuration"];
Expand All @@ -338,6 +339,7 @@ describe("isRangeReservable", () => {
reservationUnit: createMockReservationUnit(rest),
activeApplicationRounds: activeApplicationRounds ?? [],
reservableTimes: reservableTimes ?? mockReservableTimes(),
blockingReservations: rest.reservations ?? [],
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/ui/modules/__tests__/reservation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ describe("canReservationBeChanged", () => {
},
reservationUnit: baseUnit,
activeApplicationRounds: [],
blockingReservations: [],
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/ui/modules/__tests__/reservationUnit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe("getPossibleTimesForDay", () => {
activeApplicationRounds: [] as const,
reservableTimes: reservableTimes ?? mockReservableTimes(),
durationValue: duration ?? 30,
blockingReservations: [] as const,
};
}

Expand Down
3 changes: 0 additions & 3 deletions apps/ui/modules/queries/reservationUnit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ export const RESERVATION_UNIT_PARAMS_PAGE_QUERY = gql`
const IS_RESERVABLE_FRAGMENT = gql`
${BLOCKING_RESERVATION_FRAGMENT}
fragment IsReservableFields on ReservationUnitNode {
reservations(state: $state) {
...BlockingReservationFields
}
bufferTimeBefore
bufferTimeAfter
reservableTimeSpans(startDate: $beginDate, endDate: $endDate) {
Expand Down
Loading

0 comments on commit d9eda9b

Please sign in to comment.