@alfalab/core-components-confirmation 12.5.2 → 13.0.0
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/component.desktop.d.ts +1 -1
- package/component.desktop.js +5 -3
- package/component.mobile.js +6 -4
- package/component.responsive.d.ts +2 -3
- package/component.responsive.js +9 -9
- package/components/base-confirmation/component.js +9 -6
- package/components/base-confirmation/index.css +2 -2
- package/components/base-confirmation/index.js +5 -3
- package/components/countdown-loader/component.js +1 -1
- package/components/countdown-loader/index.css +2 -2
- package/components/header/component.js +1 -1
- package/components/header/index.css +4 -4
- package/components/index.js +5 -3
- package/components/screens/fatal-error/component.js +3 -3
- package/components/screens/fatal-error/index.css +6 -6
- package/components/screens/hint/component.js +3 -3
- package/components/screens/hint/index.css +12 -12
- package/components/screens/index.js +5 -3
- package/components/screens/initial/component.js +12 -9
- package/components/screens/initial/countdown-section.js +1 -1
- package/components/screens/initial/index.css +17 -20
- package/components/screens/initial/index.js +5 -3
- package/components/screens/temp-block/component.js +1 -1
- package/components/screens/temp-block/index.css +7 -7
- package/context.js +1 -0
- package/{countdown-section-41f47745.js → countdown-section-fb6524aa.js} +3 -3
- package/cssm/component.desktop.d.ts +1 -1
- package/cssm/component.desktop.js +4 -2
- package/cssm/component.mobile.js +4 -2
- package/cssm/component.responsive.d.ts +2 -3
- package/cssm/component.responsive.js +8 -8
- package/cssm/components/base-confirmation/component.js +7 -4
- package/cssm/components/base-confirmation/index.js +4 -2
- package/cssm/components/index.js +4 -2
- package/cssm/components/screens/fatal-error/component.js +2 -2
- package/cssm/components/screens/hint/component.js +2 -2
- package/cssm/components/screens/index.js +4 -2
- package/cssm/components/screens/initial/component.js +11 -8
- package/cssm/components/screens/initial/countdown-section.js +2 -2
- package/cssm/components/screens/initial/index.js +4 -2
- package/cssm/components/screens/initial/index.module.css +0 -3
- package/cssm/context.js +1 -0
- package/cssm/desktop.d.ts +1 -1
- package/cssm/desktop.js +7 -3
- package/cssm/index.d.ts +2 -6
- package/cssm/index.js +18 -26
- package/cssm/mobile.d.ts +1 -1
- package/cssm/mobile.js +7 -3
- package/cssm/shared.d.ts +4 -0
- package/cssm/shared.js +43 -0
- package/cssm/types.d.ts +11 -0
- package/desktop.d.ts +1 -1
- package/desktop.js +8 -4
- package/esm/component.desktop.d.ts +1 -1
- package/esm/component.desktop.js +5 -3
- package/esm/component.mobile.js +6 -4
- package/esm/component.responsive.d.ts +2 -3
- package/esm/component.responsive.js +9 -9
- package/esm/components/base-confirmation/component.js +9 -6
- package/esm/components/base-confirmation/index.css +2 -2
- package/esm/components/base-confirmation/index.js +5 -3
- package/esm/components/countdown-loader/component.js +1 -1
- package/esm/components/countdown-loader/index.css +2 -2
- package/esm/components/header/component.js +1 -1
- package/esm/components/header/index.css +4 -4
- package/esm/components/index.js +5 -3
- package/esm/components/screens/fatal-error/component.js +3 -3
- package/esm/components/screens/fatal-error/index.css +6 -6
- package/esm/components/screens/hint/component.js +3 -3
- package/esm/components/screens/hint/index.css +12 -12
- package/esm/components/screens/index.js +5 -3
- package/esm/components/screens/initial/component.js +8 -5
- package/esm/components/screens/initial/countdown-section.js +1 -1
- package/esm/components/screens/initial/index.css +17 -20
- package/esm/components/screens/initial/index.js +5 -3
- package/esm/components/screens/temp-block/component.js +1 -1
- package/esm/components/screens/temp-block/index.css +7 -7
- package/esm/context.js +1 -0
- package/esm/{countdown-section-83bf5f20.js → countdown-section-c65cff2d.js} +3 -3
- package/esm/desktop.d.ts +1 -1
- package/esm/desktop.js +6 -4
- package/esm/index.d.ts +2 -6
- package/esm/index.js +17 -14
- package/esm/mobile.css +2 -2
- package/esm/mobile.d.ts +1 -1
- package/esm/mobile.js +6 -4
- package/esm/shared.d.ts +4 -0
- package/esm/shared.js +20 -0
- package/esm/types.d.ts +11 -0
- package/index.d.ts +2 -6
- package/index.js +16 -24
- package/mobile.css +2 -2
- package/mobile.d.ts +1 -1
- package/mobile.js +8 -4
- package/modern/component.desktop.d.ts +1 -1
- package/modern/component.desktop.js +5 -3
- package/modern/component.mobile.js +6 -4
- package/modern/component.responsive.d.ts +2 -3
- package/modern/component.responsive.js +9 -9
- package/modern/components/base-confirmation/component.js +8 -5
- package/modern/components/base-confirmation/index.css +2 -2
- package/modern/components/base-confirmation/index.js +5 -3
- package/modern/components/countdown-loader/component.js +1 -1
- package/modern/components/countdown-loader/index.css +2 -2
- package/modern/components/header/component.js +1 -1
- package/modern/components/header/index.css +4 -4
- package/modern/components/index.js +5 -3
- package/modern/components/screens/fatal-error/component.js +3 -3
- package/modern/components/screens/fatal-error/index.css +6 -6
- package/modern/components/screens/hint/component.js +3 -3
- package/modern/components/screens/hint/index.css +12 -12
- package/modern/components/screens/index.js +5 -3
- package/modern/components/screens/initial/component.js +8 -5
- package/modern/components/screens/initial/countdown-section.js +1 -1
- package/modern/components/screens/initial/index.css +17 -20
- package/modern/components/screens/initial/index.js +5 -3
- package/modern/components/screens/temp-block/component.js +1 -1
- package/modern/components/screens/temp-block/index.css +7 -7
- package/modern/context.js +1 -0
- package/modern/{countdown-section-a28d693c.js → countdown-section-dd4e5fe3.js} +3 -3
- package/modern/desktop.d.ts +1 -1
- package/modern/desktop.js +6 -4
- package/modern/index.d.ts +2 -6
- package/modern/index.js +17 -14
- package/modern/mobile.css +2 -2
- package/modern/mobile.d.ts +1 -1
- package/modern/mobile.js +6 -4
- package/modern/shared.d.ts +4 -0
- package/modern/shared.js +20 -0
- package/modern/types.d.ts +11 -0
- package/package.json +31 -6
- package/shared.d.ts +4 -0
- package/shared.js +37 -0
- package/src/component.desktop.tsx +10 -0
- package/src/component.mobile.tsx +13 -0
- package/src/component.responsive.tsx +31 -0
- package/src/components/base-confirmation/component.tsx +123 -0
- package/src/components/base-confirmation/index.module.css +8 -0
- package/src/components/base-confirmation/index.ts +1 -0
- package/src/components/countdown-loader/component.tsx +37 -0
- package/src/components/countdown-loader/index.module.css +7 -0
- package/src/components/countdown-loader/index.ts +1 -0
- package/src/components/header/component.tsx +28 -0
- package/src/components/header/index.module.css +21 -0
- package/src/components/header/index.ts +1 -0
- package/src/components/index.ts +2 -0
- package/src/components/screens/fatal-error/component.tsx +46 -0
- package/src/components/screens/fatal-error/index.module.css +23 -0
- package/src/components/screens/fatal-error/index.ts +1 -0
- package/src/components/screens/hint/component.tsx +94 -0
- package/src/components/screens/hint/index.module.css +51 -0
- package/src/components/screens/hint/index.ts +1 -0
- package/src/components/screens/index.ts +4 -0
- package/src/components/screens/initial/component.tsx +190 -0
- package/src/components/screens/initial/countdown-section.tsx +79 -0
- package/src/components/screens/initial/index.module.css +71 -0
- package/src/components/screens/initial/index.ts +1 -0
- package/src/components/screens/temp-block/component.tsx +58 -0
- package/src/components/screens/temp-block/index.module.css +28 -0
- package/src/components/screens/temp-block/index.ts +1 -0
- package/src/context.ts +26 -0
- package/src/desktop.ts +3 -0
- package/src/index.ts +6 -0
- package/src/mobile.module.css +3 -0
- package/src/mobile.ts +3 -0
- package/src/shared.ts +4 -0
- package/src/types.ts +219 -0
- package/src/utils.ts +107 -0
- package/src/vars.css +33 -0
- package/types.d.ts +11 -0
- package/cssm/responsive.d.ts +0 -2
- package/cssm/responsive.js +0 -39
- package/esm/responsive.d.ts +0 -2
- package/esm/responsive.js +0 -23
- package/modern/responsive.d.ts +0 -2
- package/modern/responsive.js +0 -22
- package/responsive.d.ts +0 -2
- package/responsive.js +0 -31
- /package/{countdown-section-41f47745.d.ts → countdown-section-fb6524aa.d.ts} +0 -0
- /package/esm/{countdown-section-83bf5f20.d.ts → countdown-section-c65cff2d.d.ts} +0 -0
- /package/modern/{countdown-section-a28d693c.d.ts → countdown-section-dd4e5fe3.d.ts} +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { FC, useContext } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
|
|
4
|
+
import { Button } from '@alfalab/core-components-button';
|
|
5
|
+
import { Link } from '@alfalab/core-components-link';
|
|
6
|
+
import { Typography } from '@alfalab/core-components-typography';
|
|
7
|
+
|
|
8
|
+
import { ConfirmationContext } from '../../../context';
|
|
9
|
+
import { Header } from '../../header';
|
|
10
|
+
|
|
11
|
+
import styles from './index.module.css';
|
|
12
|
+
|
|
13
|
+
export type HintProps = {
|
|
14
|
+
/**
|
|
15
|
+
* Отображать в мобильной версии экран компонента
|
|
16
|
+
*/
|
|
17
|
+
mobile?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const Hint: FC<HintProps> = ({ mobile }) => {
|
|
21
|
+
const { alignContent, texts, onChangeScreen, onChangeState, breakpoint } =
|
|
22
|
+
useContext(ConfirmationContext);
|
|
23
|
+
|
|
24
|
+
const handleReturnButtonClick = () => {
|
|
25
|
+
onChangeScreen('INITIAL');
|
|
26
|
+
onChangeState('INITIAL');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className={cn(styles.component, styles[alignContent])}>
|
|
31
|
+
<Header mobile={mobile}>Не приходит сообщение?</Header>
|
|
32
|
+
|
|
33
|
+
<Typography.Text
|
|
34
|
+
view='primary-medium'
|
|
35
|
+
color='primary'
|
|
36
|
+
className={cn(styles.text, { [styles.typographyTheme]: !mobile })}
|
|
37
|
+
>
|
|
38
|
+
Если у вас изменился номер телефона, позвоните нам или обратитесь в любое
|
|
39
|
+
отделение банка.
|
|
40
|
+
</Typography.Text>
|
|
41
|
+
|
|
42
|
+
<div className={styles.phonesWrap}>
|
|
43
|
+
<div className={cn(styles.phoneWrap, { [styles.phoneContentMobile]: mobile })}>
|
|
44
|
+
<Link href='tel:+78002000000' underline={false} className={styles.phoneLink}>
|
|
45
|
+
8 800 200-00-00
|
|
46
|
+
</Link>
|
|
47
|
+
<Typography.Text
|
|
48
|
+
view='primary-medium'
|
|
49
|
+
color='primary'
|
|
50
|
+
className={cn(styles.text, { [styles.typographyTheme]: !mobile })}
|
|
51
|
+
>
|
|
52
|
+
{mobile
|
|
53
|
+
? 'Для\u00A0звонков по\u00A0России'
|
|
54
|
+
: ' \u2014\u00A0для звонков по\u00A0России'}
|
|
55
|
+
</Typography.Text>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className={cn(styles.phoneWrap, { [styles.phoneContentMobile]: mobile })}>
|
|
59
|
+
<Link href='tel:+74957888878' underline={false} className={styles.phoneLink}>
|
|
60
|
+
+7 495 78-888-78
|
|
61
|
+
</Link>
|
|
62
|
+
<Typography.Text
|
|
63
|
+
view='primary-medium'
|
|
64
|
+
color='primary'
|
|
65
|
+
className={cn(styles.text, { [styles.typographyTheme]: !mobile })}
|
|
66
|
+
>
|
|
67
|
+
{mobile
|
|
68
|
+
? 'В\u00A0Москве и\u00A0за\u00A0границей'
|
|
69
|
+
: ' \u2014\u00A0в\u00A0Москве и\u00A0за\u00A0границей'}
|
|
70
|
+
</Typography.Text>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<Typography.Text
|
|
75
|
+
view='primary-medium'
|
|
76
|
+
color='primary'
|
|
77
|
+
className={cn(styles.text, { [styles.typographyTheme]: !mobile })}
|
|
78
|
+
>
|
|
79
|
+
Если номер не менялся, возможно, перегружен сервис отправки сообщений.
|
|
80
|
+
Попробуйте повторить действие через несколько минут.
|
|
81
|
+
</Typography.Text>
|
|
82
|
+
|
|
83
|
+
<Button
|
|
84
|
+
size={mobile ? 'xs' : 's'}
|
|
85
|
+
view='secondary'
|
|
86
|
+
onClick={handleReturnButtonClick}
|
|
87
|
+
className={styles.hintButton}
|
|
88
|
+
breakpoint={breakpoint}
|
|
89
|
+
>
|
|
90
|
+
{texts.hintButton}
|
|
91
|
+
</Button>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
@import '../../../vars.css';
|
|
2
|
+
|
|
3
|
+
.component {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
align-items: flex-start;
|
|
7
|
+
& span:last-of-type {
|
|
8
|
+
margin-bottom: 0;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.center {
|
|
13
|
+
align-items: center;
|
|
14
|
+
text-align: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.text.text {
|
|
18
|
+
margin-bottom: var(--gap-xl);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.typographyTheme.typographyTheme {
|
|
22
|
+
@mixin _confirmation-text;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.phonesWrap {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
margin-bottom: var(--gap-xl);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.phoneWrap {
|
|
32
|
+
margin-bottom: var(--gap-xs);
|
|
33
|
+
|
|
34
|
+
&:last-child {
|
|
35
|
+
margin-bottom: 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.phoneLink.phoneLink {
|
|
40
|
+
@mixin action_primary_medium;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.hintButton {
|
|
44
|
+
margin-top: var(--gap-2xl);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.phoneContentMobile {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
align-items: center;
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './component';
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
FC,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import cn from 'classnames';
|
|
11
|
+
|
|
12
|
+
import { ButtonMobile } from '@alfalab/core-components-button/mobile';
|
|
13
|
+
import { CodeInputDesktop } from '@alfalab/core-components-code-input/desktop';
|
|
14
|
+
import { CodeInputMobile } from '@alfalab/core-components-code-input/mobile';
|
|
15
|
+
import { BaseCodeInputProps, CustomInputRef } from '@alfalab/core-components-code-input/shared';
|
|
16
|
+
import { Link } from '@alfalab/core-components-link';
|
|
17
|
+
import { Typography } from '@alfalab/core-components-typography';
|
|
18
|
+
import { usePrevious } from '@alfalab/hooks';
|
|
19
|
+
|
|
20
|
+
import { ConfirmationContext } from '../../../context';
|
|
21
|
+
import { Header } from '../../header';
|
|
22
|
+
|
|
23
|
+
import { CountdownSection } from './countdown-section';
|
|
24
|
+
|
|
25
|
+
import styles from './index.module.css';
|
|
26
|
+
|
|
27
|
+
export type InitialProps = {
|
|
28
|
+
/**
|
|
29
|
+
* Отображать в мобильной версии экран компонента
|
|
30
|
+
*/
|
|
31
|
+
mobile?: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const CODE_SEND_HINT_VISIBLE_DURATION = 2000;
|
|
35
|
+
|
|
36
|
+
export const Initial: FC<InitialProps> = ({ mobile }) => {
|
|
37
|
+
const {
|
|
38
|
+
state,
|
|
39
|
+
alignContent,
|
|
40
|
+
texts,
|
|
41
|
+
requiredCharAmount,
|
|
42
|
+
timeLeft,
|
|
43
|
+
phone,
|
|
44
|
+
clearCodeOnError,
|
|
45
|
+
hideCountdownSection,
|
|
46
|
+
onChangeState,
|
|
47
|
+
onInputFinished,
|
|
48
|
+
onChangeScreen,
|
|
49
|
+
onSmsRetryClick,
|
|
50
|
+
} = useContext(ConfirmationContext);
|
|
51
|
+
|
|
52
|
+
const prevState = usePrevious(state);
|
|
53
|
+
|
|
54
|
+
const inputRef = useRef<CustomInputRef>(null);
|
|
55
|
+
|
|
56
|
+
const [codeSendHintVisible, setCodeSendHintVisible] = useState(false);
|
|
57
|
+
|
|
58
|
+
const timerId = useRef(0);
|
|
59
|
+
|
|
60
|
+
const handleInputComplete: BaseCodeInputProps['onComplete'] = (code) => {
|
|
61
|
+
onInputFinished(code);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const handleSmsHintLinkClick = () => {
|
|
65
|
+
onChangeScreen('HINT');
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleInputChange = () => {
|
|
69
|
+
if (state === 'CODE_ERROR') {
|
|
70
|
+
onChangeState('INITIAL');
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleSmsRetryClick = () => {
|
|
75
|
+
if (inputRef.current) {
|
|
76
|
+
inputRef.current.reset();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
onSmsRetryClick();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const handleErrorAnimationEnd = () => {
|
|
83
|
+
if (clearCodeOnError && state !== 'INITIAL') {
|
|
84
|
+
onChangeState('INITIAL');
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const clearTimer = useCallback(() => {
|
|
89
|
+
window.clearTimeout(timerId.current);
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (inputRef.current) {
|
|
94
|
+
inputRef.current.focus();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return () => {
|
|
98
|
+
clearTimer();
|
|
99
|
+
};
|
|
100
|
+
}, [clearTimer]);
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!inputRef.current) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (state === 'CODE_ERROR' && prevState !== 'CODE_ERROR') {
|
|
108
|
+
inputRef.current.focus(requiredCharAmount - 1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (prevState === 'CODE_SENDING' && state !== 'CODE_SENDING') {
|
|
112
|
+
inputRef.current.focus();
|
|
113
|
+
}
|
|
114
|
+
}, [prevState, state, requiredCharAmount]);
|
|
115
|
+
|
|
116
|
+
useLayoutEffect(() => {
|
|
117
|
+
if (prevState === 'CODE_SENDING' && state !== 'CODE_SENDING') {
|
|
118
|
+
setCodeSendHintVisible(true);
|
|
119
|
+
|
|
120
|
+
clearTimer();
|
|
121
|
+
|
|
122
|
+
timerId.current = window.setTimeout(() => {
|
|
123
|
+
setCodeSendHintVisible(false);
|
|
124
|
+
}, CODE_SEND_HINT_VISIBLE_DURATION);
|
|
125
|
+
}
|
|
126
|
+
}, [prevState, state, clearTimer]);
|
|
127
|
+
|
|
128
|
+
const getCodeInputError = (): string | boolean => {
|
|
129
|
+
if (state === 'CODE_ERROR') {
|
|
130
|
+
return texts.codeError || true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return false;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const processing = ['CODE_CHECKING', 'CODE_SENDING'].includes(state);
|
|
137
|
+
|
|
138
|
+
const timePassed = timeLeft === 0;
|
|
139
|
+
|
|
140
|
+
const ComponentCodeInput = mobile ? CodeInputMobile : CodeInputDesktop;
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div className={cn(styles.component, styles[alignContent])}>
|
|
144
|
+
<Header mobile={mobile}>{texts.title}</Header>
|
|
145
|
+
|
|
146
|
+
<Typography.Text
|
|
147
|
+
view='primary-medium'
|
|
148
|
+
color='primary'
|
|
149
|
+
className={cn(styles.phone, { [styles.typographyTheme]: !mobile })}
|
|
150
|
+
>
|
|
151
|
+
Код отправлен на {phone}
|
|
152
|
+
</Typography.Text>
|
|
153
|
+
<ComponentCodeInput
|
|
154
|
+
disabled={processing}
|
|
155
|
+
error={getCodeInputError()}
|
|
156
|
+
ref={inputRef}
|
|
157
|
+
fields={requiredCharAmount}
|
|
158
|
+
className={cn(styles.containerInput, styles.codeInput)}
|
|
159
|
+
onComplete={handleInputComplete}
|
|
160
|
+
onChange={handleInputChange}
|
|
161
|
+
clearCodeOnError={clearCodeOnError}
|
|
162
|
+
onErrorAnimationEnd={handleErrorAnimationEnd}
|
|
163
|
+
/>
|
|
164
|
+
{!hideCountdownSection && (
|
|
165
|
+
<CountdownSection
|
|
166
|
+
processing={processing}
|
|
167
|
+
timePassed={timePassed}
|
|
168
|
+
codeSendHintVisible={codeSendHintVisible}
|
|
169
|
+
handleSmsRetryClick={handleSmsRetryClick}
|
|
170
|
+
mobile={mobile}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{mobile ? (
|
|
175
|
+
<ButtonMobile onClick={handleSmsHintLinkClick} view='link' size='xs'>
|
|
176
|
+
{texts.linkToHint}
|
|
177
|
+
</ButtonMobile>
|
|
178
|
+
) : (
|
|
179
|
+
<Link
|
|
180
|
+
onClick={handleSmsHintLinkClick}
|
|
181
|
+
className={styles.smsComeLink}
|
|
182
|
+
view={mobile ? 'primary' : 'secondary'}
|
|
183
|
+
pseudo={true}
|
|
184
|
+
>
|
|
185
|
+
{texts.linkToHint}
|
|
186
|
+
</Link>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { FC, useContext } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
|
|
4
|
+
import { Button } from '@alfalab/core-components-button';
|
|
5
|
+
import { Loader } from '@alfalab/core-components-loader';
|
|
6
|
+
import { Typography } from '@alfalab/core-components-typography';
|
|
7
|
+
|
|
8
|
+
import { ConfirmationContext } from '../../../context';
|
|
9
|
+
import { formatMsAsMinutes } from '../../../utils';
|
|
10
|
+
|
|
11
|
+
import styles from './index.module.css';
|
|
12
|
+
|
|
13
|
+
type CountdownSectionProps = {
|
|
14
|
+
codeSendHintVisible: boolean;
|
|
15
|
+
timePassed: boolean;
|
|
16
|
+
processing: boolean;
|
|
17
|
+
mobile?: boolean;
|
|
18
|
+
handleSmsRetryClick: () => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const CountdownSection: FC<CountdownSectionProps> = ({
|
|
22
|
+
codeSendHintVisible,
|
|
23
|
+
timePassed,
|
|
24
|
+
processing,
|
|
25
|
+
mobile,
|
|
26
|
+
handleSmsRetryClick,
|
|
27
|
+
}) => {
|
|
28
|
+
const { state, texts, timeLeft, blockSmsRetry, breakpoint } = useContext(ConfirmationContext);
|
|
29
|
+
|
|
30
|
+
const renderText = (text?: string) => (
|
|
31
|
+
<Typography.Text
|
|
32
|
+
className={cn(styles.countdownContainer, {
|
|
33
|
+
[styles.countdownMobile]: mobile,
|
|
34
|
+
[styles.typographyTheme]: !mobile,
|
|
35
|
+
})}
|
|
36
|
+
view={mobile ? 'primary-small' : 'primary-medium'}
|
|
37
|
+
tag='div'
|
|
38
|
+
>
|
|
39
|
+
{text}
|
|
40
|
+
</Typography.Text>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (codeSendHintVisible) return renderText(texts.codeSended);
|
|
44
|
+
|
|
45
|
+
if (processing) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
className={cn(styles.loaderWrap, styles.countdownContainer, {
|
|
49
|
+
[styles.countdownLoaderMobile]: mobile,
|
|
50
|
+
[styles.typographyTheme]: !mobile,
|
|
51
|
+
})}
|
|
52
|
+
>
|
|
53
|
+
<Loader />
|
|
54
|
+
|
|
55
|
+
<span className={styles.loaderText}>
|
|
56
|
+
{state === 'CODE_CHECKING' ? texts.codeChecking : texts.codeSending}
|
|
57
|
+
</span>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (blockSmsRetry) return renderText(texts.noAttemptsLeft);
|
|
63
|
+
|
|
64
|
+
if (timePassed) {
|
|
65
|
+
return (
|
|
66
|
+
<Button
|
|
67
|
+
size={mobile ? 'xs' : 'xxs'}
|
|
68
|
+
view='secondary'
|
|
69
|
+
onClick={handleSmsRetryClick}
|
|
70
|
+
className={cn(styles.getCodeButton, { [styles.getCodeButtonMobile]: mobile })}
|
|
71
|
+
breakpoint={breakpoint}
|
|
72
|
+
>
|
|
73
|
+
{texts.buttonRetry}
|
|
74
|
+
</Button>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return renderText(`${texts.countdown} ${formatMsAsMinutes(timeLeft)}`);
|
|
79
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
@import '../../../vars.css';
|
|
2
|
+
|
|
3
|
+
.component {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.typographyTheme.typographyTheme {
|
|
9
|
+
@mixin _confirmation-text;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.phone.phone {
|
|
13
|
+
color: var(--color-light-text-primary);
|
|
14
|
+
margin-bottom: var(--gap-2xl);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.compact {
|
|
18
|
+
margin-bottom: var(--gap-xl);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.loaderWrap {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.left {
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.center {
|
|
31
|
+
align-items: center;
|
|
32
|
+
text-align: center;
|
|
33
|
+
|
|
34
|
+
& .loaderWrap {
|
|
35
|
+
justify-content: center;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.codeInput {
|
|
40
|
+
margin-bottom: var(--gap-s);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.smsComeLink.smsComeLink {
|
|
44
|
+
@mixin action_primary_small;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.countdownContainer.countdownContainer {
|
|
48
|
+
color: var(--color-light-text-secondary);
|
|
49
|
+
margin-bottom: var(--gap-xl);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.countdownMobile.countdownMobile {
|
|
53
|
+
margin-bottom: var(--gap-l);
|
|
54
|
+
}
|
|
55
|
+
.countdownLoaderMobile.countdownLoaderMobile {
|
|
56
|
+
margin-bottom: var(--gap-m);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.getCodeButton {
|
|
60
|
+
position: relative;
|
|
61
|
+
top: var(--gap-2xs-neg);
|
|
62
|
+
margin-bottom: var(--gap-m);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.getCodeButtonMobile {
|
|
66
|
+
margin-bottom: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.containerInput {
|
|
70
|
+
min-height: 80px;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './component';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React, { FC, useContext, useEffect } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
|
|
4
|
+
import { Typography } from '@alfalab/core-components-typography';
|
|
5
|
+
|
|
6
|
+
import { ConfirmationContext } from '../../../context';
|
|
7
|
+
import { formatMsAsMinutes, useCountdown } from '../../../utils';
|
|
8
|
+
import { CountdownLoader } from '../../countdown-loader';
|
|
9
|
+
import { Header } from '../../header';
|
|
10
|
+
|
|
11
|
+
import styles from './index.module.css';
|
|
12
|
+
|
|
13
|
+
export type TempBlockProps = {
|
|
14
|
+
/**
|
|
15
|
+
* Отображать в мобильной версии экран компонента
|
|
16
|
+
*/
|
|
17
|
+
mobile?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const TempBlock: FC<TempBlockProps> = ({ mobile }) => {
|
|
21
|
+
const { alignContent, texts, tempBlockDuration, onChangeScreen, onTempBlockFinished } =
|
|
22
|
+
useContext(ConfirmationContext);
|
|
23
|
+
|
|
24
|
+
const [timeLeft, startTimer] = useCountdown(tempBlockDuration);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
startTimer();
|
|
28
|
+
}, [startTimer]);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (timeLeft === 0 && onTempBlockFinished) {
|
|
32
|
+
onTempBlockFinished();
|
|
33
|
+
}
|
|
34
|
+
}, [timeLeft, onChangeScreen, onTempBlockFinished]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className={cn(styles.component, styles[alignContent])}>
|
|
38
|
+
<Header mobile={mobile}>{texts.tempBlockTitle}</Header>
|
|
39
|
+
|
|
40
|
+
<Typography.Text
|
|
41
|
+
view='primary-medium'
|
|
42
|
+
color='primary'
|
|
43
|
+
className={cn(styles.description, { [styles.typographyTheme]: !mobile })}
|
|
44
|
+
>
|
|
45
|
+
{texts.tempBlockDescription}
|
|
46
|
+
</Typography.Text>
|
|
47
|
+
|
|
48
|
+
<div className={cn(styles.countdownWrap, { [styles.typographyTheme]: !mobile })}>
|
|
49
|
+
<CountdownLoader
|
|
50
|
+
progress={1 - timeLeft / tempBlockDuration}
|
|
51
|
+
className={styles.loader}
|
|
52
|
+
/>
|
|
53
|
+
|
|
54
|
+
{formatMsAsMinutes(timeLeft)}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@import '../../../vars.css';
|
|
2
|
+
|
|
3
|
+
.component {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.center {
|
|
9
|
+
align-items: center;
|
|
10
|
+
text-align: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.typographyTheme.typographyTheme {
|
|
14
|
+
@mixin _confirmation-text;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.description.description {
|
|
18
|
+
margin-bottom: var(--gap-xs);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.countdownWrap {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.loader {
|
|
27
|
+
margin-right: var(--gap-xs);
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './component';
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { TConfirmationContext } from './types';
|
|
4
|
+
import { ONE_DAY, ONE_MINUTE } from './utils';
|
|
5
|
+
|
|
6
|
+
const mockFn = () => undefined;
|
|
7
|
+
|
|
8
|
+
export const ConfirmationContext = createContext<TConfirmationContext>({
|
|
9
|
+
alignContent: 'left',
|
|
10
|
+
texts: {},
|
|
11
|
+
state: 'INITIAL',
|
|
12
|
+
screen: 'INITIAL',
|
|
13
|
+
requiredCharAmount: 5,
|
|
14
|
+
countdownDuration: ONE_MINUTE,
|
|
15
|
+
timeLeft: ONE_MINUTE,
|
|
16
|
+
tempBlockDuration: ONE_DAY,
|
|
17
|
+
phone: '',
|
|
18
|
+
hideCountdownSection: false,
|
|
19
|
+
breakpoint: 1024,
|
|
20
|
+
onTempBlockFinished: mockFn,
|
|
21
|
+
onInputFinished: mockFn,
|
|
22
|
+
onChangeState: mockFn,
|
|
23
|
+
onSmsRetryClick: mockFn,
|
|
24
|
+
onChangeScreen: mockFn,
|
|
25
|
+
onFatalErrorOkButtonClick: mockFn,
|
|
26
|
+
});
|
package/src/desktop.ts
ADDED
package/src/index.ts
ADDED
package/src/mobile.ts
ADDED
package/src/shared.ts
ADDED