Skip to content

Commit

Permalink
Merge pull request #226 from cnguyen812/feat/log-filters
Browse files Browse the repository at this point in the history
Feat/log filters
  • Loading branch information
JohnathanWhite authored Jul 19, 2022
2 parents e6e2159 + 40240eb commit 3d05d9f
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 75 deletions.
4 changes: 2 additions & 2 deletions ios/BitPayApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 i386";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down Expand Up @@ -725,7 +725,7 @@
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 i386";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand Down
8 changes: 7 additions & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ PODS:
- React-Core
- react-native-safe-area-context (3.3.2):
- React-Core
- react-native-slider (4.2.4):
- React-Core
- react-native-text-input-mask (3.1.4):
- InputMask (~> 6.1.0)
- React-Core
Expand Down Expand Up @@ -600,6 +602,7 @@ DEPENDENCIES:
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-text-input-mask (from `../node_modules/react-native-text-input-mask`)
- react-native-tracking-transparency (from `../node_modules/react-native-tracking-transparency`)
- react-native-user-agent (from `../node_modules/react-native-user-agent`)
Expand Down Expand Up @@ -730,6 +733,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-text-input-mask:
:path: "../node_modules/react-native-text-input-mask"
react-native-tracking-transparency:
Expand Down Expand Up @@ -814,7 +819,7 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53
FBReactNativeSpec: 659a18b561e601d39a0e273cc7f5ca8b62b3f222
FBReactNativeSpec: 30113914ceb067204672bf4fad2026fac0d1441c
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
Expand Down Expand Up @@ -864,6 +869,7 @@ SPEC CHECKSUMS:
react-native-pager-view: 3ee7d4c7697fb3ef788346e834a60cca97ed8540
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
react-native-slider: cecabb58ecffad671d2ad3ccc58c7f4d2d029e95
react-native-text-input-mask: 36a546b378fadd2efe1b7484a859d34bc2c80395
react-native-tracking-transparency: b2029ff756f1128b1f2c7c7c7f3003bc3c950f9f
react-native-user-agent: a90a1e839b99801baad67a73dd6f361a52aa3cf1
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@react-native-async-storage/async-storage": "1.15.14",
"@react-native-community/blur": "3.6.0",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/slider": "4.2.4",
"@react-native-masked-view/masked-view": "0.2.6",
"@react-navigation/bottom-tabs": "6.0.9",
"@react-navigation/material-top-tabs": "6.0.6",
Expand Down
3 changes: 3 additions & 0 deletions src/constants/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @ts-ignore
import {version} from '../../package.json'; // TODO: better way to get version
import {Network} from '.';

