re-structure to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 01:02:31 +02:00
parent 8242ec64ba
commit 7a0a13f9d5
10400 changed files with 46966 additions and 17223 deletions

View File

@@ -0,0 +1,64 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import intl from 'react-intl-universal';
import { Tab } from '@blueprintjs/core';
import { useAbilityContext } from '@/hooks/utils';
import { DrawerMainTabs } from '@/components';
import { PaymentReceiveAction, AbilitySubject } from '@/constants/abilityOption';
import InvoiceDetailActionsBar from './InvoiceDetailActionsBar';
import InvoiceGLEntriesTable from './InvoiceGLEntriesTable';
import InvoicePaymentTransactionsTable from './InvoicePaymentTransactions/InvoicePaymentTransactionsTable';
import InvoiceDetailTab from './InvoiceDetailTab';
/**
* Invoice details tabs.
* @returns {React.JSX}
*/
function InvoiceDetailsTabs() {
const ability = useAbilityContext();
return (
<DrawerMainTabs
renderActiveTabPanelOnly={true}
defaultSelectedTabId="details"
>
<Tab
title={intl.get('overview')}
id={'details'}
panel={<InvoiceDetailTab />}
/>
<Tab
title={intl.get('journal_entries')}
id={'journal_entries'}
panel={<InvoiceGLEntriesTable />}
/>
{ability.can(
PaymentReceiveAction.View,
AbilitySubject.PaymentReceive,
) && (
<Tab
title={intl.get('payment_transactions')}
id={'payment_transactions'}
panel={<InvoicePaymentTransactionsTable />}
/>
)}
</DrawerMainTabs>
);
}
/**
* Invoice view detail.
* @returns {React.JSX}
*/
export default function InvoiceDetail() {
return (
<InvoiceDetailsRoot>
<InvoiceDetailActionsBar />
<InvoiceDetailsTabs />
</InvoiceDetailsRoot>
);
}
export const InvoiceDetailsRoot = styled.div``;

View File

@@ -0,0 +1,155 @@
// @ts-nocheck
import React from 'react';
import { useHistory } from 'react-router-dom';
import {
Button,
NavbarGroup,
Classes,
NavbarDivider,
Intent,
} from '@blueprintjs/core';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import {
If,
Can,
Icon,
DrawerActionsBar,
FormattedMessage as T,
} from '@/components';
import {
SaleInvoiceAction,
PaymentReceiveAction,
AbilitySubject,
} from '../../../constants/abilityOption';
import { compose } from '@/utils';
import { BadDebtMenuItem } from './utils';
/**
* Invoice details action bar.
*/
function InvoiceDetailActionsBar({
// #withDialogActions
openDialog,
// #withAlertsActions
openAlert,
// #withDrawerActions
closeDrawer,
}) {
const history = useHistory();
// Invoice detail drawer context.
const { invoiceId, invoice } = useInvoiceDetailDrawerContext();
// Handle edit sale invoice.
const handleEditInvoice = () => {
history.push(`/invoices/${invoiceId}/edit`);
closeDrawer('invoice-detail-drawer');
};
// Handle convert to invoice.
const handleConvertToCreitNote = () => {
history.push(`/credit-notes/new?from_invoice_id=${invoiceId}`, {
invoiceId: invoiceId,
});
closeDrawer('invoice-detail-drawer');
};
// Handle delete sale invoice.
const handleDeleteInvoice = () => {
openAlert('invoice-delete', { invoiceId });
};
// Handle print invoices.
const handlePrintInvoice = () => {
openDialog('invoice-pdf-preview', { invoiceId });
};
// Handle quick payment invoice.
const handleQuickPaymentInvoice = () => {
openDialog('quick-payment-receive', { invoiceId });
};
// Handle write-off invoice.
const handleBadDebtInvoice = () => {
openDialog('write-off-bad-debt', { invoiceId });
};
// Handle notify via SMS.
const handleNotifyViaSMS = () => {
openDialog('notify-invoice-via-sms', { invoiceId });
};
// Handle cancele write-off invoice.
const handleCancelBadDebtInvoice = () => {
openAlert('cancel-bad-debt', { invoiceId });
};
return (
<DrawerActionsBar>
<NavbarGroup>
<Can I={SaleInvoiceAction.Edit} a={AbilitySubject.Invoice}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="pen-18" />}
text={<T id={'edit_invoice'} />}
onClick={handleEditInvoice}
/>
<NavbarDivider />
</Can>
<Can I={PaymentReceiveAction.Create} a={AbilitySubject.PaymentReceive}>
<If condition={invoice.is_delivered && !invoice.is_fully_paid}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="arrow-downward" iconSize={18} />}
text={<T id={'add_payment'} />}
onClick={handleQuickPaymentInvoice}
/>
</If>
<NavbarDivider />
</Can>
<Can I={SaleInvoiceAction.View} a={AbilitySubject.Invoice}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" />}
text={<T id={'print'} />}
onClick={handlePrintInvoice}
/>
</Can>
<Can I={SaleInvoiceAction.Delete} a={AbilitySubject.Invoice}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'trash-16'} iconSize={16} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handleDeleteInvoice}
/>
</Can>
<Can I={SaleInvoiceAction.Writeoff} a={AbilitySubject.Invoice}>
<NavbarDivider />
<BadDebtMenuItem
payload={{
onBadDebt: handleBadDebtInvoice,
onCancelBadDebt: handleCancelBadDebtInvoice,
onNotifyViaSMS: handleNotifyViaSMS,
onConvert: handleConvertToCreitNote,
}}
/>
</Can>
</NavbarGroup>
</DrawerActionsBar>
);
}
export default compose(
withDialogActions,
withDrawerActions,
withAlertsActions,
)(InvoiceDetailActionsBar);

