Skip to content

Add personalization via Profiles API #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["module:metro-react-native-babel-preset"]
}
18 changes: 17 additions & 1 deletion .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,23 @@ node_modules/react-native/flow-github/
[options]
emoji=true

esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable

module.system=haste
module.system.haste.use_name_reducers=true
# get basename
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
# strip .js or .js.flow suffix
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
# strip .ios suffix
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*

munge_underscores=true

Expand All @@ -51,4 +67,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

[version]
^0.67.0
^0.78.0
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ local.properties
node_modules/
npm-debug.log
yarn-error.log
third-party


# BUCK
buck-out/
Expand Down
52 changes: 33 additions & 19 deletions App/Analytics/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Analytics from "@segment/analytics-react-native";
import Appboy from "@segment/analytics-react-native-appboy";
import Analytics from '@segment/analytics-react-native';
import Appboy from '@segment/analytics-react-native-appboy';
import Config from 'react-native-config';
import R from 'ramda';

Expand All @@ -9,22 +9,36 @@ import R from 'ramda';
// implementation approach but these are here to illustrate how to call the
// various Segment eCommerce events.

const TRACK_PRODUCT_ADDED = "Product Added";
const TRACK_PRODUCT_REMOVED = "Product Removed";
const TRACK_PRODUCT_VIEWED = "Product Viewed";
const TRACK_PRODUCT_CLICKED = "Product Clicked";
const TRACK_PRODUCT_ADDED = 'Product Added';
const TRACK_PRODUCT_REMOVED = 'Product Removed';
const TRACK_PRODUCT_VIEWED = 'Product Viewed';
const TRACK_PRODUCT_CLICKED = 'Product Clicked';

const TRACK_CHECKOUT_STARTED = "Checkout Started";
const TRACK_CHECKOUT_COMPLETED = "Order Completed";
const TRACK_CART_VIEWED = "Cart Viewed";
const TRACK_PRODUCT_LIST_VIEWED = "Product List Viewed";
const TRACK_CHECKOUT_STARTED = 'Checkout Started';
const TRACK_CHECKOUT_COMPLETED = 'Order Completed';
const TRACK_CART_VIEWED = 'Cart Viewed';
const TRACK_PRODUCT_LIST_VIEWED = 'Product List Viewed';

Analytics
.configure()
.trackAppLifecycleEvents()
.using(Appboy)
.debug()
.setup(Config.SEGMENT_WRITE_KEY)
Analytics.setup(Config.SEGMENT_WRITE_KEY, {
using: [Appboy],
recordScreenViews: false,
trackAppLifecycleEvents: false,
trackAttributionData: true,

android: {
flushInterval: 60,
collectDeviceId: true
},
ios: {
trackAdvertising: true,
trackDeepLinks: true
}
})
.then(() =>
console.log('Analytics is ready')
).catch(err =>
console.error('Something went wrong', err)
);

