Skip to content

Commit

Permalink
slots UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Dobkowski committed Oct 2, 2023
1 parent c8fbf19 commit 99e7ee2
Show file tree
Hide file tree
Showing 19 changed files with 129 additions and 78 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions src/components/ContextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export const ContextButton = styled.button<{ colorType: "primary" | "danger" }>`
${({ theme, colorType, disabled }) => {
const color = colorType === "danger" ? theme.colors.error : theme.colors.primary;
const borderColor =
colorType === "danger" ? theme.colors.error : theme.colorSchemas.timeSlotButton.available.border;
const borderColor = colorType === "danger" ? theme.colors.error : theme.colorSchemas.input.border;
const borderColorHover = colorType === "danger" ? theme.colors.error : theme.colors.darkGrey;
return css`
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/AppLayoutWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const Wrapper = styled.div`
display: grid;
grid-template-columns:
1fr
min(900px, calc(100% - 40px))
min(980px, calc(100% - 40px))
1fr;
& > * {
Expand Down
26 changes: 15 additions & 11 deletions src/features/service/components/Service/BookService/BookService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Column } from "components/layout/Column";
import { useBookDateRange } from "features/service/hooks/useBookDateRange";
import { useBookSlot } from "features/service/hooks/useBookSlot";
import { Form, Formik } from "formik";
import { getServiceConfigByType } from "helpers/functions";
import { useLocale } from "helpers/hooks/useLocale";
import { convertSourceDateTimeToTargetDateTime } from "helpers/timeFormat";
import _ from "lodash";
Expand All @@ -18,9 +19,9 @@ import { useParams } from "react-router-dom";
import { useRecoilState, useRecoilValue } from "recoil";
import { hoursSystemAtom } from "state/atoms";
import { selectedDateRange } from "state/atoms/selectedDateRange";
import { selectedSlot } from "state/atoms/selectedSlot";
import { selectedSlots } from "state/atoms/selectedSlots";
import { serviceAtom } from "state/atoms/service";
import { slotsAtom } from "state/atoms/slots";
import { slotsFiltersAtom } from "state/atoms/slotsFilters";
import { timeZoneAtom } from "state/atoms/timeZone";
import { uploadAttachmentsAtom } from "state/atoms/uploadAttachments";
Expand Down Expand Up @@ -83,11 +84,11 @@ const BookService = () => {
const [searchParams] = useSearchParams();
const locale = useLocale();
const { t } = useTranslation(["forms"]);
const selectedSlotValue = useRecoilValue(selectedSlot);
const selectedDateRangeValue = useRecoilValue(selectedDateRange);
const selectedSlotsValue = useRecoilValue(selectedSlots);
const service = useRecoilValue(serviceAtom)!;
const serviceType = service?.viewConfig.displayType;
const serviceConfig = service && getServiceConfigByType({ service });
const { formFields }: { formFields: Array<FormField> } = service ?? {
formFields: [],
};
Expand All @@ -100,20 +101,22 @@ const BookService = () => {
const hoursSystem = useRecoilValue(hoursSystemAtom);
const is12HoursSystem = useMemo(() => hoursSystem === HOURS_SYSTEMS.h12, [hoursSystem]);
const [, setSelectedSlots] = useRecoilState(selectedSlots);
const slots = useRecoilValue(slotsAtom)!;

const isUploading = Object.values(uploadState).filter((item) => item.isLoading).length > 0;

const dateFormat = is12HoursSystem ? "iiii dd MMM, h:mm a" : "iiii dd MMM, H:mm";

const formattedDate =
selectedSlotValue &&
convertSourceDateTimeToTargetDateTime({
date: selectedSlotValue,
targetTimeZone: timeZone,
sourceTimeZone: service.project.localTimeZone,
dateFormat,
locale,
});
const selectedSlot = slots.find((slot) => slot.slotId === selectedSlotsValue[0])!;
const formattedDate = selectedSlotsValue?.length
? convertSourceDateTimeToTargetDateTime({
date: selectedSlot.dateTimeFrom,
targetTimeZone: timeZone,
sourceTimeZone: service.project.localTimeZone,
dateFormat,
locale,
})
: "";

const checkDisableButton = useCallback(() => {
const disabledForSlots = !selectedSlotsValue.length || loading || isUploading;
Expand Down Expand Up @@ -247,6 +250,7 @@ const BookService = () => {
selectedSlotValue: formattedDate,
selectedSlotsValue,
t,
serviceConfig,
})}
</Button>
</Column>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import { Service } from "models/service";
import { TFunction } from "react-i18next";

type GetSubmitButtonText = ({
selectedSlotValue,
selectedSlotsValue,
t,
serviceConfig,
}: {
selectedSlotValue: string;
selectedSlotsValue: string[];
t: TFunction<"forms"[]>;
serviceConfig: Service["viewConfig"]["days" | "list" | "calendar"];
}) => string;

export const getSubmitButtonText: GetSubmitButtonText = ({ selectedSlotValue, selectedSlotsValue, t }) => {
export const getSubmitButtonText: GetSubmitButtonText = ({
selectedSlotValue,
selectedSlotsValue,
t,
serviceConfig,
}) => {
const textBase = t("book-free-button");
const isMultiSelect = serviceConfig.multiSelect;

if (selectedSlotValue === "" && !selectedSlotsValue.length) return textBase;
if (selectedSlotValue === "" && selectedSlotsValue.length) return `${textBase} (${selectedSlotsValue.length})`;
if (selectedSlotValue !== "" && selectedSlotsValue.length) {
if (isMultiSelect) return `${textBase} (${selectedSlotsValue.length})`;
return `${textBase}: ${selectedSlotValue}`;
}

return `${textBase}: ${selectedSlotValue}`;
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Service } from "models/service";
import { getSubmitButtonText } from "../";

describe("getSubmitButtonText", () => {
Expand All @@ -8,21 +9,28 @@ describe("getSubmitButtonText", () => {
return "";
};

const serviceConfigMock = {
multiSelect: false,
} as Service["viewConfig"]["days" | "list" | "calendar"];

it("returns base text when no selectedSlotValue and selectedSlotsValue", () => {
const buttonText = getSubmitButtonText({
selectedSlotValue: "",
selectedSlotsValue: [],
t: tMock,
serviceConfig: serviceConfigMock,
});

expect(buttonText).toBe("Book now");
});

it("returns text with selectedSlotsValue length when no selectedSlotValue", () => {
serviceConfigMock.multiSelect = true;
const buttonText = getSubmitButtonText({
selectedSlotValue: "",
selectedSlotValue: "slot1",
selectedSlotsValue: ["slot1", "slot2"],
t: tMock,
serviceConfig: serviceConfigMock,
});

expect(buttonText).toBe("Book now (2)");
Expand All @@ -33,6 +41,7 @@ describe("getSubmitButtonText", () => {
selectedSlotValue: "slot1",
selectedSlotsValue: [],
t: tMock,
serviceConfig: serviceConfigMock,
});

expect(buttonText).toBe("Book now: slot1");
Expand Down
33 changes: 14 additions & 19 deletions src/features/service/components/Service/HoursSystem/HoursSystem.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from "react";
import { Typography } from "components/Typography";
import { Row } from "components/layout/Row";
import { useTranslation } from "react-i18next";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { hoursSystemAtom } from "state/atoms";
import styled, { css } from "styled-components";
import { HOURS_SYSTEMS } from "./enums/HoursSystem.enum";

const Wrapper = styled(Row)`
gap: 4px;
border-radius: 4px;
cursor: pointer;
padding: 3px 6px;
&:hover {
background-color: ${({ theme }) => theme.colors.primaryLight};
text-decoration: underline;
}
`;

const HoursSystemButton = styled(Typography)<{ isBold: boolean }>`
Expand All @@ -17,50 +24,38 @@ const HoursSystemButton = styled(Typography)<{ isBold: boolean }>`
${({ isBold }) => {
return css`
font-weight: ${isBold ? "700" : "normal"};
cursor: ${isBold ? "unset" : "pointer"};
&:hover {
text-decoration: ${isBold ? "none" : "underline"};
}
text-decoration: ${isBold ? "underline" : "none"};
`;
}}
`;

