diff --git a/client/src/components/ContactSelecetList.js b/client/src/components/ContactSelecetList.js index baa4b2a20..ed10398c2 100644 --- a/client/src/components/ContactSelecetList.js +++ b/client/src/components/ContactSelecetList.js @@ -1,42 +1,47 @@ import React, { useCallback, useState, useEffect, useMemo } from 'react'; import { FormattedMessage as T } from 'react-intl'; -import { ListSelect } from 'components'; -import { MenuItem } from '@blueprintjs/core'; +import { MenuItem, Button } from '@blueprintjs/core'; +import { Select } from '@blueprintjs/select'; import classNames from 'classnames'; import { CLASSES } from 'common/classes'; export default function ContactSelecetList({ contactsList, + initialContactId, selectedContactId, + selectedContactType, defaultSelectText = , onContactSelected, popoverFill = false, - ...restProps + disabled = false, }) { - const [selecetedContact, setSelectedContact] = useState(null); - - // Filter Contact List - const FilterContacts = (query, contact, index, exactMatch) => { - const normalizedTitle = contact.display_name.toLowerCase(); - const normalizedQuery = query.toLowerCase(); - if (exactMatch) { - return normalizedTitle === normalizedQuery; - } else { - return ( - `${contact.display_name} ${normalizedTitle}`.indexOf(normalizedQuery) >= - 0 - ); - } - }; - - const onContactSelect = useCallback( - (contact) => { - setSelectedContact({ ...contact }); - onContactSelected && onContactSelected(contact); - }, - [setSelectedContact, onContactSelected], + const contacts = useMemo( + () => + contactsList.map((contact) => ({ + ...contact, + _id: `${contact.id}_${contact.contact_type}`, + })), + [contactsList], ); + const initialContact = useMemo( + () => contacts.find((a) => a.id === initialContactId), + [initialContactId, contacts], + ); + + const [selecetedContact, setSelectedContact] = useState( + initialContact || null, + ); + + useEffect(() => { + if (typeof selectedContactId !== 'undefined') { + const account = selectedContactId + ? contacts.find((a) => a.id === selectedContactId) + : null; + setSelectedContact(account); + } + }, [selectedContactId, contacts, setSelectedContact]); + const handleContactRenderer = useCallback( (contact, { handleClick }) => ( { + setSelectedContact({ ...contact }); + onContactSelected && onContactSelected(contact); + }, + [setSelectedContact, onContactSelected], + ); + + // Filter Contact List + const filterContacts = (query, contact, index, exactMatch) => { + const normalizedTitle = contact.display_name.toLowerCase(); + const normalizedQuery = query.toLowerCase(); + if (exactMatch) { + return normalizedTitle === normalizedQuery; + } else { + return ( + `${contact.display_name} ${normalizedTitle}`.indexOf(normalizedQuery) >= + 0 + ); + } + }; + return ( - } itemRenderer={handleContactRenderer} + itemPredicate={filterContacts} + filterable={true} + disabled={disabled} + onItemSelect={onContactSelect} popoverProps={{ minimal: true, usePortal: !popoverFill }} className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, { [CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill, })} - {...restProps} - /> + > + - - +
+ {/* ----------- Save And Publish ----------- */} + + + - + onClick={handleClearBtnClick} + text={billId ? : } + /> + {/* ----------- Cancel ----------- */} + onClick={handleCancelBtnClick} + text={} + />
); } diff --git a/client/src/containers/Purchases/Bill/BillForm.js b/client/src/containers/Purchases/Bill/BillForm.js index 6198f4eb8..1ea41fd59 100644 --- a/client/src/containers/Purchases/Bill/BillForm.js +++ b/client/src/containers/Purchases/Bill/BillForm.js @@ -46,6 +46,9 @@ const defaultInitialValues = { entries: [...repeatValue(defaultBill, MIN_LINES_NUMBER)], }; +/** + * Bill form. + */ function BillForm({ //#WithMedia requestSubmitMedia, @@ -75,12 +78,12 @@ function BillForm({ const isNewMode = !billId; useEffect(() => { - if (bill && bill.id) { + if (!isNewMode) { changePageTitle(formatMessage({ id: 'edit_bill' })); } else { changePageTitle(formatMessage({ id: 'new_bill' })); } - }, [changePageTitle, bill, formatMessage]); + }, [changePageTitle, isNewMode, formatMessage]); // Initial values in create and edit mode. const initialValues = useMemo( @@ -146,8 +149,8 @@ function BillForm({ message: formatMessage( { id: isNewMode - ? 'the_bill_has_been_successfully_created' - : 'the_bill_has_been_successfully_edited', + ? 'the_bill_has_been_successfully_created' : + 'the_bill_has_been_successfully_edited', }, { number: values.bill_number }, ), @@ -155,11 +158,13 @@ function BillForm({ }); setSubmitting(false); - resetForm(); changePageSubtitle(''); if (submitPayload.redirect) { - history.go('/bills'); + history.push('/bills'); + } + if (submitPayload.resetForm) { + resetForm(); } }; // Handle the request error. @@ -167,7 +172,7 @@ function BillForm({ handleErrors(errors, { setErrors }); setSubmitting(false); }; - if (isNewMode) { + if (bill && bill.id) { requestEditBill(bill.id, form).then(onSuccess).catch(onError); } else { requestSubmitBill(form).then(onSuccess).catch(onError); @@ -190,9 +195,12 @@ function BillForm({ [changePageSubtitle], ); - const handleSubmitClick = useCallback(() => { - setSubmitPayload({ redirect: true }); - }, [setSubmitPayload]); + const handleSubmitClick = useCallback( + (event, payload) => { + setSubmitPayload({ ...payload }); + }, + [setSubmitPayload], + ); const handleCancelClick = useCallback(() => { history.goBack(); @@ -209,7 +217,7 @@ function BillForm({ initialValues={initialValues} onSubmit={handleFormSubmit} > - {({ isSubmitting, values }) => ( + {({ isSubmitting }) => (
@@ -220,8 +228,9 @@ function BillForm({ )} diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeFloatingActions.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeFloatingActions.js index 8befdee8e..7b4363e14 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentMadeFloatingActions.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeFloatingActions.js @@ -1,9 +1,19 @@ import React from 'react'; -import { Intent, Button } from '@blueprintjs/core'; +import { + Intent, + Button, + ButtonGroup, + Popover, + PopoverInteractionKind, + Position, + Menu, + MenuItem, +} from '@blueprintjs/core'; import { FormattedMessage as T } from 'react-intl'; import classNames from 'classnames'; - import { CLASSES } from 'common/classes'; +import { saveInvoke } from 'utils'; +import { Icon } from 'components'; /** * Payment made floating actions bar. @@ -13,56 +23,85 @@ export default function PaymentMadeFloatingActions({ onSubmitClick, onCancelClick, onClearBtnClick, + onSubmitForm, + paymentMadeId, }) { + const handleSubmitBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + }); + }; + const handleClearBtnClick = (event) => { onClearBtnClick && onClearBtnClick(event); }; - const handleSubmitClick = (event) => { - onSubmitClick && onSubmitClick(event, { redirect: true }); - }; - - const handleCancelClick = (event) => { + const handleCancelBtnClick = (event) => { onCancelClick && onCancelClick(event); + saveInvoke(onCancelClick, event); }; + const handleSubmitAndNewClick = (event) => { + onSubmitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + }); + }; + + const handleSubmitContinueEditingBtnClick = (event) => { + onSubmitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + }); + }; return (
- - - - + {/* ----------- Save and New ----------- */} + + - + text={paymentMadeId ? : } + /> + {/* ----------- Cancel ----------- */} + onClick={handleCancelBtnClick} + text={} + />
); } diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.js index a2fcb6adb..a75a3a778 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeForm.js @@ -81,6 +81,7 @@ function PaymentMadeForm({ const [clearLinesAlert, setClearLinesAlert] = useState(false); const [clearFormAlert, setClearFormAlert] = useState(false); const [fullAmount, setFullAmount] = useState(null); + const [submitPayload, setSubmitPayload] = useState({}); const [localPaymentEntries, setLocalPaymentEntries] = useState( paymentMadeEntries, @@ -155,8 +156,13 @@ function PaymentMadeForm({ intent: Intent.SUCCESS, }); setSubmitting(false); - resetForm(); + // resetForm(); changePageSubtitle(''); + + if (submitPayload.redirect) { + history.push('/payment-mades'); + } + }; const onError = (errors) => { @@ -187,6 +193,7 @@ function PaymentMadeForm({ values, handleSubmit, isSubmitting, + submitForm, } = useFormik({ validationSchema, initialValues, @@ -300,6 +307,14 @@ function PaymentMadeForm({ [values.entries], ); + const handleSubmitClick = useCallback( + (event, payload) => { + setSubmitPayload({ ...payload }); + }, + [setSubmitPayload], + ); + + return (
{/* { - history.push(`/payment-made/${payment.id}/edit`); + history.push(`/payment-mades/${payment.id}/edit`); }); // Calculates the selected rows count. diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js b/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js index 781a804cd..8ed4582af 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js @@ -21,7 +21,7 @@ export default function PaymentMadesEmptyStatus() { intent={Intent.PRIMARY} large={true} onClick={() => { - history.push('/payment-made/new'); + history.push('/payment-mades/new'); }} > New bill payment diff --git a/client/src/containers/Sales/Estimate/EstimateFloatingActions.js b/client/src/containers/Sales/Estimate/EstimateFloatingActions.js index d56def74d..d6df854ff 100644 --- a/client/src/containers/Sales/Estimate/EstimateFloatingActions.js +++ b/client/src/containers/Sales/Estimate/EstimateFloatingActions.js @@ -14,7 +14,7 @@ import { CLASSES } from 'common/classes'; import classNames from 'classnames'; import { useFormikContext } from 'formik'; import { saveInvoke } from 'utils'; -import { Icon } from 'components'; +import { If, Icon } from 'components'; /** * Estimate floating actions bar. @@ -25,12 +25,55 @@ export default function EstimateFloatingActions({ onCancelClick, onClearClick, estimateId, + estimatePublished, }) { const { resetForm, submitForm } = useFormikContext(); - const handleSubmitBtnClick = (event) => { + const handleSubmitPublishBtnClick = (event) => { saveInvoke(onSubmitClick, event, { redirect: true, + publish: true + }); + }; + + const handleSubmitPublishAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + resetForm: true, + }); + }; + + const handleSubmitPublishContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + }); + }; + + const handleSubmitDraftBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + publish: false, + }); + }; + + const handleSubmitDraftAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, + resetForm: true, + }); + }; + + const handleSubmitDraftContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, }); }; @@ -43,56 +86,117 @@ export default function EstimateFloatingActions({ resetForm(); }; - const handleSubmitAndNewClick = (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - }); - }; - return (
- - {/* ----------- Save and New ----------- */} -
); } diff --git a/client/src/containers/Sales/Estimate/EstimateForm.js b/client/src/containers/Sales/Estimate/EstimateForm.js index efdce14bf..73818f69a 100644 --- a/client/src/containers/Sales/Estimate/EstimateForm.js +++ b/client/src/containers/Sales/Estimate/EstimateForm.js @@ -103,9 +103,9 @@ const EstimateForm = ({ : estimateNextNumber; useEffect(() => { - const transNumber = !isNewMode ? estimate.estimate_number : estimateNumber; + const transNumber = !isNewMode ? estimate.estimate_number : estimateNumber; - if (isNewMode) { + if (!isNewMode) { changePageTitle(formatMessage({ id: 'edit_estimate' })); } else { changePageTitle(formatMessage({ id: 'new_estimate' })); @@ -199,11 +199,13 @@ const EstimateForm = ({ intent: Intent.SUCCESS, }); setSubmitting(false); - resetForm(); if (submitPayload.redirect) { history.push('/estimates'); } + if (submitPayload.resetForm) { + resetForm(); + } }; const onError = (errors) => { @@ -267,8 +269,8 @@ const EstimateForm = ({ estimateId={estimateId} onSubmitClick={handleSubmitClick} onCancelClick={handleCancelClick} + estimatePublished={true} /> - )} diff --git a/client/src/containers/Sales/Estimate/EstimateForm.schema.js b/client/src/containers/Sales/Estimate/EstimateForm.schema.js index 4cecb3d3c..a7830d9cc 100644 --- a/client/src/containers/Sales/Estimate/EstimateForm.schema.js +++ b/client/src/containers/Sales/Estimate/EstimateForm.schema.js @@ -14,7 +14,6 @@ const Schema = Yup.object().shape({ .required() .label(formatMessage({ id: 'expiration_date_' })), estimate_number: Yup.string() - .nullable() .max(DATATYPES_LENGTH.STRING) .label(formatMessage({ id: 'estimate_number_' })), reference: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(), diff --git a/client/src/containers/Sales/Invoice/InvoiceFloatingActions.js b/client/src/containers/Sales/Invoice/InvoiceFloatingActions.js index 0004df237..7a50896e9 100644 --- a/client/src/containers/Sales/Invoice/InvoiceFloatingActions.js +++ b/client/src/containers/Sales/Invoice/InvoiceFloatingActions.js @@ -14,8 +14,7 @@ import { FormattedMessage as T } from 'react-intl'; import { CLASSES } from 'common/classes'; import classNames from 'classnames'; import { saveInvoke } from 'utils'; -import { Icon } from 'components'; - +import { If, Icon } from 'components'; /** * Invoice floating actions bar. @@ -26,151 +25,178 @@ export default function InvoiceFloatingActions({ onCancelClick, onClearClick, invoice, + invoicePublished, }) { const { resetForm, submitForm } = useFormikContext(); - const handleSubmitPublishAndNewBtnClick = useCallback( - (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: true, - resetForm: true, - }); - }, - [submitForm], - ); + const handleSubmitPublishBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + publish: true + }); + }; - const handleSubmitPublishContinueEditingBtnClick = useCallback( - (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: true, - }); - }, - [submitForm], - ); + const handleSubmitPublishAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + resetForm: true, + }); + }; - const handleSubmitDraftAndNewBtnClick = useCallback( - (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: false, - resetForm: true, - }); - }, - [submitForm], - ); + const handleSubmitPublishContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + }); + }; - const handleSubmitDraftContinueEditingBtnClick = useCallback( - (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: true, - }); - }, - [submitForm], - ); + const handleSubmitDraftBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + publish: false, + }); + }; + + const handleSubmitDraftAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, + resetForm: true, + }); + }; + + const handleSubmitDraftContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, + }); + }; + + const handleCancelBtnClick = (event) => { + saveInvoke(onCancelClick, event); + }; + + const handleClearBtnClick = (event) => { + // saveInvoke(onClearClick, event); + resetForm(); + }; return (
- - {/* ----------- Save And Publish ----------- */} -
); } diff --git a/client/src/containers/Sales/Invoice/InvoiceForm.js b/client/src/containers/Sales/Invoice/InvoiceForm.js index aa65e2cde..646f0f05f 100644 --- a/client/src/containers/Sales/Invoice/InvoiceForm.js +++ b/client/src/containers/Sales/Invoice/InvoiceForm.js @@ -186,7 +186,6 @@ function InvoiceForm({ intent: Intent.SUCCESS, }); setSubmitting(false); - resetForm(); if (submitPayload.redirect) { history.push('/invoices'); @@ -230,7 +229,7 @@ function InvoiceForm({ }, [changePageSubtitle], ); - + return (
)} diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveFloatingActions.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveFloatingActions.js index 2f02013c4..318ea4a9e 100644 --- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveFloatingActions.js +++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveFloatingActions.js @@ -46,19 +46,28 @@ export default function PaymentReceiveFormFloatingActions({ onSubmitForm(); saveInvoke(onSubmitClick, event, { redirect: false, + resetForm: true, + }); + }; + + const handleSubmitContinueEditingBtnClick = (event) => { + onSubmitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, }); }; return (
+ {/* ----------- Save and New ----------- */} - {/* ----------- Save and New ----------- */}
); } diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js index 32d682cd1..859e079c0 100644 --- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js +++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveForm.js @@ -190,11 +190,13 @@ function PaymentReceiveForm({ intent: Intent.SUCCESS, }); setSubmitting(false); - resetForm(); if (submitPayload.redirect) { history.push('/payment-receives'); } + if (submitPayload.resetForm) { + resetForm(); + } }; // Handle request response errors. const onError = (errors) => { @@ -366,7 +368,7 @@ function PaymentReceiveForm({ const handleCancelClick = useCallback(() => { history.goBack(); }, [history]); - + return (
diff --git a/client/src/containers/Sales/Receipt/ReceiptFormFloatingActions.js b/client/src/containers/Sales/Receipt/ReceiptFormFloatingActions.js index c81044338..5333bec16 100644 --- a/client/src/containers/Sales/Receipt/ReceiptFormFloatingActions.js +++ b/client/src/containers/Sales/Receipt/ReceiptFormFloatingActions.js @@ -14,7 +14,7 @@ import { useFormikContext } from 'formik'; import classNames from 'classnames'; import { CLASSES } from 'common/classes'; import { saveInvoke } from 'utils'; -import { Icon } from 'components'; +import { If, Icon } from 'components'; /** * Receipt floating actions bar. @@ -22,21 +22,60 @@ import { Icon } from 'components'; export default function ReceiptFormFloatingActions({ isSubmitting, receiptId, + receiptPublished, onSubmitClick, onCancelClick, onClearClick, }) { const { resetForm, submitForm } = useFormikContext(); - const handleSubmitAndNewClick = useCallback( - (event) => { - submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - }); - }, - [submitForm], - ); + const handleSubmitPublishBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + publish: true, + }); + }; + + const handleSubmitPublishAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + resetForm: true, + }); + }; + + const handleSubmitPublishContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: true, + }); + }; + + const handleSubmitDraftBtnClick = (event) => { + saveInvoke(onSubmitClick, event, { + redirect: true, + publish: false, + }); + }; + + const handleSubmitDraftAndNewBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, + resetForm: true, + }); + }; + + const handleSubmitDraftContinueEditingBtnClick = (event) => { + submitForm(); + saveInvoke(onSubmitClick, event, { + redirect: false, + publish: false, + }); + }; const handleCancelBtnClick = (event) => { saveInvoke(onCancelClick, event); @@ -49,51 +88,114 @@ export default function ReceiptFormFloatingActions({ return (
- - {/* ----------- Save and New ----------- */} -
); } diff --git a/client/src/containers/Vendors/VendorFinanicalPanelTab.js b/client/src/containers/Vendors/VendorFinanicalPanelTab.js index 86929939e..5397f5b91 100644 --- a/client/src/containers/Vendors/VendorFinanicalPanelTab.js +++ b/client/src/containers/Vendors/VendorFinanicalPanelTab.js @@ -3,6 +3,7 @@ import classNames from 'classnames'; import { FormGroup, ControlGroup, Position, Classes } from '@blueprintjs/core'; import { DateInput } from '@blueprintjs/datetime'; import { FastField, ErrorMessage } from 'formik'; +import moment from 'moment'; import { MoneyInputGroup, InputPrependText, @@ -47,6 +48,12 @@ function VendorFinanicalPanelTab({ > { + form.setFieldValue( + 'opening_balance_at', + moment(date).format('YYYY-MM-DD'), + ); + }} value={tansformDateValue(value)} popoverProps={{ position: Position.BOTTOM, minimal: true }} disabled={vendorId} @@ -56,12 +63,7 @@ function VendorFinanicalPanelTab({ {/*------------ Opening balance -----------*/} - {({ - form: { values }, - field, - field: { value }, - meta: { error, touched }, - }) => ( + {({ form, field, field: { value }, meta: { error, touched } }) => ( } className={classNames( @@ -72,14 +74,15 @@ function VendorFinanicalPanelTab({ inline={true} > - + { + form.setFieldValue('opening_balance', balance); }} disabled={vendorId} /> diff --git a/client/src/containers/Vendors/VendorFloatingActions.js b/client/src/containers/Vendors/VendorFloatingActions.js index 7e3216da7..3ad4ec27c 100644 --- a/client/src/containers/Vendors/VendorFloatingActions.js +++ b/client/src/containers/Vendors/VendorFloatingActions.js @@ -79,20 +79,20 @@ export default function VendorFloatingActions({ rightIcon={} /> - {/* ----------- Clear & Reset----------- */} -
); } diff --git a/client/src/containers/Vendors/VendorFormAfterPrimarySection.js b/client/src/containers/Vendors/VendorFormAfterPrimarySection.js index 9ef0bcb0b..aa4a0763f 100644 --- a/client/src/containers/Vendors/VendorFormAfterPrimarySection.js +++ b/client/src/containers/Vendors/VendorFormAfterPrimarySection.js @@ -6,7 +6,6 @@ import classNames from 'classnames'; import { CLASSES } from 'common/classes'; import { inputIntent } from 'utils'; - /** * Vendor form after primary section. */ @@ -66,7 +65,7 @@ function VendorFormAfterPrimarySection() { label={} inline={true} > - + )} diff --git a/client/src/containers/Vendors/VendorsTable.js b/client/src/containers/Vendors/VendorsTable.js index 8f9936df1..9720faee9 100644 --- a/client/src/containers/Vendors/VendorsTable.js +++ b/client/src/containers/Vendors/VendorsTable.js @@ -32,6 +32,7 @@ function VendorsTable({ vendorsPageination, vendorTableQuery, vendorItems, + vendorsCurrentViewId, // #withVendorsActions addVendorsTableQueries, @@ -135,7 +136,9 @@ function VendorsTable({ { id: 'receivable_balance', Header: formatMessage({ id: 'receivable_balance' }), - accessor: (r) => , + accessor: (r) => ( + + ), className: 'receivable_balance', width: 100, }, @@ -182,6 +185,10 @@ function VendorsTable({ onEditVendor, onDeleteVendor, }); + const showEmptyStatus = [ + vendorsCurrentViewId === -1, + vendorItems.length === 0, + ].every((condition) => condition === true); return (
@@ -190,7 +197,7 @@ function VendorsTable({ mount={false} > - + @@ -228,11 +235,13 @@ export default compose( vendorsLoading, vendorTableQuery, vendorsPageination, + vendorsCurrentViewId, }) => ({ vendorItems, vendorsLoading, vendorsPageination, vendorTableQuery, + vendorsCurrentViewId, }), ), withVendorsActions, diff --git a/client/src/containers/Vendors/withVendors.js b/client/src/containers/Vendors/withVendors.js index e9846f243..8a4c36ee6 100644 --- a/client/src/containers/Vendors/withVendors.js +++ b/client/src/containers/Vendors/withVendors.js @@ -5,11 +5,13 @@ import { getVendorCurrentPageFactory, getVendorsTableQuery, getVendorsPaginationMetaFactory, + getVendorsCurrentViewIdFactory, } from 'store/vendors/vendors.selectors'; export default (mapState) => { const getVendorsItems = getVendorCurrentPageFactory(); const getVendorsPaginationMeta = getVendorsPaginationMetaFactory(); + const getVendorsCurrentViewId = getVendorsCurrentViewIdFactory(); const mapStateToProps = (state, props) => { const query = getVendorsTableQuery(state, props); @@ -20,6 +22,7 @@ export default (mapState) => { vendorTableQuery: query, vendorsPageination: getVendorsPaginationMeta(state, props, query), vendorsLoading: state.vendors.loading, + vendorsCurrentViewId: getVendorsCurrentViewId(state, props), }; return mapState ? mapState(mapped, state, props) : mapped; }; diff --git a/client/src/store/vendors/vendors.selectors.js b/client/src/store/vendors/vendors.selectors.js index 0bc45539b..c00a952a9 100644 --- a/client/src/store/vendors/vendors.selectors.js +++ b/client/src/store/vendors/vendors.selectors.js @@ -10,6 +10,8 @@ const vendorByIdSelector = (state, props) => state.vendors.items[props.vendorId]; const vendorsItemsSelector = (state) => state.vendors.items; +const vendorsCurrentViewIdSelector = (state) => state.vendors.currentViewId; + const vendorsPaginationSelector = (state, props) => { const viewId = state.vendors.currentViewId; return state.vendors.views?.[viewId]; @@ -57,3 +59,8 @@ export const getVendorByIdFactory = () => createSelector(vendorByIdSelector, (vendor) => { return vendor; }); + + export const getVendorsCurrentViewIdFactory = () => + createSelector(vendorsCurrentViewIdSelector, (currentViewId) => { + return currentViewId; + }); diff --git a/server/src/models/Expense.js b/server/src/models/Expense.js index a36b989e9..3369cd80e 100644 --- a/server/src/models/Expense.js +++ b/server/src/models/Expense.js @@ -1,28 +1,28 @@ -import { Model } from 'objection'; -import TenantModel from 'models/TenantModel'; -import { viewRolesBuilder } from 'lib/ViewRolesBuilder'; -import Media from './Media'; +import { Model } from "objection"; +import TenantModel from "models/TenantModel"; +import { viewRolesBuilder } from "lib/ViewRolesBuilder"; +import Media from "./Media"; export default class Expense extends TenantModel { /** * Table name */ static get tableName() { - return 'expenses_transactions'; + return "expenses_transactions"; } /** * Account transaction reference type. */ static get referenceType() { - return 'Expense'; + return "Expense"; } /** * Model timestamps. */ get timestamps() { - return ['createdAt', 'updatedAt']; + return ["createdAt", "updatedAt"]; } /** @@ -33,11 +33,18 @@ export default class Expense extends TenantModel { } /** - * + * */ - static get media () { + static get media() { return true; } + + static get virtualAttributes() { + return ["isPublished"]; + } + isPublished() { + return Boolean(this.publishedAt); + } /** * Model modifiers. @@ -46,28 +53,28 @@ export default class Expense extends TenantModel { return { filterByDateRange(query, startDate, endDate) { if (startDate) { - query.where('date', '>=', startDate); + query.where("date", ">=", startDate); } if (endDate) { - query.where('date', '<=', endDate); + query.where("date", "<=", endDate); } }, filterByAmountRange(query, from, to) { if (from) { - query.where('amount', '>=', from); + query.where("amount", ">=", from); } if (to) { - query.where('amount', '<=', to); + query.where("amount", "<=", to); } }, filterByExpenseAccount(query, accountId) { if (accountId) { - query.where('expense_account_id', accountId); + query.where("expense_account_id", accountId); } }, filterByPaymentAccount(query, accountId) { if (accountId) { - query.where('payment_account_id', accountId); + query.where("payment_account_id", accountId); } }, viewRolesBuilder(query, conditionals, expression) { @@ -80,41 +87,41 @@ export default class Expense extends TenantModel { * Relationship mapping. */ static get relationMappings() { - const Account = require('models/Account'); - const ExpenseCategory = require('models/ExpenseCategory'); - const Media = require('models/Media'); + const Account = require("models/Account"); + const ExpenseCategory = require("models/ExpenseCategory"); + const Media = require("models/Media"); return { paymentAccount: { relation: Model.BelongsToOneRelation, modelClass: Account.default, join: { - from: 'expenses_transactions.paymentAccountId', - to: 'accounts.id', + from: "expenses_transactions.paymentAccountId", + to: "accounts.id", }, }, categories: { relation: Model.HasManyRelation, modelClass: ExpenseCategory.default, join: { - from: 'expenses_transactions.id', - to: 'expense_transaction_categories.expenseId', + from: "expenses_transactions.id", + to: "expense_transaction_categories.expenseId", }, }, media: { relation: Model.ManyToManyRelation, modelClass: Media.default, join: { - from: 'expenses_transactions.id', + from: "expenses_transactions.id", through: { - from: 'media_links.model_id', - to: 'media_links.media_id', + from: "media_links.model_id", + to: "media_links.media_id", }, - to: 'media.id', + to: "media.id", }, filter(query) { - query.where('model_name', 'Expense'); - } + query.where("model_name", "Expense"); + }, }, }; } @@ -125,51 +132,50 @@ export default class Expense extends TenantModel { static get fields() { return { payment_date: { - label: 'Payment date', - column: 'payment_date', - columnType: 'date', + label: "Payment date", + column: "payment_date", + columnType: "date", }, payment_account: { - label: 'Payment account', - column: 'payment_account_id', - relation: 'accounts.id', - optionsResource: 'account', + label: "Payment account", + column: "payment_account_id", + relation: "accounts.id", + optionsResource: "account", }, amount: { - label: 'Amount', - column: 'total_amount', - columnType: 'number' + label: "Amount", + column: "total_amount", + columnType: "number", }, currency_code: { - label: 'Currency', - column: 'currency_code', - optionsResource: 'currency', + label: "Currency", + column: "currency_code", + optionsResource: "currency", }, reference_no: { - label: 'Reference No.', - column: 'reference_no', - columnType: 'string', + label: "Reference No.", + column: "reference_no", + columnType: "string", }, description: { - label: 'Description', - column: 'description', - columnType: 'string', + label: "Description", + column: "description", + columnType: "string", }, published: { - label: 'Published', - column: 'published', - + label: "Published", + column: "published", }, user: { - label: 'User', - column: 'user_id', - relation: 'users.id', - relationColumn: 'users.id', + label: "User", + column: "user_id", + relation: "users.id", + relationColumn: "users.id", }, created_at: { - label: 'Created at', - column: 'created_at', - columnType: 'date', + label: "Created at", + column: "created_at", + columnType: "date", }, }; }