Skip to content

Commit

Permalink
general refactor and performance improvements (more memoization)
Browse files Browse the repository at this point in the history
  • Loading branch information
zdmc23 committed Jul 11, 2022
1 parent 8cdc580 commit d85da8c
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 194 deletions.
19 changes: 10 additions & 9 deletions App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//import './wdyr';
import React from "react";
import { Text } from "react-native";
import { LogBox, Text } from "react-native";
import AppNavigator from "navigation/AppNavigator";

import { store, persistor } from "store/store";
Expand All @@ -22,18 +22,19 @@ import { AppConstants } from "constants";
import { enableScreens } from "react-native-screens";
enableScreens();

const StyledApp = () => {
// set default text styles
const { globalStyles } = useStyles();
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.style = { ...globalStyles.text };
return <AppNavigator />;
};

const App = () => {
// Initialize the app
useApp();

// NOTE: Necessary bc our chain of hooks depends on Redux and we need to be inside the Redux Provider
const StyledApp = () => {
// set default text styles
const { globalStyles } = useStyles();
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.style = { ...globalStyles.text };
return <AppNavigator />;
};
LogBox.ignoreAllLogs();

return (
<>
Expand Down
5 changes: 4 additions & 1 deletion components/Card/PendingContactsCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ const PendingContactsCard = ({ refreshing, onRefresh }) => {
};

const renderContactAccept = (contact, idx) => (
<View style={[globalStyles.columnContainer, styles.container(idx)]}>
<View
key={idx}
style={[globalStyles.columnContainer, styles.container(idx)]}
>
<Pressable
onPress={() => {
navigation.jumpTo(TabScreenConstants.CONTACTS, {
Expand Down
20 changes: 19 additions & 1 deletion constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const ChurchHealthConstants = Object.freeze({
export const AppConstants = Object.freeze({
NAME: "D.T",
PROTOCOL: "https",
CONTENT_TYPE_JSON: "application/json",
TIMEOUT: 15000, // 15 secs
REFRESH_INTERVAL: 0, //10 secs
});
Expand Down Expand Up @@ -273,6 +274,12 @@ export const NotificationActionConstants = Object.freeze({
MENTION: "mentioned",
});

export const NotificationPermissionConstants = Object.freeze({
GRANTED: "granted",
UNDETERMINED: "undetermined",
DENIED: "denied",
});

export const QuickActionButtonConstants = Object.freeze({
NO_ANSWER: "quick_button_no_answer",
CONTACT_ESTABLISHED: "quick_button_contact_established",
Expand Down Expand Up @@ -305,7 +312,18 @@ export const AppStateConstants = Object.freeze({
INACTIVE: "inactive",
});

export const EMPTY_CACHE = new Map([]);
export const PINConstants = {
CNONCE: "CNONCE",
CNONCE_DATETIME: "CNONCE_DATETIME",
CODE: "CODE",
DELETE: "DELETE",
SCREEN: "PIN",
SET: "SET",
VALIDATE: "VALIDATE",
CNONCE_THRESHOLD: 10,
};

export const CACHE_INTERVAL = 1000 * 60 * 2; // 2 minutes

export default {
STATUS_CIRCLE_SIZE: 15,
Expand Down
45 changes: 22 additions & 23 deletions hooks/use-app-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,33 @@ import { AppStateConstants } from "constants";

const useAppState = ({ onAppForegroundCallback, onAppBackgroundCallback }) => {
const appState = useRef(AppState.currentState);

useEffect(() => {
const subscription = AppState.addEventListener("change", (nextAppState) => {
if (
appState.current.match(
new RegExp(
`${AppStateConstants.INACTIVE}|${AppStateConstants.BACKGROUND}`
)
) &&
nextAppState === AppStateConstants.ACTIVE
) {
if (onAppForegroundCallback) onAppForegroundCallback();
}
if (
appState.current.match(new RegExp(AppStateConstants.ACTIVE)) &&
nextAppState !== AppStateConstants.ACTIVE
) {
if (onAppBackgroundCallback) onAppBackgroundCallback();
const subscription = AppState.addEventListener(
"change",
async (nextAppState) => {
if (
appState.current.match(
new RegExp(
`${AppStateConstants.INACTIVE}|${AppStateConstants.BACKGROUND}`
)
) &&
nextAppState === AppStateConstants.ACTIVE
) {
if (onAppForegroundCallback) onAppForegroundCallback();
}
if (
appState.current.match(new RegExp(AppStateConstants.ACTIVE)) &&
nextAppState !== AppStateConstants.ACTIVE
) {
if (onAppBackgroundCallback) onAppBackgroundCallback();
}
appState.current = nextAppState;
}
appState.current = nextAppState;
});
);
return () => {
subscription.remove();
};
}, []);

return {
appState: appState?.current,
};
return appState?.current;
};
export default useAppState;
112 changes: 59 additions & 53 deletions hooks/use-i18n.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo } from "react";
import { useCallback, useEffect, useMemo } from "react";
import { Alert, I18nManager } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import moment from "moment/min/moment-with-locales";
Expand Down Expand Up @@ -146,26 +146,29 @@ const useI18N = () => {
const locale = useSelector((state) => state.i18nReducer?.locale);
const { data: userData } = useMyUser();

const getCountryCode = (locale) => locale?.substring(0, 2);

const _isRTL = (_locale) => {
// if param is undefined, then default to use existing/persisted locale
_locale = _locale ?? locale;
if (!_locale) return null;
const countryCode = getCountryCode(_locale);
return RTL_LANGS.includes(countryCode);
};
const getCountryCode = useCallback((locale) => locale?.substring(0, 2), []);

const _isRTL = useCallback(
(_locale) => {
// if param is undefined, then default to use existing/persisted locale
_locale = _locale ?? locale;
if (!_locale) return null;
const countryCode = getCountryCode(_locale);
return RTL_LANGS.includes(countryCode);
},
[locale]
);

const isRTL = _isRTL();

const mapLocaleToMomentLocale = (locale) => {
const mapLocaleToMomentLocale = useCallback((locale) => {
const special = ["ar_MA", "bn_BD", "pt_BR", "tl"];
if (special.includes(locale)) {
if (locale === "tl") return "tl-ph";
return locale?.toLowerCase()?.replace("_", "-") ?? "en";
}
return locale?.split("_")?.[0];
};
}, []);

useEffect(() => {
// if no 'locale' existing in-memory or storage, then use device locale
Expand All @@ -184,54 +187,57 @@ const useI18N = () => {
return;
}, [userData?.locale]);

const reloadApp = () => {
const reloadApp = useCallback(() => {
setTimeout(() => {
Updates.reloadAsync();
}, 1000);
};

const _setLocale = (_locale) => {
if (_locale && _locale !== locale) {
i18n.locale = _locale;
moment.locale(mapLocaleToMomentLocale(_locale));
const isRTL = _isRTL(_locale);
dispatch(setLocale(_locale));
if (isRTL !== I18nManager?.isRTL) {
I18nManager.allowRTL(isRTL);
I18nManager.forceRTL(isRTL);
Alert.alert(i18n.t("global.alert"), i18n.t("global.appRestart"), [
{
text: "OK",
onPress: () => reloadApp(),
},
]);
}, []);

const _setLocale = useCallback(
(_locale) => {
if (_locale && _locale !== locale) {
i18n.locale = _locale;
moment.locale(mapLocaleToMomentLocale(_locale));
const isRTL = _isRTL(_locale);
dispatch(setLocale(_locale));
if (isRTL !== I18nManager?.isRTL) {
I18nManager.allowRTL(isRTL);
I18nManager.forceRTL(isRTL);
Alert.alert(i18n.t("global.alert"), i18n.t("global.appRestart"), [
{
text: "OK",
onPress: () => reloadApp(),
},
]);
}
}
}
};
},
[locale]
);

const numberFormat = (numberValue) => {
try {
return new Intl.NumberFormat(locale?.replace("_", "-")).format(
numberValue
);
} catch (error) {
return numberValue;
}
};
const numberFormat = useCallback(
(numberValue) => {
try {
return new Intl.NumberFormat(locale?.replace("_", "-")).format(
numberValue
);
} catch (error) {
return numberValue;
}
},
[locale]
);

const selectedEndonym = i18n?.translations[locale]?.endonym ?? "";

return useMemo(
() => ({
i18n,
isRTL,
locale,
setLocale: _setLocale,
selectedEndonym,
moment,
numberFormat,
}),
[isRTL, locale, selectedEndonym]
);
return {
i18n,
isRTL,
locale,
setLocale: _setLocale,
selectedEndonym,
moment,
numberFormat,
};
};
export default useI18N;
3 changes: 2 additions & 1 deletion hooks/use-import-contacts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";

import * as Contacts from "expo-contacts";

import { searchObjList } from "utils";
Expand Down
54 changes: 29 additions & 25 deletions hooks/use-notifications.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo } from "react";
import { useCallback } from "react";

import { useAuth } from "hooks/use-auth";
import useAPI from "hooks/use-api";
Expand All @@ -7,8 +7,35 @@ import useRequest from "hooks/use-request";
import { searchObjList } from "utils";

const useNotifications = ({ search, filter, exclude, offset, limit } = {}) => {
const { uid } = useAuth();
const { updatePost } = useAPI();
const { user } = useAuth();
const uid = user?.uid;

const markViewed = useCallback(
({ id } = {}) => {
// if !id, then mark all as viewed
// NOTE: *not* passing `mutate` bc we want responsive updates, but pull refresh will mutate
if (!id && uid) {
updatePost({
urlPath: `/dt/v1/notifications/mark_all_viewed/${uid}`,
});
return;
}
if (id)
updatePost({
urlPath: `/dt/v1/notifications/mark_viewed/${id}`,
});
},
[uid]
);

const markUnread = useCallback(({ id } = {}) => {
// NOTE: *not* passing `mutate` bc we want responsive updates, but pull refresh will mutate
if (id)
updatePost({
urlPath: `/dt/v1/notifications/mark_unread/${id}`,
});
}, []);

// TODO: constant
if (!limit) limit = 1000;
Expand Down Expand Up @@ -55,29 +82,6 @@ const useNotifications = ({ search, filter, exclude, offset, limit } = {}) => {
// place new items at the top of list
filtered = [...filteredNew, ...filteredRead];

const markViewed = ({ id } = {}) => {
// if !id, then mark all as viewed
// NOTE: *not* passing `mutate` bc we want responsive updates, but pull refresh will mutate
if (!id && uid) {
updatePost({
urlPath: `/dt/v1/notifications/mark_all_viewed/${uid}`,
});
return;
}
if (id)
updatePost({
urlPath: `/dt/v1/notifications/mark_viewed/${id}`,
});
};

const markUnread = ({ id } = {}) => {
// NOTE: *not* passing `mutate` bc we want responsive updates, but pull refresh will mutate
if (id)
updatePost({
urlPath: `/dt/v1/notifications/mark_unread/${id}`,
});
};

const hasNotifications = filteredNew?.length > 0;

return {
Expand Down
Loading

0 comments on commit d85da8c

Please sign in to comment.