From cb269b3fd879d6a27365672a6be088661a4d711e Mon Sep 17 00:00:00 2001 From: Civolilah Date: Mon, 14 Oct 2024 21:47:52 +0200 Subject: [PATCH 01/19] Implementing bulk updates functionality for expenses --- src/common/hooks/useBulkUpdatesColumns.ts | 5 ++- .../common/components/BulkUpdatesAction.tsx | 44 ++++++++++++++++--- .../common/hooks/useCustomBulkActions.tsx | 8 ++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/common/hooks/useBulkUpdatesColumns.ts b/src/common/hooks/useBulkUpdatesColumns.ts index 9873def1c6..383f887c03 100644 --- a/src/common/hooks/useBulkUpdatesColumns.ts +++ b/src/common/hooks/useBulkUpdatesColumns.ts @@ -18,7 +18,10 @@ export function useBulkUpdatesColumns() { useEffect(() => { if (statics?.bulk_updates) { - setBulkUpdates(statics.bulk_updates); + setBulkUpdates({ + ...statics.bulk_updates, + expense: ['tax_1', 'tax_2', 'tax_3'], + }); } }, [statics]); diff --git a/src/pages/clients/common/components/BulkUpdatesAction.tsx b/src/pages/clients/common/components/BulkUpdatesAction.tsx index e2cace561c..8fc17931e7 100644 --- a/src/pages/clients/common/components/BulkUpdatesAction.tsx +++ b/src/pages/clients/common/components/BulkUpdatesAction.tsx @@ -10,7 +10,7 @@ import { useBulkUpdatesColumns } from '$app/common/hooks/useBulkUpdatesColumns'; import { useCurrentCompany } from '$app/common/hooks/useCurrentCompany'; -import { useBulk } from '$app/common/queries/clients'; +import { useBulk as useBulkClients } from '$app/common/queries/clients'; import { useStaticsQuery } from '$app/common/queries/statics'; import { CountrySelector } from '$app/components/CountrySelector'; import { CustomField } from '$app/components/CustomField'; @@ -19,12 +19,13 @@ import { DropdownElement } from '$app/components/dropdown/DropdownElement'; import { Button, InputLabel, SelectField } from '$app/components/forms'; import { MarkdownEditor } from '$app/components/forms/MarkdownEditor'; import { Icon } from '$app/components/icons/Icon'; +import { TaxRateSelector } from '$app/components/tax-rates/TaxRateSelector'; import { Dispatch, SetStateAction, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { MdCached } from 'react-icons/md'; interface Props { - entity: 'client'; + entity: 'client' | 'expense'; resourceIds: string[]; setSelected: Dispatch>; } @@ -36,7 +37,8 @@ interface BulkUpdateField { | 'industrySelector' | 'sizeSelector' | 'countrySelector' - | 'customField'; + | 'customField' + | 'taxSelector'; } const bulkUpdateFieldsTypes: BulkUpdateField[] = [ @@ -48,6 +50,9 @@ const bulkUpdateFieldsTypes: BulkUpdateField[] = [ { key: 'custom_value2', type: 'customField' }, { key: 'custom_value3', type: 'customField' }, { key: 'custom_value4', type: 'customField' }, + { key: 'tax_1', type: 'taxSelector' }, + { key: 'tax_2', type: 'taxSelector' }, + { key: 'tax_3', type: 'taxSelector' }, ]; export function BulkUpdatesAction(props: Props) { @@ -55,7 +60,7 @@ export function BulkUpdatesAction(props: Props) { const { setSelected, resourceIds } = props; - const bulk = useBulk(); + const bulkClients = useBulkClients(); const { data: statics } = useStaticsQuery(); @@ -85,6 +90,20 @@ export function BulkUpdatesAction(props: Props) { ); } + if (columnKey.startsWith('tax')) { + const taxNumber = Number(columnKey.split('_')[1]); + + if (taxNumber === 1) { + return Boolean(company.enabled_tax_rates > 0); + } + + if (taxNumber === 2) { + return Boolean(company.enabled_tax_rates > 1); + } + + return Boolean(company.enabled_item_tax_rates > 2); + } + return true; }; @@ -92,6 +111,8 @@ export function BulkUpdatesAction(props: Props) { return column.replace('custom_value', props.entity); }; + console.log(bulkUpdatesColumns); + return ( <> {t('value')} )} + {getFieldType() === 'taxSelector' && ( + + value?.resource && + setNewColumnValue( + `${value.resource.name}||${value.resource.rate}` + ) + } + onClearButtonClick={() => setNewColumnValue('')} + /> + )} + {getFieldType() === 'markdownEditor' && ( { - bulk(resourceIds, 'bulk_update', { + bulkClients(resourceIds, 'bulk_update', { column, newValue: newColumnValue, }).then(() => handleOnClose()); diff --git a/src/pages/expenses/common/hooks/useCustomBulkActions.tsx b/src/pages/expenses/common/hooks/useCustomBulkActions.tsx index a607cf0084..38e93d8bc6 100644 --- a/src/pages/expenses/common/hooks/useCustomBulkActions.tsx +++ b/src/pages/expenses/common/hooks/useCustomBulkActions.tsx @@ -26,6 +26,7 @@ import { Dispatch, SetStateAction, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { MdCategory, MdDownload } from 'react-icons/md'; import { AddToInvoiceAction } from '../components/AddToInvoiceAction'; +import { BulkUpdatesAction } from '$app/pages/clients/common/components/BulkUpdatesAction'; interface Props { isVisible: boolean; @@ -185,6 +186,13 @@ export const useCustomBulkActions = () => { ), + ({ selectedIds, setSelected }) => ( + + ), ]; return customBulkActions; From 72c30c627fd0db959d8508217daab8e8dc3277fa Mon Sep 17 00:00:00 2001 From: Civolilah Date: Tue, 15 Oct 2024 08:06:23 +0200 Subject: [PATCH 02/19] Implemented bulk updates action for expenses and recurring invoices --- src/common/hooks/useBulkUpdatesColumns.ts | 1 + src/common/queries/expenses.ts | 21 +++++-- .../common/components/BulkUpdatesAction.tsx | 60 ++++++++++++++----- .../components/IncreasePricesAction.tsx | 4 +- .../common/hooks/useCustomBulkActions.tsx | 8 +++ .../recurring-invoices/common/queries.ts | 16 +++-- 6 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/common/hooks/useBulkUpdatesColumns.ts b/src/common/hooks/useBulkUpdatesColumns.ts index 383f887c03..3e594f2e8e 100644 --- a/src/common/hooks/useBulkUpdatesColumns.ts +++ b/src/common/hooks/useBulkUpdatesColumns.ts @@ -21,6 +21,7 @@ export function useBulkUpdatesColumns() { setBulkUpdates({ ...statics.bulk_updates, expense: ['tax_1', 'tax_2', 'tax_3'], + recurring_invoice: ['tax_1', 'tax_2', 'tax_3'], }); } }, [statics]); diff --git a/src/common/queries/expenses.ts b/src/common/queries/expenses.ts index 38fcc4afa3..02a4809ff7 100644 --- a/src/common/queries/expenses.ts +++ b/src/common/queries/expenses.ts @@ -90,23 +90,36 @@ export function useExpensesQuery(params: ExpensesParams) { ); } +const successMessages = { + bulk_update: 'updated_records', +}; + export function useBulk() { const queryClient = useQueryClient(); const invalidateQueryValue = useAtomValue(invalidationQueryAtom); - return ( + return async ( ids: string[], - action: 'archive' | 'restore' | 'delete' | 'bulk_categorize', + action: + | 'archive' + | 'restore' + | 'delete' + | 'bulk_categorize' + | 'bulk_update', rest?: Record ) => { toast.processing(); - request('POST', endpoint('/api/v1/expenses/bulk'), { + return request('POST', endpoint('/api/v1/expenses/bulk'), { action, ids, ...rest, }).then(() => { - toast.success(`${action}d_expense`); + const message = + successMessages[action as keyof typeof successMessages] || + `${action}d_expense`; + + toast.success(message); invalidateQueryValue && queryClient.invalidateQueries([invalidateQueryValue]); diff --git a/src/pages/clients/common/components/BulkUpdatesAction.tsx b/src/pages/clients/common/components/BulkUpdatesAction.tsx index 8fc17931e7..b29c0d0c55 100644 --- a/src/pages/clients/common/components/BulkUpdatesAction.tsx +++ b/src/pages/clients/common/components/BulkUpdatesAction.tsx @@ -11,6 +11,8 @@ import { useBulkUpdatesColumns } from '$app/common/hooks/useBulkUpdatesColumns'; import { useCurrentCompany } from '$app/common/hooks/useCurrentCompany'; import { useBulk as useBulkClients } from '$app/common/queries/clients'; +import { useBulk as useBulkExpenses } from '$app/common/queries/expenses'; +import { useBulkAction as useBulkRecurringInvoices } from '$app/pages/recurring-invoices/common/queries'; import { useStaticsQuery } from '$app/common/queries/statics'; import { CountrySelector } from '$app/components/CountrySelector'; import { CustomField } from '$app/components/CustomField'; @@ -25,7 +27,7 @@ import { useTranslation } from 'react-i18next'; import { MdCached } from 'react-icons/md'; interface Props { - entity: 'client' | 'expense'; + entity: 'client' | 'expense' | 'recurring_invoice'; resourceIds: string[]; setSelected: Dispatch>; } @@ -61,6 +63,8 @@ export function BulkUpdatesAction(props: Props) { const { setSelected, resourceIds } = props; const bulkClients = useBulkClients(); + const bulkExpenses = useBulkExpenses(); + const bulkRecurringInvoices = useBulkRecurringInvoices(); const { data: statics } = useStaticsQuery(); @@ -93,15 +97,20 @@ export function BulkUpdatesAction(props: Props) { if (columnKey.startsWith('tax')) { const taxNumber = Number(columnKey.split('_')[1]); + const enabledTaxRates = + props.entity === 'expense' + ? company.enabled_expense_tax_rates + : company.enabled_tax_rates; + if (taxNumber === 1) { - return Boolean(company.enabled_tax_rates > 0); + return Boolean(enabledTaxRates > 0); } if (taxNumber === 2) { - return Boolean(company.enabled_tax_rates > 1); + return Boolean(enabledTaxRates > 1); } - return Boolean(company.enabled_item_tax_rates > 2); + return Boolean(enabledTaxRates > 2); } return true; @@ -111,7 +120,30 @@ export function BulkUpdatesAction(props: Props) { return column.replace('custom_value', props.entity); }; - console.log(bulkUpdatesColumns); + const handleUpdate = () => { + if (props.entity === 'client') { + bulkClients(resourceIds, 'bulk_update', { + column, + newValue: newColumnValue, + }).then(() => handleOnClose()); + } + + if (props.entity === 'expense') { + bulkExpenses(resourceIds, 'bulk_update', { + column, + newValue: newColumnValue, + }).then(() => handleOnClose()); + } + + if (props.entity === 'recurring_invoice') { + bulkRecurringInvoices(resourceIds, 'bulk_update', { + column, + newValue: newColumnValue, + }).then(() => handleOnClose()); + } + + setSelected([]); + }; return ( <> @@ -156,13 +188,20 @@ export function BulkUpdatesAction(props: Props) { {getFieldType() === 'taxSelector' && ( value?.resource && setNewColumnValue( `${value.resource.name}||${value.resource.rate}` ) } + onTaxCreated={(taxRate) => + setNewColumnValue(`${taxRate.name}||${taxRate.rate}`) + } onClearButtonClick={() => setNewColumnValue('')} /> )} @@ -229,14 +268,7 @@ export function BulkUpdatesAction(props: Props) {