Skip to content

Commit

Permalink
Merge pull request #480 from City-of-Helsinki/TILA-2046
Browse files Browse the repository at this point in the history
Tila 2046 - ReservationUnits calendar event title
  • Loading branch information
wuahi authored Dec 14, 2022
2 parents 609e57c + 93aa06a commit ea90480
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 143 deletions.
3 changes: 3 additions & 0 deletions admin-ui/src/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,6 @@ export const combineResults = (

return combined;
};

export const sortByName = (a?: string, b?: string): number =>
a && b ? a.toLowerCase().localeCompare(b.toLowerCase()) : !a ? 1 : -1;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { useTranslation } from "react-i18next";
import memoize from "lodash/memoize";
import { Select, SelectProps } from "hds-react";
import { sortByName } from "../../../common/util";

function SortedSelect<T>(
props: Partial<SelectProps<T>> & { sort?: boolean; label: string }
Expand All @@ -11,9 +12,7 @@ function SortedSelect<T>(
const sortedOpts = memoize((originalOptions) => {
const opts = [...originalOptions];
if (props.sort) {
opts.sort((a, b) =>
a.label.toLowerCase().localeCompare(b.label.toLowerCase())
);
opts.sort((a, b) => sortByName(a.label, b.label));
}
return opts;
})(props.options);
Expand Down
109 changes: 69 additions & 40 deletions admin-ui/src/component/my-units/ReservationUnitCalendar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useEffect, useState } from "react";
import { toApiDate } from "common/src/common/util";
import CommonCalendar, { CalendarEvent } from "common/src/calendar/Calendar";
import { useQuery } from "@apollo/client";
import { get } from "lodash";
import { endOfISOWeek, startOfISOWeek } from "date-fns";
import { addDays, endOfISOWeek, startOfISOWeek } from "date-fns";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
import {
Query,
QueryReservationsArgs,
ReservationType,
ReservationUnitByPkTypeReservationsArgs,
QueryReservationUnitByPkArgs,
} from "common/types/gql-types";
import { reservationUrl } from "../../common/urls";
import { combineResults } from "../../common/util";
Expand All @@ -17,10 +19,11 @@ import Legend from "../reservations/requested/Legend";
import { RESERVATIONS_BY_RESERVATIONUNITS } from "./queries";
import eventStyleGetter, { legend } from "./eventStyleGetter";
import { publicUrl } from "../../common/const";
import { getReserveeName } from "../reservations/requested/util";
import Loader from "../Loader";

type Props = {
begin: string;
intersectingReservationUnits: number[];
reservationUnitPk: number;
};

Expand Down Expand Up @@ -48,55 +51,79 @@ const updateQuery = (
return combineResults(previousResult, fetchMoreResult, "reservations");
};

const getEventTitle = ({
reservationUnitPk,
reservation,
}: {
reservationUnitPk: number;
reservation: ReservationType;
}) => {
const reservationUnit = reservation.reservationUnits?.[0];
const isOtherReservationUnit = reservationUnitPk !== reservationUnit?.pk;

if (isOtherReservationUnit) {
const reserveeName = getReserveeName(reservation);
const reservationUnitName = reservationUnit?.nameFi ?? "";

return [reserveeName, reservationUnitName];
}

return null;
};

const ReservationUnitCalendar = ({
begin,
reservationUnitPk,
intersectingReservationUnits,
}: Props): JSX.Element => {
const [events, setEvents] = useState([] as CalendarEvent<ReservationType>[]);
const [hasMore, setHasMore] = useState(false);
const { notifyError } = useNotification();

const { t } = useTranslation();

const { fetchMore } = useQuery<Query, QueryReservationsArgs>(
RESERVATIONS_BY_RESERVATIONUNITS,

{
fetchPolicy: "network-only",
variables: {
offset: 0,
first: 100,
reservationUnit: intersectingReservationUnits.map(String),
begin: startOfISOWeek(new Date(begin)),
end: endOfISOWeek(new Date(begin)),
},
onCompleted: ({ reservations }) => {
if (reservations) {
setEvents(
(reservations?.edges || []).map((r) => ({
title: `${
r?.node?.reserveeOrganisationName ||
`${r?.node?.reserveeFirstName || ""} ${
r?.node?.reserveeLastName || ""
const { fetchMore, loading } = useQuery<
Query,
QueryReservationUnitByPkArgs & ReservationUnitByPkTypeReservationsArgs
>(RESERVATIONS_BY_RESERVATIONUNITS, {
fetchPolicy: "network-only",
variables: {
pk: reservationUnitPk,
from: toApiDate(startOfISOWeek(new Date(begin))),
to: toApiDate(addDays(endOfISOWeek(new Date(begin)), 1)),
},
onCompleted: ({ reservationUnitByPk }) => {
const reservations =
reservationUnitByPk?.reservations?.filter(
(item): item is ReservationType => !!item
) || [];

if (reservations) {
setEvents(
reservations.map((reservation) => {
const titleParts = getEventTitle({
reservationUnitPk,
reservation,
});
const title = titleParts
? `${titleParts[0]} / ${t("common.reservationUnit")} ${
titleParts[1]
}`
}`,
event: r?.node as ReservationType,
start: new Date(get(r?.node, "begin")),
end: new Date(get(r?.node, "end")),
}))
);
: "";

if (reservations.pageInfo.hasNextPage) {
setHasMore(true);
}
}
},
onError: () => {
notifyError(t("errors.errorFetchingData"));
},
}
);
return {
title,
event: reservation as ReservationType,
start: new Date(get(reservation, "begin")),
end: new Date(get(reservation, "end")),
};
})
);
}
},
onError: () => {
notifyError(t("errors.errorFetchingData"));
},
});
useEffect(() => {
if (hasMore) {
setHasMore(false);
Expand All @@ -110,6 +137,8 @@ const ReservationUnitCalendar = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasMore, setHasMore]);

if (loading) return <Loader />;

return (
<Container>
<CommonCalendar
Expand Down
60 changes: 4 additions & 56 deletions admin-ui/src/component/my-units/ReservationUnitCalendarView.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import { useQuery } from "@apollo/client";
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { addDays, subDays } from "date-fns";
import { intersection } from "lodash";
import {
Query,
QueryUnitsArgs,
ReservationUnitType,
} from "common/types/gql-types";
import { useNotification } from "../../context/NotificationContext";
import Loader from "../Loader";
import { UNIT_QUERY } from "./queries";
import { addDays, formatISO, startOfDay, subDays } from "date-fns";

import SingleReservationUnitFilter from "../filters/SingleReservationUnitFilter";
import { Grid, HorisontalFlex, Span6 } from "../../styles/layout";
import ReservationUnitCalendar from "./ReservationUnitCalendar";
Expand All @@ -21,54 +12,15 @@ type Params = {
reservationUnitId: string;
};

const intersectingReservationUnits = (
allReservationUnits: ReservationUnitType[],
currentReservationUnit: number
): number[] => {
const spacePks = allReservationUnits
.filter((ru) => ru.pk === currentReservationUnit)
.flatMap((ru) => ru.spaces?.map((space) => space?.pk));

return allReservationUnits
.filter(
(ru) =>
intersection(
ru.spaces?.map((space) => space?.pk),
spacePks
).length > 0
)
.map((ru) => ru.pk as number);
};

const ReservationUnitCalendarView = (): JSX.Element => {
const today = new Date(new Date().setHours(0, 0, 0, 0));
const today = formatISO(startOfDay(new Date()));

const { notifyError } = useNotification();
const [begin, setBegin] = useState(today.toISOString());
const [begin, setBegin] = useState(today);
const [reservationUnitId, setReservationUnitId] = useState(-1);
const { unitId } = useParams<Params>();

const hasReservationUnitId = reservationUnitId > 0;

const { loading: unitLoading, data: unitData } = useQuery<
Query,
QueryUnitsArgs
>(UNIT_QUERY, {
variables: {
pk: [unitId],
offset: 0,
},
onError: (err) => {
notifyError(err.message);
},
});

if (unitLoading) {
return <Loader />;
}

const unit = unitData?.units?.edges[0];

return (
<>
<Grid>
Expand Down Expand Up @@ -99,10 +51,6 @@ const ReservationUnitCalendarView = (): JSX.Element => {
key={begin + reservationUnitId}
begin={begin}
reservationUnitPk={reservationUnitId}
intersectingReservationUnits={intersectingReservationUnits(
unit?.node?.reservationUnits as ReservationUnitType[],
reservationUnitId
)}
/>
</>
)}
Expand Down
11 changes: 7 additions & 4 deletions admin-ui/src/component/my-units/UnitCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import resourceEventStyleGetter, {
PRE_PAUSE,
} from "./resourceEventStyleGetter";
import { getReserveeName } from "../reservations/requested/util";
import { sortByName } from "../../common/util";

export type Resource = {
title: string;
Expand Down Expand Up @@ -294,10 +295,12 @@ const Events = ({
);

const sortByDraftStatusAndTitle = (resources: Resource[]) => {
return resources.sort(
(a, b) =>
Number(a.isDraft) - Number(b.isDraft) || a.title.localeCompare(b.title)
);
return resources.sort((a, b) => {
const draftComparison: number = Number(a.isDraft) - Number(b.isDraft);
const titleComparison = sortByName(a.title, b.title);

return draftComparison || titleComparison;
});
};

const ResourceCalendar = ({ resources }: Props): JSX.Element => {
Expand Down
5 changes: 3 additions & 2 deletions admin-ui/src/component/my-units/UnitReservations.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from "@apollo/client";
import { CalendarEvent } from "common/src/calendar/Calendar";
import { breakpoints } from "common/src/common/style";
import { toApiDate } from "common/src/common/util";
import {
Query,
QueryReservationUnitsArgs,
Expand Down Expand Up @@ -116,8 +117,8 @@ const UnitReservations = ({
offset: 0,
first: 100,
unit: [unitPk],
from: currentDate.toISOString().substring(0, 10),
to: addDays(currentDate, 1).toISOString().substring(0, 10),
from: toApiDate(currentDate),
to: toApiDate(addDays(currentDate, 1)),
includeWithSameComponents: true,
},
onCompleted: ({ reservationUnits }) => {
Expand Down
8 changes: 3 additions & 5 deletions admin-ui/src/component/my-units/UnitReservationsView.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addDays, subDays } from "date-fns";
import { addDays, formatISO, startOfDay, subDays } from "date-fns";
import React, { useReducer, useState } from "react";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
Expand All @@ -15,13 +15,11 @@ type Params = {
};

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

const [begin, setBegin] = useState(today.toISOString());
const [begin, setBegin] = useState(today);
const { unitId } = useParams<Params>();

const { t } = useTranslation();

const initialEmptyState = { reservationUnitType: [] };

const [state, dispatch] = useReducer(
Expand Down
53 changes: 20 additions & 33 deletions admin-ui/src/component/my-units/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,28 @@ export const UNIT_QUERY = gql`
`;

export const RESERVATIONS_BY_RESERVATIONUNITS = gql`
query reservationsByReservationUnit(
$reservationUnit: [ID]
$offset: Int
$first: Int
$begin: DateTime
$end: DateTime
) {
reservations(
begin: $begin
end: $end
first: $first
offset: $offset
reservationUnit: $reservationUnit
state: ["CONFIRMED", "REQUIRES_HANDLING"]
) {
edges {
node {
user {
email
}
name
reserveeFirstName
reserveeLastName
reserveeOrganisationName
reservationUnits {
pk
}
query ReservationUnit($pk: Int, $from: Date, $to: Date) {
reservationUnitByPk(pk: $pk) {
pk
reservations(from: $from, to: $to, includeWithSameComponents: true) {
id
user {
firstName
lastName
email
}
name
reserveeFirstName
reserveeLastName
reserveeOrganisationName
reservationUnits {
pk
begin
end
state
nameFi
}
}
pageInfo {
hasNextPage
pk
begin
end
state
}
}
}
Expand Down
Loading

0 comments on commit ea90480

Please sign in to comment.