Skip to content

Instantly share code, notes, and snippets.

@juanchoperezj
Created August 11, 2023 20:30
Show Gist options
  • Save juanchoperezj/0e42afa9850845101c3ec62847a92cd2 to your computer and use it in GitHub Desktop.
Save juanchoperezj/0e42afa9850845101c3ec62847a92cd2 to your computer and use it in GitHub Desktop.
Alert component using react-native-bottom-sheet and event emmitter
import { EventEmitter } from 'eventemitter3';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Text, View } from 'react-native';
import { BottomSheetModal, BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { useNavigation } from '@react-navigation/native';
import { AuthStackScreens } from 'navigation/stacks/auth';
import Button from 'common/Button';
import styles from './styles';
import { AlertEvents, AlertProps } from './types';
const eventEmitter = new EventEmitter();
const DURATION = 3000;
// this will mount in App.tsx and will be available everywhere
const alertListener = (callback: (props: AlertProps) => void) => {
eventEmitter.on(AlertEvents.DISPLAY_ALERT, (props: AlertProps) => {
callback(props);
});
};
const Alert = () => {
const [alertProps, setAlertProps] = useState<null | AlertProps>(null);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const { navigate } = useNavigation();
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
// const snapPoints = useMemo(() => ['20%', '13%'], []);
const snapPoints = useMemo(() => ['20%', '20%'], []);
useEffect(() => {
alertListener((props: AlertProps) => {
console.log(props);
setAlertProps(props);
bottomSheetModalRef.current?.present({
props,
});
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
if (alertProps?.autoDismiss || alertProps?.duration) {
console.log('timeout');
timeoutRef.current = setTimeout(() => {
bottomSheetModalRef.current?.close();
}, alertProps?.duration ?? DURATION);
}
});
return () => {
eventEmitter.removeAllListeners();
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [alertProps?.autoDismiss, alertProps?.duration]);
return (
<BottomSheetModalProvider>
<BottomSheetModal
overDragResistanceFactor={0}
ref={bottomSheetModalRef}
index={1}
bottomInset={46}
detached={true}
snapPoints={snapPoints}
backgroundStyle={styles.sheetBackground}
containerStyle={styles.sheetContainer}
style={styles.sheet}>
<View style={styles.contentContainer}>
<View>
<Text style={styles.title}>{alertProps?.title}</Text>
<Text style={styles.description}>{alertProps?.message}</Text>
</View>
<View style={styles.actionContainer}>
<Button
style={styles.button}
title="Add funds"
onPress={() => {
bottomSheetModalRef.current?.dismiss();
navigate(AuthStackScreens.SignIn);
}}
/>
<Button
style={styles.button}
title="Close"
onPress={() => bottomSheetModalRef.current?.close()}
/>
</View>
</View>
</BottomSheetModal>
</BottomSheetModalProvider>
);
};
export default Alert;
import Alert from 'components/Alert';
const App = () => {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<NavigationContainer>
<Navigation />
<Alert />
</NavigationContainer>
</GestureHandlerRootView>
);
};
// example of use anywhere in your app
const { showAlert } = useAlert();
showAlert({
title: "❌ You don't have enough money",
message: 'Please add more funds to your account to complete the transaction.',
autoDismiss: false,
})
export const useAlert = () => {
// const { dismiss } = useBottomSheetModal();
const showAlert = useCallback((props: AlertProps) => {
eventEmitter.emit(AlertEvents.DISPLAY_ALERT, props);
}, []);
return {
showAlert,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment