-
Joel Jeremy Marquez authored
* Final PR for react-aria-components Modal migration * Complete manager modals migration * Release notes * fix lint * Apps full height * Fix lint error * VRT * Centralize providers * Feedback
Joel Jeremy Marquez authored* Final PR for react-aria-components Modal migration * Complete manager modals migration * Release notes * fix lint * Apps full height * Fix lint error * VRT * Centralize providers * Feedback
MergeUnusedPayeesModal.jsx 5.71 KiB
import React, { useState, useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { replaceModal } from 'loot-core/src/client/actions/modals';
import { send } from 'loot-core/src/platform/client/fetch';
import { usePayees } from '../../hooks/usePayees';
import { theme } from '../../style';
import { Information } from '../alerts';
import { Button } from '../common/Button2';
import { Modal, ModalButtons } from '../common/Modal';
import { Paragraph } from '../common/Paragraph';
import { Text } from '../common/Text';
import { View } from '../common/View';
const highlightStyle = { color: theme.pageTextPositive };
export function MergeUnusedPayeesModal({ payeeIds, targetPayeeId }) {
const allPayees = usePayees();
const modalStack = useSelector(state => state.modals.modalStack);
const isEditingRule = !!modalStack.find(m => m.name === 'edit-rule');
const dispatch = useDispatch();
const [shouldCreateRule, setShouldCreateRule] = useState(true);
const flashRef = useRef(null);
useEffect(() => {
// Flash the scrollbar
if (flashRef.current) {
const el = flashRef.current;
const top = el.scrollTop;
el.scrollTop = top + 1;
el.scrollTop = top;
}
}, []);
// We store the orphaned payees into state because when we merge it,
// it will be deleted and this component will automatically
// rerender. Is there a better pattern for live bindings?
//
// TODO: I think a custom `useSelector` hook that doesn't bind would
// be nice
const [payees] = useState(() =>
payeeIds.map(id => allPayees.find(p => p.id === id)),
);
const targetPayee = allPayees.find(p => p.id === targetPayeeId);
if (!targetPayee) {
return null;
}
async function onMerge() {
await send('payees-merge', {
targetId: targetPayee.id,
mergeIds: payees.map(p => p.id),
});
let ruleId;
if (shouldCreateRule && !isEditingRule) {
const id = await send('rule-add-payee-rename', {
fromNames: payees.map(p => p.name),
to: targetPayee.id,
});
ruleId = id;
}
return ruleId;
}
async function onMergeAndCreateRule() {
const ruleId = await onMerge();
if (ruleId) {
const rule = await send('rule-get', { id: ruleId });
dispatch(replaceModal('edit-rule', { rule }));
}
}
return (
<Modal name="merge-unused-payees">
{({ state: { close } }) => (
<View style={{ padding: 20, maxWidth: 500 }}>
<View>
<Paragraph style={{ marginBottom: 10, fontWeight: 500 }}>
{payees.length === 1 ? (
<>
The payee <Text style={highlightStyle}>{payees[0].name}</Text>{' '}
is not used by transactions any more. Would like to merge it
with <Text style={highlightStyle}>{targetPayee.name}</Text>?
</>
) : (
<>
The following payees are not used by transactions any more.
Would like to merge them with{' '}
<Text style={highlightStyle}>{targetPayee.name}</Text>?
<ul
ref={flashRef}
style={{
margin: 0,
marginTop: 10,
maxHeight: 140,
overflow: 'auto',
}}
>
{payees.map(p => (
<li key={p.id}>
<Text style={highlightStyle}>{p.name}</Text>
</li>
))}
</ul>
</>
)}
</Paragraph>
<Information>
Merging will remove the payee and transfer any existing rules to
the new payee.
{!isEditingRule && (
<>
{' '}
If checked below, a rule will be created to do this rename
while importing transactions.
</>
)}
</Information>
{!isEditingRule && (
<label
style={{
fontSize: 13,
marginTop: 10,
color: theme.pageTextLight,
userSelect: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<input
type="checkbox"
checked={shouldCreateRule}
onChange={e => setShouldCreateRule(e.target.checked)}
/>
<Text style={{ marginLeft: 3 }}>
Automatically rename{' '}
{payees.length === 1 ? 'this payee' : 'these payees'} in the
future
</Text>
</label>
)}
<ModalButtons style={{ marginTop: 20 }} focusButton>
<Button
variant="primary"
autoFocus
style={{ marginRight: 10 }}
onPress={() => {
onMerge();
close();
}}
>
Merge
</Button>
{!isEditingRule && (
<Button
style={{ marginRight: 10 }}
onPress={() => {
onMergeAndCreateRule();
close();
}}
>
Merge and edit rule
</Button>
)}
<Button style={{ marginRight: 10 }} onPress={close}>
Do nothing
</Button>
</ModalButtons>
</View>
</View>
)}
</Modal>
);
}