mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
refactoring: expenses landing list.
refactoring: customers landing list. refactoring: vendors landing list. refactoring: manual journals landing list.
This commit is contained in:
@@ -58,6 +58,7 @@ export default function VendorFloatingActions() {
|
||||
{/* ----------- Save and New ----------- */}
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitBtnClick}
|
||||
@@ -93,6 +94,7 @@ export default function VendorFloatingActions() {
|
||||
{/* ----------- Cancel ----------- */}
|
||||
<Button
|
||||
className={'ml1'}
|
||||
disabled={isSubmitting}
|
||||
onClick={handleCancelBtnClick}
|
||||
text={<T id={'cancel'} />}
|
||||
/>
|
||||
@@ -21,8 +21,8 @@ import VendorFloatingActions from './VendorFloatingActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
|
||||
import { compose, transformToForm } from 'utils';
|
||||
import { useVendorFormContext } from './VendorFormProvider';
|
||||
import { compose, transformToForm } from 'utils';
|
||||
|
||||
const defaultInitialValues = {
|
||||
salutation: '',
|
||||
@@ -69,6 +69,8 @@ function VendorForm({
|
||||
// #withSettings
|
||||
baseCurrency,
|
||||
}) {
|
||||
|
||||
// Vendor form context.
|
||||
const {
|
||||
vendorId,
|
||||
vendor,
|
||||
@@ -80,7 +82,9 @@ function VendorForm({
|
||||
|
||||
const isNewMode = !vendorId;
|
||||
|
||||
// History context.
|
||||
const history = useHistory();
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
/**
|
||||
@@ -104,9 +108,10 @@ function VendorForm({
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (
|
||||
values,
|
||||
{ setSubmitting: resetForm, setErrors },
|
||||
{ setSubmitting, resetForm, setErrors },
|
||||
) => {
|
||||
const requestForm = { ...values };
|
||||
setSubmitting(true);
|
||||
|
||||
const onSuccess = () => {
|
||||
AppToaster.show({
|
||||
@@ -118,6 +123,7 @@ function VendorForm({
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setSubmitPayload(false);
|
||||
setSubmitting(false);
|
||||
resetForm();
|
||||
|
||||
if (!submitPayload.noRedirect) {
|
||||
@@ -127,17 +133,18 @@ function VendorForm({
|
||||
|
||||
const onError = () => {
|
||||
setSubmitPayload(false);
|
||||
setSubmitting(false);
|
||||
};
|
||||
|
||||
if (vendor && vendor.id) {
|
||||
editVendorMutate(vendor.id, requestForm).then(onSuccess).catch(onError);
|
||||
editVendorMutate([vendor.id, requestForm]).then(onSuccess).catch(onError);
|
||||
} else {
|
||||
createVendorMutate(requestForm).then(onSuccess).catch(onError);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_CUSTOMER)}>
|
||||
<div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_VENDOR)}>
|
||||
<Formik
|
||||
validationSchema={
|
||||
isNewMode ? CreateVendorFormSchema : EditVendorFormSchema
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import 'style/pages/Vendors/PageForm.scss';
|
||||
|
||||
import { DashboardCard } from 'components';
|
||||
import VendorFrom from './VendorForm';
|
||||
@@ -11,8 +13,7 @@ import { VendorFormProvider } from './VendorFormProvider';
|
||||
*/
|
||||
function VendorFormPage() {
|
||||
const { id } = useParams();
|
||||
const history = useHistory();
|
||||
|
||||
|
||||
return (
|
||||
<VendorFormProvider vendorId={id}>
|
||||
<DashboardCard page>
|
||||
@@ -2,7 +2,6 @@ import React, { useState, createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import {
|
||||
useVendor,
|
||||
useVendors,
|
||||
useCurrencies,
|
||||
useCreateVendor,
|
||||
useEditVendor,
|
||||
@@ -17,27 +16,20 @@ function VendorFormProvider({ vendorId, ...props }) {
|
||||
// Handle fetch Currencies data table
|
||||
const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies();
|
||||
|
||||
// Handle fetch vendors data table
|
||||
const {
|
||||
data: { vendors },
|
||||
isFetching: isVendorsLoading,
|
||||
} = useVendors();
|
||||
|
||||
// Handle fetch vendor details.
|
||||
const { data: vendor, isFetching: isVendorLoading } = useVendor(vendorId, {
|
||||
enabled: !!vendorId,
|
||||
});
|
||||
|
||||
// Form submit payload.
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
// Create and edit vendor mutations.
|
||||
const { mutateAsync: createVendorMutate } = useCreateVendor();
|
||||
const { mutateAsync: editVendorMutate } = useEditVendor();
|
||||
|
||||
// Form submit payload.
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
const provider = {
|
||||
currencies,
|
||||
vendors,
|
||||
vendor,
|
||||
submitPayload,
|
||||
|
||||
@@ -48,7 +40,7 @@ function VendorFormProvider({ vendorId, ...props }) {
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isVendorLoading || isVendorsLoading || isCurrenciesLoading}
|
||||
loading={isVendorLoading || isCurrenciesLoading}
|
||||
name={'vendor-form'}
|
||||
>
|
||||
<VendorFormContext.Provider value={provider} {...props} />
|
||||
@@ -3,11 +3,16 @@ import { Tabs, Tab } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import VendorFinanicalPanelTab from './VendorFinanicalPanelTab';
|
||||
import VendorAttahmentTab from './VendorAttahmentTab';
|
||||
import CustomerAddressTabs from 'containers/Customers/CustomerAddressTabs';
|
||||
import CustomerNotePanel from 'containers/Customers/CustomerNotePanel';
|
||||
|
||||
import CustomerAddressTabs from 'containers/Customers/CustomerForm/CustomerAddressTabs';
|
||||
import CustomerNotePanel from 'containers/Customers/CustomerForm/CustomerNotePanel';
|
||||
|
||||
/**
|
||||
* Vendor form tabs.
|
||||
*/
|
||||
export default function VendorTabs() {
|
||||
const { formatMessage } = useIntl();
|
||||
return (
|
||||
@@ -19,7 +19,7 @@ import { If, DashboardActionViewsList } from 'components';
|
||||
import { useVendorsListContext } from './VendorsListProvider';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import withVendorActions from './withVendorActions';
|
||||
import withVendorsActions from './withVendorsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -28,19 +28,23 @@ import { compose } from 'utils';
|
||||
*/
|
||||
function VendorActionsBar({
|
||||
// #withVendorActions
|
||||
addVendorsTableQueries,
|
||||
setVendorsTableState,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// Vendors list context.
|
||||
const { vendorsViews } = useVendorsListContext();
|
||||
|
||||
// Handles new vendor button click.
|
||||
const onClickNewVendor = () => {
|
||||
history.push('/vendors/new');
|
||||
};
|
||||
|
||||
// Handle the active tab change.
|
||||
const handleTabChange = (viewId) => {
|
||||
addVendorsTableQueries({
|
||||
custom_view_id: viewId.id || null,
|
||||
setVendorsTableState({
|
||||
customViewId: viewId.id || null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -101,5 +105,5 @@ function VendorActionsBar({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withVendorActions,
|
||||
withVendorsActions,
|
||||
)(VendorActionsBar);
|
||||
@@ -1,22 +1,24 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
|
||||
import { compose } from 'redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { useVendorsListContext } from './VendorsListProvider';
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
|
||||
import withVendorActions from './withVendorActions';
|
||||
import withVendorsActions from './withVendorsActions';
|
||||
import withVendors from './withVendors';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
/**
|
||||
* Vendors views tabs.
|
||||
*/
|
||||
function VendorViewsTabs({
|
||||
// #withVendorActions
|
||||
addVendorsTableQueries,
|
||||
// #withVendorsActions
|
||||
setVendorsTableState,
|
||||
|
||||
// #withVendors
|
||||
vendorsTableState
|
||||
}) {
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
const { vendorsViews } = useVendorsListContext();
|
||||
|
||||
const tabs = useMemo(() =>
|
||||
@@ -29,8 +31,8 @@ function VendorViewsTabs({
|
||||
);
|
||||
|
||||
const handleTabsChange = (viewId) => {
|
||||
addVendorsTableQueries({
|
||||
custom_view_id: viewId || null,
|
||||
setVendorsTableState({
|
||||
customViewId: viewId || null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -38,7 +40,7 @@ function VendorViewsTabs({
|
||||
<Navbar className="navbar--dashboard-views">
|
||||
<NavbarGroup align={Alignment.LEFT}>
|
||||
<DashboardViewsTabs
|
||||
initialViewId={customViewId}
|
||||
customViewId={vendorsTableState.customViewId}
|
||||
resourceName={'vendors'}
|
||||
tabs={tabs}
|
||||
onChange={handleTabsChange}
|
||||
@@ -49,5 +51,6 @@ function VendorViewsTabs({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withVendorActions,
|
||||
withVendorsActions,
|
||||
withVendors(({ vendorsTableState }) => ({ vendorsTableState }))
|
||||
)(VendorViewsTabs);
|
||||
@@ -1,17 +1,20 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import 'style/pages/Vendors/List.scss';
|
||||
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
|
||||
import { VendorsListProvider } from './VendorsListProvider';
|
||||
import VendorActionsBar from 'containers/Vendors/VendorActionsBar';
|
||||
import VendorsViewPage from 'containers/Vendors/VendorsViewPage';
|
||||
import VendorsAlerts from 'containers/Vendors/VendorsAlerts';
|
||||
import VendorActionsBar from './VendorActionsBar';
|
||||
import VendorViewsTabs from './VendorViewsTabs';
|
||||
import VendorsAlerts from '../VendorsAlerts';
|
||||
import VendorsTable from './VendorsTable';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withVendors from 'containers/Vendors/withVendors';
|
||||
import withVendors from './withVendors';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { transformTableStateToQuery, compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Vendors list page.
|
||||
@@ -21,7 +24,7 @@ function VendorsList({
|
||||
changePageTitle,
|
||||
|
||||
// #withVendors
|
||||
vendorTableQuery,
|
||||
vendorsTableState,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
@@ -30,12 +33,13 @@ function VendorsList({
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
return (
|
||||
<VendorsListProvider query={vendorTableQuery}>
|
||||
<VendorsListProvider query={transformTableStateToQuery(vendorsTableState)}>
|
||||
<VendorActionsBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<VendorsViewPage />
|
||||
{/* <VendorsAlerts /> */}
|
||||
<VendorViewsTabs />
|
||||
<VendorsTable />
|
||||
<VendorsAlerts />
|
||||
</DashboardPageContent>
|
||||
</VendorsListProvider>
|
||||
);
|
||||
@@ -43,5 +47,5 @@ function VendorsList({
|
||||
|
||||
export default compose(
|
||||
withDashboardActions,
|
||||
withVendors(({ vendorTableQuery }) => ({ vendorTableQuery })),
|
||||
withVendors(({ vendorsTableState }) => ({ vendorsTableState })),
|
||||
)(VendorsList);
|
||||
@@ -2,6 +2,7 @@ import React, { createContext } from 'react';
|
||||
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { useResourceViews, useVendors } from 'hooks/query';
|
||||
import { isTableEmptyStatus } from 'utils';
|
||||
|
||||
const VendorsListContext = createContext();
|
||||
|
||||
@@ -9,22 +10,32 @@ function VendorsListProvider({ query, ...props }) {
|
||||
|
||||
// Fetch vendors list with pagination meta.
|
||||
const {
|
||||
data: { vendors, pagination },
|
||||
isFetching: isVendorsLoading,
|
||||
} = useVendors(query);
|
||||
data: { vendors, pagination, filterMeta },
|
||||
isLoading: isVendorsLoading,
|
||||
isFetching: isVendorsFetching,
|
||||
} = useVendors(query, { keepPreviousData: true });
|
||||
|
||||
// Fetch customers resource views and fields.
|
||||
const {
|
||||
data: vendorsViews,
|
||||
isFetching: isVendorsViewsLoading,
|
||||
isLoading: isVendorsViewsLoading,
|
||||
} = useResourceViews('vendors');
|
||||
|
||||
// Detarmines the datatable empty status.
|
||||
const isEmptyStatus = isTableEmptyStatus({
|
||||
data: vendors, pagination, filterMeta,
|
||||
}) && !isVendorsLoading;
|
||||
|
||||
const provider = {
|
||||
vendors,
|
||||
pagination,
|
||||
vendorsViews,
|
||||
|
||||
isVendorsLoading,
|
||||
isVendorsFetching,
|
||||
isVendorsViewsLoading,
|
||||
|
||||
isEmptyStatus
|
||||
};
|
||||
|
||||
return (
|
||||
114
client/src/containers/Vendors/VendorsLanding/VendorsTable.js
Normal file
114
client/src/containers/Vendors/VendorsLanding/VendorsTable.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { DataTable, Choose } from 'components';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
import VendorsEmptyStatus from './VendorsEmptyStatus';
|
||||
|
||||
import { useVendorsListContext } from './VendorsListProvider';
|
||||
import withVendorsActions from './withVendorsActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { ActionsMenu, useVendorsTableColumns } from './components';
|
||||
|
||||
/**
|
||||
* Vendors table.
|
||||
*/
|
||||
function VendorsTable({
|
||||
// #withVendorsActions
|
||||
setVendorsTableState,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
}) {
|
||||
// Vendors list context.
|
||||
const {
|
||||
vendors,
|
||||
pagination,
|
||||
isVendorsFetching,
|
||||
isVendorsLoading,
|
||||
} = useVendorsListContext();
|
||||
|
||||
// Vendors table columns.
|
||||
const columns = useVendorsTableColumns();
|
||||
|
||||
// History context.
|
||||
const history = useHistory();
|
||||
|
||||
// Handle edit vendor data table
|
||||
const handleEditVendor = (vendor) => {
|
||||
history.push(`/vendors/${vendor.id}/edit`);
|
||||
};
|
||||
|
||||
// Handle click delete vendor.
|
||||
const handleDeleteVendor = ({ id }) => {
|
||||
openAlert('vendor-delete', { vendorId: id });
|
||||
};
|
||||
|
||||
// Handle fetch data once the page index, size or sort by of the table change.
|
||||
const handleFetchData = React.useCallback(
|
||||
({ pageSize, pageIndex, sortBy }) => {
|
||||
setVendorsTableState({
|
||||
pageIndex,
|
||||
pageSize,
|
||||
sortBy,
|
||||
});
|
||||
},
|
||||
[setVendorsTableState],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<Choose>
|
||||
<Choose.When condition={false}>
|
||||
<VendorsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={vendors}
|
||||
|
||||
loading={isVendorsLoading}
|
||||
headerLoading={isVendorsLoading}
|
||||
progressBarLoading={isVendorsFetching}
|
||||
|
||||
onFetchData={handleFetchData}
|
||||
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
|
||||
ContextMenu={ActionsMenu}
|
||||
|
||||
payload={{
|
||||
onEdit: handleEditVendor,
|
||||
onDelete: handleDeleteVendor,
|
||||
}}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withVendorsActions,
|
||||
withAlertsActions
|
||||
)(VendorsTable);
|
||||
142
client/src/containers/Vendors/VendorsLanding/components.js
Normal file
142
client/src/containers/Vendors/VendorsLanding/components.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuDivider,
|
||||
Position,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Icon, Money } from 'components';
|
||||
import { safeCallback, firstLettersArgs } from 'utils';
|
||||
|
||||
/**
|
||||
* Actions menu.
|
||||
*/
|
||||
export function ActionsMenu({
|
||||
row: { original },
|
||||
payload: { onEdit, onDelete },
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_vendor' })}
|
||||
onClick={safeCallback(onEdit, original)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
text={formatMessage({ id: 'delete_vendor' })}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDelete, original)}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions cell.
|
||||
*/
|
||||
export function ActionsCell(props) {
|
||||
return (
|
||||
<Popover
|
||||
content={<ActionsMenu {...props} />}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
>
|
||||
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avatar table accessor.
|
||||
*/
|
||||
export function AvatarAccessor(row) {
|
||||
return <span className="avatar">{firstLettersArgs(row.display_name)}</span>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Phone number accessor.
|
||||
*/
|
||||
export function PhoneNumberAccessor(row) {
|
||||
return (
|
||||
<div>
|
||||
<div className={'work_phone'}>{row.work_phone}</div>
|
||||
<div className={'personal_phone'}>{row.personal_phone}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Balance accessor.
|
||||
*/
|
||||
export function BalanceAccessor(row) {
|
||||
return <Money amount={row.closing_balance} currency={'USD'} />;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the vendors table columns.
|
||||
*/
|
||||
export function useVendorsTableColumns() {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'avatar',
|
||||
Header: '',
|
||||
accessor: AvatarAccessor,
|
||||
className: 'avatar',
|
||||
width: 50,
|
||||
disableResizing: true,
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
id: 'display_name',
|
||||
Header: formatMessage({ id: 'display_name' }),
|
||||
accessor: 'display_name',
|
||||
className: 'display_name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'company_name',
|
||||
Header: formatMessage({ id: 'company_name' }),
|
||||
accessor: 'company_name',
|
||||
className: 'company_name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'phone_number',
|
||||
Header: formatMessage({ id: 'phone_number' }),
|
||||
accessor: PhoneNumberAccessor,
|
||||
className: 'phone_number',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
id: 'receivable_balance',
|
||||
Header: formatMessage({ id: 'receivable_balance' }),
|
||||
accessor: BalanceAccessor,
|
||||
className: 'receivable_balance',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Cell: ActionsCell,
|
||||
className: 'actions',
|
||||
width: 70,
|
||||
disableResizing: true,
|
||||
disableSortBy: true,
|
||||
},
|
||||
],
|
||||
[formatMessage],
|
||||
);
|
||||
}
|
||||
16
client/src/containers/Vendors/VendorsLanding/withVendors.js
Normal file
16
client/src/containers/Vendors/VendorsLanding/withVendors.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
getVendorsTableStateFactory,
|
||||
} from 'store/vendors/vendors.selectors';
|
||||
|
||||
export default (mapState) => {
|
||||
const getVendorsTableState = getVendorsTableStateFactory();
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const mapped = {
|
||||
vendorsTableState: getVendorsTableState(state, props),
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
return connect(mapStateToProps);
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { setVendorsTableState } from 'store/vendors/vendors.actions';
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setVendorsTableState: (queries) => dispatch(setVendorsTableState(queries)),
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps);
|
||||
@@ -1,214 +0,0 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuDivider,
|
||||
Position,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import VendorsEmptyStatus from './VendorsEmptyStatus';
|
||||
import { DataTable, Icon, Money, Choose } from 'components';
|
||||
|
||||
import { useVendorsListContext } from './VendorsListProvider';
|
||||
import withVendorsActions from './withVendorActions';
|
||||
|
||||
import { compose, firstLettersArgs, saveInvoke } from 'utils';
|
||||
|
||||
const AvatarCell = (row) => {
|
||||
return <span className="avatar">{firstLettersArgs(row.display_name)}</span>;
|
||||
};
|
||||
|
||||
function VendorsTable({
|
||||
// #withVendorsActions
|
||||
addVendorsTableQueries,
|
||||
|
||||
// #ownProps
|
||||
onEditVendor,
|
||||
onDeleteVendor,
|
||||
onSelectedRowsChange,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const { vendors } = useVendorsListContext();
|
||||
|
||||
// Vendor actions list.
|
||||
const renderContextMenu = useMemo(
|
||||
() => ({ vendor, onEditVendor, onDeleteVendor }) => {
|
||||
const handleEditVendor = () => {
|
||||
saveInvoke(onEditVendor, vendor);
|
||||
};
|
||||
const handleDeleteVendor = () => {
|
||||
saveInvoke(onDeleteVendor, vendor);
|
||||
};
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_vendor' })}
|
||||
onClick={handleEditVendor}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
text={formatMessage({ id: 'delete_vendor' })}
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleDeleteVendor}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
},
|
||||
[formatMessage],
|
||||
);
|
||||
|
||||
// Renders actions table cell.
|
||||
const renderActionsCell = useMemo(
|
||||
() => ({ cell }) => (
|
||||
<Popover
|
||||
content={renderContextMenu({
|
||||
vendor: cell.row.original,
|
||||
onEditVendor,
|
||||
onDeleteVendor,
|
||||
})}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
>
|
||||
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||
</Popover>
|
||||
),
|
||||
[onDeleteVendor, onEditVendor, renderContextMenu],
|
||||
);
|
||||
|
||||
// Table columns.
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'avatar',
|
||||
Header: '',
|
||||
accessor: AvatarCell,
|
||||
className: 'avatar',
|
||||
width: 50,
|
||||
disableResizing: true,
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
id: 'display_name',
|
||||
Header: formatMessage({ id: 'display_name' }),
|
||||
accessor: 'display_name',
|
||||
className: 'display_name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'company_name',
|
||||
Header: formatMessage({ id: 'company_name' }),
|
||||
accessor: 'company_name',
|
||||
className: 'company_name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'phone_number',
|
||||
Header: formatMessage({ id: 'phone_number' }),
|
||||
accessor: (row) => (
|
||||
<div>
|
||||
<div className={'work_phone'}>{row.work_phone}</div>
|
||||
<div className={'personal_phone'}>{row.personal_phone}</div>
|
||||
</div>
|
||||
),
|
||||
className: 'phone_number',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
id: 'receivable_balance',
|
||||
Header: formatMessage({ id: 'receivable_balance' }),
|
||||
accessor: (r) => (
|
||||
<Money amount={r.closing_balance} currency={r.currency_code} />
|
||||
),
|
||||
className: 'receivable_balance',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Cell: renderActionsCell,
|
||||
className: 'actions',
|
||||
width: 70,
|
||||
disableResizing: true,
|
||||
disableSortBy: true,
|
||||
},
|
||||
],
|
||||
[formatMessage, renderActionsCell],
|
||||
);
|
||||
|
||||
//Handle fetch data table
|
||||
const handleFetchData = useCallback(
|
||||
({ pageIndex, pageSize, sortBy }) => {
|
||||
addVendorsTableQueries({
|
||||
page: pageIndex + 1,
|
||||
page_size: pageSize,
|
||||
...(sortBy.length > 0
|
||||
? {
|
||||
column_sort_order: sortBy[0].id,
|
||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
},
|
||||
[addVendorsTableQueries],
|
||||
);
|
||||
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(selectedRows) => {
|
||||
onSelectedRowsChange &&
|
||||
onSelectedRowsChange(selectedRows.map((s) => s.original));
|
||||
},
|
||||
[onSelectedRowsChange],
|
||||
);
|
||||
|
||||
const rowContextMenu = (cell) =>
|
||||
renderContextMenu({
|
||||
vendor: cell.row.original,
|
||||
onEditVendor,
|
||||
onDeleteVendor,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<Choose>
|
||||
<Choose.When condition={false}>
|
||||
<VendorsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={vendors}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
spinnerProps={{ size: 30 }}
|
||||
rowContextMenu={rowContextMenu}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
// pagesCount={vendorsPageination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
// initialPageSize={vendorTableQuery.page_size}
|
||||
// initialPageIndex={vendorTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withVendorsActions)(VendorsTable);
|
||||
@@ -1,60 +0,0 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Route, Switch, useHistory } from 'react-router-dom';
|
||||
|
||||
import VendorsViewsTabs from './VendorViewsTabs';
|
||||
import VendorsTable from './VendorsTable';
|
||||
|
||||
import withVendorActions from './withVendorActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function VendorsViewPage({
|
||||
// #withAlertsActions.
|
||||
openAlert,
|
||||
|
||||
// #withVendorActions.
|
||||
setSelectedRowsVendors,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
// Handle Edit vendor data table
|
||||
const handleEditVendor = useCallback(
|
||||
(vendor) => {
|
||||
history.push(`/vendors/${vendor.id}/edit`);
|
||||
},
|
||||
[history],
|
||||
);
|
||||
|
||||
// Handle click delete vendor.
|
||||
const handleDeleteVendor = useCallback(
|
||||
({ id }) => {
|
||||
openAlert('vendor-delete', { vendorId: id });
|
||||
},
|
||||
[openAlert],
|
||||
);
|
||||
|
||||
// Handle select vendor rows.
|
||||
const handleSelectedRowsChange = (selectedRows) => {
|
||||
const selectedRowsIds = selectedRows.map((r) => r.id);
|
||||
setSelectedRowsVendors(selectedRowsIds);
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/vendors/:custom_view_id/custom_view', '/vendors']}
|
||||
>
|
||||
<VendorsViewsTabs />
|
||||
<VendorsTable
|
||||
onDeleteVendor={handleDeleteVendor}
|
||||
onEditVendor={handleEditVendor}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withAlertsActions, withVendorActions)(VendorsViewPage);
|
||||
@@ -1,35 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
submitVendor,
|
||||
editVendor,
|
||||
deleteVendor,
|
||||
fetchVendorsTable,
|
||||
fetchVendor,
|
||||
} from 'store/vendors/vendors.actions';
|
||||
import t from 'store/types';
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
requestSubmitVendor: (form) => dispatch(submitVendor({ form })),
|
||||
requestEditVendor: (id, form) => dispatch(editVendor({ id, form })),
|
||||
requestFetchVendor: (id) => dispatch(fetchVendor({ id })),
|
||||
requestFetchVendorsTable: (query = {}) =>
|
||||
dispatch(fetchVendorsTable({ query: { ...query } })),
|
||||
requestDeleteVender: (id) => dispatch(deleteVendor({ id })),
|
||||
changeVendorView: (id) =>
|
||||
dispatch({
|
||||
type: t.VENDORS_SET_CURRENT_VIEW,
|
||||
currentViewId: parseInt(id, 10),
|
||||
}),
|
||||
addVendorsTableQueries: (queries) =>
|
||||
dispatch({
|
||||
type: t.VENDORS_TABLE_QUERIES_ADD,
|
||||
payload: { queries },
|
||||
}),
|
||||
setSelectedRowsVendors: (selectedRows) =>
|
||||
dispatch({
|
||||
type: t.VENDOR_SELECTED_ROWS_SET,
|
||||
payload: { selectedRows },
|
||||
}),
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps);
|
||||
@@ -1,33 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { getResourceViews } from 'store/customViews/customViews.selectors';
|
||||
|
||||
import {
|
||||
getVendorCurrentPageFactory,
|
||||
getVendorTableQueryFactory,
|
||||
getVendorsPaginationMetaFactory,
|
||||
getVendorsCurrentViewIdFactory,
|
||||
} from 'store/vendors/vendors.selectors';
|
||||
|
||||
export default (mapState) => {
|
||||
const getVendorsItems = getVendorCurrentPageFactory();
|
||||
const getVendorsPaginationMeta = getVendorsPaginationMetaFactory();
|
||||
const getVendorsCurrentViewId = getVendorsCurrentViewIdFactory();
|
||||
const getVendorTableQuery = getVendorTableQueryFactory();
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const query = getVendorTableQuery(state, props);
|
||||
|
||||
const mapped = {
|
||||
vendorsCurrentPage: getVendorsItems(state, props, query),
|
||||
vendorViews: getResourceViews(state, props, 'vendors'),
|
||||
vendorItems: getVendorsItems(state, props, query),
|
||||
vendorTableQuery: query,
|
||||
vendorsPageination: getVendorsPaginationMeta(state, props, query),
|
||||
vendorsLoading: state.vendors.loading,
|
||||
vendorsCurrentViewId: getVendorsCurrentViewId(state, props),
|
||||
vendorsSelectedRows: state.vendors.selectedRows,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
return connect(mapStateToProps);
|
||||
};
|
||||
Reference in New Issue
Block a user