Skip to content

Commit 1a30873

Browse files
chore: UI improvements (#255)
1 parent bf31713 commit 1a30873

File tree

10 files changed

+260
-53
lines changed

10 files changed

+260
-53
lines changed

dapps/pos-app/app/_layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export default Sentry.wrap(function RootLayout() {
9696
headerTintColor,
9797
headerBackButtonDisplayMode: "minimal",
9898
headerTitleAlign: "center",
99+
headerBackImageSource: require("@/assets/images/arrow-left.png"),
99100
headerStyle: {
100101
backgroundColor: headerBackgroundColor,
101102
},
@@ -118,6 +119,7 @@ export default Sentry.wrap(function RootLayout() {
118119
<Stack.Screen name="payment-token" />
119120
<Stack.Screen name="payment-network" />
120121
<Stack.Screen name="scan" />
122+
<Stack.Screen name="payment-failure" />
121123
<Stack.Screen
122124
name="payment-success"
123125
options={{

dapps/pos-app/app/amount.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default function AmountScreen() {
2121
formState: { isValid },
2222
} = useForm<FormData>({
2323
defaultValues: {
24-
amount: "0",
24+
amount: "",
2525
},
2626
});
2727
const watchAmount = watch("amount");
@@ -58,21 +58,26 @@ export default function AmountScreen() {
5858
styles.amountText,
5959
{
6060
color:
61-
watchAmount === "0"
61+
watchAmount === ""
6262
? Theme["text-secondary"]
6363
: Theme["text-primary"],
6464
},
6565
]}
6666
>
67-
${watchAmount}
67+
${watchAmount || "0.00"}
6868
</ThemedText>
6969
</ThemedView>
7070
<Controller
7171
control={control}
7272
name="amount"
7373
rules={{
7474
validate: (value) => {
75-
if (!value || value === "0" || Number(value) === 0) {
75+
if (
76+
!value ||
77+
value === "0" ||
78+
value === "" ||
79+
Number(value) === 0
80+
) {
7681
return "Amount is required";
7782
}
7883
return true;
@@ -82,7 +87,7 @@ export default function AmountScreen() {
8287
<NumericKeyboard
8388
onKeyPress={(key) => {
8489
if (key === "erase") {
85-
const newDisplay = prev?.slice(0, -1) || "0";
90+
const newDisplay = prev?.slice(0, -1) || "";
8691
onChange?.(newDisplay);
8792
} else if (key === ".") {
8893
if (prev.includes(".")) return; // Don't add multiple commas
@@ -102,19 +107,15 @@ export default function AmountScreen() {
102107
style={[
103108
styles.button,
104109
{
105-
backgroundColor: isValid
106-
? Theme["bg-accent-primary"]
107-
: Theme["foreground-tertiary"], //TODO: Add a disabled color for buttons
110+
backgroundColor: Theme["bg-accent-primary"],
111+
opacity: isValid ? 1 : 0.6,
108112
},
109113
]}
110114
>
111115
<ThemedText
112-
style={[
113-
styles.buttonText,
114-
{ color: isValid ? Theme["text-invert"] : Theme["text-secondary"] },
115-
]}
116+
style={[styles.buttonText, { color: Theme["text-invert"] }]}
116117
>
117-
{isValid ? `Charge $${watchAmount}` : "Enter Amount"}
118+
{isValid ? `Charge $${watchAmount}` : "Enter amount"}
118119
</ThemedText>
119120
</Button>
120121
</ThemedView>
@@ -127,7 +128,7 @@ const styles = StyleSheet.create({
127128
justifyContent: "space-between",
128129
alignItems: "center",
129130
paddingHorizontal: Spacing["spacing-5"],
130-
paddingVertical: Spacing["spacing-10"],
131+
paddingVertical: Spacing["spacing-5"],
131132
},
132133
amountContainer: {
133134
flex: 1,

dapps/pos-app/app/index.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ export default function HomeScreen() {
2424
}
2525

2626
if (!isConnected) {
27-
router.navigate("/settings");
28-
return showInfoToast({
29-
title: "Please connect your wallet",
30-
message: "Please connect your wallet to start a payment",
31-
});
27+
return router.navigate("/settings");
3228
}
3329
router.push("/amount");
3430
};
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import * as Haptics from "expo-haptics";
2+
import { router, UnknownOutputParams, useLocalSearchParams } from "expo-router";
3+
import React, { useEffect, useRef } from "react";
4+
import { Animated, Dimensions, StyleSheet, View } from "react-native";
5+
import { useSafeAreaInsets } from "react-native-safe-area-context";
6+
import { Image } from "expo-image";
7+
8+
import { ThemedText } from "@/components/themed-text";
9+
import { ThemedView } from "@/components/themed-view";
10+
import { BorderRadius, Spacing } from "@/constants/spacing";
11+
import { useTheme } from "@/hooks/use-theme-color";
12+
import { Button } from "@/components/button";
13+
import { TokenKey } from "@/utils/networks";
14+
15+
const { width: screenWidth, height: screenHeight } = Dimensions.get("window");
16+
const diagonalLength = Math.sqrt(screenWidth ** 2 + screenHeight ** 2);
17+
const initialCircleSize = 20;
18+
const finalScale = Math.round(diagonalLength / initialCircleSize) + 1;
19+
20+
interface ScreenParams extends UnknownOutputParams {
21+
amount: string;
22+
token: TokenKey;
23+
networkCaipId: string;
24+
recipientAddress: string;
25+
}
26+
27+
export default function PaymentSuccessScreen() {
28+
const Theme = useTheme();
29+
const insets = useSafeAreaInsets();
30+
const params = useLocalSearchParams<ScreenParams>();
31+
32+
const circleScale = useRef(new Animated.Value(1)).current;
33+
const contentOpacity = useRef(new Animated.Value(0)).current;
34+
35+
const handleRetry = () => {
36+
const { amount, token, networkCaipId, recipientAddress } = params;
37+
router.dismissTo({
38+
pathname: "/scan",
39+
params: {
40+
amount,
41+
token,
42+
networkCaipId,
43+
recipientAddress,
44+
},
45+
});
46+
};
47+
48+
useEffect(() => {
49+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
50+
51+
Animated.parallel([
52+
Animated.spring(circleScale, {
53+
toValue: finalScale,
54+
tension: 15,
55+
friction: 12,
56+
useNativeDriver: true,
57+
}),
58+
Animated.sequence([
59+
Animated.delay(300),
60+
Animated.timing(contentOpacity, {
61+
toValue: 1,
62+
duration: 400,
63+
useNativeDriver: true,
64+
}),
65+
]),
66+
]).start();
67+
// eslint-disable-next-line react-hooks/exhaustive-deps
68+
}, []);
69+
70+
return (
71+
<ThemedView style={[styles.container, { paddingTop: insets.top }]}>
72+
{/* Expanding circle background */}
73+
<Animated.View
74+
style={[
75+
styles.circle,
76+
{
77+
backgroundColor: Theme["bg-primary"],
78+
width: initialCircleSize,
79+
height: initialCircleSize,
80+
borderRadius: initialCircleSize / 2,
81+
transform: [{ scale: circleScale }],
82+
},
83+
]}
84+
/>
85+
86+
{/* Content that fades in after circle expands */}
87+
<Animated.View
88+
style={[
89+
styles.contentContainer,
90+
{
91+
opacity: contentOpacity,
92+
},
93+
]}
94+
>
95+
<View
96+
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
97+
>
98+
<Image
99+
source={require("@/assets/images/warning-circle.png")}
100+
style={styles.warningCircle}
101+
/>
102+
<ThemedText
103+
style={[styles.failedText, { color: Theme["text-primary"] }]}
104+
>
105+
Payment failed
106+
</ThemedText>
107+
<ThemedText
108+
style={[
109+
styles.failedDescription,
110+
{ color: Theme["text-secondary"] },
111+
]}
112+
>
113+
The payment couldn’t be completed due to an error. Please try again
114+
or use a different payment method.
115+
</ThemedText>
116+
</View>
117+
<View style={styles.buttonContainer}>
118+
<Button
119+
onPress={handleRetry}
120+
style={[
121+
styles.button,
122+
{
123+
backgroundColor: Theme["bg-accent-primary"],
124+
},
125+
]}
126+
>
127+
<ThemedText
128+
style={[styles.buttonText, { color: Theme["text-invert"] }]}
129+
>
130+
Try again
131+
</ThemedText>
132+
</Button>
133+
</View>
134+
</Animated.View>
135+
</ThemedView>
136+
);
137+
}
138+
139+
const styles = StyleSheet.create({
140+
container: {
141+
flex: 1,
142+
paddingHorizontal: Spacing["spacing-5"],
143+
paddingBottom: Spacing["spacing-5"],
144+
},
145+
circle: {
146+
position: "absolute",
147+
top: "50%",
148+
left: "50%",
149+
marginLeft: -initialCircleSize / 2,
150+
marginTop: -initialCircleSize / 2,
151+
},
152+
contentContainer: {
153+
flex: 1,
154+
width: "100%",
155+
},
156+
failedText: {
157+
fontSize: 26,
158+
lineHeight: 28,
159+
textAlign: "center",
160+
marginBottom: Spacing["spacing-3"],
161+
},
162+
failedDescription: {
163+
fontSize: 16,
164+
lineHeight: 18,
165+
textAlign: "center",
166+
marginBottom: Spacing["spacing-3"],
167+
},
168+
warningCircle: {
169+
width: 48,
170+
height: 48,
171+
marginBottom: Spacing["spacing-3"],
172+
},
173+
buttonContainer: {
174+
width: "100%",
175+
gap: Spacing["spacing-3"],
176+
},
177+
button: {
178+
flexDirection: "row",
179+
alignItems: "center",
180+
justifyContent: "center",
181+
paddingHorizontal: Spacing["spacing-5"],
182+
paddingVertical: Spacing["spacing-5"],
183+
borderRadius: BorderRadius["5"],
184+
},
185+
buttonText: {
186+
fontSize: 18,
187+
lineHeight: 20,
188+
},
189+
});

dapps/pos-app/app/payment-success.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import * as Haptics from "expo-haptics";
22
import { router, UnknownOutputParams, useLocalSearchParams } from "expo-router";
33
import React, { useEffect, useRef } from "react";
4-
import {
5-
Animated,
6-
Dimensions,
7-
StyleSheet,
8-
TouchableOpacity,
9-
View,
10-
} from "react-native";
4+
import { Animated, Dimensions, StyleSheet, View } from "react-native";
115
import { useSafeAreaInsets } from "react-native-safe-area-context";
126

137
import { ThemedText } from "@/components/themed-text";
148
import { ThemedView } from "@/components/themed-view";
159
import { BorderRadius, Spacing } from "@/constants/spacing";
1610
import { useTheme } from "@/hooks/use-theme-color";
11+
import { Button } from "@/components/button";
1712

1813
interface SuccessParams extends UnknownOutputParams {
1914
amount: string;
@@ -100,8 +95,8 @@ export default function PaymentSuccessScreen() {
10095
</ThemedText>
10196
</View>
10297
<View style={styles.buttonContainer}>
103-
<TouchableOpacity
104-
activeOpacity={0.8}
98+
<Button
99+
onPress={() => {}}
105100
style={[
106101
styles.button,
107102
{
@@ -115,10 +110,9 @@ export default function PaymentSuccessScreen() {
115110
>
116111
Send email receipt
117112
</ThemedText>
118-
</TouchableOpacity>
113+
</Button>
119114

120-
<TouchableOpacity
121-
activeOpacity={0.8}
115+
<Button
122116
style={[
123117
styles.button,
124118
{
@@ -133,7 +127,7 @@ export default function PaymentSuccessScreen() {
133127
>
134128
New Sale
135129
</ThemedText>
136-
</TouchableOpacity>
130+
</Button>
137131
</View>
138132
</Animated.View>
139133
</ThemedView>

0 commit comments

Comments
 (0)