From df8b68fda6b0cf9475c806d1c04acc3c19e921ef Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 11 Aug 2024 18:34:45 +0200 Subject: [PATCH 1/4] feat(banking): Filter uncategorized bank transactions --- .../server/src/interfaces/CashflowService.ts | 11 ++- .../UncategorizedCashflowTransaction.ts | 40 ++++++++- .../Exclude/GetExcludedBankTransactions.ts | 15 +++- .../src/services/Banking/Exclude/_types.ts | 4 + .../Cashflow/GetRecongizedTransactions.ts | 20 ++++- .../Cashflow/GetUncategorizedTransactions.ts | 13 +++ .../AccountTransactionsUncategorizeFilter.tsx | 82 ++++++++++++++++++- 7 files changed, 175 insertions(+), 10 deletions(-) diff --git a/packages/server/src/interfaces/CashflowService.ts b/packages/server/src/interfaces/CashflowService.ts index c1f55a86f..415682ae5 100644 --- a/packages/server/src/interfaces/CashflowService.ts +++ b/packages/server/src/interfaces/CashflowService.ts @@ -167,11 +167,18 @@ export interface CategorizeTransactionAsExpenseDTO { export interface IGetUncategorizedTransactionsQuery { page?: number; pageSize?: number; + minDate?: Date; + maxDate?: Date; + minAmount?: number; + maxAmount?: number; } - export interface IGetRecognizedTransactionsQuery { page?: number; pageSize?: number; accountId?: number; -} \ No newline at end of file + minDate?: Date; + maxDate?: Date; + minAmount?: number; + maxAmount?: number; +} diff --git a/packages/server/src/models/UncategorizedCashflowTransaction.ts b/packages/server/src/models/UncategorizedCashflowTransaction.ts index 218c35982..1040fe0ca 100644 --- a/packages/server/src/models/UncategorizedCashflowTransaction.ts +++ b/packages/server/src/models/UncategorizedCashflowTransaction.ts @@ -1,5 +1,5 @@ /* eslint-disable global-require */ -import * as R from 'ramda'; +import moment from 'moment'; import { Model, ModelOptions, QueryContext, mixin } from 'objection'; import TenantModel from 'models/TenantModel'; import ModelSettings from './ModelSetting'; @@ -46,7 +46,7 @@ export default class UncategorizedCashflowTransaction extends mixin( 'isDepositTransaction', 'isWithdrawalTransaction', 'isRecognized', - 'isExcluded' + 'isExcluded', ]; } @@ -143,6 +143,42 @@ export default class UncategorizedCashflowTransaction extends mixin( query.whereNull('categorizeRefType'); query.whereNull('categorizeRefId'); }, + + /** + * Filters the not pending transactions. + */ + notPending(query) { + query.where('pending', false); + }, + + /** + * Filters the pending transactions. + */ + pending(query) { + query.where('pending', true); + }, + + minAmount(query, minAmount) { + query.where('amount', '>=', minAmount); + }, + + maxAmount(query, maxAmount) { + query.where('amount', '<=', maxAmount); + }, + + toDate(query, toDate) { + const dateFormat = 'YYYY-MM-DD'; + const _toDate = moment(toDate).endOf('day').format(dateFormat); + + query.where('date', '<=', _toDate); + }, + + fromDate(query, fromDate) { + const dateFormat = 'YYYY-MM-DD'; + const _fromDate = moment(fromDate).startOf('day').format(dateFormat); + + query.where('date', '>=', _fromDate); + }, }; } diff --git a/packages/server/src/services/Banking/Exclude/GetExcludedBankTransactions.ts b/packages/server/src/services/Banking/Exclude/GetExcludedBankTransactions.ts index 41435f1b8..43bc523de 100644 --- a/packages/server/src/services/Banking/Exclude/GetExcludedBankTransactions.ts +++ b/packages/server/src/services/Banking/Exclude/GetExcludedBankTransactions.ts @@ -1,5 +1,6 @@ -import HasTenancyService from '@/services/Tenancy/TenancyService'; import { Inject, Service } from 'typedi'; +import moment from 'moment'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; import { ExcludedBankTransactionsQuery } from './_types'; import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer'; import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; @@ -39,6 +40,18 @@ export class GetExcludedBankTransactionsService { if (_query.accountId) { q.where('account_id', _query.accountId); } + if (_query.minDate) { + q.modify('fromDate', _query.minDate); + } + if (_query.maxDate) { + q.modify('toDate', _query.maxDate); + } + if (_query.minAmount) { + q.modify('minAmount', _query.minAmount); + } + if (_query.maxAmount) { + q.modify('maxAmount', _query.maxAmount); + } }) .pagination(_query.page - 1, _query.pageSize); diff --git a/packages/server/src/services/Banking/Exclude/_types.ts b/packages/server/src/services/Banking/Exclude/_types.ts index c7aa571fd..5d1e2842d 100644 --- a/packages/server/src/services/Banking/Exclude/_types.ts +++ b/packages/server/src/services/Banking/Exclude/_types.ts @@ -4,6 +4,10 @@ export interface ExcludedBankTransactionsQuery { page?: number; pageSize?: number; accountId?: number; + minDate?: Date; + maxDate?: Date; + minAmount?: number; + maxAmount?: number; } export interface IBankTransactionUnexcludingEventPayload { diff --git a/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts b/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts index 9ba2bd102..1fec81968 100644 --- a/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts +++ b/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts @@ -23,7 +23,7 @@ export class GetRecognizedTransactionsService { ) { const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId); - const _filter = { + const _query = { page: 1, pageSize: 20, ...filter, @@ -36,11 +36,23 @@ export class GetRecognizedTransactionsService { q.whereNotNull('recognizedTransactionId'); q.modify('notExcluded'); - if (_filter.accountId) { - q.where('accountId', _filter.accountId); + if (_query.accountId) { + q.where('accountId', _query.accountId); + } + if (_query.minDate) { + q.modify('fromDate', _query.minDate); + } + if (_query.maxDate) { + q.modify('toDate', _query.maxDate); + } + if (_query.minAmount) { + q.modify('minAmount', _query.minAmount); + } + if (_query.maxAmount) { + q.modify('maxAmount', _query.maxAmount); } }) - .pagination(_filter.page - 1, _filter.pageSize); + .pagination(_query.page - 1, _query.pageSize); const data = await this.transformer.transform( tenantId, diff --git a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts index 7b3c76774..7d8da347b 100644 --- a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts +++ b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts @@ -60,6 +60,19 @@ export class GetUncategorizedTransactions { q.whereNull('matchedBankTransactions.id'); q.orderBy('date', 'DESC'); + + if (_query.minDate) { + q.modify('fromDate', _query.minDate); + } + if (_query.maxDate) { + q.modify('toDate', _query.maxDate); + } + if (_query.minAmount) { + q.modify('minAmount', _query.minAmount); + } + if (_query.maxAmount) { + q.modify('maxAmount', _query.maxAmount); + } }) .pagination(_query.page - 1, _query.pageSize); diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx index 2272c7e54..261a638f0 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx @@ -1,8 +1,21 @@ // @ts-nocheck +import * as R from 'ramda'; +import * as Yup from 'yup'; +import { useMemo } from 'react'; import { useAppQueryString } from '@/hooks'; -import { Group } from '@/components'; +import { Box, FDateInput, FFormGroup, Group, Icon, Stack } from '@/components'; import { useAccountTransactionsContext } from './AccountTransactionsProvider'; import { TagsControl } from '@/components/TagsControl'; +import { + Button, + Classes, + FormGroup, + Intent, + Popover, + Position, +} from '@blueprintjs/core'; +import { DateInput } from '@blueprintjs/datetime'; +import { Form, Formik } from 'formik'; export function AccountTransactionsUncategorizeFilter() { const { bankAccountMetaSummary } = useAccountTransactionsContext(); @@ -48,3 +61,70 @@ export function AccountTransactionsUncategorizeFilter() { ); } + +const initialValues = { + fromDate: '', + toDate: '', +}; + +const validationSchema = Yup.object().shape({ + fromDate: Yup.date() + .nullable() + .required('From Date is required') + .max(Yup.ref('toDate'), 'From Date cannot be after To Date'), + toDate: Yup.date() + .nullable() + .required('To Date is required') + .min(Yup.ref('fromDate'), 'To Date cannot be before From Date'), +}); + +function UncategorizedTransactionsDateFilter() { + const handleSubmit = () => {}; + + return ( + +
+ + + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ + fill: true, + leftElement: , + }} + style={{ marginBottom: 0 }} + /> + + + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ + fill: true, + leftElement: , + }} + style={{ marginBottom: 0 }} + /> + + + + + + + + +
+
+ ); +} From 1062b65b5b03693268a0c26a5e5603856a179b11 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 22 Aug 2024 01:03:03 +0200 Subject: [PATCH 2/4] feat: wip bank account transactions date filter --- .../AccountTransactionsDateFilter.tsx | 94 +++++++++++++++++++ .../AccountTransactionsUncategorizeFilter.tsx | 92 +++++------------- 2 files changed, 117 insertions(+), 69 deletions(-) create mode 100644 packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx new file mode 100644 index 000000000..6ce0e66dd --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.tsx @@ -0,0 +1,94 @@ +// @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'; + +const defaultValues = { + fromDate: '', + toDate: '', +}; + +const validationSchema = Yup.object().shape({ + fromDate: Yup.date() + .nullable() + .required('From Date is required') + .max(Yup.ref('toDate'), 'From Date cannot be after To Date'), + toDate: Yup.date() + .nullable() + .required('To Date is required') + .min(Yup.ref('fromDate'), 'To Date cannot be before From Date'), +}); + +interface AccountTransactionsDateFilterFormValues { + fromDate: string; + toDate: string; +} + +interface UncategorizedTransactionsDateFilterProps { + initialValues?: AccountTransactionsDateFilterFormValues; + onSubmit?: FormikConfig['onSubmit']; +} + +export function AccountTransactionsDateFilterForm({ + initialValues = {}, + onSubmit, +}: UncategorizedTransactionsDateFilterProps) { + const handleSubmit = () => { + return onSubmit && onSubmit(...arguments); + }; + + const formInitialValues = { + ...defaultValues, + ...initialValues, + }; + + return ( + +
+ + + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ + fill: true, + leftElement: , + }} + style={{ marginBottom: 0 }} + /> + + + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ + fill: true, + leftElement: , + }} + style={{ marginBottom: 0 }} + /> + + + + + + + + +
+
+ ); +} diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx index f2db7f6b6..3de1c7689 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsUncategorizeFilter.tsx @@ -1,13 +1,13 @@ // @ts-nocheck import { useMemo } from 'react'; import * as R from 'ramda'; -import * as Yup from 'yup'; -import { Form, Formik } from 'formik'; import { useAppQueryString } from '@/hooks'; -import { FDateInput, FFormGroup, Group, Icon, Stack } from '@/components'; +import { Group, Icon } from '@/components'; import { useAccountTransactionsContext } from './AccountTransactionsProvider'; import { TagsControl } from '@/components/TagsControl'; -import { Button, FormGroup, Intent, Position } from '@blueprintjs/core'; +import { Button, Classes, Position } from '@blueprintjs/core'; +import { AccountTransactionsDateFilterForm } from './AccountTransactionsDateFilter'; +import { Popover2 } from '@blueprintjs/popover2'; export function AccountTransactionsUncategorizeFilter() { const { bankAccountMetaSummary } = useAccountTransactionsContext(); @@ -58,11 +58,20 @@ export function AccountTransactionsUncategorizeFilter() { return ( - + + + } + position={Position.RIGHT} + popoverClassName={Classes.POPOVER_CONTENT_SIZING} + > + + + { + const initialValues = {}; const handleSubmit = () => {}; return ( - -
- - - - date.toLocaleDateString()} - parseDate={(str) => new Date(str)} - inputProps={{ - fill: true, - leftElement: , - }} - style={{ marginBottom: 0 }} - /> - - - - date.toLocaleDateString()} - parseDate={(str) => new Date(str)} - inputProps={{ - fill: true, - leftElement: , - }} - style={{ marginBottom: 0 }} - /> - - - - - - - - -
-
+ /> ); -} +}; From f6bad8fe30cf3adce0b3d0f374451e92f1f50e4a Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Fri, 23 Aug 2024 01:57:52 +0200 Subject: [PATCH 3/4] fix: wip filter uncategorized transactions by date --- .../Cashflow/NewCashflowTransaction.ts | 2 + .../TagsControl/TagsControl.module.scss | 1 - .../AccountTransactionsDateFilter.module.scss | 5 + .../AccountTransactionsDateFilter.tsx | 168 ++++++++++++++++-- .../AccountTransactionsUncategorizeFilter.tsx | 33 +--- .../AllTransactionsUncategorizedBoot.tsx | 20 ++- .../AccountUncategorizedDateFilter.tsx | 86 +++++++++ .../TagButton.module.scss | 11 ++ .../UncategorizedTransactions/TagButton.tsx | 9 + .../src/containers/CashFlow/withBanking.ts | 2 + .../containers/CashFlow/withBankingActions.ts | 18 ++ .../src/hooks/query/cashflowAccounts.tsx | 2 +- .../src/store/banking/banking.reducer.ts | 32 ++++ .../webapp/src/style/objects/buttons.scss | 1 - 14 files changed, 344 insertions(+), 46 deletions(-) create mode 100644 packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsDateFilter.module.scss create mode 100644 packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountUncategorizedDateFilter.tsx create mode 100644 packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.module.scss create mode 100644 packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/TagButton.tsx 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} >
- - - + + + + + new Date(str)} inputProps={{ fill: true, + placeholder: 'MM/DD/YYY', leftElement: , }} - style={{ marginBottom: 0 }} /> - + new Date(str)} inputProps={{ fill: true, + placeholder: 'MM/DD/YYY', leftElement: , }} - style={{ marginBottom: 0 }} /> - - - - + ); } + +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} - > - - + + + ); } - -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