diff --git a/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts b/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts
index 0ddf5861a..963e5b061 100644
--- a/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts
+++ b/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts
@@ -84,6 +84,8 @@ export default class NewCashflowTransactionController extends BaseController {
param('id').exists().isNumeric().toInt(),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
+ query('min_date').optional().isISO8601().toDate(),
+ query('max_date').optional().isISO8601().toDate(),
];
}
diff --git a/packages/webapp/src/components/TagsControl/TagsControl.module.scss b/packages/webapp/src/components/TagsControl/TagsControl.module.scss
index e548e2ced..0e5f626d6 100644
--- a/packages/webapp/src/components/TagsControl/TagsControl.module.scss
+++ b/packages/webapp/src/components/TagsControl/TagsControl.module.scss
@@ -2,7 +2,6 @@
display: flex;
flex-direction: row;
gap: 10px;
- margin-bottom: 14px;
}
.tag{
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.module.scss b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.module.scss
new file mode 100644
index 000000000..80d22ade7
--- /dev/null
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.module.scss
@@ -0,0 +1,5 @@
+
+
+.dateFieldGroup{
+ margin-bottom: 0;
+}
\ No newline at end of file
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx
index 6ce0e66dd..64eb3760c 100644
--- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx
@@ -1,10 +1,19 @@
// @ts-nocheck
import { Button, FormGroup, Intent, Position } from '@blueprintjs/core';
import * as Yup from 'yup';
-import { Form, Formik, FormikConfig } from 'formik';
-import { FDateInput, FFormGroup, Group, Icon, Stack } from '@/components';
+import moment from 'moment';
+import { Form, Formik, FormikConfig, useFormikContext } from 'formik';
+import {
+ FDateInput,
+ FFormGroup,
+ FSelect,
+ Group,
+ Icon,
+ Stack,
+} from '@/components';
const defaultValues = {
+ period: 'all_dates',
fromDate: '',
toDate: '',
};
@@ -21,6 +30,7 @@ const validationSchema = Yup.object().shape({
});
interface AccountTransactionsDateFilterFormValues {
+ period: string;
fromDate: string;
toDate: string;
}
@@ -34,8 +44,8 @@ export function AccountTransactionsDateFilterForm({
initialValues = {},
onSubmit,
}: UncategorizedTransactionsDateFilterProps) {
- const handleSubmit = () => {
- return onSubmit && onSubmit(...arguments);
+ const handleSubmit = (values, bag) => {
+ return onSubmit && onSubmit(values, bag);
};
const formInitialValues = {
@@ -50,9 +60,15 @@ export function AccountTransactionsDateFilterForm({
validationSchema={validationSchema}
>
);
}
+
+function AccountTransactionsDateFilterFooter() {
+ const { submitForm, setValues } = useFormikContext();
+
+ const handleFilterBtnClick = () => {
+ submitForm();
+ };
+ const handleClearBtnClick = () => {
+ setValues({
+ ...defaultValues,
+ });
+ submitForm();
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+function AccountTransactionDatePeriodField() {
+ const { setFieldValue } = useFormikContext();
+
+ const handleItemChange = (item) => {
+ const { fromDate, toDate } = getDateRangePeriod(item.value);
+
+ setFieldValue('fromDate', fromDate);
+ setFieldValue('toDate', toDate);
+ setFieldValue('period', item.value);
+ };
+
+ return (
+
+
+
+ );
+}
+
+const periodOptions = [
+ { text: 'All Dates', value: 'all_dates' },
+ { text: 'Custom', value: 'custom' },
+ { text: 'Today', value: 'today' },
+ { text: 'Yesterday', value: 'yesterday' },
+ { text: 'This week', value: 'this_week' },
+ { text: 'This year', value: 'this_year' },
+ { text: 'This month', value: 'this_month' },
+ { text: 'last week', value: 'last_week' },
+ { text: 'Last year', value: 'last_year' },
+ { text: 'Last month', value: 'last_month' },
+ { text: 'Last month', value: 'last_month' },
+];
+
+const getDateRangePeriod = (period: string) => {
+ switch (period) {
+ case 'today':
+ return {
+ fromDate: moment().startOf('day').toDate(),
+ toDate: moment().endOf('day').toDate(),
+ };
+ case 'yesterday':
+ return {
+ fromDate: moment().subtract(1, 'days').startOf('day').toDate(),
+ toDate: moment().subtract(1, 'days').endOf('day').toDate(),
+ };
+ case 'this_week':
+ return {
+ fromDate: moment().startOf('week').toDate(),
+ toDate: moment().endOf('week').toDate(),
+ };
+ case 'this_month':
+ return {
+ fromDate: moment().startOf('month').toDate(),
+ toDate: moment().endOf('month').toDate(),
+ };
+ case 'this_year':
+ return {
+ fromDate: moment().startOf('year').toDate(),
+ toDate: moment().endOf('year').toDate(),
+ };
+ case 'last_week':
+ return {
+ fromDate: moment().subtract(1, 'weeks').startOf('week').toDate(),
+ toDate: moment().subtract(1, 'weeks').endOf('week').toDate(),
+ };
+ case 'last_month':
+ return {
+ fromDate: moment().subtract(1, 'months').startOf('month').toDate(),
+ toDate: moment().subtract(1, 'months').endOf('month').toDate(),
+ };
+ case 'last_year':
+ return {
+ fromDate: moment().subtract(1, 'years').startOf('year').toDate(),
+ toDate: moment().subtract(1, 'years').endOf('year').toDate(),
+ };
+ case 'all_dates':
+ case 'custom':
+ default:
+ return { fromDate: null, toDate: null };
+ }
+};
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx
index 3de1c7689..ad46e586c 100644
--- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx
@@ -2,12 +2,11 @@
import { useMemo } from 'react';
import * as R from 'ramda';
import { useAppQueryString } from '@/hooks';
-import { Group, Icon } from '@/components';
+import { Group, Stack, } from '@/components';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
import { TagsControl } from '@/components/TagsControl';
-import { Button, Classes, Position } from '@blueprintjs/core';
-import { AccountTransactionsDateFilterForm } from './AccountTransactionsDateFilter';
-import { Popover2 } from '@blueprintjs/popover2';
+import { AccountUncategorizedDateFilter } from './UncategorizedTransactions/AccountUncategorizedDateFilter';
+import { Divider } from '@blueprintjs/core';
export function AccountTransactionsUncategorizeFilter() {
const { bankAccountMetaSummary } = useAccountTransactionsContext();
@@ -57,21 +56,17 @@ export function AccountTransactionsUncategorizeFilter() {
);
return (
-
-
+
+
- }
- position={Position.RIGHT}
- popoverClassName={Classes.POPOVER_CONTENT_SIZING}
- >
- }>Date Filter
-
+
+
+
);
}
-
-export const UncategorizedTransactionsDateFilter = () => {
- const initialValues = {};
- const handleSubmit = () => {};
-
- return (
-
- );
-};
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AllTransactionsUncategorizedBoot.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AllTransactionsUncategorizedBoot.tsx
index ce57832b3..2ca46e588 100644
--- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AllTransactionsUncategorizedBoot.tsx
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AllTransactionsUncategorizedBoot.tsx
@@ -2,9 +2,11 @@
import React from 'react';
import { flatten, map } from 'lodash';
+import * as R from 'ramda';
import { IntersectionObserver } from '@/components';
import { useAccountUncategorizedTransactionsInfinity } from '@/hooks/query';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
+import { withBanking } from '../withBanking';
const AccountUncategorizedTransactionsContext = React.createContext();
@@ -13,9 +15,15 @@ function flattenInfinityPagesData(data) {
}
/**
- * Account uncategorized transctions provider.
+ * Account un-categorized transactions provider.
*/
-function AccountUncategorizedTransactionsBoot({ children }) {
+function AccountUncategorizedTransactionsBootRoot({
+ // #withBanking
+ uncategorizedTransactionsFilter,
+
+ // #ownProps
+ children,
+}) {
const { accountId } = useAccountTransactionsContext();
// Fetches the uncategorized transactions.
@@ -29,6 +37,8 @@ function AccountUncategorizedTransactionsBoot({ children }) {
hasNextPage: hasUncategorizedTransactionsNextPage,
} = useAccountUncategorizedTransactionsInfinity(accountId, {
page_size: 50,
+ min_date: uncategorizedTransactionsFilter?.fromDate,
+ max_date: uncategorizedTransactionsFilter?.toDate,
});
// Memorized the cashflow account transactions.
const uncategorizedTransactions = React.useMemo(
@@ -69,6 +79,12 @@ function AccountUncategorizedTransactionsBoot({ children }) {
);
}
+const AccountUncategorizedTransactionsBoot = R.compose(
+ withBanking(({ uncategorizedTransactionsFilter }) => ({
+ uncategorizedTransactionsFilter,
+ })),
+)(AccountUncategorizedTransactionsBootRoot);
+
const useAccountUncategorizedTransactionsContext = () =>
React.useContext(AccountUncategorizedTransactionsContext);
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountUncategorizedDateFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountUncategorizedDateFilter.tsx
new file mode 100644
index 000000000..5de4d073f
--- /dev/null
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountUncategorizedDateFilter.tsx
@@ -0,0 +1,86 @@
+// @ts-nocheck
+import * as R from 'ramda';
+import moment from 'moment';
+import { Box, Icon } from '@/components';
+import { Button, Classes, Popover, Position } from '@blueprintjs/core';
+import { withBankingActions } from '../../withBankingActions';
+import { withBanking } from '../../withBanking';
+import { AccountTransactionsDateFilterForm } from '../AccountTransactionsDateFilter';
+import { TagButton } from './TagButton';
+
+function AccountUncategorizedDateFilterRoot({
+ uncategorizedTransactionsFilter,
+}) {
+ const fromDate = uncategorizedTransactionsFilter?.fromDate;
+ const toDate = uncategorizedTransactionsFilter?.toDate;
+
+ const fromDateFormatted = moment(fromDate).isSame(
+ moment().format('YYYY'),
+ 'year',
+ )
+ ? moment(fromDate).format('MMM, DD')
+ : moment(fromDate).format('MMM, DD, YYYY');
+ const toDateFormatted = moment(toDate).isSame(moment().format('YYYY'), 'year')
+ ? moment(toDate).format('MMM, DD')
+ : moment(toDate).format('MMM, DD, YYYY');
+
+ const buttonText =
+ fromDate && toDate
+ ? `Date: ${fromDateFormatted} → ${toDateFormatted}`
+ : 'Date Filter';
+
+ return (
+
+
+
+ }
+ position={Position.RIGHT}
+ popoverClassName={Classes.POPOVER_CONTENT}
+ >
+ }>
+ {buttonText}
+
+
+ );
+}
+
+export const AccountUncategorizedDateFilter = R.compose(
+ withBanking(({ uncategorizedTransactionsFilter }) => ({
+ uncategorizedTransactionsFilter,
+ })),
+)(AccountUncategorizedDateFilterRoot);
+
+export const UncategorizedTransactionsDateFilter = R.compose(
+ withBankingActions,
+ withBanking(({ uncategorizedTransactionsFilter }) => ({
+ uncategorizedTransactionsFilter,
+ })),
+)(
+ ({
+ // #withBankingActions
+ setUncategorizedTransactionsFilter,
+
+ // #withBanking
+ uncategorizedTransactionsFilter,
+ }) => {
+ const initialValues = {
+ ...uncategorizedTransactionsFilter,
+ };
+
+ const handleSubmit = (values) => {
+ setUncategorizedTransactionsFilter({
+ fromDate: values.fromDate,
+ toDate: values.toDate,
+ });
+ };
+
+ return (
+
+ );
+ },
+);
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.module.scss b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.module.scss
new file mode 100644
index 000000000..9bbc4f8d7
--- /dev/null
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.module.scss
@@ -0,0 +1,11 @@
+.root{
+ min-height: 26px;
+ border-radius: 15px;
+ font-size: 13px;
+ padding: 0 10px;
+
+ &:global(.bp4-button:not([class*=bp4-intent-]):not(.bp4-minimal)) {
+ background: #fff;
+ border: 1px solid #e1e2e8;
+ }
+}
\ No newline at end of file
diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.tsx
new file mode 100644
index 000000000..1b588a771
--- /dev/null
+++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.tsx
@@ -0,0 +1,9 @@
+// @ts-nocheck
+import { Button } from "@blueprintjs/core"
+import styles from './TagButton.module.scss';
+
+
+
+export const TagButton = (props) => {
+ return
+}
\ No newline at end of file
diff --git a/packages/webapp/src/containers/CashFlow/withBanking.ts b/packages/webapp/src/containers/CashFlow/withBanking.ts
index 7533e3738..0f60c76cd 100644
--- a/packages/webapp/src/containers/CashFlow/withBanking.ts
+++ b/packages/webapp/src/containers/CashFlow/withBanking.ts
@@ -25,6 +25,8 @@ export const withBanking = (mapState) => {
categorizedTransactionsSelected:
state.plaid.categorizedTransactionsSelected,
+
+ uncategorizedTransactionsFilter: state.plaid.uncategorizedFilter
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/packages/webapp/src/containers/CashFlow/withBankingActions.ts b/packages/webapp/src/containers/CashFlow/withBankingActions.ts
index f7095491d..1cd869df9 100644
--- a/packages/webapp/src/containers/CashFlow/withBankingActions.ts
+++ b/packages/webapp/src/containers/CashFlow/withBankingActions.ts
@@ -15,6 +15,8 @@ import {
removeTransactionsToCategorizeSelected,
setCategorizedTransactionsSelected,
resetCategorizedTransactionsSelected,
+ setUncategorizedTransactionsFilter,
+ resetUncategorizedTranasctionsFilter,
} from '@/store/banking/banking.reducer';
export interface WithBankingActionsProps {
@@ -40,6 +42,9 @@ export interface WithBankingActionsProps {
setCategorizedTransactionsSelected: (ids: Array) => void;
resetCategorizedTransactionsSelected: () => void;
+
+ setUncategorizedTransactionsFilter: (filter: any) => void;
+ resetUncategorizedTranasctionsFilter: () => void;
}
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
@@ -138,6 +143,19 @@ const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
*/
resetCategorizedTransactionsSelected: () =>
dispatch(resetCategorizedTransactionsSelected()),
+
+ /**
+ * Sets the uncategorized transactions filter.
+ * @param {any} filter -
+ */
+ setUncategorizedTransactionsFilter: (filter: any) =>
+ dispatch(setUncategorizedTransactionsFilter({ filter })),
+
+ /**
+ * Resets the uncategorized transactions filter.
+ */
+ resetUncategorizedTranasctionsFilter: () =>
+ dispatch(resetUncategorizedTranasctionsFilter()),
});
export const withBankingActions = connect<
diff --git a/packages/webapp/src/hooks/query/cashflowAccounts.tsx b/packages/webapp/src/hooks/query/cashflowAccounts.tsx
index 046e00657..bb0470c22 100644
--- a/packages/webapp/src/hooks/query/cashflowAccounts.tsx
+++ b/packages/webapp/src/hooks/query/cashflowAccounts.tsx
@@ -152,7 +152,7 @@ export function useAccountUncategorizedTransactionsInfinity(
const apiRequest = useApiRequest();
return useInfiniteQuery(
- [t.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY, accountId],
+ [t.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY, accountId, query],
async ({ pageParam = 1 }) => {
const response = await apiRequest.http({
...axios,
diff --git a/packages/webapp/src/store/banking/banking.reducer.ts b/packages/webapp/src/store/banking/banking.reducer.ts
index 1a72474b4..7f2ae41dc 100644
--- a/packages/webapp/src/store/banking/banking.reducer.ts
+++ b/packages/webapp/src/store/banking/banking.reducer.ts
@@ -14,6 +14,8 @@ interface StorePlaidState {
enableMultipleCategorization: boolean;
categorizedTransactionsSelected: Array;
+
+ uncategorizedFilter: { fromDate?: string; toDate?: string };
}
export const PlaidSlice = createSlice({
@@ -31,6 +33,9 @@ export const PlaidSlice = createSlice({
transactionsToCategorizeSelected: [],
enableMultipleCategorization: false,
categorizedTransactionsSelected: [],
+
+ // Filter
+ uncategorizedFilter: {},
} as StorePlaidState,
reducers: {
setPlaidId: (state: StorePlaidState, action: PayloadAction) => {
@@ -199,6 +204,26 @@ export const PlaidSlice = createSlice({
resetCategorizedTransactionsSelected: (state: StorePlaidState) => {
state.categorizedTransactionsSelected = [];
},
+
+ /**
+ * Sets the uncategorized transactions filter.
+ * @param {StorePlaidState} state
+ * @param {PayloadAction<{ filter: any }>} action
+ */
+ setUncategorizedTransactionsFilter: (
+ state: StorePlaidState,
+ action: PayloadAction<{ filter: any }>,
+ ) => {
+ state.uncategorizedFilter = action.payload.filter;
+ },
+
+ /**
+ * Resets the uncategorized transactions filter.
+ * @param {StorePlaidState} state
+ */
+ resetUncategorizedTranasctionsFilter: (state: StorePlaidState) => {
+ state.uncategorizedFilter = {};
+ },
},
});
@@ -220,6 +245,10 @@ export const {
enableMultipleCategorization,
setCategorizedTransactionsSelected,
resetCategorizedTransactionsSelected,
+
+ // Uncategorized transactions filter.
+ setUncategorizedTransactionsFilter,
+ resetUncategorizedTranasctionsFilter,
} = PlaidSlice.actions;
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
@@ -234,3 +263,6 @@ export const isMultipleCategorization = (state: any) =>
export const getTransactionsToCategorizeIdsSelected = (state: any) =>
state.plaid.transactionsToCategorizeSelected;
+
+export const getUncategorizedTransactionsFilter = (state: any) =>
+ state.uncategorizedFilter;
diff --git a/packages/webapp/src/style/objects/buttons.scss b/packages/webapp/src/style/objects/buttons.scss
index 7dbffe7f8..1dafb416d 100644
--- a/packages/webapp/src/style/objects/buttons.scss
+++ b/packages/webapp/src/style/objects/buttons.scss
@@ -17,7 +17,6 @@
&.bp4-small {
font-size: 13px;
- min-height: 29px;
}
}