export function identify(id, email) {
Analytics.identify(id, {
Expand All @@ -44,15 +58,15 @@ export function checkoutStarted(cart) {
Analytics.track(TRACK_CHECKOUT_STARTED, {
revenue: cart.total,
products: cart.products,
currency: "USD"
currency: 'USD'
});
}

export function checkoutCompleted(cart) {
Analytics.track(TRACK_CHECKOUT_COMPLETED, {
total: cart.total,
products: cart.products,
currency: "USD"
currency: 'USD'
});
}

Expand All @@ -70,5 +84,5 @@ export function productListViewed(productList) {
// Remove variants as these make messages too large with the
// default Shopify payloads
Analytics.track(TRACK_PRODUCT_LIST_VIEWED, { products: getProducts(productList) });
Analytics.flush(); // Called to show this event immediately
Analytics.flush(); // Called to show this event immediately
}
50 changes: 30 additions & 20 deletions App/Components/NavigationHeader.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React, { Component } from "react";
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
TouchableOpacity,
Image,
ImageBackground
} from "react-native";
import { connect } from "react-redux";
import { isIphoneX } from "../Themes/Metrics";
import * as Segment from "../Analytics";
} from 'react-native';
import { connect } from 'react-redux';
import { isIphoneX } from '../Themes/Metrics';
import * as Segment from '../Analytics';

const style = StyleSheet.create({
headerContainer: {
flex: 1,
width: "100%",
flexDirection: "row",
width: '100%',
flexDirection: 'row',
height: 125,
marginTop: 40 // TODO: This is an iOS only header
},
Expand All @@ -26,9 +26,9 @@ const style = StyleSheet.create({
});

const Images = {
bagButtonSmall: require("../Images/Icons/shopping-bag-512.png"),
cancelButtonSmall: require("../Images/Icons/cancel-32.png"),
backButtonSmall: require("../Images/Icons/back-arrow-32.png")
bagButtonSmall: require('../Images/Icons/shopping-bag-512.png'),
cancelButtonSmall: require('../Images/Icons/cancel-32.png'),
backButtonSmall: require('../Images/Icons/back-arrow-32.png')
};

class NavigationHeader extends Component {
Expand All @@ -39,10 +39,12 @@ class NavigationHeader extends Component {
cartItems = () => {
if (this.props.cart.products.length > 0) {
return (
<Text style={{ textAlign: "center", alignSelf: "center", top: 10 }}>{`${ this.props.cart.products.length }`}</Text>
<Text style={{ textAlign: 'center', alignSelf: 'center', top: 10 }}>{`${
this.props.cart.products.length
}`}</Text>
);
} else {
return (<Text>{""}</Text>);
return <Text>{''}</Text>;
}
};

Expand All @@ -61,7 +63,7 @@ class NavigationHeader extends Component {
<TouchableOpacity
onPress={() => {
Segment.cartViewed(this.props.cart);
this.props.navigation.navigate("ShoppingBagScreen");
this.props.navigation.navigate('ShoppingBagScreen');
}}
>
<ImageBackground
Expand All @@ -78,7 +80,15 @@ class NavigationHeader extends Component {
modalOrNotLeft = () => {
if (!this.props.modal && !isIphoneX() && this.props.nav.index !== 0) {
return (
<View style={{ flex: 0.2, marginTop: 45, marginRight: 1, flexDirection: "row", justifyContent: "center" }} >
<View
style={{
flex: 0.2,
marginTop: 45,
marginRight: 1,
flexDirection: 'row',
justifyContent: 'center'
}}
>
<TouchableOpacity onPress={() => this.props.navigation.goBack()}>
<Image
style={{ height: 30, width: 30 }}
Expand All @@ -99,15 +109,15 @@ class NavigationHeader extends Component {
<View
style={{
height: 90,
backgroundColor: "white",
flexDirection: "row",
backgroundColor: 'white',
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: "#43464b"
borderColor: '#43464b'
}}
>
{this.modalOrNotLeft()}
<View style={{ flex: 0.6, marginTop: 55 }}>
<Text style={{ fontSize: 20, textAlign: "center" }}>
<Text style={{ fontSize: 20, textAlign: 'center' }}>
{this.props.title}
</Text>
</View>
Expand All @@ -116,8 +126,8 @@ class NavigationHeader extends Component {
flex: 0.2,
marginTop: 45,
marginLeft: 1,
flexDirection: "row",
justifyContent: "center"
flexDirection: 'row',
justifyContent: 'center'
}}
>
{this.modalOrNotRight()}
Expand Down
26 changes: 14 additions & 12 deletions App/Components/ProductsGrid.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
import React, { Component } from 'react';
import { FlatList,
View,
Text,
Image,
TouchableOpacity } from 'react-native';
import { FlatList, View, Text, Image, TouchableOpacity } from 'react-native';
import styles from '../Containers/Styles/LaunchScreenStyles';
import { Metrics } from '../Themes';
import * as Segment from '../Analytics';

export default class ProductsGrid extends Component {
renderItem = (item) => {
renderItem = item => {
onPress = () => {
this.props.onPressItem(item.item);
}
};

return (
<TouchableOpacity onPress={onPress}>
<View style={styles.itemContainer}>
<Image style={styles.imageStyle} source={{uri: `${item.item.variants.edges[0].node.image.src}`}}/>
<Image
style={styles.imageStyle}
source={{ uri: `${item.item.variants.edges[0].node.image.src}` }}
/>
<View style={styles.itemTitleBar}>
<Text style={styles.itemLabel}>{item.item.title}</Text>
<Text style={styles.itemPrice}>${item.item.variants.edges[0].node.price}</Text>
<Text style={styles.itemPrice}>
${item.item.variants.edges[0].node.price}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
};

render() {
if(this.props.products) Segment.productListViewed(this.props.products);
if (this.props.products) Segment.productListViewed(this.props.products);
return (
<FlatList
data={this.props.products}
renderItem={this.renderItem}
keyExtractor={item => item.id}
numColumns={Metrics.productList.numColumns} />
numColumns={Metrics.productList.numColumns}
/>
);
}
}
68 changes: 45 additions & 23 deletions App/Components/VariantSelector.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,62 @@
import React, { Component } from 'react';
import { Button,
ActionSheetIOS,
TouchableOpacity,
Text } from 'react-native';
import {
Button,
ActionSheetIOS,
TouchableOpacity,
Text,
Platform,
Picker
} from 'react-native';
import FullButton from './FullButton';

export default class VariantSelector extends Component {

showActionSheet = () => {
let sizeLabels = [];
sizeLabels.push('CANCEL');
this.props.variants.edges.map(
(variant) => sizeLabels.push(variant.node.title.toUpperCase()));
ActionSheetIOS.showActionSheetWithOptions({
options: sizeLabels,
cancelButtonIndex: 0,
},
(buttonIndex) => {
if(buttonIndex > 0) {
this.props.handleOptionChange(sizeLabels[buttonIndex]);
}
});
}
this.props.variants.edges.map(variant =>
sizeLabels.push(variant.node.title.toUpperCase())
);
if (Platform.OS === 'ios') {
ActionSheetIOS.showActionSheetWithOptions(
{
options: sizeLabels,
cancelButtonIndex: 0
},
buttonIndex => {
if (buttonIndex > 0) {
this.props.handleOptionChange(sizeLabels[buttonIndex]);
}
}
);
}
if (Platform.OS === 'android') {
<Picker
style={{ width: 100 }}
selectedValue={this.props.selectedVariant}
onValueChange={(itemValue, itemIndex) =>
this.props.handleOptionChange(sizeLabels[itemIndex])
}
>
{sizeLabels.map((elem, index) => {
<Picker.Item label={elem} value={elem} />;
})}
</Picker>;
}
};

sizeSelectorLabel = () => {
return this.props.selectedVariant === null ?
'SELECT A SIZE' :
`SIZE: ${this.props.selectedVariant}`;
}
return this.props.selectedVariant === null
? 'SELECT A SIZE'
: `SIZE: ${this.props.selectedVariant}`;
};

render() {
return (
<FullButton
style={{marginTop: 20}}
style={{ marginTop: 20 }}
onPress={this.showActionSheet}
text={`${this.sizeSelectorLabel()}`}/>
text={`${this.sizeSelectorLabel()}`}
/>
);
}
}
Loading