mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-24 18:56:32 -05:00
feat(notes): redirect note to its primary address
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
c0d4d233da
commit
4b82031464
3 changed files with 53 additions and 3 deletions
|
@ -45,6 +45,7 @@
|
|||
"success": "Note has been created."
|
||||
},
|
||||
"error": {
|
||||
"redirecting": "An error occurred while redirecting you to the primary address of this note",
|
||||
"notFound": {
|
||||
"title": "Note not found",
|
||||
"description": "The requested note doesn't exist."
|
||||
|
|
|
@ -7,11 +7,13 @@ import { ApiError } from '../../../api/common/api-error'
|
|||
import * as getNoteModule from '../../../api/notes'
|
||||
import type { Note } from '../../../api/notes/types'
|
||||
import * as LoadingScreenModule from '../../../components/application-loader/loading-screen/loading-screen'
|
||||
import * as useApplicationStateModule from '../../../hooks/common/use-application-state'
|
||||
import * as useSingleStringUrlParameterModule from '../../../hooks/common/use-single-string-url-parameter'
|
||||
import * as setNoteDataFromServerModule from '../../../redux/note-details/methods'
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import * as CommonErrorPageModule from '../../error-pages/common-error-page'
|
||||
import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
|
||||
import * as useUiNotificationsModule from '../../notifications/ui-notification-boundary'
|
||||
import * as CreateNonExistingNoteHintModule from './create-non-existing-note-hint'
|
||||
import { NoteLoadingBoundary } from './note-loading-boundary'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
|
@ -19,13 +21,20 @@ import { Fragment } from 'react'
|
|||
import { Mock } from 'ts-mockery'
|
||||
|
||||
jest.mock('../../../hooks/common/use-single-string-url-parameter')
|
||||
jest.mock('../../../hooks/common/use-application-state')
|
||||
jest.mock('../../../api/notes')
|
||||
jest.mock('../../../redux/note-details/methods')
|
||||
jest.mock('../../error-pages/common-error-page', () => ({
|
||||
CommonErrorPage: jest.fn()
|
||||
}))
|
||||
jest.mock('../../../components/application-loader/loading-screen/loading-screen')
|
||||
jest.mock('../../notifications/ui-notification-boundary')
|
||||
jest.mock('./create-non-existing-note-hint')
|
||||
jest.mock('next/router', () => ({
|
||||
useRouter: () => ({
|
||||
push: jest.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
describe('Note loading boundary', () => {
|
||||
const mockedNoteId = 'mockedNoteId'
|
||||
|
@ -37,6 +46,7 @@ describe('Note loading boundary', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
await mockI18n()
|
||||
jest.spyOn(useApplicationStateModule, 'useApplicationState').mockReturnValue(mockedNoteId)
|
||||
jest.spyOn(CreateNonExistingNoteHintModule, 'CreateNonExistingNoteHint').mockImplementation(() => {
|
||||
return (
|
||||
<Fragment>
|
||||
|
@ -64,6 +74,11 @@ describe('Note loading boundary', () => {
|
|||
</Fragment>
|
||||
)
|
||||
})
|
||||
jest.spyOn(useUiNotificationsModule, 'useUiNotifications').mockReturnValue({
|
||||
showErrorNotification: jest.fn(),
|
||||
dismissNotification: jest.fn(),
|
||||
dispatchUiNotification: jest.fn()
|
||||
})
|
||||
mockGetNoteIdQueryParameter()
|
||||
})
|
||||
|
||||
|
|
|
@ -5,14 +5,18 @@
|
|||
*/
|
||||
import { ApiError } from '../../../api/common/api-error'
|
||||
import { ErrorToI18nKeyMapper } from '../../../api/common/error-to-i18n-key-mapper'
|
||||
import { useApplicationState } from '../../../hooks/common/use-application-state'
|
||||
import { useSingleStringUrlParameter } from '../../../hooks/common/use-single-string-url-parameter'
|
||||
import { LoadingScreen } from '../../application-loader/loading-screen/loading-screen'
|
||||
import { CommonErrorPage } from '../../error-pages/common-error-page'
|
||||
import { useUiNotifications } from '../../notifications/ui-notification-boundary'
|
||||
import { CustomAsyncLoadingBoundary } from '../async-loading-boundary/custom-async-loading-boundary'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import { CreateNonExistingNoteHint } from './create-non-existing-note-hint'
|
||||
import { useLoadNoteFromServer } from './hooks/use-load-note-from-server'
|
||||
import { useRouter } from 'next/router'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
/**
|
||||
* Loads the note identified by the note-id in the URL.
|
||||
|
@ -23,10 +27,40 @@ import React, { useEffect, useMemo } from 'react'
|
|||
*/
|
||||
export const NoteLoadingBoundary: React.FC<PropsWithChildren> = ({ children }) => {
|
||||
const [{ error, loading, value }, loadNoteFromServer] = useLoadNoteFromServer()
|
||||
const noteId = useSingleStringUrlParameter('noteId', '')
|
||||
const primaryNoteAddress = useApplicationState((state) => state.noteDetails.primaryAddress)
|
||||
const router = useRouter()
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
const [primaryAddressChecked, setPrimaryAddressChecked] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (primaryAddressChecked) {
|
||||
return
|
||||
}
|
||||
loadNoteFromServer()
|
||||
}, [loadNoteFromServer])
|
||||
}, [loadNoteFromServer, primaryAddressChecked])
|
||||
|
||||
useEffect(() => {
|
||||
if (!value || primaryAddressChecked) {
|
||||
return
|
||||
}
|
||||
if (noteId !== primaryNoteAddress) {
|
||||
router
|
||||
.replace(`/n/${primaryNoteAddress}`, undefined, { shallow: true })
|
||||
.then(() => setPrimaryAddressChecked(true))
|
||||
.catch(showErrorNotification('noteLoadingBoundary.error.redirecting'))
|
||||
} else {
|
||||
setPrimaryAddressChecked(true)
|
||||
}
|
||||
}, [
|
||||
value,
|
||||
primaryNoteAddress,
|
||||
noteId,
|
||||
router,
|
||||
showErrorNotification,
|
||||
primaryAddressChecked,
|
||||
setPrimaryAddressChecked
|
||||
])
|
||||
|
||||
const errorComponent = useMemo(() => {
|
||||
if (error === undefined) {
|
||||
|
@ -50,7 +84,7 @@ export const NoteLoadingBoundary: React.FC<PropsWithChildren> = ({ children }) =
|
|||
|
||||
return (
|
||||
<CustomAsyncLoadingBoundary
|
||||
loading={loading || !value}
|
||||
loading={loading || !value || !primaryAddressChecked}
|
||||
error={error}
|
||||
errorComponent={errorComponent}
|
||||
loadingComponent={<LoadingScreen />}>
|
||||
|
|
Loading…
Reference in a new issue