ordering-ui-react-native 0.22.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.22.00",
3
+ "version": "0.22.01",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -4,8 +4,10 @@ import {
4
4
  View,
5
5
  TouchableOpacity,
6
6
  ActivityIndicator,
7
+ Alert,
7
8
  } from 'react-native';
8
9
  import Clipboard from '@react-native-clipboard/clipboard';
10
+ import { StarPRNT } from 'react-native-star-prnt';
9
11
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
10
12
  import { useTheme } from 'styled-components/native';
11
13
  import {
@@ -35,6 +37,8 @@ import CountryPicker from 'react-native-country-picker-modal';
35
37
  import { NotFoundSource } from '../NotFoundSource';
36
38
  import { OrderHeaderComponent } from './OrderHeaderComponent';
37
39
  import { OrderContentComponent } from './OrderContentComponent';
40
+ import { _retrieveStoreData } from '../../providers/StoreUtil'
41
+ import { usePrinterCommands } from './usePrinterCommands'
38
42
 
39
43
  export const OrderDetailsUI = (props: OrderDetailsParams) => {
40
44
  const {
@@ -57,6 +61,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
57
61
  const [{ parsePrice, parseNumber, parseDate }] = useUtils();
58
62
  const [{ user, token }] = useSession();
59
63
  const [{ configs }] = useConfig();
64
+ const { generateCommands } = usePrinterCommands()
60
65
  const [, { showToast }] = useToast();
61
66
  const [unreadAlert, setUnreadAlert] = useState({
62
67
  business: false,
@@ -70,6 +75,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
70
75
  const [openModalForAccept, setOpenModalForAccept] = useState(false);
71
76
  const [openModalForMapView, setOpenModalForMapView] = useState(false);
72
77
  const [isDriverModalVisible, setIsDriverModalVisible] = useState(false);
78
+ const [printerSettings, setPrinterSettings] = useState('')
73
79
 
74
80
  if (order?.status === 7 || order?.status === 4) {
75
81
  if (drivers?.length > 0 && drivers) {
@@ -291,7 +297,40 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
291
297
  setOpenModalForAccept(true);
292
298
  };
293
299
 
300
+ const printAction = async (printerSettings: any, commands: any) => {
301
+ try {
302
+ var printResult = await StarPRNT.print(printerSettings?.emulation, commands, printerSettings?.portName);
303
+ Alert.alert(
304
+ t('PRINT_SUCCESS_TITLE', 'Print Success'),
305
+ t('PRINT_SUCCESS_SUBTITLE', `Go check your _printer_ printer!`).replace('_printer_', printerSettings?.model),
306
+ [
307
+ {text: 'OK', onPress: () => null},
308
+ ],
309
+ { cancelable: false }
310
+ )
311
+ } catch (e) {
312
+ Alert.alert(
313
+ t('PRINT_FAIL_TITLE', 'Connection Failed'),
314
+ t('PRINT_FAIL_SUBTITLE', 'Make sure your Star Printer is turned on and have thermal paper in it.'),
315
+ [
316
+ {text: 'OK', onPress: () => null},
317
+ ],
318
+ { cancelable: false }
319
+ )
320
+ }
321
+ }
322
+
294
323
  const handleViewSummaryOrder = () => {
324
+ if (printerSettings) {
325
+ const commands: any = generateCommands({
326
+ ...order,
327
+ orderStatus: getOrderStatus(order?.status, t)?.value
328
+ })
329
+ commands.push({ appendCutPaper: StarPRNT.CutPaperAction.PartialCutWithFeed })
330
+
331
+ printAction(printerSettings, commands)
332
+ return
333
+ }
295
334
  navigation?.navigate &&
296
335
  navigation.navigate('OrderSummary', {
297
336
  order,
@@ -372,6 +411,15 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
372
411
  }
373
412
  }, [driverLocation]);
374
413
 
414
+ useEffect(() => {
415
+ const getPrinterDefault = async () => {
416
+ const printer = await _retrieveStoreData('printer')
417
+ setPrinterSettings(printer)
418
+ }
419
+
420
+ getPrinterDefault()
421
+ }, [])
422
+
375
423
  const styles = StyleSheet.create({
376
424
  driverOff: {
377
425
  backgroundColor: theme.colors.notAvailable,
@@ -0,0 +1,140 @@
1
+ import { useConfig, useUtils, useLanguage} from 'ordering-components/native'
2
+
3
+ import { verifyDecimals, getProductPrice } from '../../utils';
4
+
5
+ /**
6
+ * Hook to create commands for star micronics printer using PassPRNT library
7
+ * @returns array of strings
8
+ */
9
+
10
+ export const usePrinterCommands = () => {
11
+ const [, t] = useLanguage()
12
+ const [{ configs }] = useConfig();
13
+ const [{ parsePrice, parseNumber, parseDate }] = useUtils();
14
+
15
+ const deliveryStatus: any = {
16
+ 1: t('DELIVERY', 'Delivery'),
17
+ 2: t('PICK_UP', 'Pick up'),
18
+ 3: t('EAT_IN', 'Eat In'),
19
+ 4: t('CURBSIDE', 'Curbside'),
20
+ 5: t('DRIVER_THRU', 'Driver thru'),
21
+ };
22
+
23
+ const walletName: any = {
24
+ cash: {
25
+ name: t('CASH_WALLET', 'Cash Wallet')
26
+ },
27
+ credit_point: {
28
+ name: t('POINTS_WALLET', 'Points Wallet')
29
+ }
30
+ }
31
+
32
+ const percentTip = (order: any) =>
33
+ parseInt(configs?.driver_tip_type?.value, 10) === 2 &&
34
+ !parseInt(configs?.driver_tip_use_custom?.value, 10) &&
35
+ verifyDecimals(order?.summary?.driver_tip, parseNumber);
36
+
37
+ const handlePaymethodsListString = (order: any) => {
38
+ const paymethodsList = order?.payment_events?.filter((item: any) => item.event === 'payment').map((paymethod: any) => {
39
+ return paymethod?.wallet_event
40
+ ? walletName[paymethod?.wallet_event?.wallet?.type]?.name
41
+ : t(paymethod?.paymethod?.gateway?.toUpperCase(), paymethod?.paymethod?.name)
42
+ })
43
+ return paymethodsList.join(', ')
44
+ }
45
+
46
+ const paymethodsLength = (order: any) => order?.payment_events?.filter((item: any) => item.event === 'payment')?.length
47
+
48
+ const customerName = (order: any) => `${order?.customer?.name ?? ''} ${order?.customer?.middle_name ?? ''} ${order?.customer?.lastname ?? ''} ${order?.customer?.second_lastname ?? ''}`?.replace(' ', ' ')?.trim() ?? ''
49
+
50
+ const generateCommands = (order: any) => {
51
+ let commands: any = [];
52
+
53
+ const textProps = {
54
+ fontSize: 12,
55
+ absolutePosition: 40
56
+ }
57
+
58
+ const generateProductsText = () => {
59
+ const list: any = []
60
+
61
+ if (order?.products.length) {
62
+ order?.products.map((product: any) => {
63
+ list.push(`${product?.quantity} ${product?.name} \t\t\t ${parsePrice(product.total ?? getProductPrice(product))}`)
64
+
65
+ product.options?.map((option: any) => {
66
+ list.push(`\t ${option.name}`)
67
+
68
+ option.suboptions?.map((suboption: any) => {
69
+ const { quantity, name, position, price } = suboption
70
+ const pos = position && position !== 'whole' ? `(${t(position.toUpperCase(), position)})` : ''
71
+ const string = name !== 'No'
72
+ ? pos
73
+ ? `${quantity} x ${name} ${pos} +${parsePrice(price)}`
74
+ : `${quantity} x ${name} +${parsePrice(price)}`
75
+ : 'No'
76
+
77
+ list.push(`\t\t ${string}`)
78
+ })
79
+ })
80
+
81
+ if (product.comment) {
82
+ list.push(`\t ${t('COMMENT', 'Comment')}`)
83
+ list.push(`\t\t ${product.comment}`)
84
+ }
85
+
86
+ list.push('------------------------------------------------',)
87
+ })
88
+ }
89
+
90
+ return list
91
+ }
92
+
93
+ const appends: any = [
94
+ `${t('ORDER_NO', 'Order No.')} ${order.id}`,
95
+ '\n', // need to replace with other break line command
96
+ order.orderStatus,
97
+ `${t('DELIVERY_TYPE', 'Delivery Type')}: ${deliveryStatus[order?.delivery_type]}`,
98
+ `${t('DELIVERY_DATE', 'Delivery Date')}: ${order?.delivery_datetime_utc ? parseDate(order?.delivery_datetime_utc) : parseDate(order?.delivery_datetime, { utc: false })}`,
99
+ `${t(`PAYMENT_METHOD${paymethodsLength(order) > 1 ? 'S' : ''}`, `Payment method${paymethodsLength(order) > 1 ? 's' : ''}`)}: ${handlePaymethodsListString(order)}`,
100
+ '\n', // need to replace with other break line command
101
+ `${t('CUSTOMER_DETAILS', 'Customer details')}`,
102
+ `${t('FULL_NAME', 'Full Name')}: ${customerName(order)}`,
103
+ `${t('EMAIL', 'Email')}: ${order?.customer?.email}`,
104
+ `${t('MOBILE_PHONE', 'Mobile Phone')}: ${order?.customer?.cellphone}`,
105
+ `${!!order?.customer?.phone ? `${t('MOBILE_PHONE', 'Mobile Phone')}: ${order?.customer?.phone}` : '\n'}`,
106
+ `${t('FULL_ADDRESS', 'Full Addres')}: ${order?.customer?.address}`,
107
+ `${!!order?.customer?.internal_number ? `${t('INTERNAL_NUMBER', 'Internal Number')}: ${order?.customer?.internal_number}` : '\n'}`,
108
+ `${!!order?.customer?.zipcode ? `${t('ZIPCODE', 'Zipcode')}: ${order?.customer?.zipcode}` : '\n'}`,
109
+ '\n', // need to replace with other break line command
110
+ `${t('BUSINESS_DETAILS', 'Business details')}`,
111
+ order?.business?.name,
112
+ order?.business?.email,
113
+ `${t('BUSINESS_PHONE', 'Business Phone')}: ${order?.business?.cellphone}`,
114
+ `${!!order?.business?.phone ? `${t('BUSINESS_PHONE', 'Business Phone')}: ${order?.business?.phone}` : '\n'}`,
115
+ `${t('ADDRESS', 'Address')}: ${order?.business?.address}`,
116
+ `${!!order?.business?.address_notes ? `${t('SPECIAL_ADDRESS', 'Special Address')}: ${order?.business?.address_notes}` : '\n'}`,
117
+ '\n', // need to replace with other break line command
118
+ `${t('ORDER_DETAILS', 'Order Details')}`,
119
+ ...generateProductsText(),
120
+ '\n', // need to replace with other break line command
121
+ `${t('SUBTOTAL', 'Subtotal')} \t\t\t ${parsePrice(order.tax_type === 1 ? (order?.summary?.subtotal + order?.summary?.tax) ?? 0 : order?.summary?.subtotal ?? 0)}`,
122
+ `${order?.summary?.discount > 0 ? `${order?.offer_type === 1 ? `${t('DISCOUNT', 'Discount')} (${verifyDecimals(order?.offer_rate, parsePrice)}%)` : t('DISCOUNT', 'Discount')} \t\t\t ${parsePrice(order?.summary?.discount)}` : '\n'}`,
123
+ `${order?.tax_type !== 1 ? `${t('TAX', 'Tax')} (${verifyDecimals(order?.summary?.tax_rate, parseNumber)}%) \t\t\t ${parsePrice(order?.summary?.tax ?? 0)}` : '\n'}`,
124
+ `${order?.summary?.delivery_price > 0 ? `${t('DELIVERY_FEE', 'Delivery Fee')} \t\t\t ${parsePrice(order?.summary?.delivery_price ?? 0)}` : '\n'}`,
125
+ `${t('DRIVER_TIP', 'Driver tip')} ${percentTip(order) ? `(${percentTip(order)}%)` : ''} \t\t\t ${parsePrice(order?.summary?.driver_tip ?? 0)}`,
126
+ `${t('SERVICE_FEE', 'Service Fee')} (${verifyDecimals(order?.summary?.service_fee, parseNumber)}%) \t\t\t ${parsePrice(order?.summary?.service_fee ?? 0)}`,
127
+ '------------------------------------------------',
128
+ `${t('TOTAL', 'Total')} \t\t\t ${parsePrice(order?.summary?.total ?? 0)}`
129
+ ]
130
+
131
+ commands = [
132
+ ...commands,
133
+ ...appends.map((append: any) => ({ appendBitmapText: append, ...textProps }))
134
+ ]
135
+
136
+ return commands
137
+ }
138
+
139
+ return { generateCommands }
140
+ }
@@ -0,0 +1,117 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native'
3
+ import SimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons'
4
+ import FeatherIcon from 'react-native-vector-icons/Feather'
5
+ import { useTheme } from 'styled-components/native'
6
+ import { useLanguage } from 'ordering-components/native'
7
+
8
+ import { _setStoreData, _retrieveStoreData } from '../../providers/StoreUtil'
9
+ import { Container } from './styles'
10
+ import { OText } from '../shared'
11
+
12
+ export const PrinterSettings = (props: any) => {
13
+ const { onClose } = props
14
+
15
+ const [currentPrinter, setCurrentPrinter] = useState<any>(null)
16
+
17
+ const [, t] = useLanguage()
18
+ const theme = useTheme()
19
+
20
+ const styles = StyleSheet.create({
21
+ icons: {
22
+ maxWidth: 40,
23
+ height: 40,
24
+ padding: 10,
25
+ alignItems: 'flex-end'
26
+ },
27
+ })
28
+
29
+ const printerList = [
30
+ { model: 'mPOP', emulation: 'StarPRNT', portName: 'BT:TSP100' },
31
+ { model: 'FVP10', emulation: 'StarLine', portName: 'BT:TSP100' },
32
+ { model: 'TSP100', emulation: 'StarGraphic', portName: 'BT:TSP100' },
33
+ { model: 'TSP65011', emulation: 'StarLine', portName: 'BT:TSP100' },
34
+ { model: 'TSP7001', emulation: 'StarLine', portName: 'BT:TSP100' },
35
+ { model: 'TSP80011', emulation: 'StarLine', portName: 'BT:TSP100' },
36
+ { model: 'SP700', emulation: 'StarDotimpact', portName: 'BT:TSP100' },
37
+ { model: 'SM-S210i', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
38
+ { model: 'SM-S220i', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
39
+ { model: 'SM-S230i', emulation: 'EscosMobile', portName: 'BT:TSP100' },
40
+ { model: 'SM-T300i/T300', emulation: 'EscPosMobile', portName: 'BT:TSP100' },
41
+ { model: 'SM-T400i', emulation: 'EscosMobile', portName: 'BT:TSP100' },
42
+ { model: 'SM-L200', emulation: 'StarPRNT', portName: 'BT:TSP100' },
43
+ { model: 'SM-L300', emulation: 'StarPRNT', portName: 'BT:TSP100' },
44
+ { model: 'BSC10', emulation: 'EscPos', portName: 'BT:TSP100' },
45
+ { model: 'SM-S210i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
46
+ { model: 'SM-S220i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
47
+ { model: 'SM-S230i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
48
+ { model: 'SM-T300i/T300 StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
49
+ { model: 'SM-T400i StarPRNT', emulation: 'StarPRNT', portName: 'BT:TSP100' },
50
+ ]
51
+
52
+ const handleClick = async (item: any) => {
53
+ setCurrentPrinter(item)
54
+ await _setStoreData('printer', item)
55
+ onClose && onClose()
56
+ }
57
+
58
+ useEffect(() => {
59
+ const getPrinterDefault = async () => {
60
+ const printer = await _retrieveStoreData('printer')
61
+ setCurrentPrinter(printer)
62
+ }
63
+
64
+ getPrinterDefault()
65
+ }, [])
66
+
67
+ return (
68
+ <ScrollView
69
+ showsVerticalScrollIndicator={false}
70
+ >
71
+ <OText size={24} style={{ paddingLeft: 30 }}>
72
+ {t('PRINTER_SETTINGS', 'Printer Settings')}
73
+ </OText>
74
+ <View style={{ padding: 30 }}>
75
+ {printerList.map((item: any, i: number) => (
76
+ <Container
77
+ key={i}
78
+ activeOpacity={1}
79
+ onPress={() => handleClick(item)}
80
+ >
81
+ <TouchableOpacity
82
+ activeOpacity={1}
83
+ style={{ flexDirection: 'row', alignItems: 'center' }}
84
+ onPress={() => handleClick(item)}
85
+ >
86
+ <SimpleLineIcons
87
+ name='printer'
88
+ color={theme.colors.textGray}
89
+ size={18}
90
+ style={{ ...styles.icons, color: currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray }}
91
+ />
92
+ <OText
93
+ size={18}
94
+ color={currentPrinter?.model === item.model ? theme.colors.primary : theme.colors.textGray}
95
+ >
96
+ {item.model}
97
+ </OText>
98
+ </TouchableOpacity>
99
+ {currentPrinter?.model === item.model && (
100
+ <TouchableOpacity
101
+ activeOpacity={1}
102
+ onPress={() => handleClick(null)}
103
+ >
104
+ <FeatherIcon
105
+ name='x-circle'
106
+ color={theme.colors.danger500}
107
+ size={20}
108
+ style={styles.icons}
109
+ />
110
+ </TouchableOpacity>
111
+ )}
112
+ </Container>
113
+ ))}
114
+ </View>
115
+ </ScrollView>
116
+ )
117
+ }
@@ -0,0 +1,10 @@
1
+ import styled from "styled-components/native";
2
+
3
+ export const Container = styled.View`
4
+ flex-direction: row;
5
+ justify-content: space-between;
6
+ width: 100%;
7
+ padding: 5px 5px 5px 0;
8
+ border-bottom-width: 1px;
9
+ border-bottom-color: ${(props: any) => props.theme.colors.lightGray};
10
+ `
@@ -24,6 +24,7 @@ import { LogoutButton } from '../LogoutButton';
24
24
  import { LanguageSelector } from '../LanguageSelector';
25
25
  import { UserFormDetailsUI } from '../UserFormDetails';
26
26
  import { DriverSchedule } from '../DriverSchedule'
27
+ import { PrinterSettings } from '../PrinterSettings'
27
28
  import ToggleSwitch from 'toggle-switch-react-native';
28
29
  import { UDWrapper } from '../UserFormDetails/styles';
29
30
  import {
@@ -485,11 +486,10 @@ const ProfileUI = (props: ProfileParams) => {
485
486
  handleCancelEdit={handleCancelEdit}
486
487
  toggleIsEdit={toggleIsEdit}
487
488
  isAlsea={isAlsea}
488
- allowDriverUpdateData={allowDriverUpdateData}
489
489
  />
490
490
  </View>
491
491
  )}
492
- {!validationFields.loading && !isEdit && (
492
+ {!validationFields.loading && !isEdit && allowDriverUpdateData && (
493
493
  <EditButton>
494
494
  <OButton
495
495
  text={t('EDIT', 'Edit')}
@@ -503,17 +503,31 @@ const ProfileUI = (props: ProfileParams) => {
503
503
  />
504
504
  </EditButton>
505
505
  )}
506
- <Pressable style={{ marginBottom: 10 }} onPress={() => setOpenModal(true)}>
507
- <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
508
- <OText size={16}>{t('SCHEDULE', 'Schedule')}</OText>
509
- <AntDesignIcon size={18} name='right' />
510
- </View>
511
- <View style={{
512
- borderBottomColor: theme.colors.tabBar,
513
- borderBottomWidth: 1,
514
- marginTop: 10
515
- }} />
516
- </Pressable>
506
+ {!props.isBusinessApp ? (
507
+ <Pressable style={{ marginBottom: 10 }} onPress={() => setOpenModal(true)}>
508
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
509
+ <OText size={16}>{t('SCHEDULE', 'Schedule')}</OText>
510
+ <AntDesignIcon size={18} name='right' />
511
+ </View>
512
+ <View style={{
513
+ borderBottomColor: theme.colors.tabBar,
514
+ borderBottomWidth: 1,
515
+ marginTop: 10
516
+ }} />
517
+ </Pressable>
518
+ ) : (
519
+ <Pressable style={{ marginBottom: 10 }} onPress={() => setOpenModal(true)}>
520
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
521
+ <OText size={16}>{t('PRINTER_SETTINGS', 'Printer Settings')}</OText>
522
+ <AntDesignIcon size={18} name='right' />
523
+ </View>
524
+ <View style={{
525
+ borderBottomColor: theme.colors.tabBar,
526
+ borderBottomWidth: 1,
527
+ marginTop: 10
528
+ }} />
529
+ </Pressable>
530
+ )}
517
531
  <Pressable style={{ marginBottom: 10 }} onPress={() => navigation.navigate('Sessions')}>
518
532
  <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
519
533
  <OText size={16}>{t('SESSIONS', 'Sessions')}</OText>
@@ -536,7 +550,11 @@ const ProfileUI = (props: ProfileParams) => {
536
550
  entireModal
537
551
  hideIcons
538
552
  >
539
- <DriverSchedule schedule={user?.schedule} />
553
+ {props.isBusinessApp ? (
554
+ <PrinterSettings onClose={() => setOpenModal(false)} />
555
+ ) : (
556
+ <DriverSchedule schedule={user?.schedule} />
557
+ )}
540
558
  </OModal>
541
559
  </ScrollView>
542
560
  )}
@@ -48,8 +48,8 @@ export const useLocation = () => {
48
48
  GeoLocation.getCurrentPosition(
49
49
  ({ coords }) => {
50
50
  resolve({
51
- latitude: typeof coords.latitude !== 'number' && !Number.isNaN(coords.latitude) ? coords.latitude : 0,
52
- longitude: typeof coords.longitude !== 'number' && !Number.isNaN(coords.longitude) ? coords.longitude : 0,
51
+ latitude: typeof coords.latitude === 'number' && !Number.isNaN(coords.latitude) ? coords.latitude : 0,
52
+ longitude: typeof coords.longitude === 'number' && !Number.isNaN(coords.longitude) ? coords.longitude : 0,
53
53
  speed: coords.speed,
54
54
  });
55
55
  },
@@ -59,6 +59,7 @@ export interface ProfileParams {
59
59
  isAlsea?: boolean;
60
60
  isShowDriverStatus?: boolean;
61
61
  isFocused?: boolean;
62
+ isBusinessApp?: boolean;
62
63
  }
63
64
 
64
65
  export interface AddressListParams {