mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-28 22:15:12 -04:00
Rework notifications (#1465)
* Rework notifications - dispatchUINotification returns a promise that contains the notification id - notifications use i18n instead of plain text Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> * Reformat code Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
808601eaba
commit
553e9f8ead
13 changed files with 154 additions and 105 deletions
|
@ -6,8 +6,7 @@
|
|||
|
||||
import { Editor, Hint, Hints, Pos } from 'codemirror'
|
||||
import { findWordAtCursor, generateHintListByPrefix, Hinter } from './index'
|
||||
import { DEFAULT_DURATION_IN_SECONDS, dispatchUiNotification } from '../../../../redux/ui-notifications/methods'
|
||||
import i18n from 'i18next'
|
||||
import { showErrorNotification } from '../../../../redux/ui-notifications/methods'
|
||||
|
||||
type highlightJsImport = typeof import('../../../common/hljs/hljs')
|
||||
|
||||
|
@ -22,12 +21,7 @@ const loadHighlightJs = async (): Promise<highlightJsImport | null> => {
|
|||
try {
|
||||
return await import('../../../common/hljs/hljs')
|
||||
} catch (error) {
|
||||
dispatchUiNotification(
|
||||
i18n.t('common.errorOccurred'),
|
||||
i18n.t('common.errorWhileLoadingLibrary', { name: 'highlight.js' }),
|
||||
DEFAULT_DURATION_IN_SECONDS,
|
||||
'exclamation-circle'
|
||||
)
|
||||
showErrorNotification('common.errorWhileLoadingLibrary', { name: 'highlight.js' })(error as Error)
|
||||
console.error("can't load highlight js", error)
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { showErrorNotification } from '../../../redux/ui-notifications/methods'
|
|||
import { useApplicationState } from '../../../hooks/common/use-application-state'
|
||||
|
||||
export const PinNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ className, hide }) => {
|
||||
const { t } = useTranslation()
|
||||
useTranslation()
|
||||
const { id } = useParams<EditorPagePathParams>()
|
||||
const history = useApplicationState((state) => state.history)
|
||||
|
||||
|
@ -28,8 +28,8 @@ export const PinNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ class
|
|||
}, [id, history])
|
||||
|
||||
const onPinClicked = useCallback(() => {
|
||||
toggleHistoryEntryPinning(id).catch(showErrorNotification(t('landing.history.error.updateEntry.text')))
|
||||
}, [id, t])
|
||||
toggleHistoryEntryPinning(id).catch(showErrorNotification('landing.history.error.updateEntry.text'))
|
||||
}, [id])
|
||||
|
||||
return (
|
||||
<SidebarButton
|
||||
|
|
|
@ -5,23 +5,29 @@
|
|||
*/
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { DEFAULT_DURATION_IN_SECONDS, dispatchUiNotification } from '../../redux/ui-notifications/methods'
|
||||
import { dispatchUiNotification } from '../../redux/ui-notifications/methods'
|
||||
|
||||
const localStorageKey = 'dontshowtestnotification'
|
||||
|
||||
/**
|
||||
* Spawns a notification to test the system. Only for tech demo show case.
|
||||
*/
|
||||
export const useNotificationTest = (): void => {
|
||||
useEffect(() => {
|
||||
if (window.localStorage.getItem(localStorageKey)) {
|
||||
return
|
||||
}
|
||||
console.debug('[Notifications] Dispatched test notification')
|
||||
dispatchUiNotification('Notification-Test!', 'It Works!', DEFAULT_DURATION_IN_SECONDS, 'info-circle', [
|
||||
{
|
||||
label: "Don't show again",
|
||||
onClick: () => {
|
||||
window.localStorage.setItem(localStorageKey, '1')
|
||||
void dispatchUiNotification('notificationTest.title', 'notificationTest.content', {
|
||||
icon: 'info-circle',
|
||||
buttons: [
|
||||
{
|
||||
label: "Don't show again",
|
||||
onClick: () => {
|
||||
window.localStorage.setItem(localStorageKey, '1')
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
]
|
||||
})
|
||||
}, [])
|
||||
}
|
||||
|
|
|
@ -40,33 +40,23 @@ export interface HistoryEntriesProps {
|
|||
}
|
||||
|
||||
export const HistoryContent: React.FC<HistoryContentProps> = ({ viewState, entries }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
useTranslation()
|
||||
const [pageIndex, setPageIndex] = useState(0)
|
||||
const [lastPageIndex, setLastPageIndex] = useState(0)
|
||||
|
||||
const onPinClick = useCallback(
|
||||
(noteId: string) => {
|
||||
toggleHistoryEntryPinning(noteId).catch(showErrorNotification(t('landing.history.error.updateEntry.text')))
|
||||
},
|
||||
[t]
|
||||
)
|
||||
const onPinClick = useCallback((noteId: string) => {
|
||||
toggleHistoryEntryPinning(noteId).catch(showErrorNotification('landing.history.error.updateEntry.text'))
|
||||
}, [])
|
||||
|
||||
const onDeleteClick = useCallback(
|
||||
(noteId: string) => {
|
||||
deleteNote(noteId)
|
||||
.then(() => removeHistoryEntry(noteId))
|
||||
.catch(showErrorNotification(t('landing.history.error.deleteNote.text')))
|
||||
},
|
||||
[t]
|
||||
)
|
||||
const onDeleteClick = useCallback((noteId: string) => {
|
||||
deleteNote(noteId)
|
||||
.then(() => removeHistoryEntry(noteId))
|
||||
.catch(showErrorNotification('landing.history.error.deleteNote.text'))
|
||||
}, [])
|
||||
|
||||
const onRemoveClick = useCallback(
|
||||
(noteId: string) => {
|
||||
removeHistoryEntry(noteId).catch(showErrorNotification(t('landing.history.error.deleteEntry.text')))
|
||||
},
|
||||
[t]
|
||||
)
|
||||
const onRemoveClick = useCallback((noteId: string) => {
|
||||
removeHistoryEntry(noteId).catch(showErrorNotification('landing.history.error.deleteEntry.text'))
|
||||
}, [])
|
||||
|
||||
if (entries.length === 0) {
|
||||
return (
|
||||
|
|
|
@ -16,7 +16,7 @@ import { showErrorNotification } from '../../redux/ui-notifications/methods'
|
|||
import { useApplicationState } from '../../hooks/common/use-application-state'
|
||||
|
||||
export const HistoryPage: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
useTranslation()
|
||||
|
||||
const allEntries = useApplicationState((state) => state.history)
|
||||
const [toolbarState, setToolbarState] = useState<HistoryToolbarState>(initToolbarState)
|
||||
|
@ -27,8 +27,8 @@ export const HistoryPage: React.FC = () => {
|
|||
)
|
||||
|
||||
useEffect(() => {
|
||||
refreshHistoryState().catch(showErrorNotification(t('landing.history.error.getHistory.text')))
|
||||
}, [t])
|
||||
refreshHistoryState().catch(showErrorNotification('landing.history.error.getHistory.text'))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
|
|
@ -21,11 +21,11 @@ export const ClearHistoryButton: React.FC = () => {
|
|||
|
||||
const onConfirm = useCallback(() => {
|
||||
deleteAllHistoryEntries().catch((error) => {
|
||||
showErrorNotification(t('landing.history.error.deleteEntry.text'))(error)
|
||||
refreshHistoryState().catch(showErrorNotification(t('landing.history.error.getHistory.text')))
|
||||
showErrorNotification('landing.history.error.deleteEntry.text')(error)
|
||||
refreshHistoryState().catch(showErrorNotification('landing.history.error.getHistory.text'))
|
||||
})
|
||||
handleClose()
|
||||
}, [t])
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
|
|
@ -116,8 +116,8 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
|
|||
)
|
||||
|
||||
const refreshHistory = useCallback(() => {
|
||||
refreshHistoryState().catch(showErrorNotification(t('landing.history.error.getHistory.text')))
|
||||
}, [t])
|
||||
refreshHistoryState().catch(showErrorNotification('landing.history.error.getHistory.text'))
|
||||
}, [])
|
||||
|
||||
const onUploadAllToRemote = useCallback(() => {
|
||||
if (!userExists) {
|
||||
|
@ -128,7 +128,7 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
|
|||
.map((entry) => entry.identifier)
|
||||
historyEntries.forEach((entry) => (entry.origin = HistoryEntryOrigin.REMOTE))
|
||||
importHistoryEntries(historyEntries).catch((error) => {
|
||||
showErrorNotification(t('landing.history.error.setHistory.text'))(error)
|
||||
showErrorNotification('landing.history.error.setHistory.text')(error)
|
||||
historyEntries.forEach((entry) => {
|
||||
if (localEntries.includes(entry.identifier)) {
|
||||
entry.origin = HistoryEntryOrigin.LOCAL
|
||||
|
@ -137,7 +137,7 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
|
|||
setHistoryEntries(historyEntries)
|
||||
refreshHistory()
|
||||
})
|
||||
}, [userExists, historyEntries, t, refreshHistory])
|
||||
}, [userExists, historyEntries, refreshHistory])
|
||||
|
||||
useEffect(() => {
|
||||
const newState: HistoryToolbarState = {
|
||||
|
|
|
@ -42,11 +42,11 @@ export const ImportHistoryButton: React.FC = () => {
|
|||
(entries: HistoryEntry[]): void => {
|
||||
entries.forEach((entry) => (entry.origin = userExists ? HistoryEntryOrigin.REMOTE : HistoryEntryOrigin.LOCAL))
|
||||
importHistoryEntries(mergeHistoryEntries(historyState, entries)).catch((error) => {
|
||||
showErrorNotification(t('landing.history.error.setHistory.text'))(error)
|
||||
refreshHistoryState().catch(showErrorNotification(t('landing.history.error.getHistory.text')))
|
||||
showErrorNotification('landing.history.error.setHistory.text')(error)
|
||||
refreshHistoryState().catch(showErrorNotification('landing.history.error.getHistory.text'))
|
||||
})
|
||||
},
|
||||
[historyState, userExists, t]
|
||||
[historyState, userExists]
|
||||
)
|
||||
|
||||
const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
|
|
@ -11,6 +11,7 @@ import { ForkAwesomeIcon } from '../common/fork-awesome/fork-awesome-icon'
|
|||
import { ShowIf } from '../common/show-if/show-if'
|
||||
import { IconName } from '../common/fork-awesome/types'
|
||||
import { dismissUiNotification } from '../../redux/ui-notifications/methods'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
|
||||
const STEPS_PER_SECOND = 10
|
||||
|
||||
|
@ -19,8 +20,10 @@ export interface UiNotificationProps extends UiNotification {
|
|||
}
|
||||
|
||||
export const UiNotificationToast: React.FC<UiNotificationProps> = ({
|
||||
title,
|
||||
content,
|
||||
titleI18nKey,
|
||||
contentI18nKey,
|
||||
titleI18nOptions,
|
||||
contentI18nOptions,
|
||||
date,
|
||||
icon,
|
||||
dismissed,
|
||||
|
@ -28,6 +31,7 @@ export const UiNotificationToast: React.FC<UiNotificationProps> = ({
|
|||
durationInSecond,
|
||||
buttons
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [eta, setEta] = useState<number>()
|
||||
const interval = useRef<NodeJS.Timeout | undefined>(undefined)
|
||||
|
||||
|
@ -89,15 +93,17 @@ export const UiNotificationToast: React.FC<UiNotificationProps> = ({
|
|||
)
|
||||
|
||||
const contentDom = useMemo(() => {
|
||||
return content.split('\n').map((value, lineNumber) => {
|
||||
return (
|
||||
<Fragment key={lineNumber}>
|
||||
{value}
|
||||
<br />
|
||||
</Fragment>
|
||||
)
|
||||
})
|
||||
}, [content])
|
||||
return t(contentI18nKey, contentI18nOptions)
|
||||
.split('\n')
|
||||
.map((value, lineNumber) => {
|
||||
return (
|
||||
<Fragment key={lineNumber}>
|
||||
{value}
|
||||
<br />
|
||||
</Fragment>
|
||||
)
|
||||
})
|
||||
}, [contentI18nKey, contentI18nOptions, t])
|
||||
|
||||
return (
|
||||
<Toast show={!dismissed && eta !== undefined} onClose={dismissThisNotification}>
|
||||
|
@ -106,7 +112,7 @@ export const UiNotificationToast: React.FC<UiNotificationProps> = ({
|
|||
<ShowIf condition={!!icon}>
|
||||
<ForkAwesomeIcon icon={icon as IconName} fixedWidth={true} className={'mr-1'} />
|
||||
</ShowIf>
|
||||
{title}
|
||||
<Trans i18nKey={titleI18nKey} tOptions={titleI18nOptions} />
|
||||
</strong>
|
||||
<small>{date.toRelative({ style: 'short' })}</small>
|
||||
</Toast.Header>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue