mattermost-mobile/app/screens/onboarding/index.tsx
Daniel Espino García cff12f7182
Enable exhaustive deps in the repo (#9508)
* Enable exhaustive deps in the repo

* Add tests for the new hooks

* Update claude.md

* Remove pre-commit overwrite
2026-02-18 11:56:16 +01:00

161 lines
5.2 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useRef} from 'react';
import {
View,
useWindowDimensions,
SafeAreaView,
ScrollView,
StyleSheet,
type NativeSyntheticEvent,
type NativeScrollEvent,
BackHandler,
} from 'react-native';
import Animated, {useDerivedValue, useSharedValue} from 'react-native-reanimated';
import {storeOnboardingViewedValue} from '@actions/app/global';
import {Screens} from '@constants';
import useDidMount from '@hooks/did_mount';
import {useScreenTransitionAnimation} from '@hooks/screen_transition_animation';
import SecurityManager from '@managers/security_manager';
import Background from '@screens/background';
import {goToScreen, loginAnimationOptions} from '@screens/navigation';
import FooterButtons from './footer_buttons';
import Paginator from './paginator';
import SlideItem from './slide';
import useSlidesData from './slides_data';
import type {LaunchProps} from '@typings/launch';
import type {AvailableScreens} from '@typings/screens/navigation';
interface OnboardingProps extends LaunchProps {
componentId: AvailableScreens;
theme: Theme;
}
const styles = StyleSheet.create({
onBoardingContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
verticalAlign: 'top',
},
scrollContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView);
const Onboarding = ({
componentId,
theme,
...props
}: OnboardingProps) => {
const {width} = useWindowDimensions();
const {slidesData} = useSlidesData();
const LAST_SLIDE_INDEX = slidesData.length - 1;
const slidesRef = useRef<ScrollView>(null);
const scrollX = useSharedValue(0);
const currentIndex = useDerivedValue(() => Math.round(scrollX.value / width));
const moveToSlide = useCallback((slideIndexToMove: number) => {
slidesRef.current?.scrollTo({
x: (slideIndexToMove * width),
animated: true,
});
}, [width]);
const signInHandler = useCallback(() => {
// mark the onboarding as already viewed
storeOnboardingViewedValue();
goToScreen(Screens.SERVER, '', {animated: true, theme, ...props}, loginAnimationOptions());
}, [props, theme]);
const nextSlide = useCallback(() => {
const nextSlideIndex = currentIndex.value + 1;
if (slidesRef.current && currentIndex.value < LAST_SLIDE_INDEX) {
moveToSlide(nextSlideIndex);
} else if (slidesRef.current && currentIndex.value === LAST_SLIDE_INDEX) {
signInHandler();
}
}, [LAST_SLIDE_INDEX, currentIndex, moveToSlide, signInHandler]);
const scrollHandler = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
scrollX.value = event.nativeEvent.contentOffset.x;
}, [scrollX]);
const animatedStyles = useScreenTransitionAnimation(Screens.ONBOARDING);
useDidMount(() => {
const listener = BackHandler.addEventListener('hardwareBackPress', () => {
if (!currentIndex.value) {
return false;
}
moveToSlide(currentIndex.value - 1);
return true;
});
return () => listener.remove();
});
return (
<View
style={styles.onBoardingContainer}
testID='onboarding.screen'
nativeID={SecurityManager.getShieldScreenId(componentId, false, true)}
>
<Background theme={theme}/>
<AnimatedSafeArea
style={[styles.scrollContainer, animatedStyles]}
key={'onboarding_content'}
>
<ScrollView
scrollEventThrottle={16}
horizontal={true}
showsHorizontalScrollIndicator={false}
pagingEnabled={true}
bounces={false}
onScroll={scrollHandler}
ref={slidesRef}
>
{slidesData.map((item, index) => {
return (
<SlideItem
item={item}
theme={theme}
scrollX={scrollX}
index={index}
key={`key-${index.toString()}`}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
);
})}
</ScrollView>
<Paginator
dataLength={slidesData.length}
theme={theme}
scrollX={scrollX}
moveToSlide={moveToSlide}
/>
<FooterButtons
theme={theme}
nextSlideHandler={nextSlide}
signInHandler={signInHandler}
scrollX={scrollX}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
</AnimatedSafeArea>
</View>
);
};
export default Onboarding;