Skip to content

Commit

Permalink
display if an order has been printed next to the list item
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimir-8 committed Jun 1, 2024
1 parent 35d2710 commit 3e7105b
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 71 deletions.
3 changes: 2 additions & 1 deletion src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@
"SCAN_FOR_PRINTERS": "Tap to scan",
"SEARCH_WITH_ADDRESS": "Search « {{address}} »",
"RESTAURANT_ORDER_CONNECT_PRINTER": "Connect a printer",
"RESTAURANT_ORDER_PRINTING": "Printing order {{number}} (#{{id}})",
"RESTAURANT_ORDER_PRINTING": "Printing order",
"RESTAURANT_ORDER_FAILED_TO_PRINT": "Failed to print",
"SWIPE_TO_ACCEPT_REFUSE": "Slide to the right to accept, to the left to refuse",
"ADD_COUPON": "Add a voucher code",
"VOUCHER_CODE": "Voucher code",
Expand Down
119 changes: 94 additions & 25 deletions src/navigation/restaurant/components/OrderListItem.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import { HStack, Icon, Text } from 'native-base';
import React from 'react';
import {
ActivityIndicator,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native';
import { Icon, Row, Text } from 'native-base';
import { useTranslation } from 'react-i18next';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import moment from 'moment/moment';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { useDispatch, useSelector } from 'react-redux';
import OrderNumber from '../../../components/OrderNumber';
import OrderFulfillmentMethodIcon from '../../../components/OrderFulfillmentMethodIcon';
import { PaymentMethodInfo } from '../../../components/PaymentMethodInfo';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import {
selectAutoAcceptOrdersEnabled,
selectOrderIdsFailedToPrint,
selectPrintingOrderId,
} from '../../../redux/Restaurant/selectors';
import { formatPrice } from '../../../utils/formatting';
import moment from 'moment/moment';
import Ionicons from 'react-native-vector-icons/Ionicons';
import React from 'react';
import { useDispatch } from 'react-redux';
import {
acceptOrder,
finishPreparing,
Expand Down Expand Up @@ -45,9 +56,64 @@ const styles = StyleSheet.create({
moveForwardIcon: {
color: 'white',
},
statusContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: 10,
paddingHorizontal: 20,
borderBottomWidth: StyleSheet.hairlineWidth,
},
printing: {
backgroundColor: '#26de81',
borderBottomColor: '#1cb568',
},
failedToPrint: {
backgroundColor: '#f7b731',
borderBottomColor: '#eca309',
},
statusText: {
color: 'white',
textAlign: 'center',
fontSize: 14,
fontWeight: '700',
},
});

function OrderPrintStatus({ order }) {
const printingOrderId = useSelector(selectPrintingOrderId);
const orderIdsFailedToPrint = useSelector(selectOrderIdsFailedToPrint);

const isPrinting = order['@id'] === printingOrderId;
const isFailedToPrint = orderIdsFailedToPrint.indexOf(order['@id']) !== -1;

const { t } = useTranslation();

if (isPrinting) {
return (
<View style={[styles.statusContainer, styles.printing]}>
<Text style={styles.statusText}>{t('RESTAURANT_ORDER_PRINTING')}</Text>
<ActivityIndicator size="small" color="white" animating={true} />
</View>
);
}

if (isFailedToPrint) {
return (
<View style={[styles.statusContainer, styles.failedToPrint]}>
<Text style={styles.statusText}>
{t('RESTAURANT_ORDER_FAILED_TO_PRINT')}
</Text>
</View>
);
}

return null;
}

export default function OrderListItem({ order, onItemClick }) {
const autoAcceptOrdersEnabled = useSelector(selectAutoAcceptOrdersEnabled);

const dispatch = useDispatch();

const isActionable = [STATE.NEW, STATE.ACCEPTED, STATE.STARTED].includes(
Expand All @@ -56,24 +122,27 @@ export default function OrderListItem({ order, onItemClick }) {

return (
<View style={styles.item}>
<TouchableOpacity
style={styles.content}
onPress={() => onItemClick(order)}>
<HStack alignItems="center">
<View style={styles.number}>
<OrderNumber order={order} />
</View>
<OrderFulfillmentMethodIcon order={order} small />
<PaymentMethodInfo
fullDetail={false}
paymentMethod={order.paymentMethod}
/>
{order.notes ? (
<Icon as={FontAwesome} name="comments" size="xs" />
) : null}
</HStack>
<Text>{`${formatPrice(order.itemsTotal)}`}</Text>
<Text>{moment.parseZone(order.pickupExpectedAt).format('LT')}</Text>
<TouchableOpacity style={{ flex: 1 }} onPress={() => onItemClick(order)}>
<View style={styles.content}>
<Row alignItems="center">
<View style={styles.number}>
<OrderNumber order={order} />
</View>
<OrderFulfillmentMethodIcon order={order} small />
<PaymentMethodInfo
fullDetail={false}
paymentMethod={order.paymentMethod}
/>
{order.notes ? (
<Icon as={FontAwesome} name="comments" size="xs" />
) : null}
</Row>
<Text>{`${formatPrice(order.itemsTotal)}`}</Text>
<Text>{moment.parseZone(order.pickupExpectedAt).format('LT')}</Text>
</View>
{autoAcceptOrdersEnabled && order.state === STATE.ACCEPTED ? (
<OrderPrintStatus order={order} />
) : null}
</TouchableOpacity>
{isActionable ? (
<TouchableOpacity
Expand Down
30 changes: 2 additions & 28 deletions src/navigation/restaurant/components/OrdersToPrintQueue.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import React, { useEffect } from 'react';
import {
ActivityIndicator,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Text } from 'native-base';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import {
selectAutoAcceptOrdersEnabled,
selectIsPrinterConnected,
selectOrderById,
selectOrderIdsToPrint,
selectPrintingOrderId,
} from '../../../redux/Restaurant/selectors';
Expand Down Expand Up @@ -53,11 +47,7 @@ function usePrinter() {
export default function OrdersToPrintQueue() {
const autoAcceptOrdersEnabled = useSelector(selectAutoAcceptOrdersEnabled);

const { printerConnected, printingOrderId } = usePrinter();

const printingOrder = useSelector(state =>
selectOrderById(state, printingOrderId),
);
const { printerConnected } = usePrinter();

const { t } = useTranslation();

Expand All @@ -75,18 +65,6 @@ export default function OrdersToPrintQueue() {
<Text style={styles.text}>{t('RESTAURANT_ORDER_CONNECT_PRINTER')}</Text>
</TouchableOpacity>
);
} else if (printingOrder) {
return (
<View style={[styles.container, styles.printing]}>
<Text style={styles.text}>
{t('RESTAURANT_ORDER_PRINTING', {
number: printingOrder.number,
id: printingOrder.id,
})}
</Text>
<ActivityIndicator size="small" color="white" animating={true} />
</View>
);
} else {
return null;
}
Expand All @@ -105,10 +83,6 @@ const styles = StyleSheet.create({
backgroundColor: '#f7b731',
borderBottomColor: '#eca309',
},
printing: {
backgroundColor: '#26de81',
borderBottomColor: '#1cb568',
},
text: {
color: 'white',
textAlign: 'center',
Expand Down
93 changes: 77 additions & 16 deletions src/redux/Restaurant/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,20 @@ const initialState = {
isSunmiPrinter: false,
bluetoothStarted: false,
loopeatFormats: {},
orderIdsToPrint: [],
/**
* {
* [orderId]: {
* copiesToPrint: number,
* failedAttempts: number,
* }
* }
*/
ordersToPrint: {},
printingOrderId: null,
preferences: {
printOrdersNumberOfCopies: 1,
printOrdersMaxFailedAttempts: 3,
},
};

const spliceOrders = (state, payload) => {
Expand Down Expand Up @@ -181,14 +193,21 @@ const spliceProductOptions = (state, payload) => {

function updateOrdersToPrint(state, orderId) {
if (state.restaurant.autoAcceptOrdersEnabled) {
if (state.orderIdsToPrint.includes(orderId)) {
if (state.ordersToPrint[orderId]) {
return state;
} else {
return {
...state,
orderIdsToPrint: state.orderIdsToPrint.concat(orderId),
};
}

return {
...state,
ordersToPrint: {
...state.ordersToPrint,
[orderId]: {
copiesToPrint: state.preferences.printOrdersNumberOfCopies,
failedAttempts: 0,
},
},
};

} else {
return state;
}
Expand Down Expand Up @@ -531,20 +550,62 @@ export default (state = initialState, action = {}) => {
printingOrderId: action.payload['@id'],
};

case printFulfilled.type:
return {
...state,
orderIdsToPrint: state.orderIdsToPrint.filter(
orderId => orderId !== action.payload['@id'],
),
printingOrderId: null,
};
case printFulfilled.type: {
const orderId = action.payload['@id'];
const printTask = state.ordersToPrint[orderId];

if (!printTask) {
return state;
}

if (printTask.copiesToPrint > 1) {
// We have more copies to print
return {
...state,
printingOrderId: null,
ordersToPrint: {
...state.ordersToPrint,
[orderId]: {
...printTask,
copiesToPrint: printTask.copiesToPrint - 1,
failedAttempts: 0,
},
},
};
} else {
// We have printed all needed copies

const ordersToPrint = { ...state.ordersToPrint };
delete ordersToPrint[orderId];

return {
...state,
printingOrderId: null,
ordersToPrint: ordersToPrint,
};
}
}

case printRejected.type: {
const orderId = action.payload['@id'];
const printTask = state.ordersToPrint[orderId];

if (!printTask) {
return state;
}

case printRejected.type:
return {
...state,
printingOrderId: null,
ordersToPrint: {
...state.ordersToPrint,
[orderId]: {
...printTask,
failedAttempts: printTask.failedAttempts + 1,
},
},
};
}

case BLUETOOTH_STARTED:
return {
Expand Down
39 changes: 38 additions & 1 deletion src/redux/Restaurant/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,44 @@ export const selectIsPrinterConnected = createSelector(
(printer, isSunmiPrinter) => Boolean(printer) || isSunmiPrinter,
);

export const selectOrderIdsToPrint = state => state.restaurant.orderIdsToPrint;
const selectOrdersToPrint = state => state.restaurant.ordersToPrint;

const selectPrintOrdersMaxFailedAttempts = state =>
state.restaurant.preferences.printOrdersMaxFailedAttempts;

export const selectOrderIdsToPrint = createSelector(
selectOrdersToPrint,
selectPrintOrdersMaxFailedAttempts,
(ordersToPrint, printOrdersMaxFailedAttempts) => {
const orderIdsToPrint = [];

Object.keys(ordersToPrint).forEach(orderId => {
const printTask = ordersToPrint[orderId];
if (printTask.failedAttempts <= printOrdersMaxFailedAttempts) {
orderIdsToPrint.push(orderId);
}
});

return orderIdsToPrint;
},
);

export const selectOrderIdsFailedToPrint = createSelector(
selectOrdersToPrint,
selectPrintOrdersMaxFailedAttempts,
(ordersToPrint, printOrdersMaxFailedAttempts) => {
const orderIdsFailedToPrint = [];

Object.keys(ordersToPrint).forEach(orderId => {
const printTask = ordersToPrint[orderId];
if (printTask.failedAttempts > printOrdersMaxFailedAttempts) {
orderIdsFailedToPrint.push(orderId);
}
});

return orderIdsFailedToPrint;
},
);

export const selectPrintingOrderId = state => state.restaurant.printingOrderId;

Expand Down

0 comments on commit 3e7105b

Please sign in to comment.