Major improvements to upload progress.
This commit is contained in:
11
app.json
11
app.json
@@ -6,7 +6,7 @@
|
|||||||
"scheme": "imex-mobile-scheme",
|
"scheme": "imex-mobile-scheme",
|
||||||
"userInterfaceStyle": "automatic",
|
"userInterfaceStyle": "automatic",
|
||||||
"extra": {
|
"extra": {
|
||||||
"expover": "1",
|
"expover": "8",
|
||||||
"eas": {
|
"eas": {
|
||||||
"projectId": "ffe01f3a-d507-4698-82cd-da1f1cad450b"
|
"projectId": "ffe01f3a-d507-4698-82cd-da1f1cad450b"
|
||||||
}
|
}
|
||||||
@@ -14,10 +14,7 @@
|
|||||||
"runtimeVersion": "appVersion",
|
"runtimeVersion": "appVersion",
|
||||||
"orientation": "default",
|
"orientation": "default",
|
||||||
"icon": "./assets/ImEXlogo192noa.png",
|
"icon": "./assets/ImEXlogo192noa.png",
|
||||||
"platforms": [
|
"platforms": ["ios", "android"],
|
||||||
"ios",
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "com.imex.imexmobile",
|
"bundleIdentifier": "com.imex.imexmobile",
|
||||||
@@ -51,9 +48,7 @@
|
|||||||
"fallbackToCacheTimeout": 0,
|
"fallbackToCacheTimeout": 0,
|
||||||
"url": "https://u.expo.dev/ffe01f3a-d507-4698-82cd-da1f1cad450b"
|
"url": "https://u.expo.dev/ffe01f3a-d507-4698-82cd-da1f1cad450b"
|
||||||
},
|
},
|
||||||
"assetBundlePatterns": [
|
"assetBundlePatterns": ["**/*"],
|
||||||
"**/*"
|
|
||||||
],
|
|
||||||
"web": {
|
"web": {
|
||||||
"favicon": "./assets/ImEXlogo192noa.png",
|
"favicon": "./assets/ImEXlogo192noa.png",
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
|
|||||||
import * as Application from "expo-application";
|
import * as Application from "expo-application";
|
||||||
import Constants from "expo-constants";
|
import Constants from "expo-constants";
|
||||||
import * as Notifications from "expo-notifications";
|
import * as Notifications from "expo-notifications";
|
||||||
|
import * as Updates from "expo-updates";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Alert, ScrollView, StyleSheet, View } from "react-native";
|
import { Alert, ScrollView, StyleSheet, View } from "react-native";
|
||||||
@@ -182,6 +183,44 @@ function Tab({ bodyshop, currentUser, signOutStart }) {
|
|||||||
number: `${Constants.expoConfig.version}(${Application.nativeBuildVersion} - ${Constants.expoConfig.extra.expover})`,
|
number: `${Constants.expoConfig.version}(${Application.nativeBuildVersion} - ${Constants.expoConfig.extra.expover})`,
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
|
<Button
|
||||||
|
mode="text"
|
||||||
|
onPress={() => {
|
||||||
|
Updates.checkForUpdateAsync()
|
||||||
|
.then(async (update) => {
|
||||||
|
if (update.isAvailable) {
|
||||||
|
const reloaded = await Updates.fetchUpdateAsync();
|
||||||
|
if (reloaded.isNew) {
|
||||||
|
Alert.alert(
|
||||||
|
"Update downloaded",
|
||||||
|
"The app will now restart to apply the update.",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: "Restart Now",
|
||||||
|
onPress: () => {
|
||||||
|
Updates.reloadAsync();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Alert.alert(
|
||||||
|
"No Update Available",
|
||||||
|
"You are using the latest version of the app."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
Alert.alert(
|
||||||
|
"Update Error",
|
||||||
|
`An error occurred while checking for updates: ${error.message}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Check for Update
|
||||||
|
</Button>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
import { useTheme } from "@/hooks";
|
import { useTheme } from "@/hooks";
|
||||||
import { clearUploadError } from "@/redux/photos/photos.actions";
|
import { cancelUploads, clearUploadError } from "@/redux/photos/photos.actions";
|
||||||
import { formatBytes } from "@/util/uploadUtils";
|
import { formatBytes } from "@/util/uploadUtils";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ScrollView, StyleSheet, View } from "react-native";
|
import { ScrollView, StyleSheet, View } from "react-native";
|
||||||
import { Divider, Modal, Portal, ProgressBar, Text } from "react-native-paper";
|
import {
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Modal,
|
||||||
|
Portal,
|
||||||
|
ProgressBar,
|
||||||
|
Text,
|
||||||
|
} from "react-native-paper";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import {
|
import {
|
||||||
@@ -20,6 +27,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
clearError: () => dispatch(clearUploadError()),
|
clearError: () => dispatch(clearUploadError()),
|
||||||
|
cancelUploads: () => dispatch(cancelUploads()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UploadProgress);
|
export default connect(mapStateToProps, mapDispatchToProps)(UploadProgress);
|
||||||
@@ -29,6 +37,7 @@ export function UploadProgress({
|
|||||||
photoUploadProgress,
|
photoUploadProgress,
|
||||||
uploadError,
|
uploadError,
|
||||||
clearError,
|
clearError,
|
||||||
|
cancelUploads,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -42,6 +51,10 @@ export function UploadProgress({
|
|||||||
return completed / total;
|
return completed / total;
|
||||||
}, [photoUploadProgress]);
|
}, [photoUploadProgress]);
|
||||||
|
|
||||||
|
const handleCancelUploads = () => {
|
||||||
|
cancelUploads();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<Modal
|
<Modal
|
||||||
@@ -78,10 +91,10 @@ export function UploadProgress({
|
|||||||
</Text>
|
</Text>
|
||||||
<View style={styles.progressBarContainer}>
|
<View style={styles.progressBarContainer}>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
progress={(photoUploadProgress[key].progress || 0) / 100}
|
progress={photoUploadProgress[key].progress || 0}
|
||||||
style={styles.progress}
|
style={styles.progress}
|
||||||
color={
|
color={
|
||||||
photoUploadProgress[key].progress === 100 ? "green" : "blue"
|
photoUploadProgress[key].progress === 1 ? "green" : "blue"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<View style={styles.speedRow}>
|
<View style={styles.speedRow}>
|
||||||
@@ -95,6 +108,9 @@ export function UploadProgress({
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
|
<Button onPress={handleCancelUploads}>
|
||||||
|
{t("general.actions.cancel")}
|
||||||
|
</Button>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Portal>
|
</Portal>
|
||||||
|
|||||||
@@ -53,3 +53,17 @@ export const clearUploadError = () => ({
|
|||||||
type: PhotosActionTypes.CLEAR_UPLOAD_ERROR,
|
type: PhotosActionTypes.CLEAR_UPLOAD_ERROR,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const addUploadCancelTask = (payload) => ({
|
||||||
|
type: PhotosActionTypes.ADD_UPLOAD_CANCEL_TASK,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeUploadCancelTask = (payload) => ({
|
||||||
|
type: PhotosActionTypes.REMOVE_UPLOAD_CANCEL_TASK,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const cancelUploads = () => ({
|
||||||
|
type: PhotosActionTypes.CANCEL_UPLOADS,
|
||||||
|
});
|
||||||
@@ -5,7 +5,9 @@ const INITIAL_STATE = {
|
|||||||
uploadInProgress: true,
|
uploadInProgress: true,
|
||||||
uploadError: null,
|
uploadError: null,
|
||||||
jobid: null,
|
jobid: null,
|
||||||
progress: {}
|
progress: {},
|
||||||
|
cancelTasks: {},
|
||||||
|
cancelTriggered: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const photosReducer = (state = INITIAL_STATE, action) => {
|
const photosReducer = (state = INITIAL_STATE, action) => {
|
||||||
@@ -17,7 +19,9 @@ const photosReducer = (state = INITIAL_STATE, action) => {
|
|||||||
jobid: action.payload.jobid,
|
jobid: action.payload.jobid,
|
||||||
uploadInProgress: true,
|
uploadInProgress: true,
|
||||||
uploadError: null,
|
uploadError: null,
|
||||||
progress: action.payload.progress || {}
|
progress: action.payload.progress || {},
|
||||||
|
cancelTasks: {},
|
||||||
|
cancelTriggered: false,
|
||||||
};
|
};
|
||||||
case PhotosActionTypes.MEDIA_UPLOAD_FAILURE:
|
case PhotosActionTypes.MEDIA_UPLOAD_FAILURE:
|
||||||
return {
|
return {
|
||||||
@@ -31,9 +35,12 @@ const photosReducer = (state = INITIAL_STATE, action) => {
|
|||||||
progress: { ...state.progress, [action.payload.assetId]: { ...state.progress[action.payload.assetId], ...action.payload } }
|
progress: { ...state.progress, [action.payload.assetId]: { ...state.progress[action.payload.assetId], ...action.payload } }
|
||||||
};
|
};
|
||||||
case PhotosActionTypes.MEDIA_UPLOAD_SUCCESS_ONE:
|
case PhotosActionTypes.MEDIA_UPLOAD_SUCCESS_ONE:
|
||||||
|
const { [action.payload.assetId]: _, ...remainingTasks } = state.cancelTasks;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
progress: { ...state.progress, [action.payload.assetId]: { ...state.progress[action.payload.assetId], progress: 100, status: 'completed', endTime: new Date() } }
|
progress: { ...state.progress, [action.payload.assetId]: { ...state.progress[action.payload.assetId], progress: 100, status: 'completed', endTime: new Date() } },
|
||||||
|
cancelTasks: remainingTasks
|
||||||
};
|
};
|
||||||
case PhotosActionTypes.MEDIA_UPLOAD_PROGRESS_UPDATE_BULK:
|
case PhotosActionTypes.MEDIA_UPLOAD_PROGRESS_UPDATE_BULK:
|
||||||
return {
|
return {
|
||||||
@@ -46,13 +53,35 @@ const photosReducer = (state = INITIAL_STATE, action) => {
|
|||||||
uploadInProgress: false,
|
uploadInProgress: false,
|
||||||
uploadError: null,
|
uploadError: null,
|
||||||
photos: [],
|
photos: [],
|
||||||
progress: {}
|
progress: {},
|
||||||
|
cancelTasks: {}
|
||||||
};
|
};
|
||||||
case PhotosActionTypes.CLEAR_UPLOAD_ERROR:
|
case PhotosActionTypes.CLEAR_UPLOAD_ERROR:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
photos: [], progress: {},
|
photos: [],
|
||||||
|
progress: {},
|
||||||
uploadError: null,
|
uploadError: null,
|
||||||
|
cancelTasks: {},
|
||||||
|
};
|
||||||
|
case PhotosActionTypes.ADD_UPLOAD_CANCEL_TASK:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
cancelTasks: {
|
||||||
|
...state.cancelTasks,
|
||||||
|
[action.payload.assetId]: action.payload.cancelTask,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case PhotosActionTypes.REMOVE_UPLOAD_CANCEL_TASK:
|
||||||
|
const { [action.payload.assetId]: _2, ...remainingTasks2 } = state.cancelTasks; //2 added for scoped variable conflict.
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
cancelTasks: remainingTasks2,
|
||||||
|
};
|
||||||
|
case PhotosActionTypes.CANCEL_UPLOADS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
cancelTriggered: true,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Constants from "expo-constants";
|
import Constants from "expo-constants";
|
||||||
|
import * as FileSystem from "expo-file-system/legacy";
|
||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import * as MediaLibrary from "expo-media-library";
|
import * as MediaLibrary from "expo-media-library";
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -15,6 +16,7 @@ import { selectDeleteAfterUpload } from "../app/app.selectors";
|
|||||||
import { store } from "../store";
|
import { store } from "../store";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../user/user.selectors";
|
||||||
import {
|
import {
|
||||||
|
addUploadCancelTask,
|
||||||
deleteMediaSuccess,
|
deleteMediaSuccess,
|
||||||
mediaUploadCompleted,
|
mediaUploadCompleted,
|
||||||
mediaUploadFailure,
|
mediaUploadFailure,
|
||||||
@@ -84,7 +86,7 @@ export function* openImagePickerAction({ payload: jobid }) {
|
|||||||
yield put(mediaUploadStart({ photos: result.assets, jobid, progress: _.keyBy(result.assets, 'assetId') }));
|
yield put(mediaUploadStart({ photos: result.assets, jobid, progress: _.keyBy(result.assets, 'assetId') }));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log("Saga Error: open Picker", error);
|
console.log("Saga Error: open Picker", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +121,9 @@ export function* mediaUploadStartAction({ payload: { photos, jobid } }) {
|
|||||||
}
|
}
|
||||||
// Process each batch sequentially, but photos within batch concurrently
|
// Process each batch sequentially, but photos within batch concurrently
|
||||||
for (const batch of batches) {
|
for (const batch of batches) {
|
||||||
|
const isCancelTriggered = yield select((state) => state.photos.cancelTriggered
|
||||||
|
);
|
||||||
|
if (!isCancelTriggered) {
|
||||||
const uploadTasks = batch.map((photo, index) =>
|
const uploadTasks = batch.map((photo, index) =>
|
||||||
call(uploadSinglePhoto, photo, bodyshop, index, jobid)
|
call(uploadSinglePhoto, photo, bodyshop, index, jobid)
|
||||||
);
|
);
|
||||||
@@ -128,6 +133,7 @@ export function* mediaUploadStartAction({ payload: { photos, jobid } }) {
|
|||||||
yield delay(100);
|
yield delay(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
yield put(mediaUploadCompleted(photos));
|
yield put(mediaUploadCompleted(photos));
|
||||||
|
|
||||||
@@ -260,39 +266,53 @@ function* uploadToImageProxy(photo, photoBlob, extension, key, bodyshop, jobid)
|
|||||||
|
|
||||||
let uploadResult
|
let uploadResult
|
||||||
try {
|
try {
|
||||||
uploadResult = yield new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
console.log("Starting XHR")
|
// const s3PutResponse = yield call(cleanAxios.put,
|
||||||
const xhr = new XMLHttpRequest();
|
// preSignedUploadUrlToS3,
|
||||||
xhr.upload.onprogress = (e) => {
|
// photoBlob,
|
||||||
console.log("Upload Progress:", e.loaded, e.total);
|
// {
|
||||||
store.dispatch({ ...photo, progress: e.loaded / e.total, loaded: e.loaded });
|
// headers: {
|
||||||
put(mediaUploadProgressOne({ ...photo, progress: e.loaded / e.total, loaded: e.loaded }));
|
// "Content-Type": photoBlob.type
|
||||||
|
// },
|
||||||
|
// onUploadProgress: (e) => {
|
||||||
|
// const progress = e.loaded / e.total;
|
||||||
|
// console.log("Event Progress", e)
|
||||||
|
// put(mediaUploadProgressOne({ ...photo, progress, loaded: e.loaded }));
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const task = FileSystem.createUploadTask(
|
||||||
|
preSignedUploadUrlToS3,
|
||||||
|
photo.uri,
|
||||||
|
{
|
||||||
|
//fieldName: FIELD_NAME_OF_THE_FILE_IN_REQUEST,
|
||||||
|
httpMethod: "PUT",
|
||||||
|
uploadType: FileSystem.FileSystemUploadType.BINARY_CONTENT,
|
||||||
|
mimeType: photoBlob.type,
|
||||||
|
headers: {},
|
||||||
|
//parameters: {...OTHER PARAMS IN REQUEST},
|
||||||
|
},
|
||||||
|
(progressData) => {
|
||||||
|
const sent = progressData.totalBytesSent;
|
||||||
|
const total = progressData.totalBytesExpectedToSend;
|
||||||
|
const progress = sent / total;
|
||||||
|
console.log(progress, sent)
|
||||||
|
store.dispatch(mediaUploadProgressOne({ ...photo, progress, loaded: sent }));
|
||||||
|
// onUpload(Number(progress.toFixed(2)) * 100);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
yield put(addUploadCancelTask({ assetId: photo.assetId, cancelTask: task.cancelAsync }));
|
||||||
|
uploadResult = yield task.uploadAsync();
|
||||||
|
|
||||||
};
|
|
||||||
xhr.open("PUT", preSignedUploadUrlToS3);
|
|
||||||
xhr.setRequestHeader("Content-Type", photoBlob.type);
|
|
||||||
xhr.onload = () => {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
console.log("XHR Done. Resolve promise.")
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
reject(new Error(`Upload failed: ${xhr.statusText}`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = (req, event) => {
|
|
||||||
reject(new Error("Network error"));
|
|
||||||
};
|
|
||||||
console.log("Sending XHR")
|
|
||||||
xhr.send(photoBlob);
|
|
||||||
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error uploading to S3", error.message, error.stack);
|
console.log("Error uploading to S3", error.message, error.stack);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uploadResult) {
|
if (uploadResult.status === 200) {
|
||||||
//Create doc record.
|
//Create doc record.
|
||||||
const uploaded_by = yield select(selectCurrentUser);
|
const uploaded_by = yield select(selectCurrentUser);
|
||||||
|
|
||||||
@@ -328,26 +348,34 @@ function* uploadToImageProxy(photo, photoBlob, extension, key, bodyshop, jobid)
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
console.log("Upload and record creation successful for", photo.uri);
|
console.log("Upload and record creation successful for", photo.uri);
|
||||||
|
} else {
|
||||||
|
console.log("Error uploading to Cloud", uploadResult);
|
||||||
|
throw new Error(`Cloud upload failed: ${uploadResult}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error uploading to image proxy", JSON.stringify(error));
|
console.log("Error uploading to Cloud", JSON.stringify(error));
|
||||||
throw new Error(`Image proxy upload failed: ${error.message}`);
|
throw new Error(`Cloud upload failed: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle cancellation of uploads
|
// Handle cancellation of uploads
|
||||||
function* onCancelUpload() {
|
function* onCancelUpload() {
|
||||||
yield takeEvery(PhotosActionTypes.CANCEL_UPLOAD, cancelUploadAction);
|
yield takeEvery(PhotosActionTypes.CANCEL_UPLOADS, cancelUploadAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
function* cancelUploadAction({ payload: photoId }) {
|
function* cancelUploadAction() {
|
||||||
// const task = uploadTasks.get(photoId);
|
const cancelTasks = yield select((state) => state.photos.cancelTasks);
|
||||||
// if (task) {
|
try {
|
||||||
// yield cancel(task);
|
const tasksToCancel = Object.values(cancelTasks);
|
||||||
// uploadTasks.delete(photoId);
|
for (const cancelTask of tasksToCancel) {
|
||||||
// yield put(mediaUploadFailure({ photoId, error: 'Upload cancelled' }));
|
console.log("*** ~ cancelUploadAction ~ cancelTask:", cancelTask);
|
||||||
// }
|
cancelTask();
|
||||||
|
}
|
||||||
|
yield put({ type: PhotosActionTypes.CLEAR_UPLOAD_ERROR });
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error cancelling upload", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* onMediaUploadCompleted() {
|
function* onMediaUploadCompleted() {
|
||||||
@@ -414,7 +442,7 @@ export function* photosSagas() {
|
|||||||
call(onOpenImagePicker),
|
call(onOpenImagePicker),
|
||||||
call(onMediaUploadStart),
|
call(onMediaUploadStart),
|
||||||
call(onMediaUploadCompleted),
|
call(onMediaUploadCompleted),
|
||||||
call(onMediaUploadFailure)
|
call(onMediaUploadFailure),
|
||||||
//call(onCancelUpload)
|
call(onCancelUpload)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -10,5 +10,8 @@ const PhotosActionTypes = {
|
|||||||
DELETE_MEDIA_SUCCESS: "DELETE_MEDIA_SUCCESS",
|
DELETE_MEDIA_SUCCESS: "DELETE_MEDIA_SUCCESS",
|
||||||
DELETE_MEDIA_FAILURE: "DELETE_MEDIA_FAILURE",
|
DELETE_MEDIA_FAILURE: "DELETE_MEDIA_FAILURE",
|
||||||
CLEAR_UPLOAD_ERROR: "CLEAR_UPLOAD_ERROR",
|
CLEAR_UPLOAD_ERROR: "CLEAR_UPLOAD_ERROR",
|
||||||
|
ADD_UPLOAD_CANCEL_TASK: "ADD_UPLOAD_CANCEL_TASK",
|
||||||
|
REMOVE_UPLOAD_CANCEL_TASK: "REMOVE_UPLOAD_CANCEL_TASK",
|
||||||
|
CANCEL_UPLOADS: "CANCEL_UPLOADS",
|
||||||
};
|
};
|
||||||
export default PhotosActionTypes;
|
export default PhotosActionTypes;
|
||||||
|
|||||||
Reference in New Issue
Block a user