diff --git a/native/src/components/Feedback.tsx b/native/src/components/Feedback.tsx index 823e290050..af3160e4ab 100644 --- a/native/src/components/Feedback.tsx +++ b/native/src/components/Feedback.tsx @@ -9,15 +9,12 @@ import useNavigate from '../hooks/useNavigate' import Caption from './Caption' import FeedbackButtons from './FeedbackButtons' import { SendingStatusType } from './FeedbackContainer' -import HorizontalLine from './HorizontalLine' import LoadingSpinner from './LoadingSpinner' import Note from './Note' -import NothingFound from './NothingFound' import InputSection from './base/InputSection' import TextButton from './base/TextButton' const Wrapper = styled.View` - padding: 20px; gap: 8px; ` @@ -79,11 +76,7 @@ const Feedback = ({ {isSearchFeedback ? ( - <> - - - - + ) : ( <> diff --git a/native/src/components/FeedbackContainer.tsx b/native/src/components/FeedbackContainer.tsx index bc39a50791..af4c7afc2f 100644 --- a/native/src/components/FeedbackContainer.tsx +++ b/native/src/components/FeedbackContainer.tsx @@ -1,17 +1,33 @@ import React, { ReactElement, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import styled from 'styled-components/native' import { SEND_FEEDBACK_SIGNAL_NAME } from 'shared' import { createFeedbackEndpoint, FeedbackRouteType } from 'shared/api' +import { config } from 'translations' +import buildConfig from '../constants/buildConfig' import { determineApiUrl } from '../utils/helpers' import sendTrackingSignal from '../utils/sendTrackingSignal' import { reportError } from '../utils/sentry' import Feedback from './Feedback' +import Text from './base/Text' +import TextButton from './base/TextButton' const Container = styled.View` flex: 1; background-color: ${props => props.theme.colors.backgroundColor}; + padding: 8px 20px; + gap: 8px; +` + +const Title = styled(Text)` + font-weight: 600; +` + +const Hint = styled(Title)` + margin-top: 8px; + text-align: center; ` export type SendingStatusType = 'idle' | 'sending' | 'failed' | 'successful' @@ -30,6 +46,8 @@ const FeedbackContainer = ({ query, language, routeType, cityCode, slug }: Feedb const [isPositiveRating, setIsPositiveRating] = useState(null) const [sendingStatus, setSendingStatus] = useState('idle') const [searchTerm, setSearchTerm] = useState(query) + const [showFeedback, setShowFeedback] = useState(query === undefined) + const { t } = useTranslation('feedback') useEffect(() => { setSearchTerm(query) @@ -70,20 +88,37 @@ const FeedbackContainer = ({ query, language, routeType, cityCode, slug }: Feedb }) } + if (showFeedback) { + return ( + + + + ) + } + + const fallbackLanguage = config.sourceLanguage + return ( - + <> + + {language === fallbackLanguage ? t('noResultsInUserLanguage') : t('noResultsInUserAndSourceLanguage')} + + {t('checkQuery', { appName: buildConfig().appName })} + {t('informationMissing')} + setShowFeedback(true)} /> + ) } diff --git a/native/src/components/__tests__/Feedback.spec.tsx b/native/src/components/__tests__/Feedback.spec.tsx index 7955207f10..71e3190c10 100644 --- a/native/src/components/__tests__/Feedback.spec.tsx +++ b/native/src/components/__tests__/Feedback.spec.tsx @@ -82,7 +82,6 @@ describe('Feedback', () => { , ) - expect(getByText('search:nothingFound')).toBeDefined() expect(getByText('searchTermDescription')).toBeDefined() }) diff --git a/native/src/components/__tests__/FeedbackContainer.spec.tsx b/native/src/components/__tests__/FeedbackContainer.spec.tsx index 4e630c7e92..331b2fbed5 100644 --- a/native/src/components/__tests__/FeedbackContainer.spec.tsx +++ b/native/src/components/__tests__/FeedbackContainer.spec.tsx @@ -123,6 +123,8 @@ describe('FeedbackContainer', () => { , ) + const buttonToOpenFeedback = getByText('giveFeedback') + fireEvent.press(buttonToOpenFeedback) const button = getByText('send') fireEvent.press(button) expect(await findByText('thanksMessage')).toBeDefined() @@ -148,6 +150,8 @@ describe('FeedbackContainer', () => { , ) + const buttonToOpenFeedback = getByText('giveFeedback') + fireEvent.press(buttonToOpenFeedback) const input = getByDisplayValue(query) fireEvent.changeText(input, fullSearchTerm) const button = getByText('send') @@ -168,11 +172,13 @@ describe('FeedbackContainer', () => { }) it('should disable send button if query term is removed', async () => { - const { findByText, getByDisplayValue } = render( + const { findByText, getByDisplayValue, getByText } = render( , ) + const buttonToOpenFeedback = getByText('giveFeedback') + fireEvent.press(buttonToOpenFeedback) expect(await findByText('send')).not.toBeDisabled() const input = getByDisplayValue('query') fireEvent.changeText(input, '') diff --git a/native/src/routes/__tests__/SearchModal.spec.tsx b/native/src/routes/__tests__/SearchModal.spec.tsx index c48a319772..98f552c8af 100644 --- a/native/src/routes/__tests__/SearchModal.spec.tsx +++ b/native/src/routes/__tests__/SearchModal.spec.tsx @@ -125,7 +125,7 @@ describe('SearchModal', () => { fireEvent.changeText(getByPlaceholderText('searchPlaceholder'), 'no results, please') - expect(getByText('search:nothingFound')).toBeTruthy() + expect(getByText('noResultsInUserLanguage')).toBeTruthy() }) it('should open with an initial search text if one is supplied', () => { diff --git a/translations/translations.json b/translations/translations.json index b3dca1e8d8..482c7db0d2 100644 --- a/translations/translations.json +++ b/translations/translations.json @@ -4763,7 +4763,12 @@ "positiveRating": "Diese Seite ist hilfreich", "searchTermDescription": "Für den folgenden Begriff konnte kein Ergebnis gefunden werden:", "contactMailAddress": "E-Mail für Rückfragen", - "note": "Bitte wähle eine Reaktion oder schreibe einen Kommentar, um das Feedback abschicken zu können." + "note": "Bitte wähle eine Reaktion oder schreibe einen Kommentar, um das Feedback abschicken zu können.", + "giveFeedback": "Feedback geben", + "checkQuery": "Überprüfen Sie Ihren Suchbegriff oder ändern Sie die eingestellte Sprache der {{appName}}-App.", + "informationMissing": "Hier fehlen Informationen?", + "noResultsInUserLanguage": "Es wurden leider keine passenden Ergebnisse in Deiner Sprache gefunden.", + "noResultsInUserAndSourceLanguage": "Es wurden leider keine passenden Ergebnisse in Deiner Sprache oder auf Deutsch gefunden." }, "am": { "disclaimer": "የግንኙነት መረጃና ዕትም", @@ -4947,7 +4952,12 @@ "positiveRating": "This site is useful", "searchTermDescription": "No result could be found for the following term:", "contactMailAddress": "E-Mail for further questions", - "note": "Please select a reaction or write a comment in order to send feedback." + "note": "Please select a reaction or write a comment in order to send feedback.", + "giveFeedback": "Give feedback", + "checkQuery": "Check your search term or select a different language in the {{appName}} app.", + "informationMissing": "Is information missing?", + "noResultsInUserLanguage": "Sorry, we could not find any matching results in your language.", + "noResultsInUserAndSourceLanguage": "Sorry, we could not find any matching results in your language or in German." }, "es": { "disclaimer": "Contacto y aviso legal", diff --git a/web/src/components/Feedback.tsx b/web/src/components/Feedback.tsx index 78b1abc9f2..cd718c2fd7 100644 --- a/web/src/components/Feedback.tsx +++ b/web/src/components/Feedback.tsx @@ -4,7 +4,6 @@ import styled from 'styled-components' import buildConfig from '../constants/buildConfig' import dimensions from '../constants/dimensions' -import Failure from './Failure' import FeedbackButtons from './FeedbackButtons' import { SendingStatusType } from './FeedbackContainer' import Note from './Note' @@ -49,7 +48,6 @@ type FeedbackProps = { onFeedbackChanged?: (isPositiveFeedback: boolean | null) => void onSubmit: () => void sendingStatus: SendingStatusType - noResults: boolean | undefined searchTerm: string | undefined setSearchTerm: (newTerm: string) => void closeFeedback: (() => void) | undefined @@ -64,7 +62,6 @@ const Feedback = ({ onCommentChanged, onContactMailChanged, onFeedbackChanged, - noResults, searchTerm, setSearchTerm, closeFeedback, @@ -87,12 +84,9 @@ const Feedback = ({ return ( {isSearchFeedback ? ( - <> - {noResults && } - - - - + + + ) : ( onFeedbackChanged && )} diff --git a/web/src/components/FeedbackContainer.tsx b/web/src/components/FeedbackContainer.tsx index b0df6bae2c..c797682fc5 100644 --- a/web/src/components/FeedbackContainer.tsx +++ b/web/src/components/FeedbackContainer.tsx @@ -12,7 +12,6 @@ type FeedbackContainerProps = { routeType: FeedbackRouteType onClose?: () => void query?: string - noResults?: boolean slug?: string onSubmit?: () => void initialRating: boolean | null @@ -22,7 +21,6 @@ export type SendingStatusType = 'idle' | 'sending' | 'failed' | 'successful' export const FeedbackContainer = ({ query, - noResults, language, routeType, cityCode, @@ -84,7 +82,6 @@ export const FeedbackContainer = ({ searchTerm={searchTerm} setSearchTerm={setSearchTerm} closeFeedback={onClose} - noResults={noResults} /> ) } diff --git a/web/src/components/SearchFeedback.tsx b/web/src/components/SearchFeedback.tsx index 3d3d261108..1f65e9af36 100644 --- a/web/src/components/SearchFeedback.tsx +++ b/web/src/components/SearchFeedback.tsx @@ -3,7 +3,9 @@ import { useTranslation } from 'react-i18next' import styled from 'styled-components' import { SEARCH_ROUTE } from 'shared' +import { config } from 'translations' +import buildConfig from '../constants/buildConfig' import FeedbackContainer from './FeedbackContainer' import TextButton from './base/TextButton' @@ -13,6 +15,22 @@ const Container = styled.div` align-items: center; ` +const CenteredContainer = styled.div` + text-align: center; +` + +const SmallTitle = styled.p` + font-weight: 600; +` + +const Hint = styled.p` + padding-bottom: 16px; +` + +const StyledButton = styled(TextButton)` + margin-top: 8px; +` + type SearchFeedbackProps = { cityCode: string languageCode: string @@ -26,7 +44,7 @@ const SearchFeedback = ({ cityCode, languageCode, query, noResults }: SearchFeed useEffect(() => setShowFeedback(false), [query]) - if (noResults || showFeedback) { + if (showFeedback) { return ( ) } + if (noResults) { + const fallbackLanguage = config.sourceLanguage + + return ( + + + {languageCode === fallbackLanguage ? t('noResultsInUserLanguage') : t('noResultsInUserAndSourceLanguage')} + + {t('checkQuery', { appName: buildConfig().appName })} + {t('informationMissing')} + setShowFeedback(true)} /> + + ) + } + return ( setShowFeedback(true)} text={t('informationNotFound')} /> diff --git a/web/src/components/__tests__/Feedback.spec.tsx b/web/src/components/__tests__/Feedback.spec.tsx index da1b5b1e07..ab20adbcbf 100644 --- a/web/src/components/__tests__/Feedback.spec.tsx +++ b/web/src/components/__tests__/Feedback.spec.tsx @@ -89,7 +89,6 @@ describe('Feedback', () => { />, ) expect(getByText('feedback:wantedInformation')).toBeTruthy() - expect(getByText('error:search:nothingFound')).toBeTruthy() }) it('should display error', () => { diff --git a/web/src/components/__tests__/SearchFeedback.spec.tsx b/web/src/components/__tests__/SearchFeedback.spec.tsx index b6c7381926..4c9e0217e8 100644 --- a/web/src/components/__tests__/SearchFeedback.spec.tsx +++ b/web/src/components/__tests__/SearchFeedback.spec.tsx @@ -45,17 +45,18 @@ describe('SearchFeedback', () => { expect(queryByText('feedback:wantedInformation')).toBeNull() }) - it('should show feedback if no results found', () => { + it('should show feedback button if no results found', () => { const { getByText } = renderWithTheme( , ) - expect(getByText('feedback:send')).toBeTruthy() + expect(getByText('feedback:giveFeedback')).toBeTruthy() }) it('should not allow sending search feedback if query term is removed', async () => { const { getByText, rerender } = renderWithTheme( , ) + fireEvent.click(getByText('feedback:giveFeedback')) expect(getByText('feedback:send')).toBeEnabled() // the query is controlled in the parent of SearchFeedback, so we need to update the props @@ -64,6 +65,7 @@ describe('SearchFeedback', () => { , ) + fireEvent.click(getByText('feedback:giveFeedback')) await waitFor(() => expect(getByText('feedback:send')).toBeDisabled()) }) }) diff --git a/web/src/routes/__tests__/SearchPage.spec.tsx b/web/src/routes/__tests__/SearchPage.spec.tsx index e1b76c1361..d0d436bc4c 100644 --- a/web/src/routes/__tests__/SearchPage.spec.tsx +++ b/web/src/routes/__tests__/SearchPage.spec.tsx @@ -61,7 +61,7 @@ describe('SearchPage', () => { renderRoute(searchPage, { routePattern, pathname, searchParams: query }) it('should not display results if no query entered', () => { - const { queryByText, getByPlaceholderText, getByText } = renderSearch() + const { queryByText, getByPlaceholderText, getAllByText } = renderSearch() expect(queryByText(category1.title)).toBeNull() expect(queryByText(event0.title)).toBeNull() @@ -73,13 +73,13 @@ describe('SearchPage', () => { }, }) - expect(getByText(category1.title)).toBeTruthy() - expect(getByText(event0.title)).toBeTruthy() - expect(getByText(poi0.title)).toBeTruthy() + expect(getAllByText(category1.title)).toBeTruthy() + expect(getAllByText(event0.title)).toBeTruthy() + expect(getAllByText(poi0.title)).toBeTruthy() }) it('should display nothing found for search', () => { - const { getByRole, getByPlaceholderText } = renderSearch() + const { getByPlaceholderText, getByText } = renderSearch() fireEvent.change(getByPlaceholderText('search:searchPlaceholder'), { target: { @@ -87,7 +87,7 @@ describe('SearchPage', () => { }, }) - expect(getByRole('alert')).toContainHTML('search:nothingFound') + expect(getByText('feedback:noResultsInUserAndSourceLanguage')).toBeTruthy() }) describe('url query', () => {