diff --git a/.env.dist b/.env.dist
index 1f2ec0812..fd9c8e30a 100644
--- a/.env.dist
+++ b/.env.dist
@@ -12,3 +12,6 @@ DEFAULT_SERVER=
PRIMARY_COLOR=
SMARTLOOK_PROJECT_KEY=
DEBUG_REDUX_LOGGER_LEVEL=log
+DATADOG_ENABLED=0
+DATADOG_CLIENT_TOKEN=
+DATADOG_APPLICATION_ID=
diff --git a/.github/workflows/fastlane_android.yml b/.github/workflows/fastlane_android.yml
index 336c143d5..541472939 100644
--- a/.github/workflows/fastlane_android.yml
+++ b/.github/workflows/fastlane_android.yml
@@ -89,6 +89,8 @@ jobs:
- name: Create .env file
env:
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
+ DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }}
+ DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }}
GOOGLE_MAPS_BROWSER_KEY: ${{ secrets.GOOGLE_MAPS_BROWSER_KEY }}
GOOGLE_MAPS_ANDROID_KEY: ${{ secrets.GOOGLE_MAPS_ANDROID_KEY }}
TRANSISTORSOFT_LICENSE_KEY: ${{ secrets.TRANSISTORSOFT_LICENSE_KEY }}
@@ -104,6 +106,9 @@ jobs:
echo COUNTLY_APP_KEY= >> .env
echo COUNTLY_SALT= >> .env
echo SENTRY_DSN="$SENTRY_DSN" >> .env
+ echo DATADOG_ENABLED="1" >> .env
+ echo DATADOG_CLIENT_TOKEN="$DATADOG_CLIENT_TOKEN" >> .env
+ echo DATADOG_APPLICATION_ID="$DATADOG_APPLICATION_ID" >> .env
echo GOOGLE_MAPS_BROWSER_KEY="$GOOGLE_MAPS_BROWSER_KEY" >> .env
echo GOOGLE_MAPS_ANDROID_KEY="$GOOGLE_MAPS_ANDROID_KEY" >> .env
echo TRANSISTORSOFT_LICENSE_KEY="$TRANSISTORSOFT_LICENSE_KEY" >> .env
diff --git a/.github/workflows/fastlane_ios.yml b/.github/workflows/fastlane_ios.yml
index 6a664049c..5e6c46c26 100644
--- a/.github/workflows/fastlane_ios.yml
+++ b/.github/workflows/fastlane_ios.yml
@@ -83,6 +83,8 @@ jobs:
- name: Create .env file
env:
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
+ DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }}
+ DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }}
GOOGLE_MAPS_BROWSER_KEY: ${{ secrets.GOOGLE_MAPS_BROWSER_KEY }}
GOOGLE_MAPS_ANDROID_KEY: ${{ secrets.GOOGLE_MAPS_ANDROID_KEY }}
TRANSISTORSOFT_LICENSE_KEY: ${{ secrets.TRANSISTORSOFT_LICENSE_KEY }}
@@ -97,6 +99,9 @@ jobs:
echo COUNTLY_APP_KEY= >> .env
echo COUNTLY_SALT= >> .env
echo SENTRY_DSN="$SENTRY_DSN" >> .env
+ echo DATADOG_ENABLED="1" >> .env
+ echo DATADOG_CLIENT_TOKEN="$DATADOG_CLIENT_TOKEN" >> .env
+ echo DATADOG_APPLICATION_ID="$DATADOG_APPLICATION_ID" >> .env
echo GOOGLE_MAPS_BROWSER_KEY="$GOOGLE_MAPS_BROWSER_KEY" >> .env
echo GOOGLE_MAPS_ANDROID_KEY="$GOOGLE_MAPS_ANDROID_KEY" >> .env
echo TRANSISTORSOFT_LICENSE_KEY="$TRANSISTORSOFT_LICENSE_KEY" >> .env
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 0b2c0ea7d..8f4dfa60f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -90,8 +90,9 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
- versionCode 213
- versionName "2.22.0"
+ // No need to increment the versionCode, it will be automatically incremented by the fastlane
+ versionCode 215
+ versionName "2.24.0"
manifestPlaceholders = [
tipsiStripeRedirectScheme: "coopcycle",
diff --git a/ios/CoopCycle/Info.plist b/ios/CoopCycle/Info.plist
index 4bc1e5f94..e0cdbba5b 100644
--- a/ios/CoopCycle/Info.plist
+++ b/ios/CoopCycle/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 2.22.0
+ 2.24.0
CFBundleSignature
????
CFBundleURLTypes
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 6936035c1..8f92e728e 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -14,6 +14,29 @@ PODS:
- React
- CountlyReactNative/NotificationService (22.06.1):
- React
+ - DatadogCore (2.14.2):
+ - DatadogInternal (= 2.14.2)
+ - DatadogCrashReporting (2.14.2):
+ - DatadogInternal (= 2.14.2)
+ - PLCrashReporter (~> 1.11.2)
+ - DatadogInternal (2.14.2)
+ - DatadogLogs (2.14.2):
+ - DatadogInternal (= 2.14.2)
+ - DatadogRUM (2.14.2):
+ - DatadogInternal (= 2.14.2)
+ - DatadogSDKReactNative (2.4.3):
+ - DatadogCore (~> 2.14.1)
+ - DatadogCrashReporting (~> 2.14.1)
+ - DatadogLogs (~> 2.14.1)
+ - DatadogRUM (~> 2.14.1)
+ - DatadogTrace (~> 2.14.1)
+ - DatadogWebViewTracking (~> 2.14.1)
+ - React-Core
+ - DatadogTrace (2.14.2):
+ - DatadogInternal (= 2.14.2)
+ - OpenTelemetrySwiftApi (= 1.6.0)
+ - DatadogWebViewTracking (2.14.2):
+ - DatadogInternal (= 2.14.2)
- DoubleConversion (1.1.6)
- EXConstants (15.4.5):
- ExpoModulesCore
@@ -191,6 +214,8 @@ PODS:
- nanopb/encode (= 2.30909.1)
- nanopb/decode (2.30909.1)
- nanopb/encode (2.30909.1)
+ - OpenTelemetrySwiftApi (1.6.0)
+ - PLCrashReporter (1.11.2)
- PromisesObjC (2.4.0)
- PromisesSwift (2.4.0):
- PromisesObjC (= 2.4.0)
@@ -1401,6 +1426,7 @@ PODS:
DEPENDENCIES:
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- CountlyReactNative (from `../node_modules/countly-sdk-react-native-bridge`)
+ - "DatadogSDKReactNative (from `../node_modules/@datadog/mobile-react-native`)"
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- EXConstants (from `../node_modules/expo-constants/ios`)
- EXFont (from `../node_modules/expo-font/ios`)
@@ -1501,6 +1527,13 @@ SPEC REPOS:
trunk:
- AppAuth
- CocoaLumberjack
+ - DatadogCore
+ - DatadogCrashReporting
+ - DatadogInternal
+ - DatadogLogs
+ - DatadogRUM
+ - DatadogTrace
+ - DatadogWebViewTracking
- FBAEMKit
- FBSDKCoreKit
- FBSDKCoreKit_Basics
@@ -1525,6 +1558,8 @@ SPEC REPOS:
- IQKeyboardManagerSwift
- libevent
- nanopb
+ - OpenTelemetrySwiftApi
+ - PLCrashReporter
- PromisesObjC
- PromisesSwift
- Sentry
@@ -1545,6 +1580,8 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
CountlyReactNative:
:path: "../node_modules/countly-sdk-react-native-bridge"
+ DatadogSDKReactNative:
+ :path: "../node_modules/@datadog/mobile-react-native"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
EXConstants:
@@ -1734,6 +1771,14 @@ SPEC CHECKSUMS:
boost: d3f49c53809116a5d38da093a8aa78bf551aed09
CocoaLumberjack: 543c79c114dadc3b1aba95641d8738b06b05b646
CountlyReactNative: f544f34347bc635e2951e2797d4750e66f886a09
+ DatadogCore: a3429f62b7da0e715e179833b3daa0203ba2a5ad
+ DatadogCrashReporting: 3b5e496c1f61971a93b9a1bff3312297be03f031
+ DatadogInternal: 11798eea970f195ad720168f9a51712e71affe33
+ DatadogLogs: 4192cc1979467ce0c2521d73ba92b6197e0c7f06
+ DatadogRUM: f732009eba7a848d6e2df9ef12944e30f0e94ba2
+ DatadogSDKReactNative: f418f95923dc78ad7b4dcd1710804f1672d8abfa
+ DatadogTrace: 5687191622d91152f10616e206500fe5acd8a342
+ DatadogWebViewTracking: cb818ee5943de63940b4f536320361c17af0f7b1
DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953
EXConstants: 988aa430ca0f76b43cd46b66e7fae3287f9cc2fc
EXFont: f20669cb266ef48b004f1eb1f2b20db96cd1df9f
@@ -1771,6 +1816,8 @@ SPEC CHECKSUMS:
IQKeyboardManagerSwift: 12d89768845bb77b55cc092ecc2b1f9370f06b76
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
+ OpenTelemetrySwiftApi: 657da8071c2908caecce11548e006f779924ff9c
+ PLCrashReporter: 499c53b0104f95c302d94fd723ebb03c56d9bac8
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
diff --git a/package.json b/package.json
index 254d2074c..dd959e653 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
},
"dependencies": {
"@babel/helper-get-function-arity": "^7.16.7",
+ "@datadog/mobile-react-native": "^2.4.3",
+ "@datadog/mobile-react-navigation": "^2.4.3",
"@heasy/react-native-sunmi-printer": "git+https://github.com/Surile/react-native-sunmi-printer.git#666f6f76ce737faf7a500b88a08ad10da68c5967",
"@invertase/react-native-apple-authentication": "^2.2.2",
"@mapbox/polyline": "^1.1.1",
diff --git a/src/App.js b/src/App.js
index 7ba03c0d2..29e46a097 100644
--- a/src/App.js
+++ b/src/App.js
@@ -61,6 +61,7 @@ import {
AccountResetPasswordNewPasswordScreen,
} from './navigation/navigators/AccountNavigator';
import { nativeBaseTheme } from './styles/theme';
+import { DatadogWrapper, navigationContainerOnReady } from './Datadog';
LogBox.ignoreLogs([
'Warning: isMounted(...) is deprecated in plain JavaScript React classes.',
@@ -86,6 +87,7 @@ function getCurrentRouteName() {
function onReady() {
routeNameRef.current = getCurrentRouteName();
+ navigationContainerOnReady(navigationRef);
}
/**
@@ -143,39 +145,41 @@ const App = () => {
}, []);
return (
-
-
-
-
- }
- persistor={persistor}>
-
-
-
-
-
-
-
- {
- DropdownHolder.setDropdown(ref);
- }}
- />
-
-
-
-
-
-
-
-
+
+
+
+
+
+ }
+ persistor={persistor}>
+
+
+
+
+
+
+
+ {
+ DropdownHolder.setDropdown(ref);
+ }}
+ />
+
+
+
+
+
+
+
+
+
);
};
diff --git a/src/Datadog.js b/src/Datadog.js
new file mode 100644
index 000000000..9463f28d9
--- /dev/null
+++ b/src/Datadog.js
@@ -0,0 +1,159 @@
+import React from 'react';
+import {
+ BatchSize,
+ DatadogProvider,
+ DatadogProviderConfiguration,
+ DdLogs,
+ DdSdkReactNative,
+ SdkVerbosity,
+ UploadFrequency,
+} from '@datadog/mobile-react-native';
+import Config from 'react-native-config';
+import { DdRumReactNavigationTracking } from '@datadog/mobile-react-navigation';
+
+const enabled = Config.DATADOG_ENABLED === '1';
+
+const clientToken = Config.DATADOG_CLIENT_TOKEN;
+if (enabled && !clientToken) {
+ throw new Error('DATADOG_CLIENT_TOKEN is required');
+}
+
+const applicationId = Config.DATADOG_APPLICATION_ID;
+if (enabled && !applicationId) {
+ throw new Error('DATADOG_APPLICATION_ID is required');
+}
+
+const datadogConfig = new DatadogProviderConfiguration(
+ clientToken,
+ __DEV__ ? 'dev' : 'prod',
+ applicationId,
+ true, // track User interactions (e.g.: Tap on buttons. You can use 'accessibilityLabel' element property to give tap action the name, otherwise element type will be reported)
+ true, // track XHR Resources
+ true, // track Errors
+);
+// Optional: Select your Datadog website (one of "US1", "EU1", "US3", "US5", "AP1" or "GOV")
+datadogConfig.site = 'US1';
+// Optional: Enable JavaScript long task collection
+datadogConfig.longTaskThresholdMs = 100;
+// Optional: enable or disable native crash reports
+datadogConfig.nativeCrashReportEnabled = true;
+// Optional: Sample RUM sessions (% of session are sent to Datadog. Default is 100%).
+datadogConfig.sessionSamplingRate = __DEV__ ? 100 : 20;
+// Optional: Sample tracing integrations for network calls between your app and your backend (% of calls to your instrumented backend are linked from the RUM view to the APM view. Default is 20%)
+// You need to specify the hosts of your backends to enable tracing with these backends
+datadogConfig.resourceTracingSamplingRate = __DEV__ ? 100 : 20;
+datadogConfig.telemetrySampleRate = 0;
+datadogConfig.firstPartyHosts = ['coopcycle.org']; // matches 'example.com' and subdomains like 'api.example.com'
+// Optional: let the SDK print internal logs above or equal to the provided level. Default is undefined (meaning no logs)
+datadogConfig.verbosity = __DEV__ ? SdkVerbosity.DEBUG : SdkVerbosity.WARN;
+
+if (__DEV__) {
+ // Optional: Send data more frequently
+ datadogConfig.uploadFrequency = UploadFrequency.FREQUENT;
+ // Optional: Send smaller batches of data
+ datadogConfig.batchSize = BatchSize.SMALL;
+}
+
+export function DatadogWrapper({ children }) {
+ if (!enabled) {
+ return <>{children}>;
+ }
+
+ return (
+ {children}
+ );
+}
+
+const viewNamePredicate = function customViewNamePredicate(route, trackedName) {
+ // return custom view name or null to use the previous RUM view
+ return trackedName;
+};
+
+export function navigationContainerOnReady(navigationRef) {
+ if (!enabled) {
+ return;
+ }
+
+ DdRumReactNavigationTracking.startTrackingViews(
+ navigationRef.current,
+ viewNamePredicate,
+ );
+}
+
+export const DatadogSdk = {
+ setAttributes(attributes) {
+ if (!enabled) {
+ console.debug('(disabled) DatadogSdk.setAttributes', attributes);
+ return;
+ }
+
+ DdSdkReactNative.setAttributes(attributes);
+ },
+
+ setUser(user) {
+ if (!enabled) {
+ console.debug('(disabled) DatadogSdk.setUser', user);
+ return;
+ }
+
+ DdSdkReactNative.setUser(user);
+ },
+};
+
+export const DatadogLogger = {
+ /**
+ * Send a log with debug level.
+ * @param message: The message to send.
+ * @param context: The additional context to send.
+ */
+ debug(message, context) {
+ if (!enabled) {
+ console.debug(message, context);
+ return;
+ }
+
+ DdLogs.debug(message, context);
+ },
+
+ /**
+ * Send a log with info level.
+ * @param message: The message to send.
+ * @param context: The additional context to send.
+ */
+ info(message, context) {
+ if (!enabled) {
+ console.info(message, context);
+ return;
+ }
+
+ DdLogs.info(message, context);
+ },
+
+ /**
+ * Send a log with warn level.
+ * @param message: The message to send.
+ * @param context: The additional context to send.
+ */
+ warn(message, context) {
+ if (!enabled) {
+ console.warn(message, context);
+ return;
+ }
+
+ DdLogs.warn(message, context);
+ },
+
+ /**
+ * Send a log with error level.
+ * @param message: The message to send.
+ * @param context: The additional context to send.
+ */
+ error(message, context) {
+ if (!enabled) {
+ console.error(message, context);
+ return;
+ }
+
+ DdLogs.error(message, context);
+ },
+};
diff --git a/src/navigation/restaurant/Order.js b/src/navigation/restaurant/Order.js
index 7fea23185..fb7e07a4b 100644
--- a/src/navigation/restaurant/Order.js
+++ b/src/navigation/restaurant/Order.js
@@ -20,6 +20,7 @@ import {
selectIsPrinterConnected,
selectPrinter,
} from '../../redux/Restaurant/selectors';
+import { DatadogLogger } from '../../Datadog';
const OrderNotes = ({ order }) => {
if (order.notes) {
@@ -57,7 +58,14 @@ class OrderScreen extends Component {
screen: 'RestaurantPrinter',
})
}
- printOrder={() => this.props.printOrder(this.props.order)}
+ printOrder={() => {
+ const order = this.props.order;
+ DatadogLogger.info('printing ticket', {
+ trigger: 'manual',
+ orderId: order.id,
+ });
+ this.props.printOrder(order);
+ }}
/>
@@ -87,18 +95,25 @@ class OrderScreen extends Component {
}
/>
)}
- {canEdit && (order.state === 'accepted' || order.state === 'started' || order.state === 'ready') && (
-
- this.props.navigation.navigate('RestaurantOrderCancel', { order })
- }
- onPressDelay={() =>
- this.props.navigation.navigate('RestaurantOrderDelay', { order })
- }
- onPressFulfill={() => this.fulfillOrder(order)}
- />
- )}
+ {canEdit &&
+ (order.state === 'accepted' ||
+ order.state === 'started' ||
+ order.state === 'ready') && (
+
+ this.props.navigation.navigate('RestaurantOrderCancel', {
+ order,
+ })
+ }
+ onPressDelay={() =>
+ this.props.navigation.navigate('RestaurantOrderDelay', {
+ order,
+ })
+ }
+ onPressFulfill={() => this.fulfillOrder(order)}
+ />
+ )}
);
}
diff --git a/src/navigation/restaurant/components/OrdersToPrintQueue.js b/src/navigation/restaurant/components/OrdersToPrintQueue.js
index b5cebaa3e..f6fb8de15 100644
--- a/src/navigation/restaurant/components/OrdersToPrintQueue.js
+++ b/src/navigation/restaurant/components/OrdersToPrintQueue.js
@@ -11,6 +11,7 @@ import {
} from '../../../redux/Restaurant/selectors';
import { printOrderById } from '../../../redux/Restaurant/actions';
import { useNavigation } from '@react-navigation/native';
+import { DatadogLogger } from '../../../Datadog';
function usePrinter() {
const connected = useSelector(selectIsPrinterConnected);
@@ -29,12 +30,20 @@ function usePrinter() {
return;
}
+ const orderId = orderIdsToPrint[0];
+
if (!connected) {
- console.warn('Printer is not connected');
+ DatadogLogger.info('printer is not connected', {
+ trigger: 'auto',
+ orderId,
+ });
return;
}
- const orderId = orderIdsToPrint[0];
+ DatadogLogger.info('printing ticket', {
+ trigger: 'auto',
+ orderId,
+ });
dispatch(printOrderById(orderId));
}, [printingOrderId, orderIdsToPrint, connected, dispatch]);
diff --git a/src/redux/App/actions.js b/src/redux/App/actions.js
index 8330b83d3..144f886da 100644
--- a/src/redux/App/actions.js
+++ b/src/redux/App/actions.js
@@ -25,6 +25,7 @@ import {
selectIsAuthenticated,
selectResumeCheckoutAfterActivation,
} from './selectors';
+import { DatadogSdk } from '../../Datadog'
/*
* Action Types
@@ -221,6 +222,9 @@ export const stopSound = createAction('STOP_SOUND');
function setBaseURL(baseURL) {
return (dispatch, getState) => {
dispatch(_setBaseURL(baseURL));
+ DatadogSdk.setAttributes({
+ 'instance_url': baseURL,
+ })
tracker.setUserProperty(userProperty.server, baseURL);
};
}
@@ -241,7 +245,7 @@ function authenticationSuccess(user) {
await dispatch(loadAddresses());
await dispatch(assignAllCarts());
- setRolesProperty(user);
+ updateUserProperties(user);
tracker.logEvent(
analyticsEvent.user.login._category,
analyticsEvent.user.login.success,
@@ -265,28 +269,27 @@ function logoutSuccess() {
return (dispatch, getState) => {
dispatch(_logoutSuccess());
dispatch(updateCarts({}));
- setRolesProperty(null);
+ updateUserProperties(null);
};
}
-function setRolesProperty(user) {
+function updateUserProperties(user) {
let roles;
- if (user !== null && user.roles !== null) {
- roles = user.roles.slice();
- roles.sort();
- } else {
- roles = [];
- }
-
- if (user) {
- if (roles.length > 0) {
- tracker.setUserProperty(userProperty.roles, roles.toString());
+ if (user !== null && user.username !== null) {
+ if (user.roles !== null) {
+ roles = user.roles.slice();
+ roles.sort();
} else {
- tracker.setUserProperty(userProperty.roles, 'ROLE_USER');
+ roles = ['ROLE_USER'];
}
} else {
- tracker.setUserProperty(userProperty.roles, 'ROLE_AD_HOC_CUSTOMER');
+ roles = ['ROLE_AD_HOC_CUSTOMER'];
}
+
+ DatadogSdk.setUser({
+ roles: roles.toString(),
+ })
+ tracker.setUserProperty(userProperty.roles, roles.toString());
}
function navigateToHome(dispatch, getState) {
@@ -409,7 +412,7 @@ export function bootstrap(baseURL, user, loader = true) {
dispatch(setUser(user));
dispatch(setBaseURL(baseURL));
- setRolesProperty(user);
+ updateUserProperties(user);
const httpClient = getState().app.httpClient;
diff --git a/src/redux/Restaurant/actions.js b/src/redux/Restaurant/actions.js
index 25c9b7d03..cb6200a2f 100644
--- a/src/redux/Restaurant/actions.js
+++ b/src/redux/Restaurant/actions.js
@@ -20,7 +20,12 @@ import {
} from '../App/actions';
import { selectHttpClient } from '../App/selectors';
-import { selectOrderById } from './selectors';
+import {
+ selectIsSunmiPrinter,
+ selectOrderById,
+ selectPrinter,
+} from './selectors';
+import { DatadogLogger } from '../../Datadog';
/*
* Action Types
@@ -244,6 +249,38 @@ export const printPending = createAction('PRINT_PENDING');
export const printFulfilled = createAction('PRINT_FULFILLED');
export const printRejected = createAction('PRINT_REJECTED');
+export function handlePrintFulfilled(order) {
+ return function (dispatch) {
+ DatadogLogger.info(`handlePrintFulfilled | success`, {
+ orderId: order.id,
+ });
+
+ dispatch(printFulfilled(order));
+ };
+}
+
+export function handlePrintRejected(
+ order,
+ internalErrorMessage = '',
+ messageForUser = '',
+) {
+ return function (dispatch) {
+ DatadogLogger.warn(
+ `handlePrintRejected | failed to print ticket | ${internalErrorMessage}`,
+ {
+ orderId: order.id,
+ },
+ );
+
+ dispatch(printRejected(order));
+ DropdownHolder.getDropdown().alertWithType(
+ 'error',
+ i18n.t('RESTAURANT_PRINTER_CONNECT_ERROR_TITLE'),
+ messageForUser,
+ );
+ };
+}
+
export const setPrintNumberOfCopies = createAction(
'SET_PRINT_NUMBER_OF_COPIES',
);
@@ -643,7 +680,7 @@ export function deleteOpeningHoursSpecification(openingHoursSpecification) {
};
}
-function bluetoothErrorToString(e) {
+function errorToString(e) {
if (typeof e === 'string') {
return e;
}
@@ -660,7 +697,9 @@ export function printOrderById(orderId) {
const order = selectOrderById(getState(), orderId);
if (!order) {
- console.warn('Order not found', orderId);
+ DatadogLogger.warn('printOrderById | Order not found', {
+ orderId,
+ });
return;
}
@@ -672,7 +711,8 @@ export function printOrder(order) {
return async (dispatch, getState) => {
dispatch(printPending(order));
- const { printer, isSunmiPrinter } = getState().restaurant;
+ const printer = selectPrinter(getState());
+ const isSunmiPrinter = selectIsSunmiPrinter(getState());
try {
if (isSunmiPrinter) {
@@ -680,16 +720,26 @@ export function printOrder(order) {
await SunmiPrinterLibrary.sendRAWData(
Buffer.from(encodeForPrinter(order, true)).toString('base64'),
);
- dispatch(printFulfilled(order));
+ dispatch(handlePrintFulfilled(order));
return;
}
} catch (e) {
- console.warn('printOrder with SunmiPrinter failed', e);
+ DatadogLogger.warn(
+ `printOrder with SunmiPrinter failed: ${errorToString(e)}`,
+ {
+ orderId: order.id,
+ },
+ );
}
if (!printer) {
- console.warn('No printer selected');
- dispatch(printRejected(order));
+ dispatch(
+ handlePrintRejected(
+ order,
+ 'No printer selected',
+ 'No printer selected',
+ ),
+ );
return;
}
@@ -705,11 +755,11 @@ export function printOrder(order) {
await BleManager.connect(printer.id);
} catch (e) {
dispatch(printerDisconnected());
- dispatch(printRejected(order));
- DropdownHolder.getDropdown().alertWithType(
- 'error',
- i18n.t('RESTAURANT_PRINTER_CONNECT_ERROR_TITLE'),
- bluetoothErrorToString(e),
+ dispatch(
+ handlePrintRejected(
+ order,
+ `Printer disconnected: ${errorToString(e)}`,
+ ),
);
return;
}
@@ -740,6 +790,13 @@ export function printOrder(order) {
);
if (writableCharacteristics.length > 0) {
+ DatadogLogger.info(
+ `printOrder | ${writableCharacteristics.length} writableCharacteristics found`,
+ {
+ orderId: order.id,
+ },
+ );
+
const encoded = encodeForPrinter(order);
writableCharacteristics.sort((a, b) => {
@@ -779,21 +836,18 @@ export function printOrder(order) {
writableCharacteristic.characteristic,
Array.from(encoded),
);
- dispatch(printFulfilled(order));
+ dispatch(handlePrintFulfilled(order));
} catch (e) {
- console.warn('printOrder | Write failed', e);
- dispatch(printRejected(order));
+ dispatch(
+ handlePrintRejected(order, `Write failed: ${errorToString(e)}`),
+ );
}
}
+ } else {
+ dispatch(handlePrintRejected(order, `No writable characteristics`));
}
} catch (e) {
- console.warn('printOrder | Error', e);
- dispatch(printRejected(order));
- DropdownHolder.getDropdown().alertWithType(
- 'error',
- i18n.t('RESTAURANT_PRINTER_CONNECT_ERROR_TITLE'),
- bluetoothErrorToString(e),
- );
+ dispatch(handlePrintRejected(order, `Misc error: ${errorToString(e)}`));
}
};
}
@@ -818,7 +872,7 @@ export function connectPrinter(device, cb) {
DropdownHolder.getDropdown().alertWithType(
'error',
i18n.t('RESTAURANT_PRINTER_CONNECT_ERROR_TITLE'),
- bluetoothErrorToString(e),
+ errorToString(e),
);
});
};
diff --git a/src/redux/Restaurant/selectors.js b/src/redux/Restaurant/selectors.js
index 00205ea3f..890fbec49 100644
--- a/src/redux/Restaurant/selectors.js
+++ b/src/redux/Restaurant/selectors.js
@@ -162,7 +162,7 @@ export const selectFulfilledOrders = createSelector(
export const selectPrinter = state => state.restaurant.printer;
-const selectIsSunmiPrinter = state => state.restaurant.isSunmiPrinter;
+export const selectIsSunmiPrinter = state => state.restaurant.isSunmiPrinter;
export const selectIsPrinterConnected = createSelector(
selectPrinter,
diff --git a/yarn.lock b/yarn.lock
index 815d116f1..cf47c8675 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1917,6 +1917,16 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+"@datadog/mobile-react-native@^2.4.3":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@datadog/mobile-react-native/-/mobile-react-native-2.4.3.tgz#4e0e1d046b8e98d790a91de289264c5b9039d305"
+ integrity sha512-po+R7JKiFkTS65vWKwfIWAn+aQuWdxeU61C5wc1YYtXVVBpNDCPs3qbDXxQmxJMDxMcjyDnYC0F0tO2EXS62yQ==
+
+"@datadog/mobile-react-navigation@^2.4.3":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@datadog/mobile-react-navigation/-/mobile-react-navigation-2.4.3.tgz#0008d5ae70ad892c2e587382baaa51d05e0eefc0"
+ integrity sha512-DcT8GQ2Ne1F5ryR7oM7jaKYn8pJ8r5r1BwbbqnKVkvxNAA2W4HDXn54u2C8ShuYhKs3STIjOo1zCDNxvSRsrgg==
+
"@egjs/hammerjs@^2.0.17":
version "2.0.17"
resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"