@skroz/frontend 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/Auth.js +19 -36
- package/dist/auth/AuthButtons.d.ts +18 -0
- package/dist/auth/AuthButtons.js +29 -0
- package/dist/auth/AuthFooterLinks.js +9 -25
- package/dist/auth/AuthModal.d.ts +9 -0
- package/dist/auth/AuthModal.js +5 -0
- package/dist/auth/Forgot.js +47 -59
- package/dist/auth/Login.js +33 -48
- package/dist/auth/LoginForm.js +18 -47
- package/dist/auth/LogoutButton.d.ts +3 -0
- package/dist/auth/LogoutButton.js +39 -0
- package/dist/auth/RecoverPassword.js +64 -80
- package/dist/auth/Register.js +47 -55
- package/dist/auth/ResendLinkButton.d.ts +3 -3
- package/dist/auth/ResendLinkButton.js +39 -40
- package/dist/auth/__tests__/Login.test.d.ts +1 -0
- package/dist/auth/__tests__/Login.test.js +75 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +11 -22
- package/dist/graphql/ForgotMutation.graphql.d.ts +2 -2
- package/dist/graphql/ForgotMutation.graphql.js +5 -7
- package/dist/graphql/LoginMutation.graphql.d.ts +5 -5
- package/dist/graphql/LoginMutation.graphql.js +6 -8
- package/dist/graphql/LogoutButtonMutation.graphql.d.ts +18 -0
- package/dist/graphql/LogoutButtonMutation.graphql.js +55 -0
- package/dist/graphql/RecoverPasswordMutation.graphql.d.ts +2 -2
- package/dist/graphql/RecoverPasswordMutation.graphql.js +5 -7
- package/dist/graphql/RegisterMutation.graphql.d.ts +7 -6
- package/dist/graphql/RegisterMutation.graphql.js +15 -10
- package/dist/graphql/ResendLinkButtonMutation.graphql.d.ts +2 -2
- package/dist/graphql/ResendLinkButtonMutation.graphql.js +5 -7
- package/dist/index.d.ts +0 -1
- package/dist/index.js +3 -20
- package/dist/ui/AreYouSure.js +9 -23
- package/dist/ui/FormError.js +9 -14
- package/dist/ui/FormItem.js +8 -22
- package/dist/ui/H.d.ts +1 -1
- package/dist/ui/H.js +15 -32
- package/dist/ui/Panel.d.ts +1 -1
- package/dist/ui/Panel.js +6 -23
- package/dist/ui/SeoHead.js +7 -13
- package/dist/ui/index.js +6 -18
- package/dist/utils/FrontendContext.js +6 -25
- package/dist/utils/getError.js +12 -20
- package/dist/utils/handleFormErrors.js +20 -29
- package/dist/utils/index.js +5 -28
- package/dist/utils/isObject.js +2 -6
- package/dist/utils/limitExpiresAt.js +9 -12
- package/package.json +8 -6
- package/src/auth/Auth.tsx +2 -2
- package/src/auth/AuthButtons.tsx +119 -0
- package/src/auth/AuthModal.tsx +28 -0
- package/src/auth/Forgot.tsx +29 -22
- package/src/auth/Login.tsx +25 -10
- package/src/auth/LoginForm.tsx +4 -4
- package/src/auth/LogoutButton.tsx +53 -0
- package/src/auth/RecoverPassword.tsx +34 -24
- package/src/auth/Register.tsx +29 -13
- package/src/auth/ResendLinkButton.tsx +34 -23
- package/src/auth/__tests__/Login.test.tsx +99 -0
- package/src/auth/index.ts +3 -0
- package/src/graphql/ForgotMutation.graphql.ts +77 -77
- package/src/graphql/LoginMutation.graphql.ts +73 -73
- package/src/graphql/LogoutButtonMutation.graphql.ts +74 -0
- package/src/graphql/RecoverPasswordMutation.graphql.ts +70 -74
- package/src/graphql/RegisterMutation.graphql.ts +81 -73
- package/src/graphql/ResendLinkButtonMutation.graphql.ts +77 -77
- package/src/index.ts +0 -1
- package/src/ui/H.tsx +1 -1
- package/src/ui/Panel.tsx +1 -1
- package/src/utils/limitExpiresAt.ts +3 -1
- package/dist/graphql/index.d.ts +0 -5
- package/dist/graphql/index.js +0 -16
- package/src/graphql/index.ts +0 -5
package/src/auth/LoginForm.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { LockOutlined, UserOutlined } from '@ant-design/icons';
|
|
|
4
4
|
import { useTranslation } from 'next-i18next';
|
|
5
5
|
import { useExistingForm } from '@os-design/form';
|
|
6
6
|
import FormItem from '../ui/FormItem';
|
|
7
|
-
import {
|
|
7
|
+
import { AuthInput } from '../graphql/LoginMutation.graphql';
|
|
8
8
|
import FormError from '../ui/FormError';
|
|
9
9
|
|
|
10
10
|
interface LoginFormProps {
|
|
@@ -12,8 +12,8 @@ interface LoginFormProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const LoginForm: React.FC<LoginFormProps> = ({ onPressEnter }) => {
|
|
15
|
-
const { t } = useTranslation();
|
|
16
|
-
const { Field } = useExistingForm<
|
|
15
|
+
const { t } = useTranslation('common');
|
|
16
|
+
const { Field } = useExistingForm<AuthInput>();
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<Form size='large'>
|
|
@@ -62,7 +62,7 @@ const LoginForm: React.FC<LoginFormProps> = ({ onPressEnter }) => {
|
|
|
62
62
|
onKeyDown={(e: React.KeyboardEvent) => {
|
|
63
63
|
if (e.key === 'Enter') onPressEnter();
|
|
64
64
|
}}
|
|
65
|
-
placeholder={t('
|
|
65
|
+
placeholder={t('auth.passwordPlaceholder')}
|
|
66
66
|
/>
|
|
67
67
|
</FormItem>
|
|
68
68
|
)}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { Button, message } from 'antd';
|
|
3
|
+
import { useRouter } from 'next/router';
|
|
4
|
+
import { useMutation } from 'react-relay';
|
|
5
|
+
import { LogoutOutlined } from '@ant-design/icons';
|
|
6
|
+
import getError from '../utils/getError';
|
|
7
|
+
import LogoutButtonMutationNode, {
|
|
8
|
+
LogoutButtonMutation,
|
|
9
|
+
} from '../graphql/LogoutButtonMutation.graphql';
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
SKROZ_PROTECTION NOTE:
|
|
13
|
+
The Relay compiler has generated artifacts for this mutation.
|
|
14
|
+
Explicit import of LogoutButtonMutationNode is used.
|
|
15
|
+
|
|
16
|
+
Mutation definition (for reference/regeneration):
|
|
17
|
+
graphql`
|
|
18
|
+
mutation LogoutButtonMutation {
|
|
19
|
+
logout {
|
|
20
|
+
ok
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const LogoutButton: React.FC = () => {
|
|
27
|
+
const router = useRouter();
|
|
28
|
+
|
|
29
|
+
const [commit] = useMutation<LogoutButtonMutation>(LogoutButtonMutationNode);
|
|
30
|
+
|
|
31
|
+
const logoutHandler = useCallback(() => {
|
|
32
|
+
commit({
|
|
33
|
+
variables: {},
|
|
34
|
+
onError: (error) => {
|
|
35
|
+
message.error(getError(error).message);
|
|
36
|
+
},
|
|
37
|
+
onCompleted: () => {
|
|
38
|
+
router.reload();
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}, [commit, router]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Button
|
|
45
|
+
shape="circle"
|
|
46
|
+
onClick={logoutHandler}
|
|
47
|
+
icon={<LogoutOutlined />}
|
|
48
|
+
type="link"
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default LogoutButton;
|
|
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useState } from 'react';
|
|
|
3
3
|
import { useRouter } from 'next/router';
|
|
4
4
|
import { useTranslation } from 'next-i18next';
|
|
5
5
|
import { FormProvider, useForm } from '@os-design/form';
|
|
6
|
-
import {
|
|
6
|
+
import { useMutation } from 'react-relay';
|
|
7
7
|
import Link from 'next/link';
|
|
8
8
|
import useInterval from '@os-design/use-interval';
|
|
9
9
|
import handleFormErrors from '../utils/handleFormErrors';
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
RecoverPasswordInput,
|
|
13
13
|
RecoverPasswordMutation,
|
|
14
14
|
} from '../graphql/RecoverPasswordMutation.graphql';
|
|
15
|
+
import RecoverPasswordMutationNode from '../graphql/RecoverPasswordMutation.graphql';
|
|
15
16
|
import H from '../ui/H';
|
|
16
17
|
import Panel from '../ui/Panel';
|
|
17
18
|
import FormItem from '../ui/FormItem';
|
|
@@ -21,7 +22,7 @@ import { getLimitExpiresIn, setLimitExpiresAt } from '../utils/limitExpiresAt';
|
|
|
21
22
|
|
|
22
23
|
const RecoverPassword = () => {
|
|
23
24
|
const router = useRouter();
|
|
24
|
-
const { t } = useTranslation(
|
|
25
|
+
const { t } = useTranslation('common');
|
|
25
26
|
const config = useFrontendConfig();
|
|
26
27
|
|
|
27
28
|
let { email } = router.query;
|
|
@@ -32,13 +33,22 @@ const RecoverPassword = () => {
|
|
|
32
33
|
password: '',
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`
|
|
36
|
+
/*
|
|
37
|
+
SKROZ_PROTECTION NOTE:
|
|
38
|
+
The Relay compiler has generated artifacts for this mutation.
|
|
39
|
+
Explicit import of RecoverPasswordMutationNode is used.
|
|
40
|
+
|
|
41
|
+
Mutation definition (for reference/regeneration):
|
|
42
|
+
graphql`
|
|
43
|
+
mutation RecoverPasswordMutation($input: RecoverPasswordInput!) {
|
|
44
|
+
recoverPassword(input: $input) {
|
|
45
|
+
ok
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
const [commit, loading] = useMutation<RecoverPasswordMutation>(RecoverPasswordMutationNode);
|
|
42
52
|
|
|
43
53
|
const recoverPasswordHandler = useCallback(() => {
|
|
44
54
|
commit({
|
|
@@ -49,7 +59,7 @@ const RecoverPassword = () => {
|
|
|
49
59
|
},
|
|
50
60
|
onError: (error) => handleFormErrors(form, error),
|
|
51
61
|
onCompleted: () => {
|
|
52
|
-
message.success(t('
|
|
62
|
+
message.success(t('auth.recoverySuccess'));
|
|
53
63
|
const profilePath = config.defaultPath
|
|
54
64
|
? `${config.defaultPath === '/' ? '' : config.defaultPath}/profile`
|
|
55
65
|
: '/profile';
|
|
@@ -72,21 +82,21 @@ const RecoverPassword = () => {
|
|
|
72
82
|
|
|
73
83
|
const getResendButtonTitle = () => {
|
|
74
84
|
if (resendIsDenied) {
|
|
75
|
-
return `${t('
|
|
85
|
+
return `${t('auth.openEmailResendDenied')} ${Math.ceil(
|
|
76
86
|
limitExpiresIn / 1000
|
|
77
|
-
)} ${t('
|
|
87
|
+
)} ${t('sec')}`;
|
|
78
88
|
}
|
|
79
|
-
return t('
|
|
89
|
+
return t('auth.openEmailResend');
|
|
80
90
|
};
|
|
81
91
|
|
|
82
92
|
return (
|
|
83
93
|
<div className='recovery'>
|
|
84
|
-
<div className='recovery-header'>{t('
|
|
94
|
+
<div className='recovery-header'>{t('auth.setNewPassword')}</div>
|
|
85
95
|
|
|
86
96
|
{email.length > 0 ? (
|
|
87
97
|
<>
|
|
88
98
|
<div style={{ color: 'red', marginBottom: 15 }}>
|
|
89
|
-
{t('
|
|
99
|
+
{t('auth.findCodeOnEmail')}
|
|
90
100
|
</div>
|
|
91
101
|
<FormProvider form={form}>
|
|
92
102
|
<Form layout='vertical' size='large'>
|
|
@@ -101,7 +111,7 @@ const RecoverPassword = () => {
|
|
|
101
111
|
{ error }: { error?: string }
|
|
102
112
|
) => (
|
|
103
113
|
<FormItem
|
|
104
|
-
label={t('
|
|
114
|
+
label={t('auth.setNewCodeLabel')}
|
|
105
115
|
error={error}
|
|
106
116
|
style={{ marginBottom: 0 }}
|
|
107
117
|
>
|
|
@@ -126,8 +136,8 @@ const RecoverPassword = () => {
|
|
|
126
136
|
|
|
127
137
|
// Отображаем сообщение
|
|
128
138
|
if (res.resendLink.ok)
|
|
129
|
-
message.success(t('
|
|
130
|
-
else message.error(t('
|
|
139
|
+
message.success(t('auth.openEmailResendOk'));
|
|
140
|
+
else message.error(t('auth.openEmailResendError'));
|
|
131
141
|
}}
|
|
132
142
|
>
|
|
133
143
|
{getResendButtonTitle()}
|
|
@@ -145,7 +155,7 @@ const RecoverPassword = () => {
|
|
|
145
155
|
{ error }: { error?: string }
|
|
146
156
|
) => (
|
|
147
157
|
<FormItem
|
|
148
|
-
label={t('
|
|
158
|
+
label={t('auth.setNewPassword')}
|
|
149
159
|
error={error}
|
|
150
160
|
>
|
|
151
161
|
<Input.Password
|
|
@@ -153,7 +163,7 @@ const RecoverPassword = () => {
|
|
|
153
163
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
154
164
|
onChange(e.target.value)
|
|
155
165
|
}
|
|
156
|
-
placeholder={t('
|
|
166
|
+
placeholder={t('auth.newPassword')}
|
|
157
167
|
/>
|
|
158
168
|
</FormItem>
|
|
159
169
|
)}
|
|
@@ -163,7 +173,7 @@ const RecoverPassword = () => {
|
|
|
163
173
|
onClick={recoverPasswordHandler}
|
|
164
174
|
type='primary'
|
|
165
175
|
>
|
|
166
|
-
{t('
|
|
176
|
+
{t('auth.saveNewPassword')}
|
|
167
177
|
</Button>
|
|
168
178
|
</Panel>
|
|
169
179
|
</Form>
|
|
@@ -173,15 +183,15 @@ const RecoverPassword = () => {
|
|
|
173
183
|
<>
|
|
174
184
|
<H
|
|
175
185
|
type='h2'
|
|
176
|
-
subHeader={t('
|
|
186
|
+
subHeader={t('auth.wrongParamsSubtitle')}
|
|
177
187
|
textAlign='center'
|
|
178
188
|
>
|
|
179
|
-
{t('
|
|
189
|
+
{t('auth.wrongParamsTitle')}
|
|
180
190
|
</H>
|
|
181
191
|
<div style={{ textAlign: 'center' }}>
|
|
182
192
|
<Link href={config.forgotPasswordPath || '/forgot'}>
|
|
183
193
|
<Button type='primary' shape='round' size='large'>
|
|
184
|
-
{t('
|
|
194
|
+
{t('auth.goBack')}
|
|
185
195
|
</Button>
|
|
186
196
|
</Link>
|
|
187
197
|
</div>
|
package/src/auth/Register.tsx
CHANGED
|
@@ -10,8 +10,8 @@ import AuthFooterLinks from './AuthFooterLinks';
|
|
|
10
10
|
import H from '../ui/H';
|
|
11
11
|
import { useFrontendConfig } from '../utils/FrontendContext';
|
|
12
12
|
import RegisterMutationNode, {
|
|
13
|
-
RegisterInput,
|
|
14
13
|
RegisterMutation,
|
|
14
|
+
AuthInput,
|
|
15
15
|
} from '../graphql/RegisterMutation.graphql';
|
|
16
16
|
import LoginForm from './LoginForm';
|
|
17
17
|
import FormItem from '../ui/FormItem';
|
|
@@ -27,11 +27,27 @@ const Register: React.FC<RegisterProps> = ({
|
|
|
27
27
|
isModal,
|
|
28
28
|
onForgotClick,
|
|
29
29
|
}) => {
|
|
30
|
-
const { t } = useTranslation();
|
|
30
|
+
const { t } = useTranslation('common');
|
|
31
31
|
const router = useRouter();
|
|
32
32
|
const config = useFrontendConfig();
|
|
33
33
|
|
|
34
|
-
const { form, Field } = useExistingForm<
|
|
34
|
+
const { form, Field } = useExistingForm<AuthInput>();
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
SKROZ_PROTECTION NOTE:
|
|
38
|
+
The Relay compiler has generated artifacts for this mutation.
|
|
39
|
+
Explicit import of RegisterMutationNode is used.
|
|
40
|
+
|
|
41
|
+
Mutation definition (for reference/regeneration):
|
|
42
|
+
graphql`
|
|
43
|
+
mutation RegisterMutation($input: AuthInput!) {
|
|
44
|
+
register(input: $input) {
|
|
45
|
+
id
|
|
46
|
+
email
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
*/
|
|
35
51
|
|
|
36
52
|
const [commit, loading] = useMutation<RegisterMutation>(RegisterMutationNode);
|
|
37
53
|
|
|
@@ -46,30 +62,30 @@ const Register: React.FC<RegisterProps> = ({
|
|
|
46
62
|
onCompleted: () => {
|
|
47
63
|
onFinish();
|
|
48
64
|
router.push(config.defaultPath || '/');
|
|
49
|
-
message.success(t('
|
|
65
|
+
message.success(t('auth.successRegister'));
|
|
50
66
|
},
|
|
51
67
|
});
|
|
52
68
|
}, [commit, form, onFinish, router, t, config.defaultPath]);
|
|
53
69
|
|
|
54
70
|
const forgotButton = (
|
|
55
71
|
<Button type='link' onClick={onForgotClick}>
|
|
56
|
-
{t('
|
|
72
|
+
{t('auth.forgot')}
|
|
57
73
|
</Button>
|
|
58
74
|
);
|
|
59
75
|
const loginButton = (
|
|
60
76
|
<Button type='link' shape='round'>
|
|
61
|
-
{t('
|
|
77
|
+
{t('buttons.login')}
|
|
62
78
|
</Button>
|
|
63
79
|
);
|
|
64
80
|
|
|
65
81
|
return (
|
|
66
82
|
<div className='auth no-text-selection'>
|
|
67
83
|
<H type='h1' textAlign='center'>
|
|
68
|
-
{t('
|
|
84
|
+
{t('auth.registerTitle')}
|
|
69
85
|
</H>
|
|
70
86
|
{!isModal && (
|
|
71
87
|
<div className='auth-subtitle'>
|
|
72
|
-
{t('
|
|
88
|
+
{t('auth.registerSubtitle')}{' '}
|
|
73
89
|
<Link href={config.loginPath || '/login'} passHref>
|
|
74
90
|
{loginButton}
|
|
75
91
|
</Link>
|
|
@@ -98,9 +114,9 @@ const Register: React.FC<RegisterProps> = ({
|
|
|
98
114
|
checked={value || false}
|
|
99
115
|
onChange={(e: any) => onChange(e.target.checked)}
|
|
100
116
|
>
|
|
101
|
-
{t('
|
|
117
|
+
{t('auth.acceptUserAgreement')}{' '}
|
|
102
118
|
<Link href='/docs/user-agreement'>
|
|
103
|
-
{t('
|
|
119
|
+
{t('links.userAgreement')}
|
|
104
120
|
</Link>
|
|
105
121
|
</Checkbox>
|
|
106
122
|
</FormItem>
|
|
@@ -125,9 +141,9 @@ const Register: React.FC<RegisterProps> = ({
|
|
|
125
141
|
onChange={(e: any) => onChange(e.target.checked)}
|
|
126
142
|
style={{ fontSize: '16px' }}
|
|
127
143
|
>
|
|
128
|
-
{t('
|
|
144
|
+
{t('auth.acceptPrivacyPolicy')}{' '}
|
|
129
145
|
<Link href='/docs/privacy-policy'>
|
|
130
|
-
{t('
|
|
146
|
+
{t('links.privacyPolicy')}
|
|
131
147
|
</Link>
|
|
132
148
|
</Checkbox>
|
|
133
149
|
</FormItem>
|
|
@@ -143,7 +159,7 @@ const Register: React.FC<RegisterProps> = ({
|
|
|
143
159
|
loading={loading}
|
|
144
160
|
onClick={registerHandler}
|
|
145
161
|
>
|
|
146
|
-
{t('
|
|
162
|
+
{t('buttons.register')}
|
|
147
163
|
</Button>
|
|
148
164
|
</div>
|
|
149
165
|
|
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useMutation } from 'react-relay';
|
|
3
3
|
import { Button, message } from 'antd';
|
|
4
4
|
import { useTranslation } from 'next-i18next';
|
|
5
|
-
import {
|
|
5
|
+
import ResendLinkButtonMutationNode, {
|
|
6
6
|
ResendLinkButtonMutation,
|
|
7
7
|
} from '../graphql/ResendLinkButtonMutation.graphql';
|
|
8
8
|
|
|
9
9
|
interface ResendLinkButtonProps {
|
|
10
10
|
email: string;
|
|
11
|
-
|
|
11
|
+
onCompleted?: (res: any) => void;
|
|
12
|
+
onError?: (error: any) => void;
|
|
12
13
|
disabled?: boolean;
|
|
13
|
-
|
|
14
|
-
onError: (res: any) => void;
|
|
14
|
+
children: React.ReactNode;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const ResendLinkButton: React.FC<ResendLinkButtonProps> = ({
|
|
18
18
|
email,
|
|
19
|
-
children,
|
|
20
|
-
disabled,
|
|
21
19
|
onCompleted,
|
|
22
20
|
onError,
|
|
21
|
+
disabled,
|
|
22
|
+
children,
|
|
23
23
|
}) => {
|
|
24
|
-
const { t } = useTranslation();
|
|
24
|
+
const { t } = useTranslation('common');
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
/*
|
|
27
|
+
SKROZ_PROTECTION NOTE:
|
|
28
|
+
The Relay compiler has generated artifacts for this mutation.
|
|
29
|
+
Explicit import of ResendLinkButtonMutationNode is used.
|
|
30
|
+
|
|
31
|
+
Mutation definition (for reference/regeneration):
|
|
32
|
+
graphql`
|
|
33
|
+
mutation ResendLinkButtonMutation($input: SendTokenInput!) {
|
|
34
|
+
sendToken(input: $input) {
|
|
35
|
+
codeIsSent
|
|
36
|
+
limitExpiresAt
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
const [commit, loading] = useMutation<ResendLinkButtonMutation>(ResendLinkButtonMutationNode);
|
|
34
43
|
|
|
35
44
|
const resendLinkHandler = useCallback(() => {
|
|
36
45
|
if (!email) {
|
|
37
|
-
message.error(t('
|
|
46
|
+
message.error(t('error.emailNotProvided'));
|
|
38
47
|
return;
|
|
39
48
|
}
|
|
40
49
|
commit({
|
|
@@ -45,12 +54,14 @@ const ResendLinkButton: React.FC<ResendLinkButtonProps> = ({
|
|
|
45
54
|
},
|
|
46
55
|
onError,
|
|
47
56
|
onCompleted: (res: any) => {
|
|
48
|
-
onCompleted
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
if (onCompleted) {
|
|
58
|
+
onCompleted({
|
|
59
|
+
resendLink: {
|
|
60
|
+
ok: res.sendToken.codeIsSent,
|
|
61
|
+
limitExpiresAt: res.sendToken.limitExpiresAt,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
54
65
|
},
|
|
55
66
|
});
|
|
56
67
|
}, [commit, email, onCompleted, onError, t]);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { useRouter } from 'next/router';
|
|
4
|
+
import { useMutation } from 'react-relay';
|
|
5
|
+
import { useExistingForm } from '@os-design/form';
|
|
6
|
+
import Login from '../Login';
|
|
7
|
+
|
|
8
|
+
// Mocking dependencies with verified relative paths
|
|
9
|
+
jest.mock('next/router', () => ({
|
|
10
|
+
useRouter: jest.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock('next/link', () => ({
|
|
14
|
+
__esModule: true,
|
|
15
|
+
default: ({ children, href }: any) => <a href={href}>{children}</a>,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
jest.mock('next-i18next', () => ({
|
|
19
|
+
useTranslation: () => ({
|
|
20
|
+
t: (key: string) => key,
|
|
21
|
+
}),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('antd', () => ({
|
|
25
|
+
Button: ({ children, onClick }: any) => <button onClick={onClick}>{children}</button>,
|
|
26
|
+
message: {
|
|
27
|
+
success: jest.fn(),
|
|
28
|
+
error: jest.fn(),
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
jest.mock('react-relay', () => ({
|
|
33
|
+
useMutation: jest.fn(),
|
|
34
|
+
graphql: jest.fn(),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
jest.mock('../../graphql/LoginMutation.graphql', () => ({
|
|
38
|
+
__esModule: true,
|
|
39
|
+
default: {},
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
jest.mock('@os-design/form', () => ({
|
|
43
|
+
useExistingForm: jest.fn(),
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
jest.mock('../../ui/H', () => ({ children }: { children: React.ReactNode }) => <h1>{children}</h1>);
|
|
47
|
+
jest.mock('../LoginForm', () => () => <div data-testid="login-form" />);
|
|
48
|
+
jest.mock('../AuthFooterLinks', () => () => <div data-testid="auth-footer-links" />);
|
|
49
|
+
jest.mock('../../utils/FrontendContext', () => ({
|
|
50
|
+
useFrontendConfig: () => ({
|
|
51
|
+
loginPath: '/login',
|
|
52
|
+
registerPath: '/register',
|
|
53
|
+
forgotPasswordPath: '/forgot',
|
|
54
|
+
defaultPath: '/',
|
|
55
|
+
}),
|
|
56
|
+
}));
|
|
57
|
+
jest.mock('../../utils/handleFormErrors', () => jest.fn());
|
|
58
|
+
|
|
59
|
+
describe('Login Component', () => {
|
|
60
|
+
const mockOnFinish = jest.fn();
|
|
61
|
+
const mockOnForgotClick = jest.fn();
|
|
62
|
+
const mockCommit = jest.fn();
|
|
63
|
+
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
(useRouter as jest.Mock).mockReturnValue({
|
|
66
|
+
reload: jest.fn(),
|
|
67
|
+
});
|
|
68
|
+
(useMutation as jest.Mock).mockReturnValue([mockCommit, false]);
|
|
69
|
+
(useExistingForm as jest.Mock).mockReturnValue({
|
|
70
|
+
form: {
|
|
71
|
+
values: {
|
|
72
|
+
getAll: jest.fn().mockReturnValue({}),
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should render the login title', () => {
|
|
79
|
+
const { getByText } = render(
|
|
80
|
+
<Login
|
|
81
|
+
onFinish={mockOnFinish}
|
|
82
|
+
onForgotClick={mockOnForgotClick}
|
|
83
|
+
isModal={false}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
expect(getByText('common:auth.loginTitle')).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should render the login form', () => {
|
|
90
|
+
const { getByTestId } = render(
|
|
91
|
+
<Login
|
|
92
|
+
onFinish={mockOnFinish}
|
|
93
|
+
onForgotClick={mockOnForgotClick}
|
|
94
|
+
isModal={false}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
expect(getByTestId('login-form')).toBeDefined();
|
|
98
|
+
});
|
|
99
|
+
});
|
package/src/auth/index.ts
CHANGED
|
@@ -6,3 +6,6 @@ export { default as RecoverPassword } from './RecoverPassword';
|
|
|
6
6
|
export { default as AuthFooterLinks } from './AuthFooterLinks';
|
|
7
7
|
export { default as LoginForm } from './LoginForm';
|
|
8
8
|
export { default as ResendLinkButton } from './ResendLinkButton';
|
|
9
|
+
export { default as LogoutButton } from './LogoutButton';
|
|
10
|
+
export { default as AuthModal } from './AuthModal';
|
|
11
|
+
export { default as AuthButtons } from './AuthButtons';
|