Controller Component

Controller Component can be used to create a page level custom component (one time) for some advanced use cases. The below example controller code exports a Controller Component named QuickEntry that renders couple quick entry input fields that makes parallel async calls to cloud functions and create records on tab out enabling users to perform high speed data entry.

Page Controller
import type { Store, BaseFunctionProps } from 'cloudio';
import { useStringAttribute, useNumberAttribute } from 'cloudio';
import { OmsPreOrderLines } from '@cloudio-saas/datasource-types';
import React, { useRef } from 'react';
import { Box, TextField } from '@mui/material';
import platform from 'platform';

async function createOrUpdateLine(
  linesStore: Store<OmsPreOrderLines>,
  id: string,
  resp: OmsPreOrderLines,
): Promise<string> {
  if (id) {
    // update record
    linesStore.updateRecord(id, resp);
  } else {
    // create record
    const newid = await linesStore.createNew({
      partialRecord: resp,
      addOnTop: true,
      rs: 'I',
    });
    if (!newid) {
      throw new Error('Failed to create new record!');
    }
    id = newid;
  }
  return id;
}

async function onQuickEntryQtyChange({
  appUid,
  pageId,
  itemId,
  platform,
}: BaseFunctionProps) {
  // get the stores
  const quickEntryStore = platform.getStore<OmsPreOrderLines>(
    appUid,
    pageId,
    'quickEntryAlias',
  );
  const linesStore = platform.getStore<OmsPreOrderLines>(
    appUid,
    pageId,
    'omsPreOrderLinesAlias',
  );
  if (!quickEntryStore || !linesStore) {
    platform.showError(`Store not found for ${itemId}`);
    return;
  }
  // get the current quick entry row
  const quickRow = quickEntryStore.getCurrentRecord();
  const { itemCode, itemQty } = quickRow;
  quickEntryStore.clearQuietyly().then(() => {
    quickEntryStore.createNew({ partialRecord: {}, rs: 'N' });
  });
  let id = '';
  // invoke cloud functions in parallel
  await Promise.all([
    platform
      .invokeCloudFunction(appUid, 'get-oms-item-details', {
        itemCode,
        itemQty,
      })
      .then(async (resp: OmsPreOrderLines) => {
        const { itemCode, itemQty, itemDesc } = resp;
        id = await createOrUpdateLine(linesStore, id, {
          itemCode,
          itemQty,
          itemDesc,
        });
        platform.redrawCanvasGrid(appUid, pageId, 'canvasGrid');
      }),
    platform
      .invokeCloudFunction(appUid, 'get-oms-item-price', { itemCode, itemQty })
      .then(async (resp: OmsPreOrderLines) => {
        const { sellPrice } = resp;
        id = await createOrUpdateLine(linesStore, id, {
          itemCode,
          itemQty,
          sellPrice,
        });
        platform.redrawCanvasGrid(appUid, pageId, 'canvasGrid');
      }),
  ]);
}

function QuickEntry(props: BaseFunctionProps) {
  // similar to useState hook in react for an attribute in the current record
  const [itemCode, setItemCode] = useStringAttribute('itemCode');
  const [itemQty, setItemQty] = useNumberAttribute('itemQty');
  // ref used for focus
  const ref = useRef<HTMLInputElement>(null);
  // ref to store the focus value
  const focusVal = useRef<number | undefined>(undefined);

  return (
    <Box sx={{ flex: 1, display: 'flex', minWidth: '400px', gap: '8px' }}>
      <TextField
        inputRef={ref}
        variant="standard"
        label="Item Code"
        value={itemCode ?? ''}
        onChange={(e) => {
          setItemCode(e.target.value);
        }}
        fullWidth
      />
      <TextField
        type="number"
        variant="standard"
        label="Item Qty"
        value={itemQty ?? ''}
        onChange={(e) => {
          let val: number | undefined = Number(e.target.value);
          if (Number.isNaN(val)) {
            val = undefined;
          }
          setItemQty(val);
        }}
        onFocus={() => {
          // store the existing value, so we can check against this in onBlur
          focusVal.current = itemQty;
        }}
        onBlur={(e) => {
          if (focusVal.current !== itemQty) {
            // value changed, create line
            onQuickEntryQtyChange(props);
            ref.current?.focus();
          }
        }}
        fullWidth
      />
    </Box>
  );
}

// must export a default object with all the functions to be used by this page
export default {
  QuickEntry,
};

Last updated