View File

@@ -0,0 +1,23 @@
// @ts-nocheck
import React from 'react';
import { DrawerBody } from '@/components';
import InvoiceDetail from './InvoiceDetail';
import { InvoiceDetailDrawerProvider } from './InvoiceDetailDrawerProvider';
/**
* Invoice detail drawer content.
* @returns {React.JSX}
*/
export default function InvoiceDetailDrawerContent({
// #ownProp
invoiceId,
}) {
return (
<InvoiceDetailDrawerProvider invoiceId={invoiceId}>
<DrawerBody>
<InvoiceDetail />
</DrawerBody>
</InvoiceDetailDrawerProvider>
);
}

View File

@@ -0,0 +1,51 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { DrawerHeaderContent, DrawerLoading } from '@/components';
import { Features } from '@/constants';
import { useInvoice } from '@/hooks/query';
import { useFeatureCan } from '@/hooks/state';
const InvoiceDetailDrawerContext = React.createContext();
/**
* Invoice detail provider.
*/
function InvoiceDetailDrawerProvider({ invoiceId, ...props }) {
// Features guard.
const { featureCan } = useFeatureCan();
// Fetch sale invoice details.
const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(invoiceId, {
enabled: !!invoiceId,
});
// Provider.
const provider = {
invoiceId,
invoice,
};
return (
<DrawerLoading loading={isInvoiceLoading}>
<DrawerHeaderContent
name="invoice-detail-drawer"
title={intl.get('invoice_details.drawer.title', {
invoiceNumber: invoice.invoice_no,
})}
subTitle={
featureCan(Features.Branches)
? intl.get('invoice_details.drawer.subtitle', {
value: invoice.branch?.name,
})
: null
}
/>
<InvoiceDetailDrawerContext.Provider value={provider} {...props} />
</DrawerLoading>
);
}
const useInvoiceDetailDrawerContext = () =>
React.useContext(InvoiceDetailDrawerContext);
export { InvoiceDetailDrawerProvider, useInvoiceDetailDrawerContext };

View File

@@ -0,0 +1,40 @@
// @ts-nocheck
import React from 'react';
import {
CommercialDocFooter,
T,
If,
DetailsMenu,
DetailItem,
} from '@/components';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
/**
* Invoice details footer.
* @returns {React.JSX}
*/
export function InvoiceDetailFooter() {
const { invoice } = useInvoiceDetailDrawerContext();
if (!invoice.terms_conditions && !invoice.invoice_message) {
return null;
}
return (
<CommercialDocFooter>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<If condition={invoice.terms_conditions}>
<DetailItem label={<T id={'terms_conditions'} />}>
{invoice.terms_conditions}
</DetailItem>
</If>
<If condition={invoice.invoice_message}>
<DetailItem label={<T id={'invoice.details.invoice_message'} />}>
{invoice.invoice_message}
</DetailItem>
</If>
</DetailsMenu>
</CommercialDocFooter>
);
}

