Skip to content

Commit

Permalink
Add in OpenTelemetry demo functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
jpmunz committed Nov 18, 2024
1 parent 5086019 commit cde1345
Show file tree
Hide file tree
Showing 34 changed files with 6,799 additions and 5,603 deletions.
8 changes: 7 additions & 1 deletion .licenserc.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
"src/featureflagservice/assets/vendor/",
"src/featureflagservice/priv/",
"src/productcatalogservice/genproto/",
"src/reactnativeapp/ios/Pods/",
"src/reactnativeapp/ios/build/",
"src/reactnativeapp/android/app/build/",
"src/reactnativeapp/android/.gradle/",
"src/reactnativeapp/.expo/",
"src/reactnativeapp/expo-env.d.ts",
"internal/tools/"
]
}
}
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


# All documents to be used in spell check.
ALL_DOCS := $(shell find . -type f -name '*.md' -not -path './.github/*' -not -path '*/node_modules/*' -not -path '*/_build/*' -not -path '*/deps/*' | sort)
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)
PWD := $(shell pwd)

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

src/reactnativeapp/node_modules:
npm --prefix src/reactnativeapp install

.PHONY: reactnative-android
reactnative-android: src/reactnativeapp/node_modules
npm --prefix src/reactnativeapp run android

.PHONY: reactnative-ios
reactnative-ios: src/reactnativeapp/node_modules
npm --prefix src/reactnativeapp run ios
1 change: 1 addition & 0 deletions ide-gen-proto.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ gen_proto_go checkoutservice
# gen_proto_cpp currencyservice
# gen_proto_ruby emailservice
gen_proto_ts frontend
gen_proto_ts reactnativeapp
gen_proto_js paymentservice
gen_proto_go productcatalogservice
# gen_proto_php quoteservice
Expand Down
3 changes: 3 additions & 0 deletions src/reactnativeapp/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://docs.expo.dev/guides/environment-variables/

EXPO_PUBLIC_FRONTEND_PROXY_PORT=8080
6 changes: 5 additions & 1 deletion src/reactnativeapp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ web-build/
# The following patterns were generated by expo-cli

expo-env.d.ts
# @end expo-cli
# @end expo-cli

# TODO, should we consider committing these?
protos/demo.ts
pb/demo.proto
58 changes: 57 additions & 1 deletion src/reactnativeapp/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
# Example React Native app

