Adds an info banner to the app (#190)

* added info-banner component to show the banner.text, we got from the backend config. This banner is shown on top of the landing page (intro, history, login/signup and profile) and also on top of the editor and links to `/n/banner`
* added banner to backendConfig Redux state
* added BannerState to the ApplicationState with that the showing of the banner is globally controlled, the banner text is given to the banner component and the timestamp to acknowledge a banner was read by the user
* the timestamp of a dismissed note is saved in the browsers localStorage to determine in the future if the banner should be shown

Signed-off-by: Philip Molares <philip.molares@udo.edu>
Co-authored-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Philip Molares 2020-06-15 21:54:20 +02:00 committed by GitHub
parent 75aa8b38af
commit e014eb36b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 144 additions and 15 deletions

View file

@ -1,6 +1,7 @@
import { getBackendConfig } from '../../../api/backend-config'
import { getFrontendConfig } from '../../../api/frontend-config'
import { setBackendConfig } from '../../../redux/backend-config/methods'
import { setBanner } from '../../../redux/banner/methods'
import { setFrontendConfig } from '../../../redux/frontend-config/methods'
import { getAndSetUser } from '../../../utils/apiUtils'
@ -17,5 +18,14 @@ export const loadAllConfig: (baseUrl: string) => Promise<void> = async (baseUrl)
}
setBackendConfig(backendConfig)
const banner = backendConfig.banner
if (banner.text !== '') {
const lastAcknowledgedTimestamp = window.localStorage.getItem('bannerTimeStamp') || ''
setBanner({
...banner,
show: banner.text !== '' && banner.timestamp !== lastAcknowledgedTimestamp
})
}
await getAndSetUser()
}

View file

@ -1,18 +1,15 @@
import React, { useEffect, useState } from 'react'
import React, { Fragment, useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import useMedia from 'use-media'
import { ApplicationState } from '../../redux'
import { setEditorModeConfig } from '../../redux/editor/methods'
import { Splitter } from '../common/splitter/splitter'
import { InfoBanner } from '../landing/layout/info-banner'
import { EditorWindow } from './editor-window/editor-window'
import { MarkdownPreview } from './markdown-preview/markdown-preview'
import { EditorMode } from './task-bar/editor-view-mode'
import { TaskBar } from './task-bar/task-bar'
interface RouteParameters {
id: string
}
const Editor: React.FC = () => {
const editorMode: EditorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
const isWide = useMedia({ minWidth: 576 })
@ -29,15 +26,18 @@ const Editor: React.FC = () => {
}, [editorMode, firstDraw, isWide])
return (
<div className={'d-flex flex-column vh-100'}>
<TaskBar/>
<Splitter
showLeft={editorMode === EditorMode.EDITOR || editorMode === EditorMode.BOTH}
left={<EditorWindow/>}
showRight={editorMode === EditorMode.PREVIEW || (editorMode === EditorMode.BOTH)}
right={<MarkdownPreview/>}
containerClassName={'overflow-hidden'}/>
</div>
<Fragment>
<InfoBanner/>
<div className={'d-flex flex-column vh-100'}>
<TaskBar/>
<Splitter
showLeft={editorMode === EditorMode.EDITOR || editorMode === EditorMode.BOTH}
left={<EditorWindow/>}
showRight={editorMode === EditorMode.PREVIEW || (editorMode === EditorMode.BOTH)}
right={<MarkdownPreview/>}
containerClassName={'overflow-hidden'}/>
</div>
</Fragment>
)
}

View file

@ -1,11 +1,13 @@
import React from 'react'
import { Container } from 'react-bootstrap'
import { Footer } from './layout/footer/footer'
import { InfoBanner } from './layout/info-banner'
import { HeaderBar } from './layout/navigation/header-bar/header-bar'
export const LandingLayout: React.FC = ({ children }) => {
return (
<Container className="text-white d-flex flex-column mvh-100">
<InfoBanner/>
<HeaderBar/>
<div className={'d-flex flex-column justify-content-between flex-fill text-center'}>
<div>

View file

@ -0,0 +1,34 @@
import React from 'react'
import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { ApplicationState } from '../../../redux'
import { Alert, Button } from 'react-bootstrap'
import { setBanner } from '../../../redux/banner/methods'
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
import { ShowIf } from '../../common/show-if/show-if'
export const InfoBanner: React.FC = () => {
const bannerState = useSelector((state: ApplicationState) => state.banner)
const dismissBanner = () => {
setBanner({ ...bannerState, show: false })
window.localStorage.setItem('bannerTimeStamp', bannerState.timestamp)
}
return (
<ShowIf condition={bannerState.show}>
<Alert variant='primary' dir='auto' className='mb-0 text-center d-flex flex-row justify-content-center'>
<Link to='/s/banner' className='flex-grow-1 align-self-center'>
{bannerState.text}
</Link>
<Button
variant='outline-primary'
size='sm'
className='mx-2'
onClick={dismissBanner}>
<ForkAwesomeIcon icon='times'/>
</Button>
</Alert>
</ShowIf>
)
}