IO-3092 Imgproxy changes, Split client,

This commit is contained in:
Patrick Fic
2025-02-26 20:27:02 -08:00
parent dc6cd88e8c
commit 023de62244
12 changed files with 126 additions and 32 deletions

23
App.js
View File

@@ -1,19 +1,27 @@
import { ApolloProvider } from "@apollo/client";
import * as Sentry from "@sentry/react-native";
import { SplitFactory } from "@splitsoftware/splitio-react-native";
import "expo-asset";
import "intl";
import "intl/locale-data/jsonp/en";
import React from "react";
import { MD2LightTheme as DefaultTheme, Provider as PaperProvider } from "react-native-paper";
import {
MD2LightTheme as DefaultTheme,
Provider as PaperProvider,
} from "react-native-paper";
import { SafeAreaProvider } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import * as Sentry from '@sentry/react-native';
import ScreenMainComponent from "./components/screen-main/screen-main.component";
import { logImEXEvent } from "./firebase/firebase.analytics";
import { client } from "./graphql/client";
import { persistor, store } from "./redux/store";
import "intl";
import "intl/locale-data/jsonp/en";
import "./translations/i18n";
import "expo-asset";
import Toast from "react-native-toast-message";
import { SafeAreaProvider } from "react-native-safe-area-context";
import RNEventSource from "react-native-event-source";
globalThis.EventSource = RNEventSource;
Sentry.init({
dsn: "https://8d6c3de1940a4e4f8b81cf4d2150bdea@o492140.ingest.sentry.io/5558869",
enableInExpoDevelopment: true,
@@ -27,7 +35,6 @@ Sentry.init({
debug: true, // Sentry will try to print out useful debugging information if something goes wrong with sending an event. Set this to `false` in production.
});
const theme = {
...DefaultTheme,
colors: {

View File

@@ -16,8 +16,11 @@
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.imex.imexmobile",
"buildNumber": "1",
"buildNumber": "3",
"googleServicesFile": "./GoogleService-Info.plist",
"entitlements": {
"aps-environment": "development"
},
"infoPlist": {
"NSPhotoLibraryUsageDescription": "Allow $(PRODUCT_NAME) to access your photos.",
"NSPhotoLibraryAddUsageDescription": "Allow $(PRODUCT_NAME) to save photos.",
@@ -26,7 +29,7 @@
},
"android": {
"package": "com.imex.imexmobile",
"versionCode": 1100035,
"versionCode": 1100036,
"googleServicesFile": "./google-services.json",
"permissions": [
"android.permission.READ_EXTERNAL_STORAGE",

View File

@@ -1,4 +1,5 @@
import React, { useMemo, useState } from "react";
import axios from "axios";
import React, { useEffect, useState } from "react";
import {
FlatList,
Image,
@@ -10,12 +11,12 @@ import {
import env from "../../env";
import { DetermineFileType } from "../../util/document-upload.utility";
import MediaCacheOverlay from "../media-cache-overlay/media-cache-overlay.component";
import { useEffect } from "react";
import axios from "axios";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { splitClient } from "../screen-main/screen-main.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -32,13 +33,16 @@ export function JobDocumentsComponent({ bodyshop, job, loading, refetch }) {
const [previewVisible, setPreviewVisible] = useState(false);
const [fullphotos, setFullPhotos] = useState([]);
const [imgIndex, setImgIndex] = useState(0);
const useImgproxy = splitClient.getTreatment("Imgproxy");
const onRefresh = async () => {
return refetch();
};
useEffect(() => {
async function getPhotos() {
if (bodyshop.localmediatoken === "imgproxy") {
if (useImgproxy) {
const result = await axios.post(
`${env.API_URL}/media/imgproxy/thumbnails`,
{
@@ -128,7 +132,11 @@ export function JobDocumentsComponent({ bodyshop, job, loading, refetch }) {
)}
/>
<Text>{fullphotos.length}</Text>
<Text
style={{ textAlign: "center", color: useImgproxy ? "blue" : "black" }}
>
{fullphotos.length}
</Text>
<MediaCacheOverlay
photos={fullphotos}

View File

@@ -58,17 +58,15 @@ export function ScreenJobDetail({ bodyshop, route }) {
}),
documents: () => {
return bodyshop.uselocalmediaserver
? JobDocumentsLocalComponent({
job: data.jobs_by_pk,
bodyshop: bodyshop,
})
: JobDocuments({
job: data.jobs_by_pk,
loading: loading,
refetch: refetch,
});
return bodyshop.uselocalmediaserver ? (
<JobDocumentsLocalComponent job={data.jobs_by_pk} bodyshop={bodyshop} />
) : (
<JobDocuments
job={data.jobs_by_pk}
loading={loading}
refetch={refetch}
/>
);
},
notes: () =>

View File

@@ -19,12 +19,14 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import env from "../../env";
import ScreenJobDetail from "../screen-job-detail/screen-job-detail.component";
import ScreenJobList from "../screen-job-list/screen-job-list.component";
import ScreenMediaBrowser from "../screen-media-browser/screen-media-browser.component";
import ScreenSettingsComponent from "../screen-settings/screen-settings.component";
import ScreenSignIn from "../screen-sign-in/screen-sign-in.component";
import ScreenSplash from "../screen-splash/screen-splash.component";
import { SplitFactory } from "@splitsoftware/splitio-react-native";
const ActiveJobStack = createNativeStackNavigator();
const MoreStack = createNativeStackNavigator();
@@ -148,6 +150,8 @@ const BottomTabsNavigator = () => (
</BottomTabs.Navigator>
);
export var splitClient;
export function ScreenMainComponent({
checkUserSession,
currentUser,
@@ -157,6 +161,16 @@ export function ScreenMainComponent({
checkUserSession();
}, [checkUserSession]);
useEffect(() => {
if (bodyshop && bodyshop.imexshopid) {
splitClient = SplitFactory({
//debug: true,
core: { authorizationKey: env.SPLIT_API, key: bodyshop.imexshopid },
}).client();
splitClient.setAttribute("imexshopid", bodyshop.imexshopid);
}
}, [bodyshop]);
return (
<NavigationContainer>
{currentUser.authorized === null ? (

View File

@@ -271,8 +271,7 @@ export function UploadProgress({
jobId: selectedCameraJobId !== "temp" ? selectedCameraJobId : null,
uploaded_by: currentUser.email,
photo: p,
},
bodyshop.localmediatoken === "imgproxy" ? "imgproxy" : "" //Choose which destination to use.
}
);
};

View File

@@ -7,8 +7,13 @@
"developmentClient": true,
"channel": "test",
"distribution": "internal",
"ios": { //"simulator": true
}
"ios": {}
},
"development-simulator": {
"developmentClient": true,
"channel": "test",
"distribution": "internal",
"ios": { "simulator": true }
},
"test": {
"channel": "test"

2
env.js
View File

@@ -10,6 +10,7 @@ const ENV = {
REACT_APP_CLOUDINARY_ENDPOINT: "https://res.cloudinary.com/bodyshop",
REACT_APP_CLOUDINARY_API_KEY: "473322739956866",
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS: "c_fill,h_250,w_250",
SPLIT_API: "ts615lqgnmk84thn72uk18uu5pgce6e0l4rc",
firebase: {
apiKey: "AIzaSyBw7_GTy7GtQyfkIRPVrWHEGKfcqeyXw0c",
authDomain: "imex-test.firebaseapp.com",
@@ -29,6 +30,7 @@ const ENV = {
"https://api.cloudinary.com/v1_1/bodyshop",
REACT_APP_CLOUDINARY_ENDPOINT: "https://res.cloudinary.com/bodyshop",
REACT_APP_CLOUDINARY_API_KEY: "473322739956866",
SPLIT_API: "et9pjkik6bn67he5evpmpr1agoo7gactphgk",
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS: "c_fill,h_250,w_250",
firebase: {
apiKey: "AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU",

View File

@@ -11,6 +11,7 @@ export const QUERY_BODYSHOP = gql`
shopname
features
localmediatoken
imexshopid
}
}
`;

51
package-lock.json generated
View File

@@ -1,9 +1,12 @@
{
"name": "imexmobile",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "imexmobile",
"version": "1.0.0",
"dependencies": {
"@apollo/client": "^3.12.11",
"@babel/preset-env": "7.26.8",
@@ -18,6 +21,7 @@
"@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1",
"@sentry/react-native": "~6.3.0",
"@splitsoftware/splitio-react-native": "^1.1.0",
"axios": "^1.7.9",
"cloudinary-core": "^2.13.1",
"dinero.js": "^1.9.1",
@@ -54,6 +58,7 @@
"react-native": "0.76.7",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-element-dropdown": "^2.12.4",
"react-native-event-source": "^1.1.0",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-gallery": "^2.1.5",
"react-native-image-viewing": "^0.2.2",
@@ -6145,6 +6150,37 @@
"@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@splitsoftware/splitio-commons": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.1.0.tgz",
"integrity": "sha512-7SJRBia0Pi72s76drH8kG2cVnCqkjMHMJQWJSFnG+rE/UOx9AROmuviOkY6tv6qYPJFqFQQGHGX6lXjxZhYzkw==",
"license": "Apache-2.0",
"dependencies": {
"@types/ioredis": "^4.28.0",
"tslib": "^2.3.1"
},
"peerDependencies": {
"ioredis": "^4.28.0"
},
"peerDependenciesMeta": {
"ioredis": {
"optional": true
}
}
},
"node_modules/@splitsoftware/splitio-react-native": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@splitsoftware/splitio-react-native/-/splitio-react-native-1.1.0.tgz",
"integrity": "sha512-KaXU1KB+oDC309/rc0Wq47JbM2YOgk2EohhVwpwBK5awoKUKZyW/Ne6euzknkKdTBy3kAOJlh3wI9aMkvBAgpA==",
"license": "Apache-2.0",
"dependencies": {
"@splitsoftware/splitio-commons": "2.1.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -6222,6 +6258,15 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/ioredis": {
"version": "4.28.10",
"resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz",
"integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -14325,6 +14370,12 @@
"react-native": "*"
}
},
"node_modules/react-native-event-source": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/react-native-event-source/-/react-native-event-source-1.1.0.tgz",
"integrity": "sha512-CAs76IW8kTrdy0okfV2KPopm7E9TL0uNAR+SRrN7iZ/ii0zBeHWuhD4Q2F8gRKvmkrEtCZ6uwnfYL2TFmK0QZg==",
"license": "MIT"
},
"node_modules/react-native-gesture-handler": {
"version": "2.20.2",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz",

View File

@@ -29,6 +29,7 @@
"@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1",
"@sentry/react-native": "~6.3.0",
"@splitsoftware/splitio-react-native": "^1.1.0",
"axios": "^1.7.9",
"cloudinary-core": "^2.13.1",
"dinero.js": "^1.9.1",
@@ -65,6 +66,7 @@
"react-native": "0.76.7",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-element-dropdown": "^2.12.4",
"react-native-event-source": "^1.1.0",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-gallery": "^2.1.5",
"react-native-image-viewing": "^0.2.2",

View File

@@ -5,14 +5,14 @@ import env from "../env";
import { client } from "../graphql/client";
import { INSERT_NEW_DOCUMENT } from "../graphql/documents.queries";
import { axiosAuthInterceptorId } from "./CleanAxios";
import { splitClient } from "../components/screen-main/screen-main.component";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
//Required to prevent headers from getting set and rejected from Cloudinary.
var cleanAxios = axios.create();
cleanAxios.interceptors.request.eject(axiosAuthInterceptorId);
export const handleUpload = async (ev, context, destination) => {
export const handleUpload = async (ev, context) => {
const { mediaId, onError, onSuccess, onProgress } = ev;
const { bodyshop, jobId } = context;
@@ -22,6 +22,10 @@ export const handleUpload = async (ev, context, destination) => {
).blob();
let extension = imageData.localUri.split(".").pop();
//Default to Cloudinary in case of split treatment errors.
let destination =
splitClient?.getTreatment("Imgproxy") === "on" ? "imgproxy" : "cloudinary";
let key =
destination === "imgproxy"
? `${bodyshop.id}/${jobId}/${replaceAccents(