diff --git a/dapps/pos-app/.env.example b/dapps/pos-app/.env.example
index 3d0380f2..deac4661 100644
--- a/dapps/pos-app/.env.example
+++ b/dapps/pos-app/.env.example
@@ -1,3 +1,4 @@
EXPO_PUBLIC_PROJECT_ID=""
EXPO_PUBLIC_SENTRY_DSN=""
-SENTRY_AUTH_TOKEN=""
\ No newline at end of file
+SENTRY_AUTH_TOKEN=""
+EXPO_PUBLIC_VARIANT="default" # or "polygon"
\ No newline at end of file
diff --git a/dapps/pos-app/README.md b/dapps/pos-app/README.md
index fdfec630..ba007c40 100644
--- a/dapps/pos-app/README.md
+++ b/dapps/pos-app/README.md
@@ -36,6 +36,42 @@
npm run ios
```
+## App Variants
+
+This app supports building different variants using environment configuration files. This is useful for maintaining multiple versions of the app (e.g., production, staging, or different client configurations).
+
+### Available Variants
+
+- **Default**: Uses `.env.default` configuration
+- **Variant**: Uses `.env.variant` configuration
+
+### Setting Up Variants
+
+1. Create your variant environment files:
+
+ ```bash
+ cp .env .env.default
+ cp .env .env.variant
+ ```
+
+2. Update each environment file with the appropriate configuration values for that variant.
+
+### Building Variants
+
+To build a specific variant for Android:
+
+**Default variant:**
+```bash
+npm run android:build:default
+```
+
+**Variant build:**
+```bash
+npm run android:build:variant
+```
+
+> **Note**: Each build command will temporarily copy the corresponding `.env.*` file to `.env` before building.
+
## Production Releases
For production Android releases, you'll need the actual `secrets.properties` file and keystore. Get these from the mobile team or 1Password.
diff --git a/dapps/pos-app/app/_layout.tsx b/dapps/pos-app/app/_layout.tsx
index 75884156..03f83f86 100644
--- a/dapps/pos-app/app/_layout.tsx
+++ b/dapps/pos-app/app/_layout.tsx
@@ -42,6 +42,7 @@ import { WagmiProvider } from "wagmi";
Sentry.init({
dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
sendDefaultPii: false,
+ environment: process.env.EXPO_PUBLIC_VARIANT ?? "default",
// Enable Logs
enableLogs: false,
diff --git a/dapps/pos-app/app/amount.tsx b/dapps/pos-app/app/amount.tsx
index 05966ee1..d318d710 100644
--- a/dapps/pos-app/app/amount.tsx
+++ b/dapps/pos-app/app/amount.tsx
@@ -1,5 +1,6 @@
import { Button } from "@/components/button";
import { NumericKeyboard } from "@/components/numeric-keyboard";
+import { SecondaryLogo } from "@/components/secondary-logo";
import { ThemedText } from "@/components/themed-text";
import { BorderRadius, Spacing } from "@/constants/spacing";
import { useTheme } from "@/hooks/use-theme-color";
@@ -141,6 +142,7 @@ export default function AmountScreen() {
{isValid ? `Charge $${formatAmount(watchAmount)}` : "Enter amount"}
+
);
}
@@ -174,4 +176,7 @@ const styles = StyleSheet.create({
alignItems: "center",
borderRadius: BorderRadius["5"],
},
+ secondaryLogo: {
+ marginTop: Spacing["spacing-5"],
+ },
});
diff --git a/dapps/pos-app/app/index.tsx b/dapps/pos-app/app/index.tsx
index 1f10c383..aaee605f 100644
--- a/dapps/pos-app/app/index.tsx
+++ b/dapps/pos-app/app/index.tsx
@@ -1,4 +1,5 @@
import { Button } from "@/components/button";
+import { SecondaryLogo } from "@/components/secondary-logo";
import { ThemedText } from "@/components/themed-text";
import { BorderRadius, Spacing } from "@/constants/spacing";
import { useTheme } from "@/hooks/use-theme-color";
@@ -55,6 +56,7 @@ export default function HomeScreen() {
/>
Settings
+
);
}
diff --git a/dapps/pos-app/app/payment-success.tsx b/dapps/pos-app/app/payment-success.tsx
index 72058423..9d69b732 100644
--- a/dapps/pos-app/app/payment-success.tsx
+++ b/dapps/pos-app/app/payment-success.tsx
@@ -10,10 +10,12 @@ import Animated, {
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Button } from "@/components/button";
+import { SecondaryLogo } from "@/components/secondary-logo";
import { ThemedText } from "@/components/themed-text";
import { BorderRadius, Spacing } from "@/constants/spacing";
import { useDisableBackButton } from "@/hooks/use-disable-back-button";
import { useTheme } from "@/hooks/use-theme-color";
+import { isVariant } from "@/utils/misc";
import { resetNavigation } from "@/utils/navigation";
import { StatusBar } from "expo-status-bar";
import { useColorScheme } from "@/hooks/use-color-scheme";
@@ -29,11 +31,14 @@ const finalScale = Math.ceil(diagonalLength / initialCircleSize) + 2;
export default function PaymentSuccessScreen() {
useDisableBackButton();
- const Theme = useTheme();
+ const Theme = useTheme(isVariant() ? "light" : undefined);
const params = useLocalSearchParams();
const { top } = useSafeAreaInsets();
const colorScheme = useColorScheme();
const { amount } = params;
+ const backgroundColor = isVariant()
+ ? Theme["polygon-payment-success"]
+ : Theme["bg-payment-success"];
const circleScale = useSharedValue(1);
const contentOpacity = useSharedValue(0);
@@ -65,7 +70,7 @@ export default function PaymentSuccessScreen() {
style={[
styles.circle,
{
- backgroundColor: Theme["text-success"],
+ backgroundColor,
width: initialCircleSize,
height: initialCircleSize,
borderRadius: initialCircleSize / 2,
@@ -125,6 +130,10 @@ export default function PaymentSuccessScreen() {
+
@@ -176,4 +185,8 @@ const styles = StyleSheet.create({
fontSize: 18,
lineHeight: 20,
},
+ secondaryLogo: {
+ marginTop: Spacing["spacing-5"],
+ alignSelf: "center",
+ },
});
diff --git a/dapps/pos-app/assets/images/polygon_logo.png b/dapps/pos-app/assets/images/polygon_logo.png
new file mode 100644
index 00000000..a51d411e
Binary files /dev/null and b/dapps/pos-app/assets/images/polygon_logo.png differ
diff --git a/dapps/pos-app/components/secondary-logo.tsx b/dapps/pos-app/components/secondary-logo.tsx
new file mode 100644
index 00000000..36aed9d6
--- /dev/null
+++ b/dapps/pos-app/components/secondary-logo.tsx
@@ -0,0 +1,34 @@
+import { Spacing } from "@/constants/spacing";
+import { useTheme } from "@/hooks/use-theme-color";
+import { isVariant } from "@/utils/misc";
+import { useAssets } from "expo-asset";
+import { Image } from "expo-image";
+import { ImageStyle, StyleProp, StyleSheet } from "react-native";
+
+interface SecondaryLogoProps {
+ tintColor?: string;
+ style?: StyleProp;
+}
+
+export function SecondaryLogo({ tintColor, style }: SecondaryLogoProps) {
+ const Theme = useTheme();
+ const [assets] = useAssets([require("@/assets/images/polygon_logo.png")]);
+ const showLogo = isVariant();
+ const _tintColor = tintColor ?? Theme["text-secondary"];
+
+ return showLogo ? (
+
+ ) : null;
+}
+
+const styles = StyleSheet.create({
+ logo: {
+ marginTop: Spacing["spacing-2"],
+ width: 92,
+ height: 18,
+ },
+});
diff --git a/dapps/pos-app/constants/theme.ts b/dapps/pos-app/constants/theme.ts
index ed6ccd18..e6889880 100644
--- a/dapps/pos-app/constants/theme.ts
+++ b/dapps/pos-app/constants/theme.ts
@@ -32,6 +32,7 @@ export const Colors = {
"bg-success": "rgba(48, 164, 107, 0.2)",
"bg-error": "rgba(223, 74, 52, 0.2)",
"bg-warning": "rgba(243, 161, 63, 0.2)",
+ "bg-payment-success": "#30A46B",
// Text colors
"text-primary": "#202020",
@@ -52,6 +53,10 @@ export const Colors = {
"border-success": "#30A46B",
"border-error": "#DF4A34",
"border-warning": "#F3A13F",
+
+ // Custom colors
+ "polygon-payment-success": "#6C00F6",
+ "polygon-payment-success-header": "#FFFFFF",
},
dark: {
// Foreground colors
@@ -84,6 +89,7 @@ export const Colors = {
"bg-success": "rgba(48, 164, 107, 0.2)",
"bg-error": "rgba(223, 74, 52, 0.2)",
"bg-warning": "rgba(243, 161, 63, 0.2)",
+ "bg-payment-success": "#30A46B",
// Text colors
"text-primary": "#FFFFFF",
@@ -104,6 +110,10 @@ export const Colors = {
"border-success": "#30A46B",
"border-error": "#DF4A34",
"border-warning": "#F3A13F",
+
+ // Custom colors
+ "polygon-payment-success": "#6C00F6",
+ "polygon-payment-success-header": "#FFFFFF",
},
};
diff --git a/dapps/pos-app/package.json b/dapps/pos-app/package.json
index e9c0563f..08d24d04 100644
--- a/dapps/pos-app/package.json
+++ b/dapps/pos-app/package.json
@@ -7,6 +7,8 @@
"android": "expo run:android",
"android:pos": "expo run:android --port 8082",
"android:build": "cd android && ./gradlew assembleRelease",
+ "android:build:default": "[ -f .env.default ] && cp .env.default .env && npm run android:build || (echo '.env.default not found. Please create it before running this script.' && exit 1)",
+ "android:build:variant": "[ -f .env.variant ] && cp .env.variant .env && npm run android:build || (echo '.env.variant not found. Please create it before running this script.' && exit 1)",
"prebuild": "expo prebuild",
"postprebuild": "node scripts/setup-secrets.js",
"postinstall": "patch-package",
diff --git a/dapps/pos-app/utils/misc.ts b/dapps/pos-app/utils/misc.ts
index 98e51798..2c33c752 100644
--- a/dapps/pos-app/utils/misc.ts
+++ b/dapps/pos-app/utils/misc.ts
@@ -8,3 +8,7 @@ export const getDeviceIdentifier = async () => {
return "unknown";
}
};
+
+export const isVariant = () => {
+ return process.env.EXPO_PUBLIC_VARIANT === "polygon" || false;
+};
diff --git a/dapps/pos-app/utils/navigation.ts b/dapps/pos-app/utils/navigation.ts
index a14f6155..99515dc8 100644
--- a/dapps/pos-app/utils/navigation.ts
+++ b/dapps/pos-app/utils/navigation.ts
@@ -1,5 +1,6 @@
import { Colors } from "@/constants/theme";
import { Href, router } from "expo-router";
+import { isVariant } from "./misc";
export const shouldCenterHeaderTitle = (routeName: string) => {
return routeName === "index" || routeName === "payment-success";
@@ -8,13 +9,20 @@ export const shouldCenterHeaderTitle = (routeName: string) => {
export const getHeaderBackgroundColor = (
routeName: string,
): keyof typeof Colors.light | keyof typeof Colors.dark => {
- return routeName === "payment-success" ? "text-success" : "bg-primary";
+ if (routeName === "payment-success") {
+ return isVariant() ? "polygon-payment-success" : "text-success";
+ }
+ return "bg-primary";
};
export const getHeaderTintColor = (
routeName: string,
): keyof typeof Colors.light | keyof typeof Colors.dark => {
- return routeName === "payment-success" ? "text-invert" : "text-primary";
+ if (routeName === "payment-success") {
+ return isVariant() ? "polygon-payment-success-header" : "text-invert";
+ }
+
+ return "text-primary";
};
export const resetNavigation = (href?: Href) => {