diff --git a/App.js b/App.js
index c94c6a9..047a54b 100644
--- a/App.js
+++ b/App.js
@@ -6,7 +6,7 @@ import { PersistGate } from "redux-persist/integration/react";
import * as Sentry from "sentry-expo";
import ScreenMainComponent from "./components/screen-main/screen-main.component";
import env from "./env";
-import { logImEXEvent } from "./firebase/firebase.utils";
+import { logImEXEvent } from "./firebase/firebase.analytics";
import { client } from "./graphql/client";
import { persistor, store } from "./redux/store";
import "./translations/i18n";
diff --git a/babel-translations.babel b/babel-translations.babel
index b75d7f6..ab4065b 100644
--- a/babel-translations.babel
+++ b/babel-translations.babel
@@ -1320,6 +1320,48 @@
+
+ storageexceeded
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
+
+ storageexceeded_title
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
temporarystorage
false
diff --git a/components/job-list-item/job-list-item.component.jsx b/components/job-list-item/job-list-item.component.jsx
index da29cb4..cb3b4e5 100644
--- a/components/job-list-item/job-list-item.component.jsx
+++ b/components/job-list-item/job-list-item.component.jsx
@@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
import { Button, List, Title } from "react-native-paper";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import { logImEXEvent } from "../../firebase/firebase.analytics";
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
const mapStateToProps = createStructuredSelector({});
diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx
index fb0d29c..179de25 100644
--- a/components/screen-main/screen-main.component.jsx
+++ b/components/screen-main/screen-main.component.jsx
@@ -8,7 +8,7 @@ import { Button } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import { logImEXEvent } from "../../firebase/firebase.analytics";
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
import {
checkUserSession,
diff --git a/components/screen-media-browser/screen-media-browser.component.jsx b/components/screen-media-browser/screen-media-browser.component.jsx
index 97d4771..f45f2d5 100644
--- a/components/screen-media-browser/screen-media-browser.component.jsx
+++ b/components/screen-media-browser/screen-media-browser.component.jsx
@@ -1,13 +1,14 @@
+import { useApolloClient } from "@apollo/client";
import { Ionicons } from "@expo/vector-icons";
import { AssetsSelector } from "expo-images-picker";
import * as MediaLibrary from "expo-media-library";
import _ from "lodash";
import React, { useCallback, useState } from "react";
import { useTranslation } from "react-i18next";
-import { StyleSheet, Text, View } from "react-native";
+import { StyleSheet, Text, View, Alert } from "react-native";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import { logImEXEvent } from "../../firebase/firebase.analytics";
import {
selectCurrentCameraJobId,
selectDeleteAfterUpload,
@@ -20,8 +21,9 @@ import { handleUpload } from "../../util/document-upload.utility";
import CameraSelectJob from "../camera-select-job/camera-select-job.component";
import UploadDeleteSwitch from "../upload-delete-switch/upload-delete-switch.component";
import UploadProgress from "../upload-progress/upload-progress.component";
-
+import { GET_DOC_SIZE_TOTALS } from "../../graphql/documents.queries";
//const limit = plimit(2);
+import * as FileSystem from "expo-file-system";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -47,7 +49,7 @@ export function ImageBrowserScreen({
const forceRerender = useCallback(() => {
setTick((tick) => tick + 1);
}, []);
-
+ const client = useApolloClient();
async function handleOnSuccess(uri, id) {
console.log("Succesful upload!", uri);
logImEXEvent("imexmobile_successful_upload");
@@ -56,6 +58,49 @@ export function ImageBrowserScreen({
const onDone = async (data) => {
logImEXEvent("imexmobile_upload_documents", { count: data.length });
+
+ //Validate to make sure the totals for the file sizes do not exceed the total on the job.
+
+ const queryData = await client.query({
+ query: GET_DOC_SIZE_TOTALS,
+
+ fetchPolicy: "network-only",
+ variables: {
+ jobId: selectedCameraJobId !== "temp" ? selectedCameraJobId : null,
+ },
+ });
+
+ const totalOfUploads = await data.reduce(async (acc, val) => {
+ //Get the size of the file based on URI.
+ const info = await FileSystem.getInfoAsync(val.uri, { size: true });
+ return (await acc) + info.size;
+ }, 0);
+ console.log("data :>> ", data);
+ console.log(
+ "Size of uploaded documents.",
+ queryData.data.documents_aggregate.aggregate.sum.size,
+ "Shop Limit",
+ bodyshop.jobsizelimit,
+ "Space remaining",
+ bodyshop.jobsizelimit -
+ queryData.data.documents_aggregate.aggregate.sum.size,
+ "Total of uploaded files",
+ totalOfUploads
+ );
+
+ if (
+ bodyshop.jobsizelimit -
+ queryData.data.documents_aggregate.aggregate.sum.size <=
+ totalOfUploads
+ ) {
+ //No more room... abandon ship.
+ Alert.alert(
+ t("mediabrowser.labels.storageexceeded_title"),
+ t("mediabrowser.labels.storageexceeded")
+ );
+ return;
+ }
+
const ret = await Promise.all(
data.map(async (p) => {
let filename;
diff --git a/components/upload-delete-switch/upload-delete-switch.component.jsx b/components/upload-delete-switch/upload-delete-switch.component.jsx
index 2bc9358..7195c0b 100644
--- a/components/upload-delete-switch/upload-delete-switch.component.jsx
+++ b/components/upload-delete-switch/upload-delete-switch.component.jsx
@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
import { StyleSheet, Switch, Text, View } from "react-native";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import { logImEXEvent } from "../../firebase/firebase.analytics";
import { toggleDeleteAfterUpload } from "../../redux/app/app.actions";
import { selectDeleteAfterUpload } from "../../redux/app/app.selectors";
diff --git a/firebase/firebase.analytics.js b/firebase/firebase.analytics.js
new file mode 100644
index 0000000..4e0056b
--- /dev/null
+++ b/firebase/firebase.analytics.js
@@ -0,0 +1,24 @@
+import * as Analytics from "expo-firebase-analytics";
+import { store } from "../redux/store";
+
+export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
+ const state = stateProp || store.getState();
+ const eventParams = {
+ shop:
+ (state.user && state.user.bodyshop && state.user.bodyshop.shopname) ||
+ null,
+ user:
+ (state.user && state.user.currentUser && state.user.currentUser.email) ||
+ null,
+ ...additionalParams,
+ };
+ console.log(
+ "%c[Analytics]",
+ "background-color: green ;font-weight:bold;",
+ eventName,
+ eventParams
+ );
+ Analytics.logEvent(eventName, eventParams);
+};
+
+//export const ExpoAnalytics = Analytics;
diff --git a/firebase/firebase.utils.js b/firebase/firebase.utils.js
index b06b826..0afa7e0 100644
--- a/firebase/firebase.utils.js
+++ b/firebase/firebase.utils.js
@@ -55,24 +55,24 @@ export const updateCurrentUser = (userDetails) => {
});
};
-export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
- const state = stateProp || store.getState();
- const eventParams = {
- shop:
- (state.user && state.user.bodyshop && state.user.bodyshop.shopname) ||
- null,
- user:
- (state.user && state.user.currentUser && state.user.currentUser.email) ||
- null,
- ...additionalParams,
- };
- console.log(
- "%c[Analytics]",
- "background-color: green ;font-weight:bold;",
- eventName,
- eventParams
- );
- Analytics.logEvent(eventName, eventParams);
-};
+// export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
+// const state = stateProp || store.getState();
+// const eventParams = {
+// shop:
+// (state.user && state.user.bodyshop && state.user.bodyshop.shopname) ||
+// null,
+// user:
+// (state.user && state.user.currentUser && state.user.currentUser.email) ||
+// null,
+// ...additionalParams,
+// };
+// console.log(
+// "%c[Analytics]",
+// "background-color: green ;font-weight:bold;",
+// eventName,
+// eventParams
+// );
+// Analytics.logEvent(eventName, eventParams);
+// };
//export const ExpoAnalytics = Analytics;
diff --git a/graphql/bodyshop.queries.js b/graphql/bodyshop.queries.js
index eb3b146..484586a 100644
--- a/graphql/bodyshop.queries.js
+++ b/graphql/bodyshop.queries.js
@@ -4,7 +4,7 @@ export const QUERY_BODYSHOP = gql`
query QUERY_BODYSHOP {
bodyshops(where: { associations: { active: { _eq: true } } }) {
id
-
+ jobsizelimit
md_ro_statuses
md_order_statuses
shopname
diff --git a/graphql/documents.queries.js b/graphql/documents.queries.js
index 361eb11..2c20c7f 100644
--- a/graphql/documents.queries.js
+++ b/graphql/documents.queries.js
@@ -1,11 +1,27 @@
import gql from "graphql-tag";
+export const GET_DOC_SIZE_TOTALS = gql`
+ query GET_DOC_SIZE_TOTALS($jobId: uuid!) {
+ documents_aggregate(where: { jobid: { _eq: $jobId } }) {
+ aggregate {
+ sum {
+ size
+ }
+ }
+ }
+ }
+`;
+
export const GET_DOCUMENTS_BY_JOB = gql`
query GET_DOCUMENTS_BY_JOB($jobId: uuid!) {
- documents(
- where: { jobid: { _eq: $jobId } }
- order_by: { updated_at: desc }
- ) {
+ documents_aggregate(where: { jobid: { _eq: $jobId } }) {
+ aggregate {
+ sum {
+ size
+ }
+ }
+ }
+ documents(order_by: { updated_at: desc }) {
id
name
key
diff --git a/redux/user/user.sagas.js b/redux/user/user.sagas.js
index 9ea8ce6..cf31186 100644
--- a/redux/user/user.sagas.js
+++ b/redux/user/user.sagas.js
@@ -3,9 +3,9 @@ import { all, call, put, takeLatest } from "redux-saga/effects";
import {
auth,
getCurrentUser,
- logImEXEvent,
updateCurrentUser,
} from "../../firebase/firebase.utils";
+import { logImEXEvent } from "../../firebase/firebase.analytics";
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import { client } from "../../graphql/client";
import {
diff --git a/translations/en-US/common.json b/translations/en-US/common.json
index 747bb02..f7f8544 100644
--- a/translations/en-US/common.json
+++ b/translations/en-US/common.json
@@ -90,6 +90,8 @@
"nomedia": "Look's like there's no media on your device. Take some photos or videos and they will appear here.",
"selectjob": "--- Select a job ---",
"selectjobassetselector": "Please select a job to upload media. ",
+ "storageexceeded": "Unable to uploaded selected files because there is not sufficient space available on this job.",
+ "storageexceeded_title": "Unable to upload file(s)",
"temporarystorage": "* Temporary Storage *"
},
"titles": {
diff --git a/translations/es-MX/common.json b/translations/es-MX/common.json
index e3cd237..5177c60 100644
--- a/translations/es-MX/common.json
+++ b/translations/es-MX/common.json
@@ -90,6 +90,8 @@
"nomedia": "",
"selectjob": "",
"selectjobassetselector": "",
+ "storageexceeded": "",
+ "storageexceeded_title": "",
"temporarystorage": ""
},
"titles": {
diff --git a/translations/fr-CA/common.json b/translations/fr-CA/common.json
index 3dd73ae..b47d44a 100644
--- a/translations/fr-CA/common.json
+++ b/translations/fr-CA/common.json
@@ -90,6 +90,8 @@
"nomedia": "",
"selectjob": "",
"selectjobassetselector": "",
+ "storageexceeded": "",
+ "storageexceeded_title": "",
"temporarystorage": ""
},
"titles": {
diff --git a/util/document-upload.utility.js b/util/document-upload.utility.js
index ccbb33c..c459b46 100644
--- a/util/document-upload.utility.js
+++ b/util/document-upload.utility.js
@@ -153,6 +153,7 @@ export const uploadToCloudinary = async (
type: fileType,
extension: extension,
bodyshopid: bodyshop.id,
+ size: file.size,
},
],
},