@xk2800/nextjs-template 0.8.0-beta.3 → 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 [open, setOpen] = useState(false)
33
- const [type, setType] = useState<FeedbackType>("feedback")
34
- const [message, setMessage] = useState("")
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
- <DialogTrigger asChild>
62
- <Button variant="ghost" size="sm">
63
- <MessageSquare />
64
- Feedback
65
- </Button>
66
- </DialogTrigger>
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>
@@ -0,0 +1,9 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ declare function POST(request: NextRequest): Promise<NextResponse<{
4
+ error: string;
5
+ }> | NextResponse<{
6
+ success: boolean;
7
+ }>>;
8
+
9
+ export { POST };
@@ -0,0 +1,9 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ declare function POST(request: NextRequest): Promise<NextResponse<{
4
+ error: string;
5
+ }> | NextResponse<{
6
+ success: boolean;
7
+ }>>;
8
+
9
+ export { POST };