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

Commit ea90480

Browse files
authored
Merge pull request #480 from City-of-Helsinki/TILA-2046
Tila 2046 - ReservationUnits calendar event title
2 parents 609e57c + 93aa06a commit ea90480

9 files changed

Lines changed: 112 additions & 143 deletions

File tree

admin-ui/src/common/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,6 @@ export const combineResults = (
390390

391391
return combined;
392392
};
393+
394+
export const sortByName = (a?: string, b?: string): number =>
395+
a && b ? a.toLowerCase().localeCompare(b.toLowerCase()) : !a ? 1 : -1;

admin-ui/src/component/ReservationUnits/ReservationUnitEditor/SortedSelect.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from "react";
22
import { useTranslation } from "react-i18next";
33
import memoize from "lodash/memoize";
44
import { Select, SelectProps } from "hds-react";
5+
import { sortByName } from "../../../common/util";
56

67
function SortedSelect<T>(
78
props: Partial<SelectProps<T>> & { sort?: boolean; label: string }
@@ -11,9 +12,7 @@ function SortedSelect<T>(
1112
const sortedOpts = memoize((originalOptions) => {
1213
const opts = [...originalOptions];
1314
if (props.sort) {
14-
opts.sort((a, b) =>
15-
a.label.toLowerCase().localeCompare(b.label.toLowerCase())
16-
);
15+
opts.sort((a, b) => sortByName(a.label, b.label));
1716
}
1817
return opts;
1918
})(props.options);

admin-ui/src/component/my-units/ReservationUnitCalendar.tsx

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import React, { useEffect, useState } from "react";
2+
import { toApiDate } from "common/src/common/util";
23
import CommonCalendar, { CalendarEvent } from "common/src/calendar/Calendar";
34
import { useQuery } from "@apollo/client";
45
import { get } from "lodash";
5-
import { endOfISOWeek, startOfISOWeek } from "date-fns";
6+
import { addDays, endOfISOWeek, startOfISOWeek } from "date-fns";
67
import styled from "styled-components";
78
import { useTranslation } from "react-i18next";
89
import {
910
Query,
10-
QueryReservationsArgs,
1111
ReservationType,
12+
ReservationUnitByPkTypeReservationsArgs,
13+
QueryReservationUnitByPkArgs,
1214
} from "common/types/gql-types";
1315
import { reservationUrl } from "../../common/urls";
1416
import { combineResults } from "../../common/util";
@@ -17,10 +19,11 @@ import Legend from "../reservations/requested/Legend";
1719
import { RESERVATIONS_BY_RESERVATIONUNITS } from "./queries";
1820
import eventStyleGetter, { legend } from "./eventStyleGetter";
1921
import { publicUrl } from "../../common/const";
22+
import { getReserveeName } from "../reservations/requested/util";
23+
import Loader from "../Loader";
2024

2125
type Props = {
2226
begin: string;
23-
intersectingReservationUnits: number[];
2427
reservationUnitPk: number;
2528
};
2629

@@ -48,55 +51,79 @@ const updateQuery = (
4851
return combineResults(previousResult, fetchMoreResult, "reservations");
4952
};
5053

54+
const getEventTitle = ({
55+
reservationUnitPk,
56+
reservation,
57+
}: {
58+
reservationUnitPk: number;
59+
reservation: ReservationType;
60+
}) => {
61+
const reservationUnit = reservation.reservationUnits?.[0];
62+
const isOtherReservationUnit = reservationUnitPk !== reservationUnit?.pk;
63+
64+
if (isOtherReservationUnit) {
65+
const reserveeName = getReserveeName(reservation);
66+
const reservationUnitName = reservationUnit?.nameFi ?? "";
67+
68+
return [reserveeName, reservationUnitName];
69+
}
70+
71+
return null;
72+
};
73+
5174
const ReservationUnitCalendar = ({
5275
begin,
5376
reservationUnitPk,
54-
intersectingReservationUnits,
5577
}: Props): JSX.Element => {
5678
const [events, setEvents] = useState([] as CalendarEvent<ReservationType>[]);
5779
const [hasMore, setHasMore] = useState(false);
5880
const { notifyError } = useNotification();
5981

6082
const { t } = useTranslation();
6183

62-
const { fetchMore } = useQuery<Query, QueryReservationsArgs>(
63-
RESERVATIONS_BY_RESERVATIONUNITS,
64-
65-
{
66-
fetchPolicy: "network-only",
67-
variables: {
68-
offset: 0,
69-
first: 100,
70-
reservationUnit: intersectingReservationUnits.map(String),
71-
begin: startOfISOWeek(new Date(begin)),
72-
end: endOfISOWeek(new Date(begin)),
73-
},
74-
onCompleted: ({ reservations }) => {
75-
if (reservations) {
76-
setEvents(
77-
(reservations?.edges || []).map((r) => ({
78-
title: `${
79-
r?.node?.reserveeOrganisationName ||
80-
`${r?.node?.reserveeFirstName || ""} ${
81-
r?.node?.reserveeLastName || ""
84+
const { fetchMore, loading } = useQuery<
85+
Query,
86+
QueryReservationUnitByPkArgs & ReservationUnitByPkTypeReservationsArgs
87+
>(RESERVATIONS_BY_RESERVATIONUNITS, {
88+
fetchPolicy: "network-only",
89+
variables: {
90+
pk: reservationUnitPk,
91+
from: toApiDate(startOfISOWeek(new Date(begin))),
92+
to: toApiDate(addDays(endOfISOWeek(new Date(begin)), 1)),
93+
},
94+
onCompleted: ({ reservationUnitByPk }) => {
95+
const reservations =
96+
reservationUnitByPk?.reservations?.filter(
97+
(item): item is ReservationType => !!item
98+
) || [];
99+
100+
if (reservations) {
101+
setEvents(
102+
reservations.map((reservation) => {
103+
const titleParts = getEventTitle({
104+
reservationUnitPk,
105+
reservation,
106+
});
107+
const title = titleParts
108+
? `${titleParts[0]} / ${t("common.reservationUnit")} ${
109+
titleParts[1]
82110
}`
83-
}`,
84-
event: r?.node as ReservationType,
85-
start: new Date(get(r?.node, "begin")),
86-
end: new Date(get(r?.node, "end")),
87-
}))
88-
);
111+
: "";
89112

90-
if (reservations.pageInfo.hasNextPage) {
91-
setHasMore(true);
92-
}
93-
}
94-
},
95-
onError: () => {
96-
notifyError(t("errors.errorFetchingData"));
97-
},
98-
}
99-
);
113+
return {
114+
title,
115+
event: reservation as ReservationType,
116+
start: new Date(get(reservation, "begin")),
117+
end: new Date(get(reservation, "end")),
118+
};
119+
})
120+
);
121+
}
122+
},
123+
onError: () => {
124+
notifyError(t("errors.errorFetchingData"));
125+
},
126+
});
100127
useEffect(() => {
101128
if (hasMore) {
102129
setHasMore(false);
@@ -110,6 +137,8 @@ const ReservationUnitCalendar = ({
110137
// eslint-disable-next-line react-hooks/exhaustive-deps
111138
}, [hasMore, setHasMore]);
112139

140+
if (loading) return <Loader />;
141+
113142
return (
114143
<Container>
115144
<CommonCalendar

admin-ui/src/component/my-units/ReservationUnitCalendarView.tsx

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1-
import { useQuery } from "@apollo/client";
21
import React, { useState } from "react";
32
import { useParams } from "react-router-dom";
4-
import { addDays, subDays } from "date-fns";
5-
import { intersection } from "lodash";
6-
import {
7-
Query,
8-
QueryUnitsArgs,
9-
ReservationUnitType,
10-
} from "common/types/gql-types";
11-
import { useNotification } from "../../context/NotificationContext";
12-
import Loader from "../Loader";
13-
import { UNIT_QUERY } from "./queries";
3+
import { addDays, formatISO, startOfDay, subDays } from "date-fns";
4+
145
import SingleReservationUnitFilter from "../filters/SingleReservationUnitFilter";
156
import { Grid, HorisontalFlex, Span6 } from "../../styles/layout";
167
import ReservationUnitCalendar from "./ReservationUnitCalendar";
@@ -21,54 +12,15 @@ type Params = {
2112
reservationUnitId: string;
2213
};
2314

24-
const intersectingReservationUnits = (
25-
allReservationUnits: ReservationUnitType[],
26-
currentReservationUnit: number
27-
): number[] => {
28-
const spacePks = allReservationUnits
29-
.filter((ru) => ru.pk === currentReservationUnit)
30-
.flatMap((ru) => ru.spaces?.map((space) => space?.pk));
31-
32-
return allReservationUnits
33-
.filter(
34-
(ru) =>
35-
intersection(
36-
ru.spaces?.map((space) => space?.pk),
37-
spacePks
38-
).length > 0
39-
)
40-
.map((ru) => ru.pk as number);
41-
};
42-
4315
const ReservationUnitCalendarView = (): JSX.Element => {
44-
const today = new Date(new Date().setHours(0, 0, 0, 0));
16+
const today = formatISO(startOfDay(new Date()));
4517

46-
const { notifyError } = useNotification();
47-
const [begin, setBegin] = useState(today.toISOString());
18+
const [begin, setBegin] = useState(today);
4819
const [reservationUnitId, setReservationUnitId] = useState(-1);
4920
const { unitId } = useParams<Params>();
5021

5122
const hasReservationUnitId = reservationUnitId > 0;
5223

53-
const { loading: unitLoading, data: unitData } = useQuery<
54-
Query,
55-
QueryUnitsArgs
56-
>(UNIT_QUERY, {
57-
variables: {
58-
pk: [unitId],
59-
offset: 0,
60-
},
61-
onError: (err) => {
62-
notifyError(err.message);
63-
},
64-
});
65-
66-
if (unitLoading) {
67-
return <Loader />;
68-
}
69-
70-
const unit = unitData?.units?.edges[0];
71-
7224
return (
7325
<>
7426
<Grid>
@@ -99,10 +51,6 @@ const ReservationUnitCalendarView = (): JSX.Element => {
9951
key={begin + reservationUnitId}
10052
begin={begin}
10153
reservationUnitPk={reservationUnitId}
102-
intersectingReservationUnits={intersectingReservationUnits(
103-
unit?.node?.reservationUnits as ReservationUnitType[],
104-
reservationUnitId
105-
)}
10654
/>
10755
</>
10856
)}

admin-ui/src/component/my-units/UnitCalendar.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import resourceEventStyleGetter, {
1919
PRE_PAUSE,
2020
} from "./resourceEventStyleGetter";
2121
import { getReserveeName } from "../reservations/requested/util";
22+
import { sortByName } from "../../common/util";
2223

2324
export type Resource = {
2425
title: string;
@@ -294,10 +295,12 @@ const Events = ({
294295
);
295296

296297
const sortByDraftStatusAndTitle = (resources: Resource[]) => {
297-
return resources.sort(
298-
(a, b) =>
299-
Number(a.isDraft) - Number(b.isDraft) || a.title.localeCompare(b.title)
300-
);
298+
return resources.sort((a, b) => {
299+
const draftComparison: number = Number(a.isDraft) - Number(b.isDraft);
300+
const titleComparison = sortByName(a.title, b.title);
301+
302+
return draftComparison || titleComparison;
303+
});
301304
};
302305

303306
const ResourceCalendar = ({ resources }: Props): JSX.Element => {

admin-ui/src/component/my-units/UnitReservations.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useQuery } from "@apollo/client";
22
import { CalendarEvent } from "common/src/calendar/Calendar";
33
import { breakpoints } from "common/src/common/style";
4+
import { toApiDate } from "common/src/common/util";
45
import {
56
Query,
67
QueryReservationUnitsArgs,
@@ -116,8 +117,8 @@ const UnitReservations = ({
116117
offset: 0,
117118
first: 100,
118119
unit: [unitPk],
119-
from: currentDate.toISOString().substring(0, 10),
120-
to: addDays(currentDate, 1).toISOString().substring(0, 10),
120+
from: toApiDate(currentDate),
121+
to: toApiDate(addDays(currentDate, 1)),
121122
includeWithSameComponents: true,
122123
},
123124
onCompleted: ({ reservationUnits }) => {

admin-ui/src/component/my-units/UnitReservationsView.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addDays, subDays } from "date-fns";
1+
import { addDays, formatISO, startOfDay, subDays } from "date-fns";
22
import React, { useReducer, useState } from "react";
33
import { useTranslation } from "react-i18next";
44
import { useParams } from "react-router-dom";
@@ -15,13 +15,11 @@ type Params = {
1515
};
1616

1717
const UnitReservationsView = (): JSX.Element => {
18-
const today = new Date(new Date().setHours(0, 0, 0, 0));
18+
const today = formatISO(startOfDay(new Date()));
1919

20-
const [begin, setBegin] = useState(today.toISOString());
20+
const [begin, setBegin] = useState(today);
2121
const { unitId } = useParams<Params>();
22-
2322
const { t } = useTranslation();
24-
2523
const initialEmptyState = { reservationUnitType: [] };
2624

2725
const [state, dispatch] = useReducer(

admin-ui/src/component/my-units/queries.ts

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,41 +28,28 @@ export const UNIT_QUERY = gql`
2828
`;
2929

3030
export const RESERVATIONS_BY_RESERVATIONUNITS = gql`
31-
query reservationsByReservationUnit(
32-
$reservationUnit: [ID]
33-
$offset: Int
34-
$first: Int
35-
$begin: DateTime
36-
$end: DateTime
37-
) {
38-
reservations(
39-
begin: $begin
40-
end: $end
41-
first: $first
42-
offset: $offset
43-
reservationUnit: $reservationUnit
44-
state: ["CONFIRMED", "REQUIRES_HANDLING"]
45-
) {
46-
edges {
47-
node {
48-
user {
49-
email
50-
}
51-
name
52-
reserveeFirstName
53-
reserveeLastName
54-
reserveeOrganisationName
55-
reservationUnits {
56-
pk
57-
}
31+
query ReservationUnit($pk: Int, $from: Date, $to: Date) {
32+
reservationUnitByPk(pk: $pk) {
33+
pk
34+
reservations(from: $from, to: $to, includeWithSameComponents: true) {
35+
id
36+
user {
37+
firstName
38+
lastName
39+
email
40+
}
41+
name
42+
reserveeFirstName
43+
reserveeLastName
44+
reserveeOrganisationName
45+
reservationUnits {
5846
pk
59-
begin
60-
end
61-
state
47+
nameFi
6248
}
63-
}
64-
pageInfo {
65-
hasNextPage
49+
pk
50+
begin
51+
end
52+
state
6653
}
6754
}
6855
}

0 commit comments

Comments
 (0)