Added google analytics tracking.
This commit is contained in:
2
App.js
2
App.js
@@ -9,6 +9,7 @@ import { PersistGate } from "redux-persist/integration/react";
|
|||||||
import * as Sentry from "sentry-expo";
|
import * as Sentry from "sentry-expo";
|
||||||
import ScreenMainComponent from "./components/screen-main/screen-main.component";
|
import ScreenMainComponent from "./components/screen-main/screen-main.component";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
|
import { logImEXEvent } from "./firebase/firebase.utils";
|
||||||
import { client } from "./graphql/client";
|
import { client } from "./graphql/client";
|
||||||
import { persistor, store } from "./redux/store";
|
import { persistor, store } from "./redux/store";
|
||||||
import "./translations/i18n";
|
import "./translations/i18n";
|
||||||
@@ -32,6 +33,7 @@ export default class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
logImEXEvent("imexmobile_app_start");
|
||||||
await Font.loadAsync({
|
await Font.loadAsync({
|
||||||
Roboto: require("native-base/Fonts/Roboto.ttf"),
|
Roboto: require("native-base/Fonts/Roboto.ttf"),
|
||||||
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
|
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
|
||||||
|
|||||||
36
GoogleService-Info.plist
Normal file
36
GoogleService-Info.plist
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CLIENT_ID</key>
|
||||||
|
<string>253497221485-qgnj5ve8q0gk2jsmsbsf8qh1i8q04enq.apps.googleusercontent.com</string>
|
||||||
|
<key>REVERSED_CLIENT_ID</key>
|
||||||
|
<string>com.googleusercontent.apps.253497221485-qgnj5ve8q0gk2jsmsbsf8qh1i8q04enq</string>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyAVKJ2eHZpKxsA0a3qyZImg-ePfuwcuCrE</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>253497221485</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.imex.imexmobile</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>imex-prod</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>imex-prod.appspot.com</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:253497221485:ios:fcbe67f6c6f7da68227a64</string>
|
||||||
|
<key>DATABASE_URL</key>
|
||||||
|
<string>https://imex-prod.firebaseio.com</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
20
app.json
20
app.json
@@ -8,11 +8,13 @@
|
|||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "com.imex.imexmobile",
|
"bundleIdentifier": "com.imex.imexmobile",
|
||||||
"buildNumber": "1.0.3"
|
"buildNumber": "1.0.3",
|
||||||
|
"googleServicesFile": "./GoogleService-Info.plist"
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"package": "com.imex.imexmobile",
|
"package": "com.imex.imexmobile",
|
||||||
"versionCode": 1
|
"versionCode": 1,
|
||||||
|
"googleServicesFile": "./google-services.json"
|
||||||
},
|
},
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/logo1024.png",
|
"image": "./assets/logo1024.png",
|
||||||
@@ -28,7 +30,19 @@
|
|||||||
"assetBundlePatterns": ["**/*"],
|
"assetBundlePatterns": ["**/*"],
|
||||||
|
|
||||||
"web": {
|
"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": "",
|
"description": "",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
|
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
|
||||||
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
|
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
|
||||||
import { selectCurrentCameraJobId } from "../../redux/app/app.selectors";
|
import { selectCurrentCameraJobId } from "../../redux/app/app.selectors";
|
||||||
@@ -48,6 +49,7 @@ export function CameraSelectJob({
|
|||||||
<Picker
|
<Picker
|
||||||
selectedValue={cameraJobId}
|
selectedValue={cameraJobId}
|
||||||
onValueChange={(value, idx) => {
|
onValueChange={(value, idx) => {
|
||||||
|
logImEXEvent("imexmobile_setcamerajobid");
|
||||||
setCameraJobId(value);
|
setCameraJobId(value);
|
||||||
setCameraJob(data.jobs[idx]);
|
setCameraJob(data.jobs[idx]);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TouchableOpacity } from "react-native-gesture-handler";
|
|||||||
import Swipeable from "react-native-gesture-handler/Swipeable";
|
import Swipeable from "react-native-gesture-handler/Swipeable";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
|
import { setCameraJob, setCameraJobId } from "../../redux/app/app.actions";
|
||||||
import styles from "../styles";
|
import styles from "../styles";
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) {
|
|||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.swipe_view, styles.swipe_view_blue]}
|
style={[styles.swipe_view, styles.swipe_view_blue]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
logImEXEvent("imexmobile_setcamerajobid_swipe");
|
||||||
setCameraJobId(item.id);
|
setCameraJobId(item.id);
|
||||||
setCameraJob(item);
|
setCameraJob(item);
|
||||||
navigation.navigate("MediaBrowserTab");
|
navigation.navigate("MediaBrowserTab");
|
||||||
@@ -50,6 +52,7 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
|
logImEXEvent("imexmobile_view_job_detail");
|
||||||
navigation.push("JobDetail", {
|
navigation.push("JobDetail", {
|
||||||
jobId: item.id,
|
jobId: item.id,
|
||||||
title: item.ro_number || t("general.labels.na"),
|
title: item.ro_number || t("general.labels.na"),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { StyleSheet, Text, View } from "react-native";
|
import { StyleSheet, Text, View } from "react-native";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import {
|
import {
|
||||||
selectCurrentCameraJobId,
|
selectCurrentCameraJobId,
|
||||||
selectDeleteAfterUpload,
|
selectDeleteAfterUpload,
|
||||||
@@ -51,6 +52,7 @@ export function ImageBrowserScreen({
|
|||||||
|
|
||||||
async function handleOnSuccess(uri, id) {
|
async function handleOnSuccess(uri, id) {
|
||||||
console.log("Succesful upload!", uri);
|
console.log("Succesful upload!", uri);
|
||||||
|
logImEXEvent("imexmobile_successful_upload");
|
||||||
if (deleteAfterUpload) {
|
if (deleteAfterUpload) {
|
||||||
try {
|
try {
|
||||||
const result = await MediaLibrary.deleteAssetsAsync([id]);
|
const result = await MediaLibrary.deleteAssetsAsync([id]);
|
||||||
@@ -64,6 +66,7 @@ export function ImageBrowserScreen({
|
|||||||
|
|
||||||
const onDone = async (data) => {
|
const onDone = async (data) => {
|
||||||
console.log("Assets :>> ", data);
|
console.log("Assets :>> ", data);
|
||||||
|
logImEXEvent("imexmobile_upload_documents", { count: data.length });
|
||||||
const actions = [];
|
const actions = [];
|
||||||
data.forEach(function (p) {
|
data.forEach(function (p) {
|
||||||
let filename;
|
let filename;
|
||||||
@@ -205,6 +208,7 @@ const styles = StyleSheet.create({
|
|||||||
|
|
||||||
function handleOnError(...props) {
|
function handleOnError(...props) {
|
||||||
console.log("HandleOnError", props);
|
console.log("HandleOnError", props);
|
||||||
|
logImEXEvent("imexmobile_upload_documents_error", { props });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(ImageBrowserScreen);
|
export default connect(mapStateToProps, null)(ImageBrowserScreen);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { StyleSheet, Switch, Text, View } from "react-native";
|
import { StyleSheet, Switch, Text, View } from "react-native";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { toggleDeleteAfterUpload } from "../../redux/app/app.actions";
|
import { toggleDeleteAfterUpload } from "../../redux/app/app.actions";
|
||||||
import { selectDeleteAfterUpload } from "../../redux/app/app.selectors";
|
import { selectDeleteAfterUpload } from "../../redux/app/app.selectors";
|
||||||
|
|
||||||
@@ -29,7 +30,10 @@ export function UploadDeleteSwitch({
|
|||||||
trackColor={{ false: "#767577", true: "#81b0ff" }}
|
trackColor={{ false: "#767577", true: "#81b0ff" }}
|
||||||
thumbColor={deleteAfterUpload ? "tomato" : "#f4f3f4"}
|
thumbColor={deleteAfterUpload ? "tomato" : "#f4f3f4"}
|
||||||
ios_backgroundColor="#3e3e3e"
|
ios_backgroundColor="#3e3e3e"
|
||||||
onValueChange={() => toggleDeleteAfterUpload()}
|
onValueChange={() => {
|
||||||
|
logImEXEvent("imexmobile_toggle_delete_after_upload");
|
||||||
|
toggleDeleteAfterUpload();
|
||||||
|
}}
|
||||||
value={deleteAfterUpload}
|
value={deleteAfterUpload}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import * as Analytics from "expo-firebase-analytics";
|
||||||
import * as firebase from "firebase/app";
|
import * as firebase from "firebase/app";
|
||||||
import "firebase/auth";
|
import "firebase/auth";
|
||||||
|
import { store } from "../redux/store";
|
||||||
|
|
||||||
//const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
|
//const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
|
||||||
// const config = {
|
// const config = {
|
||||||
@@ -52,3 +54,25 @@ export const updateCurrentUser = (userDetails) => {
|
|||||||
}, reject);
|
}, 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;
|
||||||
|
|||||||
47
google-services.json
Normal file
47
google-services.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"expo-av": "~8.7.0",
|
"expo-av": "~8.7.0",
|
||||||
"expo-camera": "~9.1.0",
|
"expo-camera": "~9.1.0",
|
||||||
"expo-file-system": "~9.3.0",
|
"expo-file-system": "~9.3.0",
|
||||||
|
"expo-firebase-analytics": "~2.6.0",
|
||||||
"expo-font": "~8.4.0",
|
"expo-font": "~8.4.0",
|
||||||
"expo-images-picker": "https://github.com/snaptsoft/expo-images-picker/",
|
"expo-images-picker": "https://github.com/snaptsoft/expo-images-picker/",
|
||||||
"expo-localization": "~9.1.0",
|
"expo-localization": "~9.1.0",
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
|
import * as Analytics from "expo-firebase-analytics";
|
||||||
import { all, call, put, takeLatest } from "redux-saga/effects";
|
import { all, call, put, takeLatest } from "redux-saga/effects";
|
||||||
import {
|
import {
|
||||||
auth,
|
auth,
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
|
logImEXEvent,
|
||||||
updateCurrentUser,
|
updateCurrentUser,
|
||||||
} from "../../firebase/firebase.utils";
|
} from "../../firebase/firebase.utils";
|
||||||
|
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||||
|
import { client } from "../../graphql/client";
|
||||||
import {
|
import {
|
||||||
sendPasswordResetFailure,
|
sendPasswordResetFailure,
|
||||||
sendPasswordResetSuccess,
|
sendPasswordResetSuccess,
|
||||||
|
setBodyshop,
|
||||||
signInFailure,
|
signInFailure,
|
||||||
signInSuccess,
|
signInSuccess,
|
||||||
signOutFailure,
|
signOutFailure,
|
||||||
@@ -15,18 +20,15 @@ import {
|
|||||||
updateUserDetailsSuccess,
|
updateUserDetailsSuccess,
|
||||||
validatePasswordResetFailure,
|
validatePasswordResetFailure,
|
||||||
validatePasswordResetSuccess,
|
validatePasswordResetSuccess,
|
||||||
setBodyshop,
|
|
||||||
} from "./user.actions";
|
} from "./user.actions";
|
||||||
import UserActionTypes from "./user.types";
|
import UserActionTypes from "./user.types";
|
||||||
import { client } from "../../graphql/client";
|
|
||||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
|
||||||
|
|
||||||
export function* onEmailSignInStart() {
|
export function* onEmailSignInStart() {
|
||||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||||
}
|
}
|
||||||
export function* signInWithEmail({ payload: { email, password } }) {
|
export function* signInWithEmail({ payload: { email, password } }) {
|
||||||
try {
|
try {
|
||||||
//logImEXEvent("redux_sign_in_attempt", { user: email });
|
logImEXEvent("imexmobile_sign_in_attempt", { user: email });
|
||||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||||
yield put(
|
yield put(
|
||||||
signInSuccess({
|
signInSuccess({
|
||||||
@@ -74,7 +76,7 @@ export function* onSignOutStart() {
|
|||||||
}
|
}
|
||||||
export function* signOutStart() {
|
export function* signOutStart() {
|
||||||
try {
|
try {
|
||||||
//logImEXEvent("redux_sign_out");
|
logImEXEvent("imexmobile_sign_out");
|
||||||
|
|
||||||
yield auth.signOut();
|
yield auth.signOut();
|
||||||
yield put(signOutSuccess());
|
yield put(signOutSuccess());
|
||||||
@@ -102,8 +104,10 @@ export function* onSignInSuccess() {
|
|||||||
|
|
||||||
export function* signInSuccessSaga({ payload }) {
|
export function* signInSuccessSaga({ payload }) {
|
||||||
try {
|
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]));
|
yield put(setBodyshop(shop.data.bodyshops[0]));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("UH-OH. Couldn't get shop details.", error);
|
console.log("UH-OH. Couldn't get shop details.", error);
|
||||||
|
|||||||
12
yarn.lock
12
yarn.lock
@@ -4282,6 +4282,18 @@ expo-file-system@~9.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
uuid "^3.4.0"
|
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:
|
expo-font@~8.4.0:
|
||||||
version "8.4.0"
|
version "8.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-8.4.0.tgz#7cb4cc9d852dd8d0977ce425146b94221b40c1d5"
|
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-8.4.0.tgz#7cb4cc9d852dd8d0977ce425146b94221b40c1d5"
|
||||||
|
|||||||
Reference in New Issue
Block a user