diff --git a/frontend/components/dashboard/scan-terminal/UserFeedbackModal.tsx b/frontend/components/dashboard/scan-terminal/UserFeedbackModal.tsx index 642d90dc..d85473b1 100644 --- a/frontend/components/dashboard/scan-terminal/UserFeedbackModal.tsx +++ b/frontend/components/dashboard/scan-terminal/UserFeedbackModal.tsx @@ -7,6 +7,10 @@ import { getAnalyticsClientId, getAnalyticsSessionId, } from "@/lib/app-analytics"; +import { + getSupabaseBrowserClient, + hasSupabasePublicEnv, +} from "@/lib/supabase/client"; import type { UserFeedbackEntry } from "@/types/ops"; export type FeedbackCategory = "bug" | "data" | "idea" | "payment" | "account" | "other"; @@ -60,6 +64,7 @@ export function UserFeedbackModal({ const [category, setCategory] = useState("bug"); const [message, setMessage] = useState(""); const [contact, setContact] = useState(""); + const [loginEmailContact, setLoginEmailContact] = useState(""); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(""); const [submitted, setSubmitted] = useState(false); @@ -68,10 +73,36 @@ export function UserFeedbackModal({ if (!open) return; setCategory(draft?.category || "bug"); setMessage(""); + setContact(""); + setLoginEmailContact(""); setError(""); setSubmitted(false); }, [open, draft?.category]); + useEffect(() => { + if (!open || !hasSupabasePublicEnv()) return; + let cancelled = false; + + const loadLoginEmail = async () => { + try { + const { + data: { session }, + } = await getSupabaseBrowserClient().auth.getSession(); + const email = String(session?.user?.email || "").trim(); + if (cancelled || !email) return; + setLoginEmailContact(email); + setContact(email); + } catch { + // Feedback can still be submitted; the backend will attach auth email when present. + } + }; + + void loadLoginEmail(); + return () => { + cancelled = true; + }; + }, [open]); + const contextPreview = useMemo(() => { const context = draft?.context || {}; const city = String(context.city || context.display_city || "").trim(); @@ -197,12 +228,20 @@ export function UserFeedbackModal({ diff --git a/frontend/components/dashboard/scan-terminal/__tests__/feedbackWorkflow.test.ts b/frontend/components/dashboard/scan-terminal/__tests__/feedbackWorkflow.test.ts index 4a73f3d6..616f3824 100644 --- a/frontend/components/dashboard/scan-terminal/__tests__/feedbackWorkflow.test.ts +++ b/frontend/components/dashboard/scan-terminal/__tests__/feedbackWorkflow.test.ts @@ -48,10 +48,14 @@ export function runTests() { assert( modalSource.includes("/api/feedback") && modalSource.includes("getAnalyticsClientId") && + modalSource.includes("getSupabaseBrowserClient") && + modalSource.includes("hasSupabasePublicEnv") && + modalSource.includes(".auth.getSession()") && + modalSource.includes("readOnly={Boolean(loginEmailContact)}") && modalSource.includes("onSubmitted") && modalSource.includes("navigator.userAgent") && modalSource.includes("type=\"textarea\"") === false, - "feedback modal must submit to the feedback API, notify the dashboard after success, and attach client/session diagnostics without using invalid textarea input types", + "feedback modal must submit to the feedback API, lock contact to the login email when available, notify the dashboard after success, and attach client/session diagnostics without using invalid textarea input types", ); assert( feedbackRouteSource.includes("export async function GET") &&