mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
Merge branch 'develop' into more-e2e-test-cases
This commit is contained in:
@@ -1,14 +1,115 @@
|
||||
// @ts-nocheck
|
||||
import React, { useReducer, useEffect } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Button, ButtonGroup, Intent, HTMLSelect } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import intl from 'react-intl-universal';
|
||||
import PropTypes from 'prop-types';
|
||||
import { range } from 'lodash';
|
||||
import { Icon } from '@/components';
|
||||
import styled from 'styled-components';
|
||||
import { x } from '@xstyled/emotion';
|
||||
import { Icon, FormattedMessage as T } from '@/components';
|
||||
import { useIsDarkMode } from '@/hooks/useDarkMode';
|
||||
|
||||
import '@/style/components/DataTable/Pagination.scss';
|
||||
// Styled components
|
||||
const StyledButtonGroup = styled(ButtonGroup)`
|
||||
.bp4-button {
|
||||
background: transparent;
|
||||
padding: 5px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledPaginationButton = styled(Button)`
|
||||
--x-button-text-color: #666666;
|
||||
--x-button-hover-background: #E6EFFB;
|
||||
--x-button-active-text-color: #000;
|
||||
--x-button-active-background: #E6EFFB;
|
||||
--x-button-active-disabled-background: #E6EFFB;
|
||||
|
||||
.bp4-dark & {
|
||||
--x-button-text-color: rgba(255, 255, 255, 0.8);
|
||||
--x-button-hover-background: var(--color-dark-gray3);
|
||||
--x-button-active-text-color: var(--color-light-gray2);
|
||||
--x-button-active-background: var(--color-dark-gray3);
|
||||
--x-button-active-disabled-background: var(--color-dark-gray3);
|
||||
}
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
border-radius: 5px;
|
||||
|
||||
&:not([class*="bp4-intent-"]).bp4-minimal {
|
||||
color: var(--x-button-text-color);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--x-button-hover-background);
|
||||
}
|
||||
.bp4-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--x-button-text-color);
|
||||
}
|
||||
}
|
||||
&.is-active {
|
||||
&.bp4-intent-primary.bp4-minimal:disabled,
|
||||
&.bp4-intent-primary.bp4-minimal.bp4-disabled {
|
||||
background-color: var(--x-button-active-disabled-background);
|
||||
|
||||
.bp4-button-text {
|
||||
color: var(--x-button-active-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledPreviousButton = styled(StyledPaginationButton)`
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.bp4-icon {
|
||||
[dir="rtl"] & {
|
||||
transform: scale(-1);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledNextButton = styled(StyledPaginationButton)`
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.bp4-icon {
|
||||
order: 1;
|
||||
margin-right: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHTMLSelect = styled(HTMLSelect)`
|
||||
--x-html-select-text-color: #666;
|
||||
--x-html-select-border-color: #e8e8e8;
|
||||
|
||||
.bp4-dark & {
|
||||
--x-html-select-text-color: rgba(255, 255, 255, 0.8);
|
||||
--x-html-select-border-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
&.bp4-html-select.bp4-minimal {
|
||||
margin-left: 6px;
|
||||
|
||||
select {
|
||||
height: 24px;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
padding-right: 14px;
|
||||
padding-left: 8px;
|
||||
border: 1px solid var(--x-html-select-border-color);
|
||||
font-size: 13px;
|
||||
border-radius: 3px;
|
||||
color: var(--x-html-select-text-color);
|
||||
}
|
||||
&::after {
|
||||
border-left-width: 3px;
|
||||
border-right-width: 3px;
|
||||
border-top-width: 4px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const TYPE = {
|
||||
PAGE_CHANGE: 'PAGE_CHANGE',
|
||||
@@ -91,6 +192,7 @@ export function Pagination({
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
}) {
|
||||
const isDark = useIsDarkMode();
|
||||
const [state, dispatch] = useReducer(
|
||||
reducer,
|
||||
{ currentPage, total, size },
|
||||
@@ -107,10 +209,10 @@ export function Pagination({
|
||||
}, [total, size, currentPage]);
|
||||
|
||||
return (
|
||||
<div class="pagination">
|
||||
<div class="pagination__buttons-group">
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
<x.div display="flex" p="20px 14px" fontSize="13px">
|
||||
<x.div>
|
||||
<StyledButtonGroup>
|
||||
<StyledPreviousButton
|
||||
disabled={state.currentPage <= 1}
|
||||
onClick={() => {
|
||||
dispatch({ type: 'PAGE_CHANGE', page: state.currentPage - 1 });
|
||||
@@ -121,14 +223,13 @@ export function Pagination({
|
||||
onPageChange({ page, pageSize });
|
||||
}}
|
||||
minimal={true}
|
||||
className={'pagination__item pagination__item--previous'}
|
||||
icon={<Icon icon={'arrow-back-24'} iconSize={12} />}
|
||||
>
|
||||
<T id="previous" />
|
||||
</Button>
|
||||
</StyledPreviousButton>
|
||||
|
||||
{state.pages.map((page) => (
|
||||
<Button
|
||||
<StyledPaginationButton
|
||||
key={page}
|
||||
intent={state.currentPage === page ? Intent.PRIMARY : Intent.NONE}
|
||||
disabled={state.currentPage === page}
|
||||
@@ -139,18 +240,12 @@ export function Pagination({
|
||||
onPageChange({ page, pageSize });
|
||||
}}
|
||||
minimal={true}
|
||||
className={classNames(
|
||||
'pagination__item',
|
||||
'pagination__item--page',
|
||||
{
|
||||
'is-active': state.currentPage === page,
|
||||
},
|
||||
)}
|
||||
className={state.currentPage === page ? 'is-active' : ''}
|
||||
>
|
||||
{page}
|
||||
</Button>
|
||||
</StyledPaginationButton>
|
||||
))}
|
||||
<Button
|
||||
<StyledNextButton
|
||||
disabled={state.currentPage === state.totalPages}
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
@@ -163,18 +258,17 @@ export function Pagination({
|
||||
onPageChange({ page, pageSize });
|
||||
}}
|
||||
minimal={true}
|
||||
className={'pagination__item pagination__item--next'}
|
||||
icon={<Icon icon={'arrow-forward-24'} iconSize={12} />}
|
||||
>
|
||||
<T id="next" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</StyledNextButton>
|
||||
</StyledButtonGroup>
|
||||
</x.div>
|
||||
|
||||
<div class="pagination__controls">
|
||||
<div class="pagination__goto-control">
|
||||
<x.div display="flex" alignItems="center" ml="auto">
|
||||
<x.div display="none">
|
||||
Go to
|
||||
<HTMLSelect
|
||||
<StyledHTMLSelect
|
||||
minimal={true}
|
||||
options={range(1, state.totalPages + 1)}
|
||||
value={state.currentPage}
|
||||
@@ -186,11 +280,11 @@ export function Pagination({
|
||||
onPageChange({ page, pageSize });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</x.div>
|
||||
|
||||
<div class="pagination__pagesize-control">
|
||||
<x.div ml="12px" color={isDark ? 'rgba(255, 255, 255, 0.6)' : '#666'}>
|
||||
<T id={'page_size'} />
|
||||
<HTMLSelect
|
||||
<StyledHTMLSelect
|
||||
minimal={true}
|
||||
options={pageSizesOptions}
|
||||
value={size}
|
||||
@@ -202,17 +296,17 @@ export function Pagination({
|
||||
onPageSizeChange({ pageSize, page: 1 });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</x.div>
|
||||
</x.div>
|
||||
|
||||
<div class="pagination__info">
|
||||
<x.div color={isDark ? 'rgba(255, 255, 255, 0.6)' : '#666'} ml="12px" display="flex" alignItems="center">
|
||||
{intl.get('showing_current_page_to_total', {
|
||||
currentPage: state.currentPage,
|
||||
totalPages: state.totalPages,
|
||||
total: total,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</x.div>
|
||||
</x.div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import React from 'react';
|
||||
import { getColumnWidth } from '@/utils';
|
||||
import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot';
|
||||
import { CLASSES } from '@/constants';
|
||||
|
||||
const getReportColWidth = (data, accessor, headerText) => {
|
||||
return getColumnWidth(
|
||||
@@ -13,7 +14,7 @@ const getReportColWidth = (data, accessor, headerText) => {
|
||||
};
|
||||
|
||||
const descriptionAccessor = (transaction) => {
|
||||
return <span style={{ color: '#5F6B7C' }}>{transaction.description}</span>;
|
||||
return <span className={CLASSES.TEXT_MUTED}>{transaction.description}</span>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ export function useExcludedTransactionsColumns() {
|
||||
() => [
|
||||
{
|
||||
Header: 'Date',
|
||||
accessor: 'formatted_date',
|
||||
accessor: 'formatted_date',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ function AllocateLandedCostDialogProvider({
|
||||
dialogName,
|
||||
...props
|
||||
}) {
|
||||
const [transactionsType, setTransactionsType] = React.useState(null);
|
||||
const [transactionsType, setTransactionsType] = React.useState('Bill');
|
||||
const [transactionId, setTransactionId] = React.useState(null);
|
||||
const [transactionEntryId, setTransactionEntryId] = React.useState(null);
|
||||
|
||||
@@ -34,7 +34,8 @@ function AllocateLandedCostDialogProvider({
|
||||
});
|
||||
// Retrieve the landed cost transactions based on the given transactions type.
|
||||
const {
|
||||
data: { transactions: landedCostTransactions },
|
||||
data: landedCostTransactions,
|
||||
isLoading: isLandedCostTransactionsLoading,
|
||||
} = useLandedCostTransaction(transactionsType, {
|
||||
enabled: !!transactionsType,
|
||||
});
|
||||
@@ -88,6 +89,7 @@ function AllocateLandedCostDialogProvider({
|
||||
costTransactionEntries,
|
||||
transactionsType,
|
||||
landedCostTransactions,
|
||||
isLandedCostTransactionsLoading,
|
||||
setTransactionsType,
|
||||
setTransactionId,
|
||||
setTransactionEntryId,
|
||||
|
||||
@@ -38,7 +38,7 @@ function AllocateLandedCostFloatingActions({
|
||||
<DialogFooterActions alignment={'left'}>
|
||||
{costTransactionEntry && (
|
||||
<UnallocatedAmount>
|
||||
<T id={'landed_cost.dialog.label_unallocated_cost_amount'}/>
|
||||
<T id={'landed_cost.dialog.label_unallocated_cost_amount'} />
|
||||
<strong>{formattedUnallocatedCostAmount}</strong>
|
||||
</UnallocatedAmount>
|
||||
)}
|
||||
@@ -68,11 +68,16 @@ const AllocateDialogFooter = styled(DialogFooter)`
|
||||
`;
|
||||
|
||||
const UnallocatedAmount = styled.div`
|
||||
color: #3f5278;
|
||||
--x-color-text: #3f5278;
|
||||
|
||||
.bp4-dark & {
|
||||
--x-color-text: var(--color-light-gray1);
|
||||
}
|
||||
color: var(--x-color-text);
|
||||
align-self: center;
|
||||
|
||||
strong {
|
||||
color: #353535;
|
||||
color: var(--x-color-text);
|
||||
padding-left: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
RadioGroup,
|
||||
Radio,
|
||||
InputGroup,
|
||||
Spinner,
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { x } from '@xstyled/emotion';
|
||||
import { FormattedMessage as T, If, FFormGroup, FSelect, FRadioGroup, FInputGroup } from '@/components';
|
||||
import { handleStringChange } from '@/utils';
|
||||
import { FieldRequiredHint } from '@/components';
|
||||
@@ -28,7 +30,7 @@ import { useAllocateLandedConstDialogContext } from './AllocateLandedCostDialogP
|
||||
*/
|
||||
export default function AllocateLandedCostFormFields() {
|
||||
// Allocated landed cost dialog.
|
||||
const { costTransactionEntries, landedCostTransactions } =
|
||||
const { costTransactionEntries, landedCostTransactions, isLandedCostTransactionsLoading } =
|
||||
useAllocateLandedConstDialogContext();
|
||||
|
||||
const { values, setFieldValue, form } = useFormikContext();
|
||||
@@ -97,21 +99,35 @@ export default function AllocateLandedCostFormFields() {
|
||||
inline
|
||||
fill
|
||||
>
|
||||
<FSelect
|
||||
name={'transaction_id'}
|
||||
items={landedCostTransactions}
|
||||
onItemChange={handleTransactionChange}
|
||||
filterable={false}
|
||||
valueAccessor={'id'}
|
||||
textAccessor={'name'}
|
||||
labelAccessor={'formatted_unallocated_cost_amount'}
|
||||
placeholder={intl.get('landed_cost.dialog.label_select_transaction')}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
<x.div position="relative" w="100%">
|
||||
<FSelect
|
||||
name={'transaction_id'}
|
||||
items={landedCostTransactions || []}
|
||||
onItemChange={handleTransactionChange}
|
||||
filterable={false}
|
||||
valueAccessor={'id'}
|
||||
textAccessor={'name'}
|
||||
labelAccessor={'formatted_unallocated_cost_amount'}
|
||||
placeholder={intl.get('landed_cost.dialog.label_select_transaction')}
|
||||
popoverProps={{ minimal: true }}
|
||||
disabled={isLandedCostTransactionsLoading}
|
||||
/>
|
||||
{isLandedCostTransactionsLoading && (
|
||||
<x.div
|
||||
position="absolute"
|
||||
right="35px"
|
||||
top="50%"
|
||||
transform="translateY(-50%)"
|
||||
pointerEvents="none"
|
||||
>
|
||||
<Spinner size={16} />
|
||||
</x.div>
|
||||
)}
|
||||
</x.div>
|
||||
</FFormGroup>
|
||||
|
||||
{/*------------ Transaction line -----------*/}
|
||||
<If condition={costTransactionEntries.length > 0}>
|
||||
<If condition={costTransactionEntries?.length > 0}>
|
||||
<FFormGroup
|
||||
name={'transaction_entry_id'}
|
||||
label={<T id={'transaction_line'} />}
|
||||
|
||||
@@ -32,13 +32,12 @@ function BadDebtForm({
|
||||
// #withCurrentOrganization
|
||||
organization: { base_currency },
|
||||
}) {
|
||||
const { invoice, dialogName, createBadDebtMutate, cancelBadDebtMutate } =
|
||||
useBadDebtContext();
|
||||
const { invoice, dialogName, createBadDebtMutate } = useBadDebtContext();
|
||||
|
||||
// Initial form values
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
amount: invoice.due_amount,
|
||||
amount: invoice?.due_amount || '',
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
@@ -67,7 +66,7 @@ function BadDebtForm({
|
||||
}
|
||||
setSubmitting(false);
|
||||
};
|
||||
createBadDebtMutate([invoice.id, form]).then(onSuccess).catch(onError);
|
||||
createBadDebtMutate([invoice?.id, form]).then(onSuccess).catch(onError);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
FMoneyInputGroup,
|
||||
FTextArea,
|
||||
FormattedMessage as T,
|
||||
FFormGroup,
|
||||
} from '@/components';
|
||||
|
||||
import { useAutofocus } from '@/hooks';
|
||||
@@ -53,7 +54,7 @@ function BadDebtFormFields() {
|
||||
fill
|
||||
>
|
||||
<ControlGroup>
|
||||
<InputPrependText text={invoice.currency_code} />
|
||||
<InputPrependText text={invoice?.currency_code || ''} />
|
||||
<FMoneyInputGroup
|
||||
name={'amount'}
|
||||
minimal={true}
|
||||
@@ -73,6 +74,7 @@ function BadDebtFormFields() {
|
||||
name={'expense_account_id'}
|
||||
items={accounts}
|
||||
filterByTypes={[ACCOUNT_TYPE.EXPENSE]}
|
||||
fill
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ function BadDebtDialog({ dialogName, payload: { invoiceId = null }, isOpen }) {
|
||||
name={dialogName}
|
||||
title={<T id={'bad_debt.dialog.bad_debt'} />}
|
||||
isOpen={isOpen}
|
||||
canEscapeJeyClose={true}
|
||||
canEscapeKeyClose={true}
|
||||
autoFocus={true}
|
||||
className={'dialog--bad-debt'}
|
||||
>
|
||||
|
||||
@@ -424,7 +424,7 @@ export function useUnexcludeUncategorizedTransactions(
|
||||
UnexcludeBankTransactionsValue
|
||||
>(
|
||||
(value: { ids: Array<number | string> }) =>
|
||||
apiRequest.delete(`/banking/exclude/bulk`, { ids: value.ids }),
|
||||
apiRequest.delete(`/banking/exclude/bulk`, { data: { ids: value.ids } }),
|
||||
{
|
||||
onSuccess: (res, id) => {
|
||||
onValidateExcludeUncategorizedTransaction(queryClient);
|
||||
|
||||
@@ -341,7 +341,7 @@ export function useCancelBadDebt(props) {
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
(id) => apiRequest.post(`sale-invoices/${id}/writeoff/cancel`),
|
||||
(id) => apiRequest.post(`sale-invoices/${id}/cancel-writeoff`),
|
||||
{
|
||||
onSuccess: (res, id) => {
|
||||
// Invalidate
|
||||
|
||||
@@ -67,9 +67,6 @@ export function useLandedCostTransaction(query, props) {
|
||||
},
|
||||
{
|
||||
select: (res) => res.data,
|
||||
defaultData: {
|
||||
transactions: [],
|
||||
},
|
||||
...props,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
|
||||
.bp4-dialog-footer{
|
||||
padding-top: 10px;
|
||||
// padding-top: 10px;
|
||||
}
|
||||
|
||||
.bigcapital-datatable {
|
||||
@@ -30,6 +30,10 @@
|
||||
border: 1px solid #d1dee2;
|
||||
min-width: auto;
|
||||
|
||||
.bp4-dark & {
|
||||
border-color: var(--color-dark-gray5);
|
||||
}
|
||||
|
||||
.tbody,
|
||||
.tbody-inner {
|
||||
height: auto;
|
||||
@@ -43,6 +47,10 @@
|
||||
padding: 0.4rem;
|
||||
margin-left: -1px;
|
||||
border-left: 1px solid #ececec;
|
||||
|
||||
.bp4-dark & {
|
||||
border-left-color: var(--color-dark-gray5);
|
||||
}
|
||||
}
|
||||
|
||||
.bp4-form-group{
|
||||
@@ -51,6 +59,10 @@
|
||||
&:not(.bp4-intent-danger) .bp4-input{
|
||||
border: 1px solid #d0dfe2;
|
||||
|
||||
.bp4-dark & {
|
||||
border-color: var(--color-dark-gray5);
|
||||
}
|
||||
|
||||
&:focus{
|
||||
box-shadow: 0 0 0 1px #116cd0;
|
||||
border-color: #116cd0;
|
||||
|
||||
Reference in New Issue
Block a user