@bbearai/react-native 0.1.2 → 0.1.3

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/dist/index.d.mts CHANGED
@@ -27,6 +27,15 @@ 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
+ /** Create a new thread */
31
+ createThread: (options: {
32
+ subject: string;
33
+ message: string;
34
+ }) => Promise<{
35
+ success: boolean;
36
+ threadId?: string;
37
+ error?: string;
38
+ }>;
30
39
  /** Re-check tester status (call after auth state changes) */
31
40
  refreshTesterStatus: () => Promise<void>;
32
41
  }
package/dist/index.d.ts CHANGED
@@ -27,6 +27,15 @@ 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
+ /** Create a new thread */
31
+ createThread: (options: {
32
+ subject: string;
33
+ message: string;
34
+ }) => Promise<{
35
+ success: boolean;
36
+ threadId?: string;
37
+ error?: string;
38
+ }>;
30
39
  /** Re-check tester status (call after auth state changes) */
31
40
  refreshTesterStatus: () => Promise<void>;
32
41
  }
package/dist/index.js CHANGED
@@ -61,6 +61,7 @@ var BugBearContext = (0, import_react.createContext)({
61
61
  sendMessage: async () => false,
62
62
  markAsRead: async () => {
63
63
  },
64
+ createThread: async () => ({ success: false }),
64
65
  refreshTesterStatus: async () => {
65
66
  }
66
67
  });
@@ -111,6 +112,13 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
111
112
  await client.markThreadAsRead(threadId);
112
113
  await refreshThreads();
113
114
  }, [client, refreshThreads]);
