@skroz/frontend 0.0.2

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.
Files changed (95) hide show
  1. package/LICENCE.md +21 -0
  2. package/dist/auth/Auth.d.ts +8 -0
  3. package/dist/auth/Auth.js +52 -0
  4. package/dist/auth/AuthFooterLinks.d.ts +4 -0
  5. package/dist/auth/AuthFooterLinks.js +26 -0
  6. package/dist/auth/Forgot.d.ts +7 -0
  7. package/dist/auth/Forgot.js +68 -0
  8. package/dist/auth/Login.d.ts +8 -0
  9. package/dist/auth/Login.js +65 -0
  10. package/dist/auth/LoginForm.d.ts +6 -0
  11. package/dist/auth/LoginForm.js +48 -0
  12. package/dist/auth/RecoverPassword.d.ts +2 -0
  13. package/dist/auth/RecoverPassword.js +96 -0
  14. package/dist/auth/Register.d.ts +8 -0
  15. package/dist/auth/Register.js +68 -0
  16. package/dist/auth/ResendLinkButton.d.ts +11 -0
  17. package/dist/auth/ResendLinkButton.js +50 -0
  18. package/dist/auth/index.d.ts +8 -0
  19. package/dist/auth/index.js +22 -0
  20. package/dist/graphql/ForgotPasswordMutation.graphql.d.ts +24 -0
  21. package/dist/graphql/ForgotPasswordMutation.graphql.js +76 -0
  22. package/dist/graphql/LoginMutation.graphql.d.ts +26 -0
  23. package/dist/graphql/LoginMutation.graphql.js +69 -0
  24. package/dist/graphql/RegisterMutation.graphql.d.ts +26 -0
  25. package/dist/graphql/RegisterMutation.graphql.js +69 -0
  26. package/dist/graphql/ResendLinkButtonMutation.graphql.d.ts +25 -0
  27. package/dist/graphql/ResendLinkButtonMutation.graphql.js +76 -0
  28. package/dist/graphql/index.d.ts +5 -0
  29. package/dist/graphql/index.js +16 -0
  30. package/dist/graphql/recoveryMutation.graphql.d.ts +19 -0
  31. package/dist/graphql/recoveryMutation.graphql.js +67 -0
  32. package/dist/index.d.ts +4 -0
  33. package/dist/index.js +20 -0
  34. package/dist/ui/AreYouSure.d.ts +10 -0
  35. package/dist/ui/AreYouSure.js +43 -0
  36. package/dist/ui/FormError.d.ts +3 -0
  37. package/dist/ui/FormError.js +15 -0
  38. package/dist/ui/FormItem.d.ts +12 -0
  39. package/dist/ui/FormItem.js +27 -0
  40. package/dist/ui/H.d.ts +16 -0
  41. package/dist/ui/H.js +39 -0
  42. package/dist/ui/Panel.d.ts +16 -0
  43. package/dist/ui/Panel.js +24 -0
  44. package/dist/ui/SeoHead.d.ts +13 -0
  45. package/dist/ui/SeoHead.js +14 -0
  46. package/dist/ui/index.d.ts +6 -0
  47. package/dist/ui/index.js +18 -0
  48. package/dist/utils/FrontendContext.d.ts +14 -0
  49. package/dist/utils/FrontendContext.js +30 -0
  50. package/dist/utils/getError.d.ts +11 -0
  51. package/dist/utils/getError.js +73 -0
  52. package/dist/utils/handleFormErrors.d.ts +15 -0
  53. package/dist/utils/handleFormErrors.js +62 -0
  54. package/dist/utils/index.d.ts +5 -0
  55. package/dist/utils/index.js +28 -0
  56. package/dist/utils/isObject.d.ts +2 -0
  57. package/dist/utils/isObject.js +6 -0
  58. package/dist/utils/limitExpiresAt.d.ts +3 -0
  59. package/dist/utils/limitExpiresAt.js +19 -0
  60. package/package.json +48 -0
  61. package/src/auth/Auth.tsx +76 -0
  62. package/src/auth/AuthFooterLinks.tsx +27 -0
  63. package/src/auth/Forgot.tsx +122 -0
  64. package/src/auth/Login.tsx +115 -0
  65. package/src/auth/LoginForm.tsx +74 -0
  66. package/src/auth/RecoverPassword.tsx +185 -0
  67. package/src/auth/Register.tsx +174 -0
  68. package/src/auth/ResendLinkButton.tsx +71 -0
  69. package/src/auth/index.ts +8 -0
  70. package/src/graphql/ForgotPasswordMutation.graphql.ts +100 -0
  71. package/src/graphql/LoginMutation.graphql.ts +95 -0
  72. package/src/graphql/RegisterMutation.graphql.ts +95 -0
  73. package/src/graphql/ResendLinkButtonMutation.graphql.ts +101 -0
  74. package/src/graphql/index.ts +5 -0
  75. package/src/graphql/recoveryMutation.graphql.ts +91 -0
  76. package/src/index.ts +4 -0
  77. package/src/locales/ru/common.json +271 -0
  78. package/src/styles/auth.less +142 -0
  79. package/src/styles/colors.less +55 -0
  80. package/src/styles/components.less +2 -0
  81. package/src/styles/panels.less +61 -0
  82. package/src/styles/sizes.less +92 -0
  83. package/src/ui/AreYouSure.tsx +55 -0
  84. package/src/ui/FormError.tsx +21 -0
  85. package/src/ui/FormItem.tsx +60 -0
  86. package/src/ui/H.tsx +76 -0
  87. package/src/ui/Panel.tsx +44 -0
  88. package/src/ui/SeoHead.tsx +69 -0
  89. package/src/ui/index.ts +6 -0
  90. package/src/utils/FrontendContext.tsx +30 -0
  91. package/src/utils/getError.ts +101 -0
  92. package/src/utils/handleFormErrors.ts +77 -0
  93. package/src/utils/index.ts +5 -0
  94. package/src/utils/isObject.ts +4 -0
  95. package/src/utils/limitExpiresAt.ts +14 -0
