Skip to content
Merged
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
132 changes: 70 additions & 62 deletions src/screens/Picking/PickingPickTypeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DeliveryType, DeliveryTypeCode, DeliveryTypeOrderCount } from '../../ty
import Theme from '../../utils/Theme';
import { DELIVERY_TYPES, PRIORITY_LABELS } from './constants';
import { usePickingContext } from './PickingContext';
import PickingPickTypeSkeleton from './PickingPickTypeSkeleton';
import styles from './styles';

const NUMBER_OF_ORDERS_THRESHOLD = 10;
Expand All @@ -21,10 +22,12 @@ export default function PickingPickTypeScreen() {
const [deliveryType, setDeliveryType] = React.useState<DeliveryType | null>(DELIVERY_TYPES[0]);
const [numberOfOrdersToGroup, setNumberOfOrdersToGroup] = React.useState<string>('');
const [counts, setCounts] = React.useState<Record<string, DeliveryTypeOrderCount>>({});
const [hasLoadedCounts, setHasLoadedCounts] = React.useState<boolean>(false);

const fetchCounts = React.useCallback(() => {
dispatch(
getPickTaskCountsAction(({ response, errorMessage }) => {
setHasLoadedCounts(true);
if (errorMessage || !response?.data) {
Alert.alert('Error', 'Failed to load pick task counts. Please try again.');
return;
Comment on lines 27 to 33
Expand Down Expand Up @@ -99,69 +102,74 @@ export default function PickingPickTypeScreen() {
<Paragraph>Please select the appropriate pick type and specify the number of orders to group.</Paragraph>
</View>

<View style={styles.optionsCard}>
{DELIVERY_TYPES.map((item, index) => {
const selected = isSelected(item);
const count = counts[item.code];
const isEmpty = !count || count.availableCount === 0;
const priorityLabel = item.code === DeliveryTypeCode.DEFAULT ? undefined : PRIORITY_LABELS[item.priority];
const isLast = index === DELIVERY_TYPES.length - 1;

return (
<TouchableOpacity
key={item.label}
activeOpacity={0.7}
style={[styles.optionRow, isLast && styles.optionRowLast, selected && styles.optionRowSelected]}
onPress={() => setDeliveryType(item)}
{!hasLoadedCounts ? (
<PickingPickTypeSkeleton />
) : (
<>
<View style={styles.optionsCard}>
{DELIVERY_TYPES.map((item, index) => {
const selected = isSelected(item);
const count = counts[item.code];
const isEmpty = !count || count.availableCount === 0;
const priorityLabel = item.code === DeliveryTypeCode.DEFAULT ? undefined : PRIORITY_LABELS[item.priority];
const isLast = index === DELIVERY_TYPES.length - 1;

return (
<TouchableOpacity
key={item.label}
activeOpacity={0.7}
style={[styles.optionRow, isLast && styles.optionRowLast, selected && styles.optionRowSelected]}
onPress={() => setDeliveryType(item)}
>
Comment on lines +118 to +123
<RadioButton
value={item.code}
color={Theme.colors.primary}
status={selected ? 'checked' : 'unchecked'}
onPress={() => setDeliveryType(item)}
/>

<View style={styles.optionRowContent}>
<View>
<Paragraph style={styles.optionTitle}>{item.label}</Paragraph>
{priorityLabel ? <Paragraph style={styles.optionSubtitle}>{priorityLabel}</Paragraph> : null}
</View>

<View style={styles.countWrapper}>
<Paragraph style={[styles.countValue, isEmpty && styles.countValueEmpty]}>
{count ? count.availableCount : 0}
</Paragraph>
<Paragraph style={styles.countCaption}>Orders</Paragraph>
</View>
</View>
</TouchableOpacity>
);
})}
</View>

<View style={styles.formWrapper}>
<PaperTextInput
autoCompleteType="off"
style={[styles.marginTopSmall, styles.whiteInput]}
label="Orders to Group"
mode="outlined"
keyboardType="numeric"
value={numberOfOrdersToGroup}
onChangeText={setNumberOfOrdersToGroup}
onSubmitEditing={handleRetrievePickTasks}
/>

<Button
mode="contained"
style={styles.marginTop}
contentStyle={styles.ctaContent}
disabled={!deliveryType || !numberOfOrdersToGroup}
onPress={handleRetrievePickTasks}
>
<RadioButton
value={item.code}
color={Theme.colors.primary}
status={selected ? 'checked' : 'unchecked'}
onPress={() => setDeliveryType(item)}
/>

<View style={styles.optionRowContent}>
<View>
<Paragraph style={styles.optionTitle}>{item.label}</Paragraph>
{priorityLabel ? <Paragraph style={styles.optionSubtitle}>{priorityLabel}</Paragraph> : null}
</View>

{/* Count is always rendered: shows 0 until counts load */}
<View style={styles.countWrapper}>
<Paragraph style={[styles.countValue, isEmpty && styles.countValueEmpty]}>
{count ? count.availableCount : 0}
</Paragraph>
<Paragraph style={styles.countCaption}>Orders</Paragraph>
</View>
</View>
</TouchableOpacity>
);
})}
</View>

<View style={styles.formWrapper}>
<PaperTextInput
autoCompleteType="off"
style={[styles.marginTopSmall, styles.whiteInput]}
label="Orders to Group"
mode="outlined"
keyboardType="numeric"
value={numberOfOrdersToGroup}
onChangeText={setNumberOfOrdersToGroup}
onSubmitEditing={handleRetrievePickTasks}
/>

<Button
mode="contained"
style={styles.marginTop}
contentStyle={styles.ctaContent}
disabled={!deliveryType || !numberOfOrdersToGroup}
onPress={handleRetrievePickTasks}
>
Retrieve Pick Tasks
</Button>
</View>
Retrieve Pick Tasks
</Button>
</View>
</>
)}
</ScrollView>
);
}
43 changes: 43 additions & 0 deletions src/screens/Picking/PickingPickTypeSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { View } from 'react-native';

import { ShimmerBlock } from '../../components/ContentSkeleton';
import { DeliveryTypeCode } from '../../types/picking';
import { DELIVERY_TYPES } from './constants';
import styles from './styles';

export default function PickingPickTypeSkeleton() {
return (
<>
<View style={styles.optionsCard}>
{DELIVERY_TYPES.map((item, index) => {
const isLast = index === DELIVERY_TYPES.length - 1;
const hasPriorityLabel = item.code !== DeliveryTypeCode.DEFAULT;

return (
<View key={item.label} style={[styles.optionRow, isLast && styles.optionRowLast]}>
<ShimmerBlock style={styles.radioSkeleton} />

Comment on lines +18 to +20
<View style={styles.optionRowContent}>
<View>
<ShimmerBlock style={styles.optionTitleSkeleton} />
{hasPriorityLabel ? <ShimmerBlock style={styles.optionSubtitleSkeleton} /> : null}
</View>

<View style={styles.countWrapper}>
<ShimmerBlock style={styles.countValueSkeleton} />
<ShimmerBlock style={styles.countCaptionSkeleton} />
</View>
</View>
</View>
);
})}
</View>

<View style={styles.formWrapper}>
<ShimmerBlock style={[styles.marginTopSmall, styles.inputSkeleton]} />
<ShimmerBlock style={[styles.marginTop, styles.buttonSkeleton]} />
</View>
</>
);
}
40 changes: 40 additions & 0 deletions src/screens/Picking/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,46 @@ export default StyleSheet.create({
whiteInput: {
backgroundColor: 'white'
},
radioSkeleton: {
width: 20,
height: 20,
borderRadius: 10,
margin: 8
},
optionTitleSkeleton: {
width: 120,
height: 14,
borderRadius: 4,
marginVertical: 3
},
optionSubtitleSkeleton: {
width: 56,
height: 12,
borderRadius: 4,
marginVertical: 2
},
countValueSkeleton: {
width: 20,
height: 14,
borderRadius: 4,
marginVertical: 2
},
countCaptionSkeleton: {
width: 34,
height: 9,
borderRadius: 4,
marginVertical: 2
},
inputSkeleton: {
width: '100%',
height: 64,
borderRadius: 4
},
buttonSkeleton: {
width: '100%',
height: 48,
borderRadius: 4
},
ctaContent: {
height: 48
},
Expand Down