feat: auto-complete warehouse transfer row.

This commit is contained in:
a.bouhuolia
2022-02-14 23:30:52 +02:00
parent 913245d202
commit bb56790ce9
7 changed files with 226 additions and 34 deletions

View File

@@ -3,11 +3,12 @@ import { FastField } from 'formik';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import { useWarehouseTransferFormContext } from './WarehouseTransferFormProvider'; import { useWarehouseTransferFormContext } from './WarehouseTransferFormProvider';
import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable';
import { import {
entriesFieldShouldUpdate, entriesFieldShouldUpdate,
defaultWarehouseTransferEntry, defaultWarehouseTransferEntry,
} from './utils'; } from './utils';
import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable';
/** /**
* Warehouse transafer editor field. * Warehouse transafer editor field.
@@ -35,6 +36,8 @@ export default function WarehouseTransferEditorField() {
items={items} items={items}
defaultEntry={defaultWarehouseTransferEntry} defaultEntry={defaultWarehouseTransferEntry}
errors={error} errors={error}
sourceWarehouseId={values.from_warehouse_id}
distentionWarehouseId={value.to_warehouse_id}
/> />
)} )}
</FastField> </FastField>

View File

@@ -68,9 +68,7 @@ function WarehouseTransferForm({
const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => { const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
setSubmitting(true); setSubmitting(true);
// Transformes the values of the form to request. // Transformes the values of the form to request.
const form = { const form = transformValueToRequest(values);
...transformValueToRequest(values),
};
// Handle the request success. // Handle the request success.
const onSuccess = () => { const onSuccess = () => {

View File

@@ -17,8 +17,6 @@ const Schema = Yup.object().shape({
entries: Yup.array().of( entries: Yup.array().of(
Yup.object().shape({ Yup.object().shape({
item_id: Yup.number().nullable(), item_id: Yup.number().nullable(),
// source_warehouse: Yup.number().nullable(),
// destination_warehouse: Yup.number().nullable(),
description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT), description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT),
quantity: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10), quantity: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10),
}), }),

View File

@@ -1,16 +1,14 @@
import React from 'react'; import React from 'react';
import { useWarehouseTransferTableColumns } from '../utils';
import { DataTableEditable } from 'components'; import { DataTableEditable } from 'components';
import {
saveInvoke, import { useWarehouseTransferTableColumns } from '../utils';
compose, import { useFetchItemWarehouseQuantity } from './hooks';
updateTableCell, import { useDeepCompareEffect } from 'hooks/utils';
updateMinEntriesLines,
updateAutoAddNewLine, import { saveInvoke } from 'utils';
updateRemoveLineByIndex, import { mutateTableCell, mutateTableRow, deleteTableRow } from './utils';
orderingLinesIndexes,
} from 'utils';
/** /**
* Warehouse transfer form entries table. * Warehouse transfer form entries table.
*/ */
@@ -21,34 +19,63 @@ export default function WarehouseTransferFormEntriesTable({
defaultEntry, defaultEntry,
onUpdateData, onUpdateData,
errors, errors,
destinationWarehouseId,
sourceWarehouseId,
}) { }) {
// Fetch the table row.
const { newRowMeta, setTableRow, resetTableRow, cellsLoading } =
useFetchItemWarehouseQuantity();
// Retrieve the warehouse transfer table columns. // Retrieve the warehouse transfer table columns.
const columns = useWarehouseTransferTableColumns(); const columns = useWarehouseTransferTableColumns();
// Observes the new row meta to call `onUpdateData` callback.
useDeepCompareEffect(() => {
if (newRowMeta) {
const newRow = {
item_id: newRowMeta.itemId,
warehouses: newRowMeta.warehouses,
description: '',
quantity: 0,
};
const newRows = mutateTableRow(newRowMeta.rowIndex, newRow, entries);
saveInvoke(onUpdateData, newRows);
resetTableRow();
}
}, [newRowMeta]);
// Handle update data. // Handle update data.
const handleUpdateData = React.useCallback( const handleUpdateData = React.useCallback(
(rowIndex, columnId, value) => { (rowIndex, columnId, itemId) => {
const newRows = compose( if (columnId === 'item_id') {
// Update auto-adding new line. setTableRow({
updateAutoAddNewLine(defaultEntry, ['item_id']), rowIndex,
// Update the row value of the given row index and column id. columnId,
updateTableCell(rowIndex, columnId, value), itemId,
)(entries); sourceWarehouseId,
destinationWarehouseId,
});
}
const editCell = mutateTableCell(rowIndex, columnId, defaultEntry);
const newRows = editCell(itemId, entries);
saveInvoke(onUpdateData, newRows); saveInvoke(onUpdateData, newRows);
}, },
[entries, defaultEntry, onUpdateData], [
entries,
defaultEntry,
onUpdateData,
destinationWarehouseId,
sourceWarehouseId,
setTableRow,
],
); );
// Handles click remove datatable row. // Handles click remove datatable row.
const handleRemoveRow = React.useCallback( const handleRemoveRow = React.useCallback(
(rowIndex) => { (rowIndex) => {
const newRows = compose( const newRows = deleteTableRow(rowIndex, defaultEntry, entries);
// Ensure minimum lines count.
updateMinEntriesLines(4, defaultEntry),
// Remove the line by the given index.
updateRemoveLineByIndex(rowIndex),
)(entries);
saveInvoke(onUpdateData, newRows); saveInvoke(onUpdateData, newRows);
}, },
[entries, defaultEntry, onUpdateData], [entries, defaultEntry, onUpdateData],
@@ -58,12 +85,17 @@ export default function WarehouseTransferFormEntriesTable({
<DataTableEditable <DataTableEditable
columns={columns} columns={columns}
data={entries} data={entries}
cellsLoading={!!cellsLoading}
cellsLoadingCoords={cellsLoading}
payload={{ payload={{
items, items,
errors: errors || [], errors: errors || [],
updateData: handleUpdateData, updateData: handleUpdateData,
removeRow: handleRemoveRow, removeRow: handleRemoveRow,
autoFocus: ['item_id', 0], autoFocus: ['item_id', 0],
sourceWarehouseId,
destinationWarehouseId,
}} }}
/> />
); );

View File

@@ -0,0 +1,86 @@
// @ts-nocheck
import React from 'react';
import { useItem } from 'hooks/query';
interface IItemMeta {
rowIndex: number;
columnId: string;
itemId: number;
sourceWarehouseId: number;
distentionWarehouseId: number;
}
type CellLoading = any;
interface IWarehouseMeta {
warehouseId: number;
warehouseQuantity: number;
warehouseQuantityFormatted: string;
}
interface IRow {
rowIndex: number;
columnId: number;
itemId: number;
warehouses: IWarehouseMeta[];
}
/**
* Fetches the item warehouse quantity.
* @returns
*/
export const useFetchItemWarehouseQuantity = () => {
// Holds the table row meta of the given row index.
const [tableRow, setTableRow] = React.useState<IItemMeta | null>(null);
// Table cells loading coords.
const [cellsLoading, setCellsLoading] = React.useState<CellLoading | null>(
null,
);
// Fetches the item warehouse locations.
const {
data: item,
isLoading: isItemLoading,
isSuccess: isItemSuccess,
} = useItem(tableRow?.itemId, {
enabled: !!(tableRow && tableRow.itemId),
});
// Effects with row cells loading state.
React.useEffect(() => {
setCellsLoading(null);
if (isItemLoading && tableRow) {
setCellsLoading([
[tableRow.rowIndex, 'quantity'],
[tableRow.rowIndex, 'source_warehouse'],
[tableRow.rowIndex, 'destination_warehouse'],
]);
}
}, [isItemLoading, tableRow]);
// New table row meta.
const newRowMeta = React.useMemo(() => {
return isItemSuccess
? {
...tableRow,
warehouses: [],
}
: null;
}, [isItemSuccess, tableRow]);
// Reset the table row.
const resetTableRow = React.useCallback(() => {
setTableRow(null);
setCellsLoading(null);
}, []);
return {
setTableRow,
resetTableRow,
cellsLoading,
newRowMeta,
};
};

View File

@@ -2,16 +2,25 @@ import React from 'react';
import moment from 'moment'; import moment from 'moment';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import { AppToaster } from 'components';
import { omit } from 'lodash'; import { omit } from 'lodash';
import { useFormikContext } from 'formik';
import * as R from 'ramda';
import { AppToaster } from 'components';
import {
orderingLinesIndexes,
updateAutoAddNewLine,
updateTableCell,
} from 'utils';
import { import {
compose, compose,
transformToForm, transformToForm,
repeatValue, repeatValue,
transactionNumber, transactionNumber,
defaultFastFieldShouldUpdate, defaultFastFieldShouldUpdate,
updateTableRow,
updateMinEntriesLines,
updateRemoveLineByIndex,
} from 'utils'; } from 'utils';
// import { defaultFastFieldShouldUpdate } from 'utils'; // import { defaultFastFieldShouldUpdate } from 'utils';
@@ -88,6 +97,10 @@ export const useObserveTransferNoSettings = (prefix, nextNumber) => {
export const entriesFieldShouldUpdate = (newProps, oldProps) => { export const entriesFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.items !== oldProps.items || newProps.items !== oldProps.items ||
newProps.formik.values.from_warehouse_id !==
oldProps.formik.values.from_warehouse_id ||
newProps.formik.values.to_warehouse_id !==
oldProps.formik.values.to_warehouse_id ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };
@@ -102,7 +115,7 @@ export function transformValueToRequest(values) {
return { return {
...values, ...values,
entries: entries.map((entry) => ({ entries: entries.map((entry) => ({
...omit(entry, ['destination_warehouse', 'source_warehouse']), ...omit(entry, ['warehouses']),
})), })),
}; };
} }
@@ -122,3 +135,42 @@ export const transformErrors = (errors, { setErrors }) => {
}); });
} }
}; };
/**
* Mutates table cell.
* @param {*} rowIndex
* @param {*} columnId
* @param {*} defaultEntry
* @param {*} value
* @param {*} entries
* @returns
*/
export const mutateTableCell = R.curry(
(rowIndex, columnId, defaultEntry, value, entries) => {
return compose(
// Update auto-adding new line.
updateAutoAddNewLine(defaultEntry, ['item_id']),
// Update the row value of the given row index and column id.
updateTableCell(rowIndex, columnId, value),
)(entries);
},
);
/**
* Compose table rows when insert a new row to table rows.
*/
export const mutateTableRow = R.curry((rowIndex, newRow, rows) => {
return compose(orderingLinesIndexes, updateTableRow(rowIndex, newRow))(rows);
});
/**
* Deletes the table row from the given rows.
*/
export const deleteTableRow = R.curry((rowIndex, defaultEntry, rows) => {
return compose(
// Ensure minimum lines count.
updateMinEntriesLines(4, defaultEntry),
// Remove the line by the given index.
updateRemoveLineByIndex(rowIndex),
)(rows);
});

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { find, get } from 'lodash';
import { Tooltip, Button, Intent, Position } from '@blueprintjs/core'; import { Tooltip, Button, Intent, Position } from '@blueprintjs/core';
import { import {
@@ -43,6 +44,26 @@ export function ActionsCellRenderer({
); );
} }
function SourceWarehouseAccessorCell({ value, row: { original }, payload }) {
const warehouse = find(
original.warehouses,
(w) => w.warehouseId === payload.sourceWarehouseId,
);
return get(warehouse, 'warehouseQuantityFormatted', '0');
}
function DistentionWarehouseAccessorCell({
value,
row: { original },
payload,
}) {
const warehouse = find(
original.warehouses,
(w) => w.warehouseId === payload.distentionWarehouseId,
);
return get(warehouse, 'warehouseQuantityFormatted', '0');
}
/** /**
* Retrieves warehouse transfer table columns. * Retrieves warehouse transfer table columns.
* @returns * @returns
@@ -82,6 +103,7 @@ export const useWarehouseTransferTableColumns = () => {
Header: 'Source Warehouse', Header: 'Source Warehouse',
accessor: 'source_warehouse', accessor: 'source_warehouse',
disableSortBy: true, disableSortBy: true,
Cell: SourceWarehouseAccessorCell,
align: 'right', align: 'right',
width: 120, width: 120,
}, },
@@ -89,6 +111,7 @@ export const useWarehouseTransferTableColumns = () => {
id: 'destination_warehouse', id: 'destination_warehouse',
Header: 'Destination Warehouse', Header: 'Destination Warehouse',
accessor: 'destination_warehouse', accessor: 'destination_warehouse',
Cell: DistentionWarehouseAccessorCell,
disableSortBy: true, disableSortBy: true,
align: 'right', align: 'right',
width: 120, width: 120,