@@ -0,0 +1,122 @@
1
+ import React, { useCallback } from 'react';
2
+ import { Button, Form, Input, message } from 'antd';
3
+ import { useRouter } from 'next/router';
4
+ import { UserOutlined } from '@ant-design/icons';
5
+ import { useTranslation } from 'next-i18next';
6
+ import Link from 'next/link';
7
+ import { useExistingForm } from '@os-design/form';
8
+ import { graphql, useMutation } from 'react-relay';
9
+ import { setLimitExpiresAt } from '../utils/limitExpiresAt';
10
+ import handleFormErrors from '../utils/handleFormErrors';
11
+ import H from '../ui/H';
12
+ import { useFrontendConfig } from '../utils/FrontendContext';
13
+ import { RegisterInput } from '../graphql/RegisterMutation.graphql';
14
+ import {
15
+ ForgotPasswordMutation,
16
+ ForgotPasswordMutation$data,
17
+ } from '../graphql/ForgotPasswordMutation.graphql';
18
+ import FormItem from '../ui/FormItem';
19
+
20
+ interface ForgotProps {
21
+ onFinish: () => void;
22
+ onLoginClick?: () => void;
23
+ }
24
+
25
+ const Forgot: React.FC<ForgotProps> = ({ onFinish, onLoginClick }) => {
26
+ const { t } = useTranslation();
27
+ const router = useRouter();
28
+ const config = useFrontendConfig();
29
+
30
+ const { form, useValue, Field } = useExistingForm<RegisterInput>();
31
+ const email = useValue('email');
32
+
33
+ const [commit, loading] = useMutation<ForgotPasswordMutation>(
34
+ graphql`
35
+ mutation ForgotPasswordMutation($input: ForgotPasswordInput!) {
36
+ forgotPassword(input: $input) {
37
+ recoveryLinkIsSent
38
+ limitExpiresAt
39
+ }
40
+ }
41
+ `
42
+ );
43
+
44
+ const forgotPasswordHandler = useCallback(() => {
45
+ commit({
46
+ variables: {
47
+ input: {
48
+ email,
49
+ },
50
+ },
51
+ onError: (error) => handleFormErrors(form, error),
52
+ onCompleted: (res: ForgotPasswordMutation$data) => {
53
+ setLimitExpiresAt(res.forgotPassword.limitExpiresAt);
54
+ if (!res.forgotPassword.recoveryLinkIsSent)
55
+ message.error(t('common:auth.forgotSendError'));
56
+ router.push(`/recovery?email=${email}`);
57
+ onFinish();
58
+ },
59
+ });
60
+ }, [commit, email, form, onFinish, router, t]);
61
+
62
+ const loginButton = (
63
+ <Button type='link' onClick={onLoginClick} shape='round'>
64
+ {t('common:buttons.login')}
65
+ </Button>
66
+ );
67
+
68
+ return (
69
+ <div className='auth no-text-selection'>
70
+ <H type='h1' textAlign='center'>
71
+ {t('common:auth.forgotTitle')}
72
+ </H>
73
+ <div className='auth-subtitle'>
74
+ {t('common:auth.forgotSubtitle')}{' '}
75
+ {onLoginClick ? (
76
+ loginButton
77
+ ) : (
78
+ <Link href={config.loginPath || '/login'} passHref>
79
+ {loginButton}
80
+ </Link>
81
+ )}
82
+ </div>
83
+
84
+ <Form size='large'>
85
+ <Field
86
+ name='email'
87
+ render={({ value, onChange }: { value: string, onChange: (val: string) => void }, { error }: { error?: string }) => (
88
+ <FormItem error={error}>
89
+ <Input
90
+ value={value}
91
+ prefix={<UserOutlined />}
92
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value)}
93
+ placeholder='Email'
94
+ size='large'
95
+ />
96
+ </FormItem>
97
+ )}
98
+ />
99
+ </Form>
100
+
101
+ <div className='auth-button'>
102
+ <Button
103
+ type='primary'
104
+ shape='round'
105
+ size='large'
106
+ loading={loading}
107
+ onClick={forgotPasswordHandler}
108
+ >
109
+ {t('common:auth.forgotSendInstructions')}
110
+ </Button>
111
+ </div>
112
+
113
+ <div className='auth-footer'>
114
+ <div className='auth-footer-issues'>
115
+ {t('common:auth.forgotIssues')}
116
+ </div>
117
+ </div>
118
+ </div>
119
+ );
120
+ };
121
+
122
+ export default Forgot;
@@ -0,0 +1,115 @@
1
+ import React, { useCallback } from 'react';
2
+ import { Button, message } from 'antd';
3
+ import { useRouter } from 'next/router';
4
+ import { useTranslation } from 'next-i18next';
5
+ import Link from 'next/link';
6
+ import { graphql, useMutation } from 'react-relay';
7
+ import { useExistingForm } from '@os-design/form';
8
+ import {
9
+ RegisterInput,
10
+ LoginMutation,
11
+ LoginMutation$data,
12
+ } from '../graphql/LoginMutation.graphql';
13
+ import handleFormErrors from '../utils/handleFormErrors';
14
+ import AuthFooterLinks from './AuthFooterLinks';
15
+ import H from '../ui/H';
16
+ import { useFrontendConfig } from '../utils/FrontendContext';
17
+ import LoginForm from './LoginForm';
18
+
19
+ interface LoginProps {
20
+ onFinish: () => void;
21
+ isModal: boolean;
22
+ onForgotClick?: () => void;
23
+ }
24
+
25
+ const Login: React.FC<LoginProps> = ({ onFinish, onForgotClick, isModal }) => {
26
+ const { t } = useTranslation();
27
+ const router = useRouter();
28
+ const { form } = useExistingForm<RegisterInput>();
29
+ const config = useFrontendConfig();
30
+
31
+ const [commit, loading] = useMutation<LoginMutation>(
32
+ graphql`
33
+ mutation LoginMutation($input: RegisterInput!) {
34
+ login(input: $input) {
35
+ ok
36
+ }
37
+ }
38
+ `
39
+ );
40
+
41
+ const loginHandler = useCallback(() => {
42
+ commit({
43
+ variables: {
44
+ input: {
45
+ ...form.values.getAll(),
46
+ },
47
+ },
48
+ onError: (error) => {
49
+ handleFormErrors(form, error);
50
+ },
51
+ onCompleted: (res: LoginMutation$data) => {
52
+ if (!res.login.ok) {
53
+ message.error(t('common:auth.loginError'));
54
+ return;
55
+ }
56
+ onFinish();
57
+ message.success(t('common:auth.loginSuccess'));
58
+ router.reload();
59
+ },
60
+ });
61
+ }, [commit, form, router, onFinish, t]);
62
+
63
+ const forgotButton = (
64
+ <Button type='link' onClick={onForgotClick}>
65
+ {t('common:auth.forgot')}
66
+ </Button>
67
+ );
68
+ const registerButton = (
69
+ <Button type='link' shape='round' className='register-link'>
70
+ {t('common:buttons.register')}
71
+ </Button>
72
+ );
73
+
74
+ return (
75
+ <div className='auth no-text-selection'>
76
+ <H type='h1' textAlign='center'>
77
+ {t('common:auth.loginTitle')}
78
+ </H>
79
+ {!isModal && (
80
+ <div className='auth-subtitle'>
81
+ {t('common:auth.loginSubtitle')}{' '}
82
+ <Link href={config.registerPath || '/register'} passHref>
83
+ {registerButton}
84
+ </Link>
85
+ </div>
86
+ )}
87
+ <LoginForm onPressEnter={loginHandler} />
88
+ <div className='auth-button'>
89
+ <Button
90
+ type='primary'
91
+ shape='round'
92
+ size='large'
93
+ loading={loading}
94
+ onClick={loginHandler}
95
+ >
96
+ {t('common:buttons.login')}
97
+ </Button>
98
+ </div>
99
+ <div className='auth-footer'>
100
+ <div>
101
+ {onForgotClick ? (
102
+ forgotButton
103
+ ) : (
104
+ <Link href={config.forgotPasswordPath || '/forgot'} passHref>
105
+ {forgotButton}
106
+ </Link>
107
+ )}
108
+ </div>
109
+ <AuthFooterLinks />
110
+ </div>
111
+ </div>
112
+ );
113
+ };
114
+
115
+ export default Login;
@@ -0,0 +1,74 @@
1
+ import { Form, Input } from 'antd';
2
+ import React from 'react';
3
+ import { LockOutlined, UserOutlined } from '@ant-design/icons';
4
+ import { useTranslation } from 'next-i18next';
5
+ import { useExistingForm } from '@os-design/form';
6
+ import FormItem from '../ui/FormItem';
7
+ import { RegisterInput } from '../graphql/LoginMutation.graphql';
8
+ import FormError from '../ui/FormError';
9
+
10
+ interface LoginFormProps {
11
+ onPressEnter: () => void;
12
+ }
13
+
14
+ const LoginForm: React.FC<LoginFormProps> = ({ onPressEnter }) => {
15
+ const { t } = useTranslation();
16
+ const { Field } = useExistingForm<RegisterInput>();
17
+
18
+ return (
19
+ <Form size='large'>
20
+ <FormError />
21
+ <Field
22
+ name='email'
23
+ render={(
24
+ {
25
+ value,
26
+ onChange,
27
+ }: { value: string; onChange: (val: string) => void },
28
+ { error }: { error?: string }
29
+ ) => (
30
+ <FormItem error={error}>
31
+ <Input
32
+ prefix={<UserOutlined />}
33
+ value={value}
34
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
35
+ onChange(e.target.value)
36
+ }
37
+ onKeyDown={(e: React.KeyboardEvent) => {
38
+ if (e.key === 'Enter') onPressEnter();
39
+ }}
40
+ placeholder='Email'
41
+ />
42
+ </FormItem>
43
+ )}
44
+ />
45
+
46
+ <Field
47
+ name='password'
48
+ render={(
49
+ {
50
+ value,
51
+ onChange,
52
+ }: { value: string; onChange: (val: string) => void },
53
+ { error }: { error?: string }
54
+ ) => (
55
+ <FormItem error={error}>
56
+ <Input.Password
57
+ prefix={<LockOutlined />}
58
+ value={value}
59
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
60
+ onChange(e.target.value)
61
+ }
62
+ onKeyDown={(e: React.KeyboardEvent) => {
63
+ if (e.key === 'Enter') onPressEnter();
64
+ }}
65
+ placeholder={t('common:auth.passwordPlaceholder')}
66
+ />
67
+ </FormItem>
68
+ )}
69
+ />
70
+ </Form>
71
+ );
72
+ };
73
+
74
+ export default LoginForm;
@@ -0,0 +1,185 @@
1
+ import { Button, Form, Input, message } from 'antd';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useRouter } from 'next/router';
4
+ import { useTranslation } from 'next-i18next';
5
+ import { FormProvider, useForm } from '@os-design/form';
6
+ import { graphql, useMutation } from 'react-relay';
7
+ import Link from 'next/link';
8
+ import useInterval from '@os-design/use-interval';
9
+ import handleFormErrors from '../utils/handleFormErrors';
10
+ import { useFrontendConfig } from '../utils/FrontendContext';
11
+ import {
12
+ RecoverPasswordInput,
13
+ recoveryMutation,
14
+ } from '../graphql/recoveryMutation.graphql';
15
+ import H from '../ui/H';
16
+ import Panel from '../ui/Panel';
17
+ import FormItem from '../ui/FormItem';
18
+ import FormError from '../ui/FormError';
19
+ import ResendLinkButton from './ResendLinkButton';
20
+ import { ResendLinkButtonMutation$data } from '../graphql/ResendLinkButtonMutation.graphql';
21
+ import { getLimitExpiresIn, setLimitExpiresAt } from '../utils/limitExpiresAt';
22
+
23
+ const RecoverPassword = () => {
24
+ const router = useRouter();
25
+ const { t } = useTranslation(['common']);
26
+ const config = useFrontendConfig();
27
+
28
+ let { email } = router.query;
29
+ if (typeof email !== 'string' || !email) email = '';
30
+
31
+ const { form, Field } = useForm<RecoverPasswordInput>({
32
+ token: '',
33
+ password: '',
34
+ });
35
+
36
+ const [commit, loading] = useMutation<recoveryMutation>(
37
+ graphql`
38
+ mutation recoveryMutation($input: RecoverPasswordInput!) {
39
+ recoverPassword(input: $input) {
40
+ ok
41
+ }
42
+ }
43
+ `
44
+ );
45
+
46
+ const recoverPasswordHandler = useCallback(() => {
47
+ commit({
48
+ variables: {
49
+ input: {
50
+ ...form.values.getAll(),
51
+ },
52
+ },
53
+ onError: (error) => handleFormErrors(form, error),
54
+ onCompleted: () => {
55
+ message.success(t('common:auth.recoverySuccess'));
56
+ const profilePath = config.defaultPath
57
+ ? `${config.defaultPath === '/' ? '' : config.defaultPath}/profile`
58
+ : '/profile';
59
+ router.push(profilePath);
60
+ },
61
+ });
62
+ }, [commit, form, router, t, config.defaultPath]);
63
+
64
+ const [limitExpiresIn, setLimitExpiresIn] = useState(0);
65
+
66
+ // Update limitExpiresIn
67
+ const updateLimitExpiresIn = useCallback(
68
+ () => setLimitExpiresIn(getLimitExpiresIn()),
69
+ []
70
+ );
71
+ useEffect(updateLimitExpiresIn, [updateLimitExpiresIn]); // Initial update
72
+ useInterval(updateLimitExpiresIn, limitExpiresIn > 0 ? 1000 : null); // Update every second
73
+
74
+ const resendIsDenied = limitExpiresIn > 0;
75
+
76
+ const getResendButtonTitle = () => {
77
+ if (resendIsDenied) {
78
+ return `${t('common:auth.openEmailResendDenied')} ${Math.ceil(
79
+ limitExpiresIn / 1000
80
+ )} ${t('common:sec')}`;
81
+ }
82
+ return t('common:auth.openEmailResend');
83
+ };
84
+
85
+ return (
86
+ <div className='recovery'>
87
+ <div className='recovery-header'>
88
+ {t('common:auth.setNewPassword')}
89
+ </div>
90
+
91
+ {email.length > 0 ? (
92
+ <>
93
+ <div style={{ color: 'red', marginBottom: 15 }}>
94
+ {t('common:auth.findCodeOnEmail')}
95
+ </div>
96
+ <FormProvider form={form}>
97
+ <Form layout='vertical' size='large'>
98
+ <FormError />
99
+ <Field
100
+ name='token'
101
+ render={({ value, onChange }: { value: string, onChange: (val: string) => void }, { error }: { error?: string }) => (
102
+ <FormItem
103
+ label='Код из письма'
104
+ error={error}
105
+ style={{ marginBottom: 0 }}
106
+ >
107
+ <Input
108
+ placeholder='------'
109
+ value={value}
110
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value)}
111
+ />
112
+ </FormItem>
113
+ )}
114
+ />
115
+ <div style={{ marginBottom: 25 }}>
116
+ <ResendLinkButton
117
+ email={email}
118
+ type='recovery'
119
+ disabled={resendIsDenied}
120
+ onError={(error: any) => handleFormErrors(form, error)}
121
+ onCompleted={(res: ResendLinkButtonMutation$data) => {
122
+ setLimitExpiresAt(res.resendLink.limitExpiresAt);
123
+ setLimitExpiresIn(getLimitExpiresIn());
124
+
125
+ // Отображаем сообщение
126
+ if (res.resendLink.ok)
127
+ message.success(t('common:auth.openEmailResendOk'));
128
+ else
129
+ message.error(t('common:auth.openEmailResendError'));
130
+ }}
131
+ >
132
+ {getResendButtonTitle()}
133
+ </ResendLinkButton>
134
+ </div>
135
+
136
+ <Panel bg='secondary'>
137
+ <Field
138
+ name='password'
139
+ render={({ value, onChange }: { value: string, onChange: (val: string) => void }, { error }: { error?: string }) => (
140
+ <FormItem
141
+ label={t('common:auth.setNewPassword')}
142
+ error={error}
143
+ >
144
+ <Input.Password
145
+ value={value}
146
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value)}
147
+ placeholder={t('common:auth.newPassword')}
148
+ />
149
+ </FormItem>
150
+ )}
151
+ />
152
+ <Button
153
+ loading={loading}
154
+ onClick={recoverPasswordHandler}
155
+ type='primary'
156
+ >
157
+ {t('common:auth.saveNewPassword')}
158
+ </Button>
159
+ </Panel>
160
+ </Form>
161
+ </FormProvider>
162
+ </>
163
+ ) : (
164
+ <>
165
+ <H
166
+ type='h2'
167
+ subHeader='Вы перешли на эту страницу с неверными параметрами, вернитесь назад, чтобы исправить ошибку'
168
+ textAlign='center'
169
+ >
170
+ Ошибочные параметры
171
+ </H>
172
+ <div style={{ textAlign: 'center' }}>
173
+ <Link href={config.forgotPasswordPath || '/forgot'}>
174
+ <Button type='primary' shape='round' size='large'>
175
+ Вернуться назад
176
+ </Button>
177
+ </Link>
178
+ </div>
179
+ </>
180
+ )}
181
+ </div>
182
+ );
183
+ };
184
+
185
+ export default RecoverPassword;
@@ -0,0 +1,174 @@
1
+ import React, { useCallback } from 'react';
2
+ import { Button, Checkbox, message } from 'antd';
3
+ import { useRouter } from 'next/router';
4
+ import { useTranslation } from 'next-i18next';
5
+ import Link from 'next/link';
6
+ import { useExistingForm } from '@os-design/form';
7
+ import { graphql, useMutation } from 'react-relay';
8
+ import handleFormErrors from '../utils/handleFormErrors';
9
+ import AuthFooterLinks from './AuthFooterLinks';
10
+ import H from '../ui/H';
11
+ import { useFrontendConfig } from '../utils/FrontendContext';
12
+ import {
13
+ RegisterInput,
14
+ RegisterMutation,
15
+ } from '../graphql/RegisterMutation.graphql';
16
+ import LoginForm from './LoginForm';
17
+ import FormItem from '../ui/FormItem';
18
+
19
+ interface RegisterProps {
20
+ onFinish: () => void;
21
+ isModal: boolean;
22
+ onForgotClick?: () => void;
23
+ }
24
+
25
+ const Register: React.FC<RegisterProps> = ({
26
+ onFinish,
27
+ isModal,
28
+ onForgotClick,
29
+ }) => {
30
+ const { t } = useTranslation();
31
+ const router = useRouter();
32
+ const config = useFrontendConfig();
33
+
34
+ const { form, Field } = useExistingForm<RegisterInput>();
35
+
36
+ const [commit, loading] = useMutation<RegisterMutation>(
37
+ graphql`
38
+ mutation RegisterMutation($input: RegisterInput!) {
39
+ register(input: $input) {
40
+ ok
41
+ }
42
+ }
43
+ `
44
+ );
45
+
46
+ const registerHandler = useCallback(() => {
47
+ commit({
48
+ variables: {
49
+ input: {
50
+ ...form.values.getAll(),
51
+ },
52
+ },
53
+ onError: (error) => handleFormErrors(form, error),
54
+ onCompleted: () => {
55
+ onFinish();
56
+ router.push(config.defaultPath || '/');
57
+ message.success(t('common:auth.successRegister'));
58
+ },
59
+ });
60
+ }, [commit, form, onFinish, router, t, config.defaultPath]);
61
+
62
+ const forgotButton = (
63
+ <Button type='link' onClick={onForgotClick}>
64
+ {t('common:auth.forgot')}
65
+ </Button>
66
+ );
67
+ const loginButton = (
68
+ <Button type='link' shape='round'>
69
+ {t('common:buttons.login')}
70
+ </Button>
71
+ );
72
+
73
+ return (
74
+ <div className='auth no-text-selection'>
75
+ <H type='h1' textAlign='center'>
76
+ {t('common:auth.registerTitle')}
77
+ </H>
78
+ {!isModal && (
79
+ <div className='auth-subtitle'>
80
+ {t('common:auth.registerSubtitle')}{' '}
81
+ <Link href={config.loginPath || '/login'} passHref>
82
+ {loginButton}
83
+ </Link>
84
+ </div>
85
+ )}
86
+
87
+ {/* Форма входа и регистрации одинаковые */}
88
+ <LoginForm onPressEnter={registerHandler} />
89
+
90
+ <div>
91
+ <Field
92
+ name='isUserAgreementAgree'
93
+ render={(
94
+ {
95
+ value,
96
+ onChange,
97
+ }: {
98
+ value: boolean | null | undefined;
99
+ onChange: (val: boolean | null | undefined) => void;
100
+ },
101
+ { error }: { error?: string }
102
+ ) => (
103
+ <FormItem error={error} style={{ marginBottom: 0 }}>
104
+ <Checkbox
105
+ style={{ fontSize: '16px' }}
106
+ checked={value || false}
107
+ onChange={(e: any) => onChange(e.target.checked)}
108
+ >
109
+ {t('common:auth.acceptUserAgreement')}{' '}
110
+ <Link href='/docs/user-agreement'>
111
+ {t('common:links.userAgreement')}
112
+ </Link>
113
+ </Checkbox>
114
+ </FormItem>
115
+ )}
116
+ />
117
+
118
+ <Field
119
+ name='isPrivacyPolicyAgree'
120
+ render={(
121
+ {
122
+ value,
123
+ onChange,
124
+ }: {
125
+ value: boolean | null | undefined;
126
+ onChange: (val: boolean | null | undefined) => void;
127
+ },
128
+ { error }: { error?: string }
129
+ ) => (
130
+ <FormItem error={error}>
131
+ <Checkbox
132
+ checked={value || false}
133
+ onChange={(e: any) => onChange(e.target.checked)}
134
+ style={{ fontSize: '16px' }}
135
+ >
136
+ {t('common:auth.acceptPrivacyPolicy')}{' '}
137
+ <Link href='/docs/privacy-policy'>
138
+ {t('common:links.privacyPolicy')}
139
+ </Link>
140
+ </Checkbox>
141
+ </FormItem>
142
+ )}
143
+ />
144
+ </div>
145
+
146
+ <div className='auth-button'>
147
+ <Button
148
+ type='primary'
149
+ shape='round'
150
+ size='large'
151
+ loading={loading}
152
+ onClick={registerHandler}
153
+ >
154
+ {t('common:buttons.register')}
155
+ </Button>
156
+ </div>
157
+
158
+ <div className='auth-footer'>
159
+ <div>
160
+ {onForgotClick ? (
161
+ forgotButton
162
+ ) : (
163
+ <Link href={config.forgotPasswordPath || '/forgot'} passHref>
164
+ {forgotButton}
165
+ </Link>
166
+ )}
167
+ </div>
168
+ <AuthFooterLinks />
169
+ </div>
170
+ </div>
171
+ );
172
+ };
173
+
174
+ export default Register;