From bb56790ce9b5f102166214703711753f500f8bc8 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Mon, 14 Feb 2022 23:30:52 +0200 Subject: [PATCH] feat: auto-complete warehouse transfer row. --- .../WarehouseTransferEditorField.js | 5 +- .../WarehouseTransferForm.js | 4 +- .../WarehouseTransferForm.schema.js | 2 - .../WarehouseTransferFormEntriesTable.js | 82 ++++++++++++------ .../WarehouseTransferForm/hooks.ts | 86 +++++++++++++++++++ .../WarehouseTransferForm/utils.js | 58 ++++++++++++- src/containers/WarehouseTransfers/utils.js | 23 +++++ 7 files changed, 226 insertions(+), 34 deletions(-) create mode 100644 src/containers/WarehouseTransfers/WarehouseTransferForm/hooks.ts diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferEditorField.js b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferEditorField.js index 8c39e2dcf..8a69fda0c 100644 --- a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferEditorField.js +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferEditorField.js @@ -3,11 +3,12 @@ import { FastField } from 'formik'; import classNames from 'classnames'; import { CLASSES } from 'common/classes'; import { useWarehouseTransferFormContext } from './WarehouseTransferFormProvider'; +import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable'; import { entriesFieldShouldUpdate, defaultWarehouseTransferEntry, } from './utils'; -import WarehouseTransferFormEntriesTable from './WarehouseTransferFormEntriesTable'; + /** * Warehouse transafer editor field. @@ -35,6 +36,8 @@ export default function WarehouseTransferEditorField() { items={items} defaultEntry={defaultWarehouseTransferEntry} errors={error} + sourceWarehouseId={values.from_warehouse_id} + distentionWarehouseId={value.to_warehouse_id} /> )} diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.js b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.js index c5990ba34..1e35320a4 100644 --- a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.js +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.js @@ -68,9 +68,7 @@ function WarehouseTransferForm({ const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => { setSubmitting(true); // Transformes the values of the form to request. - const form = { - ...transformValueToRequest(values), - }; + const form = transformValueToRequest(values); // Handle the request success. const onSuccess = () => { diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.schema.js b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.schema.js index defb8db87..5f7ed3e06 100644 --- a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.schema.js +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferForm.schema.js @@ -17,8 +17,6 @@ const Schema = Yup.object().shape({ entries: Yup.array().of( Yup.object().shape({ item_id: Yup.number().nullable(), - // source_warehouse: Yup.number().nullable(), - // destination_warehouse: Yup.number().nullable(), description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT), quantity: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10), }), diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferFormEntriesTable.js b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferFormEntriesTable.js index 8ba567803..6f23e9b97 100644 --- a/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferFormEntriesTable.js +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/WarehouseTransferFormEntriesTable.js @@ -1,16 +1,14 @@ import React from 'react'; -import { useWarehouseTransferTableColumns } from '../utils'; import { DataTableEditable } from 'components'; -import { - saveInvoke, - compose, - updateTableCell, - updateMinEntriesLines, - updateAutoAddNewLine, - updateRemoveLineByIndex, - orderingLinesIndexes, -} from 'utils'; + +import { useWarehouseTransferTableColumns } from '../utils'; +import { useFetchItemWarehouseQuantity } from './hooks'; +import { useDeepCompareEffect } from 'hooks/utils'; + +import { saveInvoke } from 'utils'; +import { mutateTableCell, mutateTableRow, deleteTableRow } from './utils'; + /** * Warehouse transfer form entries table. */ @@ -21,34 +19,63 @@ export default function WarehouseTransferFormEntriesTable({ defaultEntry, onUpdateData, errors, + + destinationWarehouseId, + sourceWarehouseId, }) { + // Fetch the table row. + const { newRowMeta, setTableRow, resetTableRow, cellsLoading } = + useFetchItemWarehouseQuantity(); + // Retrieve the warehouse transfer table columns. 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. const handleUpdateData = React.useCallback( - (rowIndex, columnId, value) => { - const newRows = 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); + (rowIndex, columnId, itemId) => { + if (columnId === 'item_id') { + setTableRow({ + rowIndex, + columnId, + itemId, + sourceWarehouseId, + destinationWarehouseId, + }); + } + const editCell = mutateTableCell(rowIndex, columnId, defaultEntry); + const newRows = editCell(itemId, entries); saveInvoke(onUpdateData, newRows); }, - [entries, defaultEntry, onUpdateData], + [ + entries, + defaultEntry, + onUpdateData, + destinationWarehouseId, + sourceWarehouseId, + setTableRow, + ], ); // Handles click remove datatable row. const handleRemoveRow = React.useCallback( (rowIndex) => { - const newRows = compose( - // Ensure minimum lines count. - updateMinEntriesLines(4, defaultEntry), - // Remove the line by the given index. - updateRemoveLineByIndex(rowIndex), - )(entries); - + const newRows = deleteTableRow(rowIndex, defaultEntry, entries); saveInvoke(onUpdateData, newRows); }, [entries, defaultEntry, onUpdateData], @@ -58,12 +85,17 @@ export default function WarehouseTransferFormEntriesTable({ ); diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/hooks.ts b/src/containers/WarehouseTransfers/WarehouseTransferForm/hooks.ts new file mode 100644 index 000000000..ef462a7c2 --- /dev/null +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/hooks.ts @@ -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(null); + + // Table cells loading coords. + const [cellsLoading, setCellsLoading] = React.useState( + 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, + }; +}; diff --git a/src/containers/WarehouseTransfers/WarehouseTransferForm/utils.js b/src/containers/WarehouseTransfers/WarehouseTransferForm/utils.js index d03dda138..9c13f8580 100644 --- a/src/containers/WarehouseTransfers/WarehouseTransferForm/utils.js +++ b/src/containers/WarehouseTransfers/WarehouseTransferForm/utils.js @@ -2,16 +2,25 @@ import React from 'react'; import moment from 'moment'; import intl from 'react-intl-universal'; import { Intent } from '@blueprintjs/core'; -import { useFormikContext } from 'formik'; -import { AppToaster } from 'components'; import { omit } from 'lodash'; +import { useFormikContext } from 'formik'; +import * as R from 'ramda'; +import { AppToaster } from 'components'; +import { + orderingLinesIndexes, + updateAutoAddNewLine, + updateTableCell, +} from 'utils'; import { compose, transformToForm, repeatValue, transactionNumber, defaultFastFieldShouldUpdate, + updateTableRow, + updateMinEntriesLines, + updateRemoveLineByIndex, } from 'utils'; // import { defaultFastFieldShouldUpdate } from 'utils'; @@ -88,6 +97,10 @@ export const useObserveTransferNoSettings = (prefix, nextNumber) => { export const entriesFieldShouldUpdate = (newProps, oldProps) => { return ( 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) ); }; @@ -102,7 +115,7 @@ export function transformValueToRequest(values) { return { ...values, 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); +}); diff --git a/src/containers/WarehouseTransfers/utils.js b/src/containers/WarehouseTransfers/utils.js index 1c8713416..79f8ba72c 100644 --- a/src/containers/WarehouseTransfers/utils.js +++ b/src/containers/WarehouseTransfers/utils.js @@ -1,5 +1,6 @@ import React from 'react'; import intl from 'react-intl-universal'; +import { find, get } from 'lodash'; import { Tooltip, Button, Intent, Position } from '@blueprintjs/core'; 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. * @returns @@ -82,6 +103,7 @@ export const useWarehouseTransferTableColumns = () => { Header: 'Source Warehouse', accessor: 'source_warehouse', disableSortBy: true, + Cell: SourceWarehouseAccessorCell, align: 'right', width: 120, }, @@ -89,6 +111,7 @@ export const useWarehouseTransferTableColumns = () => { id: 'destination_warehouse', Header: 'Destination Warehouse', accessor: 'destination_warehouse', + Cell: DistentionWarehouseAccessorCell, disableSortBy: true, align: 'right', width: 120,