Skip to content

Commit

Permalink
Merge branch 'develop' into cleanup/common-wealth-bank
Browse files Browse the repository at this point in the history
  • Loading branch information
Civolilah committed Nov 6, 2024
2 parents 3783233 + b9cbd2b commit a3e6b8a
Show file tree
Hide file tree
Showing 24 changed files with 291 additions and 124 deletions.
19 changes: 16 additions & 3 deletions src/common/queries/expenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
ids: string[],
action: 'archive' | 'restore' | 'delete' | 'bulk_categorize',
action:
| 'archive'
| 'restore'
| 'delete'
| 'bulk_categorize'
| 'bulk_update',
rest?: Record<string, unknown>
) => {
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]);
Expand Down
150 changes: 129 additions & 21 deletions src/pages/clients/common/components/BulkUpdatesAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,30 @@

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 { 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';
import { Modal } from '$app/components/Modal';
import { DropdownElement } from '$app/components/dropdown/DropdownElement';
import { Button, InputLabel, SelectField } from '$app/components/forms';
import {
Button,
InputField,
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';
import Toggle from '$app/components/forms/Toggle';

interface Props {
entity: 'client';
entity: 'client' | 'expense' | 'recurring_invoice';
resourceIds: string[];
setSelected: Dispatch<SetStateAction<string[]>>;
}
Expand All @@ -36,26 +45,39 @@ interface BulkUpdateField {
| 'industrySelector'
| 'sizeSelector'
| 'countrySelector'
| 'customField';
| 'customField'
| 'taxSelector'
| 'toggle'
| 'textarea';
}

const bulkUpdateFieldsTypes: BulkUpdateField[] = [
{ key: 'private_notes', type: 'markdownEditor' },
{ key: 'public_notes', type: 'markdownEditor' },
{ key: 'terms', type: 'markdownEditor' },
{ key: 'footer', type: 'markdownEditor' },
{ key: 'industry_id', type: 'industrySelector' },
{ key: 'size_id', type: 'sizeSelector' },
{ key: 'country_id', type: 'countrySelector' },
{ key: 'custom_value1', type: 'customField' },
{ key: 'custom_value2', type: 'customField' },
{ key: 'custom_value3', type: 'customField' },
{ key: 'custom_value4', type: 'customField' },
{ key: 'tax1', type: 'taxSelector' },
{ key: 'tax2', type: 'taxSelector' },
{ key: 'tax3', type: 'taxSelector' },
{ key: 'should_be_invoiced', type: 'toggle' },
{ key: 'uses_inclusive_taxes', type: 'toggle' },
];

export function BulkUpdatesAction(props: Props) {
const [t] = useTranslation();

const { setSelected, resourceIds } = props;

const bulk = useBulk();
const bulkClients = useBulkClients();
const bulkExpenses = useBulkExpenses();
const bulkRecurringInvoices = useBulkRecurringInvoices();

const { data: statics } = useStaticsQuery();

Expand All @@ -75,23 +97,85 @@ export function BulkUpdatesAction(props: Props) {
};

const getFieldType = () => {
if (props.entity === 'expense' && column.includes('notes')) {
return 'textarea';
}

return bulkUpdateFieldsTypes.find(({ key }) => key === column)?.type || '';
};

const showColumn = (columnKey: string) => {
if (columnKey.includes('rate')) {
return false;
}

if (columnKey.startsWith('custom_value')) {
return Boolean(
company.custom_fields[columnKey.replace('custom_value', props.entity)]
);
}

if (columnKey.startsWith('tax')) {
const taxNumber = Number(columnKey.split('tax')[1]);

const enabledTaxRates =
props.entity === 'expense'
? company.enabled_expense_tax_rates
: company.enabled_tax_rates;

if (taxNumber === 1) {
return Boolean(enabledTaxRates > 0);
}

if (taxNumber === 2) {
return Boolean(enabledTaxRates > 1);
}

return Boolean(enabledTaxRates > 2);
}

return true;
};

const getColumnTranslation = (currentColumn: string) => {
if (currentColumn.startsWith('custom_value')) {
return company.custom_fields[
currentColumn.replace('custom_value', props.entity)
].split('|')[0];
}

return t(currentColumn);
};

const getCustomFieldKey = () => {
return column.replace('custom_value', props.entity);
};

const handleUpdate = () => {
if (props.entity === 'client') {
bulkClients(resourceIds, 'bulk_update', {
column,
newValue: newColumnValue,
}).then(() => handleOnClose());
}

if (props.entity === 'expense') {
bulkExpenses(resourceIds, 'bulk_update', {
column,
new_value: newColumnValue,
}).then(() => handleOnClose());
}

if (props.entity === 'recurring_invoice') {
bulkRecurringInvoices(resourceIds, 'bulk_update', {
column,
new_value: newColumnValue,
}).then(() => handleOnClose());
}

setSelected([]);
};

return (
<>
<DropdownElement
Expand All @@ -117,22 +201,38 @@ export function BulkUpdatesAction(props: Props) {
setNewColumnValue('');
}}
withBlank
customSelector
>
{bulkUpdatesColumns?.[props.entity].map(
(currentColumn) =>
showColumn(currentColumn) && (
<option key={currentColumn} value={currentColumn}>
{t(currentColumn)}
</option>
)
)}
{bulkUpdatesColumns?.[props.entity]
.filter((currentCol) => showColumn(currentCol))
.map((currentColumn) => (
<option key={currentColumn} value={currentColumn}>
{getColumnTranslation(currentColumn)}
</option>
))}
</SelectField>

<div className="flex flex-col">
{Boolean(getFieldType()) && (
<InputLabel className="mb-2">{t('value')}</InputLabel>
)}

{getFieldType() === 'taxSelector' && (
<TaxRateSelector
defaultValue={newColumnValue}
onChange={(value) =>
value?.resource &&
setNewColumnValue(
`${value.resource.name}||${value.resource.rate}`
)
}
onTaxCreated={(taxRate) =>
setNewColumnValue(`${taxRate.name}||${taxRate.rate}`)
}
onClearButtonClick={() => setNewColumnValue('')}
/>
)}

{getFieldType() === 'markdownEditor' && (
<MarkdownEditor
value={newColumnValue as string}
Expand Down Expand Up @@ -190,19 +290,27 @@ export function BulkUpdatesAction(props: Props) {
fieldOnly
/>
)}

{getFieldType() === 'toggle' && (
<Toggle
checked={newColumnValue as boolean}
onChange={(value) => setNewColumnValue(value)}
/>
)}

{getFieldType() === 'textarea' && (
<InputField
element="textarea"
value={newColumnValue as string}
onValueChange={(value) => setNewColumnValue(value)}
/>
)}
</div>

<div className="flex self-end">
<Button
behavior="button"
onClick={() => {
bulk(resourceIds, 'bulk_update', {
column,
newValue: newColumnValue,
}).then(() => handleOnClose());

setSelected([]);
}}
onClick={handleUpdate}
disabled={!column}
disableWithoutIcon
>
Expand Down
2 changes: 2 additions & 0 deletions src/pages/credits/common/components/CreditDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ export function CreditDetails(props: Props) {
}
value={credit?.is_amount_discount.toString()}
errorMessage={errors?.errors.is_amount_discount}
customSelector
dismissable={false}
>
<option value="false">{t('percent')}</option>
<option value="true">{t('amount')}</option>
Expand Down
8 changes: 8 additions & 0 deletions src/pages/expenses/common/hooks/useCustomBulkActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -185,6 +186,13 @@ export const useCustomBulkActions = () => {
</DropdownElement>
</>
),
({ selectedIds, setSelected }) => (
<BulkUpdatesAction
entity="expense"
resourceIds={selectedIds}
setSelected={setSelected}
/>
),
];

return customBulkActions;
Expand Down
Loading

0 comments on commit a3e6b8a

Please sign in to comment.