Skip to content

Commit

Permalink
2732: Allow language change for local news
Browse files Browse the repository at this point in the history
  • Loading branch information
steffenkleinle committed Aug 1, 2024
1 parent 90e3e08 commit a0edd15
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ dist
# IntelliJ
**/workspace.xml
runConfigurations.xml
**/prettier.xml

.tsbuild

Expand Down
8 changes: 0 additions & 8 deletions native/.idea/prettier.xml

This file was deleted.

1 change: 1 addition & 0 deletions native/src/components/__tests__/News.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const localNews: [LocalNewsModel] = [
timestamp: DateTime.fromISO('2019-03-01T00:00:00.000'),
title: 'Local News',
content: 'Local news with url: https://example.com',
availableLanguages: {},
}),
]

Expand Down
1 change: 1 addition & 0 deletions native/src/components/__tests__/NewsListItem.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const localNews = new LocalNewsModel({
timestamp: DateTime.fromISO('2020-01-20T00:00:00.000Z'),
title: 'Test Push Notification',
content: 'Some "test text with lots of "html entities" which won't be displayed.',
availableLanguages: {},
})
describe('NewsListItem', () => {
const navigateToNews = jest.fn()
Expand Down
18 changes: 16 additions & 2 deletions native/src/routes/LocalNews.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { ReactElement } from 'react'
import React, { ReactElement, useCallback } from 'react'

import { LOCAL_NEWS_TYPE, NEWS_ROUTE, NewsRouteType } from 'shared'

import News from '../components/News'
import { NavigationProps, RouteProps } from '../constants/NavigationTypes'
import useHeader from '../hooks/useHeader'
import { CityContentData } from '../hooks/useLoadCityContent'
import usePreviousProp from '../hooks/usePreviousProp'
import urlFromRouteInformation from '../navigation/url'

type LocalNewsProps = {
Expand All @@ -20,7 +21,10 @@ type LocalNewsProps = {
const LocalNews = ({ route, navigation, data, newsId, navigateToNews, refresh }: LocalNewsProps): ReactElement => {
const cityCode = data.city.code
const languageCode = data.language.code
const availableLanguages = newsId !== null ? [languageCode] : data.languages.map(it => it.code)
const selectedLocalNews = data.localNews.find(it => it.id === newsId)
const availableLanguages = selectedLocalNews
? Object.keys(selectedLocalNews.availableLanguages)
: data.languages.map(it => it.code)
const shareUrl = urlFromRouteInformation({
route: NEWS_ROUTE,
cityCode,
Expand All @@ -30,6 +34,16 @@ const LocalNews = ({ route, navigation, data, newsId, navigateToNews, refresh }:
})
useHeader({ navigation, route, availableLanguages, data, shareUrl })

const onLanguageChange = useCallback(
(newLanguage: string) => {
if (selectedLocalNews) {
navigation.setParams({ newsId: selectedLocalNews.availableLanguages[newLanguage] })
}
},
[selectedLocalNews, navigation],
)
usePreviousProp({ prop: languageCode, onPropChange: onLanguageChange })

return (
<News
newsId={newsId}
Expand Down
2 changes: 2 additions & 0 deletions native/src/routes/__tests__/LocalNews.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ const news: [LocalNewsModel, LocalNewsModel] = [
title: 'Local news 1',
timestamp: DateTime.fromISO('2020-01-20T00:00:00.000Z'),
content: 'Local news content 2',
availableLanguages: {},
}),
new LocalNewsModel({
id: 1234,
title: 'Local news 2',
timestamp: DateTime.fromISO('2020-01-20T00:00:00.000Z'),
content: 'Local news content 2',
availableLanguages: {},
}),
]

Expand Down
3 changes: 3 additions & 0 deletions native/src/utils/DatabaseConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ type ContentLocalNewsJsonType = {
timestamp: string
title: string
content: string
available_languages: Record<string, number>
}
type CityCodeType = string
type LanguageCodeType = string
Expand Down Expand Up @@ -540,6 +541,7 @@ class DatabaseConnector {
timestamp: it.timestamp.toISO(),
title: it.title,
content: it.content,
available_languages: it.availableLanguages,
}),
)
await this.writeFile(this.getContentPath('localNews', context), JSON.stringify(jsonModels))
Expand All @@ -555,6 +557,7 @@ class DatabaseConnector {
timestamp: DateTime.fromISO(jsonObject.timestamp),
title: jsonObject.title,
content: jsonObject.content,
availableLanguages: jsonObject.available_languages,
}),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('localnews', () => {
timestamp: date,
message:
'In summer there are often ticks in forest and meadows with high grass. These are very small animals. They feed on the blood of people or animals they sting, like mosquitoes. But they stay in the skin longer and can transmit dangerous diseases. If you have been in high grass, you should search your body very thoroughly for ticks. They like to sit in the knees, armpits or in the groin area. If you discover a tick in your skin, you should carefully pull it out with tweezers without crushing it. If the sting inflames, you must see a doctor.',
available_languages: {},
})

const item = createNewsItem('2020-03-20T17:50:00+02:00')
Expand All @@ -26,6 +27,7 @@ describe('localnews', () => {
timestamp: date,
content:
'In summer there are often ticks in forest and meadows with high grass. These are very small animals. They feed on the blood of people or animals they sting, like mosquitoes. But they stay in the skin longer and can transmit dangerous diseases. If you have been in high grass, you should search your body very thoroughly for ticks. They like to sit in the knees, armpits or in the groin area. If you discover a tick in your skin, you should carefully pull it out with tweezers without crushing it. If the sting inflames, you must see a doctor.',
availableLanguages: {},
})

const itemValue = createNewsItemModel(DateTime.fromISO('2020-03-20T17:50:00+02:00'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('localnews', () => {
timestamp: date,
message:
'In summer there are often ticks in forest and meadows with high grass. These are very small animals. They feed on the blood of people or animals they sting, like mosquitoes. But they stay in the skin longer and can transmit dangerous diseases. If you have been in high grass, you should search your body very thoroughly for ticks. They like to sit in the knees, armpits or in the groin area. If you discover a tick in your skin, you should carefully pull it out with tweezers without crushing it. If the sting inflames, you must see a doctor.',
available_languages: {},
})

const item1 = createNewsItem('2020-03-20T17:50:00+02:00')
Expand All @@ -28,6 +29,7 @@ describe('localnews', () => {
timestamp: date,
content:
'In summer there are often ticks in forest and meadows with high grass. These are very small animals. They feed on the blood of people or animals they sting, like mosquitoes. But they stay in the skin longer and can transmit dangerous diseases. If you have been in high grass, you should search your body very thoroughly for ticks. They like to sit in the knees, armpits or in the groin area. If you discover a tick in your skin, you should carefully pull it out with tweezers without crushing it. If the sting inflames, you must see a doctor.',
availableLanguages: {},
})

const itemModel1 = createNewsItemModel(DateTime.fromISO('2020-03-20T17:50:00+02:00'))
Expand Down
10 changes: 5 additions & 5 deletions shared/api/endpoints/createLocalNewsElementEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export default (baseUrl: string): Endpoint<ParamsType, LocalNewsModel> =>
)
}

const { id, timestamp, title, message } = localNewsModel
return new LocalNewsModel({
id,
timestamp: DateTime.fromISO(timestamp),
title,
content: message,
id: localNewsModel.id,
timestamp: DateTime.fromISO(localNewsModel.timestamp),
title: localNewsModel.title,
content: localNewsModel.message,
availableLanguages: localNewsModel.available_languages,
})
})
.build()
1 change: 1 addition & 0 deletions shared/api/endpoints/createLocalNewsEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default (baseUrl: string): Endpoint<ParamsType, Array<LocalNewsModel>> =>
timestamp: DateTime.fromISO(localNews.timestamp),
title: localNews.title,
content: localNews.message,
availableLanguages: localNews.available_languages,
}),
),
)
Expand Down
1 change: 1 addition & 0 deletions shared/api/endpoints/testing/NewsModelBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class LocalNewsModelBuilder {
title: 'first news item',
timestamp: DateTime.fromISO('2017-11-18T19:30:00.000Z'),
content: 'This is a sample news',
availableLanguages: {},
}),
}),
)
Expand Down
19 changes: 17 additions & 2 deletions shared/api/models/LocalNewsModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@ class LocalNewsModel {
_timestamp: DateTime
_title: string
_content: string
_availableLanguages: Record<string, number>

constructor(params: { id: number; timestamp: DateTime; title: string; content: string }) {
const { id, timestamp, title, content } = params
constructor(params: {
id: number
timestamp: DateTime
title: string
content: string
availableLanguages: Record<string, { id: number }>
}) {
const { id, timestamp, title, content, availableLanguages } = params
this._id = id
this._timestamp = timestamp
this._title = decodeHTML(title)
this._content = decodeHTML(content)
this._availableLanguages = Object.entries(availableLanguages).reduce(
(acc, [code, value]) => ({ ...acc, [code]: value.id }),
{},
)
}

get availableLanguages(): Record<string, number> {
return this._availableLanguages
}

get timestamp(): DateTime {
Expand Down
1 change: 1 addition & 0 deletions shared/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export type JsonLocalNewsType = {
timestamp: string
title: string
message: string
available_languages: Record<string, { id: number }>
}
export type JsonOfferPostType = {
'zammad-url': string | undefined
Expand Down
2 changes: 2 additions & 0 deletions web/src/components/__tests__/LocalNewsList.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ describe('LocalNewsList', () => {
title: 'Important',
timestamp: date,
content: 'This is a very important content from your favourite city!',
availableLanguages: {},
})

const localNews2 = new LocalNewsModel({
id: 218,
title: 'Love :)',
timestamp: date,
content: 'I am a random local news content content and I like it!!!!!!!!!',
availableLanguages: {},
})

const items = [localNews1, localNews2]
Expand Down
39 changes: 24 additions & 15 deletions web/src/routes/LocalNewsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import React, { ReactElement } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate, useParams } from 'react-router-dom'

import { LOCAL_NEWS_TYPE, NEWS_ROUTE, pathnameFromRouteInformation, replaceLinks } from 'shared'
import {
LOCAL_NEWS_TYPE,
NEWS_ROUTE,
NewsRouteInformationType,
pathnameFromRouteInformation,
replaceLinks,
} from 'shared'
import { createLocalNewsEndpoint, LocalNewsModel, NotFoundError, useLoadFromEndpoint } from 'shared/api'

import { CityRouteProps } from '../CityContentSwitcher'
Expand Down Expand Up @@ -35,6 +41,14 @@ const LocalNewsPage = ({ city, pathname, languageCode, cityCode }: CityRouteProp

const newsModel = newsId ? localNews?.find((it: LocalNewsModel) => it.id.toString() === newsId) : undefined

const createNewsPath = ({ languageCode: newLanguageCode, newsId }: Partial<NewsRouteInformationType>): string =>
pathnameFromRouteInformation({
route: NEWS_ROUTE,
newsType: LOCAL_NEWS_TYPE,
cityCode,
languageCode: newLanguageCode ?? languageCode,
newsId,
})
const renderLocalNewsListItem = (localNewsItem: LocalNewsModel) => {
const { id, title, content, timestamp } = localNewsItem
return (
Expand All @@ -43,27 +57,22 @@ const LocalNewsPage = ({ city, pathname, languageCode, cityCode }: CityRouteProp
content={content}
timestamp={timestamp}
key={id}
link={pathnameFromRouteInformation({
route: NEWS_ROUTE,
newsType: LOCAL_NEWS_TYPE,
cityCode,
languageCode,
newsId: id,
})}
link={createNewsPath({ newsId: id })}
t={t}
type={LOCAL_NEWS_TYPE}
/>
)
}

// Language change is not possible between local news detail views because we don't know the id of other languages
const languageChangePaths = city.languages.map(({ code, name }) => ({
path: newsId
? null
: pathnameFromRouteInformation({ route: NEWS_ROUTE, newsType: LOCAL_NEWS_TYPE, cityCode, languageCode: code }),
name,
code,
}))
const languageChangePaths = city.languages.map(({ code, name }) => {
const newNewsId = newsModel?.availableLanguages[code]
return {
path: newsId && newNewsId === undefined ? null : createNewsPath({ languageCode: code, newsId: newNewsId }),
name,
code,
}
})

const pageTitle = `${newsModel && newsModel.title ? newsModel.title : t('localNews.pageTitle')} - ${city.name}`
const locationLayoutParams: Omit<CityContentLayoutProps, 'isLoading'> = {
Expand Down

0 comments on commit a0edd15

Please sign in to comment.