export const DEVTOOLS_ENABLED = false;
Expand All @@ -8,6 +10,7 @@ export const APP_ANALYTICS_ENABLED = !__DEV__;
export const APP_NAME = 'bitpay';
export const APP_NAME_UPPERCASE = 'BitPay';
export const APP_NETWORK = Network.mainnet;
export const APP_VERSION = version;
export const BASE_BITPAY_URLS = {
[Network.mainnet]: 'https://bitpay.com',
[Network.testnet]: 'https://test.bitpay.com',
Expand Down
12 changes: 5 additions & 7 deletions src/navigation/services/buy-crypto/utils/simplex-utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {Currencies} from '../../../../constants/currencies';
import {APP_NAME} from '../../../../constants/config';
// @ts-ignore
import {version} from '../../../../../package.json'; // TODO: better way to get version
import UserAgent from 'react-native-user-agent';
import {APP_NAME, APP_VERSION} from '../../../../constants/config';
import {Currencies} from '../../../../constants/currencies';

const PASSTHROUGH_URI_DEV = 'https://cmgustavo.github.io/website/simplex/';
const PASSTHROUGH_URI_PROD = 'https://bws.bitpay.com/static/simplex/';
Expand Down Expand Up @@ -102,11 +100,11 @@ const getUserAgent = (): string => {
};

const getAppVersion = (): string => {
return version;
return APP_VERSION;
};

const checkSimplexCoin = (coin: string): string => {
if (coin == 'PAX') {
if (coin === 'PAX') {
return 'USDP';
}
return coin;
Expand Down Expand Up @@ -201,7 +199,7 @@ export const getPaymentUrl = (

let str = '';
for (let key in dataSrc) {
if (str != '') {
if (str !== '') {
str += '&';
}
str += key + '=' + encodeURIComponent(dataSrc[key]);
Expand Down
151 changes: 106 additions & 45 deletions src/navigation/tabs/settings/about/screens/SessionLog.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import Slider from '@react-native-community/slider';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {memo, useState} from 'react';
import {useTranslation} from 'react-i18next';
import React, {useState, useCallback} from 'react';
import Mailer from 'react-native-mail';
import {Alert, FlatList} from 'react-native';
import {useSelector} from 'react-redux';
import Mailer from 'react-native-mail';
import styled from 'styled-components/native';
import {RootState} from '../../../../../store';
import {LogLevel} from '../../../../../store/log/log.models';
import {LogActions} from '../../../../../store/log';
import {AboutStackParamList} from '../AboutStack';
import Button from '../../../../../components/button/Button';
import {WIDTH} from '../../../../../components/styled/Containers';
import {BaseText} from '../../../../../components/styled/Text';
import {IS_ANDROID, IS_IOS} from '../../../../../constants';
import {APP_VERSION} from '../../../../../constants/config';
import {LogActions} from '../../../../../store/log';
import {LogEntry, LogLevel} from '../../../../../store/log/log.models';
import {
SlateDark,
Caution,
Warning,
LinkBlue,
SlateDark,
Warning,
White,
} from '../../../../../styles/colors';
import {BaseText} from '../../../../../components/styled/Text';
// @ts-ignore
import {version} from '../../../../../../package.json'; // TODO: better way to get version
import {useAppDispatch} from '../../../../../utils/hooks';
import {useAppDispatch, useAppSelector} from '../../../../../utils/hooks';
import {AboutStackParamList} from '../AboutStack';

export interface SessionLogsParamList {}

Expand All @@ -44,25 +44,76 @@ const Logs = styled(BaseText)<{color?: string | null}>`
color ? color : dark ? White : SlateDark};
`;

const SessionLogs: React.FC<SessionLogsScreenProps> = () => {
const FilterLabelsContainer = styled.View`
flex-direction: row;
margin-top: 16px;
`;

const FilterLabel = styled(BaseText)`
flex: 1 1 100%;
text-align: center;
`;

const MIN_LOG_LEVEL = LogLevel.Error;
const MAX_LOG_LEVEL = LogLevel.Debug;
const TOTAL_LOG_LEVELS = MAX_LOG_LEVEL - MIN_LOG_LEVEL + 1;

const THUMB_WIDTH = IS_IOS || IS_ANDROID ? 30 : 0;
const SLIDER_WIDTH =
((TOTAL_LOG_LEVELS - 1) / TOTAL_LOG_LEVELS) * WIDTH + THUMB_WIDTH;

const LogColorMap: Partial<{[key in LogLevel]: string | null}> = {
[LogLevel.Error]: Caution,
[LogLevel.Warn]: Warning,
[LogLevel.Debug]: LinkBlue,
};

const FilterLabels: React.VFC<{onPress?: (level: LogLevel) => any}> = memo(
props => {
const levels = [];

for (let i = MIN_LOG_LEVEL; i <= MAX_LOG_LEVEL; ++i) {
levels.push(i);
}

return (
<FilterLabelsContainer>
{levels.map(level => (
<FilterLabel onPress={() => props.onPress?.(level)} key={level}>
{LogLevel[level]}
</FilterLabel>
))}
</FilterLabelsContainer>
);
},
);

const renderItem = ({item}: {item: LogEntry}) => (
<Logs color={LogColorMap[item.level]}>
[{LogLevel[item.level]}] {item.message}
</Logs>
);

const keyExtractor = (item: LogEntry, index: number) => item.message + index;

const SessionLogs: React.VFC<SessionLogsScreenProps> = () => {
const {t} = useTranslation();
const dispatch = useAppDispatch();
const logs = useSelector(({LOG}: RootState) => LOG.logs);
const [filterLevel] = useState(LogLevel.None);
const logs = useAppSelector(({LOG}) => LOG.logs);
const [filterLevel, setFilterLevel] = useState(LogLevel.Info);

const filteredLogs = logs.filter(log => log.level <= filterLevel);

let logStr: string =
'Session Logs.\nBe careful, this could contain sensitive private data\n\n';
logStr += filteredLogs.map(log => {
const formattedLevel = LogLevel[log.level].toLowerCase();
return `[${log.timestamp}] [${formattedLevel}] ${log.message}\n`;
});
const onFilterLevelChange = (level: LogLevel) => {
if (level !== filterLevel) {
setFilterLevel(level);
}
};

const handleEmail = (data: string) => {
Mailer.mail(
{
subject: `BitPay v${version} Logs`,
subject: `BitPay v${APP_VERSION} Logs`,
body: data,
isHTML: false,
},
Expand All @@ -77,33 +128,26 @@ const SessionLogs: React.FC<SessionLogsScreenProps> = () => {
);
};

const showDisclaimer = (data: string) => {
const showDisclaimer = () => {
let logStr =
'Session Logs.\nBe careful, this could contain sensitive private data\n\n';
logStr += filteredLogs.map(log => {
const formattedLevel = LogLevel[log.level].toLowerCase();

return `[${log.timestamp}] [${formattedLevel}] ${log.message}\n`;
});

Alert.alert(
'Warning',
'Be careful, this could contain sensitive private data.',
[{text: 'Continue', onPress: () => handleEmail(data)}, {text: 'Cancel'}],
[
{text: 'Continue', onPress: () => handleEmail(logStr)},
{text: 'Cancel'},
],
{cancelable: true},
);
};

const renderItem = useCallback(
({item}) => (
<Logs
color={
LogLevel[item.level].toLowerCase() === 'error'
? Caution
: LogLevel[item.level].toLowerCase() === 'warn'
? Warning
: LogLevel[item.level].toLowerCase() === 'debug'
? LinkBlue
: null
}>
[{LogLevel[item.level]}] {item.message}
</Logs>
),
[],
);

return (
<LogsContainer>
<FlatList
Expand All @@ -113,10 +157,27 @@ const SessionLogs: React.FC<SessionLogsScreenProps> = () => {
}}
data={filteredLogs}
renderItem={renderItem}
keyExtractor={(item, index) => item.message + index}
keyExtractor={keyExtractor}
/>

<FilterLabels onPress={onFilterLevelChange} />

<Slider
step={1}
value={filterLevel}
minimumValue={MIN_LOG_LEVEL}
maximumValue={MAX_LOG_LEVEL}
onValueChange={onFilterLevelChange}
style={{
alignSelf: 'center',
width: SLIDER_WIDTH,
}}
// iOS
tapToSeek={true}
/>

<ButtonContainer>
<Button onPress={() => showDisclaimer(logStr)}>
<Button onPress={() => showDisclaimer()}>
{t('Send Logs By Email')}
</Button>
</ButtonContainer>
Expand Down
5 changes: 2 additions & 3 deletions src/navigation/tabs/settings/components/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import {
SettingTitle,
} from '../../../../components/styled/Containers';
import Button from '../../../../components/button/Button';
// @ts-ignore
import {version} from '../../../../../package.json'; // TODO: better way to get version
import {useNavigation} from '@react-navigation/native';
import {URL} from '../../../../constants';
import {APP_VERSION} from '../../../../constants/config';
import {useTranslation} from 'react-i18next';
import {View} from 'react-native';
import {useDispatch} from 'react-redux';
Expand Down Expand Up @@ -59,7 +58,7 @@ const About = () => {
<Setting>
<SettingTitle>{t('Version')}</SettingTitle>

<Button buttonType="pill">{version}</Button>
<Button buttonType="pill">{APP_VERSION}</Button>
</Setting>

<Hr />
Expand Down
13 changes: 6 additions & 7 deletions src/store/app/app.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ export const startAppInit = (): Effect => async (dispatch, getState) => {
dispatch(LogActions.clear());
dispatch(LogActions.info(`Initializing app (${__DEV__ ? 'D' : 'P'})...`));

const {APP, BITPAY_ID} = getState();
const {network, pinLockActive, biometricLockActive, colorScheme} = APP;

dispatch(LogActions.debug(`Network: ${network}`));
dispatch(LogActions.debug(`Theme: ${colorScheme || 'system'}`));

await dispatch(startWalletStoreInit());

const {appFirstOpenData, onboardingCompleted, migrationComplete} =
Expand All @@ -93,13 +99,6 @@ export const startAppInit = (): Effect => async (dispatch, getState) => {
dispatch(LogActions.info('success [setMigrationComplete]'));
}

const {BITPAY_ID} = getState();
const {network, pinLockActive, biometricLockActive, colorScheme} =
getState().APP;

dispatch(LogActions.debug(`Network: ${network}`));
dispatch(LogActions.debug(`Theme: ${colorScheme || 'system'}`));

const token = BITPAY_ID.apiToken[network];
const isPaired = !!token;
const identity = dispatch(initializeAppIdentity());
Expand Down
Loading

0 comments on commit 3d05d9f

Please sign in to comment.