@upstep/react-native 0.6.7 → 0.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/FeedbackButton.tsx +35 -4
- package/src/FeedbackContext.tsx +15 -5
- package/src/FeedbackSheet.tsx +16 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upstep/react-native",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"description": "Upstep feedback SDK for React Native",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@upstep/types": "0.5.
|
|
15
|
+
"@upstep/types": "0.5.1"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
18
|
"react": ">=18",
|
package/src/FeedbackButton.tsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { TouchableOpacity, Text, StyleSheet } from "react-native";
|
|
2
|
+
import { TouchableOpacity, Text, View, StyleSheet } from "react-native";
|
|
3
3
|
import { useUpstep } from "./FeedbackContext";
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
position?: "bottom-right" | "bottom-left";
|
|
7
7
|
label?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export function FeedbackButton({ position = "bottom-right", label = "Feedback" }: Props) {
|
|
11
|
+
export function FeedbackButton({ position = "bottom-right", label = "Feedback", icon }: Props) {
|
|
11
12
|
const { openSheet, accentColor } = useUpstep();
|
|
12
13
|
|
|
13
14
|
return (
|
|
@@ -20,12 +21,21 @@ export function FeedbackButton({ position = "bottom-right", label = "Feedback" }
|
|
|
20
21
|
]}
|
|
21
22
|
activeOpacity={0.85}
|
|
22
23
|
>
|
|
23
|
-
<
|
|
24
|
+
{icon ?? <ChatIcon />}
|
|
24
25
|
<Text style={styles.label}>{label}</Text>
|
|
25
26
|
</TouchableOpacity>
|
|
26
27
|
);
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
function ChatIcon() {
|
|
31
|
+
return (
|
|
32
|
+
<View style={styles.iconWrap}>
|
|
33
|
+
<View style={styles.iconBubble} />
|
|
34
|
+
<View style={styles.iconTail} />
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
const styles = StyleSheet.create({
|
|
30
40
|
btn: {
|
|
31
41
|
position: "absolute",
|
|
@@ -45,6 +55,27 @@ const styles = StyleSheet.create({
|
|
|
45
55
|
},
|
|
46
56
|
right: { right: 20 },
|
|
47
57
|
left: { left: 20 },
|
|
48
|
-
icon: { fontSize: 14 },
|
|
49
58
|
label: { color: "#fff", fontSize: 14, fontWeight: "600" },
|
|
59
|
+
iconWrap: { width: 16, height: 16, position: "relative" },
|
|
60
|
+
iconBubble: {
|
|
61
|
+
position: "absolute",
|
|
62
|
+
top: 0,
|
|
63
|
+
left: 0,
|
|
64
|
+
right: 2,
|
|
65
|
+
bottom: 3,
|
|
66
|
+
borderRadius: 4,
|
|
67
|
+
borderWidth: 1.5,
|
|
68
|
+
borderColor: "#fff",
|
|
69
|
+
},
|
|
70
|
+
iconTail: {
|
|
71
|
+
position: "absolute",
|
|
72
|
+
bottom: 0,
|
|
73
|
+
left: 3,
|
|
74
|
+
width: 5,
|
|
75
|
+
height: 5,
|
|
76
|
+
borderRightWidth: 1.5,
|
|
77
|
+
borderBottomWidth: 1.5,
|
|
78
|
+
borderColor: "#fff",
|
|
79
|
+
transform: [{ rotate: "45deg" }],
|
|
80
|
+
},
|
|
50
81
|
});
|
package/src/FeedbackContext.tsx
CHANGED
|
@@ -38,6 +38,7 @@ interface UpstepContextValue {
|
|
|
38
38
|
identify: (userId: string | undefined) => void;
|
|
39
39
|
accentColor: string;
|
|
40
40
|
theme: "light" | "dark" | "auto";
|
|
41
|
+
showBranding: boolean;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const UpstepContext = createContext<UpstepContextValue | null>(null);
|
|
@@ -50,6 +51,7 @@ export function FeedbackProvider({
|
|
|
50
51
|
const [feedItems, setFeedItems] = useState<Feedback[]>([]);
|
|
51
52
|
const [feedLoading, setFeedLoading] = useState(true);
|
|
52
53
|
const [isOpen, setIsOpen] = useState(false);
|
|
54
|
+
const [showBranding, setShowBranding] = useState(true);
|
|
53
55
|
|
|
54
56
|
useEffect(() => {
|
|
55
57
|
client.setUserId(config.userId);
|
|
@@ -60,6 +62,7 @@ export function FeedbackProvider({
|
|
|
60
62
|
try {
|
|
61
63
|
const data = await client.listFeedback({ sort: "votes", limit: 30 });
|
|
62
64
|
setFeedItems(data.items);
|
|
65
|
+
setShowBranding(data.showBranding ?? true);
|
|
63
66
|
} catch {
|
|
64
67
|
// non-critical
|
|
65
68
|
} finally {
|
|
@@ -81,9 +84,11 @@ export function FeedbackProvider({
|
|
|
81
84
|
);
|
|
82
85
|
|
|
83
86
|
const vote = useCallback(async (feedbackId: string, value: VoteValue) => {
|
|
84
|
-
//
|
|
87
|
+
// Capture snapshot for rollback, then animate into new sorted position
|
|
88
|
+
let snapshot: Feedback[] = [];
|
|
85
89
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
86
90
|
setFeedItems((prev) => {
|
|
91
|
+
snapshot = prev;
|
|
87
92
|
const updated = prev.map((f) => {
|
|
88
93
|
if (f.id !== feedbackId) return f;
|
|
89
94
|
const wasVoted = f.userVote === "UP";
|
|
@@ -96,10 +101,14 @@ export function FeedbackProvider({
|
|
|
96
101
|
return [...updated].sort((a, b) => b.upvotes - a.upvotes);
|
|
97
102
|
});
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
try {
|
|
105
|
+
await client.vote(feedbackId, value);
|
|
106
|
+
} catch {
|
|
107
|
+
// API failed — animate back to original order
|
|
108
|
+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
109
|
+
setFeedItems(snapshot);
|
|
110
|
+
}
|
|
111
|
+
}, [client]);
|
|
103
112
|
|
|
104
113
|
const getItem = useCallback(
|
|
105
114
|
(feedbackId: string) => client.getItem(feedbackId),
|
|
@@ -126,6 +135,7 @@ export function FeedbackProvider({
|
|
|
126
135
|
isOpen, openSheet, closeSheet, identify,
|
|
127
136
|
accentColor: config.accentColor ?? DEFAULT_ACCENT,
|
|
128
137
|
theme: config.theme ?? "auto",
|
|
138
|
+
showBranding,
|
|
129
139
|
}}
|
|
130
140
|
>
|
|
131
141
|
{children}
|
package/src/FeedbackSheet.tsx
CHANGED
|
@@ -60,7 +60,7 @@ type Nav =
|
|
|
60
60
|
// ─── FeedbackSheet ────────────────────────────────────────────────────────────
|
|
61
61
|
|
|
62
62
|
export function FeedbackSheet() {
|
|
63
|
-
const { isOpen, closeSheet, accentColor, theme, loadFeed } = useUpstep();
|
|
63
|
+
const { isOpen, closeSheet, accentColor, theme, loadFeed, showBranding } = useUpstep();
|
|
64
64
|
const scheme = useColorScheme();
|
|
65
65
|
const isDark = theme === "dark" || (theme === "auto" && scheme === "dark");
|
|
66
66
|
const p = isDark ? DARK : LIGHT;
|
|
@@ -193,19 +193,21 @@ export function FeedbackSheet() {
|
|
|
193
193
|
)}
|
|
194
194
|
</ScrollView>
|
|
195
195
|
|
|
196
|
-
{/* Branding
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
196
|
+
{/* Branding — hidden for Business plan */}
|
|
197
|
+
{showBranding && (
|
|
198
|
+
<TouchableOpacity
|
|
199
|
+
onPress={() => Linking.openURL("https://upstep.dev")}
|
|
200
|
+
activeOpacity={0.6}
|
|
201
|
+
style={[
|
|
202
|
+
styles.poweredBy,
|
|
203
|
+
{ borderTopColor: p.border, paddingBottom: insets.bottom + 10, backgroundColor: p.bg },
|
|
204
|
+
]}
|
|
205
|
+
>
|
|
206
|
+
<Text style={[styles.poweredByText, { color: p.textFaint }]}>
|
|
207
|
+
Powered by <Text style={{ fontWeight: "700" }}>Upstep.dev</Text>
|
|
208
|
+
</Text>
|
|
209
|
+
</TouchableOpacity>
|
|
210
|
+
)}
|
|
209
211
|
</View>
|
|
210
212
|
</KeyboardAvoidingView>
|
|
211
213
|
</Modal>
|