115
+ const createThread = (0, import_react.useCallback)(async (options) => {
116
+ const result = await client.createThread(options);
117
+ if (result.success) {
118
+ await refreshThreads();
119
+ }
120
+ return result;
121
+ }, [client, refreshThreads]);
114
122
  const initializeBugBear = (0, import_react.useCallback)(async () => {
115
123
  setIsLoading(true);
116
124
  try {
@@ -172,6 +180,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
172
180
  getThreadMessages,
173
181
  sendMessage,
174
182
  markAsRead,
183
+ createThread,
175
184
  refreshTesterStatus
176
185
  }
177
186
  },
@@ -214,7 +223,8 @@ function BugBearButton({
214
223
  refreshThreads,
215
224
  getThreadMessages,
216
225
  sendMessage,
217
- markAsRead
226
+ markAsRead,
227
+ createThread
218
228
  } = useBugBear();
219
229
  const [modalVisible, setModalVisible] = (0, import_react2.useState)(false);
220
230
  const [activeTab, setActiveTab] = (0, import_react2.useState)("tests");
@@ -225,6 +235,9 @@ function BugBearButton({
225
235
  const [replyText, setReplyText] = (0, import_react2.useState)("");
226
236
  const [sendingReply, setSendingReply] = (0, import_react2.useState)(false);
227
237
  const [loadingMessages, setLoadingMessages] = (0, import_react2.useState)(false);
238
+ const [composeSubject, setComposeSubject] = (0, import_react2.useState)("");
239
+ const [composeMessage, setComposeMessage] = (0, import_react2.useState)("");
240
+ const [sendingNewMessage, setSendingNewMessage] = (0, import_react2.useState)(false);
228
241
  const getInitialPosition = () => {
229
242
  const buttonSize = 56;
230
243
  const margin = 16;
@@ -387,6 +400,27 @@ function BugBearButton({
387
400
  setSelectedThread(null);
388
401
  setThreadMessages([]);
389
402
  setReplyText("");
403
+ setComposeSubject("");
404
+ setComposeMessage("");
405
+ };
406
+ const handleStartNewMessage = () => {
407
+ setMessageView("compose");
408
+ setComposeSubject("");
409
+ setComposeMessage("");
410
+ };
411
+ const handleSendNewMessage = async () => {
412
+ if (!composeSubject.trim() || !composeMessage.trim()) return;
413
+ setSendingNewMessage(true);
414
+ const result = await createThread({
415
+ subject: composeSubject.trim(),
416
+ message: composeMessage.trim()
417
+ });
418
+ if (result.success) {
419
+ setComposeSubject("");
420
+ setComposeMessage("");
421
+ setMessageView("list");
422
+ }
423
+ setSendingNewMessage(false);
390
424
  };
391
425
  const formatRelativeTime = (dateString) => {
392
426
  const date = new Date(dateString);
@@ -638,9 +672,46 @@ function BugBearButton({
638
672
  },
639
673
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passButtonText }, submitting ? "..." : "\u2713 Pass")
640
674
  )))
641
- ) : null), activeTab === "messages" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, messageView === "list" ? (
675
+ ) : null), activeTab === "messages" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, messageView === "compose" ? (
676
+ /* Compose New Message View */
677
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: handleBackToThreadList, style: styles.backButton }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.backButtonText }, "\u2190 Back to Messages")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.composeHeader }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.composeTitle }, "New Message"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.composeSubtitle }, "Send a message to the QA team")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.composeForm }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.label }, "Subject"), /* @__PURE__ */ import_react2.default.createElement(
678
+ import_react_native2.TextInput,
679
+ {
680
+ style: styles.composeSubjectInput,
681
+ value: composeSubject,
682
+ onChangeText: setComposeSubject,
683
+ placeholder: "What's this about?",
684
+ placeholderTextColor: "#9CA3AF",
685
+ maxLength: 100
686
+ }
687
+ ), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [styles.label, { marginTop: 16 }] }, "Message"), /* @__PURE__ */ import_react2.default.createElement(
688
+ import_react_native2.TextInput,
689
+ {
690
+ style: styles.composeMessageInput,
691
+ value: composeMessage,
692
+ onChangeText: setComposeMessage,
693
+ placeholder: "Write your message...",
694
+ placeholderTextColor: "#9CA3AF",
695
+ multiline: true,
696
+ numberOfLines: 6,
697
+ textAlignVertical: "top",
698
+ maxLength: 2e3
699
+ }
700
+ ), /* @__PURE__ */ import_react2.default.createElement(
701
+ import_react_native2.TouchableOpacity,
702
+ {
703
+ style: [
704
+ styles.composeSendButton,
705
+ (!composeSubject.trim() || !composeMessage.trim() || sendingNewMessage) && styles.composeSendButtonDisabled
706
+ ],
707
+ onPress: handleSendNewMessage,
708
+ disabled: !composeSubject.trim() || !composeMessage.trim() || sendingNewMessage
709
+ },
710
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.composeSendButtonText }, sendingNewMessage ? "Sending..." : "Send Message")
711
+ )))
712
+ ) : messageView === "list" ? (
642
713
  /* Thread List View */
643
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, threads.length === 0 ? /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "No messages yet"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Messages from admins will appear here")) : /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, threads.map((thread) => /* @__PURE__ */ import_react2.default.createElement(
714
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: handleStartNewMessage, style: styles.newMessageButton }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.newMessageButtonIcon }, "\u2709\uFE0F"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.newMessageButtonText }, "New Message")), threads.length === 0 ? /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "No messages yet"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Start a conversation or wait for messages from admins")) : /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, threads.map((thread) => /* @__PURE__ */ import_react2.default.createElement(
644
715
  import_react_native2.TouchableOpacity,
