From 9964bf569ae71d911be4ccfef62dd3bd12e89ff3 Mon Sep 17 00:00:00 2001 From: div Date: Sat, 30 Nov 2024 20:04:59 +0530 Subject: [PATCH] [FIX] fixed #6031 migrate root component to react functional component --- .storybook/storybook.requires.ts | 4 +- app/index.tsx | 254 +++++++++++++++---------------- 2 files changed, 129 insertions(+), 129 deletions(-) diff --git a/.storybook/storybook.requires.ts b/.storybook/storybook.requires.ts index 79eb456c1b..4d2e29a1cf 100644 --- a/.storybook/storybook.requires.ts +++ b/.storybook/storybook.requires.ts @@ -12,12 +12,12 @@ const normalizedStories = [ directory: "./app", files: "**/*.stories.?(ts|tsx|js|jsx)", importPathMatcher: - /^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/, + /^\.(?:(?:^|[\\/]|(?:(?:(?!(?:^|[\\/])\.).)*?)[\\/])(?!\.)(?=.)[^\\/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/, // @ts-ignore req: require.context( "../app", true, - /^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/ + /^\.(?:(?:^|[\\/]|(?:(?:(?!(?:^|[\\/])\.).)*?)[\\/])(?!\.)(?=.)[^\\/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/ ), }, ]; diff --git a/app/index.tsx b/app/index.tsx index 89b0d6d5e9..b8d26cfc81 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { Dimensions, EmitterSubscription, Linking } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context'; @@ -78,34 +78,67 @@ const parseDeepLinking = (url: string) => { return null; }; -export default class Root extends React.Component<{}, IState> { - private listenerTimeout!: any; - private dimensionsListener?: EmitterSubscription; +const Root: React.FC = () => { + const [dimensions, setDimensions] = useState(Dimensions.get('window')); + const [state, setState] = useState<{ themePreferences: IThemePreference; theme: TSupportedThemes }>({ + themePreferences: initialTheme(), + theme: getTheme(initialTheme()) + }); + const initTheme = initialTheme(); + const [themeState, setThemeState] = useState({ + ...state, + width: dimensions.width, + height: dimensions.height, + scale: dimensions.scale, + fontScale: dimensions.fontScale + }); + + useEffect(() => { + // init function + const init = async () => { + store.dispatch(appInitLocalSettings()); + + // Open app from push notification + const notification = await initializePushNotifications(); + if (notification) { + onNotification(notification); + return; + } + + await getInitialNotification(); + + // Open app from deep linking + const deepLinking = await Linking.getInitialURL(); + const parsedDeepLinkingURL = parseDeepLinking(deepLinking!); + if (parsedDeepLinkingURL) { + store.dispatch(deepLinkingOpen(parsedDeepLinkingURL)); + return; + } + + // Open app from app icon + store.dispatch(appInit()); + }; + + const initTablet = () => { + const { width } = themeState; + setMasterDetail(width); + }; + + // initialize + init(); - constructor(props: any) { - super(props); - this.init(); if (!isFDroidBuild) { - this.initCrashReport(); + initCrashReport(); } - const { width, height, scale, fontScale } = Dimensions.get('window'); - const theme = initialTheme(); - this.state = { - theme: getTheme(theme), - themePreferences: theme, - width, - height, - scale, - fontScale - }; + if (isTablet) { - this.initTablet(); + initTablet(); } - setNativeTheme(theme); - } - componentDidMount() { - this.listenerTimeout = setTimeout(() => { + // Set the native theme for the app + setNativeTheme(initTheme); + + const timeout = setTimeout(() => { Linking.addEventListener('url', ({ url }) => { const parsedDeepLinkingURL = parseDeepLinking(url); if (parsedDeepLinkingURL) { @@ -113,128 +146,95 @@ export default class Root extends React.Component<{}, IState> { } }); }, 5000); - this.dimensionsListener = Dimensions.addEventListener('change', this.onDimensionsChange); - } - - componentWillUnmount() { - clearTimeout(this.listenerTimeout); - this.dimensionsListener?.remove?.(); - - unsubscribeTheme(); - } - init = async () => { - store.dispatch(appInitLocalSettings()); + const dimensionsListener: EmitterSubscription = Dimensions.addEventListener('change', onDimensionsChange); - // Open app from push notification - const notification = await initializePushNotifications(); - if (notification) { - onNotification(notification); - return; - } - - await getInitialNotification(); - - // Open app from deep linking - const deepLinking = await Linking.getInitialURL(); - const parsedDeepLinkingURL = parseDeepLinking(deepLinking!); - if (parsedDeepLinkingURL) { - store.dispatch(deepLinkingOpen(parsedDeepLinkingURL)); - return; - } - - // Open app from app icon - store.dispatch(appInit()); - }; + return () => { + clearTimeout(timeout); + dimensionsListener.remove(); + unsubscribeTheme(); + }; + }, []); - getMasterDetail = (width: number) => { - if (!isTablet) { - return false; - } - return width > MIN_WIDTH_MASTER_DETAIL_LAYOUT; - }; + useEffect(() => { + // Subscribe to Appearance changes whenever themePreferences changes + subscribeTheme(themePreferences, () => setTheme(themePreferences)); + }, [themeState.themePreferences]); // Dependency array ensures this runs when `themePreferences` changes - setMasterDetail = (width: number) => { - const isMasterDetail = this.getMasterDetail(width); - store.dispatch(setMasterDetailAction(isMasterDetail)); + const initCrashReport = () => { + getAllowCrashReport().then(allowCrashReport => { + toggleCrashErrorsReport(allowCrashReport); + }); + getAllowAnalyticsEvents().then(allowAnalyticsEvents => { + toggleAnalyticsEventsReport(allowAnalyticsEvents); + }); }; - // Dimensions update fires twice - onDimensionsChange = debounce(({ window: { width, height, scale, fontScale } }: { window: IDimensions }) => { - this.setDimensions({ + // Handle dimensions change + const onDimensionsChange = debounce(({ window: { width, height, scale, fontScale } }: { window: IDimensions }) => { + setDimensions({ width, height, scale, fontScale }); - this.setMasterDetail(width); + setMasterDetail(width); }); - setTheme = (newTheme = {}) => { - // change theme state - this.setState( - prevState => newThemeState(prevState, newTheme as IThemePreference), - () => { - const { themePreferences } = this.state; - // subscribe to Appearance changes - subscribeTheme(themePreferences, this.setTheme); - } - ); - }; + const setTheme = (newTheme?: {} | undefined) => { + if (!newTheme) { + return; + } - setDimensions = ({ width, height, scale, fontScale }: IDimensions) => { - this.setState({ width, height, scale, fontScale }); + // Typecast newTheme to IThemePreference when setting state + setState(prevState => newThemeState(prevState, newTheme as IThemePreference)); }; - initTablet = () => { - const { width } = this.state; - this.setMasterDetail(width); + const getMasterDetail = (width: number) => { + if (!isTablet) { + return false; + } + return width > MIN_WIDTH_MASTER_DETAIL_LAYOUT; }; - initCrashReport = () => { - getAllowCrashReport().then(allowCrashReport => { - toggleCrashErrorsReport(allowCrashReport); - }); - getAllowAnalyticsEvents().then(allowAnalyticsEvents => { - toggleAnalyticsEventsReport(allowAnalyticsEvents); - }); + const setMasterDetail = (width: number) => { + const isMasterDetail = getMasterDetail(width); + store.dispatch(setMasterDetailAction(isMasterDetail)); }; - - render() { - const { themePreferences, theme, width, height, scale, fontScale } = this.state; - return ( - - - + + + - - - - - - - - - - - - - - - - - ); - } -} + + + + + + + + + + + + + + + + ); +}; +export default Root;