digitalfabrik/integreat-app

View on GitHub
native/src/components/Page.tsx

Summary

Maintainability
A
0 mins
Test Coverage
F
51%
import { mapValues } from 'lodash'
import { DateTime } from 'luxon'
import React, { ReactElement, ReactNode, useCallback, useContext, useMemo, useState } from 'react'
import styled from 'styled-components/native'

import dimensions from '../constants/dimensions'
import useCityAppContext from '../hooks/useCityAppContext'
import useNavigateToLink from '../hooks/useNavigateToLink'
import useResourceCache from '../hooks/useResourceCache'
import { LanguageResourceCacheStateType, PageResourceCacheEntryStateType } from '../utils/DataContainer'
import { RESOURCE_CACHE_DIR_PATH } from '../utils/DatabaseConnector'
import Caption from './Caption'
import RemoteContent from './RemoteContent'
import { StaticServerContext } from './StaticServerProvider'
import TimeStamp from './TimeStamp'

const Container = styled.View<{ $padding: boolean }>`
  ${props => props.$padding && `padding: 0 ${dimensions.pageContainerPaddingHorizontal}px 8px;`}
`
export type ParsedCacheDictionaryType = Record<string, string>

const createCacheDictionary = (
  resourceCache: LanguageResourceCacheStateType,
  resourceCacheUrl: string,
  pagePath?: string,
): ParsedCacheDictionaryType =>
  pagePath
    ? mapValues(resourceCache[pagePath] || {}, (file: PageResourceCacheEntryStateType) =>
        file.filePath.startsWith(RESOURCE_CACHE_DIR_PATH)
          ? file.filePath.replace(RESOURCE_CACHE_DIR_PATH, resourceCacheUrl)
          : file.filePath,
      )
    : {}

type PageProps = {
  title?: string
  content: string
  BeforeContent?: ReactNode
  AfterContent?: ReactNode
  Footer?: ReactNode
  language: string
  lastUpdate?: DateTime
  path?: string
  padding?: boolean
}

const Page = ({
  title,
  content,
  BeforeContent,
  AfterContent,
  Footer,
  language,
  lastUpdate,
  path,
  padding = true,
}: PageProps): ReactElement => {
  const { cityCode, languageCode } = useCityAppContext()
  const resourceCache = useResourceCache({ cityCode, languageCode })
  const resourceCacheUrl = useContext(StaticServerContext)
  const [loading, setLoading] = useState(true)
  const navigateToLink = useNavigateToLink()

  const cacheDictionary = useMemo(
    () => createCacheDictionary(resourceCache, resourceCacheUrl, path),
    [resourceCache, resourceCacheUrl, path],
  )
  const onLinkPress = useCallback(
    (url: string) => {
      const shareUrl = Object.keys(cacheDictionary).find(remoteUrl => cacheDictionary[remoteUrl] === url)
      navigateToLink(url, shareUrl || url)
    },
    [cacheDictionary, navigateToLink],
  )
  const onLoad = useCallback(() => setLoading(false), [setLoading])

  return (
    <Container $padding={padding}>
      {!loading && title ? <Caption title={title} /> : null}
      {!loading && BeforeContent}
      <RemoteContent
        content={content}
        cacheDictionary={cacheDictionary}
        onLinkPress={onLinkPress}
        onLoad={onLoad}
        loading={loading}
        language={language}
        resourceCacheUrl={resourceCacheUrl}
      />
      {!loading && AfterContent}
      {!loading && !!content && lastUpdate && <TimeStamp lastUpdate={lastUpdate} />}
      {!loading && Footer}
    </Container>
  )
}

export default Page