refactoring: invoice, receipt, payment receive, estimate and journal number dialogs.

This commit is contained in:
a.bouhuolia
2021-02-23 10:52:25 +02:00
parent 6e00c2ef7d
commit 236bb896db
37 changed files with 467 additions and 204 deletions

View File

@@ -5,11 +5,7 @@ import InviteUserDialog from 'containers/Dialogs/InviteUserDialog';
import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog'; import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog';
import CurrencyFormDialog from 'containers/Dialogs/CurrencyFormDialog'; import CurrencyFormDialog from 'containers/Dialogs/CurrencyFormDialog';
import ExchangeRateFormDialog from 'containers/Dialogs/ExchangeRateFormDialog'; import ExchangeRateFormDialog from 'containers/Dialogs/ExchangeRateFormDialog';
import JournalNumberDialog from 'containers/Dialogs/JournalNumberDialog';
import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberDialog';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
import InventoryAdjustmentDialog from 'containers/Dialogs/InventoryAdjustmentFormDialog'; import InventoryAdjustmentDialog from 'containers/Dialogs/InventoryAdjustmentFormDialog';
import PaymentViaVoucherDialog from 'containers/Dialogs/PaymentViaVoucherDialog'; import PaymentViaVoucherDialog from 'containers/Dialogs/PaymentViaVoucherDialog';
@@ -20,11 +16,6 @@ export default function DialogsContainer() {
return ( return (
<div> <div>
<AccountDialog dialogName={'account-form'} /> <AccountDialog dialogName={'account-form'} />
<JournalNumberDialog dialogName={'journal-number-form'} />
<PaymentReceiveNumberDialog dialogName={'payment-receive-number-form'} />
<EstimateNumberDialog dialogName={'estimate-number-form'} />
<ReceiptNumberDialog dialogName={'receipt-number-form'} />
<InvoiceNumberDialog dialogName={'invoice-number-form'} />
<CurrencyFormDialog dialogName={'currency-form'} /> <CurrencyFormDialog dialogName={'currency-form'} />
<InviteUserDialog dialogName={'invite-user'} /> <InviteUserDialog dialogName={'invite-user'} />
<ExchangeRateFormDialog dialogName={'exchangeRate-form'} /> <ExchangeRateFormDialog dialogName={'exchangeRate-form'} />

View File

@@ -15,6 +15,7 @@ import MakeJournalEntriesHeader from './MakeJournalEntriesHeader';
import MakeJournalFormFloatingActions from './MakeJournalFormFloatingActions'; import MakeJournalFormFloatingActions from './MakeJournalFormFloatingActions';
import MakeJournalEntriesField from './MakeJournalEntriesField'; import MakeJournalEntriesField from './MakeJournalEntriesField';
import MakeJournalFormFooter from './MakeJournalFormFooter'; import MakeJournalFormFooter from './MakeJournalFormFooter';
import MakeJournalFormDialogs from './MakeJournalFormDialogs';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
@@ -167,6 +168,8 @@ function MakeJournalEntriesForm({
<MakeJournalEntriesField /> <MakeJournalEntriesField />
<MakeJournalFormFooter /> <MakeJournalFormFooter />
<MakeJournalFormFloatingActions /> <MakeJournalFormFloatingActions />
<MakeJournalFormDialogs />
</Form> </Form>
</Formik> </Formik>
</div> </div>

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { useFormikContext } from 'formik';
import JournalNumberDialog from 'containers/Dialogs/JournalNumberDialog';
import { transactionNumber } from 'utils';
/**
* Make journal form dialogs.
*/
export default function MakeJournalFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the journal number form submit confirm.
const handleConfirm = (values) => {
setFieldValue(
'journal_number',
transactionNumber(values.number_prefix, values.next_number),
);
};
return (
<>
<JournalNumberDialog
dialogName={'journal-number-form'}
onConfirm={handleConfirm}
/>
</>
);
}

View File

@@ -1,13 +1,12 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { DialogContent } from 'components'; import { DialogContent } from 'components';
import { useQuery, queryCache } from 'react-query'; import { useSaveSettings, useSettingsEstimates } from 'hooks/query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm'; import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import { compose, optionsMapToArray } from 'utils'; import { compose, optionsMapToArray, saveInvoke } from 'utils';
/** /**
* Estimate number dialog's content. * Estimate number dialog's content.
@@ -18,28 +17,26 @@ function EstimateNumberDialogContent({
nextNumber, nextNumber,
numberPrefix, numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions // #withDialogActions
closeDialog, closeDialog,
// #ownProps
onConfirm,
}) { }) {
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({})); const { isLoading: isSettingsLoading } = useSettingsEstimates();
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
const handleSubmitForm = (values, { setSubmitting }) => { const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => { const options = optionsMapToArray(values).map((option) => ({
return { key: option.key, ...option, group: 'sales_estimates' }; key: option.key,
}); ...option,
requestSubmitOptions({ options }) group: 'sales_estimates',
}));
saveSettingsMutate({ options })
.then(() => { .then(() => {
setSubmitting(false); setSubmitting(false);
closeDialog('estimate-number-form'); closeDialog('estimate-number-form');
saveInvoke(onConfirm, values);
setTimeout(() => {
queryCache.invalidateQueries('settings');
// setEstimateNumberChanged(true);
}, 250);
}) })
.catch(() => { .catch(() => {
setSubmitting(false); setSubmitting(false);
@@ -51,7 +48,7 @@ function EstimateNumberDialogContent({
}, [closeDialog]); }, [closeDialog]);
return ( return (
<DialogContent isLoading={fetchSettings.isFetching}> <DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm <ReferenceNumberForm
initialNumber={nextNumber} initialNumber={nextNumber}
initialPrefix={numberPrefix} initialPrefix={numberPrefix}
@@ -64,7 +61,6 @@ function EstimateNumberDialogContent({
export default compose( export default compose(
withDialogActions, withDialogActions,
withSettingsActions,
withSettings(({ estimatesSettings }) => ({ withSettings(({ estimatesSettings }) => ({
nextNumber: estimatesSettings?.nextNumber, nextNumber: estimatesSettings?.nextNumber,
numberPrefix: estimatesSettings?.numberPrefix, numberPrefix: estimatesSettings?.numberPrefix,

View File

@@ -2,13 +2,18 @@ import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components'; import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect'; import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils'; import { saveInvoke, compose } from 'utils';
const EstimateNumberDialogContent = lazy(() => const EstimateNumberDialogContent = lazy(() =>
import('./EstimateNumberDialogContent'), import('./EstimateNumberDialogContent'),
); );
function EstimateNumberDialog({ dialogName, paylaod = { id: null }, isOpen }) { function EstimateNumberDialog({
dialogName,
paylaod = { id: null },
isOpen,
onConfirm
}) {
return ( return (
<Dialog <Dialog
name={dialogName} name={dialogName}
@@ -19,7 +24,9 @@ function EstimateNumberDialog({ dialogName, paylaod = { id: null }, isOpen }) {
className={'dialog--journal-number-settings'} className={'dialog--journal-number-settings'}
> >
<DialogSuspense> <DialogSuspense>
<EstimateNumberDialogContent EstimateNumberId={paylaod.id} /> <EstimateNumberDialogContent
estimateNumberId={paylaod.id}
onConfirm={(values) => saveInvoke(onConfirm, values)}/>
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>
); );

View File

@@ -16,24 +16,30 @@ import { compose, optionsMapToArray } from 'utils';
*/ */
function InvoiceNumberDialogContent({ function InvoiceNumberDialogContent({
// #ownProps
onConfirm,
// #withSettings // #withSettings
nextNumber, nextNumber,
numberPrefix, numberPrefix,
// #withDialogActions // #withDialogActions
closeDialog, closeDialog,
}) { }) {
const { mutateAsync: saveSettings } = useSaveSettings(); const { mutateAsync: saveSettings } = useSaveSettings();
const handleSubmitForm = (values, { setSubmitting }) => { const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => { const options = optionsMapToArray(values).map((option) => ({
return { key: option.key, ...option, group: 'sales_invoices' }; key: option.key,
}); ...option,
group: 'sales_invoices',
}));
saveSettings({ options }) saveSettings({ options })
.then(() => { .then(() => {
setSubmitting(false); setSubmitting(false);
closeDialog('invoice-number-form'); closeDialog('invoice-number-form');
onConfirm(values);
}) })
.catch(() => { .catch(() => {
setSubmitting(false); setSubmitting(false);
@@ -64,5 +70,4 @@ export default compose(
nextNumber: invoiceSettings?.nextNumber, nextNumber: invoiceSettings?.nextNumber,
numberPrefix: invoiceSettings?.numberPrefix, numberPrefix: invoiceSettings?.numberPrefix,
})), })),
// withInvoicesActions,
)(InvoiceNumberDialogContent); )(InvoiceNumberDialogContent);

View File

@@ -1,6 +1,6 @@
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
import { DialogContent } from 'components'; import { DialogContent } from 'components';
import { useSettings } from 'hooks/query'; import { useSettingsInvoices } from 'hooks/query';
const InvoiceNumberDialogContext = createContext(); const InvoiceNumberDialogContext = createContext();
@@ -8,15 +8,15 @@ const InvoiceNumberDialogContext = createContext();
* Invoice number dialog provider. * Invoice number dialog provider.
*/ */
function InvoiceNumberDialogProvider({ query, ...props }) { function InvoiceNumberDialogProvider({ query, ...props }) {
const { isLoading } = useSettings(); const { isLoading: isSettingsLoading } = useSettingsInvoices();
// Provider payload. // Provider payload.
const provider = { const provider = {
isSettingsLoading,
}; };
return ( return (
<DialogContent isLoading={isLoading}> <DialogContent isLoading={isSettingsLoading}>
<InvoiceNumberDialogContext.Provider value={provider} {...props} /> <InvoiceNumberDialogContext.Provider value={provider} {...props} />
</DialogContent> </DialogContent>
); );

View File

@@ -2,13 +2,19 @@ import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components'; import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect'; import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils'; import { compose, saveInvoke } from 'utils';
const InvoiceNumberDialogContent = lazy(() => const InvoiceNumberDialogContent = lazy(() =>
import('./InvoiceNumberDialogContent'), import('./InvoiceNumberDialogContent'),
); );
function InvoiceNumberDialog({ dialogName, payload = { id: null }, isOpen }) { function InvoiceNumberDialog({
dialogName,
payload = { id: null },
isOpen,
onConfirm,
}) {
return ( return (
<Dialog <Dialog
title={<T id={'invoice_number_settings'} />} title={<T id={'invoice_number_settings'} />}
@@ -18,7 +24,9 @@ function InvoiceNumberDialog({ dialogName, payload = { id: null }, isOpen }) {
isOpen={isOpen} isOpen={isOpen}
> >
<DialogSuspense> <DialogSuspense>
<InvoiceNumberDialogContent InvoiceNumberId={payload.id} /> <InvoiceNumberDialogContent
InvoiceNumberId={payload.id}
onConfirm={(values) => saveInvoke(onConfirm, values)} />
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>
); );

View File

@@ -1,15 +1,12 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { DialogContent } from 'components'; import { DialogContent } from 'components';
import { useQuery, queryCache } from 'react-query'; import { useSaveSettings, useSettingsManualJournals } from 'hooks/query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm'; import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
// import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; import { saveInvoke, compose, optionsMapToArray } from 'utils';
import { compose, optionsMapToArray } from 'utils';
import 'style/pages/ManualJournal/JournalNumberDialog.scss' import 'style/pages/ManualJournal/JournalNumberDialog.scss'
@@ -21,28 +18,25 @@ function JournalNumberDialogContent({
nextNumber, nextNumber,
numberPrefix, numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions // #withDialogActions
closeDialog, closeDialog,
}) { // #ownProps
const fetchSettings = useQuery( onConfirm
['settings'], }) {
() => requestFetchOptions({}), const { isLoading: isSettingsLoading } = useSettingsManualJournals();
); const { mutateAsync: saveSettingsMutate } = useSaveSettings();
// Handle the form submit.
const handleSubmitForm = (values, { setSubmitting }) => { const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => ({ const options = optionsMapToArray(values).map((option) => ({
key: option.key, ...option, group: 'manual_journals', key: option.key, ...option, group: 'manual_journals',
})); }));
requestSubmitOptions({ options }).then(() => { saveSettingsMutate({ options }).then(() => {
setSubmitting(false); setSubmitting(false);
closeDialog('journal-number-form'); closeDialog('journal-number-form');
saveInvoke(onConfirm, values);
}).catch(() => { }).catch(() => {
setSubmitting(false); setSubmitting(false);
}); });
@@ -53,7 +47,7 @@ function JournalNumberDialogContent({
}, [closeDialog]); }, [closeDialog]);
return ( return (
<DialogContent isLoading={fetchSettings.isFetching}> <DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm <ReferenceNumberForm
initialNumber={nextNumber} initialNumber={nextNumber}
initialPrefix={numberPrefix} initialPrefix={numberPrefix}
@@ -66,10 +60,8 @@ function JournalNumberDialogContent({
export default compose( export default compose(
withDialogActions, withDialogActions,
withSettingsActions,
withSettings(({ manualJournalsSettings }) => ({ withSettings(({ manualJournalsSettings }) => ({
nextNumber: manualJournalsSettings?.nextNumber, nextNumber: manualJournalsSettings?.nextNumber,
numberPrefix: manualJournalsSettings?.numberPrefix, numberPrefix: manualJournalsSettings?.numberPrefix,
})), })),
// withManualJournalsActions,
)(JournalNumberDialogContent); )(JournalNumberDialogContent);

View File

@@ -2,7 +2,7 @@ import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components'; import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect'; import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils'; import { saveInvoke, compose } from 'utils';
const JournalNumberDialogContent = lazy(() => import('./JournalNumberDialogContent')); const JournalNumberDialogContent = lazy(() => import('./JournalNumberDialogContent'));
@@ -10,7 +10,12 @@ function JournalNumberDialog({
dialogName, dialogName,
payload = { id: null }, payload = { id: null },
isOpen, isOpen,
onConfirm
}) { }) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values)
};
return ( return (
<Dialog <Dialog
name={dialogName} name={dialogName}
@@ -23,6 +28,7 @@ function JournalNumberDialog({
<DialogSuspense> <DialogSuspense>
<JournalNumberDialogContent <JournalNumberDialogContent
journalNumberId={payload.id} journalNumberId={payload.id}
onConfirm={handleConfirm}
/> />
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>

View File

@@ -1,15 +1,14 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { DialogContent } from 'components'; import { DialogContent } from 'components';
import { useQuery } from 'react-query'; import { useSaveSettings, useSettingsPaymentReceives } from 'hooks/query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm'; import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettingsActions from 'containers/Settings/withSettingsActions'; import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
// import withPaymentReceivesActions from 'containers/Sales/PaymentReceive/withPaymentReceivesActions';
import { compose, optionsMapToArray } from 'utils'; import { saveInvoke, compose, optionsMapToArray } from 'utils';
/** /**
* payment receive number dialog's content. * payment receive number dialog's content.
@@ -20,31 +19,28 @@ function PaymentNumberDialogContent({
nextNumber, nextNumber,
numberPrefix, numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions // #withDialogActions
closeDialog, closeDialog,
// #withPaymentReceivesActions // #ownProps
// setPaymentReceiveNumberChanged, onConfirm,
}) { }) {
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({})); const { isLoading: isSettingsLoading } = useSettingsPaymentReceives();
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
const handleSubmitForm = (values, { setSubmitting }) => { const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => { const options = optionsMapToArray(values).map((option) => ({
return { key: option.key, ...option, group: 'payment_receives' }; key: option.key,
}); ...option,
group: 'payment_receives',
}));
requestSubmitOptions({ options }) saveSettingsMutate({ options })
.then(() => { .then(() => {
setSubmitting(false); setSubmitting(false);
closeDialog('payment-receive-number-form'); closeDialog('payment-receive-number-form');
setTimeout(() => { saveInvoke(onConfirm, values);
// setPaymentReceiveNumberChanged(true);
}, 250);
}) })
.catch(() => { .catch(() => {
setSubmitting(false); setSubmitting(false);
@@ -55,9 +51,8 @@ function PaymentNumberDialogContent({
closeDialog('payment-receive-number-form'); closeDialog('payment-receive-number-form');
}, [closeDialog]); }, [closeDialog]);
return ( return (
<DialogContent isLoading={fetchSettings.isFetching}> <DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm <ReferenceNumberForm
initialNumber={nextNumber} initialNumber={nextNumber}
initialPrefix={numberPrefix} initialPrefix={numberPrefix}
@@ -75,5 +70,4 @@ export default compose(
nextNumber: paymentReceiveSettings?.nextNumber, nextNumber: paymentReceiveSettings?.nextNumber,
numberPrefix: paymentReceiveSettings?.numberPrefix, numberPrefix: paymentReceiveSettings?.numberPrefix,
})), })),
// withPaymentReceivesActions,
)(PaymentNumberDialogContent); )(PaymentNumberDialogContent);

View File

@@ -2,16 +2,20 @@ import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components'; import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect'; import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils'; import { saveInvoke, compose } from 'utils';
const PaymentReceiveNumbereDialogConetnet = lazy(() => const PaymentReceiveNumbereDialogConetnet = lazy(() =>
import('./PaymentReceiveNumberDialogContent'), import('./PaymentReceiveNumberDialogContent'),
); );
/**
* Payment receive number dialog.
*/
function PaymentReceiveNumberDialog({ function PaymentReceiveNumberDialog({
dialogName, dialogName,
payload = { id: null }, payload = { id: null },
isOpen, isOpen,
onConfirm
}) { }) {
return ( return (
<Dialog <Dialog
@@ -24,6 +28,7 @@ function PaymentReceiveNumberDialog({
<DialogSuspense> <DialogSuspense>
<PaymentReceiveNumbereDialogConetnet <PaymentReceiveNumbereDialogConetnet
paymentReceiveNumberId={payload.id} paymentReceiveNumberId={payload.id}
onConfirm={(values) => saveInvoke(onConfirm, values)}
/> />
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>

View File

@@ -1,49 +1,45 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { DialogContent } from 'components'; import { DialogContent } from 'components';
import { useQuery } from 'react-query';
import { useSettingsReceipts, useSaveSettings } from 'hooks/query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm'; import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import { compose, optionsMapToArray } from 'utils'; import { compose, optionsMapToArray, saveInvoke } from 'utils';
/** /**
* Receipt number dialog's content. * Receipt number dialog's content.
*/ */
function ReceiptNumberDialogContent({ function ReceiptNumberDialogContent({
// #ownProps
receiptId,
onConfirm,
// #withSettings // #withSettings
nextNumber, nextNumber,
numberPrefix, numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions // #withDialogActions
closeDialog, closeDialog,
// #withReceiptActions
setReceiptNumberChanged,
}) { }) {
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({})); const { isLoading: isSettingsLoading } = useSettingsReceipts();
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
const handleSubmitForm = (values, { setSubmitting }) => { const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => { const options = optionsMapToArray(values).map((option) => ({
return { key: option.key, ...option, group: 'sales_receipts' }; key: option.key,
}); ...option,
group: 'sales_receipts',
}));
requestSubmitOptions({ options }) saveSettingsMutate({ options })
.then(() => { .then(() => {
setSubmitting(false); setSubmitting(false);
closeDialog('receipt-number-form'); closeDialog('receipt-number-form');
saveInvoke(onConfirm, values)
setTimeout(() => {
setReceiptNumberChanged(true);
}, 250);
}) })
.catch(() => { .catch(() => {
setSubmitting(false); setSubmitting(false);
@@ -55,7 +51,7 @@ function ReceiptNumberDialogContent({
}, [closeDialog]); }, [closeDialog]);
return ( return (
<DialogContent isLoading={fetchSettings.isFetching}> <DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm <ReferenceNumberForm
initialNumber={nextNumber} initialNumber={nextNumber}
initialPrefix={numberPrefix} initialPrefix={numberPrefix}
@@ -68,7 +64,6 @@ function ReceiptNumberDialogContent({
export default compose( export default compose(
withDialogActions, withDialogActions,
withSettingsActions,
withSettings(({ receiptSettings }) => ({ withSettings(({ receiptSettings }) => ({
nextNumber: receiptSettings?.nextNumber, nextNumber: receiptSettings?.nextNumber,
numberPrefix: receiptSettings?.numberPrefix, numberPrefix: receiptSettings?.numberPrefix,

View File

@@ -2,13 +2,25 @@ import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components'; import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect'; import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils'; import { compose, saveInvoke } from 'utils';
const ReceiptNumberDialogContent = lazy(() => const ReceiptNumberDialogContent = lazy(() =>
import('./ReceiptNumberDialogContent'), import('./ReceiptNumberDialogContent'),
); );
function ReceiptNumberDialog({ dialogName, paylaod = { id: null }, isOpen }) { /**
* Sale receipt number dialog.
*/
function ReceiptNumberDialog({
dialogName,
paylaod = { id: null },
isOpen,
onConfirm,
}) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values);
};
return ( return (
<Dialog <Dialog
name={dialogName} name={dialogName}
@@ -18,7 +30,10 @@ function ReceiptNumberDialog({ dialogName, paylaod = { id: null }, isOpen }) {
isOpen={isOpen} isOpen={isOpen}
> >
<DialogSuspense> <DialogSuspense>
<ReceiptNumberDialogContent ReceiptNumberId={paylaod.id} /> <ReceiptNumberDialogContent
receiptId={paylaod.id}
onConfirm={handleConfirm}
/>
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>
); );

View File

@@ -1,27 +1,25 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as T, useIntl } from 'react-intl';
import classNames from 'classnames';
import { shortcutBox } from 'common/homepageOptions'; import { shortcutBox } from 'common/homepageOptions';
import { Icon } from 'components'; import { Icon } from 'components';
function ShortcutBox({ title, iconColor, description }) { function ShortcutBox({ title, iconColor, description }) {
return ( return (
<div className={'shortcut-box'}> <div className={'shortcut-box'}>
<div className={'shortcut-box__header'}> <a href={'#'}>
<span <div className={'shortcut-box__header'}>
className={'header--icon'} <span
style={{ backgroundColor: `${iconColor}` }} className={'header--icon'}
> style={{ backgroundColor: `${iconColor}` }}
<Icon icon={'clock'} iconSize={24} /> >
</span> <Icon icon={'clock'} iconSize={24} />
<span> </span>
<a href={'#'}> <span>
<Icon icon={'arrow-top-right'} iconSize={24} /> <Icon icon={'arrow-top-right'} iconSize={24} />
</a> </span>
</span> </div>
</div> <div className={'shortcut-box__title'}>{title}</div>
<div className={'shortcut-box__title'}>{title}</div> <div className={'shortcut-box__description'}>{description}</div>
<div className={'shortcut-box__description'}>{description}</div> </a>
</div> </div>
); );
} }

View File

@@ -8,7 +8,7 @@ import {
Position, Position,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import { ErrorMessage, FastField, useFormikContext } from 'formik'; import { ErrorMessage, FastField } from 'formik';
import { import {
CategoriesSelectList, CategoriesSelectList,
Hint, Hint,
@@ -26,13 +26,11 @@ import { handleStringChange, inputIntent } from 'utils';
* Item form primary section. * Item form primary section.
*/ */
export default function ItemFormPrimarySection() { export default function ItemFormPrimarySection() {
const { itemsCategories } = useItemFormContext(); // Item form context.
const { isNewMode, item, itemsCategories } = useItemFormContext();
const nameFieldRef = useRef(null); const nameFieldRef = useRef(null);
// Formik context.
const { values: { type } } = useFormikContext();
useEffect(() => { useEffect(() => {
// Auto focus item name field once component mount. // Auto focus item name field once component mount.
if (nameFieldRef.current) { if (nameFieldRef.current) {
@@ -87,7 +85,7 @@ export default function ItemFormPrimarySection() {
form.setFieldValue('type', _value); form.setFieldValue('type', _value);
})} })}
selectedValue={value} selectedValue={value}
disabled={type === 'inventory'} disabled={!isNewMode && item.type === 'inventory'}
> >
<Radio label={<T id={'service'} />} value="service" /> <Radio label={<T id={'service'} />} value="service" />
<Radio label={<T id={'non_inventory'} />} value="non-inventory" /> <Radio label={<T id={'non_inventory'} />} value="non-inventory" />

View File

@@ -58,9 +58,8 @@ export default function ReferenceNumberForm({
tincidunt porta quam, tincidunt porta quam,
</p> </p>
<Row> <Row>
{/* prefix */} {/* ------------- Prefix ------------- */}
<Col> <Col xs={6}>
<FormGroup <FormGroup
label={<T id={'prefix'} />} label={<T id={'prefix'} />}
className={'form-group--'} className={'form-group--'}
@@ -75,8 +74,9 @@ export default function ReferenceNumberForm({
/> />
</FormGroup> </FormGroup>
</Col> </Col>
{/* next_number */}
<Col> {/* ------------- Next number ------------- */}
<Col xs={6}>
<FormGroup <FormGroup
label={<T id={'next_number'} />} label={<T id={'next_number'} />}
className={'form-group--'} className={'form-group--'}

View File

@@ -16,6 +16,7 @@ import EstimateFormHeader from './EstimateFormHeader';
import EstimateItemsEntriesField from './EstimateItemsEntriesField'; import EstimateItemsEntriesField from './EstimateItemsEntriesField';
import EstimateFloatingActions from './EstimateFloatingActions'; import EstimateFloatingActions from './EstimateFloatingActions';
import EstimateFormFooter from './EstimateFormFooter'; import EstimateFormFooter from './EstimateFormFooter';
import EstimateFormDialogs from './EstimateFormDialogs';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
@@ -158,12 +159,11 @@ function EstimateForm({
> >
<Form> <Form>
<EstimateFormHeader /> <EstimateFormHeader />
<EstimateItemsEntriesField />
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
<EstimateItemsEntriesField />
</div>
<EstimateFormFooter /> <EstimateFormFooter />
<EstimateFloatingActions /> <EstimateFloatingActions />
<EstimateFormDialogs />
</Form> </Form>
</Formik> </Formik>
</div> </div>

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { useFormikContext } from 'formik';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import { transactionNumber } from 'utils';
/**
* Estimate form dialogs.
*/
export default function EstimateFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleEstimateNumberFormConfirm = (values) => {
setFieldValue(
'estimate_number',
transactionNumber(values.number_prefix, values.next_number),
);
};
return (
<>
<EstimateNumberDialog
dialogName={'estimate-number-form'}
onConfirm={handleEstimateNumberFormConfirm}
/>
</>
);
}

View File

@@ -32,7 +32,7 @@ function EstimateFormHeader({
}) { }) {
const { customers } = useEstimateFormContext(); const { customers } = useEstimateFormContext();
const handleEstimateNumberChange = () => { const handleEstimateNumberBtnClick = () => {
openDialog('estimate-number-form', {}); openDialog('estimate-number-form', {});
}; };
@@ -135,7 +135,7 @@ function EstimateFormHeader({
/> />
<InputPrependButton <InputPrependButton
buttonProps={{ buttonProps={{
onClick: handleEstimateNumberChange, onClick: handleEstimateNumberBtnClick,
icon: <Icon icon={'settings-18'} />, icon: <Icon icon={'settings-18'} />,
}} }}
tooltip={true} tooltip={true}

View File

@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { FastField } from 'formik'; import { FastField } from 'formik';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable'; import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
import { useEstimateFormContext } from './EstimateFormProvider'; import { useEstimateFormContext } from './EstimateFormProvider';
@@ -10,18 +12,20 @@ export default function EstimateFormItemsEntriesField() {
const { items } = useEstimateFormContext(); const { items } = useEstimateFormContext();
return ( return (
<FastField name={'entries'}> <div className={classNames(CLASSES.PAGE_FORM_BODY)}>
{({ form, field: { value }, meta: { error, touched } }) => ( <FastField name={'entries'}>
<ItemsEntriesTable {({ form, field: { value }, meta: { error, touched } }) => (
entries={value} <ItemsEntriesTable
onUpdateData={(entries) => { entries={value}
form.setFieldValue('entries', entries); onUpdateData={(entries) => {
}} form.setFieldValue('entries', entries);
items={items} }}
errors={error} items={items}
linesNumber={4} errors={error}
/> linesNumber={4}
)} />
</FastField> )}
</FastField>
</div>
); );
} }

View File

@@ -15,6 +15,7 @@ import InvoiceFormHeader from './InvoiceFormHeader';
import InvoiceItemsEntriesEditorField from './InvoiceItemsEntriesEditorField'; import InvoiceItemsEntriesEditorField from './InvoiceItemsEntriesEditorField';
import InvoiceFloatingActions from './InvoiceFloatingActions'; import InvoiceFloatingActions from './InvoiceFloatingActions';
import InvoiceFormFooter from './InvoiceFormFooter'; import InvoiceFormFooter from './InvoiceFormFooter';
import InvoiceFormDialogs from './InvoiceFormDialogs';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
@@ -159,6 +160,7 @@ function InvoiceForm({
</div> </div>
<InvoiceFormFooter /> <InvoiceFormFooter />
<InvoiceFloatingActions /> <InvoiceFloatingActions />
<InvoiceFormDialogs />
</Form> </Form>
</Formik> </Formik>
</div> </div>

View File

@@ -0,0 +1,27 @@
import React from 'react';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
import { useFormikContext } from 'formik';
import { transactionNumber } from 'utils';
/**
* Invoice form dialogs.
*/
export default function InvoiceFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleInvoiceNumberFormConfirm = (values) => {
setFieldValue(
'invoice_no',
transactionNumber(values.number_prefix, values.next_number),
);
};
return (
<>
<InvoiceNumberDialog
dialogName={'invoice-number-form'}
onConfirm={handleInvoiceNumberFormConfirm}
/>
</>
);
}

View File

@@ -6,6 +6,7 @@ import {
useCustomers, useCustomers,
useCreateInvoice, useCreateInvoice,
useEditInvoice, useEditInvoice,
useSettingsInvoices,
} from 'hooks/query'; } from 'hooks/query';
const InvoiceFormContext = createContext(); const InvoiceFormContext = createContext();
@@ -14,7 +15,7 @@ const InvoiceFormContext = createContext();
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function InvoiceFormProvider({ invoiceId, ...props }) { function InvoiceFormProvider({ invoiceId, ...props }) {
const { data: invoice, isFetching: isInvoiceLoading } = useInvoice( const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(
invoiceId, invoiceId,
{ {
enabled: !!invoiceId, enabled: !!invoiceId,
@@ -24,21 +25,24 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
// Handle fetching the items table based on the given query. // Handle fetching the items table based on the given query.
const { const {
data: { items }, data: { items },
isFetching: isItemsLoading, isLoading: isItemsLoading,
} = useItems(); } = useItems();
// Handle fetch customers data table or list // Handle fetch customers data table or list
const { const {
data: { customers }, data: { customers },
isFetching: isCustomersLoading, isLoading: isCustomersLoading,
} = useCustomers(); } = useCustomers();
// Handle fetching settings.
const { isLoading: isSettingsLoading } = useSettingsInvoices();
// Create and edit invoice mutations. // Create and edit invoice mutations.
const { mutateAsync: createInvoiceMutate } = useCreateInvoice(); const { mutateAsync: createInvoiceMutate } = useCreateInvoice();
const { mutateAsync: editInvoiceMutate } = useEditInvoice(); const { mutateAsync: editInvoiceMutate } = useEditInvoice();
// Form submit payload. // Form submit payload.
const [submitPayload, setSubmitPayload] = useState({}); const [submitPayload, setSubmitPayload] = useState();
// Detarmines whether the form in new mode. // Detarmines whether the form in new mode.
const isNewMode = !invoiceId; const isNewMode = !invoiceId;
@@ -53,16 +57,22 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
isInvoiceLoading, isInvoiceLoading,
isItemsLoading, isItemsLoading,
isCustomersLoading, isCustomersLoading,
isSettingsLoading,
createInvoiceMutate, createInvoiceMutate,
editInvoiceMutate, editInvoiceMutate,
setSubmitPayload, setSubmitPayload,
isNewMode isNewMode,
}; };
return ( return (
<DashboardInsider <DashboardInsider
loading={isInvoiceLoading || isItemsLoading || isCustomersLoading} loading={
isInvoiceLoading ||
isItemsLoading ||
isCustomersLoading ||
isSettingsLoading
}
name={'invoice-form'} name={'invoice-form'}
> >
<InvoiceFormContext.Provider value={provider} {...props} /> <InvoiceFormContext.Provider value={provider} {...props} />

View File

@@ -12,6 +12,7 @@ import PaymentReceiveFormBody from './PaymentReceiveFormBody';
import PaymentReceiveFloatingActions from './PaymentReceiveFloatingActions'; import PaymentReceiveFloatingActions from './PaymentReceiveFloatingActions';
import PaymentReceiveFormFooter from './PaymentReceiveFormFooter'; import PaymentReceiveFormFooter from './PaymentReceiveFormFooter';
import PaymentReceiveFormAlerts from './PaymentReceiveFormAlerts'; import PaymentReceiveFormAlerts from './PaymentReceiveFormAlerts';
import PaymentReceiveFormDialogs from './PaymentReceiveFormDialogs';
import { PaymentReceiveInnerProvider } from './PaymentReceiveInnerProvider'; import { PaymentReceiveInnerProvider } from './PaymentReceiveInnerProvider';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
@@ -164,7 +165,9 @@ function PaymentReceiveForm({
<PaymentReceiveFormFooter /> <PaymentReceiveFormFooter />
<PaymentReceiveFloatingActions /> <PaymentReceiveFloatingActions />
{/* Alerts & Dialogs */}
<PaymentReceiveFormAlerts /> <PaymentReceiveFormAlerts />
<PaymentReceiveFormDialogs />
</PaymentReceiveInnerProvider> </PaymentReceiveInnerProvider>
</Form> </Form>
</Formik> </Formik>

View File

@@ -0,0 +1,27 @@
import React from 'react';
import { useFormikContext } from 'formik';
import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberDialog';
import { transactionNumber } from 'utils';
/**
* Payment receive form dialogs.
*/
export default function PaymentReceiveFormDialogs() {
const { setFieldValue } = useFormikContext();
const handleUpdatePaymentNumber = (values) => {
setFieldValue(
'payment_receive_no',
transactionNumber(values.number_prefix, values.next_number),
);
};
return (
<>
<PaymentReceiveNumberDialog
dialogName={'payment-receive-number-form'}
onConfirm={handleUpdatePaymentNumber}
/>
</>
);
}

View File

@@ -32,7 +32,7 @@ import {
Money, Money,
} from 'components'; } from 'components';
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider'; import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import { amountPaymentEntries, fullAmountPaymentEntries } from './utils'; import { amountPaymentEntries, fullAmountPaymentEntries } from './utils';
@@ -41,7 +41,12 @@ import { toSafeInteger } from 'lodash';
/** /**
* Payment receive header fields. * Payment receive header fields.
*/ */
function PaymentReceiveHeaderFields({ baseCurrency }) { function PaymentReceiveHeaderFields({
baseCurrency,
// #withDialogActions
openDialog,
}) {
// Payment receive form context. // Payment receive form context.
const { customers, accounts, isNewMode } = usePaymentReceiveFormContext(); const { customers, accounts, isNewMode } = usePaymentReceiveFormContext();
@@ -73,6 +78,12 @@ function PaymentReceiveHeaderFields({ baseCurrency }) {
setFieldValue('entries', newEntries); setFieldValue('entries', newEntries);
}; };
// Handle click open payment receive number dialog.
const handleClickOpenDialog = () => {
openDialog('payment-receive-number-form')
};
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------------- Customer name ------------- */} {/* ------------- Customer name ------------- */}
@@ -185,7 +196,7 @@ function PaymentReceiveHeaderFields({ baseCurrency }) {
/> />
<InputPrependButton <InputPrependButton
buttonProps={{ buttonProps={{
// onClick: handlePaymentReceiveNumberChange, onClick: handleClickOpenDialog,
icon: <Icon icon={'settings-18'} />, icon: <Icon icon={'settings-18'} />,
}} }}
tooltip={true} tooltip={true}
@@ -253,4 +264,5 @@ export default compose(
withSettings(({ organizationSettings }) => ({ withSettings(({ organizationSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency, baseCurrency: organizationSettings?.baseCurrency,
})), })),
withDialogActions
)(PaymentReceiveHeaderFields); )(PaymentReceiveHeaderFields);

View File

@@ -21,6 +21,7 @@ import ReceiptFromHeader from './ReceiptFormHeader';
import ReceiptItemsEntriesEditor from './ReceiptItemsEntriesEditor'; import ReceiptItemsEntriesEditor from './ReceiptItemsEntriesEditor';
import ReceiptFormFloatingActions from './ReceiptFormFloatingActions'; import ReceiptFormFloatingActions from './ReceiptFormFloatingActions';
import ReceiptFormFooter from './ReceiptFormFooter'; import ReceiptFormFooter from './ReceiptFormFooter';
import ReceiptFormDialogs from './ReceiptFormDialogs';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
@@ -170,6 +171,8 @@ function ReceiptForm({
<ReceiptItemsEntriesEditor /> <ReceiptItemsEntriesEditor />
<ReceiptFormFooter /> <ReceiptFormFooter />
<ReceiptFormFloatingActions /> <ReceiptFormFloatingActions />
<ReceiptFormDialogs />
</Form> </Form>
</Formik> </Formik>
</div> </div>

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { useFormikContext } from 'formik';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import { transactionNumber } from 'utils';
/**
* Receipt form dialogs.
*/
export default function ReceiptFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the receipt number form submit confirm.
const handleReceiptNumberFormConfirm = (values) => {
setFieldValue(
'receipt_number',
transactionNumber(values.number_prefix, values.next_number),
);
};
return (
<>
<ReceiptNumberDialog
dialogName={'receipt-number-form'}
onConfirm={handleReceiptNumberFormConfirm}
/>
</>
);
}

View File

@@ -39,7 +39,7 @@ function ReceiptFormProvider({ receiptId, ...props }) {
} = useItems(); } = useItems();
// Fetch receipt settings. // Fetch receipt settings.
const { isFetching: isSettingLoading } = useSettings(); const { isLoading: isSettingLoading } = useSettings();
const { mutateAsync: createReceiptMutate } = useCreateReceipt(); const { mutateAsync: createReceiptMutate } = useCreateReceipt();
const { mutateAsync: editReceiptMutate } = useEditReceipt(); const { mutateAsync: editReceiptMutate } = useEditReceipt();

View File

@@ -11,9 +11,11 @@ export function useCreateBill(props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('purchases/bills', values), { return useMutation((values) => apiRequest.post('purchases/bills', values), {
onSuccess: () => { onSuccess: (res, values) => {
queryClient.invalidateQueries('BILLS'); queryClient.invalidateQueries('BILLS');
queryClient.invalidateQueries('BILL'); queryClient.invalidateQueries('BILL');
queryClient.invalidateQueries(['VENDORS']);
queryClient.invalidateQueries(['VENDOR', values.vendor_id]);
}, },
...props, ...props,
}); });
@@ -29,9 +31,11 @@ export function useEditBill(props) {
return useMutation( return useMutation(
([id, values]) => apiRequest.post(`purchases/bills/${id}`, values), ([id, values]) => apiRequest.post(`purchases/bills/${id}`, values),
{ {
onSuccess: () => { onSuccess: (res, [id, values]) => {
queryClient.invalidateQueries('BILLS'); queryClient.invalidateQueries('BILLS');
queryClient.invalidateQueries('BILL'); queryClient.invalidateQueries('BILL');
queryClient.invalidateQueries(['VENDORS']);
queryClient.invalidateQueries(['VENDOR', values.vendor_id]);
}, },
...props, ...props,
}, },
@@ -46,9 +50,10 @@ export function useDeleteBill(props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`purchases/bills/${id}`), { return useMutation((id) => apiRequest.delete(`purchases/bills/${id}`), {
onSuccess: () => { onSuccess: (res, id) => {
queryClient.invalidateQueries('BILLS'); queryClient.invalidateQueries('BILLS');
queryClient.invalidateQueries('BILL'); queryClient.invalidateQueries('BILL');
queryClient.invalidateQueries(['VENDORS']);
}, },
...props, ...props,
}); });
@@ -122,6 +127,7 @@ export function useOpenBill(props) {
{ {
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries('BILLS'); queryClient.invalidateQueries('BILLS');
queryClient.invalidateQueries(['VENDORS']);
}, },
...props, ...props,
}, },

View File

@@ -13,6 +13,7 @@ export function useCreateEstimate(props) {
return useMutation((values) => apiRequest.post('sales/estimates', values), { return useMutation((values) => apiRequest.post('sales/estimates', values), {
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries('SALE_ESTIMATES'); queryClient.invalidateQueries('SALE_ESTIMATES');
queryClient.invalidateQueries(['SETTINGS', 'ESTIMATES']);
}, },
...props, ...props,
}); });

View File

@@ -10,7 +10,7 @@ export const useAuthInviteAccept = (props) => {
return useMutation( return useMutation(
([values, token]) => apiRequest.post(`invite/accept/${token}`, values), ([values, token]) => apiRequest.post(`invite/accept/${token}`, values),
props, props,
) );
} }
/** /**

View File

@@ -11,8 +11,11 @@ export function useCreateInvoice(props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('sales/invoices', values), { return useMutation((values) => apiRequest.post('sales/invoices', values), {
onSuccess: () => { onSuccess: (values) => {
queryClient.invalidateQueries('SALE_INVOICES'); queryClient.invalidateQueries('SALE_INVOICES');
queryClient.invalidateQueries(['SETTINGS', 'INVOICES']);
queryClient.invalidateQueries('CUSTOMERS');
queryClient.invalidateQueries(['CUSTOMER', values.customer_id]);
}, },
...props, ...props,
}); });
@@ -28,9 +31,11 @@ export function useEditInvoice(props) {
return useMutation( return useMutation(
([id, values]) => apiRequest.post(`sales/invoices/${id}`, values), ([id, values]) => apiRequest.post(`sales/invoices/${id}`, values),
{ {
onSuccess: (res, id) => { onSuccess: (res, [id, values]) => {
queryClient.invalidateQueries('SALE_INVOICES'); queryClient.invalidateQueries('SALE_INVOICES');
queryClient.invalidateQueries(['SALE_INVOICE', id]); queryClient.invalidateQueries(['SALE_INVOICE', id]);
queryClient.invalidateQueries('CUSTOMERS');
queryClient.invalidateQueries(['CUSTOMER', values.customer_id]);
}, },
...props, ...props,
}, },
@@ -48,6 +53,7 @@ export function useDeleteInvoice(props) {
onSuccess: (res, id) => { onSuccess: (res, id) => {
queryClient.invalidateQueries('SALE_INVOICES'); queryClient.invalidateQueries('SALE_INVOICES');
queryClient.invalidateQueries(['SALE_INVOICE', id]); queryClient.invalidateQueries(['SALE_INVOICE', id]);
queryClient.invalidateQueries('CUSTOMERS');
}, },
...props, ...props,
}); });
@@ -97,6 +103,7 @@ export function useDeliverInvoice(props) {
onSuccess: (res, id) => { onSuccess: (res, id) => {
queryClient.invalidateQueries('SALE_INVOICES'); queryClient.invalidateQueries('SALE_INVOICES');
queryClient.invalidateQueries(['SALE_INVOICE', id]); queryClient.invalidateQueries(['SALE_INVOICE', id]);
queryClient.invalidateQueries('CUSTOMERS');
}, },
...props, ...props,
}); });

View File

@@ -3,34 +3,6 @@ import { useDispatch } from 'react-redux';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import t from 'store/types'; import t from 'store/types';
/**
* Retrieve settings.
*/
export function useSettings(query, props) {
const dispatch = useDispatch();
const apiRequest = useApiRequest();
const settings = useQuery(
['SETTINGS', query],
async () => {
const {
data: { settings },
} = await apiRequest.get('settings', { params: query });
return settings;
},
{
initialData: [],
...props,
},
);
dispatch({
type: t.SETTING_SET,
options: settings.data,
});
return settings;
}
/** /**
* Saves the settings. * Saves the settings.
*/ */
@@ -45,3 +17,90 @@ export function useSaveSettings(props) {
...props, ...props,
}); });
} }
function useSettingsQuery(key, query, props) {
const dispatch = useDispatch();
const apiRequest = useApiRequest();
return useQuery(
key,
() => apiRequest.get('settings', { params: query }),
{
select: (res) => res.data.settings,
initialDataUpdatedAt: 0,
initialData: {
data: {
settings: [],
},
},
onSuccess: (settings) => {
dispatch({ type: t.SETTING_SET, options: settings });
},
...props,
},
);
}
/**
* Retrieve the all settings of the organization.
*/
export function useSettings() {
return useSettingsQuery(['SETTINGS', 'ALL'], {});
}
/**
* Retrieve invoices settings.
*/
export function useSettingsInvoices(props) {
return useSettingsQuery(
['SETTINGS', 'INVOICES'],
{ group: 'sale_invoices' },
props,
);
}
/**
* Retrieve invoices settings.
*/
export function useSettingsEstimates(props) {
return useSettingsQuery(
['SETTINGS', 'ESTIMATES'],
{ group: 'sale_estimates' },
props,
);
}
/**
* Retrieve payment receives settings.
*/
export function useSettingsPaymentReceives(props) {
return useSettingsQuery(
['SETTINGS', 'PAYMENT_RECEIVES'],
{ group: 'payment_receives' },
props,
);
}
/**
* Retrieve sale receipts settings.
* @param {*} props
*/
export function useSettingsReceipts(props) {
return useSettingsQuery(
['SETTINGS', 'RECEIPTS'],
{ group: 'sale_receipts' },
props,
);
}
/**
* Retrieve sale receipts settings.
* @param {*} props
*/
export function useSettingsManualJournals(props) {
return useSettingsQuery(
['SETTINGS', 'MANUAL_JOURNALS'],
{ group: 'sale_receipts' },
props,
);
}

View File

@@ -1,9 +1,10 @@
.homepage { .homepage {
&__container { &__container {
display: flex; display: flex;
height: 100%;
margin: 22px 32px; margin: 22px 32px;
background-color: transparent; background-color: transparent;
align-items: flex-start;
.shortcut-boxes { .shortcut-boxes {
flex: 2; flex: 2;
@@ -12,23 +13,27 @@
background-color: #fff; background-color: #fff;
border-bottom: 1px solid #d2dce2; border-bottom: 1px solid #d2dce2;
border-right: 1px solid #d2dce2; border-right: 1px solid #d2dce2;
max-width: 800px;
.shortcut-box { .shortcut-box {
width: 50%; width: 50%;
// height: 174px;
padding: 16px; padding: 16px;
border-left: 1px solid #d2dce2; border-left: 1px solid #d2dce2;
border-top: 1px solid #d2dce2; border-top: 1px solid #d2dce2;
background-color: transparent; background-color: transparent;
transition: 0.2s; transition: 0.2s;
a{
text-decoration: none;
}
&__header { &__header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 14px; margin-bottom: 14px;
span > a { span {
color: #d6d6e0; color: #d6d6e0;
} }
.header--icon { .header--icon {
@@ -62,7 +67,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-bottom: 32px; padding-bottom: 32px;
width: 100%; max-width: 400px;
&__title { &__title {
font-size: 16px; font-size: 16px;

View File

@@ -34,7 +34,7 @@ $sidebar-width: 100%;
$sidebar-menu-item-color: rgb(255, 255, 255); $sidebar-menu-item-color: rgb(255, 255, 255);
$sidebar-menu-item-color-active: rgb(255, 255, 255); $sidebar-menu-item-color-active: rgb(255, 255, 255);
$sidebar-popover-submenu-bg: rgb(1, 20, 62); $sidebar-popover-submenu-bg: rgb(1, 20, 62);
$sidebar-menu-label-color: rgba(255, 255, 255, 0.45); $sidebar-menu-label-color: rgba(255, 255, 255, 0.5);
$sidebar-submenu-item-color: rgba(255, 255, 255, 0.85); $sidebar-submenu-item-color: rgba(255, 255, 255, 0.85);
$sidebar-submenu-item-hover-color: rgb(255, 255, 255); $sidebar-submenu-item-hover-color: rgb(255, 255, 255);
$sidebar-logo-opacity: 0.5; $sidebar-logo-opacity: 0.5;