Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit d9eda9b

Browse files
committed
fix: include space hierarchy when checking collisions
1 parent 655bb62 commit d9eda9b

15 files changed

Lines changed: 79 additions & 123 deletions

File tree

apps/ui/components/reservation-unit/utils.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ describe("getNextAvailableTime", () => {
220220
},
221221
reservableTimes,
222222
activeApplicationRounds: activeApplicationRounds ?? [],
223+
blockingReservations: [],
223224
};
224225
}
225226

apps/ui/components/reservation-unit/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
startOfDay,
88
} from "date-fns";
99
import type {
10+
BlockingReservationFieldsFragment,
1011
ReservationUnitNode,
1112
ReservationUnitPageQuery,
1213
} from "@gql/gql-types";
@@ -63,6 +64,7 @@ type AvailableTimesProps = {
6364
reservationUnit: QueryT;
6465
reservableTimes: ReservableMap;
6566
activeApplicationRounds: readonly RoundPeriod[];
67+
blockingReservations: readonly BlockingReservationFieldsFragment[];
6668
fromStartOfDay?: boolean;
6769
};
6870

@@ -74,6 +76,7 @@ function getAvailableTimesForDay({
7476
reservationUnit,
7577
reservableTimes,
7678
activeApplicationRounds,
79+
blockingReservations,
7780
}: AvailableTimesProps): string[] {
7881
if (!reservationUnit) {
7982
return [];
@@ -89,6 +92,7 @@ function getAvailableTimesForDay({
8992
reservationUnit,
9093
activeApplicationRounds,
9194
durationValue: duration,
95+
blockingReservations,
9296
})
9397
.map((n) => {
9498
const [slotHours, slotMinutes] = n.label.split(":").map(Number);
@@ -105,6 +109,7 @@ function getAvailableTimesForDay({
105109
reservationUnit,
106110
reservableTimes,
107111
activeApplicationRounds,
112+
blockingReservations,
108113
});
109114

110115
return isReservable && !isBefore(startDate, startTime) ? n.label : null;

apps/ui/components/reservation/EditStep0.tsx

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { breakpoints } from "common/src/common/style";
22
import type { PendingReservation } from "@/modules/types";
33
import type {
4+
BlockingReservationFieldsFragment,
45
ReservationQuery,
56
ReservationUnitPageQuery,
67
} from "@gql/gql-types";
@@ -9,7 +10,6 @@ import { Button, IconArrowRight, IconCross } from "hds-react";
910
import React from "react";
1011
import { useTranslation } from "next-i18next";
1112
import styled from "styled-components";
12-
import { filterNonNullable } from "common/src/helpers";
1313
import {
1414
canReservationTimeBeChanged,
1515
convertFormToFocustimeSlot,
@@ -48,6 +48,7 @@ type Props = {
4848
reservationUnit: ReservationUnitNodeT;
4949
reservationForm: UseFormReturn<PendingReservationFormType>;
5050
activeApplicationRounds: readonly RoundPeriod[];
51+
blockingReservations: readonly BlockingReservationFieldsFragment[];
5152
nextStep: () => void;
5253
apiBaseUrl: string;
5354
isLoading: boolean;
@@ -103,29 +104,14 @@ const PinkBox = styled.div`
103104
}
104105
`;
105106

106-
/// To check availability for the reservation.
107-
/// The check functions use the reservationUnit instead of a list of other reservations
108-
/// so have to do some questionable edits.
109-
function getWithoutThisReservation(
110-
reservationUnit: ReservationUnitNodeT,
111-
reservation: ReservationNodeT
112-
): ReservationUnitNodeT {
113-
const otherReservations = filterNonNullable(
114-
reservationUnit?.reservations?.filter((n) => n?.pk !== reservation.pk)
115-
);
116-
return {
117-
...reservationUnit,
118-
reservations: otherReservations,
119-
};
120-
}
121-
122107
export function EditStep0({
123108
reservation,
124109
reservationUnit,
125110
activeApplicationRounds,
126111
reservationForm,
127112
nextStep,
128113
isLoading,
114+
blockingReservations: blockingReservationsOrig,
129115
}: Props): JSX.Element {
130116
const { t, i18n } = useTranslation();
131117

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

140126
const reservableTimes = useReservableTimes(reservationUnit);
141127

142-
const resUnit = getWithoutThisReservation(reservationUnit, reservation);
128+
const blockingReservations = blockingReservationsOrig.filter(
129+
(r) => r.pk !== reservation.pk
130+
);
143131

144132
const submitReservation = (data: PendingReservationFormType) => {
145133
const slot = convertFormToFocustimeSlot({
146134
data,
147-
reservationUnit: resUnit,
135+
reservationUnit,
148136
reservableTimes,
149137
activeApplicationRounds,
138+
blockingReservations,
150139
});
151140
if (!slot.isReservable) {
152141
return;
@@ -173,8 +162,9 @@ export function EditStep0({
173162
reservation,
174163
newReservation,
175164
reservableTimes,
176-
reservationUnit: resUnit,
165+
reservationUnit,
177166
activeApplicationRounds,
167+
blockingReservations,
178168
});
179169

180170
if (isNewReservationValid) {
@@ -191,25 +181,28 @@ export function EditStep0({
191181
const durationOptions = getDurationOptions(reservationUnit, t);
192182
const focusSlot = convertFormToFocustimeSlot({
193183
data: watch(),
194-
reservationUnit: resUnit,
184+
reservationUnit,
195185
reservableTimes,
196186
activeApplicationRounds,
187+
blockingReservations,
197188
});
198189
const startingTimeOptions = getPossibleTimesForDay({
199190
reservableTimes,
200191
interval: reservationUnit?.reservationStartInterval,
201192
date: fromUIDate(watch("date") ?? "") ?? new Date(),
202-
reservationUnit: resUnit,
193+
reservationUnit,
203194
activeApplicationRounds,
204195
durationValue,
196+
blockingReservations,
205197
});
206198

207199
const nextAvailableTime = getNextAvailableTime({
208200
start: focusDate,
209201
reservableTimes,
210202
duration: durationValue,
211-
reservationUnit: resUnit,
203+
reservationUnit,
212204
activeApplicationRounds,
205+
blockingReservations,
213206
});
214207

215208
const lang = convertLanguageCode(i18n.language);
@@ -245,13 +238,14 @@ export function EditStep0({
245238
/>
246239
<StyledCalendarWrapper>
247240
<ReservationTimePicker
248-
reservationUnit={resUnit}
241+
reservationUnit={reservationUnit}
249242
reservableTimes={reservableTimes}
250243
activeApplicationRounds={activeApplicationRounds}
251244
reservationForm={reservationForm}
252245
isReservationQuotaReached={false}
253246
startingTimeOptions={startingTimeOptions}
254247
submitReservation={submitReservation}
248+
blockingReservations={blockingReservations}
255249
/>
256250
</StyledCalendarWrapper>
257251
<form

apps/ui/components/reservation/ReservationTimePicker.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Children, useEffect, useMemo, useState } from "react";
22
import classNames from "classnames";
33
import {
4+
BlockingReservationFieldsFragment,
45
ReservationNode,
56
ReservationTypeChoice,
67
ReservationUnitPageQuery,
@@ -105,6 +106,7 @@ type Props = {
105106
reservationUnit: NonNullable<ReservationUnitPageQuery["reservationUnit"]>;
106107
reservableTimes: ReservableMap;
107108
activeApplicationRounds: readonly RoundPeriod[];
109+
blockingReservations: readonly BlockingReservationFieldsFragment[];
108110
reservationForm: UseFormReturn<PendingReservationFormType>;
109111
isReservationQuotaReached: boolean;
110112
submitReservation: (d: PendingReservationFormType) => void;
@@ -147,18 +149,18 @@ function useSlotPropGetter({
147149
function useCalendarEventChange({
148150
reservationUnit,
149151
focusSlot,
152+
blockingReservations,
150153
}: Pick<Props, "reservationUnit"> & {
151154
focusSlot: ReturnType<typeof convertFormToFocustimeSlot>;
155+
blockingReservations: readonly BlockingReservationFieldsFragment[];
152156
}): Array<CalendarEventBuffer | CalendarEvent<ReservationNode>> {
153157
const { t } = useTranslation();
154158
// TODO this doesn't optimize anything
155159
// any change in the event will cause a full recalculation
156160
const calendarEvents: Array<
157161
CalendarEventBuffer | CalendarEvent<ReservationNode>
158162
> = useMemo(() => {
159-
const existingReservations = filterNonNullable(
160-
reservationUnit.reservations
161-
);
163+
const existingReservations = blockingReservations;
162164

163165
const shouldDisplayFocusSlot = focusSlot.isReservable;
164166

@@ -214,7 +216,7 @@ function useCalendarEventChange({
214216
...(pendingReservation != null ? [pendingReservation] : []),
215217
]),
216218
];
217-
}, [reservationUnit, t, focusSlot]);
219+
}, [reservationUnit, t, focusSlot, blockingReservations]);
218220

219221
return calendarEvents;
220222
}
@@ -228,6 +230,7 @@ export function ReservationTimePicker({
228230
loginAndSubmitButton,
229231
submitReservation,
230232
startingTimeOptions,
233+
blockingReservations,
231234
}: Props) {
232235
const { t, i18n } = useTranslation();
233236
const [calendarViewType, setCalendarViewType] = useState<WeekOptions>("week");
@@ -248,11 +251,13 @@ export function ReservationTimePicker({
248251
reservationUnit,
249252
activeApplicationRounds,
250253
reservableTimes,
254+
blockingReservations,
251255
});
252256

253257
const calendarEvents = useCalendarEventChange({
254258
reservationUnit,
255259
focusSlot,
260+
blockingReservations,
256261
});
257262
const slotPropGetter = useSlotPropGetter({
258263
reservableTimes,
@@ -294,6 +299,7 @@ export function ReservationTimePicker({
294299
reservationUnit,
295300
reservableTimes,
296301
activeApplicationRounds,
302+
blockingReservations,
297303
});
298304

299305
if (!isReservable) {
@@ -351,6 +357,7 @@ export function ReservationTimePicker({
351357
reservationUnit,
352358
reservableTimes,
353359
activeApplicationRounds,
360+
blockingReservations,
354361
});
355362
if (!isReservable) {
356363
return false;

apps/ui/gql/gql-types.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6515,19 +6515,6 @@ export type IsReservableFieldsFragment = {
65156515
reservationsMinDaysBefore?: number | null;
65166516
reservationBegins?: string | null;
65176517
reservationEnds?: string | null;
6518-
reservations?: Array<{
6519-
pk?: number | null;
6520-
id: string;
6521-
state?: ReservationStateChoice | null;
6522-
isBlocked?: boolean | null;
6523-
begin: string;
6524-
end: string;
6525-
numPersons?: number | null;
6526-
calendarUrl?: string | null;
6527-
bufferTimeBefore: number;
6528-
bufferTimeAfter: number;
6529-
affectedReservationUnits?: Array<number | null> | null;
6530-
}> | null;
65316518
reservableTimeSpans?: Array<{
65326519
startDatetime?: string | null;
65336520
endDatetime?: string | null;
@@ -6626,19 +6613,6 @@ export type ReservationUnitPageQuery = {
66266613
nameSv?: string | null;
66276614
};
66286615
}>;
6629-
reservations?: Array<{
6630-
pk?: number | null;
6631-
id: string;
6632-
state?: ReservationStateChoice | null;
6633-
isBlocked?: boolean | null;
6634-
begin: string;
6635-
end: string;
6636-
numPersons?: number | null;
6637-
calendarUrl?: string | null;
6638-
bufferTimeBefore: number;
6639-
bufferTimeAfter: number;
6640-
affectedReservationUnits?: Array<number | null> | null;
6641-
}> | null;
66426616
reservableTimeSpans?: Array<{
66436617
startDatetime?: string | null;
66446618
endDatetime?: string | null;
@@ -8001,9 +7975,6 @@ export const BlockingReservationFieldsFragmentDoc = gql`
80017975
`;
80027976
export const IsReservableFieldsFragmentDoc = gql`
80037977
fragment IsReservableFields on ReservationUnitNode {
8004-
reservations(state: $state) {
8005-
...BlockingReservationFields
8006-
}
80077978
bufferTimeBefore
80087979
bufferTimeAfter
80097980
reservableTimeSpans(startDate: $beginDate, endDate: $endDate) {
@@ -8018,7 +7989,6 @@ export const IsReservableFieldsFragmentDoc = gql`
80187989
reservationBegins
80197990
reservationEnds
80207991
}
8021-
${BlockingReservationFieldsFragmentDoc}
80227992
`;
80237993
export const ReservationUnitNameFieldsFragmentDoc = gql`
80247994
fragment ReservationUnitNameFields on ReservationUnitNode {

apps/ui/modules/__tests__/reservable.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
isStartTimeValid,
1515
} from "../reservable";
1616
import {
17+
BlockingReservationFieldsFragment,
1718
type IsReservableFieldsFragment,
1819
ReservationStartInterval,
1920
ReservationStateChoice,
@@ -322,7 +323,7 @@ describe("isRangeReservable", () => {
322323
bufferTimeBefore?: number;
323324
bufferTimeAfter?: number;
324325
reservableTimes?: ReservableMap;
325-
reservations?: IsReservableFieldsFragment["reservations"];
326+
reservations?: BlockingReservationFieldsFragment[];
326327
interval?: ReservationStartInterval;
327328
maxReservationDuration?: IsReservableFieldsFragment["maxReservationDuration"];
328329
minReservationDuration?: IsReservableFieldsFragment["minReservationDuration"];
@@ -338,6 +339,7 @@ describe("isRangeReservable", () => {
338339
reservationUnit: createMockReservationUnit(rest),
339340
activeApplicationRounds: activeApplicationRounds ?? [],
340341
reservableTimes: reservableTimes ?? mockReservableTimes(),
342+
blockingReservations: rest.reservations ?? [],
341343
};
342344
}
343345

apps/ui/modules/__tests__/reservation.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ describe("canReservationBeChanged", () => {
601601
},
602602
reservationUnit: baseUnit,
603603
activeApplicationRounds: [],
604+
blockingReservations: [],
604605
};
605606
}
606607

apps/ui/modules/__tests__/reservationUnit.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ describe("getPossibleTimesForDay", () => {
9999
activeApplicationRounds: [] as const,
100100
reservableTimes: reservableTimes ?? mockReservableTimes(),
101101
durationValue: duration ?? 30,
102+
blockingReservations: [] as const,
102103
};
103104
}
104105

apps/ui/modules/queries/reservationUnit.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ export const RESERVATION_UNIT_PARAMS_PAGE_QUERY = gql`
120120
const IS_RESERVABLE_FRAGMENT = gql`
121121
${BLOCKING_RESERVATION_FRAGMENT}
122122
fragment IsReservableFields on ReservationUnitNode {
123-
reservations(state: $state) {
124-
...BlockingReservationFields
125-
}
126123
bufferTimeBefore
127124
bufferTimeAfter
128125
reservableTimeSpans(startDate: $beginDate, endDate: $endDate) {

0 commit comments

Comments
 (0)