-
Joel Jeremy Marquez authored
* Mobile create account * Release notes * Update add button style * Add back desktop page header padding * Empty accounts handling * decimal keyboard on CreateLocalAccount balance input * VRT updates
Joel Jeremy Marquez authored* Mobile create account * Release notes * Update add button style * Add back desktop page header padding * Empty accounts handling * decimal keyboard on CreateLocalAccount balance input * VRT updates
MobileAccounts.js 7.48 KiB
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import * as queries from 'loot-core/src/client/queries';
import { useActions } from '../../hooks/useActions';
import useCategories from '../../hooks/useCategories';
import useNavigate from '../../hooks/useNavigate';
import { useSetThemeColor } from '../../hooks/useSetThemeColor';
import Add from '../../icons/v1/Add';
import { theme, styles } from '../../style';
import Button from '../common/Button';
import Text from '../common/Text';
import TextOneLine from '../common/TextOneLine';
import View from '../common/View';
import { Page } from '../Page';
import PullToRefresh from '../responsive/PullToRefresh';
import CellValue from '../spreadsheet/CellValue';
function AccountHeader({ name, amount, style = {} }) {
return (
<View
style={{
flex: '1 0 auto',
flexDirection: 'row',
marginTop: 10,
marginRight: 10,
color: theme.pageTextLight,
...style,
}}
>
<View style={{ flex: 1 }}>
<Text
style={{
...styles.text,
textTransform: 'uppercase',
fontSize: 13,
}}
data-testid="name"
>
{name}
</Text>
</View>
<CellValue
binding={amount}
style={{ ...styles.text, fontSize: 13 }}
type="financial"
/>
</View>
);
}
function AccountCard({ account, updated, getBalanceQuery, onSelect }) {
return (
<View
style={{
flex: '1 0 auto',
flexDirection: 'row',
backgroundColor: theme.tableBackground,
boxShadow: `0 1px 1px ${theme.mobileAccountShadow}`,
borderRadius: 6,
marginTop: 10,
marginRight: 10,
}}
data-testid="account"
>
<Button
onMouseDown={() => onSelect(account.id)}
style={{
flexDirection: 'row',
flex: 1,
alignItems: 'center',
borderRadius: 6,
'&:active': {
opacity: 0.1,
},
}}
>
<View
style={{
flex: '1 auto',
margin: '10px 0',
}}
>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}
>
<TextOneLine
style={{
...styles.text,
fontSize: 17,
fontWeight: 600,
color: updated ? theme.mobileAccountText : theme.pillText,
paddingRight: 30,
}}
data-testid="account-name"
>
{account.name}
</TextOneLine>
{account.bankId && (
<View
style={{
backgroundColor: theme.noticeBackgroundDark,
marginLeft: '-23px',
width: 8,
height: 8,
borderRadius: 8,
}}
/>
)}
</View>
</View>
<CellValue
binding={getBalanceQuery(account)}
type="financial"
style={{ fontSize: 16, color: 'inherit' }}
getStyle={value => value < 0 && { color: 'inherit' }}
data-testid="account-balance"
/>
</Button>
</View>
);
}
function EmptyMessage() {
return (
<View style={{ flex: 1, padding: 30 }}>
<Text style={styles.text}>
For Actual to be useful, you need to add an account. You can link an
account to automatically download transactions, or manage it locally
yourself.
</Text>
</View>
);
}
function AccountList({
accounts,
updatedAccounts,
getBalanceQuery,
getOnBudgetBalance,
getOffBudgetBalance,
onAddAccount,
onSelectAccount,
onSync,
}) {
const budgetedAccounts = accounts.filter(account => account.offbudget === 0);
const offbudgetAccounts = accounts.filter(account => account.offbudget === 1);
const noBackgroundColorStyle = {
backgroundColor: 'transparent',
color: 'white',
};
return (
<View style={{ flex: 1, backgroundColor: theme.mobilePageBackground }}>
<Page
title="Accounts"
titleStyle={{
backgroundColor: theme.mobileHeaderBackground,
color: theme.mobileHeaderText,
fontSize: 16,
}}
headerRightContent={
<Button
type="bare"
style={{
paddingLeft: 12,
paddingRight: 12,
...noBackgroundColorStyle,
}}
activeStyle={noBackgroundColorStyle}
hoveredStyle={noBackgroundColorStyle}
onClick={onAddAccount}
>
<Add width={20} height={20} />
</Button>
}
>
{accounts.length === 0 && <EmptyMessage />}
<PullToRefresh onRefresh={onSync}>
{budgetedAccounts.length > 0 && (
<AccountHeader name="For Budget" amount={getOnBudgetBalance()} />
)}
{budgetedAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
{offbudgetAccounts.length > 0 && (
<AccountHeader
name="Off budget"
amount={getOffBudgetBalance()}
style={{ marginTop: 30 }}
/>
)}
{offbudgetAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
</PullToRefresh>
</Page>
</View>
);
}
export default function Accounts() {
let accounts = useSelector(state => state.queries.accounts);
let newTransactions = useSelector(state => state.queries.newTransactions);
let updatedAccounts = useSelector(state => state.queries.updatedAccounts);
let numberFormat = useSelector(
state => state.prefs.local.numberFormat || 'comma-dot',
);
let hideFraction = useSelector(
state => state.prefs.local.hideFraction || false,
);
const { list: categories } = useCategories();
let { getAccounts, replaceModal, syncAndDownload } = useActions();
const transactions = useState({});
const navigate = useNavigate();
useEffect(() => {
(async () => getAccounts())();
}, []);
const onSelectAccount = id => {
navigate(`/accounts/${id}`);
};
const onSelectTransaction = transaction => {
navigate(`/transaction/${transaction}`);
};
useSetThemeColor(theme.mobileViewTheme);
return (
<View style={{ flex: 1 }}>
<AccountList
// This key forces the whole table rerender when the number
// format changes
key={numberFormat + hideFraction}
accounts={accounts.filter(account => !account.closed)}
categories={categories}
transactions={transactions || []}
updatedAccounts={updatedAccounts}
newTransactions={newTransactions}
getBalanceQuery={queries.accountBalance}
getOnBudgetBalance={queries.budgetedAccountBalance}
getOffBudgetBalance={queries.offbudgetAccountBalance}
onAddAccount={() => replaceModal('add-account')}
onSelectAccount={onSelectAccount}
onSelectTransaction={onSelectTransaction}
onSync={syncAndDownload}
/>
</View>
);
}