diff --git a/web/src/components/CityContentToolbar.tsx b/web/src/components/CityContentToolbar.tsx index 7c9c4dc59e..1c34472296 100644 --- a/web/src/components/CityContentToolbar.tsx +++ b/web/src/components/CityContentToolbar.tsx @@ -73,9 +73,7 @@ const CityContentToolbar = (props: CityContentToolbarProps) => { id='copy-icon' /> - {hasFeedbackOption && ( - - )} + {hasFeedbackOption && } ) } diff --git a/web/src/components/Feedback.tsx b/web/src/components/Feedback.tsx index 201dd5b670..78b1abc9f2 100644 --- a/web/src/components/Feedback.tsx +++ b/web/src/components/Feedback.tsx @@ -46,7 +46,7 @@ type FeedbackProps = { contactMail: string onCommentChanged: (comment: string) => void onContactMailChanged: (contactMail: string) => void - onFeedbackChanged: (isPositiveFeedback: boolean | null) => void + onFeedbackChanged?: (isPositiveFeedback: boolean | null) => void onSubmit: () => void sendingStatus: SendingStatusType noResults: boolean | undefined @@ -94,7 +94,7 @@ const Feedback = ({ ) : ( - + onFeedbackChanged && )} void + isPositiveRating: boolean | null + setIsPositiveRating?: (isPositiveFeedback: boolean | null) => void } export type SendingStatusType = 'idle' | 'sending' | 'failed' | 'successful' @@ -28,8 +30,9 @@ export const FeedbackContainer = ({ slug, onClose, onSubmit, + isPositiveRating, + setIsPositiveRating, }: FeedbackContainerProps): ReactElement => { - const [isPositiveRating, setIsPositiveRating] = useState(null) const [comment, setComment] = useState('') const [contactMail, setContactMail] = useState('') const [sendingStatus, setSendingStatus] = useState('idle') diff --git a/web/src/components/FeedbackToolbarItem.tsx b/web/src/components/FeedbackToolbarItem.tsx index 7c962a6372..0bf40d9bf6 100644 --- a/web/src/components/FeedbackToolbarItem.tsx +++ b/web/src/components/FeedbackToolbarItem.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next' import { FeedbackRouteType } from 'shared/api' -import { FeedbackIcon } from '../assets' +import { HappySmileyIcon, SadSmileyIcon } from '../assets' import useCityContentParams from '../hooks/useCityContentParams' import { RouteType } from '../routes' import FeedbackContainer from './FeedbackContainer' @@ -13,20 +13,20 @@ import ToolbarItem from './ToolbarItem' type FeedbackToolbarItemProps = { route: RouteType slug?: string - isInBottomActionSheet: boolean } -const FeedbackToolbarItem = ({ route, slug, isInBottomActionSheet }: FeedbackToolbarItemProps): ReactElement => { +const FeedbackToolbarItem = ({ route, slug }: FeedbackToolbarItemProps): ReactElement => { const { cityCode, languageCode } = useCityContentParams() const [isFeedbackOpen, setIsFeedbackOpen] = useState(false) const [isSubmitted, setIsSubmitted] = useState(false) + const [isPositiveRating, setIsPositiveRating] = useState(null) const { t } = useTranslation('feedback') const title = isSubmitted ? t('thanksHeadline') : t('headline') return ( <> {isFeedbackOpen && ( - setIsFeedbackOpen(false)} wrapInPortal={isInBottomActionSheet}> + setIsFeedbackOpen(false)} wrapInPortal> setIsFeedbackOpen(false)} onSubmit={() => setIsSubmitted(true)} @@ -34,10 +34,27 @@ const FeedbackToolbarItem = ({ route, slug, isInBottomActionSheet }: FeedbackToo cityCode={cityCode} language={languageCode} slug={slug} + isPositiveRating={isPositiveRating} + setIsPositiveRating={setIsPositiveRating} /> )} - setIsFeedbackOpen(true)} /> + { + setIsFeedbackOpen(true) + setIsPositiveRating(true) + }} + /> + { + setIsFeedbackOpen(true) + setIsPositiveRating(false) + }} + /> ) } diff --git a/web/src/components/Layout.tsx b/web/src/components/Layout.tsx index 37af04ecff..988a4fe823 100644 --- a/web/src/components/Layout.tsx +++ b/web/src/components/Layout.tsx @@ -1,11 +1,11 @@ -import React, { ReactNode, useLayoutEffect, useState } from 'react' +import React, { ReactNode } from 'react' import styled, { css } from 'styled-components' import dimensions from '../constants/dimensions' import useWindowDimensions from '../hooks/useWindowDimensions' +import '../styles/Aside.css' import { MobileBanner } from './MobileBanner' - -const additionalToolbarTopSpacing = 32 +import Portal from './Portal' export const RichLayout = styled.div` position: relative; @@ -49,6 +49,7 @@ const Body = styled.div<{ $fullWidth: boolean; $disableScrollingSafari: boolean background-color: ${props => props.theme.colors.backgroundColor}; word-wrap: break-word; min-height: 100%; + display: flex; /* Fix jumping iOS Safari Toolbar by prevent scrolling on body */ @@ -93,25 +94,6 @@ const Main = styled.main<{ $fullWidth: boolean }>` } ` -const Aside = styled.aside<{ $languageSelectorHeight: number }>` - top: ${props => props.$languageSelectorHeight + dimensions.headerHeightLarge + additionalToolbarTopSpacing}px; - margin-top: ${props => props.$languageSelectorHeight - dimensions.navigationMenuHeight}px; - display: inline-block; - position: sticky; - width: ${dimensions.toolbarWidth}px; - vertical-align: top; - z-index: 10; - - &:empty { - display: none; - } - - &:empty + * { - display: block; - max-width: 100%; - } -` - export const LAYOUT_ELEMENT_ID = 'layout' type LayoutProps = { @@ -133,20 +115,18 @@ const Layout = ({ fullWidth = false, disableScrollingSafari = false, }: LayoutProps): JSX.Element => { - const { width, viewportSmall } = useWindowDimensions() - const [languageSelectorHeight, setLanguageSelectorHeight] = useState(0) - - useLayoutEffect(() => { - const panelHeight = document.getElementById('languageSelector')?.clientHeight - setLanguageSelectorHeight(panelHeight ?? 0) - }, [width]) + const { viewportSmall } = useWindowDimensions() return ( {header} - {!viewportSmall && } + {!viewportSmall && ( + + {toolbar} + + )}
{children}
{viewportSmall && toolbar} diff --git a/web/src/components/SearchFeedback.tsx b/web/src/components/SearchFeedback.tsx index 8ddd9f9651..30cfb58d32 100644 --- a/web/src/components/SearchFeedback.tsx +++ b/web/src/components/SearchFeedback.tsx @@ -35,6 +35,7 @@ const SearchFeedback = ({ cityCode, languageCode, query, noResults }: SearchFeed routeType={SEARCH_ROUTE} query={query} noResults={noResults} + isPositiveRating={null} /> ) diff --git a/web/src/components/__tests__/FeedbackContainer.spec.tsx b/web/src/components/__tests__/FeedbackContainer.spec.tsx index fa69973f29..c09da48195 100644 --- a/web/src/components/__tests__/FeedbackContainer.spec.tsx +++ b/web/src/components/__tests__/FeedbackContainer.spec.tsx @@ -34,14 +34,13 @@ describe('FeedbackContainer', () => { language, onClose: closeModal, query, + isPositiveRating: null, }) it('should display thanks message for modal', async () => { - const { getByRole, findByText } = renderWithTheme() - const buttonRating = getByRole('button', { - name: 'feedback:useful', - }) - fireEvent.click(buttonRating) + const { getByRole, findByText } = renderWithTheme( + , + ) const button = getByRole('button', { name: 'feedback:send', }) diff --git a/web/src/components/__tests__/FeedbackToolbarItem.spec.tsx b/web/src/components/__tests__/FeedbackToolbarItem.spec.tsx index 68db4cfee5..7806782a44 100644 --- a/web/src/components/__tests__/FeedbackToolbarItem.spec.tsx +++ b/web/src/components/__tests__/FeedbackToolbarItem.spec.tsx @@ -18,18 +18,17 @@ jest.mock('focus-trap-react', () => ({ children }: { children: ReactElement }) = describe('FeedbackToolbarItem', () => { it('should open and update title on submit feedback', async () => { const { queryByText, findByText, getByText } = renderWithRouterAndTheme( - , + , ) expect(queryByText('feedback:headline')).toBeFalsy() expect(queryByText('feedback:thanksHeadline')).toBeFalsy() - fireEvent.click(getByText('feedback:feedback')) + fireEvent.click(getByText('feedback:useful')) expect(getByText('feedback:headline')).toBeTruthy() expect(queryByText('feedback:thanksHeadline')).toBeFalsy() - fireEvent.click(getByText('feedback:useful')) fireEvent.click(getByText('feedback:send')) expect(await findByText('feedback:thanksMessage')).toBeTruthy() diff --git a/web/src/styles/Aside.css b/web/src/styles/Aside.css new file mode 100644 index 0000000000..bc083e933b --- /dev/null +++ b/web/src/styles/Aside.css @@ -0,0 +1,14 @@ +.aside { + position: fixed; + top: 35%; + width: 100px; + left: 1%; + + @media (min-width: 1100px) { + left: 10%; + } + + &:empty { + display: none; + } +}