Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import TransferDetails from './screens/TransfersDetails';
import ViewAvailableItem from './screens/ViewAvailableItem';
import ApiClient from './utils/ApiClient';
import Theme from './utils/Theme';
import EntryScreen from './screens/SortationNew/EntryScreen';

const Stack = createStackNavigator();
export interface OwnProps {
Expand Down Expand Up @@ -291,6 +292,7 @@ class Main extends Component<Props, State> {
options={{ title: 'Packing Location' }}
/>
<Stack.Screen name="AppInfo" component={AppInfoScreen} options={{ title: 'App Info' }} />
<Stack.Screen name="NewSortation" component={EntryScreen} options={{ title: 'Sortation (New)' }} />
<Stack.Screen
name="Sortation"
component={SortationEntryScreen}
Expand Down
60 changes: 49 additions & 11 deletions src/components/ScannerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import {
AppState,
InteractionManager,
Keyboard,
KeyboardTypeOptions,
TextInput as NativeTextInput,
StyleProp,
ViewStyle
} from 'react-native';
import { TextInput as PaperTextInput } from 'react-native-paper';

import { IconSource } from 'react-native-paper/lib/typescript/components/Icon';
import IconKeyboard from '../assets/images/icon_keyboard.svg';
import IconScanAction from '../assets/images/icon_scan_action.svg';
import { appConfig } from '../constants';
import Theme from '../utils/Theme';

type ScannerInputProps = {
value: string;
Expand All @@ -25,12 +27,18 @@ type ScannerInputProps = {
* Useful if there is a custom non-native modal open.
*/
isEnabled?: boolean;
placeholder?: string;
/**
* Time in milliseconds to wait after the last input before auto-submitting.
* Set to 0 or null to disable auto-submit.
* @default appConfig.DEFAULT_DEBOUNCE_TIME
*/
autoSubmitTimeout?: number;
left?: React.ReactNode;
leftIcon: IconSource;
right?: React.ReactNode;
theme?: any;
keyboardType?: KeyboardTypeOptions;
};

/**
Expand All @@ -55,10 +63,16 @@ export const ScannerInput = forwardRef<NativeTextInput, ScannerInputProps>(
value,
onChange,
onSubmit,
label = 'Scan Barcode',
label = 'Barcode',
style,
isEnabled = true,
autoSubmitTimeout = appConfig.DEFAULT_DEBOUNCE_TIME
placeholder = 'Scan...',
leftIcon = 'barcode',
autoSubmitTimeout = appConfig.DEFAULT_DEBOUNCE_TIME,
left,
right,
theme,
keyboardType
},
ref
) => {
Expand Down Expand Up @@ -121,8 +135,8 @@ export const ScannerInput = forwardRef<NativeTextInput, ScannerInputProps>(

// Auto-submit after timeout
useEffect(() => {
// Don't auto-submit if disabled
if (!autoSubmitTimeout) {
// Don't auto-submit if disabled or screen not focused
if (!autoSubmitTimeout || !shouldBeFocused) {
return;
}

Expand All @@ -140,14 +154,14 @@ export const ScannerInput = forwardRef<NativeTextInput, ScannerInputProps>(

const timer = setTimeout(() => {
const trimmed = value.trim();
if (trimmed && trimmed !== lastSubmittedValue.current) {
if (trimmed && trimmed !== lastSubmittedValue.current && shouldBeFocused) {
lastSubmittedValue.current = trimmed;
onSubmit(trimmed);
}
}, autoSubmitTimeout);

return () => clearTimeout(timer);
}, [value, autoSubmitTimeout, onSubmit]);
}, [value, autoSubmitTimeout, onSubmit, shouldBeFocused]);

const handleBlur = () => {
if (shouldBeFocused) {
Expand Down Expand Up @@ -204,18 +218,42 @@ export const ScannerInput = forwardRef<NativeTextInput, ScannerInputProps>(
label={label}
value={value}
style={style}
theme={theme}
// Keep keyboard hidden
showSoftInputOnFocus={showKeyboard}
autoCorrect={false}
autoCompleteType="off"
placeholder={placeholder}
keyboardType={keyboardType}
importantForAutofill="no"
blurOnSubmit={false}
disabled={!isEnabled}
returnKeyType="done"
// @ts-ignore
left={<PaperTextInput.Icon name={() => <IconScanAction height={24} width={24} />} />}
left={
left || (
// @ts-ignore
<PaperTextInput.Icon
disabled={!isEnabled}
name={leftIcon}
color={isEnabled ? theme?.colors?.primary : Theme.colors.disabled}
/>
)
}
right={
// @ts-ignore
<PaperTextInput.Icon name={() => <IconKeyboard height={24} width={24} />} onPress={handleKeyboardPress} />
right || (
// @ts-ignore
<PaperTextInput.Icon
disabled={!isEnabled}
name={({ color }) => (
<IconKeyboard
height={24}
width={24}
fill={isEnabled ? theme?.colors?.primary || color : Theme.colors.disabled}
/>
)}
onPress={handleKeyboardPress}
/>
)
}
onBlur={handleBlur}
onFocus={() => {}}
Expand Down
5 changes: 1 addition & 4 deletions src/redux/sagas/putaway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,14 @@ function* createPutawayOder(action: any) {

function* patchPutawayTask(action: any) {
try {
yield put(showScreenLoading('Submitting...'));
const { facilityId, putawayItemId, payload } = action.payload;
const response = yield call(api.patchPutawayTask, facilityId, putawayItemId, payload);
yield put({
type: PATCH_PUTAWAY_TASK_REQUEST_SUCCESS,
payload: response.data
});
yield put(hideScreenLoading());
yield action.callback({ success: true, data: response.data });
} catch (error) {
yield put(hideScreenLoading());
yield action.callback({
error: true,
errorMessage: error.message
Expand All @@ -121,7 +118,7 @@ function* patchPutawayTask(action: any) {

function* getPutawayDetailsByContainerId(action: any) {
try {
const location = yield select(userLocation)
const location = yield select(userLocation);
if (!location || !location.id) {
return;
}
Expand Down
7 changes: 7 additions & 0 deletions src/screens/Dashboard/dashboardData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ const dashboardEntries: DashboardEntry[] = [
icon: IconSortation,
navigationScreenName: 'Sortation'
},
{
key: 'new-sortation',
screenName: 'Sortation (New)',
entryDescription: 'Manage sortation tasks and workflows',
icon: IconSortation,
navigationScreenName: 'NewSortation'
},
{
key: 'putaway',
screenName: 'Putaway',
Expand Down
45 changes: 45 additions & 0 deletions src/screens/SortationNew/EntryScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useNavigation } from '@react-navigation/native';
import React from 'react';

import SortationForm from './SortationForm';
import SortationSummary from './SortationSummary';
import { useSortation } from './useSortation';

export default function EntryScreen() {
const navigation = useNavigation();
const { state, actions } = useSortation();

if (state.isSorted) {
return (
<SortationSummary
productBarcode={state.productBarcode}
quantity={state.quantity}
containerBarcode={state.containerBarcode}
storageLocationBarcode={state.storageLocationBarcode}
onReset={actions.onReset}
onToDashboard={() => navigation.navigate('Dashboard' as never)}
/>
);
}

return (
<SortationForm
currentStep={state.currentStep}
productBarcode={state.productBarcode}
setProductBarcode={actions.setProductBarcode}
handleProductScan={actions.handleProductScan}
quantity={state.quantity}
setQuantity={actions.setQuantity}
setCurrentStep={actions.setCurrentStep}
containerBarcode={state.containerBarcode}
setContainerBarcode={actions.setContainerBarcode}
storageLocationBarcode={state.storageLocationBarcode}
handleSubmit={actions.handleSubmit}
handleBack={actions.handleBack}
handleNext={actions.handleNext}
loading={state.loading}
error={state.error}
task={state.task}
/>
);
}
104 changes: 104 additions & 0 deletions src/screens/SortationNew/SortationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import { ScrollView, View } from 'react-native';
import { Button } from 'react-native-paper';
import { ScannerInput } from '../../components/ScannerInput';
import { SortationTask } from '../../types/sortation';
import { StepInput } from './StepInput';
import styles from './styles';

type SortationFormProps = {
currentStep: number;
productBarcode: string;
setProductBarcode: (v: string) => void;
handleProductScan: (v: string) => void;
quantity: string;
setQuantity: (v: string) => void;
setCurrentStep: (v: number) => void;
containerBarcode: string;
setContainerBarcode: (v: string) => void;
storageLocationBarcode: string;
handleSubmit: () => void;
handleBack: () => void;
handleNext: () => void;
loading: boolean;
error: string | null;
task: SortationTask | null;
};

const SortationForm: React.FC<SortationFormProps> = ({
currentStep,
productBarcode,
setProductBarcode,
handleProductScan,
quantity,
setQuantity,
containerBarcode,
setContainerBarcode,
storageLocationBarcode,
handleBack,
handleNext,
loading,
error,
task
}) => {
return (
<ScrollView keyboardShouldPersistTaps="handled" style={styles.screen}>
<StepInput
label="Product Barcode"
icon="package-variant"
value={productBarcode}
isActive={currentStep === 1}
error={error}
onChange={setProductBarcode}
onSubmit={handleProductScan}
/>

<StepInput
label="Quantity"
icon="layers-outline"
value={quantity}
placeholder={task?.quantity?.toString()}
keyboardType="numeric"
isActive={currentStep === 2}
error={error}
onChange={setQuantity}
onSubmit={handleNext}
/>

<StepInput
label="Container Barcode"
icon="package-variant-closed"
value={containerBarcode}
placeholder={task?.container?.locationNumber}
isActive={currentStep === 3}
error={error}
onChange={setContainerBarcode}
onSubmit={handleNext}
/>

<View style={styles.formRow}>
<ScannerInput
label="Storage Location"
// @ts-ignore
leftIcon="map-marker"
value={storageLocationBarcode}
isEnabled={false}
autoSubmitTimeout={0}
onChange={() => {}}
onSubmit={() => {}}
/>
</View>

<View style={styles.buttonRow}>
<Button mode="outlined" style={styles.buttonLeft} disabled={currentStep === 4 || loading} onPress={handleBack}>
Back
</Button>
<Button mode="contained" loading={loading} style={styles.buttonRight} disabled={loading} onPress={handleNext}>
{currentStep === 4 ? 'Confirm' : currentStep === 3 ? 'Review' : 'Next'}
</Button>
</View>
</ScrollView>
);
};

export default SortationForm;
Loading