digitalfabrik/integreat-app

View on GitHub
web/src/components/ChatContainer.tsx

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
import React, { ReactElement, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'

import { ChatIcon } from '../assets'
import buildConfig from '../constants/buildConfig'
import dimensions from '../constants/dimensions'
import useLockedBody from '../hooks/useLockedBody'
import useWindowDimensions from '../hooks/useWindowDimensions'
import ChatContentWrapper from './ChatContentWrapper'
import ChatController from './ChatController'
import ChatModal from './ChatModal'
import Icon from './base/Icon'

const ChatButtonContainer = styled.button`
  position: fixed;
  bottom: 10%;
  inset-inline-end: 10%;
  background-color: transparent;
  border: none;
  display: flex;
  flex-direction: column;

  @media ${dimensions.smallViewport} {
    bottom: 85px;
    inset-inline-end: 12px;
  }
`

const Circle = styled.div`
  background-color: ${props => props.theme.colors.themeColor};
  border-radius: 50%;
  box-shadow: 0 2px 3px 3px rgb(0 0 0 / 20%);
  align-self: center;
  padding: 8px;
`

const MinimizedToolbar = styled.div`
  position: fixed;
  z-index: 200;
  bottom: 0;
  inset-inline-end: 20px;

  @media ${dimensions.smallViewport} {
    display: none;
  }
`

const StyledIcon = styled(Icon)`
  display: flex;
  width: 24px;
  height: 24px;
  align-self: center;
  justify-content: center;
  color: ${props => props.theme.colors.backgroundColor};

  @media ${dimensions.smallViewport} {
    width: 40px;
    height: 40px;
  }
`

const ChatTitle = styled.span`
  margin-top: 8px;
`

export enum ChatVisibilityStatus {
  closed,
  minimized,
  maximized,
}

type ChatContainerProps = {
  city: string
  language: string
}

const ChatContainer = ({ city, language }: ChatContainerProps): ReactElement => {
  const { t } = useTranslation('chat')
  const [chatVisibilityStatus, setChatVisibilityStatus] = useState<ChatVisibilityStatus>(ChatVisibilityStatus.closed)
  const { viewportSmall } = useWindowDimensions()
  const isChatMaximized = chatVisibilityStatus === ChatVisibilityStatus.maximized
  useLockedBody(isChatMaximized)
  const title = t('header', { appName: buildConfig().appName })

  if (isChatMaximized) {
    return (
      <ChatModal
        data-testid='chat-modal'
        title={title}
        resizeModal={() => setChatVisibilityStatus(ChatVisibilityStatus.minimized)}
        closeModal={() => setChatVisibilityStatus(ChatVisibilityStatus.closed)}
        visibilityStatus={chatVisibilityStatus}>
        <ChatController city={city} language={language} />
      </ChatModal>
    )
  }

  if (chatVisibilityStatus === ChatVisibilityStatus.minimized) {
    return (
      <MinimizedToolbar data-testid='chat-minimized-toolbar'>
        <ChatContentWrapper
          title={title}
          onResize={() => setChatVisibilityStatus(ChatVisibilityStatus.maximized)}
          onClose={() => setChatVisibilityStatus(ChatVisibilityStatus.closed)}
          small={false}
          visibilityStatus={chatVisibilityStatus}
        />
      </MinimizedToolbar>
    )
  }

  return (
    <ChatButtonContainer
      data-testid='chat-button-container'
      onClick={() => setChatVisibilityStatus(ChatVisibilityStatus.maximized)}>
      <Circle>
        <StyledIcon src={ChatIcon} title={t('button')} />
      </Circle>
      {!viewportSmall && <ChatTitle>{t('button')}</ChatTitle>}
    </ChatButtonContainer>
  )
}

export default ChatContainer