View File

@@ -0,0 +1,109 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import { defaultTo } from 'lodash';
import {
ButtonLink,
Row,
Col,
DetailsMenu,
DetailItem,
FormatDate,
CommercialDocHeader,
CommercialDocTopHeader,
CustomerDrawerLink,
ExchangeRateDetailItem,
} from '@/components';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
import { InvoiceDetailsStatus } from './utils';
/**
* Invoice detail header.
*/
export default function InvoiceDetailHeader() {
const { invoice } = useInvoiceDetailDrawerContext();
const handleCustomerLinkClick = () => {};
return (
<CommercialDocHeader>
<CommercialDocTopHeader>
<DetailsMenu>
<AmountDetailItem label={intl.get('amount')}>
<h3 class="big-number">{invoice.formatted_amount}</h3>
</AmountDetailItem>
<StatusDetailItem label={''}>
<InvoiceDetailsStatus invoice={invoice} />
</StatusDetailItem>
</DetailsMenu>
</CommercialDocTopHeader>
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem label={intl.get('invoice_date')}>
<FormatDate value={invoice.invoice_date} />
</DetailItem>
<DetailItem label={intl.get('due_date')}>
<FormatDate value={invoice.due_date} />
</DetailItem>
<DetailItem label={intl.get('customer_name')}>
<CustomerDrawerLink customerId={invoice.customer_id}>
{invoice.customer?.display_name}
</CustomerDrawerLink>
</DetailItem>
<DetailItem label={intl.get('invoice.details.invoice_no')}>
{invoice.invoice_no}
</DetailItem>
<ExchangeRateDetailItem
exchangeRate={invoice?.exchange_rate}
toCurrency={invoice?.currency_code}
/>
</DetailsMenu>
</Col>
<Col xs={6}>
<DetailsMenu
direction={'horizantal'}
minLabelSize={'180px'}
textAlign={'right'}
>
<DetailItem label={intl.get('due_amount')}>
<strong>{invoice.formatted_due_amount}</strong>
</DetailItem>
<DetailItem label={intl.get('invoice.details.payment_amount')}>
<strong>{invoice.formatted_payment_amount}</strong>
</DetailItem>
<DetailItem
label={intl.get('reference')}
children={defaultTo(invoice.reference_no, '--')}
/>
<DetailItem
label={intl.get('invoice.details.created_at')}
children={<FormatDate value={invoice.created_at} />}
/>
</DetailsMenu>
</Col>
</Row>
</CommercialDocHeader>
);
}
const StatusDetailItem = styled(DetailItem)`
width: 50%;
text-align: right;
position: relative;
top: -5px;
`;
const AmountDetailItem = styled(DetailItem)`
width: 50%;
`;

View File

@@ -0,0 +1,23 @@
// @ts-nocheck
import React from 'react';
import { CommercialDocBox } from '@/components';
import InvoiceDetailHeader from './InvoiceDetailHeader';
import InvoiceDetailTable from './InvoiceDetailTable';
import { InvoiceDetailTableFooter } from './InvoiceDetailTableFooter';
import { InvoiceDetailFooter } from './InvoiceDetailFooter';
/**
* Invoice readonly details tab panel.
*/
export default function InvoiceDetailTab() {
return (
<CommercialDocBox>
<InvoiceDetailHeader />
<InvoiceDetailTable />
<InvoiceDetailTableFooter />
<InvoiceDetailFooter />
</CommercialDocBox>
);
}

View File

