@xk2800/nextjs-template 0.8.0-beta.4 → 0.8.0-beta.5
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.
|
@@ -22,18 +22,52 @@ const FEEDBACK_MAX_LENGTH = 2000
|
|
|
22
22
|
|
|
23
23
|
type FeedbackType = "bug" | "feedback"
|
|
24
24
|
|
|
25
|
+
export type FeedbackDialogProps = {
|
|
26
|
+
/** Control the dialog from outside (e.g. a "Report" button on an error). */
|
|
27
|
+
open?: boolean
|
|
28
|
+
onOpenChange?: (open: boolean) => void
|
|
29
|
+
/** Pre-filled each time the dialog opens, e.g. the error the user just hit. */
|
|
30
|
+
defaultType?: FeedbackType
|
|
31
|
+
defaultMessage?: string
|
|
32
|
+
/** Render the "Feedback" header button. Default `true`. */
|
|
33
|
+
showTrigger?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
/**
|
|
26
37
|
* Header button + dialog that POSTs to /api/feedback. Render it only when a
|
|
27
38
|
* feedback channel is configured (FEEDBACK_DISCORD_WEBHOOK_URL or
|
|
28
39
|
* FEEDBACK_EMAIL); otherwise the route answers 503.
|
|
29
40
|
*/
|
|
30
|
-
export default function FeedbackDialog(
|
|
41
|
+
export default function FeedbackDialog({
|
|
42
|
+
open: openProp,
|
|
43
|
+
onOpenChange,
|
|
44
|
+
defaultType = "feedback",
|
|
45
|
+
defaultMessage = "",
|
|
46
|
+
showTrigger = true,
|
|
47
|
+
}: FeedbackDialogProps = {}) {
|
|
31
48
|
const pathname = usePathname()
|
|
32
|
-
const [
|
|
33
|
-
const
|
|
34
|
-
const
|
|
49
|
+
const [openState, setOpenState] = useState(false)
|
|
50
|
+
const open = openProp ?? openState
|
|
51
|
+
const setOpen = (next: boolean) => {
|
|
52
|
+
setOpenState(next)
|
|
53
|
+
onOpenChange?.(next)
|
|
54
|
+
}
|
|
55
|
+
const [type, setType] = useState<FeedbackType>(defaultType)
|
|
56
|
+
const [message, setMessage] = useState(defaultMessage)
|
|
35
57
|
const [isSending, setIsSending] = useState(false)
|
|
36
58
|
|
|
59
|
+
// With a pre-filled message, re-apply it every time the dialog opens so a
|
|
60
|
+
// second error report doesn't start from the first one's text. Without one,
|
|
61
|
+
// keep whatever the user had typed (a closed dialog keeps its draft).
|
|
62
|
+
const [wasOpen, setWasOpen] = useState(open)
|
|
63
|
+
if (open !== wasOpen) {
|
|
64
|
+
setWasOpen(open)
|
|
65
|
+
if (open && defaultMessage) {
|
|
66
|
+
setType(defaultType)
|
|
67
|
+
setMessage(defaultMessage)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
37
71
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
38
72
|
e.preventDefault()
|
|
39
73
|
setIsSending(true)
|
|
@@ -58,12 +92,14 @@ export default function FeedbackDialog() {
|
|
|
58
92
|
|
|
59
93
|
return (
|
|
60
94
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
95
|
+
{showTrigger && (
|
|
96
|
+
<DialogTrigger asChild>
|
|
97
|
+
<Button variant="ghost" size="sm">
|
|
98
|
+
<MessageSquare />
|
|
99
|
+
Feedback
|
|
100
|
+
</Button>
|
|
101
|
+
</DialogTrigger>
|
|
102
|
+
)}
|
|
67
103
|
<DialogContent>
|
|
68
104
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
69
105
|
<DialogHeader>
|