diff --git a/src/components/Charts/AssetsHistoryChart.tsx b/src/components/Charts/AssetsHistoryChart.tsx index dbd8d69..cd50132 100644 --- a/src/components/Charts/AssetsHistoryChart.tsx +++ b/src/components/Charts/AssetsHistoryChart.tsx @@ -21,6 +21,7 @@ import { RootDispatch, RootState } from '../../store'; import Loading from '../UI/Loading'; import translate from '../../i18n/locale'; import { useThemeColors } from '../../lib/common'; +import ErrorBoundary from '../UI/ErrorBoundary'; function AccountsLengthMessage() { return ( @@ -154,124 +155,130 @@ export default function AssetsHistoryChart() { }, [start, end]); return useMemo(() => ( - - + + - - {translate('assets_history_chart')} - {' '} - {currentCode} - - { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(); - dispatch.firefly.getAccountChart(); + - - - - - {loading && ( - - - + + {translate('assets_history_chart')} + {' '} + {currentCode} + + { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(); + dispatch.firefly.getAccountChart(); + }} + > + + - - )} - {!loading && ( - datum.childName} - labelComponent={( - !v.skip), (c: { maxY: number }) => c.maxY)?.maxY || 0} - minY={minBy(accounts.filter((v) => !v.skip), (c: { minY: number }) => c.minY)?.minY || 0} - colors={colors} - /> - )} - /> - )} - > - ((x !== 0) ? `${(Math.round(x) / 1000)}k` : '0')} - style={{ - grid: { stroke: '#949494', strokeWidth: 0.2 }, - axis: { stroke: colors.brandLight }, - tickLabels: { - fill: colors.text, - fontWeight: 200, - }, - }} - /> - (new Date(x).toLocaleString(Localization.locale, { month: 'short' }))} - style={{ - grid: { stroke: '#949494', strokeWidth: 0.2 }, - axis: { stroke: colors.brandLight }, - tickLabels: { - fill: colors.text, - fontWeight: 200, - angle: getTickValues().length > 7 ? -40 : 0, - }, - }} - /> - {accounts.filter((v) => !v.skip).map((chart) => chart.entries.length > 0 && ( - + {loading && ( + + + + + + )} + {!loading && ( + - ))} - - )} - {accounts.length > 4 && ()} - - - - ), [loading, accounts]); + height={400} + domainPadding={2} + containerComponent={( + datum.childName} + labelComponent={( + c.maxY)?.maxY || 0} + minY={minBy(accounts, (c: { minY: number }) => c.minY)?.minY || 0} + colors={colors} + /> + )} + /> + )} + > + ((x !== 0) ? `${(Math.round(x) / 1000)}k` : '0')} + style={{ + grid: { stroke: '#949494', strokeWidth: 0.2 }, + axis: { stroke: colors.brandLight }, + tickLabels: { + fill: colors.text, + fontWeight: 200, + }, + }} + /> + (new Date(x).toLocaleString(Localization.locale, { month: 'short' }))} + style={{ + grid: { stroke: '#949494', strokeWidth: 0.2 }, + axis: { stroke: colors.brandLight }, + tickLabels: { + fill: colors.text, + fontWeight: 200, + angle: getTickValues().length > 7 ? -40 : 0, + }, + }} + /> + {accounts.map((chart) => chart.entries.length > 0 && ( + + ))} + + )} + {accounts.length > 4 && ()} + + + + + ), [ + loading, + accounts, + colors, + ]); } diff --git a/src/components/Charts/BalanceHistoryChart.tsx b/src/components/Charts/BalanceHistoryChart.tsx index 970c6f6..4dcba7b 100644 --- a/src/components/Charts/BalanceHistoryChart.tsx +++ b/src/components/Charts/BalanceHistoryChart.tsx @@ -18,6 +18,7 @@ import { useThemeColors } from '../../lib/common'; import { RootDispatch, RootState } from '../../store'; import translate from '../../i18n/locale'; import { AStack, AText } from '../UI/ALibrary'; +import ErrorBoundary from '../UI/ErrorBoundary'; export default function BalanceHistoryChart() { const { colors } = useThemeColors(); @@ -43,163 +44,165 @@ export default function BalanceHistoryChart() { }, [start, end]); return ( - - + + - - {translate('balance_history_chart')} - {' '} - {currentCode} - - { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(); - dispatch.firefly.getBalanceChart(); + - - - - {loading && ( + + {translate('balance_history_chart')} + {' '} + {currentCode} + + { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(); + dispatch.firefly.getBalanceChart(); + }} + > + + + + {loading && ( - )} - {!loading && (!isEmpty(spentChart) || !isEmpty(earnedChart)) && ( - - ((x !== 0) ? `${(Math.round(x) / 1000)}k` : '0')} - style={{ - axis: { stroke: colors.brandLight }, - tickLabels: { - fill: colors.text, - fontWeight: 200, - }, + )} + {!loading && (!isEmpty(spentChart) || !isEmpty(earnedChart)) && ( + + height={400} + domainPadding={10} + minDomain={{ x: 0.5 }} + > + ((x !== 0) ? `${(Math.round(x) / 1000)}k` : '0')} + style={{ + axis: { stroke: colors.brandLight }, + tickLabels: { + fill: colors.text, + fontWeight: 200, + }, + }} + /> - (new Date(x).toLocaleString(Localization.locale, { month: 'short' }))} - style={{ - axis: { stroke: colors.brandLight }, - tickLabels: { - fill: colors.text, - fontWeight: 200, - angle: getTickValues().length > 7 ? -40 : 0, - }, - }} - /> + (new Date(x).toLocaleString(Localization.locale, { month: 'short' }))} + style={{ + axis: { stroke: colors.brandLight }, + tickLabels: { + fill: colors.text, + fontWeight: 200, + angle: getTickValues().length > 7 ? -40 : 0, + }, + }} + /> - {!isEmpty(earnedChart) && ( - ((datum._y === 0) ? 0 : 7) }} - style={{ - data: { - fill: colors.brandStyle70, - width: 15, - }, - }} - data={earnedChart} - name="gain" - /> - )} + {!isEmpty(earnedChart) && ( + ((datum._y === 0) ? 0 : 7) }} + style={{ + data: { + fill: colors.brandStyle70, + width: 15, + }, + }} + data={earnedChart} + name="gain" + /> + )} - {!isEmpty(spentChart) && ( - ((datum._y === 0) ? 0 : 7) }} - style={{ - data: { - fill: colors.brandStyle20, - width: 15, - }, - }} - data={spentChart} - name="loose" - /> - )} + {!isEmpty(spentChart) && ( + ((datum._y === 0) ? 0 : 7) }} + style={{ + data: { + fill: colors.brandStyle20, + width: 15, + }, + }} + data={spentChart} + name="loose" + /> + )} - {!isEmpty(earnedChart) && !isEmpty(spentChart) && ( - ({ x: pts.x, y: pts.y + spentChart[index].y }))} - name="lineBalance" - /> - )} + {!isEmpty(earnedChart) && !isEmpty(spentChart) && ( + ({ x: pts.x, y: pts.y + spentChart[index].y }))} + name="lineBalance" + /> + )} - {!isEmpty(earnedChart) && !isEmpty(spentChart) && ( - ((datum.y < 0) ? colors.red : colors.green), - strokeWidth: 5, - }, - labels: { - fontSize: 10, - fontWeight: 600, - fill: colors.text, - }, - }} - size={7} - labels={({ datum }) => (datum.y !== 0 ? `${(round(datum.y / 1000, 1))}k` : '')} - data={earnedChart.map((pts, index) => ({ x: pts.x, y: pts.y + spentChart[index].y }))} - name="ptsBalance" - /> + {!isEmpty(earnedChart) && !isEmpty(spentChart) && ( + ((datum.y < 0) ? colors.red : colors.green), + strokeWidth: 5, + }, + labels: { + fontSize: 10, + fontWeight: 600, + fill: colors.text, + }, + }} + size={7} + labels={({ datum }) => (datum.y !== 0 ? `${(round(datum.y / 1000, 1))}k` : '')} + data={earnedChart.map((pts, index) => ({ x: pts.x, y: pts.y + spentChart[index].y }))} + name="ptsBalance" + /> + )} + )} - - )} - {!loading && (isEmpty(spentChart) && isEmpty(earnedChart)) && ( + {!loading && (isEmpty(spentChart) && isEmpty(earnedChart)) && ( {translate('balance_history_chart_no_data')} - )} - - - + )} + + + + ); } diff --git a/src/components/Forms/OauthForm.tsx b/src/components/Forms/OauthForm.tsx index 4fa2fd4..fe387df 100644 --- a/src/components/Forms/OauthForm.tsx +++ b/src/components/Forms/OauthForm.tsx @@ -9,10 +9,13 @@ import { Text, Switch, ScrollView, - KeyboardAvoidingView, } from 'native-base'; import { - Alert, Platform, View, Pressable, + View, + Pressable, + KeyboardAvoidingView, + Platform, + Alert, } from 'react-native'; import * as Haptics from 'expo-haptics'; import * as Clipboard from 'expo-clipboard'; @@ -63,13 +66,8 @@ export default function OauthForm({ return ( @@ -272,7 +270,7 @@ export default function OauthForm({ )} - + ); diff --git a/src/components/Screens/ChartScreen.tsx b/src/components/Screens/ChartScreen.tsx index 50b2fe1..2b1e034 100644 --- a/src/components/Screens/ChartScreen.tsx +++ b/src/components/Screens/ChartScreen.tsx @@ -94,5 +94,5 @@ export default function ChartScreen() { - ), []); + ), [colors]); } diff --git a/src/components/Screens/HomeScreen.tsx b/src/components/Screens/HomeScreen.tsx index 390f24f..52b7a73 100644 --- a/src/components/Screens/HomeScreen.tsx +++ b/src/components/Screens/HomeScreen.tsx @@ -377,7 +377,14 @@ function NetWorth() { )} - ), [loading, hideBalance]); + ), [ + loading, + hideBalance, + colors, + netWorth, + balance, + currentCode, + ]); } export default function HomeScreen({ navigation }: ScreenType) { @@ -532,5 +539,5 @@ export default function HomeScreen({ navigation }: ScreenType) { - ), [])); + ), [colors])); } diff --git a/src/components/Screens/TransactionsScreen.tsx b/src/components/Screens/TransactionsScreen.tsx index 2116732..81887e0 100644 --- a/src/components/Screens/TransactionsScreen.tsx +++ b/src/components/Screens/TransactionsScreen.tsx @@ -77,6 +77,7 @@ function ListFooterComponent({ loadMore, initLoading }) { )} ), [ + colors, page, totalPages, loading, @@ -241,7 +242,7 @@ function RenderItem({ item }: { item: TransactionType }) { - ), [item]); + ), [item, colors]); } async function deleteAlert(transaction: TransactionType, rowMap, closeRow, deleteRow) { diff --git a/src/components/UI/ALibrary/AStack.tsx b/src/components/UI/ALibrary/AStack.tsx index e804403..e110d4c 100644 --- a/src/components/UI/ALibrary/AStack.tsx +++ b/src/components/UI/ALibrary/AStack.tsx @@ -35,6 +35,7 @@ type AStackType = { justifyContent?: 'center' | 'flex-start' | 'flex-end' | 'space-between' | 'space-around' | 'space-evenly' alignItems?: FlexAlignType backgroundColor?: string + flexWrap?: 'wrap' | 'nowrap' style?: AStyle children: React.ReactNode } @@ -49,6 +50,7 @@ export default function AStack({ justifyContent = 'center', alignItems = 'center', backgroundColor = 'transparent', + flexWrap = 'nowrap', style = {}, children, }: AStackType) { @@ -61,6 +63,7 @@ export default function AStack({ justifyContent, alignItems, backgroundColor, + flexWrap, paddingHorizontal: px, paddingVertical: py, marginHorizontal: mx, diff --git a/src/components/UI/ErrorBoundary.tsx b/src/components/UI/ErrorBoundary.tsx new file mode 100644 index 0000000..822ddb7 --- /dev/null +++ b/src/components/UI/ErrorBoundary.tsx @@ -0,0 +1,46 @@ +import React, { ErrorInfo, ReactNode } from 'react'; +import { View } from 'react-native'; +import { AText } from './ALibrary'; + +interface ErrorBoundaryProps { + children: ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; + error: Error | null; + errorInfo: ErrorInfo | null; +} + +class ErrorBoundary extends React.Component { + constructor(props) { + super(props); + this.state = { hasError: false, error: null, errorInfo: null }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + this.setState({ + hasError: true, + error, + errorInfo, + }); + } + + render() { + const { hasError, error, errorInfo } = this.state; + const { children } = this.props; + if (hasError) { + return ( + + Something went wrong! + {error?.message} + {errorInfo?.componentStack} + + ); + } + + return children as ReactNode; + } +} + +export default ErrorBoundary; diff --git a/src/components/UI/Filters.tsx b/src/components/UI/Filters.tsx index 7058aa7..4352591 100644 --- a/src/components/UI/Filters.tsx +++ b/src/components/UI/Filters.tsx @@ -1,10 +1,15 @@ import React, { useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { HStack, VStack } from 'native-base'; -import { Text, TouchableOpacity, View } from 'react-native'; +import { + Text, + TouchableOpacity, + View, + ScrollView, +} from 'react-native'; import { useNavigation } from '@react-navigation/native'; - import { AntDesign, Ionicons } from '@expo/vector-icons'; + +import { AStack } from './ALibrary'; import { RootDispatch, RootState } from '../../store'; import translate from '../../i18n/locale'; import { useThemeColors } from '../../lib/common'; @@ -33,13 +38,13 @@ export default function Filters() { } = useDispatch(); return useMemo(() => ( - - - + {currencies.map((currency) => ( ))} - + - + {[1, 3, 6, 12].map((period) => ( ))} - + {translate('home_accounts')} - + {accounts.map((account) => ( - - + + + ), [ range, currencies, diff --git a/src/components/UI/NavigationHeader.tsx b/src/components/UI/NavigationHeader.tsx index e7693a0..4fad407 100644 --- a/src/components/UI/NavigationHeader.tsx +++ b/src/components/UI/NavigationHeader.tsx @@ -43,6 +43,7 @@ export default function NavigationHeader({ navigation }): React.ReactNode { range, start, end, + colors, ]); } @@ -152,5 +153,6 @@ export default function NavigationHeader({ navigation }): React.ReactNode { range, start, end, + colors, ]); }