@bbearai/react-native 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,19 +1,19 @@
1
- # @bugbearai/react-native
1
+ # @bbearai/react-native
2
2
 
3
3
  BugBear QA widget for React Native mobile apps.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @bugbearai/react-native @bugbearai/core
8
+ npm install @bbearai/react-native @bbearai/core
9
9
  # or
10
- yarn add @bugbearai/react-native @bugbearai/core
10
+ yarn add @bbearai/react-native @bbearai/core
11
11
  ```
12
12
 
13
13
  ## Quick Start
14
14
 
15
15
  ```tsx
16
- import { BugBearProvider, BugBearWidget } from '@bugbearai/react-native';
16
+ import { BugBearProvider, BugBearWidget } from '@bbearai/react-native';
17
17
 
18
18
  function App() {
19
19
  return (
package/dist/index.d.mts CHANGED
@@ -27,6 +27,8 @@ interface BugBearContextValue {
27
27
  sendMessage: (threadId: string, content: string) => Promise<boolean>;
28
28
  /** Mark a thread as read */
29
29
  markAsRead: (threadId: string) => Promise<void>;
30
+ /** Re-check tester status (call after auth state changes) */
31
+ refreshTesterStatus: () => Promise<void>;
30
32
  }
31
33
  declare function useBugBear(): BugBearContextValue;
32
34
  interface BugBearProviderProps {
@@ -34,8 +36,14 @@ interface BugBearProviderProps {
34
36
  children: ReactNode;
35
37
  /** App version string */
36
38
  appVersion?: string;
39
+ /**
40
+ * Set to false to delay initialization until auth is ready.
41
+ * When enabled changes from false to true, BugBear will initialize.
42
+ * @default true
43
+ */
44
+ enabled?: boolean;
37
45
  }
38
- declare function BugBearProvider({ config, children, appVersion }: BugBearProviderProps): React.JSX.Element;
46
+ declare function BugBearProvider({ config, children, appVersion, enabled }: BugBearProviderProps): React.JSX.Element;
39
47
 
40
48
  interface BugBearButtonProps {
41
49
  /** Get current app context */
package/dist/index.d.ts CHANGED
@@ -27,6 +27,8 @@ interface BugBearContextValue {
27
27
  sendMessage: (threadId: string, content: string) => Promise<boolean>;
28
28
  /** Mark a thread as read */
29
29
  markAsRead: (threadId: string) => Promise<void>;
30
+ /** Re-check tester status (call after auth state changes) */
31
+ refreshTesterStatus: () => Promise<void>;
30
32
  }
31
33
  declare function useBugBear(): BugBearContextValue;
32
34
  interface BugBearProviderProps {
@@ -34,8 +36,14 @@ interface BugBearProviderProps {
34
36
  children: ReactNode;
35
37
  /** App version string */
36
38
  appVersion?: string;
39
+ /**
40
+ * Set to false to delay initialization until auth is ready.
41
+ * When enabled changes from false to true, BugBear will initialize.
42
+ * @default true
43
+ */
44
+ enabled?: boolean;
37
45
  }
38
- declare function BugBearProvider({ config, children, appVersion }: BugBearProviderProps): React.JSX.Element;
46
+ declare function BugBearProvider({ config, children, appVersion, enabled }: BugBearProviderProps): React.JSX.Element;
39
47
 
40
48
  interface BugBearButtonProps {
41
49
  /** Get current app context */
package/dist/index.js CHANGED
@@ -60,12 +60,14 @@ var BugBearContext = (0, import_react.createContext)({
60
60
  getThreadMessages: async () => [],
61
61
  sendMessage: async () => false,
62
62
  markAsRead: async () => {
63
+ },
64
+ refreshTesterStatus: async () => {
63
65
  }
64
66
  });
65
67
  function useBugBear() {
66
68
  return (0, import_react.useContext)(BugBearContext);
67
69
  }
68
- function BugBearProvider({ config, children, appVersion }) {
70
+ function BugBearProvider({ config, children, appVersion, enabled = true }) {
69
71
  const [client] = (0, import_react.useState)(() => (0, import_core.createBugBear)(config));
70
72
  const [isTester, setIsTester] = (0, import_react.useState)(false);
71
73
  const [isQAEnabled, setIsQAEnabled] = (0, import_react.useState)(false);
@@ -74,7 +76,9 @@ function BugBearProvider({ config, children, appVersion }) {
74
76
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
75
77
  const [threads, setThreads] = (0, import_react.useState)([]);
76
78
  const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
77
- const getDeviceInfo = () => {
79
+ const [initCount, setInitCount] = (0, import_react.useState)(0);
80
+ const hasInitialized = (0, import_react.useRef)(false);
81
+ const getDeviceInfo = (0, import_react.useCallback)(() => {
78
82
  const { width, height } = import_react_native.Dimensions.get("window");
79
83
  return {
80
84
  platform: import_react_native.Platform.OS,
@@ -82,56 +86,67 @@ function BugBearProvider({ config, children, appVersion }) {
82
86
  appVersion,
83
87
  screenSize: { width, height }
84
88
  };
85
- };
86
- const refreshAssignments = async () => {
89
+ }, [appVersion]);
90
+ const refreshAssignments = (0, import_react.useCallback)(async () => {
87
91
  const newAssignments = await client.getAssignedTests();
88
92
  setAssignments(newAssignments);
89
- };
90
- const refreshThreads = async () => {
93
+ }, [client]);
94
+ const refreshThreads = (0, import_react.useCallback)(async () => {
91
95
  const newThreads = await client.getThreadsForTester();
92
96
  setThreads(newThreads);
93
97
  const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
94
98
  setUnreadCount(totalUnread);
95
- };
96
- const getThreadMessages = async (threadId) => {
99
+ }, [client]);
100
+ const getThreadMessages = (0, import_react.useCallback)(async (threadId) => {
97
101
  return client.getThreadMessages(threadId);
98
- };
99
- const sendMessage = async (threadId, content) => {
102
+ }, [client]);
103
+ const sendMessage = (0, import_react.useCallback)(async (threadId, content) => {
100
104
  const success = await client.sendMessage(threadId, content);
101
105
  if (success) {
102
106
  await refreshThreads();
103
107
  }
104
108
  return success;
105
- };
106
- const markAsRead = async (threadId) => {
109
+ }, [client, refreshThreads]);
110
+ const markAsRead = (0, import_react.useCallback)(async (threadId) => {
107
111
  await client.markThreadAsRead(threadId);
108
112
  await refreshThreads();
109
- };
110
- (0, import_react.useEffect)(() => {
111
- const init = async () => {
112
- setIsLoading(true);
113
- try {
114
- const [qaEnabled, info] = await Promise.all([
115
- client.isQAEnabled(),
116
- client.getTesterInfo()
113
+ }, [client, refreshThreads]);
114
+ const initializeBugBear = (0, import_react.useCallback)(async () => {
115
+ setIsLoading(true);
116
+ try {
117
+ const [qaEnabled, info] = await Promise.all([
118
+ client.isQAEnabled(),
119
+ client.getTesterInfo()
120
+ ]);
121
+ setIsQAEnabled(qaEnabled);
122
+ setTesterInfo(info);
123
+ setIsTester(!!info);
124
+ if (info && qaEnabled) {
125
+ await Promise.all([
126
+ refreshAssignments(),
127
+ refreshThreads()
117
128
  ]);
118
- setIsQAEnabled(qaEnabled);
119
- setTesterInfo(info);
120
- setIsTester(!!info);
121
- if (info && qaEnabled) {
122
- await Promise.all([
123
- refreshAssignments(),
124
- refreshThreads()
125
- ]);
126
- }
127
- } catch (err) {
128
- console.error("BugBear: Init error", err);
129
- } finally {
130
- setIsLoading(false);
131
129
  }
132
- };
133
- init();
134
- }, [client]);
130
+ } catch (err) {
131
+ console.error("BugBear: Init error", err);
132
+ } finally {
133
+ setIsLoading(false);
134
+ }
135
+ }, [client, refreshAssignments, refreshThreads]);
136
+ const refreshTesterStatus = (0, import_react.useCallback)(async () => {
137
+ await initializeBugBear();
138
+ }, [initializeBugBear]);
139
+ (0, import_react.useEffect)(() => {
140
+ if (enabled && !hasInitialized.current) {
141
+ hasInitialized.current = true;
142
+ initializeBugBear();
143
+ }
144
+ }, [enabled, initializeBugBear]);
145
+ (0, import_react.useEffect)(() => {
146
+ if (initCount > 0) {
147
+ initializeBugBear();
148
+ }
149
+ }, [initCount, initializeBugBear]);
135
150
  const currentAssignment = assignments.find(
136
151
  (a) => a.status === "in_progress"
137
152
  ) || assignments[0] || null;
@@ -156,7 +171,8 @@ function BugBearProvider({ config, children, appVersion }) {
156
171
  refreshThreads,
157
172
  getThreadMessages,
158
173
  sendMessage,
159
- markAsRead
174
+ markAsRead,
175
+ refreshTesterStatus
160
176
  }
161
177
  },
162
178
  children
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/BugBearProvider.tsx
2
- import React, { createContext, useContext, useEffect, useState } from "react";
2
+ import React, { createContext, useContext, useEffect, useState, useCallback, useRef } from "react";
3
3
  import {
4
4
  createBugBear
5
5
  } from "@bbearai/core";
@@ -24,12 +24,14 @@ var BugBearContext = createContext({
24
24
  getThreadMessages: async () => [],
25
25
  sendMessage: async () => false,
26
26
  markAsRead: async () => {
27
+ },
28
+ refreshTesterStatus: async () => {
27
29
  }
28
30
  });
29
31
  function useBugBear() {
30
32
  return useContext(BugBearContext);
31
33
  }
32
- function BugBearProvider({ config, children, appVersion }) {
34
+ function BugBearProvider({ config, children, appVersion, enabled = true }) {
33
35
  const [client] = useState(() => createBugBear(config));
34
36
  const [isTester, setIsTester] = useState(false);
35
37
  const [isQAEnabled, setIsQAEnabled] = useState(false);
@@ -38,7 +40,9 @@ function BugBearProvider({ config, children, appVersion }) {
38
40
  const [isLoading, setIsLoading] = useState(true);
39
41
  const [threads, setThreads] = useState([]);
40
42
  const [unreadCount, setUnreadCount] = useState(0);
41
- const getDeviceInfo = () => {
43
+ const [initCount, setInitCount] = useState(0);
44
+ const hasInitialized = useRef(false);
45
+ const getDeviceInfo = useCallback(() => {
42
46
  const { width, height } = Dimensions.get("window");
43
47
  return {
44
48
  platform: Platform.OS,
@@ -46,56 +50,67 @@ function BugBearProvider({ config, children, appVersion }) {
46
50
  appVersion,
47
51
  screenSize: { width, height }
48
52
  };
49
- };
50
- const refreshAssignments = async () => {
53
+ }, [appVersion]);
54
+ const refreshAssignments = useCallback(async () => {
51
55
  const newAssignments = await client.getAssignedTests();
52
56
  setAssignments(newAssignments);
53
- };
54
- const refreshThreads = async () => {
57
+ }, [client]);
58
+ const refreshThreads = useCallback(async () => {
55
59
  const newThreads = await client.getThreadsForTester();
56
60
  setThreads(newThreads);
57
61
  const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
58
62
  setUnreadCount(totalUnread);
59
- };
60
- const getThreadMessages = async (threadId) => {
63
+ }, [client]);
64
+ const getThreadMessages = useCallback(async (threadId) => {
61
65
  return client.getThreadMessages(threadId);
62
- };
63
- const sendMessage = async (threadId, content) => {
66
+ }, [client]);
67
+ const sendMessage = useCallback(async (threadId, content) => {
64
68
  const success = await client.sendMessage(threadId, content);
65
69
  if (success) {
66
70
  await refreshThreads();
67
71
  }
68
72
  return success;
69
- };
70
- const markAsRead = async (threadId) => {
73
+ }, [client, refreshThreads]);
74
+ const markAsRead = useCallback(async (threadId) => {
71
75
  await client.markThreadAsRead(threadId);
72
76
  await refreshThreads();
73
- };
74
- useEffect(() => {
75
- const init = async () => {
76
- setIsLoading(true);
77
- try {
78
- const [qaEnabled, info] = await Promise.all([
79
- client.isQAEnabled(),
80
- client.getTesterInfo()
77
+ }, [client, refreshThreads]);
78
+ const initializeBugBear = useCallback(async () => {
79
+ setIsLoading(true);
80
+ try {
81
+ const [qaEnabled, info] = await Promise.all([
82
+ client.isQAEnabled(),
83
+ client.getTesterInfo()
84
+ ]);
85
+ setIsQAEnabled(qaEnabled);
86
+ setTesterInfo(info);
87
+ setIsTester(!!info);
88
+ if (info && qaEnabled) {
89
+ await Promise.all([
90
+ refreshAssignments(),
91
+ refreshThreads()
81
92
  ]);
82
- setIsQAEnabled(qaEnabled);
83
- setTesterInfo(info);
84
- setIsTester(!!info);
85
- if (info && qaEnabled) {
86
- await Promise.all([
87
- refreshAssignments(),
88
- refreshThreads()
89
- ]);
90
- }
91
- } catch (err) {
92
- console.error("BugBear: Init error", err);
93
- } finally {
94
- setIsLoading(false);
95
93
  }
96
- };
97
- init();
98
- }, [client]);
94
+ } catch (err) {
95
+ console.error("BugBear: Init error", err);
96
+ } finally {
97
+ setIsLoading(false);
98
+ }
99
+ }, [client, refreshAssignments, refreshThreads]);
100
+ const refreshTesterStatus = useCallback(async () => {
101
+ await initializeBugBear();
102
+ }, [initializeBugBear]);
103
+ useEffect(() => {
104
+ if (enabled && !hasInitialized.current) {
105
+ hasInitialized.current = true;
106
+ initializeBugBear();
107
+ }
108
+ }, [enabled, initializeBugBear]);
109
+ useEffect(() => {
110
+ if (initCount > 0) {
111
+ initializeBugBear();
112
+ }
113
+ }, [initCount, initializeBugBear]);
99
114
  const currentAssignment = assignments.find(
100
115
  (a) => a.status === "in_progress"
101
116
  ) || assignments[0] || null;
@@ -120,7 +135,8 @@ function BugBearProvider({ config, children, appVersion }) {
120
135
  refreshThreads,
121
136
  getThreadMessages,
122
137
  sendMessage,
123
- markAsRead
138
+ markAsRead,
139
+ refreshTesterStatus
124
140
  }
125
141
  },
126
142
  children
@@ -128,7 +144,7 @@ function BugBearProvider({ config, children, appVersion }) {
128
144
  }
129
145
 
130
146
  // src/BugBearButton.tsx
131
- import React2, { useState as useState2, useEffect as useEffect2, useRef } from "react";
147
+ import React2, { useState as useState2, useEffect as useEffect2, useRef as useRef2 } from "react";
132
148
  import {
133
149
  View,
134
150
  Text,
@@ -197,9 +213,9 @@ function BugBearButton({
197
213
  return { x, y };
198
214
  };
199
215
  const initialPos = getInitialPosition();
200
- const pan = useRef(new Animated.ValueXY(initialPos)).current;
201
- const isDragging = useRef(false);
202
- const panResponder = useRef(
216
+ const pan = useRef2(new Animated.ValueXY(initialPos)).current;
217
+ const isDragging = useRef2(false);
218
+ const panResponder = useRef2(
203
219
  PanResponder.create({
204
220
  onStartShouldSetPanResponder: () => draggable,
205
221
  onMoveShouldSetPanResponder: (_, gestureState) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/react-native",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "BugBear React Native components for mobile apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -25,7 +25,13 @@
25
25
  "directory": "packages/react-native"
26
26
  },
27
27
  "license": "MIT",
28
- "keywords": ["bugbear", "qa", "testing", "react-native", "mobile"],
28
+ "keywords": [
29
+ "bugbear",
30
+ "qa",
31
+ "testing",
32
+ "react-native",
33
+ "mobile"
34
+ ],
29
35
  "scripts": {
30
36
  "build": "tsup src/index.tsx --format cjs,esm --dts --external react --external react-native",
31
37
  "dev": "tsup src/index.tsx --format cjs,esm --dts --external react --external react-native --watch",