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