1/** 2 * Copyright (c) 650 Industries. 3 * Copyright (c) Meta Platforms, Inc. and affiliates. 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8import React, { useCallback, useMemo } from 'react'; 9import { StyleSheet, View } from 'react-native'; 10 11import { ErrorToast } from './ErrorToast'; 12import * as LogBoxData from '../Data/LogBoxData'; 13import { LogBoxLog } from '../Data/LogBoxLog'; 14import { useLogs } from '../Data/LogContext'; 15import { useRejectionHandler } from '../useRejectionHandler'; 16 17export function ErrorToastContainer() { 18 useRejectionHandler(); 19 const { logs, isDisabled } = useLogs(); 20 if (!logs.length || isDisabled) { 21 return null; 22 } 23 return <ErrorToastStack logs={logs} />; 24} 25 26function ErrorToastStack({ logs }: { logs: LogBoxLog[] }) { 27 const onDismissWarns = useCallback(() => { 28 LogBoxData.clearWarnings(); 29 }, []); 30 31 const onDismissErrors = useCallback(() => { 32 LogBoxData.clearErrors(); 33 }, []); 34 35 const setSelectedLog = useCallback((index: number): void => { 36 LogBoxData.setSelectedLog(index); 37 }, []); 38 39 function openLog(log: LogBoxLog) { 40 let index = logs.length - 1; 41 42 // Stop at zero because if we don't find any log, we'll open the first log. 43 while (index > 0 && logs[index] !== log) { 44 index -= 1; 45 } 46 setSelectedLog(index); 47 } 48 49 const warnings = useMemo(() => logs.filter((log) => log.level === 'warn'), [logs]); 50 51 const errors = useMemo( 52 () => logs.filter((log) => log.level === 'error' || log.level === 'fatal'), 53 [logs] 54 ); 55 56 return ( 57 <View style={styles.list}> 58 {warnings.length > 0 && ( 59 <ErrorToast 60 log={warnings[warnings.length - 1]} 61 level="warn" 62 totalLogCount={warnings.length} 63 onPressOpen={() => openLog(warnings[warnings.length - 1])} 64 onPressDismiss={onDismissWarns} 65 /> 66 )} 67 68 {errors.length > 0 && ( 69 <ErrorToast 70 log={errors[errors.length - 1]} 71 level="error" 72 totalLogCount={errors.length} 73 onPressOpen={() => openLog(errors[errors.length - 1])} 74 onPressDismiss={onDismissErrors} 75 /> 76 )} 77 </View> 78 ); 79} 80 81const styles = StyleSheet.create({ 82 list: { 83 bottom: 6, 84 left: 10, 85 right: 10, 86 maxWidth: 320, 87 // @ts-expect-error 88 position: 'fixed', 89 }, 90}); 91 92export default LogBoxData.withSubscription(ErrorToastContainer); 93