@@ -0,0 +1,30 @@
// @ts-nocheck
import React from 'react';
import { CommercialDocEntriesTable } from '@/components';
import { useInvoiceReadonlyEntriesColumns } from './utils';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
import { TableStyle } from '@/constants';
/**
* Invoice readonly details entries table columns.
*/
export default function InvoiceDetailTable() {
// Invoice readonly entries table columns.
const columns = useInvoiceReadonlyEntriesColumns();
// Invoice details drawer context.
const {
invoice: { entries },
} = useInvoiceDetailDrawerContext();
return (
<CommercialDocEntriesTable
columns={columns}
data={entries}
styleName={TableStyle.Constrant}
/>
);
}

View File

@@ -0,0 +1,53 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
FormatNumber,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
} from '@/components';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
/**
* Invoice details footer.
*/
export function InvoiceDetailTableFooter() {
const { invoice } = useInvoiceDetailDrawerContext();
return (
<InvoiceDetailsFooterRoot>
<InvoiceTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine
title={<T id={'invoice.details.subtotal'} />}
value={<FormatNumber value={invoice.balance} />}
borderStyle={TotalLineBorderStyle.SingleDark}
/>
<TotalLine
title={<T id={'invoice.details.total'} />}
value={invoice.formatted_amount}
borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold}
/>
<TotalLine
title={<T id={'invoice.details.payment_amount'} />}
value={invoice.formatted_payment_amount}
/>
<TotalLine
title={<T id={'invoice.details.due_amount'} />}
value={invoice.formatted_due_amount}
textStyle={TotalLineTextStyle.Bold}
/>
</InvoiceTotalLines>
</InvoiceDetailsFooterRoot>
);
}
const InvoiceDetailsFooterRoot = styled.div``;
const InvoiceTotalLines = styled(TotalLines)`
margin-left: auto;
`;

View File

@@ -0,0 +1,45 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { Card } from '@/components';
import { useTransactionsByReference } from '@/hooks/query';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
import JournalEntriesTable, {
AmountDisplayedBaseCurrencyMessage,
} from '../../JournalEntriesTable/JournalEntriesTable';
/**
* Invoice GL entries table.
* @returns {React.JSX}
*/
export default function InvoiceGLEntriesTable() {
const { invoiceId } = useInvoiceDetailDrawerContext();
// Handle fetch transaction by reference.
const {
data: { transactions },
isLoading: isTransactionLoading,
} = useTransactionsByReference(
{
reference_id: invoiceId,
reference_type: 'SaleInvoice',
},
{ enabled: !!invoiceId },
);
return (
<InvoiceGLEntriesRoot>
<AmountDisplayedBaseCurrencyMessage />
<InvoiceGLEntriesDatatable
loading={isTransactionLoading}
transactions={transactions}
/>
</InvoiceGLEntriesRoot>
);
}
const InvoiceGLEntriesDatatable = styled(JournalEntriesTable)``;
const InvoiceGLEntriesRoot = styled(Card)``;

View File

@@ -0,0 +1,82 @@
// @ts-nocheck
import React from 'react';
import { useHistory } from 'react-router-dom';
import { DataTable, Card, TableSkeletonRows } from '@/components';
import {
useInvoicePaymentTransactionsColumns,
ActionsMenu,
} from './components';
import { useInvoiceDetailDrawerContext } from '../InvoiceDetailDrawerProvider';
import { useInvoicePaymentTransactions } from '@/hooks/query';
import { TableStyle } from '@/constants';
import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils';
/**
* Invoice payment transactions datatable.
*/
function InvoicePaymentTransactionsTable({
// #withAlertsActions
openAlert,
// #withDrawerActions
closeDrawer,
}) {
const history = useHistory();
// Invoice payment transactions table columns.
const columns = useInvoicePaymentTransactionsColumns();
// Invoice drawer context.
const { invoiceId } = useInvoiceDetailDrawerContext();
// Fetch invoice payment transactions.
const {
data: paymentTransactions,
isFetching: isPaymentTransactionFetching,
isLoading: isPaymentTransactionLoading,
} = useInvoicePaymentTransactions(invoiceId, {
enabled: !!invoiceId,
});
// Handles delete payment transactions.
const handleDeletePaymentTransactons = ({ payment_receive_id }) => {
openAlert('payment-receive-delete', {
paymentReceiveId: payment_receive_id,
});
};
// Handles edit payment transactions.
const handleEditPaymentTransactions = ({ payment_receive_id }) => {
history.push(`/payment-receives/${payment_receive_id}/edit`);
closeDrawer('invoice-detail-drawer');
};
return (
<Card>
<DataTable
columns={columns}
data={paymentTransactions}
loading={isPaymentTransactionLoading}
headerLoading={isPaymentTransactionLoading}
progressBarLoading={isPaymentTransactionFetching}
TableLoadingRenderer={TableSkeletonRows}
styleName={TableStyle.Constrant}
ContextMenu={ActionsMenu}
payload={{
onDelete: handleDeletePaymentTransactons,
onEdit: handleEditPaymentTransactions,
}}
/>
</Card>
);
}
export default compose(
withAlertsActions,
withDrawerActions,
)(InvoicePaymentTransactionsTable);

