Skip to content

Commit cde1345

Browse files
committed
Add in OpenTelemetry demo functionality
1 parent 5086019 commit cde1345

34 files changed

+6799
-5603
lines changed

.licenserc.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
"src/featureflagservice/assets/vendor/",
4646
"src/featureflagservice/priv/",
4747
"src/productcatalogservice/genproto/",
48+
"src/reactnativeapp/ios/Pods/",
49+
"src/reactnativeapp/ios/build/",
50+
"src/reactnativeapp/android/app/build/",
51+
"src/reactnativeapp/android/.gradle/",
52+
"src/reactnativeapp/.expo/",
53+
"src/reactnativeapp/expo-env.d.ts",
4854
"internal/tools/"
4955
]
50-
}
56+
}

Makefile

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
# All documents to be used in spell check.
6-
ALL_DOCS := $(shell find . -type f -name '*.md' -not -path './.github/*' -not -path '*/node_modules/*' -not -path '*/_build/*' -not -path '*/deps/*' | sort)
6+
ALL_DOCS := $(shell find . -type f -name '*.md' -not -path './.github/*' -not -path '*/node_modules/*' -not -path '*/_build/*' -not -path '*/deps/*' -not -path */Pods/* -not -path */.expo/* | sort)
77
PWD := $(shell pwd)
88

99
TOOLS_DIR := ./internal/tools
@@ -191,3 +191,13 @@ else
191191
@echo "Please provide a service name using `service=[service name]` or `SERVICE=[service name]`"
192192
endif
193193

194+
src/reactnativeapp/node_modules:
195+
npm --prefix src/reactnativeapp install
196+
197+
.PHONY: reactnative-android
198+
reactnative-android: src/reactnativeapp/node_modules
199+
npm --prefix src/reactnativeapp run android
200+
201+
.PHONY: reactnative-ios
202+
reactnative-ios: src/reactnativeapp/node_modules
203+
npm --prefix src/reactnativeapp run ios

ide-gen-proto.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ gen_proto_go checkoutservice
7272
# gen_proto_cpp currencyservice
7373
# gen_proto_ruby emailservice
7474
gen_proto_ts frontend
75+
gen_proto_ts reactnativeapp
7576
gen_proto_js paymentservice
7677
gen_proto_go productcatalogservice
7778
# gen_proto_php quoteservice

src/reactnativeapp/.env

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# https://docs.expo.dev/guides/environment-variables/
2+
3+
EXPO_PUBLIC_FRONTEND_PROXY_PORT=8080

src/reactnativeapp/.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ web-build/
1717
# The following patterns were generated by expo-cli
1818

1919
expo-env.d.ts
20-
# @end expo-cli
20+
# @end expo-cli
21+
22+
# TODO, should we consider committing these?
23+
protos/demo.ts
24+
pb/demo.proto

src/reactnativeapp/README.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,59 @@
11
# Example React Native app
22

3-
This was created using [`npx create-expo-app@latest`](https://reactnative.dev/docs/environment-setup#start-a-new-react-native-project-with-expo)
3+
This was created using [`npx create-expo-app@latest`](https://reactnative.dev/docs/environment-setup#start-a-new-react-native-project-with-expo)
4+
5+
Content was taken from the web app example in src/frontend and modified to work
6+
in a React Native environment.
7+
8+
## Get started
9+
10+
Unlike the other components under src/ which run within docker containers this
11+
app is meant to be run on either mobile emulators on your machine or physical
12+
devices. If this is your first time running a React Native app you will need to
13+
setup your local environment for Android or iOS development or both following
14+
[this guide](https://reactnative.dev/docs/set-up-your-environment).
15+
16+
Start the OpenTelemetry demo:
17+
18+
```bash
19+
cd ../..
20+
make start # or start-minimal
21+
```
22+
23+
Before running the app the Typescript protobuf files need to be generated. This
24+
requires at least `protoc`, if you do not have the other dev tools installed you
25+
can comment the other invocations in `ide-gen-proto.sh` and just have
26+
`gen_proto_ts reactnativeapp` before running:
27+
28+
```bash
29+
make generate-protobuf
30+
```
31+
32+
Then start the React Native app:
33+
34+
```bash
35+
make reactnative-android
36+
```
37+
38+
Or
39+
40+
```bash
41+
make reactnative-ios
42+
```
43+
44+
You can also install dependencies and launch the app directly from this folder using:
45+
46+
```bash
47+
cd src/reactnativeapp
48+
npm install
49+
```
50+
51+
```bash
52+
npm run android
53+
```
54+
55+
Or
56+
57+
```bash
58+
npm run ios
59+
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { Tabs } from "expo-router";
4+
import React from "react";
5+
import { TabBarIcon } from "@/components/navigation/TabBarIcon";
6+
import { useCart } from "@/providers/Cart.provider";
7+
8+
export default function TabLayout() {
9+
const {
10+
cart: { items },
11+
} = useCart();
12+
13+
let itemsInCart = 0;
14+
items.forEach((item) => {
15+
itemsInCart += item.quantity;
16+
});
17+
18+
return (
19+
<Tabs>
20+
<Tabs.Screen
21+
name="index"
22+
options={{
23+
title: "Products",
24+
tabBarShowLabel: false,
25+
tabBarIcon: ({ color, focused }) => (
26+
<TabBarIcon
27+
name={focused ? "list" : "list-outline"}
28+
color={color}
29+
/>
30+
),
31+
}}
32+
/>
33+
<Tabs.Screen
34+
name="cart"
35+
options={{
36+
title: "Cart",
37+
tabBarShowLabel: false,
38+
tabBarBadge: itemsInCart || undefined,
39+
tabBarIcon: ({ color, focused }) => (
40+
<TabBarIcon
41+
name={focused ? "cart" : "cart-outline"}
42+
color={color}
43+
/>
44+
),
45+
}}
46+
/>
47+
</Tabs>
48+
);
49+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
/**
4+
* Copied with modification from src/frontend/components/Cart/CartDetail.tsx
5+
*/
6+
import { router } from "expo-router";
7+
import { ThemedView } from "@/components/ThemedView";
8+
import { ThemedText } from "@/components/ThemedText";
9+
import { Pressable, StyleSheet } from "react-native";
10+
import { useCart } from "@/providers/Cart.provider";
11+
import CheckoutForm from "@/components/CheckoutForm";
12+
import EmptyCart from "@/components/EmptyCart";
13+
import { ThemedScrollView } from "@/components/ThemedScrollView";
14+
import { useCallback, useMemo } from "react";
15+
import { IFormData } from "@/components/CheckoutForm/CheckoutForm";
16+
import Toast from "react-native-toast-message";
17+
import SessionGateway from "@/gateways/Session.gateway";
18+
import { useThemeColor } from "@/hooks/useThemeColor";
19+
20+
export default function Cart() {
21+
const tint = useThemeColor({}, "tint");
22+
const styles = useMemo(() => getStyles(tint), [tint]);
23+
const {
24+
cart: { items },
25+
emptyCart,
26+
placeOrder,
27+
} = useCart();
28+
29+
const onEmptyCart = useCallback(() => {
30+
emptyCart();
31+
Toast.show({
32+
type: "success",
33+
position: "bottom",
34+
text1: "Your cart was emptied",
35+
});
36+
}, [emptyCart]);
37+
38+
const onPlaceOrder = useCallback(
39+
async ({
40+
email,
41+
state,
42+
streetAddress,
43+
country,
44+
city,
45+
zipCode,
46+
creditCardCvv,
47+
creditCardExpirationMonth,
48+
creditCardExpirationYear,
49+
creditCardNumber,
50+
}: IFormData) => {
51+
const { userId } = await SessionGateway.getSession();
52+
await placeOrder({
53+
userId,
54+
email,
55+
address: {
56+
streetAddress,
57+
state,
58+
country,
59+
city,
60+
zipCode,
61+
},
62+
// TODO simplify react native demo for now by hard-coding the selected currency
63+
userCurrency: "USD",
64+
creditCard: {
65+
creditCardCvv,
66+
creditCardExpirationMonth,
67+
creditCardExpirationYear,
68+
creditCardNumber,
69+
},
70+
});
71+
72+
Toast.show({
73+
type: "success",
74+
position: "bottom",
75+
text1: "Your order is Complete!",
76+
text2: "We've sent you a confirmation email.",
77+
});
78+
79+
router.replace("/");
80+
},
81+
[placeOrder],
82+
);
83+
84+
if (!items.length) {
85+
return <EmptyCart />;
86+
}
87+
88+
return (
89+
<ThemedView style={styles.container}>
90+
<ThemedView>
91+
<ThemedScrollView>
92+
{items.map((item) => (
93+
<ThemedView key={item.productId} style={styles.cartItem}>
94+
<ThemedText>{item.product.name}</ThemedText>
95+
<ThemedText style={styles.bold}>{item.quantity}</ThemedText>
96+
</ThemedView>
97+
))}
98+
</ThemedScrollView>
99+
</ThemedView>
100+
<ThemedView style={styles.emptyCartContainer}>
101+
<Pressable style={styles.emptyCart} onPress={onEmptyCart}>
102+
<ThemedText style={styles.emptyCartText}>Empty Cart</ThemedText>
103+
</Pressable>
104+
</ThemedView>
105+
<CheckoutForm onSubmit={onPlaceOrder} />
106+
</ThemedView>
107+
);
108+
}
109+
110+
const getStyles = (tint: string) =>
111+
StyleSheet.create({
112+
container: {
113+
flex: 1,
114+
gap: 20,
115+
justifyContent: "flex-start",
116+
},
117+
emptyCartContainer: {
118+
display: "flex",
119+
alignItems: "flex-end",
120+
},
121+
emptyCart: {
122+
borderRadius: 4,
123+
backgroundColor: "green",
124+
alignItems: "center",
125+
width: 100,
126+
right: 20,
127+
position: "relative",
128+
},
129+
emptyCartText: {
130+
color: "white",
131+
},
132+
cartItem: {
133+
marginLeft: 20,
134+
marginRight: 20,
135+
display: "flex",
136+
flexDirection: "row",
137+
justifyContent: "space-between",
138+
borderStyle: "solid",
139+
borderBottomWidth: 1,
140+
borderColor: tint,
141+
},
142+
bold: {
143+
fontWeight: "bold",
144+
},
145+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { ThemedView } from "@/components/ThemedView";
4+
import ProductList from "@/components/ProductList";
5+
import { useQuery } from "@tanstack/react-query";
6+
import { ScrollView, StyleSheet } from "react-native";
7+
import { ThemedText } from "@/components/ThemedText";
8+
import ApiGateway from "@/gateways/Api.gateway";
9+
10+
export default function Index() {
11+
const { data: productList = [] } = useQuery({
12+
// TODO simplify react native demo for now by hard-coding the selected currency
13+
queryKey: ["products", "USD"],
14+
queryFn: () => ApiGateway.listProducts("USD"),
15+
});
16+
17+
return (
18+
<ThemedView style={styles.container}>
19+
<ScrollView>
20+
{productList.length ? (
21+
<ProductList productList={productList} />
22+
) : (
23+
<ThemedText>
24+
No products found, make sure the backend services for the
25+
OpenTelemetry demo are running
26+
</ThemedText>
27+
)}
28+
</ScrollView>
29+
</ThemedView>
30+
);
31+
}
32+
33+
const styles = StyleSheet.create({
34+
container: {
35+
flex: 1,
36+
justifyContent: "center",
37+
alignItems: "center",
38+
},
39+
});

0 commit comments

Comments
 (0)