Skip to content
Open
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
14 changes: 9 additions & 5 deletions src/apis/picking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,20 @@ export function getPickTasksApi(facilityId: string, params?: Partial<PickTaskPar
}

// Fetch all open pick tasks (across every queue type) for the discrete picking order list.
export function getOpenPickTasksApi(facilityId: string) {
// When excludeAssignedRequisitions is true, the backend skips pick tasks already assigned to other users.
export function getOpenPickTasksApi(facilityId: string, excludeAssignedRequisitions?: boolean) {
const statuses = ['PENDING', 'PICKING'];
const query = statuses.map((status) => `status=${encodeURIComponent(status)}`);

return ApiClient.get(
`/facilities/${facilityId}/pick-tasks?${statuses.map((status) => `status=${encodeURIComponent(status)}`).join('&')}`
);
if (excludeAssignedRequisitions !== undefined) {
query.push(`excludeAssignedRequisitions=${excludeAssignedRequisitions}`);
}

return ApiClient.get(`/facilities/${facilityId}/pick-tasks?${query.join('&')}`);
}

export function getPickTaskCountsApi(facilityId: string) {
return ApiClient.get(`/facilities/${facilityId}/pick-tasks/counts`);
return ApiClient.get(`/facilities/${facilityId}/pick-tasks/counts?excludeAssignedRequisitions=true`);
}

export function patchPickTaskApi(facilityId: string, taskId: string, params: PickTaskActionParams) {
Expand Down
2 changes: 2 additions & 0 deletions src/redux/actions/picking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export function getPickTasksAction(
}

export function getOpenPickTasksAction(
excludeAssignedRequisitions: boolean,
callback: (response: {
response?: {
data: PickTask[];
Expand All @@ -85,6 +86,7 @@ export function getOpenPickTasksAction(
) {
return {
type: GET_OPEN_PICK_TASKS_REQUEST,
payload: { excludeAssignedRequisitions },
callback
};
}
Expand Down
6 changes: 5 additions & 1 deletion src/redux/sagas/picking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ function* getOpenPickTasksAction(action: any) {
// No full-screen loading indicator here on purpose: the list screen renders its own
// inline skeleton / pull-to-refresh state so the screen never blocks on the fetch.
// @ts-ignore
const response = yield call(api.getOpenPickTasksApi, currentLocation.id);
const response = yield call(
api.getOpenPickTasksApi,
currentLocation.id,
action.payload?.excludeAssignedRequisitions
);
yield action.callback({ response });
yield put({ type: GET_OPEN_PICK_TASKS_REQUEST_SUCCESS, payload: response.data });
} catch (error) {
Expand Down
25 changes: 19 additions & 6 deletions src/screens/Picking/DiscretePickingListScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { navigate } from '../../NavigationService';
import { getOpenPickTasksAction } from '../../redux/actions/picking';
import { DiscretePickingOrder, PickTask } from '../../types/picking';
import { emptyStateMessage } from '../../utils/emptyStateMessage';
import { ToggleRow } from '../Dashboard/ToggleRow';
import { DELIVERY_TYPES } from './constants';
import DiscretePickingCardSkeleton from './DiscretePickingCardSkeleton';
import DiscretePickingFilterSkeleton from './DiscretePickingFilterSkeleton';
Expand All @@ -33,18 +34,19 @@ export default function DiscretePickingListScreen() {
const [tasks, setTasks] = useState<PickTask[]>([]);
const [searchTerm, setSearchTerm] = useState<string>('');
const [selectedQueueType, setSelectedQueueType] = useState<QueueTypeFilter>(ALL_QUEUE_TYPES);
const [excludeAssignedRequisitions, setExcludeAssignedRequisitions] = useState<boolean>(true);
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [isPullRefreshing, setIsPullRefreshing] = useState<boolean>(false);
const [hasLoaded, setHasLoaded] = useState<boolean>(false);

const fetchOrders = useCallback(
(fromPull = false) => {
(excludeAssignedRequisitionsParam: boolean, fromPull = false) => {
setIsRefreshing(true);
if (fromPull) {
setIsPullRefreshing(true);
}
dispatch(
getOpenPickTasksAction(({ response, errorMessage }) => {
getOpenPickTasksAction(excludeAssignedRequisitionsParam, ({ response, errorMessage }) => {
if (!errorMessage && response?.data) {
setTasks(response.data);
}
Expand All @@ -59,8 +61,8 @@ export default function DiscretePickingListScreen() {

useFocusEffect(
useCallback(() => {
fetchOrders();
}, [fetchOrders])
fetchOrders(excludeAssignedRequisitions);
}, [fetchOrders, excludeAssignedRequisitions])
);

const sortedOrders = useMemo(() => sortOrders(groupTasksIntoOrders(tasks)), [tasks]);
Expand Down Expand Up @@ -129,6 +131,15 @@ export default function DiscretePickingListScreen() {
})}
</ScrollView>
)}
{!isLoadingList && (
<View style={styles.showAssignedToggle}>
<ToggleRow
title="Show assigned orders"
value={!excludeAssignedRequisitions}
onValueChange={(value) => setExcludeAssignedRequisitions(!value)}
/>
</View>
)}
</View>

{isLoadingList ? (
Expand All @@ -137,7 +148,9 @@ export default function DiscretePickingListScreen() {
<FlatList
data={visibleOrders}
keyExtractor={(order) => order.requisitionId}
renderItem={({ item }) => <DiscretePickingOrderCard order={item} onPress={handleOrderPress} />}
renderItem={({ item }) => (
<DiscretePickingOrderCard order={item} showAssignee={!excludeAssignedRequisitions} onPress={handleOrderPress} />
)}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag"
contentContainerStyle={styles.listContent}
Expand All @@ -150,7 +163,7 @@ export default function DiscretePickingListScreen() {
description={emptyStateMessage('orders', searchTerm, 'No open orders ready for picking')}
/>
}
onRefresh={() => fetchOrders(true)}
onRefresh={() => fetchOrders(excludeAssignedRequisitions, true)}
/>
)}
</View>
Expand Down
8 changes: 8 additions & 0 deletions src/screens/Picking/DiscretePickingOrderCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function DiscretePickingOrderCard({ order, onPress }: Props) {
? DELIVERY_TYPE_LABELS[order.deliveryTypeCode] ?? order.deliveryTypeCode
: null;
const lineCountLabel = order.taskCount === 1 ? 'Line' : 'Lines';
const assigneeName = order.assignee ? `${order.assignee.firstName} ${order.assignee.lastName}`.trim() : null;

return (
<Card style={LayoutStyle.listItemContainer} onPress={() => onPress(order)}>
Expand Down Expand Up @@ -75,6 +76,13 @@ export default function DiscretePickingOrderCard({ order, onPress }: Props) {
{lineCountLabel}: <Text style={[styles.chipText, styles.fontBold]}>{order.taskCount}</Text>
</Text>
</Chip>
{assigneeName ? (
<Chip icon="account" style={styles.chipDefault}>
<Text style={styles.chipText}>
Assigned to: <Text style={[styles.chipText, styles.fontBold]}>{assigneeName}</Text>
</Text>
</Chip>
) : null}
</View>
</Card.Content>
</Card>
Expand Down
1 change: 1 addition & 0 deletions src/screens/Picking/discretePickingLib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function groupTasksIntoOrders(tasks: PickTask[]): DiscretePickingOrder[]
destination: task.destination,
destinationLocationType: task.destinationLocationType,
deliveryTypeCode: task.deliveryTypeCode,
assignee: task.assignee,
priority: task.priority,
taskCount: 0,
inProgress: false,
Expand Down
3 changes: 3 additions & 0 deletions src/screens/Picking/discretePickingStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export default StyleSheet.create({
flexDirection: 'row',
overflow: 'hidden'
},
showAssignedToggle: {
paddingHorizontal: Theme.spacing.medium
},
filterChipSkeleton: {
height: 32,
borderRadius: 12,
Expand Down
1 change: 1 addition & 0 deletions src/types/picking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export type DiscretePickingOrder = {
destination?: string;
destinationLocationType?: string;
deliveryTypeCode?: DeliveryTypeCode;
assignee?: Person | null;
/** requisition.priority (lower = higher priority) */
priority?: number;
/** number of open pick tasks (line items) in this order */
Expand Down