View File

@@ -0,0 +1,91 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import clsx from 'classnames';
import { Intent, Menu, MenuItem, MenuDivider } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import { FormatDateCell, Icon, Can } from '@/components';
import { safeCallback } from '@/utils';
import { PaymentReceiveAction, AbilitySubject } from '@/constants/abilityOption';
/**
* Table actions menu.
*/
export function ActionsMenu({
row: { original },
payload: { onEdit, onDelete },
}) {
return (
<Menu>
<Can I={PaymentReceiveAction.Edit} a={AbilitySubject.PaymentReceive}>
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('invoice_transactions.action.edit_transaction')}
onClick={safeCallback(onEdit, original)}
/>
</Can>
<Can I={PaymentReceiveAction.Delete} a={AbilitySubject.PaymentReceive}>
<MenuDivider />
<MenuItem
text={intl.get('invoice_transactions.action.delete_transaction')}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
icon={<Icon icon="trash-16" iconSize={16} />}
/>
</Can>
</Menu>
);
}
/**
* Retrieve invoice payment transactions table columns.
*/
export const useInvoicePaymentTransactionsColumns = () => {
return React.useMemo(
() => [
{
id: 'date',
Header: intl.get('payment_date'),
accessor: 'formatted_payment_date',
Cell: FormatDateCell,
width: 110,
className: 'date',
textOverview: true,
},
{
id: 'deposit_account_name',
Header: intl.get('invoice_transactions.column.withdrawal_account'),
accessor: 'deposit_account_name',
width: 120,
textOverview: true,
},
{
id: 'amount',
Header: intl.get('amount'),
accessor: 'formatted_payment_amount',
align: 'right',
width: 120,
className: clsx(CLASSES.FONT_BOLD),
textOverview: true,
},
{
id: 'payment_number.',
Header: intl.get('payment_no'),
accessor: 'payment_number',
width: 100,
className: 'payment_number',
textOverview: true,
},
{
id: 'payment_reference_no',
Header: intl.get('reference_no'),
accessor: 'payment_reference_no',
width: 90,
className: 'payment_reference_no',
clickable: true,
textOverview: true,
},
],
[],
);
};

View File

@@ -0,0 +1,34 @@
// @ts-nocheck
import React from 'react';
import { Drawer, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers';
import { compose } from '@/utils';
const InvoiceDetailDrawerContent = React.lazy(() =>
import('./InvoiceDetailDrawerContent'),
);
/**
* Invoice Detail drawer.
*/
function InvoiceDetailDrawer({
name,
// #withDrawer
isOpen,
payload: { invoiceId },
}) {
return (
<Drawer
isOpen={isOpen}
name={name}
style={{ minWidth: '700px', maxWidth: '1000px' }}
size={'65%'}
>
<DrawerSuspense>
<InvoiceDetailDrawerContent invoiceId={invoiceId} />
</DrawerSuspense>
</Drawer>
);
}
export default compose(withDrawers())(InvoiceDetailDrawer);

View File

@@ -0,0 +1,186 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import {
Button,
Popover,
PopoverInteractionKind,
Position,
MenuItem,
Menu,
Intent,
Tag,
} from '@blueprintjs/core';
import { getColumnWidth } from '@/utils';
import {
FormatNumberCell,
Icon,
FormattedMessage as T,
Choose,
Can,
TextOverviewTooltipCell,
} from '@/components';
import { SaleInvoiceAction, AbilitySubject } from '@/constants/abilityOption';
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
/**
* Retrieve invoice readonly details table columns.
*/
export const useInvoiceReadonlyEntriesColumns = () => {
// Invoice details drawer context.
const {
invoice: { entries },
} = useInvoiceDetailDrawerContext();
return React.useMemo(
() => [
{
Header: intl.get('product_and_service'),
accessor: 'item.name',
Cell: TextOverviewTooltipCell,
disableSortBy: true,
textOverview: true,
width: 150,
},
{
Header: intl.get('description'),
accessor: 'description',
Cell: TextOverviewTooltipCell,
disableSortBy: true,
textOverview: true,
},
{
Header: intl.get('quantity'),
accessor: 'quantity',
Cell: FormatNumberCell,
align: 'right',
disableSortBy: true,
textOverview: true,
width: getColumnWidth(entries, 'quantity', {
minWidth: 60,
magicSpacing: 5,
}),
},
{
Header: intl.get('rate'),
accessor: 'rate',
Cell: FormatNumberCell,
align: 'right',
disableSortBy: true,
textOverview: true,
width: getColumnWidth(entries, 'rate', {
minWidth: 60,
magicSpacing: 5,
}),
},
{
Header: intl.get('amount'),
accessor: 'amount',
Cell: FormatNumberCell,
align: 'right',
disableSortBy: true,
textOverview: true,
width: getColumnWidth(entries, 'amount', {
minWidth: 60,
magicSpacing: 5,
}),
},
],
[],
);
};
/**
* Invoice details more actions menu.
* @returns {React.JSX}
*/
export const BadDebtMenuItem = ({
payload: { onCancelBadDebt, onBadDebt, onNotifyViaSMS, onConvert },
}) => {
const { invoice } = useInvoiceDetailDrawerContext();
return (
<Popover
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
modifiers={{
offset: { offset: '0, 4' },
}}
content={
<Menu>
<Choose>
<Choose.When condition={!invoice.is_writtenoff}>
<MenuItem
text={<T id={'bad_debt.dialog.bad_debt'} />}
onClick={onBadDebt}
/>
</Choose.When>
<Choose.When condition={invoice.is_writtenoff}>
<MenuItem
onClick={onCancelBadDebt}
text={<T id={'bad_debt.dialog.cancel_bad_debt'} />}
/>
</Choose.When>
</Choose>
<Can I={SaleInvoiceAction.Edit} a={AbilitySubject.Invoice}>
<MenuItem
onClick={onConvert}
text={<T id={'invoice.convert_to_credit_note'} />}
/>
</Can>
<Can I={SaleInvoiceAction.NotifyBySms} a={AbilitySubject.Invoice}>
<MenuItem
onClick={onNotifyViaSMS}
text={<T id={'notify_via_sms.dialog.notify_via_sms'} />}
/>
</Can>
</Menu>
}
>
<Button icon={<Icon icon="more-vert" iconSize={16} />} minimal={true} />
</Popover>
);
};
/**
* Invoice details status.
* @returns {React.JSX}
*/
export function InvoiceDetailsStatus({ invoice }) {
return (
<Choose>
<Choose.When condition={invoice.is_fully_paid && invoice.is_delivered}>
<StatusTag intent={Intent.SUCCESS} round={true}>
<T id={'paid'} />
</StatusTag>
</Choose.When>
<Choose.When condition={invoice.is_delivered}>
<Choose>
<Choose.When condition={invoice.is_overdue}>
<StatusTag intent={Intent.WARNING} round={true}>
<T id={'overdue'} />
</StatusTag>
</Choose.When>
<Choose.Otherwise>
<StatusTag intent={Intent.PRIMARY} round={true}>
<T id={'delivered'} />
</StatusTag>
</Choose.Otherwise>
</Choose>
</Choose.When>
<Choose.Otherwise>
<StatusTag round={true} minimal={true}>
<T id={'draft'} />
</StatusTag>
</Choose.Otherwise>
</Choose>
);
}
const StatusTag = styled(Tag)`
min-width: 65px;
text-align: center;
`;