@jarve/bug-reporter 0.2.0 → 0.3.0
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 +8 -7
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +135 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -91
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Bug reporter widget for Next.js apps. Reports flow to your JARVE Agency dashboar
|
|
|
14
14
|
### 1. Register your site
|
|
15
15
|
|
|
16
16
|
Go to your JARVE Agency dashboard at `/admin/bug-reports/sites` and:
|
|
17
|
+
|
|
17
18
|
- Click **Add Site**
|
|
18
19
|
- Enter your site name and color
|
|
19
20
|
- Click **Generate API Key**
|
|
@@ -34,7 +35,7 @@ The widget uses Tailwind CSS classes. Add the package to your Tailwind content c
|
|
|
34
35
|
**Tailwind v4** (add `@source` in your CSS file):
|
|
35
36
|
|
|
36
37
|
```css
|
|
37
|
-
@source
|
|
38
|
+
@source '../node_modules/@jarve/bug-reporter/dist';
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
**Tailwind v3** (add to `content` in `tailwind.config.ts`):
|
|
@@ -72,12 +73,12 @@ Click the blue bug icon (bottom-right) to report bugs. They'll appear in your JA
|
|
|
72
73
|
|
|
73
74
|
## Props
|
|
74
75
|
|
|
75
|
-
| Prop
|
|
76
|
-
|
|
77
|
-
| `apiUrl`
|
|
78
|
-
| `apiKey`
|
|
79
|
-
| `user`
|
|
80
|
-
| `children` | `ReactNode`
|
|
76
|
+
| Prop | Type | Required | Description |
|
|
77
|
+
| ---------- | --------------------------------- | -------- | ---------------------------------------------------------- |
|
|
78
|
+
| `apiUrl` | `string` | Yes | Base URL for the external bug reporter API |
|
|
79
|
+
| `apiKey` | `string` | Yes | Your site's API key (starts with `brk_`) |
|
|
80
|
+
| `user` | `{ name: string, email: string }` | No | User info. If omitted, the AI will ask during conversation |
|
|
81
|
+
| `children` | `ReactNode` | Yes | Your app content |
|
|
81
82
|
|
|
82
83
|
## What gets captured
|
|
83
84
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
+
type FloatingButtonPosition = 'left' | 'right';
|
|
4
|
+
|
|
3
5
|
interface BugReporterUser {
|
|
4
6
|
name: string;
|
|
5
7
|
email: string;
|
|
@@ -14,10 +16,12 @@ interface JarveBugReporterProps {
|
|
|
14
16
|
apiUrl: string;
|
|
15
17
|
/** API key for your site (starts with "brk_") */
|
|
16
18
|
apiKey: string;
|
|
19
|
+
/** Optional position for the floating button (default: 'right') */
|
|
20
|
+
buttonPosition?: FloatingButtonPosition;
|
|
17
21
|
/** Optional user info. If not provided, the AI will ask for name/email during the conversation. */
|
|
18
22
|
user?: BugReporterUser;
|
|
19
23
|
children: React.ReactNode;
|
|
20
24
|
}
|
|
21
|
-
declare function JarveBugReporter({ apiUrl, apiKey, user, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
declare function JarveBugReporter({ apiUrl, apiKey, user, buttonPosition, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
22
26
|
|
|
23
27
|
export { type BugReporterApiConfig, type BugReporterUser, JarveBugReporter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
+
type FloatingButtonPosition = 'left' | 'right';
|
|
4
|
+
|
|
3
5
|
interface BugReporterUser {
|
|
4
6
|
name: string;
|
|
5
7
|
email: string;
|
|
@@ -14,10 +16,12 @@ interface JarveBugReporterProps {
|
|
|
14
16
|
apiUrl: string;
|
|
15
17
|
/** API key for your site (starts with "brk_") */
|
|
16
18
|
apiKey: string;
|
|
19
|
+
/** Optional position for the floating button (default: 'right') */
|
|
20
|
+
buttonPosition?: FloatingButtonPosition;
|
|
17
21
|
/** Optional user info. If not provided, the AI will ask for name/email during the conversation. */
|
|
18
22
|
user?: BugReporterUser;
|
|
19
23
|
children: React.ReactNode;
|
|
20
24
|
}
|
|
21
|
-
declare function JarveBugReporter({ apiUrl, apiKey, user, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
declare function JarveBugReporter({ apiUrl, apiKey, user, buttonPosition, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
22
26
|
|
|
23
27
|
export { type BugReporterApiConfig, type BugReporterUser, JarveBugReporter };
|
package/dist/index.js
CHANGED
|
@@ -57,16 +57,21 @@ function cn(...inputs) {
|
|
|
57
57
|
|
|
58
58
|
// src/floating-button.tsx
|
|
59
59
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
60
|
-
function FloatingButton({ isActive, onClick }) {
|
|
60
|
+
function FloatingButton({ isActive, onClick, position = "right" }) {
|
|
61
|
+
const sideClasses = position === "left" ? "left-4 md:left-6" : "right-4 md:right-6";
|
|
61
62
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
62
63
|
"button",
|
|
63
64
|
{
|
|
64
65
|
onClick,
|
|
65
66
|
className: cn(
|
|
66
|
-
"fixed
|
|
67
|
-
"hover:scale-110 focus:
|
|
68
|
-
|
|
69
|
-
"bottom-4
|
|
67
|
+
"fixed z-[9999] flex items-center justify-center rounded-full shadow-lg transition-all duration-200",
|
|
68
|
+
"hover:scale-110 focus:ring-2 focus:ring-offset-2 focus:outline-none",
|
|
69
|
+
// size + vertical position
|
|
70
|
+
"bottom-4 h-11 w-11 md:bottom-6 md:h-12 md:w-12",
|
|
71
|
+
// horizontal side
|
|
72
|
+
sideClasses,
|
|
73
|
+
// active vs idle colors
|
|
74
|
+
isActive ? "animate-pulse bg-red-500 text-white focus:ring-red-400" : "bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-400"
|
|
70
75
|
),
|
|
71
76
|
title: isActive ? "Cancel bug capture" : "Report a bug",
|
|
72
77
|
"aria-label": isActive ? "Cancel bug capture" : "Report a bug",
|
|
@@ -196,8 +201,7 @@ var errorListener = null;
|
|
|
196
201
|
var rejectionListener = null;
|
|
197
202
|
function startCapturing() {
|
|
198
203
|
if (isCapturing) return;
|
|
199
|
-
if (console.error.__bugReporterPatched)
|
|
200
|
-
return;
|
|
204
|
+
if (console.error.__bugReporterPatched) return;
|
|
201
205
|
isCapturing = true;
|
|
202
206
|
capturedErrors = [];
|
|
203
207
|
originalConsoleError = console.error;
|
|
@@ -443,12 +447,21 @@ function CaptureOverlay({
|
|
|
443
447
|
skipFonts: true
|
|
444
448
|
});
|
|
445
449
|
const blob = dataUrlToBlob(dataUrl);
|
|
446
|
-
const metadata = collectMetadata(
|
|
450
|
+
const metadata = collectMetadata(
|
|
451
|
+
section,
|
|
452
|
+
siteId,
|
|
453
|
+
reporterName,
|
|
454
|
+
reporterEmail,
|
|
455
|
+
elementInfo
|
|
456
|
+
);
|
|
447
457
|
const consoleErrors = getCapturedErrors();
|
|
448
458
|
const networkErrors = getCapturedNetworkErrors();
|
|
449
459
|
onCapture({ screenshot: blob, metadata, consoleErrors, networkErrors });
|
|
450
460
|
} catch (err) {
|
|
451
|
-
console.warn(
|
|
461
|
+
console.warn(
|
|
462
|
+
"Bug reporter: first capture attempt failed, retrying with simpler settings",
|
|
463
|
+
err
|
|
464
|
+
);
|
|
452
465
|
try {
|
|
453
466
|
const dataUrl = await (0, import_html_to_image.toPng)(section, {
|
|
454
467
|
quality: 0.6,
|
|
@@ -457,13 +470,25 @@ function CaptureOverlay({
|
|
|
457
470
|
cacheBust: true
|
|
458
471
|
});
|
|
459
472
|
const retryBlob = dataUrlToBlob(dataUrl);
|
|
460
|
-
const metadata = collectMetadata(
|
|
473
|
+
const metadata = collectMetadata(
|
|
474
|
+
section,
|
|
475
|
+
siteId,
|
|
476
|
+
reporterName,
|
|
477
|
+
reporterEmail,
|
|
478
|
+
elementInfo
|
|
479
|
+
);
|
|
461
480
|
const consoleErrors = getCapturedErrors();
|
|
462
481
|
const networkErrors = getCapturedNetworkErrors();
|
|
463
482
|
onCapture({ screenshot: retryBlob, metadata, consoleErrors, networkErrors });
|
|
464
483
|
} catch (e) {
|
|
465
484
|
console.error("Bug reporter: screenshot capture failed after retry");
|
|
466
|
-
const metadata = collectMetadata(
|
|
485
|
+
const metadata = collectMetadata(
|
|
486
|
+
section,
|
|
487
|
+
siteId,
|
|
488
|
+
reporterName,
|
|
489
|
+
reporterEmail,
|
|
490
|
+
elementInfo
|
|
491
|
+
);
|
|
467
492
|
const consoleErrors = getCapturedErrors();
|
|
468
493
|
const networkErrors = getCapturedNetworkErrors();
|
|
469
494
|
onCapture({
|
|
@@ -594,7 +619,16 @@ function CaptureOverlay({
|
|
|
594
619
|
document.removeEventListener("click", handleClick, true);
|
|
595
620
|
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
596
621
|
};
|
|
597
|
-
}, [
|
|
622
|
+
}, [
|
|
623
|
+
isActive,
|
|
624
|
+
isTouchMode,
|
|
625
|
+
handleMouseMove,
|
|
626
|
+
handleClick,
|
|
627
|
+
handleTouchEnd,
|
|
628
|
+
handlePointerDown,
|
|
629
|
+
handleKeyDown,
|
|
630
|
+
handleScroll
|
|
631
|
+
]);
|
|
598
632
|
const highlightRect = isTouchMode ? selectedRect : hoveredRect;
|
|
599
633
|
const showHighlight = isTouchMode ? !!selectedSection : !!hoveredElement && !!hoveredRect;
|
|
600
634
|
if (!isActive) return null;
|
|
@@ -605,20 +639,21 @@ function CaptureOverlay({
|
|
|
605
639
|
"data-bug-reporter": true,
|
|
606
640
|
role: "alert",
|
|
607
641
|
"aria-live": "assertive",
|
|
608
|
-
className: "fixed top-0
|
|
642
|
+
className: "fixed top-0 right-0 left-0 z-[10000] flex items-center justify-center gap-3 bg-indigo-600 px-4 py-2 text-center text-sm font-medium text-white",
|
|
609
643
|
children: isTouchMode ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
610
644
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Tap the section with the bug" }),
|
|
611
645
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
612
646
|
"button",
|
|
613
647
|
{
|
|
614
648
|
onClick: onCancel,
|
|
615
|
-
className: "
|
|
649
|
+
className: "min-h-[44px] rounded-md bg-white/20 px-3 py-1 text-sm font-medium",
|
|
616
650
|
children: "Cancel"
|
|
617
651
|
}
|
|
618
652
|
)
|
|
619
653
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
620
|
-
"Click on the section with the bug. Press
|
|
621
|
-
|
|
654
|
+
"Click on the section with the bug. Press",
|
|
655
|
+
" ",
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("kbd", { className: "mx-1 rounded bg-indigo-800 px-1.5 py-0.5 text-xs", children: "Esc" }),
|
|
622
657
|
" to cancel."
|
|
623
658
|
] })
|
|
624
659
|
}
|
|
@@ -628,7 +663,7 @@ function CaptureOverlay({
|
|
|
628
663
|
{
|
|
629
664
|
ref: overlayRef,
|
|
630
665
|
"data-bug-reporter": true,
|
|
631
|
-
className: "
|
|
666
|
+
className: "pointer-events-none fixed z-[9998] rounded-sm border-2 border-indigo-500 transition-all duration-150 ease-out",
|
|
632
667
|
style: {
|
|
633
668
|
top: highlightRect.top - 2,
|
|
634
669
|
left: highlightRect.left - 2,
|
|
@@ -642,11 +677,11 @@ function CaptureOverlay({
|
|
|
642
677
|
"div",
|
|
643
678
|
{
|
|
644
679
|
"data-bug-reporter": true,
|
|
645
|
-
className: "fixed
|
|
680
|
+
className: "fixed right-0 bottom-0 left-0 z-[10000] border-t border-gray-200 bg-white shadow-lg",
|
|
646
681
|
style: { paddingBottom: "env(safe-area-inset-bottom, 0px)" },
|
|
647
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between px-4 py-3
|
|
648
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm font-medium text-gray-900
|
|
649
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2
|
|
682
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between gap-3 px-4 py-3", children: [
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-sm font-medium text-gray-900", children: "Capture this section?" }),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex shrink-0 gap-2", children: [
|
|
650
685
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
651
686
|
"button",
|
|
652
687
|
{
|
|
@@ -656,7 +691,7 @@ function CaptureOverlay({
|
|
|
656
691
|
setSelectedTarget(null);
|
|
657
692
|
touchCoordsRef.current = null;
|
|
658
693
|
},
|
|
659
|
-
className: "
|
|
694
|
+
className: "min-h-[44px] rounded-md border border-gray-300 px-4 text-sm font-medium text-gray-700",
|
|
660
695
|
children: "Cancel"
|
|
661
696
|
}
|
|
662
697
|
),
|
|
@@ -664,7 +699,7 @@ function CaptureOverlay({
|
|
|
664
699
|
"button",
|
|
665
700
|
{
|
|
666
701
|
onClick: handleConfirmCapture,
|
|
667
|
-
className: "
|
|
702
|
+
className: "min-h-[44px] rounded-md bg-indigo-600 px-4 text-sm font-medium text-white",
|
|
668
703
|
children: "Capture"
|
|
669
704
|
}
|
|
670
705
|
)
|
|
@@ -738,7 +773,9 @@ function ReportModal({
|
|
|
738
773
|
})
|
|
739
774
|
});
|
|
740
775
|
if (response.status === 401) {
|
|
741
|
-
console.error(
|
|
776
|
+
console.error(
|
|
777
|
+
"Bug reporter: invalid or missing API key. Check your BugReporter apiKey prop."
|
|
778
|
+
);
|
|
742
779
|
setMessages([
|
|
743
780
|
{
|
|
744
781
|
role: "assistant",
|
|
@@ -835,9 +872,7 @@ function ReportModal({
|
|
|
835
872
|
setModalState("submitted");
|
|
836
873
|
} catch (err) {
|
|
837
874
|
console.error("Bug reporter: failed to submit report", err);
|
|
838
|
-
setErrorMessage(
|
|
839
|
-
err instanceof Error ? err.message : "Failed to submit report"
|
|
840
|
-
);
|
|
875
|
+
setErrorMessage(err instanceof Error ? err.message : "Failed to submit report");
|
|
841
876
|
setModalState("error");
|
|
842
877
|
}
|
|
843
878
|
},
|
|
@@ -850,10 +885,7 @@ function ReportModal({
|
|
|
850
885
|
if (!input.trim() || isLoading || !captureResult) return;
|
|
851
886
|
const userMessage = input.trim();
|
|
852
887
|
setInput("");
|
|
853
|
-
const newMessages = [
|
|
854
|
-
...messages,
|
|
855
|
-
{ role: "user", content: userMessage }
|
|
856
|
-
];
|
|
888
|
+
const newMessages = [...messages, { role: "user", content: userMessage }];
|
|
857
889
|
setMessages(newMessages);
|
|
858
890
|
setIsLoading(true);
|
|
859
891
|
try {
|
|
@@ -869,7 +901,9 @@ function ReportModal({
|
|
|
869
901
|
})
|
|
870
902
|
});
|
|
871
903
|
if (response.status === 401) {
|
|
872
|
-
console.error(
|
|
904
|
+
console.error(
|
|
905
|
+
"Bug reporter: invalid or missing API key. Check your BugReporter apiKey prop."
|
|
906
|
+
);
|
|
873
907
|
setMessages([
|
|
874
908
|
...newMessages,
|
|
875
909
|
{
|
|
@@ -881,10 +915,7 @@ function ReportModal({
|
|
|
881
915
|
}
|
|
882
916
|
if (!response.ok) throw new Error("Failed to get AI response");
|
|
883
917
|
const data = await response.json();
|
|
884
|
-
setMessages([
|
|
885
|
-
...newMessages,
|
|
886
|
-
{ role: "assistant", content: data.message }
|
|
887
|
-
]);
|
|
918
|
+
setMessages([...newMessages, { role: "assistant", content: data.message }]);
|
|
888
919
|
if (data.readyToSubmit && data.structuredReport) {
|
|
889
920
|
await submitReport(
|
|
890
921
|
[...newMessages, { role: "assistant", content: data.message }],
|
|
@@ -935,65 +966,66 @@ function ReportModal({
|
|
|
935
966
|
"div",
|
|
936
967
|
{
|
|
937
968
|
className: cn(
|
|
938
|
-
"
|
|
939
|
-
"w-full max-w-lg
|
|
940
|
-
"max-[768px]:mx-0 max-[768px]:
|
|
969
|
+
"flex flex-col overflow-hidden rounded-xl border border-gray-200 bg-white shadow-2xl dark:border-gray-800 dark:bg-gray-950",
|
|
970
|
+
"mx-4 w-full max-w-lg",
|
|
971
|
+
"max-[768px]:mx-0 max-[768px]:h-full max-[768px]:max-w-none max-[768px]:rounded-none",
|
|
941
972
|
"min-[769px]:max-h-[85vh]"
|
|
942
973
|
),
|
|
943
974
|
children: [
|
|
944
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between
|
|
975
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between border-b border-gray-200 bg-gray-50/30 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/30", children: [
|
|
945
976
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
946
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "font-semibold text-
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Bug Report" }),
|
|
947
978
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: siteId })
|
|
948
979
|
] }),
|
|
949
980
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
950
981
|
"button",
|
|
951
982
|
{
|
|
952
983
|
onClick: handleClose,
|
|
953
|
-
className: "p-1.5
|
|
984
|
+
className: "rounded-md p-1.5 transition-colors hover:bg-gray-100 dark:hover:bg-gray-800",
|
|
954
985
|
"aria-label": "Close",
|
|
955
986
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.X, { className: "h-4 w-4 text-gray-600 dark:text-gray-400" })
|
|
956
987
|
}
|
|
957
988
|
)
|
|
958
989
|
] }),
|
|
959
|
-
screenshotUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "
|
|
990
|
+
screenshotUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "border-b border-gray-200 bg-gray-50/10 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/10", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
960
991
|
"img",
|
|
961
992
|
{
|
|
962
993
|
src: screenshotUrl,
|
|
963
994
|
alt: "Captured section",
|
|
964
|
-
className: "
|
|
995
|
+
className: "max-h-40 w-full rounded-md border border-gray-200 object-contain dark:border-gray-700"
|
|
965
996
|
}
|
|
966
997
|
) }),
|
|
967
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-1 overflow-y-auto px-4 py-3
|
|
968
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.CheckCircle2, { className: "h-12 w-12 text-green-500
|
|
969
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "font-semibold text-
|
|
970
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "text-sm text-gray-500 dark:text-gray-400
|
|
971
|
-
"Reference:
|
|
972
|
-
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-3", children: modalState === "submitted" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.CheckCircle2, { className: "mb-3 h-12 w-12 text-green-500" }),
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Report Submitted" }),
|
|
1001
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1002
|
+
"Reference:",
|
|
1003
|
+
" ",
|
|
1004
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { className: "rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800", children: reportId == null ? void 0 : reportId.slice(0, 8) })
|
|
973
1005
|
] }),
|
|
974
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm text-gray-500 dark:text-gray-400
|
|
1006
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: "Thanks for the report \u2014 we'll look into it." }),
|
|
975
1007
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
976
1008
|
"button",
|
|
977
1009
|
{
|
|
978
1010
|
onClick: handleClose,
|
|
979
|
-
className: "mt-4 px-4 py-2
|
|
1011
|
+
className: "mt-4 rounded-md bg-indigo-600 px-4 py-2 text-sm text-white transition-colors hover:bg-indigo-700",
|
|
980
1012
|
children: "Done"
|
|
981
1013
|
}
|
|
982
1014
|
)
|
|
983
1015
|
] }) : modalState === "error" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
984
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.X, { className: "h-12 w-12 text-red-500
|
|
985
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "font-semibold text-
|
|
986
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm text-gray-500 dark:text-gray-400
|
|
1016
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.X, { className: "mb-3 h-12 w-12 text-red-500" }),
|
|
1017
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Submission Failed" }),
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: errorMessage || "Something went wrong. Please try again." }),
|
|
987
1019
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
988
1020
|
"button",
|
|
989
1021
|
{
|
|
990
1022
|
onClick: () => setModalState("chatting"),
|
|
991
|
-
className: "mt-4 px-4 py-2
|
|
1023
|
+
className: "mt-4 rounded-md bg-indigo-600 px-4 py-2 text-sm text-white transition-colors hover:bg-indigo-700",
|
|
992
1024
|
children: "Try Again"
|
|
993
1025
|
}
|
|
994
1026
|
)
|
|
995
1027
|
] }) : modalState === "submitting" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col items-center justify-center py-8", children: [
|
|
996
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Loader2, { className: "h-8 w-8 animate-spin text-indigo-500
|
|
1028
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Loader2, { className: "mb-3 h-8 w-8 animate-spin text-indigo-500" }),
|
|
997
1029
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Submitting your report..." })
|
|
998
1030
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
999
1031
|
(captureResult == null ? void 0 : captureResult.screenshot.size) === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-amber-600", children: "Screenshot could not be captured. Please describe the visual issue in detail." }),
|
|
@@ -1002,42 +1034,53 @@ function ReportModal({
|
|
|
1002
1034
|
{
|
|
1003
1035
|
className: cn(
|
|
1004
1036
|
"text-sm leading-relaxed",
|
|
1005
|
-
msg.role === "assistant" ? "
|
|
1037
|
+
msg.role === "assistant" ? "rounded-lg bg-gray-100/50 p-3 text-gray-900 dark:bg-gray-800/50 dark:text-gray-100" : "ml-8 rounded-lg bg-indigo-600 p-3 text-white"
|
|
1006
1038
|
),
|
|
1007
1039
|
children: msg.content
|
|
1008
1040
|
},
|
|
1009
1041
|
i
|
|
1010
1042
|
)),
|
|
1011
|
-
isLoading && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "bg-gray-100/50 dark:bg-gray-800/50
|
|
1043
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 rounded-lg bg-gray-100/50 p-3 dark:bg-gray-800/50", children: [
|
|
1012
1044
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Loader2, { className: "h-3.5 w-3.5 animate-spin text-gray-500" }),
|
|
1013
1045
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Thinking..." })
|
|
1014
1046
|
] }),
|
|
1015
1047
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: chatEndRef })
|
|
1016
1048
|
] }) }),
|
|
1017
|
-
modalState === "chatting" && /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1018
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("
|
|
1033
|
-
|
|
1049
|
+
modalState === "chatting" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "border-t border-gray-200 px-4 py-3 dark:border-gray-800", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1051
|
+
"textarea",
|
|
1052
|
+
{
|
|
1053
|
+
ref: inputRef,
|
|
1054
|
+
value: input,
|
|
1055
|
+
onChange: (e) => setInput(e.target.value),
|
|
1056
|
+
onKeyDown: handleKeyDown,
|
|
1057
|
+
placeholder: "Describe what's wrong...",
|
|
1058
|
+
rows: 2,
|
|
1059
|
+
className: "w-full resize-none rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-transparent focus:ring-2 focus:ring-indigo-400 focus:outline-none dark:border-gray-700 dark:bg-gray-950 dark:text-gray-100",
|
|
1060
|
+
disabled: isLoading
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1064
|
+
captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "flex-1 text-xs text-amber-600", children: [
|
|
1065
|
+
[
|
|
1066
|
+
captureResult.consoleErrors.length > 0 ? `${captureResult.consoleErrors.length} console error${captureResult.consoleErrors.length !== 1 ? "s" : ""}` : null,
|
|
1067
|
+
captureResult.networkErrors.length > 0 ? `${captureResult.networkErrors.length} failed request${captureResult.networkErrors.length !== 1 ? "s" : ""}` : null
|
|
1068
|
+
].filter(Boolean).join(" + "),
|
|
1069
|
+
" ",
|
|
1070
|
+
"captured \u2014 these will be included in the report."
|
|
1071
|
+
] }),
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex justify-end gap-2", children: [
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1034
1074
|
"button",
|
|
1035
1075
|
{
|
|
1036
1076
|
onClick: sendMessage,
|
|
1037
1077
|
disabled: !input.trim() || isLoading,
|
|
1038
|
-
className: "
|
|
1078
|
+
className: "flex items-center gap-1 rounded-md bg-indigo-600 px-3 py-2 text-nowrap text-white transition-colors hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50",
|
|
1039
1079
|
title: "Send message",
|
|
1040
|
-
children:
|
|
1080
|
+
children: [
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Send, { className: "h-4 w-4" }),
|
|
1082
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-medium", children: "Send message" })
|
|
1083
|
+
]
|
|
1041
1084
|
}
|
|
1042
1085
|
),
|
|
1043
1086
|
messages.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -1045,22 +1088,14 @@ function ReportModal({
|
|
|
1045
1088
|
{
|
|
1046
1089
|
onClick: handleManualSubmit,
|
|
1047
1090
|
disabled: isLoading,
|
|
1048
|
-
className: "px-
|
|
1091
|
+
className: "rounded-md bg-green-600 px-3 py-2 text-xs font-medium text-nowrap text-white transition-colors hover:bg-green-700 disabled:opacity-50",
|
|
1049
1092
|
title: "Submit report now",
|
|
1050
|
-
children: "Submit"
|
|
1093
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm font-medium", children: "Submit report" })
|
|
1051
1094
|
}
|
|
1052
1095
|
)
|
|
1053
1096
|
] })
|
|
1054
|
-
] }),
|
|
1055
|
-
captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "text-xs text-amber-600 mt-1.5", children: [
|
|
1056
|
-
[
|
|
1057
|
-
captureResult.consoleErrors.length > 0 ? `${captureResult.consoleErrors.length} console error${captureResult.consoleErrors.length !== 1 ? "s" : ""}` : null,
|
|
1058
|
-
captureResult.networkErrors.length > 0 ? `${captureResult.networkErrors.length} failed request${captureResult.networkErrors.length !== 1 ? "s" : ""}` : null
|
|
1059
|
-
].filter(Boolean).join(" + "),
|
|
1060
|
-
" ",
|
|
1061
|
-
"captured \u2014 these will be included in the report."
|
|
1062
1097
|
] })
|
|
1063
|
-
] })
|
|
1098
|
+
] }) })
|
|
1064
1099
|
]
|
|
1065
1100
|
}
|
|
1066
1101
|
)
|
|
@@ -1074,8 +1109,10 @@ function JarveBugReporter({
|
|
|
1074
1109
|
apiUrl,
|
|
1075
1110
|
apiKey,
|
|
1076
1111
|
user,
|
|
1112
|
+
buttonPosition,
|
|
1077
1113
|
children
|
|
1078
1114
|
}) {
|
|
1115
|
+
const safeApiKey = apiKey || "";
|
|
1079
1116
|
const [captureMode, setCaptureMode] = (0, import_react3.useState)(false);
|
|
1080
1117
|
const [captureResult, setCaptureResult] = (0, import_react3.useState)(null);
|
|
1081
1118
|
const [showModal, setShowModal] = (0, import_react3.useState)(false);
|
|
@@ -1104,12 +1141,19 @@ function JarveBugReporter({
|
|
|
1104
1141
|
clearCapturedErrors();
|
|
1105
1142
|
clearCapturedNetworkErrors();
|
|
1106
1143
|
}, []);
|
|
1107
|
-
const siteId =
|
|
1144
|
+
const siteId = safeApiKey.startsWith("brk_") ? safeApiKey.slice(4, 12) : "external";
|
|
1108
1145
|
const reporterName = (user == null ? void 0 : user.name) || "Anonymous";
|
|
1109
1146
|
const reporterEmail = (user == null ? void 0 : user.email) || "unknown@external";
|
|
1110
1147
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1111
1148
|
children,
|
|
1112
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1150
|
+
FloatingButton,
|
|
1151
|
+
{
|
|
1152
|
+
isActive: captureMode,
|
|
1153
|
+
onClick: toggleCaptureMode,
|
|
1154
|
+
position: buttonPosition
|
|
1155
|
+
}
|
|
1156
|
+
),
|
|
1113
1157
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1114
1158
|
CaptureOverlay,
|
|
1115
1159
|
{
|