export const HoursSystem = () => {
const { t } = useTranslation();
const hoursSystem = useRecoilValue(hoursSystemAtom);
const setHoursSystem = useSetRecoilState(hoursSystemAtom);

const handleHoursSystemChange = (hoursSystem: string) => {
localStorage.setItem("HOURS_SYSTEM", hoursSystem);
setHoursSystem(hoursSystem);
const handleHoursSystemChange = () => {
const newHoursSystem = hoursSystem === HOURS_SYSTEMS.h12 ? HOURS_SYSTEMS.h24 : HOURS_SYSTEMS.h12;
localStorage.setItem("HOURS_SYSTEM", newHoursSystem);
setHoursSystem(newHoursSystem);
};

return (
<Wrapper>
<Typography className="timezone-info" typographyType="label" color="inherit" as="span">{`${t(
"format",
)}:`}</Typography>
<Wrapper onClick={handleHoursSystemChange}>
<HoursSystemButton
className="timezone-info"
typographyType="label"
color="inherit"
as="span"
isBold={hoursSystem === HOURS_SYSTEMS.h12}
onClick={() => handleHoursSystemChange(HOURS_SYSTEMS.h12)}
>
12h
</HoursSystemButton>
<Typography className="timezone-info" typographyType="label" color="inherit" as="span">
|
</Typography>
<HoursSystemButton
className="timezone-info"
typographyType="label"
color="inherit"
as="span"
isBold={hoursSystem === HOURS_SYSTEMS.h24}
onClick={() => handleHoursSystemChange(HOURS_SYSTEMS.h24)}
>
24h
</HoursSystemButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Typography } from "components/Typography";
import { Box } from "components/layout/Box";
import { useLangParam } from "features/i18n/useLangParam";
import { useRescheduleBooking } from "features/service/hooks/useRescheduleBooking";
import { getPath } from "helpers/functions";
import { getPath, getServiceConfigByType } from "helpers/functions";
import { useLocale } from "helpers/hooks/useLocale";
import { convertSourceDateTimeToTargetDateTime } from "helpers/timeFormat";
import { BOOKING_FORM_TYPES } from "models/service";
Expand Down Expand Up @@ -53,6 +53,7 @@ const RescheduleService = () => {
const selectedDateRangeValue = useRecoilValue(selectedDateRange);
const selectedSlotsValue = useRecoilValue(selectedSlots);
const service = useRecoilValue(serviceAtom)!;
const serviceConfig = service && getServiceConfigByType({ service });
const slot = useRecoilValue(selectedSlotSelector);
const { rescheduleBookingMutation, loading } = useRescheduleBooking();
const timeZone = useRecoilValue(timeZoneAtom);
Expand Down Expand Up @@ -176,6 +177,7 @@ const RescheduleService = () => {
selectedSlotValue: formattedDateTo,
selectedSlotsValue,
t,
serviceConfig,
})}
</Button>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ const PaginationButton = styled(ContextButton)`
height: 36px;
width: 36px;
display: grid;
border: none;
&:hover {
border: none;
background: ${({ theme, disabled }) =>
disabled ? "transparent" : theme.colorSchemas.timeSlotButton.available.background};
}
& > * {
margin: auto;
${({ theme, disabled }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const ServiceCalendarWrapper = () => {
const [serviceCalendarFilters, setServiceCalendarFilters] = useRecoilState(slotsFiltersAtom);
const { t } = useTranslation();
const slotsViewConfig = useRecoilValue(slotsViewConfiguration);

const pageSize = Math.min(slotsViewConfig.maxDaysPerPage, Math.trunc(width / slotsViewConfig.slotsColumnWidth));
const daysToRender = useMemo(
() => days.slice(0, pageSize === 0 ? slotsViewConfig.minDaysPerPage : pageSize),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const TimeSlotButton = styled.button<TimeSlotButtonProps>`
flex-direction: column;
align-items: center;
justify-content: center;
padding: 4px 0;
padding: 6px 0;
${({ theme, state, showDuration, showQuantity }) => {
const colorSchema = theme.colorSchemas.timeSlotButton[state] as any;
Expand All @@ -48,8 +48,8 @@ const TimeSlotButton = styled.button<TimeSlotButtonProps>`
color: ${colorSchema.text};
cursor: ${state === "unavailable" ? "unset" : "pointer"};
border-radius: ${({ theme }) => theme.borderRadius};
background-color: ${colorSchema.background};
min-width: ${showDuration ? "96px" : "unset"};
background-color: ${colorSchema.background} !important;
border: 1px solid ${colorSchema.border};
min-height: ${timeSlotHeight[`${showDuration}-${showQuantity}`] ?? "unset"};
`;
}}
Expand All @@ -58,7 +58,7 @@ const TimeSlotButton = styled.button<TimeSlotButtonProps>`
${({ theme, state }) => {
const colorSchema = theme.colorSchemas.timeSlotButton[state];
return css`
background-color: ${colorSchema.backgroundHover};
background-color: ${colorSchema.backgroundHover} !important;
`;
}}
}
Expand All @@ -74,10 +74,10 @@ interface DummySlotProps {
}

const dummyTimeSlotHeight: Record<string, string> = {
"true-true": "70px",
"false-true": "44px",
"true-true": "67px",
"false-true": "47px",
"true-false": "54px",
"false-false": "26px",
"false-false": "32px",
};

const DummySlotWrapper = styled.div<DummySlotProps>`
Expand Down Expand Up @@ -150,9 +150,9 @@ const getBaseSlotContent = (
};

const QuantityText = styled(Typography)`
font-size: 10px;
line-height: 12px;
margin: 2px 0;
font-size: 9px;
line-height: 11px;
margin: 2px 0 0;
`;
const DurationText = styled(Typography)`
&.unavailable-time-slot {
Expand All @@ -165,7 +165,7 @@ const WrapperWithDuration = styled.div`
flex-direction: column;
em {
line-height: 6px;
line-height: 0px;
}
`;

Expand Down Expand Up @@ -212,7 +212,7 @@ const getDurationQuantitySlotContent = (
{slot.quantity > 0 && (
<>
<QuantityText typographyType="body" weight="500" as="span" align="center" color="inherit">
{t("available")} {slot.quantity > 999 ? "999+" : slot.quantity.toFixed(0)}
{slot.quantity > 999 ? "999+" : slot.quantity.toFixed(0)}
</QuantityText>
</>
)}
Expand Down Expand Up @@ -249,7 +249,7 @@ const getQuantitySlotContent = (
{slot.quantity > 0 && (
<>
<QuantityText typographyType="body" weight="500" as="span" align="center" color="inherit">
{t("available")} {slot.quantity > 999 ? "999+" : slot.quantity.toFixed(0)}
{slot.quantity > 999 ? "999+" : slot.quantity.toFixed(0)}
</QuantityText>
</>
)}
Expand Down
Loading

0 comments on commit 99e7ee2

Please sign in to comment.