645
716
  {
646
717
  key: thread.id,
@@ -1670,6 +1741,81 @@ var styles = import_react_native2.StyleSheet.create({
1670
1741
  fontSize: 14,
1671
1742
  fontWeight: "600",
1672
1743
  color: "#fff"
1744
+ },
1745
+ // New message button styles
1746
+ newMessageButton: {
1747
+ flexDirection: "row",
1748
+ alignItems: "center",
1749
+ justifyContent: "center",
1750
+ backgroundColor: "#7C3AED",
1751
+ paddingVertical: 12,
1752
+ paddingHorizontal: 20,
1753
+ borderRadius: 12,
1754
+ marginBottom: 16
1755
+ },
1756
+ newMessageButtonIcon: {
1757
+ fontSize: 16,
1758
+ marginRight: 8
1759
+ },
1760
+ newMessageButtonText: {
1761
+ fontSize: 15,
1762
+ fontWeight: "600",
1763
+ color: "#fff"
1764
+ },
1765
+ // Compose view styles
1766
+ composeHeader: {
1767
+ marginBottom: 20
1768
+ },
1769
+ composeTitle: {
1770
+ fontSize: 20,
1771
+ fontWeight: "600",
1772
+ color: "#111827",
1773
+ marginBottom: 4
1774
+ },
1775
+ composeSubtitle: {
1776
+ fontSize: 14,
1777
+ color: "#6B7280"
1778
+ },
1779
+ composeForm: {
1780
+ backgroundColor: "#F9FAFB",
1781
+ borderRadius: 12,
1782
+ padding: 16
1783
+ },
1784
+ composeSubjectInput: {
1785
+ backgroundColor: "#fff",
1786
+ borderWidth: 1,
1787
+ borderColor: "#E5E7EB",
1788
+ borderRadius: 8,
1789
+ paddingHorizontal: 12,
1790
+ paddingVertical: 10,
1791
+ fontSize: 15,
1792
+ color: "#111827"
1793
+ },
1794
+ composeMessageInput: {
1795
+ backgroundColor: "#fff",
1796
+ borderWidth: 1,
1797
+ borderColor: "#E5E7EB",
1798
+ borderRadius: 8,
1799
+ paddingHorizontal: 12,
1800
+ paddingVertical: 10,
1801
+ fontSize: 15,
1802
+ color: "#111827",
1803
+ minHeight: 120
1804
+ },
1805
+ composeSendButton: {
1806
+ backgroundColor: "#7C3AED",
1807
+ paddingVertical: 14,
1808
+ borderRadius: 12,
1809
+ alignItems: "center",
1810
+ marginTop: 20
1811
+ },
1812
+ composeSendButtonDisabled: {
1813
+ backgroundColor: "#C4B5FD"
1814
+ },
1815
+ composeSendButtonText: {
1816
+ fontSize: 16,
1817
+ fontWeight: "600",
1818
+ color: "#fff"
1673
1819
  }
1674
1820
  });
1675
1821
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -25,6 +25,7 @@ var BugBearContext = createContext({
25
25
  sendMessage: async () => false,
26
26
  markAsRead: async () => {
27
27
  },
28
+ createThread: async () => ({ success: false }),
28
29
  refreshTesterStatus: async () => {
29
30
  }
30
31
  });
@@ -75,6 +76,13 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
75
76
  await client.markThreadAsRead(threadId);
76
77
  await refreshThreads();
77
78
  }, [client, refreshThreads]);
