diff --git a/src/components/BarcodeCameraView.js b/src/components/BarcodeCameraView.js
new file mode 100644
index 000000000..ec6c2abf6
--- /dev/null
+++ b/src/components/BarcodeCameraView.js
@@ -0,0 +1,144 @@
+import React, { useState, forwardRef } from 'react';
+import { Dimensions, Text } from 'react-native';
+import { View, Vibration } from 'react-native';
+import { CameraView, useCameraPermissions } from 'expo-camera/next';
+import _ from 'lodash';
+import { Icon } from 'native-base';
+import Ionicons from 'react-native-vector-icons/Ionicons';
+import { TouchableOpacity } from 'react-native-gesture-handler';
+import FocusHandler from './FocusHandler';
+
+function getBoxBoundaries(points) {
+ const xs = points.map(point => point.x);
+ const ys = points.map(point => point.y);
+ const minX = Math.min(...xs);
+ const maxX = Math.max(...xs);
+ const minY = Math.min(...ys);
+ const maxY = Math.max(...ys);
+ return { minX, maxX, minY, maxY };
+}
+
+function horizontalLineIntersectsBox(lineY, lineStartX, lineEndX, points) {
+ const { minX, maxX, minY, maxY } = getBoxBoundaries(points);
+
+ if (lineY < minY || lineY > maxY) {
+ return false;
+ }
+ if (lineStartX > lineEndX) {
+ [lineStartX, lineEndX] = [lineEndX, lineStartX];
+ }
+ return lineEndX >= minX && lineStartX <= maxX;
+}
+
+function BarcodeCameraView({ disabled, ...props }, ref) {
+ const [hasPermission, requestPermission] = useCameraPermissions();
+
+ const { width: CameraWidth } = Dimensions.get('window');
+ const CameraHeight = CameraWidth * 0.55;
+ const PaddingHorizontal = CameraWidth * 0.1618;
+
+ const [barcode, setBarcode] = useState(null);
+ const [flash, setFlash] = useState(false);
+
+ //The hide behavior is a hack to force the camera to re-render
+ //if another camera is opened on modal. If we don't do this, the
+ //camera will not render.
+ const [hide, setHide] = useState(disabled ?? false);
+
+ if (!hasPermission) {
+ return (
+
+ No camera permission
+
+ );
+ }
+
+ if (!hasPermission.granted) {
+ requestPermission();
+ return ;
+ }
+
+ const onScanned = _.throttle(result => {
+ const { data, cornerPoints } = result;
+ if (
+ !horizontalLineIntersectsBox(
+ CameraHeight / 2,
+ PaddingHorizontal,
+ CameraWidth - PaddingHorizontal,
+ cornerPoints,
+ )
+ ) {
+ return;
+ }
+
+ if (data !== barcode) {
+ Vibration.vibrate();
+ setBarcode(data);
+ props.onScanned(data);
+ }
+ }, 200);
+
+ return (
+ <>
+ {
+ if (!disabled) {
+ setHide(false);
+ }
+ }}
+ onBlur={() => {
+ setHide(true);
+ }}
+ />
+ {!hide && (
+
+
+
+ setFlash(!flash)}>
+
+
+
+
+ )}
+ {hide && (
+
+ )}
+ >
+ );
+}
+
+export default forwardRef(BarcodeCameraView);
diff --git a/src/components/NotificationHandler.js b/src/components/NotificationHandler.js
index 98a6bed78..6f1b91f18 100644
--- a/src/components/NotificationHandler.js
+++ b/src/components/NotificationHandler.js
@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import {
clearNotifications,
+ shouldNotificationBeDisplayed,
startSound,
stopSound,
} from '../redux/App/actions';
@@ -10,6 +11,7 @@ import NotificationModal from './NotificationModal';
import {
selectNotificationsToDisplay,
selectNotificationsWithSound,
+ selectShouldNotificationBeDisplayed
} from '../redux/App/selectors';
import { AppState } from 'react-native';
@@ -25,6 +27,7 @@ const NOTIFICATION_DURATION_MS = 10000;
export default function NotificationHandler() {
const notificationsToDisplay = useSelector(selectNotificationsToDisplay);
const notificationsWithSound = useSelector(selectNotificationsWithSound);
+ const shouldNotificationBeDisplayed = useSelector(selectShouldNotificationBeDisplayed);
const hasNotifications = useMemo(
() =>
@@ -53,12 +56,19 @@ export default function NotificationHandler() {
// but it's very limited, e.g. handlers set via setTimeout are not executed
// so we do not play sound in that case, because we will not be able to stop it
// use memoized value to avoid re-starting the sound when more notifications arrive
- if (hasNotificationsWithSound && AppState.currentState === 'active') {
+ if (
+ shouldNotificationBeDisplayed &&
+ hasNotificationsWithSound &&
+ AppState.currentState === 'active') {
dispatch(startSound());
} else {
dispatch(stopSound());
}
- }, [hasNotificationsWithSound, dispatch]);
+ }, [shouldNotificationBeDisplayed, hasNotificationsWithSound, dispatch]);
+
+ if (!shouldNotificationBeDisplayed) {
+ return null;
+ }
return (
+ {title}
+ {value ?? '-'}
+
+ );
+}
+
+function BarcodePage({
+ t,
+ httpClient,
+ navigation,
+ taskLists,
+ shouldNotificationBeDisplayed,
+}) {
+ const [barcode, setBarcode] = useState(null);
+ const [entity, setEntity] = useState(null);
+ const [clientActionsQueue, setClientActionsQueue] = useState([]);
+ const [showNoteModal, setShowNoteModal] = useState(false);
+ const [noteLoading, setNoteLoading] = useState(false);
+
+ const note = useRef(null);
+
+ const askToUnassign = useCallback(
+ ({ token }) =>
+ new Promise((resolve, reject) => {
+ Alert.alert(
+ t('BARCODE_TASK_ALREADY_ASSIGNED_TITLE'),
+ t('BARCODE_TASK_ALREADY_ASSIGNED_SELF_MESSAGE'),
+ [
+ {
+ text: t('BARCODE_TASK_ALREADY_ASSIGNED_UNASSIGN'),
+ onPress: () => {
+ _unassignTask(httpClient, entity.id, token)
+ .then(resolve)
+ .catch(reject);
+ },
+ },
+ {
+ text: t('TASK_COMPLETE_ALERT_NEGATIVE'),
+ onPress: () =>
+ _startTask(httpClient, entity.id).then(resolve).catch(reject),
+ },
+ {
+ text: t('OK'),
+ onPress: resolve,
+ },
+ ],
+ );
+ }),
+ [t, httpClient, entity],
+ );
+
+ const askToAssign = useCallback(
+ ({ token }) =>
+ new Promise((resolve, reject) => {
+ Alert.alert(
+ t('BARCODE_TASK_ALREADY_ASSIGNED_TITLE'),
+ t('BARCODE_TASK_ALREADY_ASSIGNED_ANOTHER_MESSAGE'),
+ [
+ {
+ text: t('BARCODE_TASK_ALREADY_ASSIGNED_ASSIGN_TO_ME'),
+ onPress: () => {
+ _assignTask(httpClient, entity.id, token)
+ .then(resolve)
+ .catch(reject);
+ },
+ },
+ {
+ text: t('OK'),
+ onPress: resolve,
+ },
+ ],
+ );
+ }),
+ [t, httpClient, entity],
+ );
+
+ const askToStartPickup = useCallback(
+ ({ payload: { task_id } }) => {
+ return new Promise((resolve, reject) => {
+ Alert.alert(
+ t('ASK_TO_START_PICKUP_TITLE'),
+ t('ASK_TO_START_PICKUP_MESSAGE'),
+ [
+ {
+ text: t('TASK_COMPLETE_ALERT_NEGATIVE'),
+ onPress: () => {
+ _startTask(httpClient, task_id)
+ .then(resolve)
+ .catch(reject);
+ },
+ },
+ {
+ text: t('OK'),
+ onPress: resolve,
+ },
+ ],
+ );
+ });
+ },
+ [t, httpClient],
+ )
+
+ const warningMultiplePackages = ({ count, details }) =>
+ new Promise((resolve, _reject) => {
+ Alert.alert(
+ t('TASK_MULTIPLE_PACKAGES'),
+ `${t('X_PACKAGES', { count })}:\n\n${details}\n\n${t(
+ 'NO_NEED_TO_SCAN_OTHERS',
+ )}`,
+ [{ text: t('OK'), onPress: resolve }],
+ );
+ });
+
+ const checkMultiplePackages = packages => {
+ if (!packages) return;
+ const count = packages.reduce((acc, p) => acc + p.barcodes.length, 0);
+ if (count > 1) {
+ const details = packages
+ .map(p => `${p.barcodes.length}x ${p.name}`)
+ .join('\n');
+ return {
+ action: 'warn_multiple_packages',
+ fn: () => warningMultiplePackages({ count, details }),
+ };
+ }
+ return null;
+ };
+
+ async function* actionGenerator(actions) {
+ for (const action of actions) {
+ yield action;
+ }
+ }
+
+ const checkClientAction = useCallback(
+ ({ action, ...params }) => {
+ if (!entity) return;
+
+ switch (action) {
+ case 'ask_to_unassign':
+ return askToUnassign(params);
+ case 'ask_to_assign':
+ return askToAssign(params);
+ case 'ask_to_start_pickup':
+ return askToStartPickup(params);
+ case 'ask_to_complete_pickup':
+ case 'ask_to_complete':
+ return new Promise((resolve, _reject) => {
+ const id = params?.payload?.task_id ?? entity.id;
+ navigation.dispatch(StackActions.pop(1));
+ navigateToTask(
+ navigation,
+ null,
+ taskLists.find(task => task['@id'] === `/api/tasks/${id}`),
+ );
+ resolve();
+ });
+ case 'warn_multiple_packages':
+ return params.fn();
+ default:
+ return;
+ }
+ },
+ [entity, navigation, taskLists, askToAssign, askToUnassign, askToStartPickup],
+ );
+
+ useEffect(() => {
+ shouldNotificationBeDisplayed(false);
+ return () => {
+ shouldNotificationBeDisplayed(true);
+ };
+ }, [shouldNotificationBeDisplayed]);
+
+ useEffect(() => {
+ async function processActions() {
+ if (clientActionsQueue.length === 0) return;
+
+ const generator = actionGenerator(clientActionsQueue);
+
+ try {
+ for await (const action of generator) {
+ await checkClientAction(action);
+ }
+ } catch (error) {
+ console.error('Error processing actions:', error);
+ } finally {
+ setClientActionsQueue([]);
+ }
+ }
+
+ processActions();
+ }, [clientActionsQueue, checkClientAction]);
+
+ return (
+ <>
+ setShowNoteModal(false)}
+ onBackdropPress={() => setShowNoteModal(false)}>
+
+ {t('NOTES')}
+
+
+
+
+ 0}
+ onScanned={async code => {
+ if (clientActionsQueue.length > 0) return;
+ const { entity, client_action: { action = null, payload = null } = {}, token_action } = await _fetchBarcode(
+ httpClient,
+ code,
+ );
+ setBarcode(code);
+ setEntity(entity);
+
+ const multi_package_action = checkMultiplePackages(entity?.barcodes?.packages);
+ setClientActionsQueue(
+ [
+ ...clientActionsQueue,
+ { action, payload, token: token_action },
+ multi_package_action,
+ ].filter(e => e.action),
+ );
+ }}
+ />
+ console.log(">>>>>>>>>> enter")}
+ // onTouchEnd={() => console.log(">>>>>>>>>> leave")}
+ >
+
+ {entity?.status ? t(`TASK_${entity.status}`) : '-'}
+
+
+
+
+
+
+
+
+
+ phonecall(entity?.address?.telephone, true)}
+ />
+ }
+ onPress={() => setShowNoteModal(true)}>
+ {t('ADD_NOTE')}
+
+
+ NavigationHolder.dispatch(
+ CommonActions.navigate('CourierBarcodeReport', { entity }),
+ )
+ }
+ disabled={entity == null}
+ _icon={{
+ as: Ionicons,
+ name: 'warning',
+ color: 'red.500',
+ }}
+ />
+
+
+ >
+ );
+}
+
+const styles = StyleSheet.create({
+ data: {
+ fontWeight: '600',
+ fontSize: 16,
+ },
+ note: {
+ fontSize: 14,
+ },
+ light: { color: 'black' },
+ dark: { color: 'white' },
+ section: { paddingVertical: 8 },
+ title: { fontSize: 16, paddingBottom: 3 },
+});
+
+function mapStateToProps(state) {
+ return {
+ httpClient: state.app.httpClient,
+ user: state.app.user,
+ taskLists: selectTasks(state),
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ shouldNotificationBeDisplayed: should =>
+ dispatch(shouldNotificationBeDisplayed(should)),
+ };
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(withTranslation()(BarcodePage));
diff --git a/src/navigation/courier/barcode/BarcodeIncident.js b/src/navigation/courier/barcode/BarcodeIncident.js
new file mode 100644
index 000000000..dd56aa64f
--- /dev/null
+++ b/src/navigation/courier/barcode/BarcodeIncident.js
@@ -0,0 +1,220 @@
+import React, { useMemo, useState, useRef, useEffect } from 'react';
+import { Dimensions } from 'react-native';
+import { withTranslation } from 'react-i18next';
+import {
+ Button,
+ VStack,
+ Text,
+ Skeleton,
+ ScrollView,
+ HStack,
+ IconButton,
+ Icon,
+ TextArea,
+ View,
+ Image,
+ FormControl,
+ Stack,
+ Flex,
+} from 'native-base';
+import { connect } from 'react-redux';
+import { useQuery } from 'react-query';
+import Ionicons from 'react-native-vector-icons/Ionicons';
+import { CameraView } from 'expo-camera/next';
+import { addPicture, reportIncident } from '../../../redux/Courier/taskActions';
+
+function BarcodeIncident({
+ route,
+ t,
+ navigation,
+ httpClient,
+ addPicture,
+ reportIncident,
+}) {
+ const { entity } = route.params;
+
+ const [selectedFailureReason, setFailureReason] = useState(null);
+ const [notes, setNotes] = useState(null);
+ const [enableCamera, setEnableCamera] = useState(false);
+ const camera = useRef(null);
+ const [pictures, setPictures] = useState([]);
+
+ const { width } = Dimensions.get('window');
+
+ useEffect(() => {
+ navigation.setOptions({ headerShown: !enableCamera });
+ }, [enableCamera, navigation]);
+
+ const { data, isSuccess, isError } = useQuery(
+ ['task', 'failure_reasons', entity.id],
+ async () => {
+ return await httpClient.get(`/api/tasks/${entity.id}/failure_reasons`);
+ },
+ );
+
+ const values = useMemo(() => {
+ if (!isSuccess || !data) {
+ return null;
+ }
+ return data['hydra:member'].map((value, index) => (
+
+ ));
+ }, [data, isSuccess]);
+
+ if (isError) {
+ return (
+
+ Failure reasons are not available
+
+ );
+ }
+
+ // CAMERA VIEW MODE
+ if (enableCamera) {
+ const _takePicture = async () => {
+ const options = { quality: 0.35, base64: true };
+ const pictureOpts = await camera.current.takePictureAsync(options);
+ setPictures([...pictures, pictureOpts.uri]);
+ setEnableCamera(false);
+ };
+ return (
+
+
+
+ }
+ onPress={_takePicture}
+ />
+
+
+ );
+ }
+ // END
+
+ // DETAILS MODE
+ if (selectedFailureReason) {
+ return (
+ <>
+
+
+
+ {t('FAILURE_REASON')}
+
+
+
+ {t('NOTES')}
+
+
+
+ {t('PICTURES')}
+
+
+
+ {pictures.map((picture, index) => (
+
+
+ }
+ onPress={() =>
+ setPictures(pictures.filter((_p, i) => i !== index))
+ }
+ />
+
+ ))}
+
+
+
+
+
+
+ >
+ );
+ }
+ // END
+
+ // PICKER MODE
+ return (
+
+
+
+ {values}
+
+
+
+ );
+ // END
+}
+
+function mapStateToProps(state) {
+ return {
+ httpClient: state.app.httpClient,
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ addPicture: base64 => dispatch(addPicture(null, base64)),
+ reportIncident: (task_id, notes, failureReasonCode, onSuccess) =>
+ dispatch(
+ reportIncident(
+ { '@id': `/api/tasks/${task_id}` },
+ notes ?? '',
+ failureReasonCode,
+ [],
+ onSuccess,
+ ),
+ ),
+ };
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(withTranslation()(BarcodeIncident));
diff --git a/src/navigation/courier/barcode/BarcodeReport.js b/src/navigation/courier/barcode/BarcodeReport.js
new file mode 100644
index 000000000..f89e1c9e7
--- /dev/null
+++ b/src/navigation/courier/barcode/BarcodeReport.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import { withTranslation } from 'react-i18next';
+import { Button, VStack, Text } from 'native-base';
+import { Alert } from 'react-native';
+
+function BarcodeReport({ route, t, navigation }) {
+ const { entity } = route.params;
+ return (
+
+
+ {t('TASK')} #{entity?.id}
+
+
+
+
+ );
+}
+
+export default withTranslation()(BarcodeReport);
diff --git a/src/navigation/index.js b/src/navigation/index.js
index 45fee0c2c..2958711d1 100644
--- a/src/navigation/index.js
+++ b/src/navigation/index.js
@@ -43,6 +43,9 @@ import CourierSettings from './courier/Settings';
import CourierSettingsTags from './courier/Tags';
import CourierTaskListPage from './courier/TaskListPage';
import CourierTasksPage from './courier/TasksPage';
+import CourierBarcodePage from './courier/barcode/Barcode';
+import CourierBarcodeReportPage from './courier/barcode/BarcodeReport';
+import CourierBarcodeIncidentPage from './courier/barcode/BarcodeIncident';
import CheckoutLoginRegister from './checkout/CheckoutLoginRegister';
import CheckoutMercadopago from './checkout/Mercadopago';
@@ -100,6 +103,9 @@ export default {
CheckoutMercadopago,
CheckoutMoreInfos,
CourierTasksPage,
+ CourierBarcodePage,
+ CourierBarcodeReportPage,
+ CourierBarcodeIncidentPage,
CourierTaskListPage,
CourierSettings,
CourierSettingsTags,
diff --git a/src/navigation/navigators/CourierNavigator.js b/src/navigation/navigators/CourierNavigator.js
index da9f42784..160bc9e98 100644
--- a/src/navigation/navigators/CourierNavigator.js
+++ b/src/navigation/navigators/CourierNavigator.js
@@ -73,7 +73,11 @@ const MainStack = createStackNavigator();
const headerButtons = nav => (
nav.navigate('CourierBarcode')}
+ />
+ nav.navigate('CourierSettings')}
/>
@@ -111,6 +115,32 @@ const MainNavigator = () => (
);
+const BarcodeStack = createStackNavigator();
+const BarcodeNavigator = () => (
+
+
+
+
+
+
+
+);
+
const SettingsStack = createStackNavigator();
const SettingsNavigator = () => (
@@ -151,5 +181,12 @@ export default () => (
headerShown: false,
}}
/>
+
);
diff --git a/src/navigation/task/Complete.js b/src/navigation/task/Complete.js
index 3a26f229c..3c691326c 100644
--- a/src/navigation/task/Complete.js
+++ b/src/navigation/task/Complete.js
@@ -105,7 +105,7 @@ const FailureReasonPicker = ({ task, httpClient, onValueChange }) => {
const failureReasonObj = _.find(data['hydra:member'], r => r.code === selectedFailureReason)
onValueChange(selectedFailureReason, failureReasonObj);
setFailureReason(selectedFailureReason)
- }
+ }
if (isError) {
return Failure reasons are not available;
@@ -256,10 +256,16 @@ const SubmitButton = ({ task, tasks, notes, contactName, failureReason, validate
const navigateOnSuccess = () => {
// Make sure to use merge = true, so that it doesn't break
// when navigating to DispatchTaskList
- navigation.navigate({
- name: route.params?.navigateAfter,
- merge: true,
- });
+
+ if (route.params?.navigateAfter !== null) {
+ navigation.navigate({
+ name: route.params?.navigateAfter,
+ merge: true,
+ });
+ } else {
+ navigation.goBack();
+ }
+
}
if (success) {
diff --git a/src/navigation/utils.js b/src/navigation/utils.js
index 6587db0b5..75b795493 100644
--- a/src/navigation/utils.js
+++ b/src/navigation/utils.js
@@ -1,7 +1,7 @@
let navigateAfter = null;
export const navigateToTask = (navigation, route, task, tasks = []) => {
- if (route.name !== 'TaskHome') {
+ if (route !== null && route.name !== 'TaskHome') {
navigateAfter = route.name;
}
diff --git a/src/redux/App/actions.js b/src/redux/App/actions.js
index f8fa659bc..c4a13b7a1 100644
--- a/src/redux/App/actions.js
+++ b/src/redux/App/actions.js
@@ -42,6 +42,7 @@ export const SAVE_PUSH_NOTIFICATION_TOKEN_SUCCESS =
'@app/SAVE_PUSH_NOTIFICATION_TOKEN_SUCCESS';
export const DELETE_PUSH_NOTIFICATION_TOKEN_SUCCESS =
'@app/DELETE_PUSH_NOTIFICATION_TOKEN_SUCCESS';
+export const SHOULD_NOTIFICATION_BE_DISPLAYED = '@app/SHOULD_NOTIFICATION_BE_DISPLAYED';
export const LOGIN = '@app/LOGIN';
export const SET_LOADING = '@app/SET_LOADING';
@@ -165,6 +166,9 @@ export const savePushNotificationTokenSuccess = createFsAction(
export const deletePushNotificationTokenSuccess = createFsAction(
DELETE_PUSH_NOTIFICATION_TOKEN_SUCCESS,
);
+export const shouldNotificationBeDisplayed = createFsAction(
+ SHOULD_NOTIFICATION_BE_DISPLAYED,
+)
const _loadMyStoresSuccess = createFsAction(LOAD_MY_STORES_SUCCESS);
diff --git a/src/redux/App/reducers.js b/src/redux/App/reducers.js
index fc1a43bd4..cfcc9220b 100644
--- a/src/redux/App/reducers.js
+++ b/src/redux/App/reducers.js
@@ -43,6 +43,7 @@ import {
RESET_PASSWORD_REQUEST_SUCCESS,
RESUME_CHECKOUT_AFTER_ACTIVATION,
SAVE_PUSH_NOTIFICATION_TOKEN_SUCCESS,
+ SHOULD_NOTIFICATION_BE_DISPLAYED,
SET_BACKGROUND_GEOLOCATION_ENABLED,
SET_BASE_URL,
SET_CURRENT_ROUTE,
@@ -72,6 +73,7 @@ const initialState = {
appState: AppState.currentState,
pushNotificationToken: null,
pushNotificationTokenSaved: null,
+ shouldNotificationBeDisplayed: true,
loading: false,
notifications: [],
lastAuthenticationError: null,
@@ -210,6 +212,13 @@ export default (state = initialState, action = {}) => {
return updateNotifications(state, event, params);
}
+ case SHOULD_NOTIFICATION_BE_DISPLAYED: {
+ return {
+ ...state,
+ shouldNotificationBeDisplayed: action.payload,
+ }
+ }
+
case CLEAR_NOTIFICATIONS:
return {
...state,
diff --git a/src/redux/App/selectors.js b/src/redux/App/selectors.js
index 1e747493a..7a3dddb32 100644
--- a/src/redux/App/selectors.js
+++ b/src/redux/App/selectors.js
@@ -232,3 +232,4 @@ export const selectNotificationsToDisplay = createSelector(
export const selectSettingsLatLng = state => state.app.settings.latlng;
export const selectStripePublishableKey = state =>
state.app.settings.stripe_publishable_key;
+export const selectShouldNotificationBeDisplayed = state => state.app.shouldNotificationBeDisplayed;
diff --git a/src/redux/Courier/taskActions.js b/src/redux/Courier/taskActions.js
index b12e74bb4..8ec88348a 100644
--- a/src/redux/Courier/taskActions.js
+++ b/src/redux/Courier/taskActions.js
@@ -77,12 +77,10 @@ export const reportIncidentRequest = createAction(REPORT_INCIDENT_REQUEST);
export const reportIncidentSuccess = createAction(REPORT_INCIDENT_SUCCESS);
export const reportIncidentFailure = createAction(REPORT_INCIDENT_FAILURE);
-export const addPicture = createAction(ADD_PICTURE, (task, base64) => ({
- task,
+export const addPicture = createAction(ADD_PICTURE, (_task, base64) => ({
base64,
}));
-export const addSignature = createAction(ADD_SIGNATURE, (task, base64) => ({
- task,
+export const addSignature = createAction(ADD_SIGNATURE, (_task, base64) => ({
base64,
}));
export const clearFiles = createAction(CLEAR_FILES);
@@ -263,7 +261,6 @@ function uploadEntitiesImages(entities, url, state) {
return Promise.all(promises);
}
-
export function reportIncident(
task,
description = null,
@@ -279,20 +276,21 @@ export function reportIncident(
description,
failureReasonCode,
metadata: failureReasonMetadata,
- task: task['@id']
+ task: task['@id'],
};
-
// Make sure to return a promise for testing
return httpClient
.post('/api/incidents', payload)
.then(incident => {
- uploadEntityImages(incident, '/api/incident_images', getState())
- .then(uploadTasks => httpClient.execUploadTask(uploadTasks));
+ uploadEntityImages(incident, '/api/incident_images', getState()).then(
+ uploadTasks => httpClient.execUploadTask(uploadTasks),
+ );
dispatch(clearFiles());
dispatch(reportIncidentSuccess(incident));
+ console.log(onSuccess);
if (typeof onSuccess === 'function') {
- setTimeout(() => onSuccess(), 100);
+ setTimeout(onSuccess, 100);
}
})
.catch(e => {
@@ -350,13 +348,7 @@ export function markTaskFailed(
};
}
-
-export function markTaskDone(
- task,
- notes = '',
- onSuccess,
- contactName = '',
-) {
+export function markTaskDone(task, notes = '', onSuccess, contactName = '') {
return function (dispatch, getState) {
dispatch(markTaskDoneRequest(task));
const httpClient = selectHttpClient(getState());
@@ -393,12 +385,7 @@ export function markTaskDone(
};
}
-export function markTasksDone(
- tasks,
- notes = '',
- onSuccess,
- contactName = '',
-) {
+export function markTasksDone(tasks, notes = '', onSuccess, contactName = '') {
return function (dispatch, getState) {
dispatch(markTasksDoneRequest());
const httpClient = selectHttpClient(getState());