From 82e03978b89938219958032efb1448cc76baa181 Mon Sep 17 00:00:00 2001 From: Saumit Date: Sat, 27 Sep 2025 02:14:26 +0530 Subject: Initial snapshot - OpenTelemetry demo 2.1.3 -f --- src/react-native-app/app/(tabs)/_layout.tsx | 62 ++++++++++++ src/react-native-app/app/(tabs)/cart.tsx | 145 +++++++++++++++++++++++++++ src/react-native-app/app/(tabs)/index.tsx | 39 +++++++ src/react-native-app/app/(tabs)/settings.tsx | 40 ++++++++ src/react-native-app/app/_layout.tsx | 59 +++++++++++ 5 files changed, 345 insertions(+) create mode 100644 src/react-native-app/app/(tabs)/_layout.tsx create mode 100644 src/react-native-app/app/(tabs)/cart.tsx create mode 100644 src/react-native-app/app/(tabs)/index.tsx create mode 100644 src/react-native-app/app/(tabs)/settings.tsx create mode 100644 src/react-native-app/app/_layout.tsx (limited to 'src/react-native-app/app') diff --git a/src/react-native-app/app/(tabs)/_layout.tsx b/src/react-native-app/app/(tabs)/_layout.tsx new file mode 100644 index 0000000..ba2a7b0 --- /dev/null +++ b/src/react-native-app/app/(tabs)/_layout.tsx @@ -0,0 +1,62 @@ +// 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 ( + + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + + ); +} diff --git a/src/react-native-app/app/(tabs)/cart.tsx b/src/react-native-app/app/(tabs)/cart.tsx new file mode 100644 index 0000000..c91f847 --- /dev/null +++ b/src/react-native-app/app/(tabs)/cart.tsx @@ -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 ; + } + + return ( + + + + {items.map((item) => ( + + {item.product.name} + {item.quantity} + + ))} + + + + + Empty Cart + + + + + ); +} + +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", + }, + }); diff --git a/src/react-native-app/app/(tabs)/index.tsx b/src/react-native-app/app/(tabs)/index.tsx new file mode 100644 index 0000000..c01e1ea --- /dev/null +++ b/src/react-native-app/app/(tabs)/index.tsx @@ -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 ( + + + {productList.length ? ( + + ) : ( + + No products found, make sure the backend services for the + OpenTelemetry demo are running + + )} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: "center", + alignItems: "center", + }, +}); diff --git a/src/react-native-app/app/(tabs)/settings.tsx b/src/react-native-app/app/(tabs)/settings.tsx new file mode 100644 index 0000000..d278918 --- /dev/null +++ b/src/react-native-app/app/(tabs)/settings.tsx @@ -0,0 +1,40 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +import { useQueryClient } from '@tanstack/react-query' +import { ThemedView } from "@/components/ThemedView"; +import { StyleSheet } from "react-native"; +import { getFrontendProxyURL, setFrontendProxyURL } from "@/utils/Settings"; +import { setupTracerProvider } from "@/hooks/useTracer"; +import { trace } from "@opentelemetry/api"; +import { Setting } from "@/components/Setting"; + +export default function Settings() { + const queryClient = useQueryClient() + + const onSetFrontendProxyURL = async (value: string) => { + await setFrontendProxyURL(value); + + // Clear any cached queries since we now have a new endpoint to hit for everything + await queryClient.invalidateQueries(); + + // Need to setup a new tracer provider since the export URL for traces has now changed + trace.disable(); + const provider = setupTracerProvider(value); + trace.setGlobalTracerProvider(provider); + }; + + return ( + + + + ); +} + +const styles = StyleSheet.create({ + container: { + display: "flex", + gap: 20, + paddingLeft: 20, + height: "100%", + }, +}); diff --git a/src/react-native-app/app/_layout.tsx b/src/react-native-app/app/_layout.tsx new file mode 100644 index 0000000..d8ac89c --- /dev/null +++ b/src/react-native-app/app/_layout.tsx @@ -0,0 +1,59 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +import { SplashScreen, Stack } from "expo-router"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { + DarkTheme, + DefaultTheme, + ThemeProvider, +} from "@react-navigation/native"; +import { useColorScheme } from "react-native"; +import { RootSiblingParent } from "react-native-root-siblings"; +import Toast from "react-native-toast-message"; +import { useFonts } from "expo-font"; +import { useEffect, useMemo } from "react"; +import { useTracer } from "@/hooks/useTracer"; +import CartProvider from "@/providers/Cart.provider"; + +const queryClient = new QueryClient(); + +export default function RootLayout() { + const colorScheme = useColorScheme(); + const [fontsLoaded] = useFonts({ + SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"), + }); + const { loaded: tracerLoaded } = useTracer(); + + const loaded = useMemo( + () => fontsLoaded && tracerLoaded, + [fontsLoaded, tracerLoaded], + ); + useEffect(() => { + if (loaded) { + SplashScreen.hideAsync(); + } + }, [loaded]); + + if (!loaded) { + return null; + } + + return ( + + + + + {/* + TODO Once https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2359 is available it can + be used here to provide telemetry for navigation between tabs + */} + + + + + + + + + ); +} -- cgit v1.2.3