79
+ const createThread = useCallback(async (options) => {
80
+ const result = await client.createThread(options);
81
+ if (result.success) {
82
+ await refreshThreads();
83
+ }
84
+ return result;
85
+ }, [client, refreshThreads]);
78
86
  const initializeBugBear = useCallback(async () => {
79
87
  setIsLoading(true);
80
88
  try {
@@ -136,6 +144,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
136
144
  getThreadMessages,
137
145
  sendMessage,
138
146
  markAsRead,
147
+ createThread,
139
148
  refreshTesterStatus
140
149
  }
141
150
  },
@@ -191,7 +200,8 @@ function BugBearButton({
191
200
  refreshThreads,
192
201
  getThreadMessages,
193
202
  sendMessage,
194
- markAsRead
203
+ markAsRead,
204
+ createThread
195
205
  } = useBugBear();
196
206
  const [modalVisible, setModalVisible] = useState2(false);
197
207
  const [activeTab, setActiveTab] = useState2("tests");
@@ -202,6 +212,9 @@ function BugBearButton({
202
212
  const [replyText, setReplyText] = useState2("");
203
213
  const [sendingReply, setSendingReply] = useState2(false);
204
214
  const [loadingMessages, setLoadingMessages] = useState2(false);
215
+ const [composeSubject, setComposeSubject] = useState2("");
216
+ const [composeMessage, setComposeMessage] = useState2("");
217
+ const [sendingNewMessage, setSendingNewMessage] = useState2(false);
205
218
  const getInitialPosition = () => {
206
219
  const buttonSize = 56;
207
220
  const margin = 16;
@@ -364,6 +377,27 @@ function BugBearButton({
364
377
  setSelectedThread(null);
365
378
  setThreadMessages([]);
366
379
  setReplyText("");
380
+ setComposeSubject("");
381
+ setComposeMessage("");
382
+ };
383
+ const handleStartNewMessage = () => {
384
+ setMessageView("compose");
385
+ setComposeSubject("");
386
+ setComposeMessage("");
387
+ };
388
+ const handleSendNewMessage = async () => {
389
+ if (!composeSubject.trim() || !composeMessage.trim()) return;
390
+ setSendingNewMessage(true);
391
+ const result = await createThread({
392
+ subject: composeSubject.trim(),
393
+ message: composeMessage.trim()
394
+ });
395
+ if (result.success) {
396
+ setComposeSubject("");
397
+ setComposeMessage("");
398
+ setMessageView("list");
399
+ }
400
+ setSendingNewMessage(false);
367
401
  };
368
402
  const formatRelativeTime = (dateString) => {
369
403
  const date = new Date(dateString);
@@ -615,9 +649,46 @@ function BugBearButton({
615
649
  },
616
650
  /* @__PURE__ */ React2.createElement(Text, { style: styles.passButtonText }, submitting ? "..." : "\u2713 Pass")
617
651
  )))
618
- ) : null), activeTab === "messages" && /* @__PURE__ */ React2.createElement(View, null, messageView === "list" ? (
652
+ ) : null), activeTab === "messages" && /* @__PURE__ */ React2.createElement(View, null, messageView === "compose" ? (
653
+ /* Compose New Message View */
654
+ /* @__PURE__ */ React2.createElement(View, null, /* @__PURE__ */ React2.createElement(TouchableOpacity, { onPress: handleBackToThreadList, style: styles.backButton }, /* @__PURE__ */ React2.createElement(Text, { style: styles.backButtonText }, "\u2190 Back to Messages")), /* @__PURE__ */ React2.createElement(View, { style: styles.composeHeader }, /* @__PURE__ */ React2.createElement(Text, { style: styles.composeTitle }, "New Message"), /* @__PURE__ */ React2.createElement(Text, { style: styles.composeSubtitle }, "Send a message to the QA team")), /* @__PURE__ */ React2.createElement(View, { style: styles.composeForm }, /* @__PURE__ */ React2.createElement(Text, { style: styles.label }, "Subject"), /* @__PURE__ */ React2.createElement(
655
+ TextInput,
656
+ {
657
+ style: styles.composeSubjectInput,
658
+ value: composeSubject,
659
+ onChangeText: setComposeSubject,
660
+ placeholder: "What's this about?",
661
+ placeholderTextColor: "#9CA3AF",
662
+ maxLength: 100
663
+ }
664
+ ), /* @__PURE__ */ React2.createElement(Text, { style: [styles.label, { marginTop: 16 }] }, "Message"), /* @__PURE__ */ React2.createElement(
665
+ TextInput,
666
+ {
667
+ style: styles.composeMessageInput,
668
+ value: composeMessage,
669
+ onChangeText: setComposeMessage,
670
+ placeholder: "Write your message...",
671
+ placeholderTextColor: "#9CA3AF",
672
+ multiline: true,
673
+ numberOfLines: 6,
674
+ textAlignVertical: "top",
675
+ maxLength: 2e3
676
+ }
677
+ ), /* @__PURE__ */ React2.createElement(
678
+ TouchableOpacity,
679
+ {
680
+ style: [
681
+ styles.composeSendButton,
682
+ (!composeSubject.trim() || !composeMessage.trim() || sendingNewMessage) && styles.composeSendButtonDisabled
683
+ ],
684
+ onPress: handleSendNewMessage,
685
+ disabled: !composeSubject.trim() || !composeMessage.trim() || sendingNewMessage
686
+ },
687
+ /* @__PURE__ */ React2.createElement(Text, { style: styles.composeSendButtonText }, sendingNewMessage ? "Sending..." : "Send Message")
688
+ )))
689
+ ) : messageView === "list" ? (
619
690
  /* Thread List View */
620
- /* @__PURE__ */ React2.createElement(View, null, threads.length === 0 ? /* @__PURE__ */ React2.createElement(View, { style: styles.emptyState }, /* @__PURE__ */ React2.createElement(Text, { style: styles.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ React2.createElement(Text, { style: styles.emptyTitle }, "No messages yet"), /* @__PURE__ */ React2.createElement(Text, { style: styles.emptySubtitle }, "Messages from admins will appear here")) : /* @__PURE__ */ React2.createElement(View, null, threads.map((thread) => /* @__PURE__ */ React2.createElement(
691
+ /* @__PURE__ */ React2.createElement(View, null, /* @__PURE__ */ React2.createElement(TouchableOpacity, { onPress: handleStartNewMessage, style: styles.newMessageButton }, /* @__PURE__ */ React2.createElement(Text, { style: styles.newMessageButtonIcon }, "\u2709\uFE0F"), /* @__PURE__ */ React2.createElement(Text, { style: styles.newMessageButtonText }, "New Message")), threads.length === 0 ? /* @__PURE__ */ React2.createElement(View, { style: styles.emptyState }, /* @__PURE__ */ React2.createElement(Text, { style: styles.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ React2.createElement(Text, { style: styles.emptyTitle }, "No messages yet"), /* @__PURE__ */ React2.createElement(Text, { style: styles.emptySubtitle }, "Start a conversation or wait for messages from admins")) : /* @__PURE__ */ React2.createElement(View, null, threads.map((thread) => /* @__PURE__ */ React2.createElement(
621
692
  TouchableOpacity,
622
693
  {
623
694
  key: thread.id,
@@ -1647,6 +1718,81 @@ var styles = StyleSheet.create({
1647
1718
  fontSize: 14,
1648
1719
  fontWeight: "600",
1649
1720
  color: "#fff"
1721
+ },
1722
+ // New message button styles
1723
+ newMessageButton: {
1724
+ flexDirection: "row",
1725
+ alignItems: "center",
1726
+ justifyContent: "center",
1727
+ backgroundColor: "#7C3AED",
1728
+ paddingVertical: 12,
1729
+ paddingHorizontal: 20,
1730
+ borderRadius: 12,
1731
+ marginBottom: 16
1732
+ },
1733
+ newMessageButtonIcon: {
1734
+ fontSize: 16,
1735
+ marginRight: 8
1736
+ },
1737
+ newMessageButtonText: {
1738
+ fontSize: 15,
1739
+ fontWeight: "600",
1740
+ color: "#fff"
1741
+ },
1742
+ // Compose view styles
1743
+ composeHeader: {
1744
+ marginBottom: 20
1745
+ },
1746
+ composeTitle: {
1747
+ fontSize: 20,
1748
+ fontWeight: "600",
1749
+ color: "#111827",
1750
+ marginBottom: 4
1751
+ },
1752
+ composeSubtitle: {
1753
+ fontSize: 14,
1754
+ color: "#6B7280"
1755
+ },
1756
+ composeForm: {
1757
+ backgroundColor: "#F9FAFB",
1758
+ borderRadius: 12,
1759
+ padding: 16
1760
+ },
1761
+ composeSubjectInput: {
1762
+ backgroundColor: "#fff",
1763
+ borderWidth: 1,
1764
+ borderColor: "#E5E7EB",
1765
+ borderRadius: 8,
1766
+ paddingHorizontal: 12,
1767
+ paddingVertical: 10,
1768
+ fontSize: 15,
1769
+ color: "#111827"
1770
+ },
1771
+ composeMessageInput: {
1772
+ backgroundColor: "#fff",
1773
+ borderWidth: 1,
1774
+ borderColor: "#E5E7EB",
1775
+ borderRadius: 8,
1776
+ paddingHorizontal: 12,
1777
+ paddingVertical: 10,
1778
+ fontSize: 15,
1779
+ color: "#111827",
1780
+ minHeight: 120
1781
+ },
1782
+ composeSendButton: {
1783
+ backgroundColor: "#7C3AED",
1784
+ paddingVertical: 14,
1785
+ borderRadius: 12,
1786
+ alignItems: "center",
1787
+ marginTop: 20
1788
+ },
1789
+ composeSendButtonDisabled: {
1790
+ backgroundColor: "#C4B5FD"
1791
+ },
1792
+ composeSendButtonText: {
1793
+ fontSize: 16,
1794
+ fontWeight: "600",
1795
+ color: "#fff"
1650
1796
  }
1651
1797
  });
1652
1798
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/react-native",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "BugBear React Native components for mobile apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",