Skip to content

Commit

Permalink
[Feature] Add ability to create schedules from existing transactions (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
xentara1 authored Feb 3, 2024
1 parent a5ab1a8 commit 29a515f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 15 deletions.
3 changes: 3 additions & 0 deletions packages/desktop-client/src/components/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ export function Modals() {
modalProps={modalProps}
id={options?.id || null}
actions={actions}
transaction={options?.transaction || null}
/>
);

Expand All @@ -320,6 +321,8 @@ export function Modals() {
modalProps={modalProps}
actions={actions}
transactionIds={options?.transactionIds}
getTransaction={options?.getTransaction}
pushModal={options?.pushModal}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ function updateScheduleConditions(schedule, fields) {
};
}

export function ScheduleDetails({ modalProps, actions, id }) {
export function ScheduleDetails({ modalProps, actions, id, transaction }) {
const adding = id == null;
const fromTrans = transaction != null;
const payees = useCachedPayees({ idKey: true });
const globalDispatch = useDispatch();
const dateFormat = useSelector(state => {
return state.prefs.local.dateFormat || 'MM/dd/yyyy';
});

const [state, dispatch] = useReducer(
(state, action) => {
switch (action.type) {
Expand Down Expand Up @@ -143,6 +143,11 @@ export function ScheduleDetails({ modalProps, actions, id }) {
fields: { ...state.fields, ...fields },
};
case 'set-transactions':
if (fromTrans && action.transactions) {
action.transactions.sort(a => {
return transaction.id === a.id ? -1 : 1;
});
}
return { ...state, transactions: action.transactions };
case 'set-repeats':
return {
Expand Down Expand Up @@ -210,12 +215,30 @@ export function ScheduleDetails({ modalProps, actions, id }) {
endOccurrences: '1',
endDate: monthUtils.currentDay(),
};
const schedule = {
posts_transaction: false,
_date: date,
_conditions: [{ op: 'isapprox', field: 'date', value: date }],
_actions: [],
};

const schedule = fromTrans
? {
posts_transaction: false,
_conditions: [{ op: 'isapprox', field: 'date', value: date }],
_actions: [],
_account: transaction.account,
_amount: transaction.amount,
_amountOp: 'is',
name: transaction.payee ? payees[transaction.payee].name : '',
_payee: transaction.payee ? transaction.payee : '',
_date: {
...date,
frequency: 'monthly',
start: transaction.date,
patterns: [],
},
}
: {
posts_transaction: false,
_date: date,
_conditions: [{ op: 'isapprox', field: 'date', value: date }],
_actions: [],
};

dispatch({ type: 'set-schedule', schedule });
} else {
Expand All @@ -226,6 +249,7 @@ export function ScheduleDetails({ modalProps, actions, id }) {
}
}
}

run();
}, []);

Expand Down Expand Up @@ -321,7 +345,11 @@ export function ScheduleDetails({ modalProps, actions, id }) {
};
}, [state.schedule, state.transactionsMode, state.fields]);

const selectedInst = useSelected('transactions', state.transactions, []);
const selectedInst = useSelected(
'transactions',
state.transactions,
transaction ? [transaction.id] : [],
);

async function onSave() {
dispatch({ type: 'form-error', error: null });
Expand Down Expand Up @@ -415,7 +443,6 @@ export function ScheduleDetails({ modalProps, actions, id }) {
}

const payee = payees ? payees[state.fields.payee] : null;

// This is derived from the date
const repeats = state.fields.date ? !!state.fields.date.frequency : false;
return (
Expand Down
30 changes: 30 additions & 0 deletions packages/desktop-client/src/components/schedules/ScheduleLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import React, { useCallback, useRef, useState } from 'react';
import { useSchedules } from 'loot-core/src/client/data-hooks/schedules';
import { send } from 'loot-core/src/platform/client/fetch';
import { type Query } from 'loot-core/src/shared/query';
import { type TransactionEntity } from 'loot-core/src/types/models';

import { type BoundActions } from '../../hooks/useActions';
import { SvgAdd } from '../../icons/v0';
import { Button } from '../common/Button';
import { Modal } from '../common/Modal';
import { Search } from '../common/Search';
import { Text } from '../common/Text';
Expand All @@ -14,14 +17,23 @@ import { type CommonModalProps } from '../Modals';

import { ROW_HEIGHT, SchedulesTable } from './SchedulesTable';

type ModalParams = {
id: string;
transaction: TransactionEntity;
};

export function ScheduleLink({
modalProps,
actions,
transactionIds: ids,
getTransaction,
pushModal,
}: {
actions: BoundActions;
modalProps?: CommonModalProps;
transactionIds: string[];
getTransaction: (transactionId: string) => TransactionEntity;
pushModal: (name: string, params: ModalParams) => void;
}) {
const [filter, setFilter] = useState('');

Expand All @@ -45,6 +57,14 @@ export function ScheduleLink({
actions.popModal();
}

async function onCreate() {
actions.popModal();
pushModal('schedule-edit', {
id: null,
transaction: getTransaction(ids[0]),
});
}

return (
<Modal title="Link Schedule" size={{ width: 600 }} {...modalProps}>
<View
Expand All @@ -70,6 +90,16 @@ export function ScheduleLink({
value={filter}
onChange={setFilter}
/>
{ids.length === 1 && (
<Button
type="primary"
style={{ marginLeft: 15, padding: '4px 10px' }}
onClick={onCreate}
>
<SvgAdd style={{ width: '20', padding: '3' }} />
Create New
</Button>
)}
</View>

<View
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ export function SelectedTransactionsButton({
case 'link-schedule':
pushModal('schedule-link', {
transactionIds: [...selectedItems],
getTransaction,
pushModal,
});
break;
case 'unlink-schedule':
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { memo, useMemo, useCallback } from 'react';
import React, { memo, useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';

import {
format as formatDate,
parseISO,
isValid as isDateValid,
parseISO,
} from 'date-fns';

import {
Expand All @@ -14,10 +14,10 @@ import {
import { integerToCurrency } from 'loot-core/src/shared/util';

import { useCategories } from '../../hooks/useCategories';
import { useSelectedItems, useSelectedDispatch } from '../../hooks/useSelected';
import { useSelectedDispatch, useSelectedItems } from '../../hooks/useSelected';
import { SvgArrowsSynchronize } from '../../icons/v2';
import { theme, styles } from '../../style';
import { Table, Row, Field, Cell, SelectCell } from '../table';
import { styles, theme } from '../../style';
import { Cell, Field, Row, SelectCell, Table } from '../table';
import { DisplayId } from '../util/DisplayId';

function serializeTransaction(transaction, dateFormat) {
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/2222.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Features
authors: [xentara1]
---

Add ability to create schedules from existing transactions

0 comments on commit 29a515f

Please sign in to comment.