Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix : migrate root component to react functional component #6033

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
4 changes: 2 additions & 2 deletions .storybook/storybook.requires.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)?)$/
),
},
];
Expand Down
255 changes: 128 additions & 127 deletions app/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -78,163 +78,164 @@ 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<IDimensions>(Dimensions.get('window'));
const [state, setState] = useState<{ themePreferences: IThemePreference; theme: TSupportedThemes }>({
themePreferences: initialTheme(),
theme: getTheme(initialTheme())
});
const initTheme = initialTheme();
const [themeState, setThemeState] = useState<IState>({
...state,
width: dimensions.width,
height: dimensions.height,
scale: dimensions.scale,
fontScale: dimensions.fontScale
});

useEffect(() => {
// init function
divyanshu-patil marked this conversation as resolved.
Show resolved Hide resolved
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) {
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
}
});
}, 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
divyanshu-patil marked this conversation as resolved.
Show resolved Hide resolved
const onDimensionsChange = debounce(({ window: { width, height, scale, fontScale } }: { window: IDimensions }) => {
divyanshu-patil marked this conversation as resolved.
Show resolved Hide resolved
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));
setThemeState(prevstate => ({ ...prevstate, ...state }));
};

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 (
<SafeAreaProvider initialMetrics={initialWindowMetrics} style={{ backgroundColor: themes[this.state.theme].surfaceRoom }}>
<Provider store={store}>
<ThemeContext.Provider
const { themePreferences, theme, width, height, scale, fontScale } = themeState;
return (
<SafeAreaProvider initialMetrics={initialWindowMetrics} style={{ backgroundColor: themes[themeState.theme].surfaceRoom }}>
<Provider store={store}>
<ThemeContext.Provider
value={{
theme,
themePreferences,
setTheme,
colors: colors[theme]
}}>
<DimensionsContext.Provider
value={{
theme,
themePreferences,
setTheme: this.setTheme,
colors: colors[theme]
width,
height,
scale,
fontScale,
setDimensions
}}>
<DimensionsContext.Provider
value={{
width,
height,
scale,
fontScale,
setDimensions: this.setDimensions
}}>
<GestureHandlerRootView>
<ActionSheetProvider>
<AppContainer />
<TwoFactor />
<ScreenLockedView />
<ChangePasscodeView />
<InAppNotification />
<Toast />
<Loading />
</ActionSheetProvider>
</GestureHandlerRootView>
</DimensionsContext.Provider>
</ThemeContext.Provider>
</Provider>
</SafeAreaProvider>
);
}
}
<GestureHandlerRootView>
<ActionSheetProvider>
<AppContainer />
<TwoFactor />
<ScreenLockedView />
<ChangePasscodeView />
<InAppNotification />
<Toast />
<Loading />
</ActionSheetProvider>
</GestureHandlerRootView>
</DimensionsContext.Provider>
</ThemeContext.Provider>
</Provider>
</SafeAreaProvider>
);
};
export default Root;