web/src/routes/TuNewsDetailPage.tsx
import React, { ReactElement } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate, useParams } from 'react-router-dom'
import styled from 'styled-components'
import { TU_NEWS_TYPE } from 'shared'
import { createTunewsElementEndpoint, NotFoundError, useLoadFromEndpoint } from 'shared/api'
import { CityRouteProps } from '../CityContentSwitcher'
import { TuNewsActiveIcon } from '../assets'
import CityContentLayout, { CityContentLayoutProps } from '../components/CityContentLayout'
import CityContentToolbar from '../components/CityContentToolbar'
import FailureSwitcher from '../components/FailureSwitcher'
import Helmet from '../components/Helmet'
import LoadingSpinner from '../components/LoadingSpinner'
import Page from '../components/Page'
import Icon from '../components/base/Icon'
import { tunewsApiBaseUrl } from '../constants/urls'
import { TU_NEWS_DETAIL_ROUTE } from './index'
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
`
const StyledBanner = styled.div`
position: relative;
display: flex;
height: 60px;
overflow: hidden;
align-items: center;
margin: 25px 0;
background-color: ${props => props.theme.colors.tunewsThemeColorLight};
border-radius: 11px;
`
const StyledIcon = styled(Icon)`
width: 100%;
height: 100%;
`
const StyledTitle = styled.div`
display: flex;
width: 185px;
height: 100%;
align-items: center;
justify-content: center;
background-color: ${props => props.theme.colors.tunewsThemeColor};
color: ${props => props.theme.colors.backgroundColor};
font-size: 20px;
font-weight: 700;
`
const TuNewsDetailPage = ({ city, pathname, cityCode, languageCode }: CityRouteProps): ReactElement | null => {
// This component is only opened when there is a news ID in the route
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const newsId = useParams().newsId!
const navigate = useNavigate()
const { t } = useTranslation('news')
const {
data: newsModel,
loading,
error: newsError,
} = useLoadFromEndpoint(createTunewsElementEndpoint, tunewsApiBaseUrl, { id: parseInt(newsId, 10) })
if (!city) {
return null
}
const pageTitle = `${newsModel?.title ?? t('pageTitle')} - ${city.name}`
// Language change is not possible between tuNews detail views because we don't know the id of other languages
const languageChangePaths = city.languages.map(({ code, name }) => ({ path: null, name, code }))
const locationLayoutParams: Omit<CityContentLayoutProps, 'isLoading'> = {
city,
languageChangePaths,
route: TU_NEWS_DETAIL_ROUTE,
languageCode,
Toolbar: <CityContentToolbar hasFeedbackOption={false} route={TU_NEWS_DETAIL_ROUTE} pageTitle={pageTitle} />,
}
if (loading) {
return (
<CityContentLayout isLoading {...locationLayoutParams}>
<LoadingSpinner />
</CityContentLayout>
)
}
if (!newsModel) {
const error =
!newsError || newsError instanceof NotFoundError
? new NotFoundError({
type: TU_NEWS_TYPE,
id: pathname,
city: cityCode,
language: languageCode,
})
: newsError
return (
<CityContentLayout isLoading={false} {...locationLayoutParams}>
<FailureSwitcher error={error} />
</CityContentLayout>
)
}
return (
<CityContentLayout isLoading={false} {...locationLayoutParams}>
<Helmet pageTitle={pageTitle} languageChangePaths={languageChangePaths} cityModel={city} />
<StyledContainer>
<>
<StyledBanner>
<StyledTitle>
<StyledIcon src={TuNewsActiveIcon} />
</StyledTitle>
</StyledBanner>
<Page
title={newsModel.title}
content={newsModel.content}
lastUpdate={newsModel.date}
showLastUpdateText={false}
onInternalLinkClick={navigate}
/>
</>
</StyledContainer>
</CityContentLayout>
)
}
export default TuNewsDetailPage