Skip to content

Commit

Permalink
refactor: TimeSelector to use ControlledSelect
Browse files Browse the repository at this point in the history
  • Loading branch information
joonatank committed Jan 15, 2025
1 parent 27057fe commit 34af436
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 104 deletions.
20 changes: 13 additions & 7 deletions apps/ui/components/application/Page2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { useTranslation } from "next-i18next";
import { useRouter } from "next/router";
import styled from "styled-components";
import { useFormContext } from "react-hook-form";
import { useForm, useFormContext } from "react-hook-form";
import type { ApplicationEventSchedulePriority } from "common/types/common";
import {
Priority,
Expand All @@ -35,7 +35,7 @@ import {
} from "common/src/conversion";
import { getReadableList } from "@/modules/util";
import { AccordionWithState as Accordion } from "@/components/Accordion";
import { TimeSelector } from "./TimeSelector";
import { TimeSelector, TimeSelectorFormValues } from "./TimeSelector";
import { errorToast, successToast } from "common/src/common/toast";
import { ButtonContainer } from "common/styles/util";

Expand Down Expand Up @@ -251,10 +251,17 @@ const getApplicationEventsWhichMinDurationsIsNotFulfilled = (

function Page2({ application, onNext }: Props): JSX.Element {
const { t, i18n } = useTranslation();
const [reservationUnitPk, setReservationUnitPk] = useState<number>(
const initialReservationUnitPk =
application?.applicationSections?.[0]?.reservationUnitOptions?.[0]
?.reservationUnit?.pk ?? 0
);
?.reservationUnit?.pk ?? 0;

const timeSelectorForm = useForm<TimeSelectorFormValues>({
defaultValues: {
reservationUnitPk: initialReservationUnitPk,
priority: 300,
},
});
const reservationUnitPk = timeSelectorForm.watch("reservationUnitPk");

const [minDurationMsg, setMinDurationMsg] = useState(true);
const router = useRouter();
Expand Down Expand Up @@ -456,8 +463,7 @@ function Page2({ application, onNext }: Props): JSX.Element {
resetCells={() => resetCells(index)}
summaryData={[summaryDataPrimary, summaryDataSecondary]}
reservationUnitOptions={reservationUnitOptions}
reservationUnitPk={reservationUnitPk}
setReservationUnitPk={setReservationUnitPk}
form={timeSelectorForm}
/>
</Accordion>
);
Expand Down
162 changes: 65 additions & 97 deletions apps/ui/components/application/TimeSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { useTranslation } from "next-i18next";
import {
Button,
ButtonVariant,
IconCross,
OptionInProps,
Select,
} from "hds-react";
import { Button, ButtonVariant, IconCross } from "hds-react";
import type { ApplicationEventSchedulePriority } from "common/types/common";
import { fontBold, fontRegular } from "common/src/common/typography";
import { fontRegular } from "common/src/common/typography";
import { breakpoints } from "common/src/common/style";
import {
convertOptionToHDS,
fromMondayFirstUnsafe,
toNumber,
} from "common/src/helpers";
import { fromMondayFirstUnsafe } from "common/src/helpers";
import { WEEKDAYS } from "common/src/const";
import { arrowDown, arrowUp, MediumButton } from "@/styles/util";
import { TimePreview } from "./TimePreview";
import { type ApplicationEventScheduleFormType } from "./Form";
import { UseFormReturn } from "react-hook-form";
import { ControlledSelect } from "common/src/components/form";
import { Flex } from "common/styles/util";

type Cell = {
hour: number;
Expand All @@ -28,6 +21,11 @@ type Cell = {
key: string;
};

export type TimeSelectorFormValues = {
reservationUnitPk: number;
priority: ApplicationEventSchedulePriority;
};

type Props = {
index: number;
cells: Cell[][];
Expand All @@ -39,8 +37,7 @@ type Props = {
ApplicationEventScheduleFormType[],
];
reservationUnitOptions: { label: string; value: number }[];
reservationUnitPk: number;
setReservationUnitPk: (pk: number) => void;
form: UseFormReturn<TimeSelectorFormValues>;
};

const CalendarHead = styled.div`
Expand Down Expand Up @@ -199,27 +196,6 @@ const Day = ({
);
};

const OptionWrapper = styled.div`
margin-top: var(--spacing-m);
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-s);
@media (min-width: ${breakpoints.s}) {
grid-template-columns: repeat(2, 1fr);
}
`;

const StyledSelect = styled(Select)`
label {
${fontBold};
}
[class*="buttonLabel"] {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`;

const CalendarContainer = styled.div`
margin-top: var(--spacing-layout-s);
display: grid;
Expand Down Expand Up @@ -324,9 +300,10 @@ const TimePreviewContainer = styled.div`
margin: var(--spacing-xl) 0;
`;

const ButtonContainer = styled.div`
display: flex;
flex-direction: row;
const ButtonContainer = styled(Flex).attrs({
$direction: "row",
$gap: "none",
})`
margin-top: var(--spacing-layout-l);
margin-bottom: var(--spacing-layout-s);
`;
Expand Down Expand Up @@ -366,12 +343,9 @@ export function TimeSelector({
index,
summaryData,
reservationUnitOptions,
reservationUnitPk,
setReservationUnitPk,
form,
}: Props): JSX.Element | null {
const { t } = useTranslation();
const [priority, setPriority] =
useState<ApplicationEventSchedulePriority>(300);
const [paintState, setPaintState] = useState<
ApplicationEventSchedulePriority | false
>(false); // toggle value true = set, false = clear: ;
Expand All @@ -395,12 +369,9 @@ export function TimeSelector({
label: t("application:Page2.legend.selected-2"),
},
];
const priorityOptions: OptionInProps[] = [300, 200]
.map((n) => ({
label: t(`application:Page2.priorityLabels.${n}`),
value: n,
}))
.map(convertOptionToHDS);

const { watch } = form;
const priority = watch("priority");

if (!cells) {
return null;
Expand All @@ -422,57 +393,14 @@ export function TimeSelector({
);
};

const resUOpts = reservationUnitOptions.map(convertOptionToHDS);
return (
<>
<OptionWrapper>
<StyledSelect
id={`time-selector__select--priority-${index}`}
texts={{
label: t("application:Page2.prioritySelectLabel"),
}}
options={priorityOptions}
value={
priorityOptions.find((n) => toNumber(n.value) === priority)?.value
}
defaultValue={priorityOptions[0].value}
onChange={(val) => {
const e = val.find(() => true);
const value = toNumber(e?.value);
if (value != null) {
setPriority(value);
}
return {
invalid: false,
};
}}
/>
<StyledSelect
id={`time-selector__select--reservation-unit-${index}`}
texts={{
label: t("application:Page2.reservationUnitSelectLabel"),
}}
options={resUOpts}
value={
resUOpts.find((n) => toNumber(n.value) === reservationUnitPk)?.value
}
defaultValue={reservationUnitOptions[0].value}
onChange={(selection) => {
const val = selection.find(() => true);
const pk = toNumber(val?.value);
if (pk != null) {
setReservationUnitPk(pk);
}
return {
invalid: false,
};
}}
/>
</OptionWrapper>
<OptionSelector
reservationUnitOptions={reservationUnitOptions}
form={form}
/>
<CalendarContainer
onMouseLeave={() => {
setPainting(false);
}}
onMouseLeave={() => setPainting(false)}
aria-multiselectable
aria-labelledby={`timeSelector-${index}`}
role="listbox"
Expand Down Expand Up @@ -526,3 +454,43 @@ export function TimeSelector({
</>
);
}

const OptionWrapper = styled.div`
margin-top: var(--spacing-m);
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-s);
@media (min-width: ${breakpoints.s}) {
grid-template-columns: repeat(2, 1fr);
}
`;

function OptionSelector({
reservationUnitOptions,
form,
}: Pick<Props, "reservationUnitOptions" | "form">) {
const { t } = useTranslation();
const { control } = form;

const priorityOptions = [300, 200].map((n) => ({
label: t(`application:Page2.priorityLabels.${n}`),
value: n,
}));

return (
<OptionWrapper>
<ControlledSelect
name="priority"
label={t("application:Page2.prioritySelectLabel")}
control={control}
options={priorityOptions}
/>
<ControlledSelect
name="reservationUnitPk"
label={t("application:Page2.reservationUnitSelectLabel")}
control={control}
options={reservationUnitOptions}
/>
</OptionWrapper>
);
}

0 comments on commit 34af436

Please sign in to comment.