mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-23 11:37:02 -04:00
feat(auth): refactor auth, add oidc
Some checks are pending
Docker / build-and-push (frontend) (push) Waiting to run
Docker / build-and-push (backend) (push) Waiting to run
Deploy HD2 docs to Netlify / Deploys to netlify (push) Waiting to run
E2E Tests / backend-sqlite (push) Waiting to run
E2E Tests / backend-mariadb (push) Waiting to run
E2E Tests / backend-postgres (push) Waiting to run
E2E Tests / Build test build of frontend (push) Waiting to run
E2E Tests / frontend-cypress (1) (push) Blocked by required conditions
E2E Tests / frontend-cypress (2) (push) Blocked by required conditions
E2E Tests / frontend-cypress (3) (push) Blocked by required conditions
Lint and check format / Lint files and check formatting (push) Waiting to run
REUSE Compliance Check / reuse (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Static Analysis / Njsscan code scanning (push) Waiting to run
Static Analysis / CodeQL analysis (push) Waiting to run
Run tests & build / Test and build with NodeJS 20 (push) Waiting to run
Some checks are pending
Docker / build-and-push (frontend) (push) Waiting to run
Docker / build-and-push (backend) (push) Waiting to run
Deploy HD2 docs to Netlify / Deploys to netlify (push) Waiting to run
E2E Tests / backend-sqlite (push) Waiting to run
E2E Tests / backend-mariadb (push) Waiting to run
E2E Tests / backend-postgres (push) Waiting to run
E2E Tests / Build test build of frontend (push) Waiting to run
E2E Tests / frontend-cypress (1) (push) Blocked by required conditions
E2E Tests / frontend-cypress (2) (push) Blocked by required conditions
E2E Tests / frontend-cypress (3) (push) Blocked by required conditions
Lint and check format / Lint files and check formatting (push) Waiting to run
REUSE Compliance Check / reuse (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Static Analysis / Njsscan code scanning (push) Waiting to run
Static Analysis / CodeQL analysis (push) Waiting to run
Run tests & build / Test and build with NodeJS 20 (push) Waiting to run
Thanks to all HedgeDoc team members for the time discussing, helping with weird Nest issues, providing feedback and suggestions! Co-authored-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
1609f3e01f
commit
7f665fae4b
109 changed files with 2927 additions and 1700 deletions
124
frontend/src/components/login-page/new-user/new-user-card.tsx
Normal file
124
frontend/src/components/login-page/new-user/new-user-card.tsx
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Button, Card, Form } from 'react-bootstrap'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { useAsync } from 'react-use'
|
||||
import { cancelPendingUser, confirmPendingUser, getPendingUserInfo } from '../../../api/auth/pending-user'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useUiNotifications } from '../../notifications/ui-notification-boundary'
|
||||
import { UsernameLabelField } from '../../common/fields/username-label-field'
|
||||
import { DisplayNameField } from '../../common/fields/display-name-field'
|
||||
import { ProfilePictureChoice, ProfilePictureSelectField } from '../../common/fields/profile-picture-select-field'
|
||||
import { useOnInputChange } from '../../../hooks/common/use-on-input-change'
|
||||
import { fetchAndSetUser } from '../utils/fetch-and-set-user'
|
||||
|
||||
/**
|
||||
* The card where a new user can enter their user information.
|
||||
*/
|
||||
export const NewUserCard: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const { showErrorNotification } = useUiNotifications()
|
||||
const { value, error, loading } = useAsync(getPendingUserInfo, [])
|
||||
const [username, setUsername] = useState('')
|
||||
const [displayName, setDisplayName] = useState('')
|
||||
const [pictureChoice, setPictureChoice] = useState(ProfilePictureChoice.FALLBACK)
|
||||
const [isUsernameSubmittable, setIsUsernameSubmittable] = useState(false)
|
||||
const [isDisplayNameSubmittable, setIsDisplayNameSubmittable] = useState(false)
|
||||
|
||||
const isSubmittable = useMemo(() => {
|
||||
return isUsernameSubmittable && isDisplayNameSubmittable
|
||||
}, [isUsernameSubmittable, isDisplayNameSubmittable])
|
||||
|
||||
const onChangeUsername = useOnInputChange(setUsername)
|
||||
const onChangeDisplayName = useOnInputChange(setDisplayName)
|
||||
|
||||
const submitUserdata = useCallback(() => {
|
||||
confirmPendingUser({
|
||||
username,
|
||||
displayName,
|
||||
profilePicture: pictureChoice === ProfilePictureChoice.PROVIDER ? value?.photoUrl : undefined
|
||||
})
|
||||
.then(() => fetchAndSetUser())
|
||||
.then(() => {
|
||||
router.push('/')
|
||||
})
|
||||
.catch(showErrorNotification('login.welcome.error'))
|
||||
}, [username, displayName, pictureChoice, router, showErrorNotification, value?.photoUrl])
|
||||
|
||||
const cancelUserCreation = useCallback(() => {
|
||||
cancelPendingUser()
|
||||
.catch(showErrorNotification('login.welcome.cancelError'))
|
||||
.finally(() => {
|
||||
router.push('/login')
|
||||
})
|
||||
}, [router, showErrorNotification])
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
showErrorNotification('login.welcome.error')(error)
|
||||
router.push('/login')
|
||||
}
|
||||
}, [error, router, showErrorNotification])
|
||||
|
||||
useEffect(() => {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
setUsername(value.username ?? '')
|
||||
setDisplayName(value.displayName ?? '')
|
||||
if (value.photoUrl) {
|
||||
setPictureChoice(ProfilePictureChoice.PROVIDER)
|
||||
}
|
||||
}, [value])
|
||||
|
||||
if (!value && !loading) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card.Body>
|
||||
{loading && <p>Loading...</p>}
|
||||
<Card.Title>
|
||||
{displayName !== '' ? (
|
||||
<Trans i18nKey={'login.welcome.title'} values={{ name: displayName }} />
|
||||
) : (
|
||||
<Trans i18nKey={'login.welcome.titleFallback'} />
|
||||
)}
|
||||
</Card.Title>
|
||||
<Trans i18nKey={'login.welcome.description'} />
|
||||
<hr />
|
||||
<Form onSubmit={submitUserdata} className={'d-flex flex-column gap-3'}>
|
||||
<DisplayNameField
|
||||
onChange={onChangeDisplayName}
|
||||
value={displayName}
|
||||
onValidityChange={setIsDisplayNameSubmittable}
|
||||
/>
|
||||
<UsernameLabelField
|
||||
onChange={onChangeUsername}
|
||||
value={username}
|
||||
onValidityChange={setIsUsernameSubmittable}
|
||||
/>
|
||||
<ProfilePictureSelectField
|
||||
onChange={setPictureChoice}
|
||||
value={pictureChoice}
|
||||
pictureUrl={value?.photoUrl}
|
||||
username={username}
|
||||
/>
|
||||
<div className={'d-flex gap-3'}>
|
||||
<Button variant={'secondary'} type={'button'} className={'w-50'} onClick={cancelUserCreation}>
|
||||
<Trans i18nKey={'common.cancel'} />
|
||||
</Button>
|
||||
<Button variant={'success'} type={'submit'} className={'w-50'} disabled={!isSubmittable}>
|
||||
<Trans i18nKey={'common.continue'} />
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue