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,46 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import { Tab } from '@blueprintjs/core';
import { DrawerMainTabs } from '@/components';
import ReceiptDetailTab from './ReceiptDetailTab';
import ReceiptDetailActionBar from './ReceiptDetailActionBar';
import { ReceiptDetailsGLEntriesPanel } from './ReceiptDetailsGLEntriesPanel';
/**
* Receipt view detail.
* @returns {React.JSX}
*/
export default function ReceiptDetail() {
return (
<ReceiptDetailsRoot>
<ReceiptDetailActionBar />
<ReceiptDetailsTabs />
</ReceiptDetailsRoot>
);
}
/**
* Receipt details tabs bar.
* @returns {React.JSX}
*/
function ReceiptDetailsTabs() {
return (
<DrawerMainTabs defaultSelectedTabId="details">
<Tab
title={intl.get('details')}
id={'details'}
panel={<ReceiptDetailTab />}
/>
<Tab
title={intl.get('journal_entries')}
id={'journal_entries'}
panel={<ReceiptDetailsGLEntriesPanel />}
/>
</DrawerMainTabs>
);
}
const ReceiptDetailsRoot = styled.div``;

View File

@@ -0,0 +1,109 @@
// @ts-nocheck
import React from 'react';
import { useHistory } from 'react-router-dom';
import {
Button,
NavbarGroup,
Classes,
NavbarDivider,
Intent,
} from '@blueprintjs/core';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import {
Can,
Icon,
FormattedMessage as T,
DrawerActionsBar,
} from '@/components';
import { ReceiptMoreMenuItems } from './components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
import { SaleReceiptAction, AbilitySubject } from '@/constants/abilityOption';
import { safeCallback, compose } from '@/utils';
/**
* Receipt details actions bar.
* @returns {React.JSX}
*/
function ReceiptDetailActionBar({
// #withDialogActions
openDialog,
// #withAlertsActions
openAlert,
// #withDrawerActions
closeDrawer,
}) {
const history = useHistory();
const { receiptId } = useReceiptDetailDrawerContext();
// Handle edit sale receipt.
const onEditReceipt = () => {
history.push(`/receipts/${receiptId}/edit`);
closeDrawer('receipt-detail-drawer');
};
// Handle delete sale receipt.
const onDeleteReceipt = () => {
openAlert('receipt-delete', { receiptId });
};
// Handle print receipt.
const onPrintReceipt = () => {
openDialog('receipt-pdf-preview', { receiptId });
};
// Handle notify via SMS.
const handleNotifyViaSMS = () => {
openDialog('notify-receipt-via-sms', { receiptId });
};
return (
<DrawerActionsBar>
<NavbarGroup>
<Can I={SaleReceiptAction.Edit} a={AbilitySubject.Receipt}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="pen-18" />}
text={<T id={'edit_receipt'} />}
onClick={safeCallback(onEditReceipt)}
/>
<NavbarDivider />
</Can>
<Can I={SaleReceiptAction.View} a={AbilitySubject.Receipt}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" />}
text={<T id={'print'} />}
onClick={safeCallback(onPrintReceipt)}
/>
</Can>
<Can I={SaleReceiptAction.Delete} a={AbilitySubject.Receipt}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'trash-16'} iconSize={16} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={safeCallback(onDeleteReceipt)}
/>
</Can>
<Can I={SaleReceiptAction.NotifyBySms} a={AbilitySubject.Receipt}>
<NavbarDivider />
<ReceiptMoreMenuItems
payload={{
onNotifyViaSMS: handleNotifyViaSMS,
}}
/>
</Can>
</NavbarGroup>
</DrawerActionsBar>
);
}
export default compose(
withDialogActions,
withDrawerActions,
withAlertsActions,
)(ReceiptDetailActionBar);

View File

@@ -0,0 +1,22 @@
// @ts-nocheck
import React from 'react';
import { DrawerBody } from '@/components';
import ReceiptDetail from './ReceiptDetail';
import { ReceiptDetailDrawerProvider } from './ReceiptDetailDrawerProvider';
/**
* Receipt detail drawer content.
*/
export default function ReceiptDetailDrawerContent({
// #ownProp
receiptId,
}) {
return (
<ReceiptDetailDrawerProvider receiptId={receiptId}>
<DrawerBody>
<ReceiptDetail />
</DrawerBody>
</ReceiptDetailDrawerProvider>
);
}

View File

@@ -0,0 +1,55 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { DrawerHeaderContent, DrawerLoading } from '@/components';
import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state';
import { useReceipt } from '@/hooks/query';
// useTransactionsByReference
const ReceiptDetailDrawerContext = React.createContext();
/**
* Receipt detail provider.
*/
function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
// Features guard.
const { featureCan } = useFeatureCan();
// Fetch sale receipt details.
const { data: receipt, isFetching: isReceiptLoading } = useReceipt(
receiptId,
{
enabled: !!receiptId,
},
);
// Provider.
const provider = {
receiptId,
receipt,
};
return (
<DrawerLoading loading={isReceiptLoading}>
<DrawerHeaderContent
name="receipt-detail-drawer"
title={intl.get('receipt.drawer.title', {
number: receipt.receipt_number,
})}
subTitle={
featureCan(Features.Branches)
? intl.get('receipt.drawer.subtitle', {
value: receipt.branch?.name,
})
: null
}
/>
<ReceiptDetailDrawerContext.Provider value={provider} {...props} />
</DrawerLoading>
);
}
const useReceiptDetailDrawerContext = () =>
React.useContext(ReceiptDetailDrawerContext);
export { ReceiptDetailDrawerProvider, useReceiptDetailDrawerContext };

View File

@@ -0,0 +1,36 @@
// @ts-nocheck
import React from 'react';
import {
CommercialDocFooter,
T,
If,
DetailsMenu,
DetailItem,
} from '@/components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
/**
* Receipt details footer
* @returns {React.JSX}
*/
export default function ReceiptDetailFooter() {
const { receipt } = useReceiptDetailDrawerContext();
return (
<CommercialDocFooter>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<If condition={receipt.statement}>
<DetailItem label={<T id={'receipt.details.statement'} />}>
{receipt.statement}
</DetailItem>
</If>
<If condition={receipt.receipt_message}>
<DetailItem label={<T id={'receipt.details.receipt_message'} />}>
{receipt.receipt_message}
</DetailItem>
</If>
</DetailsMenu>
</CommercialDocFooter>
);
}

View File

@@ -0,0 +1,101 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import { defaultTo } from 'lodash';
import {
ButtonLink,
CustomerDrawerLink,
CommercialDocHeader,
CommercialDocTopHeader,
ExchangeRateDetailItem,
Row,
Col,
FormatDate,
DetailsMenu,
DetailItem,
} from '@/components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
import { ReceiptDetailsStatus } from './components';
/**
* Receipt details header.
*/
export default function ReceiptDetailHeader() {
const { receipt } = useReceiptDetailDrawerContext();
return (
<CommercialDocHeader>
<CommercialDocTopHeader>
<DetailsMenu>
<AmountReceiptItem label={intl.get('amount')}>
<h3 class="big-number">{receipt.formatted_amount}</h3>
</AmountReceiptItem>
<StatusReceiptItem>
<ReceiptDetailsStatus receipt={receipt} />
</StatusReceiptItem>
</DetailsMenu>
</CommercialDocTopHeader>
<Row>
<Col xs={6}>
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
<DetailItem
label={intl.get('receipt.details.receipt_number')}
children={defaultTo(receipt.receipt_number, '-')}
/>
<DetailItem label={intl.get('customer_name')}>
<CustomerDrawerLink customerId={receipt.customer_id}>
{receipt.customer?.display_name}
</CustomerDrawerLink>
</DetailItem>
<DetailItem
label={intl.get('receipt_date')}
children={<FormatDate value={receipt.receipt_date} />}
/>
<DetailItem
label={intl.get('closed_date')}
children={<FormatDate value={receipt.closed_at_date} />}
/>
<ExchangeRateDetailItem
exchangeRate={receipt?.exchange_rate}
toCurrency={receipt?.currency_code}
/>
</DetailsMenu>
</Col>
<Col xs={6}>
<DetailsMenu
direction={'horizantal'}
minLabelSize={'180px'}
textAlign={'right'}
>
<DetailItem
label={intl.get('deposit_account')}
children={receipt.deposit_account?.name}
/>
<DetailItem
label={intl.get('reference')}
children={defaultTo(receipt.reference_no, '--')}
/>
<DetailItem
label={intl.get('receipt.details.created_at')}
children={<FormatDate value={receipt.created_at} />}
/>
</DetailsMenu>
</Col>
</Row>
</CommercialDocHeader>
);
}
const AmountReceiptItem = styled(DetailItem)`
width: 50%;
`;
const StatusReceiptItem = styled(DetailItem)`
width: 50%;
text-align: right;
`;

View File

@@ -0,0 +1,25 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { CommercialDocBox } from '@/components';
import ReceiptDetailHeader from './ReceiptDetailHeader';
import ReceiptDetailTable from './ReceiptDetailTable';
import ReceiptDetailTableFooter from './ReceiptDetailTableFooter';
import ReceiptDetailFooter from './ReceiptDetailFooter';
export default function ReceiptDetailTab() {
return (
<ReceiptDetailsOverviewRoot>
<CommercialDocBox>
<ReceiptDetailHeader />
<ReceiptDetailTable />
<ReceiptDetailTableFooter />
<ReceiptDetailFooter />
</CommercialDocBox>
</ReceiptDetailsOverviewRoot>
);
}
const ReceiptDetailsOverviewRoot = styled.div``;

View File

@@ -0,0 +1,30 @@
// @ts-nocheck
import React from 'react';
import { CommercialDocEntriesTable } from '@/components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
import { useReceiptReadonlyEntriesTableColumns } from './utils';
import { TableStyle } from '@/constants';
/**
* Receipt readonly details table columns.
*/
export default function ReceiptDetailTable() {
// Receipt details drawer context.
const {
receipt: { entries },
} = useReceiptDetailDrawerContext();
// Receipt readonly entries table columns.
const columns = useReceiptReadonlyEntriesTableColumns();
return (
<CommercialDocEntriesTable
columns={columns}
data={entries}
styleName={TableStyle.Constrant}
/>
);
}

View File

@@ -0,0 +1,52 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
FormatNumber,
} from '@/components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
/**
* Receipts read-only details table footer.
*/
export default function ReceiptDetailTableFooter() {
const { receipt } = useReceiptDetailDrawerContext();
return (
<ReceiptDetailsFooterRoot>
<ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine
title={<T id={'receipt.details.subtotal'} />}
value={<FormatNumber value={receipt.amount} />}
/>
<TotalLine
title={<T id={'receipt.details.total'} />}
value={receipt.formatted_amount}
borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold}
/>
<TotalLine
title={<T id={'receipt.details.payment_amount'} />}
value={receipt.formatted_amount}
borderStyle={TotalLineBorderStyle.DoubleDark}
/>
<TotalLine
title={<T id={'receipt.details.due_amount'} />}
value={'0'}
/>
</ReceiptTotalLines>
</ReceiptDetailsFooterRoot>
);
}
export const ReceiptDetailsFooterRoot = styled.div``;
export const ReceiptTotalLines = styled(TotalLines)`
margin-left: auto;
`;

View File

@@ -0,0 +1,44 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { Card } from '@/components';
import { useTransactionsByReference } from '@/hooks/query';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
import JournalEntriesTable, {
AmountDisplayedBaseCurrencyMessage,
} from '../../JournalEntriesTable/JournalEntriesTable';
/**
* Receipt details GL entries panel.
* @returns {React.JSX}
*/
export function ReceiptDetailsGLEntriesPanel() {
// Receipt details drawer context.
const { receiptId } = useReceiptDetailDrawerContext();
// Handle fetch transaction by reference.
const {
data: { transactions },
isLoading: isTransactionLoading,
} = useTransactionsByReference(
{
reference_id: receiptId,
reference_type: 'SaleReceipt',
},
{ enabled: !!receiptId },
);
return (
<ReceiptGLEntriesRoot>
<AmountDisplayedBaseCurrencyMessage />
<JournalEntriesTable
loading={isTransactionLoading}
transactions={transactions}
/>
</ReceiptGLEntriesRoot>
);
}
const ReceiptGLEntriesRoot = styled(Card)``;

View File

@@ -0,0 +1,59 @@
// @ts-nocheck
import React from 'react';
import {
Button,
Popover,
PopoverInteractionKind,
Position,
MenuItem,
Menu,
Intent,
Tag,
} from '@blueprintjs/core';
import { Icon, Choose, T } from '@/components';
/**
* Receipt details status.
* @returns {React.JSX}
*/
export function ReceiptDetailsStatus({ receipt }) {
return (
<Choose>
<Choose.When condition={receipt.is_closed}>
<Tag round={true} intent={Intent.SUCCESS}>
<T id={'closed'} />
</Tag>
</Choose.When>
<Choose.Otherwise>
<Tag intent={Intent.WARNING} round={true}>
<T id={'draft'} />
</Tag>
</Choose.Otherwise>
</Choose>
);
}
export function ReceiptMoreMenuItems({ payload: { onNotifyViaSMS } }) {
return (
<Popover
minimal={true}
content={
<Menu>
<MenuItem
onClick={onNotifyViaSMS}
text={<T id={'notify_via_sms.dialog.notify_via_sms'} />}
/>
</Menu>
}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
modifiers={{
offset: { offset: '0, 4' },
}}
>
<Button icon={<Icon icon="more-vert" iconSize={16} />} minimal={true} />
</Popover>
);
}

View File

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

View File

@@ -0,0 +1,70 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { getColumnWidth } from '@/utils';
import { FormatNumberCell, TextOverviewTooltipCell } from '@/components';
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
export const useReceiptReadonlyEntriesTableColumns = () => {
// Receipt details drawer context.
const {
receipt: { entries },
} = useReceiptDetailDrawerContext();
return React.useMemo(
() => [
{
Header: intl.get('product_and_service'),
accessor: 'item.name',
Cell: TextOverviewTooltipCell,
width: 150,
className: 'name',
disableSortBy: true,
textOverview: true,
},
{
Header: intl.get('description'),
accessor: 'description',
Cell: TextOverviewTooltipCell,
className: 'description',
disableSortBy: true,
textOverview: true,
},
{
Header: intl.get('quantity'),
accessor: 'quantity',
Cell: FormatNumberCell,
width: getColumnWidth(entries, 'quantity', {
minWidth: 60,
magicSpacing: 5,
}),
align: 'right',
disableSortBy: true,
},
{
Header: intl.get('rate'),
accessor: 'rate',
Cell: FormatNumberCell,
width: getColumnWidth(entries, 'rate', {
minWidth: 60,
magicSpacing: 5,
}),
align: 'right',
disableSortBy: true,
textOverview: true,
},
{
Header: intl.get('amount'),
accessor: 'amount',
Cell: FormatNumberCell,
width: getColumnWidth(entries, 'amount', {
minWidth: 60,
magicSpacing: 5,
}),
align: 'right',
disableSortBy: true,
textOverview: true,
},
],
[],
);
};