Files
Newbie_CRM/src/components/shared/bug-report-modal.tsx
T
Rene a02f013f38
Build & Auto-Repair / build (push) Has been cancelled
Replace native selects with shadcn Select across all pages
- lead-scoring-settings.tsx: Feature type dropdown
- bug-report-modal.tsx: Severity dropdown
- client-portal/support/page.tsx: Severity dropdown
- time-tracking/page.tsx: Timer project + manual entry project dropdowns
- proposals/new/page.tsx: Lead + customer dropdowns
2026-07-01 15:39:00 +02:00

197 lines
7.6 KiB
TypeScript

"use client"
import { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { X, Bug, Loader2, CheckCircle } from "lucide-react"
interface BugReportModalProps {
open: boolean
onClose: () => void
}
export function BugReportModal({ open, onClose }: BugReportModalProps) {
const [title, setTitle] = useState("")
const [description, setDescription] = useState("")
const [severity, setSeverity] = useState("medium")
const [loading, setLoading] = useState(false)
const [submitted, setSubmitted] = useState(false)
const [error, setError] = useState("")
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError("")
setLoading(true)
try {
const res = await fetch("/api/bug-reports", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title,
description,
severity,
page_url: window.location.href,
}),
})
if (res.ok) {
setSubmitted(true)
setTitle("")
setDescription("")
setSeverity("medium")
} else {
const data = await res.json().catch(() => ({}))
setError(data.error || "Failed to submit bug report.")
}
} catch {
setError("Connection error. Please try again.")
} finally {
setLoading(false)
}
}
const handleClose = () => {
setSubmitted(false)
setError("")
onClose()
}
return (
<AnimatePresence>
{open && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
onClick={handleClose}
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 10 }}
className="relative w-full max-w-md rounded-xl border bg-white dark:bg-[#141414] p-6 shadow-2xl"
>
<button
onClick={handleClose}
className="absolute right-4 top-4 text-[#8A9078] hover:text-[#2D3020] dark:hover:text-white transition-colors"
>
<X className="h-5 w-5" />
</button>
{submitted ? (
<div className="flex flex-col items-center py-8 text-center">
<CheckCircle className="h-12 w-12 text-emerald-500 mb-4" />
<h3 className="text-lg font-semibold text-[#2D3020] dark:text-white mb-2">
Bug Report Submitted
</h3>
<p className="text-sm text-[#8A9078] dark:text-[#AAAAAA]">
Thank you for your report. The development team will investigate.
</p>
<button
onClick={handleClose}
className="mt-6 rounded-lg bg-[#C84B4B] px-6 py-2 text-sm font-medium text-white hover:bg-[#C84B4B]/80 transition-colors"
>
Done
</button>
</div>
) : (
<>
<div className="flex items-center gap-3 mb-6">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-[#FAEAEA] dark:bg-red-900/30">
<Bug className="h-5 w-5 text-[#C84B4B]" />
</div>
<div>
<h3 className="text-lg font-semibold text-[#2D3020] dark:text-white">
Report a Bug
</h3>
<p className="text-xs text-[#8A9078] dark:text-[#AAAAAA]">
Help us improve the system
</p>
</div>
</div>
{error && (
<div className="mb-4 rounded-lg bg-red-500/10 px-4 py-2 text-sm text-red-500">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="mb-1.5 block text-sm font-medium text-[#8A9078] dark:text-[#CCCCCC]">
Title <span className="text-[#C84B4B]">*</span>
</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Brief description of the issue"
required
className="w-full rounded-lg border border-[#D4D8CC] dark:border-[#333333] bg-white dark:bg-[#1E1E1E] px-3 py-2 text-sm text-[#2D3020] dark:text-white placeholder-[#8A9078] focus:border-[#C84B4B] focus:outline-none focus:ring-1 focus:ring-[#C84B4B]"
/>
</div>
<div>
<label className="mb-1.5 block text-sm font-medium text-[#8A9078] dark:text-[#CCCCCC]">
Description <span className="text-[#C84B4B]">*</span>
</label>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="What happened? What did you expect?"
rows={4}
required
className="w-full resize-none rounded-lg border border-[#D4D8CC] dark:border-[#333333] bg-white dark:bg-[#1E1E1E] px-3 py-2 text-sm text-[#2D3020] dark:text-white placeholder-[#8A9078] focus:border-[#C84B4B] focus:outline-none focus:ring-1 focus:ring-[#C84B4B]"
/>
</div>
<div>
<label className="mb-1.5 block text-sm font-medium text-[#8A9078] dark:text-[#CCCCCC]">
Severity
</label>
<Select value={severity} onValueChange={setSeverity}>
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low Minor cosmetic issue</SelectItem>
<SelectItem value="medium">Medium Affects functionality</SelectItem>
<SelectItem value="high">High Major feature broken</SelectItem>
<SelectItem value="critical">Critical System is blocked</SelectItem>
</SelectContent>
</Select>
</div>
<div className="rounded-lg bg-[#FAFAF6] dark:bg-[#1A1A1A] px-3 py-2">
<p className="text-xs text-[#8A9078]">
<span className="font-medium">Page:</span> {typeof window !== "undefined" ? window.location.href : ""}
</p>
</div>
<button
type="submit"
disabled={loading}
className="flex w-full items-center justify-center gap-2 rounded-lg bg-[#C84B4B] px-4 py-2.5 text-sm font-medium text-white hover:bg-[#C84B4B]/80 disabled:opacity-50 transition-colors"
>
{loading && <Loader2 className="h-4 w-4 animate-spin" />}
{loading ? "Submitting..." : "Submit Bug Report"}
</button>
</form>
</>
)}
</motion.div>
</div>
)}
</AnimatePresence>
)
}