a02f013f38
Build & Auto-Repair / build (push) Has been cancelled
- 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
197 lines
7.6 KiB
TypeScript
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>
|
|
)
|
|
}
|