@dubsdotapp/expo 0.2.64 → 0.2.66

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dubsdotapp/expo",
3
- "version": "0.2.64",
3
+ "version": "0.2.66",
4
4
  "description": "React Native SDK for the Dubs betting platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -4,6 +4,8 @@ import { useDubs } from '../provider';
4
4
  import { DUBS_EXPO_PROJECT_ID } from '../constants';
5
5
 
6
6
  export interface PushNotificationStatus {
7
+ /** Whether push notifications are enabled in the SDK configuration */
8
+ enabled: boolean;
7
9
  /** Whether notification permission has been granted */
8
10
  hasPermission: boolean;
9
11
  /** The Expo push token, if registered */
@@ -27,7 +29,7 @@ export interface PushNotificationStatus {
27
29
  }
28
30
 
29
31
  export function usePushNotifications(): PushNotificationStatus {
30
- const { client, appName } = useDubs();
32
+ const { client, appName, pushEnabled } = useDubs();
31
33
  const channelId = useMemo(() => appName.toLowerCase().replace(/[^a-z0-9-]/g, ''), [appName]);
32
34
  const [hasPermission, setHasPermission] = useState(false);
33
35
  const [expoPushToken, setExpoPushToken] = useState<string | null>(null);
@@ -72,6 +74,7 @@ export function usePushNotifications(): PushNotificationStatus {
72
74
  }, [client, getDeviceName]);
73
75
 
74
76
  const register = useCallback(async (): Promise<boolean> => {
77
+ if (!pushEnabled) return false;
75
78
  if (registering.current) return false;
76
79
  registering.current = true;
77
80
  setLoading(true);
@@ -138,6 +141,7 @@ export function usePushNotifications(): PushNotificationStatus {
138
141
  }, [client, expoPushToken]);
139
142
 
140
143
  const restoreIfGranted = useCallback(async () => {
144
+ if (!pushEnabled) return;
141
145
  try {
142
146
  const Notifications = getNotificationsModule();
143
147
  if (!Notifications) return;
@@ -171,6 +175,7 @@ export function usePushNotifications(): PushNotificationStatus {
171
175
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
172
176
 
173
177
  return {
178
+ enabled: pushEnabled,
174
179
  hasPermission,
175
180
  expoPushToken,
176
181
  loading,
package/src/provider.tsx CHANGED
@@ -24,6 +24,7 @@ export interface DubsContextValue {
24
24
  network: DubsNetwork;
25
25
  disconnect: () => Promise<void>;
26
26
  uiConfig: UiConfig;
27
+ pushEnabled: boolean;
27
28
  }
28
29
 
29
30
  const DubsContext = createContext<DubsContextValue | null>(null);
@@ -57,6 +58,8 @@ export interface DubsProviderProps {
57
58
  redirectUri?: string;
58
59
  /** App URL shown in Phantom's connect screen. */
59
60
  appUrl?: string;
61
+ /** Enable Dubs push notifications. Default: true. Set false if your app manages its own Firebase/push. */
62
+ pushEnabled?: boolean;
60
63
  }
61
64
 
62
65
  // ── Provider ──
@@ -77,6 +80,7 @@ export function DubsProvider({
77
80
  managed = true,
78
81
  redirectUri,
79
82
  appUrl,
83
+ pushEnabled = true,
80
84
  }: DubsProviderProps) {
81
85
  // Resolve network config — explicit props override network defaults
82
86
  const config = NETWORK_CONFIG[network];
@@ -129,6 +133,7 @@ export function DubsProvider({
129
133
  renderRegistration={renderRegistration}
130
134
  accentColor={uiConfig.accentColor}
131
135
  uiConfig={uiConfig}
136
+ pushEnabled={pushEnabled}
132
137
  >
133
138
  {children}
134
139
  </ExternalWalletProvider>
@@ -163,6 +168,7 @@ export function DubsProvider({
163
168
  renderRegistration={renderRegistration}
164
169
  accentColor={uiConfig.accentColor}
165
170
  uiConfig={uiConfig}
171
+ pushEnabled={pushEnabled}
166
172
  >
167
173
  {children}
168
174
  </ManagedInner>
@@ -186,6 +192,7 @@ function ManagedInner({
186
192
  renderRegistration,
187
193
  accentColor,
188
194
  uiConfig,
195
+ pushEnabled,
189
196
  children,
190
197
  }: {
191
198
  client: DubsClient;
@@ -199,6 +206,7 @@ function ManagedInner({
199
206
  renderRegistration?: (props: RegistrationScreenProps) => React.ReactNode;
200
207
  accentColor?: string;
201
208
  uiConfig: UiConfig;
209
+ pushEnabled: boolean;
202
210
  children: React.ReactNode;
203
211
  }) {
204
212
  const managedDisconnect = useDisconnect();
@@ -211,8 +219,8 @@ function ManagedInner({
211
219
  }, [client, managedDisconnect]);
212
220
 
213
221
  const value = useMemo<DubsContextValue>(
214
- () => ({ client, wallet, connection, appName, network, disconnect, uiConfig }),
215
- [client, wallet, connection, appName, network, disconnect, uiConfig],
222
+ () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
223
+ [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled],
216
224
  );
217
225
 
218
226
  return (
@@ -250,6 +258,7 @@ function ExternalWalletProvider({
250
258
  renderRegistration,
251
259
  accentColor,
252
260
  uiConfig,
261
+ pushEnabled,
253
262
  children,
254
263
  }: {
255
264
  client: DubsClient;
@@ -264,6 +273,7 @@ function ExternalWalletProvider({
264
273
  renderRegistration?: (props: RegistrationScreenProps) => React.ReactNode;
265
274
  accentColor?: string;
266
275
  uiConfig: UiConfig;
276
+ pushEnabled: boolean;
267
277
  children: React.ReactNode;
268
278
  }) {
269
279
  const disconnect = useCallback(async () => {
@@ -273,8 +283,8 @@ function ExternalWalletProvider({
273
283
  }, [client, storage, wallet]);
274
284
 
275
285
  const value = useMemo<DubsContextValue>(
276
- () => ({ client, wallet, connection, appName, network, disconnect, uiConfig }),
277
- [client, wallet, connection, appName, network, disconnect, uiConfig],
286
+ () => ({ client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled }),
287
+ [client, wallet, connection, appName, network, disconnect, uiConfig, pushEnabled],
278
288
  );
279
289
 
280
290
  if (!managed) {
@@ -73,7 +73,7 @@ export function AuthGate({
73
73
  appName = 'Dubs',
74
74
  accentColor,
75
75
  }: AuthGateProps) {
76
- const { client } = useDubs();
76
+ const { client, pushEnabled } = useDubs();
77
77
  const auth = useAuth();
78
78
  const [phase, setPhase] = useState<'init' | 'active'>('init');
79
79
  const [registrationPhase, setRegistrationPhase] = useState(false);
@@ -109,10 +109,10 @@ export function AuthGate({
109
109
 
110
110
  // Show push setup after new registration completes (not restored sessions)
111
111
  useEffect(() => {
112
- if (auth.status === 'authenticated' && registrationPhase && !isRestoredSession) {
112
+ if (pushEnabled && auth.status === 'authenticated' && registrationPhase && !isRestoredSession) {
113
113
  setShowPushSetup(true);
114
114
  }
115
- }, [auth.status, registrationPhase, isRestoredSession]);
115
+ }, [pushEnabled, auth.status, registrationPhase, isRestoredSession]);
116
116
 
117
117
  useEffect(() => {
118
118
  if (auth.token) onSaveToken(auth.token);
@@ -151,7 +151,7 @@ export function AuthGate({
151
151
  }
152
152
  return (
153
153
  <AuthContext.Provider value={auth}>
154
- <PushTokenRestorer />
154
+ {pushEnabled && <PushTokenRestorer />}
155
155
  {children}
156
156
  </AuthContext.Provider>
157
157
  );
@@ -254,36 +254,38 @@ export function UserProfileSheet({
254
254
  ) : null}
255
255
 
256
256
  {/* Push Notifications */}
257
- <View style={[styles.notifRow, { backgroundColor: t.surface, borderColor: t.border }]}>
258
- <View style={styles.notifLeft}>
259
- <Text style={[styles.notifLabel, { color: t.text }]}>Push Notifications</Text>
260
- <Text
261
- style={[
262
- styles.notifStatus,
263
- { color: push.hasPermission ? t.success : t.textMuted },
264
- ]}
265
- >
266
- {push.hasPermission ? 'Enabled' : 'Disabled'}
267
- </Text>
257
+ {push.enabled && (
258
+ <View style={[styles.notifRow, { backgroundColor: t.surface, borderColor: t.border }]}>
259
+ <View style={styles.notifLeft}>
260
+ <Text style={[styles.notifLabel, { color: t.text }]}>Push Notifications</Text>
261
+ <Text
262
+ style={[
263
+ styles.notifStatus,
264
+ { color: push.hasPermission ? t.success : t.textMuted },
265
+ ]}
266
+ >
267
+ {push.hasPermission ? 'Enabled' : 'Disabled'}
268
+ </Text>
269
+ </View>
270
+ {!push.hasPermission && (
271
+ <TouchableOpacity
272
+ style={[styles.enableButton, { backgroundColor: t.accent }]}
273
+ onPress={push.register}
274
+ disabled={push.loading}
275
+ activeOpacity={0.8}
276
+ >
277
+ {push.loading ? (
278
+ <ActivityIndicator size="small" color="#FFFFFF" />
279
+ ) : (
280
+ <Text style={styles.enableText}>Enable</Text>
281
+ )}
282
+ </TouchableOpacity>
283
+ )}
268
284
  </View>
269
- {!push.hasPermission && (
270
- <TouchableOpacity
271
- style={[styles.enableButton, { backgroundColor: t.accent }]}
272
- onPress={push.register}
273
- disabled={push.loading}
274
- activeOpacity={0.8}
275
- >
276
- {push.loading ? (
277
- <ActivityIndicator size="small" color="#FFFFFF" />
278
- ) : (
279
- <Text style={styles.enableText}>Enable</Text>
280
- )}
281
- </TouchableOpacity>
282
- )}
283
- </View>
285
+ )}
284
286
 
285
287
  {/* Push error */}
286
- {push.error ? (
288
+ {push.enabled && push.error ? (
287
289
  <View style={[styles.errorBox, { backgroundColor: t.errorBg, borderColor: t.errorBorder }]}>
288
290
  <Text style={[styles.errorText, { color: t.errorText }]}>{push.error.message}</Text>
289
291
  </View>