-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathStdcmLoader.tsx
105 lines (88 loc) · 3.28 KB
/
StdcmLoader.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { useEffect, useRef, useState, type RefObject } from 'react';
import { Button } from '@osrd-project/ui-core';
import cx from 'classnames';
import { useTranslation } from 'react-i18next';
import type { LoaderStatus } from '../types';
const LOADER_HEIGHT = 176;
const LOADER_OFFSET = 32;
type StdcmLoaderProps = {
cancelStdcmRequest: () => void;
launchButtonRef: RefObject<HTMLDivElement>;
formRef: RefObject<HTMLDivElement>;
};
const StdcmLoader = ({ cancelStdcmRequest, launchButtonRef, formRef }: StdcmLoaderProps) => {
const { t } = useTranslation('stdcm');
const loaderRef = useRef<HTMLDivElement>(null);
const { top } = launchButtonRef.current!.getBoundingClientRect();
const windowHeight = window.innerHeight;
const [loaderStatus, setLoaderStatus] = useState<LoaderStatus>({
status: windowHeight - top - 32 > LOADER_HEIGHT ? 'loader-absolute' : 'loader-fixed-bottom',
firstLaunch: true,
});
useEffect(() => {
// Depending on the scroll, change the position of the loader between fixed, sticky or absolute
const handleScroll = () => {
if (!loaderRef.current || !launchButtonRef.current || !formRef.current) return;
const { scrollY, innerHeight } = window;
const isLoaderFitting =
innerHeight - launchButtonRef.current.getBoundingClientRect().top >
LOADER_HEIGHT + LOADER_OFFSET;
// Loader doesn't fit between the bottom of the form and bottom of the viewport
if (!isLoaderFitting) {
setLoaderStatus({
firstLaunch: false,
status: 'loader-fixed-bottom',
});
return;
}
const currentFormHeight = formRef.current.clientHeight;
const topFormPosition = formRef.current.getBoundingClientRect().top;
const launchButtonHeight = launchButtonRef.current.clientHeight;
const shouldLoaderStickTop =
scrollY >
currentFormHeight + scrollY + topFormPosition - launchButtonHeight - LOADER_OFFSET;
// Loader reaches the top of the screen minus its top offset
if (shouldLoaderStickTop) {
setLoaderStatus({
firstLaunch: false,
status: 'loader-fixed-top',
});
return;
}
setLoaderStatus({
firstLaunch: false,
status: 'loader-absolute',
});
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<div
ref={loaderRef}
className={cx('stdcm-loader', `${loaderStatus.status}`, {
'with-fade-in-animation':
loaderStatus.status === 'loader-absolute' && loaderStatus.firstLaunch,
'with-slide-animation':
loaderStatus.status === 'loader-fixed-bottom' && loaderStatus.firstLaunch,
})}
>
<div className="stdcm-loader__wrapper">
<h2>{t('simulation.calculatingSimulation')}</h2>
<div className="stdcm-loader__cancel-btn">
<Button
data-testid="cancel-simulation-button"
variant="Cancel"
label={t('simulation.stopCalculation')}
size="small"
onClick={cancelStdcmRequest}
/>
</div>
</div>
<p className="stdcm-loader__info-message">{t('simulation.infoMessage')}</p>
</div>
);
};
export default StdcmLoader;