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

Commit f84096b

Browse files
authored
TILA-2689: sticky header styling and less buttons (#684)
* Add: translate common error message * Fix: show only the primary buttons in sticky header * Fix: sticky header styling * Fix: reverse sticky header buttons order
1 parent a5fd9e4 commit f84096b

8 files changed

Lines changed: 157 additions & 98 deletions

File tree

admin-ui/src/component/StickyHeader.tsx

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { ButtonContainer } from "app/styles/layout";
12
import { breakpoints } from "common/src/common/style";
23
import React from "react";
34
import styled from "styled-components";
45

56
const Sticky = styled.div`
6-
z-index: 101;
7+
z-index: var(--tilavaraus-admin-stack-sticky-reservation-header);
78
position: sticky;
89
top: 0px;
910
width: 100%;
@@ -13,39 +14,73 @@ const Sticky = styled.div`
1314

1415
const StickyContent = styled.div`
1516
color: var(--color-white);
16-
background: var(--color-bus);
17-
border-width: 1px 0;
17+
background: var(--color-bus-dark);
18+
border-width: 0px;
1819
border-style: solid;
1920
border-color: var(--color-black-20);
20-
padding: var(--spacing-2-xs) var(--spacing-s) var(--spacing-2-xs) 48px;
21+
padding: 10px;
2122
display: flex;
22-
flex-direction: row;
2323
justify-content: space-between;
2424
gap: var(--spacing-s);
2525
line-height: 1.5;
26-
button,
27-
a {
28-
border-color: var(--color-white) !important;
29-
color: var(--color-white) !important;
26+
&& button,
27+
&& a {
28+
border-color: var(--color-white);
29+
color: var(--color-white);
30+
&:hover,
31+
&:focus-within {
32+
background-color: unset;
33+
color: var(--color-black-10);
34+
border-color: var(--color-black-10);
35+
}
3036
}
31-
@media (max-width: ${breakpoints.s}) {
32-
padding: var(--spacing-xs) var(--spacing-s);
33-
flex-direction: column;
37+
flex-direction: column;
38+
@media (min-width: ${breakpoints.l}) {
39+
flex-direction: row;
3440
}
3541
`;
3642

37-
const AlignVertically = styled.div`
38-
display: flex;
39-
gap: var(--spacing-m);
40-
flex-direction: row;
41-
align-items: center;
42-
`;
43+
const Name = styled.h2`
44+
font-weight: 500;
45+
font-family: var(--tilavaraus-admin-font-medium);
46+
margin-top: 0;
4347
44-
const Name = styled.div`
45-
font-size: var(--fontsize-body-xl);
48+
font-size: var(--fontsize-heading-xs);
49+
margin-bottom: var(--spacing-2-xs);
50+
@media (min-width: ${breakpoints.s}) {
51+
font-size: var(--fontsize-heading-m);
52+
margin-bottom: var(--spacing-s);
53+
}
4654
`;
4755
const Tagline = styled.div`
48-
font-size: var(--fontsize-body-l);
56+
font-size: var(--fontsize-body-m);
57+
`;
58+
59+
const StyledButtonContainer = styled(ButtonContainer)`
60+
margin: 0;
61+
flex-grow: 0;
62+
flex-shrink: 0;
63+
width: auto;
64+
align-items: center;
65+
flex-direction: row-reverse;
66+
67+
justify-content: space-between;
68+
& > button {
69+
flex: 1;
70+
max-width: 50%;
71+
}
72+
@media (min-width: ${breakpoints.s}) {
73+
justify-content: flex-end;
74+
& > button {
75+
flex: unset;
76+
max-width: unset;
77+
}
78+
}
79+
`;
80+
81+
const TagContainer = styled.div`
82+
flex-grow: 1;
83+
flex-shrink: 1;
4984
`;
5085

5186
type Props = {
@@ -57,11 +92,11 @@ type Props = {
5792
const StickyHeader = ({ name, tagline, buttons }: Props): JSX.Element => (
5893
<Sticky>
5994
<StickyContent>
60-
<div>
95+
<TagContainer>
6196
<Name>{name}</Name>
6297
<Tagline>{tagline}</Tagline>
63-
</div>
64-
<AlignVertically>{buttons}</AlignVertically>
98+
</TagContainer>
99+
<StyledButtonContainer>{buttons}</StyledButtonContainer>
65100
</StickyContent>
66101
</Sticky>
67102
);

admin-ui/src/component/reservations/requested/ApprovalButtons.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
import { useTranslation } from "react-i18next";
77
import { addHours, isToday } from "date-fns";
88
import { Button } from "hds-react";
9-
import { ButtonContainer } from "app/styles/layout";
109
import DenyDialog from "./DenyDialog";
1110
import ApproveDialog from "./ApproveDialog";
1211
import ReturnToRequiredHandlingDialog from "./ReturnToRequiresHandlingDialog";
@@ -66,12 +65,14 @@ const ApprovalButtons = ({
6665
reservation,
6766
handleClose,
6867
handleAccept,
68+
disableNonEssentialButtons,
6969
}: {
7070
state: ReservationsReservationStateChoices;
7171
isFree: boolean;
7272
reservation: ReservationType;
7373
handleClose: () => void;
7474
handleAccept: () => void;
75+
disableNonEssentialButtons?: boolean;
7576
}) => {
7677
const { setModalContent } = useModal();
7778
const { t } = useTranslation();
@@ -124,7 +125,7 @@ const ApprovalButtons = ({
124125
!reservation.recurringReservation && isPossibleToEdit(state, endTime);
125126

126127
return (
127-
<ButtonContainer>
128+
<>
128129
{endTime > new Date() && isPossibleToApprove(state, endTime) && (
129130
<Button {...btnCommon} onClick={handleApproveClick}>
130131
{t("RequestedReservation.approve")}
@@ -140,10 +141,10 @@ const ApprovalButtons = ({
140141
{t("RequestedReservation.returnToHandling")}
141142
</Button>
142143
)}
143-
{isAllowedToModify && (
144+
{!disableNonEssentialButtons && isAllowedToModify && (
144145
<ButtonLikeLink to="edit">{t("ApprovalButtons.edit")}</ButtonLikeLink>
145146
)}
146-
</ButtonContainer>
147+
</>
147148
);
148149
};
149150

admin-ui/src/component/reservations/requested/ApprovalButtonsRecurring.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
import { useTranslation } from "react-i18next";
77
import { Button } from "hds-react";
88
import { ButtonLikeLink } from "app/styles/util";
9-
import { ButtonContainer } from "app/styles/layout";
109
import DenyDialog from "./DenyDialog";
1110
import { useModal } from "../../../context/ModalContext";
1211
import { useRecurringReservations } from "./hooks";
@@ -17,10 +16,12 @@ const ApprovalButtonsRecurring = ({
1716
recurringReservation,
1817
handleClose,
1918
handleAccept,
19+
disableNonEssentialButtons,
2020
}: {
2121
recurringReservation: RecurringReservationType;
2222
handleClose: () => void;
2323
handleAccept: () => void;
24+
disableNonEssentialButtons?: boolean;
2425
}) => {
2526
const { setModalContent } = useModal();
2627
const { t } = useTranslation();
@@ -82,12 +83,14 @@ const ApprovalButtonsRecurring = ({
8283
}
8384

8485
return (
85-
<ButtonContainer>
86+
<>
8687
<Button {...btnCommon} onClick={handleDenyClick}>
8788
{t("ApprovalButtons.recurring.rejectAllButton")}
8889
</Button>
89-
<ButtonLikeLink to="edit">{t("ApprovalButtons.edit")}</ButtonLikeLink>
90-
</ButtonContainer>
90+
{!disableNonEssentialButtons && (
91+
<ButtonLikeLink to="edit">{t("ApprovalButtons.edit")}</ButtonLikeLink>
92+
)}
93+
</>
9194
);
9295
};
9396

admin-ui/src/component/reservations/requested/ApproveDialog.tsx

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,32 @@ const DialogContent = ({
5454
onClose: () => void;
5555
onAccept: () => void;
5656
}) => {
57-
const [approveReservationMutation] =
58-
useMutation<Mutation>(APPROVE_RESERVATION);
57+
const { notifyError, notifySuccess } = useNotification();
58+
const { t, i18n } = useTranslation();
59+
60+
const [approveReservationMutation] = useMutation<Mutation>(
61+
APPROVE_RESERVATION,
62+
{
63+
onCompleted: () => {
64+
notifySuccess(t("RequestedReservation.ApproveDialog.approved"));
65+
onAccept();
66+
},
67+
onError: (err) => {
68+
const { message } = err;
69+
const hasTranslatedErrorMsg = i18n.exists(
70+
`errors.descriptive.${message}`
71+
);
72+
const errorTranslated = hasTranslatedErrorMsg
73+
? `errors.descriptive.${message}`
74+
: `errors.descriptive.genericError`;
75+
notifyError(
76+
t("RequestedReservation.ApproveDialog.errorSaving", {
77+
error: t(errorTranslated),
78+
})
79+
);
80+
},
81+
}
82+
);
5983

6084
const approveReservation = (input: ReservationApproveMutationInput) =>
6185
approveReservationMutation({ variables: { input } });
@@ -64,36 +88,16 @@ const DialogContent = ({
6488
const [handlingDetails, setHandlingDetails] = useState<string>(
6589
reservation.workingMemo || ""
6690
);
67-
const { notifyError, notifySuccess } = useNotification();
68-
const { t } = useTranslation();
69-
7091
const hasPrice = Boolean(reservation.price !== undefined);
7192
const priceIsValid = !hasPrice || !Number.isNaN(parseNumber(price));
7293

73-
const handleApprove = async () => {
74-
try {
75-
const res = await approveReservation({
76-
pk: reservation.pk,
77-
price: parseNumber(price),
78-
priceNet: calcPriceNet(price, reservation.taxPercentageValue),
79-
handlingDetails,
80-
});
81-
82-
if (res.data?.approveReservation?.errors) {
83-
notifyError(
84-
t("RequestedReservation.ApproveDialog.errorSaving", {
85-
error: res.data?.approveReservation?.errors
86-
.map((e) => `${e?.field}: ${e?.messages}`)
87-
.join(", "),
88-
})
89-
);
90-
} else {
91-
notifySuccess(t("RequestedReservation.ApproveDialog.approved"));
92-
onAccept();
93-
}
94-
} catch (e) {
95-
notifyError(t("RequestedReservation.ApproveDialog.errorSaving"));
96-
}
94+
const handleApprove = () => {
95+
approveReservation({
96+
pk: reservation.pk,
97+
price: parseNumber(price),
98+
priceNet: calcPriceNet(price, reservation.taxPercentageValue),
99+
handlingDetails,
100+
});
97101
};
98102

99103
return (

admin-ui/src/component/reservations/requested/RequestedReservation.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ import {
3434
import { useModal } from "../../../context/ModalContext";
3535
import { UPDATE_WORKING_MEMO } from "./queries";
3636
import BreadcrumbWrapper from "../../BreadcrumbWrapper";
37-
import { Container, HorisontalFlex } from "../../../styles/layout";
37+
import {
38+
ButtonContainer,
39+
Container,
40+
HorisontalFlex,
41+
} from "../../../styles/layout";
3842
import { publicUrl } from "../../../common/const";
3943
import ShowWhenTargetInvisible from "../../ShowWhenTargetInvisible";
4044
import StickyHeader from "../../StickyHeader";
@@ -109,11 +113,13 @@ const ButtonsWithPermChecks = ({
109113
reservation,
110114
isFree,
111115
onReservationUpdated,
116+
disableNonEssentialButtons,
112117
}: {
113118
reservation: ReservationType;
114119
isFree: boolean;
115120
// Hack to deal with reservation query not being cached so we need to refetch
116121
onReservationUpdated: () => void;
122+
disableNonEssentialButtons?: boolean;
117123
}) => {
118124
const { setModalContent } = useModal();
119125

@@ -134,6 +140,7 @@ const ButtonsWithPermChecks = ({
134140
onReservationUpdated();
135141
closeDialog();
136142
}}
143+
disableNonEssentialButtons={disableNonEssentialButtons}
137144
/>
138145
) : (
139146
<ApprovalButtons
@@ -145,6 +152,7 @@ const ButtonsWithPermChecks = ({
145152
onReservationUpdated();
146153
closeDialog();
147154
}}
155+
disableNonEssentialButtons={disableNonEssentialButtons}
148156
/>
149157
)}
150158
</VisibleIfPermission>
@@ -447,6 +455,7 @@ const RequestedReservation = ({
447455
reservation={reservation}
448456
isFree={!isNonFree}
449457
onReservationUpdated={refetch}
458+
disableNonEssentialButtons
450459
/>
451460
}
452461
/>
@@ -457,11 +466,13 @@ const RequestedReservation = ({
457466
reservation={reservation}
458467
tagline={reservationTagline}
459468
/>
460-
<ButtonsWithPermChecks
461-
reservation={reservation}
462-
onReservationUpdated={refetch}
463-
isFree={!isNonFree}
464-
/>
469+
<ButtonContainer>
470+
<ButtonsWithPermChecks
471+
reservation={reservation}
472+
onReservationUpdated={refetch}
473+
isFree={!isNonFree}
474+
/>
475+
</ButtonContainer>
465476
<ReservationSummary reservation={reservation} isFree={!isNonFree} />
466477
<div>
467478
<VisibleIfPermission

0 commit comments

Comments
 (0)