diff --git a/App.js b/App.js index 4dd4934..03a0515 100644 --- a/App.js +++ b/App.js @@ -9,6 +9,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 { client } from "./graphql/client"; import { persistor, store } from "./redux/store"; import "./translations/i18n"; @@ -32,6 +33,7 @@ export default class App extends React.Component { } async componentDidMount() { + logImEXEvent("imexmobile_app_start"); await Font.loadAsync({ Roboto: require("native-base/Fonts/Roboto.ttf"), Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"), diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist new file mode 100644 index 0000000..9b285f7 --- /dev/null +++ b/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 253497221485-qgnj5ve8q0gk2jsmsbsf8qh1i8q04enq.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.253497221485-qgnj5ve8q0gk2jsmsbsf8qh1i8q04enq + API_KEY + AIzaSyAVKJ2eHZpKxsA0a3qyZImg-ePfuwcuCrE + GCM_SENDER_ID + 253497221485 + PLIST_VERSION + 1 + BUNDLE_ID + com.imex.imexmobile + PROJECT_ID + imex-prod + STORAGE_BUCKET + imex-prod.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:253497221485:ios:fcbe67f6c6f7da68227a64 + DATABASE_URL + https://imex-prod.firebaseio.com + + \ No newline at end of file diff --git a/app.json b/app.json index 8c80422..53c83cb 100644 --- a/app.json +++ b/app.json @@ -8,11 +8,13 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "com.imex.imexmobile", - "buildNumber": "1.0.3" + "buildNumber": "1.0.3", + "googleServicesFile": "./GoogleService-Info.plist" }, "android": { "package": "com.imex.imexmobile", - "versionCode": 1 + "versionCode": 1, + "googleServicesFile": "./google-services.json" }, "splash": { "image": "./assets/logo1024.png", @@ -28,7 +30,19 @@ "assetBundlePatterns": ["**/*"], "web": { - "favicon": "./assets/logo192noa.png" + "favicon": "./assets/logo192noa.png", + "config": { + "firebase": { + "apiKey": "AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU", + "authDomain": "imex-prod.firebaseapp.com", + "databaseURL": "https://imex-prod.firebaseio.com", + "projectId": "imex-prod", + "storageBucket": "imex-prod.appspot.com", + "messagingSenderId": "253497221485", + "appId": "1:253497221485:web:9b65736a635a45ce227a64", + "measurementId": "G-96694D66L2" + } + } }, "description": "", "hooks": { diff --git a/components/camera-select-job/camera-select-job.component.jsx b/components/camera-select-job/camera-select-job.component.jsx index 2e311f0..613c4d2 100644 --- a/components/camera-select-job/camera-select-job.component.jsx +++ b/components/camera-select-job/camera-select-job.component.jsx @@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next"; import { View } from "react-native"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { logImEXEvent } from "../../firebase/firebase.utils"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; import { selectCurrentCameraJobId } from "../../redux/app/app.selectors"; @@ -48,6 +49,7 @@ export function CameraSelectJob({ { + logImEXEvent("imexmobile_setcamerajobid"); setCameraJobId(value); setCameraJob(data.jobs[idx]); }} diff --git a/components/job-list-item/job-list-item.component.jsx b/components/job-list-item/job-list-item.component.jsx index 62c9b76..54e4221 100644 --- a/components/job-list-item/job-list-item.component.jsx +++ b/components/job-list-item/job-list-item.component.jsx @@ -8,6 +8,7 @@ import { TouchableOpacity } from "react-native-gesture-handler"; import Swipeable from "react-native-gesture-handler/Swipeable"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { logImEXEvent } from "../../firebase/firebase.utils"; import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions"; import styles from "../styles"; @@ -32,6 +33,7 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) { { + logImEXEvent("imexmobile_setcamerajobid_swipe"); setCameraJobId(item.id); setCameraJob(item); navigation.navigate("MediaBrowserTab"); @@ -50,6 +52,7 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) { }; const onPress = () => { + logImEXEvent("imexmobile_view_job_detail"); navigation.push("JobDetail", { jobId: item.id, title: item.ro_number || t("general.labels.na"), diff --git a/components/screen-media-browser/screen-media-browser.component.jsx b/components/screen-media-browser/screen-media-browser.component.jsx index 7b047a4..ac31b2f 100644 --- a/components/screen-media-browser/screen-media-browser.component.jsx +++ b/components/screen-media-browser/screen-media-browser.component.jsx @@ -9,6 +9,7 @@ import { useTranslation } from "react-i18next"; import { StyleSheet, Text, View } from "react-native"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { logImEXEvent } from "../../firebase/firebase.utils"; import { selectCurrentCameraJobId, selectDeleteAfterUpload, @@ -51,6 +52,7 @@ export function ImageBrowserScreen({ async function handleOnSuccess(uri, id) { console.log("Succesful upload!", uri); + logImEXEvent("imexmobile_successful_upload"); if (deleteAfterUpload) { try { const result = await MediaLibrary.deleteAssetsAsync([id]); @@ -64,6 +66,7 @@ export function ImageBrowserScreen({ const onDone = async (data) => { console.log("Assets :>> ", data); + logImEXEvent("imexmobile_upload_documents", { count: data.length }); const actions = []; data.forEach(function (p) { let filename; @@ -205,6 +208,7 @@ const styles = StyleSheet.create({ function handleOnError(...props) { console.log("HandleOnError", props); + logImEXEvent("imexmobile_upload_documents_error", { props }); } export default connect(mapStateToProps, null)(ImageBrowserScreen); diff --git a/components/upload-delete-switch/upload-delete-switch.component.jsx b/components/upload-delete-switch/upload-delete-switch.component.jsx index a1542ec..2bc9358 100644 --- a/components/upload-delete-switch/upload-delete-switch.component.jsx +++ b/components/upload-delete-switch/upload-delete-switch.component.jsx @@ -3,6 +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 { toggleDeleteAfterUpload } from "../../redux/app/app.actions"; import { selectDeleteAfterUpload } from "../../redux/app/app.selectors"; @@ -29,7 +30,10 @@ export function UploadDeleteSwitch({ trackColor={{ false: "#767577", true: "#81b0ff" }} thumbColor={deleteAfterUpload ? "tomato" : "#f4f3f4"} ios_backgroundColor="#3e3e3e" - onValueChange={() => toggleDeleteAfterUpload()} + onValueChange={() => { + logImEXEvent("imexmobile_toggle_delete_after_upload"); + toggleDeleteAfterUpload(); + }} value={deleteAfterUpload} /> diff --git a/firebase/firebase.utils.js b/firebase/firebase.utils.js index 2991b51..b06b826 100644 --- a/firebase/firebase.utils.js +++ b/firebase/firebase.utils.js @@ -1,5 +1,7 @@ +import * as Analytics from "expo-firebase-analytics"; import * as firebase from "firebase/app"; import "firebase/auth"; +import { store } from "../redux/store"; //const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG); // const config = { @@ -52,3 +54,25 @@ export const updateCurrentUser = (userDetails) => { }, reject); }); }; + +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/google-services.json b/google-services.json new file mode 100644 index 0000000..162fc0e --- /dev/null +++ b/google-services.json @@ -0,0 +1,47 @@ +{ + "project_info": { + "project_number": "253497221485", + "firebase_url": "https://imex-prod.firebaseio.com", + "project_id": "imex-prod", + "storage_bucket": "imex-prod.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:253497221485:android:c48f224bc1afd537227a64", + "android_client_info": { + "package_name": "com.imex.imexmobile" + } + }, + "oauth_client": [ + { + "client_id": "253497221485-1tjt8aflekk0s4d1jibd8p7cbtkoocv1.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDfmdrww4t6cnHbB4yNpJv0qLLRTwzIyUs" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "253497221485-1tjt8aflekk0s4d1jibd8p7cbtkoocv1.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "253497221485-qgnj5ve8q0gk2jsmsbsf8qh1i8q04enq.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.imex.imexmobile" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/package.json b/package.json index dcbe3ee..341ceff 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "expo-av": "~8.7.0", "expo-camera": "~9.1.0", "expo-file-system": "~9.3.0", + "expo-firebase-analytics": "~2.6.0", "expo-font": "~8.4.0", "expo-images-picker": "https://github.com/snaptsoft/expo-images-picker/", "expo-localization": "~9.1.0", diff --git a/redux/user/user.sagas.js b/redux/user/user.sagas.js index 2fd0e55..9ea8ce6 100644 --- a/redux/user/user.sagas.js +++ b/redux/user/user.sagas.js @@ -1,12 +1,17 @@ +import * as Analytics from "expo-firebase-analytics"; import { all, call, put, takeLatest } from "redux-saga/effects"; import { auth, getCurrentUser, + logImEXEvent, updateCurrentUser, } from "../../firebase/firebase.utils"; +import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries"; +import { client } from "../../graphql/client"; import { sendPasswordResetFailure, sendPasswordResetSuccess, + setBodyshop, signInFailure, signInSuccess, signOutFailure, @@ -15,18 +20,15 @@ import { updateUserDetailsSuccess, validatePasswordResetFailure, validatePasswordResetSuccess, - setBodyshop, } from "./user.actions"; import UserActionTypes from "./user.types"; -import { client } from "../../graphql/client"; -import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries"; export function* onEmailSignInStart() { yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail); } export function* signInWithEmail({ payload: { email, password } }) { try { - //logImEXEvent("redux_sign_in_attempt", { user: email }); + logImEXEvent("imexmobile_sign_in_attempt", { user: email }); const { user } = yield auth.signInWithEmailAndPassword(email, password); yield put( signInSuccess({ @@ -74,7 +76,7 @@ export function* onSignOutStart() { } export function* signOutStart() { try { - //logImEXEvent("redux_sign_out"); + logImEXEvent("imexmobile_sign_out"); yield auth.signOut(); yield put(signOutSuccess()); @@ -102,8 +104,10 @@ export function* onSignInSuccess() { export function* signInSuccessSaga({ payload }) { try { - const shop = yield client.query({ query: QUERY_BODYSHOP }); + Analytics.setUserId(payload.email); + const shop = yield client.query({ query: QUERY_BODYSHOP }); + logImEXEvent("imexmobile_sign_in_success", payload); yield put(setBodyshop(shop.data.bodyshops[0])); } catch (error) { console.log("UH-OH. Couldn't get shop details.", error); diff --git a/yarn.lock b/yarn.lock index 2f40c25..79f6fe9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4282,6 +4282,18 @@ expo-file-system@~9.3.0: dependencies: uuid "^3.4.0" +expo-firebase-analytics@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/expo-firebase-analytics/-/expo-firebase-analytics-2.6.0.tgz#6c549ed2dceecb22d7d7160034a00896963d38a3" + integrity sha512-ciLHxYKfS0Oih184ckVJyYj95fWvK+xfDXG9yOkpzow/NIf9snp8ziXSMyJTwFg93bNr3uqvKxk985LSvEPe9Q== + dependencies: + expo-firebase-core "~1.2.0" + +expo-firebase-core@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/expo-firebase-core/-/expo-firebase-core-1.2.0.tgz#1f41d777cb04e19f495d27491b1596bdeb233f95" + integrity sha512-ojqiJLlH5BXQsrElPOtYsO0tHR2333mRDxV625Y0NQyjFBF17NQxlmCCkyh2uGO94LgcZTfB13SMiNHOe9RcZQ== + expo-font@~8.4.0: version "8.4.0" resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-8.4.0.tgz#7cb4cc9d852dd8d0977ce425146b94221b40c1d5"