Files
actual/packages/desktop-client/src/components/accounts/AccountSyncCheck.tsx
Joel Jeremy Marquez e078ed21ba [Typescript migration] Migrate AccountSyncCheck to ts (#3757)
* Migrate AccountSyncCheck to ts

* Release notes

* Fix lint
2024-11-03 13:04:43 -08:00

189 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useCallback, useRef, useState } from 'react';
import { Trans } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { t } from 'i18next';
import { unlinkAccount } from 'loot-core/client/actions';
import { type AccountEntity } from 'loot-core/types/models';
import { authorizeBank } from '../../gocardless';
import { useAccounts } from '../../hooks/useAccounts';
import { SvgExclamationOutline } from '../../icons/v1';
import { theme } from '../../style';
import { Button } from '../common/Button2';
import { Link } from '../common/Link';
import { Popover } from '../common/Popover';
import { View } from '../common/View';
function getErrorMessage(type: string, code: string) {
switch (type.toUpperCase()) {
case 'ITEM_ERROR':
switch (code.toUpperCase()) {
case 'NO_ACCOUNTS':
return t(
'No open accounts could be found. Did you close the account? If so, unlink the account.',
);
case 'ITEM_LOGIN_REQUIRED':
return t(
'Your password or something else has changed with your bank and you need to login again.',
);
default:
}
break;
case 'INVALID_INPUT':
switch (code.toUpperCase()) {
case 'INVALID_ACCESS_TOKEN':
return t('Item is no longer authorized. You need to login again.');
default:
}
break;
case 'RATE_LIMIT_EXCEEDED':
return t('Rate limit exceeded for this item. Please try again later.');
case 'INVALID_ACCESS_TOKEN':
return t(
'Your SimpleFIN Access Token is no longer valid. Please reset and generate a new token.',
);
case 'ACCOUNT_NEEDS_ATTENTION':
return (
<Trans>
The account needs your attention at{' '}
<Link variant="external" to="https://bridge.simplefin.org/auth/login">
SimpleFIN
</Link>
.
</Trans>
);
default:
}
return (
<Trans>
An internal error occurred. Try to login again, or get{' '}
<Link variant="external" to="https://actualbudget.org/contact/">
in touch
</Link>{' '}
for support.
</Trans>
);
}
export function AccountSyncCheck() {
const accounts = useAccounts();
const failedAccounts = useSelector(state => state.account.failedAccounts);
const dispatch = useDispatch();
const { id } = useParams();
const [open, setOpen] = useState(false);
const triggerRef = useRef(null);
const reauth = useCallback(
(acc: AccountEntity) => {
setOpen(false);
if (acc.account_id) {
authorizeBank(dispatch, { upgradingAccountId: acc.account_id });
}
},
[dispatch],
);
const unlink = useCallback(
(acc: AccountEntity) => {
if (acc.id) {
dispatch(unlinkAccount(acc.id));
}
setOpen(false);
},
[dispatch],
);
if (!failedAccounts || !id) {
return null;
}
const error = failedAccounts.get(id);
if (!error) {
return null;
}
const account = accounts.find(account => account.id === id);
if (!account) {
return null;
}
const { type, code } = error;
const showAuth =
(type === 'ITEM_ERROR' && code === 'ITEM_LOGIN_REQUIRED') ||
(type === 'INVALID_INPUT' && code === 'INVALID_ACCESS_TOKEN');
return (
<View>
<Button
ref={triggerRef}
variant="bare"
style={{
flexDirection: 'row',
alignItems: 'center',
color: theme.errorText,
backgroundColor: theme.errorBackground,
padding: '4px 8px',
borderRadius: 4,
}}
onPress={() => setOpen(true)}
>
<SvgExclamationOutline
style={{ width: 14, height: 14, marginRight: 5 }}
/>{' '}
<Trans>
This account is experiencing connection problems. Lets fix it.
</Trans>
</Button>
<Popover
triggerRef={triggerRef}
placement="bottom start"
isOpen={open}
onOpenChange={() => setOpen(false)}
style={{ fontSize: 14, padding: 15, maxWidth: 400 }}
>
<div style={{ marginBottom: '1.15em' }}>
<Trans>The server returned the following error:</Trans>
</div>
<div style={{ marginBottom: '1.25em', color: theme.errorText }}>
{getErrorMessage(error.type, error.code)}
</div>
<View style={{ justifyContent: 'flex-end', flexDirection: 'row' }}>
{showAuth ? (
<>
<Button onPress={() => unlink(account)}>
<Trans>Unlink</Trans>
</Button>
<Button
variant="primary"
autoFocus
onPress={() => reauth(account)}
style={{ marginLeft: 5 }}
>
<Trans>Reauthorize</Trans>
</Button>
</>
) : (
<Button onPress={() => unlink(account)}>
<Trans>Unlink account</Trans>
</Button>
)}
</View>
</Popover>
</View>
);
}