This was created using [`npx create-expo-app@latest`](https://reactnative.dev/docs/environment-setup#start-a-new-react-native-project-with-expo)
This was created using [`npx create-expo-app@latest`](https://reactnative.dev/docs/environment-setup#start-a-new-react-native-project-with-expo)

Content was taken from the web app example in src/frontend and modified to work
in a React Native environment.

## Get started

Unlike the other components under src/ which run within docker containers this
app is meant to be run on either mobile emulators on your machine or physical
devices. If this is your first time running a React Native app you will need to
setup your local environment for Android or iOS development or both following
[this guide](https://reactnative.dev/docs/set-up-your-environment).

Start the OpenTelemetry demo:

```bash
cd ../..
make start # or start-minimal
```

Before running the app the Typescript protobuf files need to be generated. This
requires at least `protoc`, if you do not have the other dev tools installed you
can comment the other invocations in `ide-gen-proto.sh` and just have
`gen_proto_ts reactnativeapp` before running:

```bash
make generate-protobuf
```

Then start the React Native app:

```bash
make reactnative-android
```

Or

```bash
make reactnative-ios
```

You can also install dependencies and launch the app directly from this folder using:

```bash
cd src/reactnativeapp
npm install
```

```bash
npm run android
```

Or

```bash
npm run ios
```
49 changes: 49 additions & 0 deletions src/reactnativeapp/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
import { Tabs } from "expo-router";
import React from "react";
import { TabBarIcon } from "@/components/navigation/TabBarIcon";
import { useCart } from "@/providers/Cart.provider";

export default function TabLayout() {
const {
cart: { items },
} = useCart();

let itemsInCart = 0;
items.forEach((item) => {
itemsInCart += item.quantity;
});

return (
<Tabs>
<Tabs.Screen
name="index"
options={{
title: "Products",
tabBarShowLabel: false,
tabBarIcon: ({ color, focused }) => (
<TabBarIcon
name={focused ? "list" : "list-outline"}
color={color}
/>
),
}}
/>
<Tabs.Screen
name="cart"
options={{
title: "Cart",
tabBarShowLabel: false,
tabBarBadge: itemsInCart || undefined,
tabBarIcon: ({ color, focused }) => (
<TabBarIcon
name={focused ? "cart" : "cart-outline"}
color={color}
/>
),
}}
/>
</Tabs>
);
}
145 changes: 145 additions & 0 deletions src/reactnativeapp/app/(tabs)/cart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
/**
* Copied with modification from src/frontend/components/Cart/CartDetail.tsx
*/
import { router } from "expo-router";
import { ThemedView } from "@/components/ThemedView";
import { ThemedText } from "@/components/ThemedText";
import { Pressable, StyleSheet } from "react-native";
import { useCart } from "@/providers/Cart.provider";
import CheckoutForm from "@/components/CheckoutForm";
import EmptyCart from "@/components/EmptyCart";
import { ThemedScrollView } from "@/components/ThemedScrollView";
import { useCallback, useMemo } from "react";
import { IFormData } from "@/components/CheckoutForm/CheckoutForm";
import Toast from "react-native-toast-message";
import SessionGateway from "@/gateways/Session.gateway";
import { useThemeColor } from "@/hooks/useThemeColor";

export default function Cart() {
const tint = useThemeColor({}, "tint");
const styles = useMemo(() => getStyles(tint), [tint]);
const {
cart: { items },
emptyCart,
placeOrder,
} = useCart();

const onEmptyCart = useCallback(() => {
emptyCart();
Toast.show({
type: "success",
position: "bottom",
text1: "Your cart was emptied",
});
}, [emptyCart]);

const onPlaceOrder = useCallback(
async ({
email,
state,
streetAddress,
country,
city,
zipCode,
creditCardCvv,
creditCardExpirationMonth,
creditCardExpirationYear,
creditCardNumber,
}: IFormData) => {
const { userId } = await SessionGateway.getSession();
await placeOrder({
userId,
email,
address: {
streetAddress,
state,
country,
city,
zipCode,
},
// TODO simplify react native demo for now by hard-coding the selected currency
userCurrency: "USD",
creditCard: {
creditCardCvv,
creditCardExpirationMonth,
creditCardExpirationYear,
creditCardNumber,
},
});

Toast.show({
type: "success",
position: "bottom",
text1: "Your order is Complete!",
text2: "We've sent you a confirmation email.",
});

router.replace("/");
},
[placeOrder],
);

if (!items.length) {
return <EmptyCart />;
}

return (
<ThemedView style={styles.container}>
<ThemedView>
<ThemedScrollView>
{items.map((item) => (
<ThemedView key={item.productId} style={styles.cartItem}>
<ThemedText>{item.product.name}</ThemedText>
<ThemedText style={styles.bold}>{item.quantity}</ThemedText>
</ThemedView>
))}
</ThemedScrollView>
</ThemedView>
<ThemedView style={styles.emptyCartContainer}>
<Pressable style={styles.emptyCart} onPress={onEmptyCart}>
<ThemedText style={styles.emptyCartText}>Empty Cart</ThemedText>
</Pressable>
</ThemedView>
<CheckoutForm onSubmit={onPlaceOrder} />
</ThemedView>
);
}

const getStyles = (tint: string) =>
StyleSheet.create({
container: {
flex: 1,
gap: 20,
justifyContent: "flex-start",
},
emptyCartContainer: {
display: "flex",
alignItems: "flex-end",
},
emptyCart: {
borderRadius: 4,
backgroundColor: "green",
alignItems: "center",
width: 100,
right: 20,
position: "relative",
},
emptyCartText: {
color: "white",
},
cartItem: {
marginLeft: 20,
marginRight: 20,
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
borderStyle: "solid",
borderBottomWidth: 1,
borderColor: tint,
},
bold: {
fontWeight: "bold",
},
});
39 changes: 39 additions & 0 deletions src/reactnativeapp/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
import { ThemedView } from "@/components/ThemedView";
import ProductList from "@/components/ProductList";
import { useQuery } from "@tanstack/react-query";
import { ScrollView, StyleSheet } from "react-native";
import { ThemedText } from "@/components/ThemedText";
import ApiGateway from "@/gateways/Api.gateway";

export default function Index() {
const { data: productList = [] } = useQuery({
// TODO simplify react native demo for now by hard-coding the selected currency
queryKey: ["products", "USD"],
queryFn: () => ApiGateway.listProducts("USD"),
});

return (
<ThemedView style={styles.container}>
<ScrollView>
{productList.length ? (
<ProductList productList={productList} />
) : (
<ThemedText>
No products found, make sure the backend services for the
OpenTelemetry demo are running
</ThemedText>
)}
</ScrollView>
</ThemedView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
Loading

0 comments on commit cde1345

Please # to comment.