mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-27 13:34:28 -04:00
Correct use selector (#515)
This commit is contained in:
parent
971421925a
commit
a41d3d1515
20 changed files with 74 additions and 205 deletions
|
@ -1,3 +1,5 @@
|
|||
|
||||
import equal from 'fast-deep-equal'
|
||||
import React from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { ApplicationState } from '../../../redux'
|
||||
|
@ -9,7 +11,7 @@ export interface BrandingProps {
|
|||
}
|
||||
|
||||
export const Branding: React.FC<BrandingProps> = ({ inline = false }) => {
|
||||
const branding = useSelector((state: ApplicationState) => state.config.branding)
|
||||
const branding = useSelector((state: ApplicationState) => state.config.branding, equal)
|
||||
const showBranding = !!branding.name || !!branding.logo
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,11 +7,11 @@ export interface DocumentTitleProps {
|
|||
}
|
||||
|
||||
export const DocumentTitle: React.FC<DocumentTitleProps> = ({ title }) => {
|
||||
const branding = useSelector((state: ApplicationState) => state.config.branding)
|
||||
const brandingName = useSelector((state: ApplicationState) => state.config.branding.name)
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${title ? title + ' - ' : ''}CodiMD ${branding.name ? ` @ ${branding.name}` : ''}`
|
||||
}, [branding, title])
|
||||
document.title = `${title ? title + ' - ' : ''}CodiMD ${brandingName ? ` @ ${brandingName}` : ''}`
|
||||
}, [brandingName, title])
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import equal from 'fast-deep-equal'
|
||||
import React from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
@ -8,7 +9,7 @@ import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
|||
import { ShowIf } from '../show-if/show-if'
|
||||
|
||||
export const MotdBanner: React.FC = () => {
|
||||
const bannerState = useSelector((state: ApplicationState) => state.banner)
|
||||
const bannerState = useSelector((state: ApplicationState) => state.banner, equal)
|
||||
|
||||
const dismissBanner = () => {
|
||||
setBanner({ ...bannerState, show: false })
|
||||
|
|
|
@ -19,7 +19,7 @@ import { NavbarBranding } from './navbar-branding'
|
|||
export const AppBar: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { id } = useParams<EditorPathParams>()
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
|
||||
return (
|
||||
<Navbar bg={'light'}>
|
||||
|
@ -39,10 +39,10 @@ export const AppBar: React.FC = () => {
|
|||
<Button className="mx-2" size="sm" variant="primary">
|
||||
<ForkAwesomeIcon icon="plus"/> <Trans i18nKey="editor.documentBar.new"/>
|
||||
</Button>
|
||||
<ShowIf condition={!user}>
|
||||
<ShowIf condition={!userExists}>
|
||||
<SignInButton size={'sm'} />
|
||||
</ShowIf>
|
||||
<ShowIf condition={!!user}>
|
||||
<ShowIf condition={userExists}>
|
||||
<UserDropdown />
|
||||
</ShowIf>
|
||||
</Nav>
|
||||
|
|
|
@ -14,12 +14,12 @@ export enum EditorMode {
|
|||
|
||||
export const EditorViewMode: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const editorConfig = useSelector((state: ApplicationState) => state.editorConfig)
|
||||
const editorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
|
||||
return (
|
||||
<ToggleButtonGroup
|
||||
type="radio"
|
||||
name="options"
|
||||
value={editorConfig.editorMode}
|
||||
value={editorMode}
|
||||
onChange={(value: EditorMode) => {
|
||||
setEditorMode(value)
|
||||
}}>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useSelector } from 'react-redux'
|
|||
import { deleteHistory, deleteHistoryEntry, getHistory, setHistory, updateHistoryEntry } from '../../api/history'
|
||||
import { deleteNote } from '../../api/notes'
|
||||
import { ApplicationState } from '../../redux'
|
||||
|
||||
import {
|
||||
collectEntries,
|
||||
downloadHistory,
|
||||
|
@ -46,7 +47,7 @@ export const HistoryPage: React.FC = () => {
|
|||
const [localHistoryEntries, setLocalHistoryEntries] = useState<HistoryEntry[]>(loadHistoryFromLocalStore)
|
||||
const [remoteHistoryEntries, setRemoteHistoryEntries] = useState<HistoryEntry[]>([])
|
||||
const [toolbarState, setToolbarState] = useState<HistoryToolbarState>(toolbarInitState)
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const historyWrite = useCallback((entries: HistoryEntry[]) => {
|
||||
|
@ -61,24 +62,24 @@ export const HistoryPage: React.FC = () => {
|
|||
}, [historyWrite, localHistoryEntries])
|
||||
|
||||
const importHistory = useCallback((entries: HistoryEntry[]): void => {
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
setHistory(entries)
|
||||
.then(() => setRemoteHistoryEntries(entries))
|
||||
.catch(() => setError('setHistory'))
|
||||
} else {
|
||||
setLocalHistoryEntries(entries)
|
||||
}
|
||||
}, [user])
|
||||
}, [userExists])
|
||||
|
||||
const refreshHistory = useCallback(() => {
|
||||
const localHistory = loadHistoryFromLocalStore()
|
||||
setLocalHistoryEntries(localHistory)
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
getHistory()
|
||||
.then((remoteHistory) => setRemoteHistoryEntries(remoteHistory))
|
||||
.catch(() => setError('getHistory'))
|
||||
}
|
||||
}, [user])
|
||||
}, [userExists])
|
||||
|
||||
useEffect(() => {
|
||||
refreshHistory()
|
||||
|
@ -94,17 +95,17 @@ export const HistoryPage: React.FC = () => {
|
|||
|
||||
const clearHistory = useCallback(() => {
|
||||
setLocalHistoryEntries([])
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
deleteHistory()
|
||||
.then(() => setRemoteHistoryEntries([]))
|
||||
.catch(() => setError('deleteHistory'))
|
||||
}
|
||||
historyWrite([])
|
||||
}, [historyWrite, user])
|
||||
}, [historyWrite, userExists])
|
||||
|
||||
const uploadAll = useCallback((): void => {
|
||||
const newHistory = mergeEntryArrays(localHistoryEntries, remoteHistoryEntries)
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
setHistory(newHistory)
|
||||
.then(() => {
|
||||
setRemoteHistoryEntries(newHistory)
|
||||
|
@ -113,7 +114,7 @@ export const HistoryPage: React.FC = () => {
|
|||
})
|
||||
.catch(() => setError('setHistory'))
|
||||
}
|
||||
}, [historyWrite, localHistoryEntries, remoteHistoryEntries, user])
|
||||
}, [historyWrite, localHistoryEntries, remoteHistoryEntries, userExists])
|
||||
|
||||
const removeFromHistoryClick = useCallback((entryId: string, location: HistoryEntryOrigin): void => {
|
||||
if (location === HistoryEntryOrigin.LOCAL) {
|
||||
|
@ -126,14 +127,14 @@ export const HistoryPage: React.FC = () => {
|
|||
}, [])
|
||||
|
||||
const deleteNoteClick = useCallback((entryId: string, location: HistoryEntryOrigin): void => {
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
deleteNote(entryId)
|
||||
.then(() => {
|
||||
removeFromHistoryClick(entryId, location)
|
||||
})
|
||||
.catch(() => setError('deleteNote'))
|
||||
}
|
||||
}, [user, removeFromHistoryClick])
|
||||
}, [userExists, removeFromHistoryClick])
|
||||
|
||||
const pinClick = useCallback((entryId: string, location: HistoryEntryOrigin): void => {
|
||||
if (location === HistoryEntryOrigin.LOCAL) {
|
||||
|
|
|
@ -49,7 +49,7 @@ export const initState: HistoryToolbarState = {
|
|||
export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange, tags, onClearHistory, onRefreshHistory, onExportHistory, onImportHistory, onUploadAll }) => {
|
||||
const [t] = useTranslation()
|
||||
const [state, setState] = useState<HistoryToolbarState>(initState)
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
|
||||
const titleSortChanged = (direction: SortModeEnum) => {
|
||||
setState(prevState => ({
|
||||
|
@ -118,7 +118,7 @@ export const HistoryToolbar: React.FC<HistoryToolbarProps> = ({ onSettingsChange
|
|||
<ForkAwesomeIcon icon='refresh'/>
|
||||
</Button>
|
||||
</InputGroup>
|
||||
<ShowIf condition={!!user}>
|
||||
<ShowIf condition={userExists}>
|
||||
<InputGroup className={'mr-1 mb-1'}>
|
||||
<Button variant={'light'} title={t('landing.history.toolbar.uploadAll')} onClick={onUploadAll}>
|
||||
<ForkAwesomeIcon icon='cloud-upload'/>
|
||||
|
|
|
@ -10,10 +10,10 @@ import { SignInButton } from '../../landing-layout/navigation/sign-in-button'
|
|||
|
||||
export const CoverButtons: React.FC = () => {
|
||||
useTranslation()
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const authProviders = useSelector((state: ApplicationState) => state.config.authProviders)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
const anyAuthProviderActivated = useSelector((state: ApplicationState) => Object.values(state.config.authProviders).includes(true))
|
||||
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ export const CoverButtons: React.FC = () => {
|
|||
variant="success"
|
||||
size="lg"
|
||||
/>
|
||||
<ShowIf condition={Object.values(authProviders).includes(true)}>
|
||||
<ShowIf condition={anyAuthProviderActivated}>
|
||||
<span className="m-2">
|
||||
<Trans i18nKey="common.or"/>
|
||||
</span>
|
||||
|
|
|
@ -10,7 +10,7 @@ import { VersionInfo } from './version-info'
|
|||
export const PoweredByLinks: React.FC = () => {
|
||||
useTranslation()
|
||||
|
||||
const config = useSelector((state: ApplicationState) => state.config)
|
||||
const specialLinks = useSelector((state: ApplicationState) => Object.entries(state.config.specialLinks) as [string, string][])
|
||||
|
||||
return (
|
||||
<p>
|
||||
|
@ -20,7 +20,7 @@ export const PoweredByLinks: React.FC = () => {
|
|||
|
|
||||
<TranslatedInternalLink href='/n/release-notes' i18nKey='landing.footer.releases'/>
|
||||
{
|
||||
Object.entries({ ...config.specialLinks }).map(([i18nKey, href]) =>
|
||||
specialLinks.map(([i18nKey, href]) =>
|
||||
<Fragment key={i18nKey}>
|
||||
|
|
||||
<TranslatedExternalLink href={href} i18nKey={'landing.footer.' + i18nKey}/>
|
||||
|
|
|
@ -8,6 +8,7 @@ import frontendVersion from '../../../version.json'
|
|||
import { TranslatedExternalLink } from '../../common/links/translated-external-link'
|
||||
import { ShowIf } from '../../common/show-if/show-if'
|
||||
import { CopyableField } from '../../common/copyable-field/copyable-field'
|
||||
import equal from 'fast-deep-equal'
|
||||
|
||||
export const VersionInfo: React.FC = () => {
|
||||
const [show, setShow] = useState(false)
|
||||
|
@ -17,7 +18,7 @@ export const VersionInfo: React.FC = () => {
|
|||
|
||||
const { t } = useTranslation()
|
||||
|
||||
const serverVersion = useSelector((state: ApplicationState) => state.config.version)
|
||||
const serverVersion = useSelector((state: ApplicationState) => state.config.version, equal)
|
||||
|
||||
const column = (title: string, version: string, sourceCodeLink: string, issueTrackerLink: string) => (
|
||||
<Col md={6} className={'flex-column'}>
|
||||
|
|
|
@ -12,7 +12,7 @@ import './header-bar.scss'
|
|||
|
||||
const HeaderBar: React.FC = () => {
|
||||
useTranslation()
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
|
||||
return (
|
||||
<Navbar className="justify-content-between">
|
||||
|
@ -25,7 +25,7 @@ const HeaderBar: React.FC = () => {
|
|||
</HeaderNavLink>
|
||||
</div>
|
||||
<div className="d-inline-flex">
|
||||
{!user
|
||||
{!userExists
|
||||
? <Fragment>
|
||||
<span className={'mx-1 d-flex'}>
|
||||
<NewGuestNoteButton/>
|
||||
|
|
|
@ -13,9 +13,9 @@ type SignInButtonProps = {
|
|||
|
||||
export const SignInButton: React.FC<SignInButtonProps> = ({ variant, ...props }) => {
|
||||
const { t } = useTranslation()
|
||||
const authProviders = useSelector((state: ApplicationState) => state.config.authProviders)
|
||||
const anyAuthProviderActive = useSelector((state: ApplicationState) => Object.values(state.config.authProviders).includes(true))
|
||||
return (
|
||||
<ShowIf condition={Object.values(authProviders).includes(true)}>
|
||||
<ShowIf condition={anyAuthProviderActive}>
|
||||
<LinkContainer to="/login" title={t('login.signIn')}>
|
||||
<Button
|
||||
variant={variant || 'success'}
|
||||
|
|
|
@ -7,10 +7,11 @@ import { ApplicationState } from '../../../redux'
|
|||
import { clearUser } from '../../../redux/user/methods'
|
||||
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
|
||||
import { UserAvatar } from '../../common/user-avatar/user-avatar'
|
||||
import equal from 'fast-deep-equal'
|
||||
|
||||
export const UserDropdown: React.FC = () => {
|
||||
useTranslation()
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const user = useSelector((state: ApplicationState) => state.user, equal)
|
||||
|
||||
if (!user) {
|
||||
return null
|
||||
|
|
|
@ -9,12 +9,13 @@ import { ViaInternal } from './auth/via-internal'
|
|||
import { ViaLdap } from './auth/via-ldap'
|
||||
import { OneClickType, ViaOneClick } from './auth/via-one-click'
|
||||
import { ViaOpenId } from './auth/via-openid'
|
||||
|
||||
import equal from 'fast-deep-equal'
|
||||
export const LoginPage: React.FC = () => {
|
||||
useTranslation()
|
||||
const authProviders = useSelector((state: ApplicationState) => state.config.authProviders)
|
||||
const customAuthNames = useSelector((state: ApplicationState) => state.config.customAuthNames)
|
||||
const userLoginState = useSelector((state: ApplicationState) => state.user)
|
||||
const authProviders = useSelector((state: ApplicationState) => state.config.authProviders, equal)
|
||||
const customSamlAuthName = useSelector((state: ApplicationState) => state.config.customAuthNames.saml)
|
||||
const customOauthAuthName = useSelector((state: ApplicationState) => state.config.customAuthNames.oauth2)
|
||||
const userLoggedIn = useSelector((state: ApplicationState) => !!state.user)
|
||||
|
||||
const oneClickProviders = [authProviders.dropbox, authProviders.facebook, authProviders.github, authProviders.gitlab,
|
||||
authProviders.google, authProviders.oauth2, authProviders.saml, authProviders.twitter]
|
||||
|
@ -22,15 +23,15 @@ export const LoginPage: React.FC = () => {
|
|||
const oneClickCustomName: (type: OneClickType) => string | undefined = (type) => {
|
||||
switch (type) {
|
||||
case OneClickType.SAML:
|
||||
return customAuthNames.saml
|
||||
return customSamlAuthName
|
||||
case OneClickType.OAUTH2:
|
||||
return customAuthNames.oauth2
|
||||
return customOauthAuthName
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (userLoginState) {
|
||||
if (userLoggedIn) {
|
||||
// TODO Redirect to previous page?
|
||||
return (
|
||||
<Redirect to='/history'/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import equal from 'deep-equal'
|
||||
import equal from 'fast-deep-equal'
|
||||
import { DomElement } from 'domhandler'
|
||||
import emojiData from 'emoji-mart/data/twitter.json'
|
||||
import { Data } from 'emoji-mart/dist-es/utils/data'
|
||||
|
|
|
@ -10,9 +10,9 @@ import { ProfileChangePassword } from './settings/profile-change-password'
|
|||
import { ProfileDisplayName } from './settings/profile-display-name'
|
||||
|
||||
export const ProfilePage: React.FC = () => {
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userProvider = useSelector((state: ApplicationState) => state.user?.provider)
|
||||
|
||||
if (!user) {
|
||||
if (!userProvider) {
|
||||
return (
|
||||
<Redirect to={'/login'}/>
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ export const ProfilePage: React.FC = () => {
|
|||
<Row className="h-100 flex justify-content-center">
|
||||
<Col lg={6}>
|
||||
<ProfileDisplayName/>
|
||||
<ShowIf condition={user.provider === LoginProvider.INTERNAL}>
|
||||
<ShowIf condition={userProvider === LoginProvider.INTERNAL}>
|
||||
<ProfileChangePassword/>
|
||||
</ShowIf>
|
||||
<ProfileAccountManagement/>
|
||||
|
|
|
@ -9,18 +9,18 @@ import { getAndSetUser } from '../../login-page/auth/utils'
|
|||
export const ProfileDisplayName: React.FC = () => {
|
||||
const regexInvalidDisplayName = /^\s*$/
|
||||
const { t } = useTranslation()
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const userName = useSelector((state: ApplicationState) => state.user?.name)
|
||||
const [submittable, setSubmittable] = useState(false)
|
||||
const [error, setError] = useState(false)
|
||||
const [displayName, setDisplayName] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
setDisplayName(user.name)
|
||||
if (userName !== undefined) {
|
||||
setDisplayName(userName)
|
||||
}
|
||||
}, [user])
|
||||
}, [userName])
|
||||
|
||||
if (!user) {
|
||||
if (!userName) {
|
||||
return <Alert variant={'danger'}>User not logged in</Alert>
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@ export enum RegisterError {
|
|||
|
||||
export const RegisterPage: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const config = useSelector((state: ApplicationState) => state.config)
|
||||
const user = useSelector((state: ApplicationState) => state.user)
|
||||
const allowRegister = useSelector((state: ApplicationState) => state.config.allowRegister)
|
||||
const specialLinks = useSelector((state: ApplicationState) => state.config.specialLinks)
|
||||
const userExists = useSelector((state: ApplicationState) => !!state.user)
|
||||
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
@ -40,13 +41,13 @@ export const RegisterPage: React.FC = () => {
|
|||
setReady(username !== '' && password !== '' && password.length >= 8 && password === passwordAgain)
|
||||
}, [username, password, passwordAgain])
|
||||
|
||||
if (!config.allowRegister) {
|
||||
if (!allowRegister) {
|
||||
return (
|
||||
<Redirect to={'/login'}/>
|
||||
)
|
||||
}
|
||||
|
||||
if (user) {
|
||||
if (userExists) {
|
||||
return (
|
||||
<Redirect to={'/intro'}/>
|
||||
)
|
||||
|
@ -105,17 +106,17 @@ export const RegisterPage: React.FC = () => {
|
|||
required
|
||||
/>
|
||||
</Form.Group>
|
||||
<ShowIf condition={!!config.specialLinks?.termsOfUse || !!config.specialLinks?.privacy}>
|
||||
<ShowIf condition={!!specialLinks?.termsOfUse || !!specialLinks?.privacy}>
|
||||
<Trans i18nKey='login.register.infoTermsPrivacy'/>
|
||||
<ul>
|
||||
<ShowIf condition={!!config.specialLinks?.termsOfUse}>
|
||||
<ShowIf condition={!!specialLinks?.termsOfUse}>
|
||||
<li>
|
||||
<TranslatedExternalLink i18nKey='landing.footer.termsOfUse' href={config.specialLinks.termsOfUse}/>
|
||||
<TranslatedExternalLink i18nKey='landing.footer.termsOfUse' href={specialLinks.termsOfUse}/>
|
||||
</li>
|
||||
</ShowIf>
|
||||
<ShowIf condition={!!config.specialLinks?.privacy}>
|
||||
<ShowIf condition={!!specialLinks?.privacy}>
|
||||
<li>
|
||||
<TranslatedExternalLink i18nKey='landing.footer.privacy' href={config.specialLinks.privacy}/>
|
||||
<TranslatedExternalLink i18nKey='landing.footer.privacy' href={specialLinks.privacy}/>
|
||||
</li>
|
||||
</ShowIf>
|
||||
</ul>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue