sforkowany z mirror/soapbox
Merge branch 'add-login-form-to-navbar' into 'develop'
Add login form to navbar See merge request soapbox-pub/soapbox-fe!1368set-dependency-scanning-config-1
commit
87dccd79ae
|
@ -19,7 +19,7 @@ const useButtonStyles = ({
|
|||
}: IButtonStyles) => {
|
||||
const themes = {
|
||||
primary:
|
||||
'border-transparent text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2',
|
||||
'border-primary-600 text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2',
|
||||
secondary:
|
||||
'border-transparent text-primary-700 bg-primary-100 hover:bg-primary-200 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2',
|
||||
ghost: 'shadow-none border-gray-200 text-gray-700 bg-white dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2',
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
[data-reach-tooltip] {
|
||||
@apply pointer-events-none absolute px-2.5 py-1.5 rounded shadow whitespace-nowrap text-xs font-medium bg-gray-800 text-white;
|
||||
z-index: 1;
|
||||
z-index: 100;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, Redirect } from 'react-router-dom';
|
||||
|
||||
import { logIn, verifyCredentials } from 'soapbox/actions/auth';
|
||||
import { fetchInstance } from 'soapbox/actions/instance';
|
||||
import SiteLogo from 'soapbox/components/site-logo';
|
||||
import { Avatar, Button } from 'soapbox/components/ui';
|
||||
import { Avatar, Button, Form, IconButton, Input, Tooltip } from 'soapbox/components/ui';
|
||||
import Search from 'soapbox/features/compose/components/search';
|
||||
import { useOwnAccount, useSoapboxConfig } from 'soapbox/hooks';
|
||||
|
||||
|
@ -13,16 +16,56 @@ import { openSidebar } from '../../../actions/sidebar';
|
|||
|
||||
import ProfileDropdown from './profile-dropdown';
|
||||
|
||||
const messages = defineMessages({
|
||||
login: { id: 'navbar.login.action', defaultMessage: 'Log in' },
|
||||
username: { id: 'navbar.login.username.placeholder', defaultMessage: 'Email or username' },
|
||||
password: { id: 'navbar.login.password.label', defaultMessage: 'Password' },
|
||||
forgotPassword: { id: 'navbar.login.forgot_password', defaultMessage: 'Forgot password?' },
|
||||
});
|
||||
|
||||
const Navbar = () => {
|
||||
const dispatch = useDispatch();
|
||||
const node = React.useRef(null);
|
||||
const intl = useIntl();
|
||||
|
||||
const node = useRef(null);
|
||||
|
||||
const account = useOwnAccount();
|
||||
const soapboxConfig = useSoapboxConfig();
|
||||
const singleUserMode = soapboxConfig.get('singleUserMode');
|
||||
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const [username, setUsername] = useState<string>('');
|
||||
const [password, setPassword] = useState<string>('');
|
||||
const [mfaToken, setMfaToken] = useState<boolean>(false);
|
||||
|
||||
const onOpenSidebar = () => dispatch(openSidebar());
|
||||
|
||||
const handleSubmit: React.FormEventHandler = (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
dispatch(logIn(intl, username, password) as any)
|
||||
.then(({ access_token }: { access_token: string }) => {
|
||||
setLoading(false);
|
||||
|
||||
return (
|
||||
dispatch(verifyCredentials(access_token) as any)
|
||||
// Refetch the instance for authenticated fetch
|
||||
.then(() => dispatch(fetchInstance()))
|
||||
);
|
||||
})
|
||||
.catch((error: AxiosError) => {
|
||||
setLoading(false);
|
||||
|
||||
const data: any = error.response?.data;
|
||||
if (data?.error === 'mfa_required') {
|
||||
setMfaToken(data.mfa_token);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (mfaToken) return <Redirect to={`/login?token=${encodeURIComponent(mfaToken)}`} />;
|
||||
|
||||
return (
|
||||
<nav className='bg-white dark:bg-slate-800 shadow z-50 sticky top-0' ref={node}>
|
||||
<div className='max-w-7xl mx-auto px-2 sm:px-6 lg:px-8'>
|
||||
|
@ -64,17 +107,57 @@ const Navbar = () => {
|
|||
</ProfileDropdown>
|
||||
</div>
|
||||
) : (
|
||||
<div className='space-x-1.5'>
|
||||
<Button theme='secondary' to='/login' size='sm'>
|
||||
<FormattedMessage id='account.login' defaultMessage='Log In' />
|
||||
</Button>
|
||||
<>
|
||||
<Form className='hidden lg:flex space-x-2 items-center' onSubmit={handleSubmit}>
|
||||
<Input
|
||||
required
|
||||
value={username}
|
||||
onChange={(event) => setUsername(event.target.value)}
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(messages.username)}
|
||||
className='max-w-[200px]'
|
||||
/>
|
||||
|
||||
{!singleUserMode && (
|
||||
<Button theme='primary' to='/signup' size='sm'>
|
||||
<FormattedMessage id='account.register' defaultMessage='Sign up' />
|
||||
<Input
|
||||
required
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
type='password'
|
||||
placeholder={intl.formatMessage(messages.password)}
|
||||
className='max-w-[200px]'
|
||||
/>
|
||||
|
||||
<Link to='/reset-password'>
|
||||
<Tooltip text={intl.formatMessage(messages.forgotPassword)}>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/icons/help.svg')}
|
||||
className='bg-transparent text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-200 cursor-pointer'
|
||||
iconClassName='w-5 h-5'
|
||||
/>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
|
||||
<Button
|
||||
theme='primary'
|
||||
type='submit'
|
||||
disabled={isLoading}
|
||||
>
|
||||
{intl.formatMessage(messages.login)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<div className='space-x-1.5 lg:hidden'>
|
||||
<Button theme='secondary' to='/login' size='sm'>
|
||||
<FormattedMessage id='account.login' defaultMessage='Log In' />
|
||||
</Button>
|
||||
|
||||
{!singleUserMode && (
|
||||
<Button theme='primary' to='/signup' size='sm'>
|
||||
<FormattedMessage id='account.register' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@ import { dismissAlert } from '../../../actions/alerts';
|
|||
import { getAlerts } from '../../../selectors';
|
||||
|
||||
const CustomNotificationStack = (props) => (
|
||||
<div role='assertive' data-testid='toast' className='z-1000 fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 sm:items-start'>
|
||||
<div role='assertive' data-testid='toast' className='z-1000 fixed inset-0 flex items-end px-4 py-6 pointer-events-none pt-16 lg:pt-20 sm:items-start'>
|
||||
<NotificationStack {...props} />
|
||||
</div>
|
||||
);
|
||||
|
|
Ładowanie…
Reference in New Issue