Simpl-Resultat/src/components/settings/FeedbackConsentDialog.tsx
maximus 4f4ab87bea feat: feedback hub widget in Settings Logs card (#67)
Closes #67

Add opt-in Feedback Hub widget integrated into the Settings Logs card. Routes through a Rust command to bypass CORS and centralize privacy audit. First submission triggers a one-time consent dialog; three opt-in checkboxes (context, logs, identify with Maximus account) all unchecked by default. Wording and payload follow the cross-app conventions in la-compagnie-maximus/docs/feedback-hub-ops.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:36:26 +00:00

67 lines
2.3 KiB
TypeScript

import { useEffect } from "react";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { X, Globe } from "lucide-react";
interface FeedbackConsentDialogProps {
onAccept: () => void;
onCancel: () => void;
}
export default function FeedbackConsentDialog({
onAccept,
onCancel,
}: FeedbackConsentDialogProps) {
const { t } = useTranslation();
useEffect(() => {
function handleEscape(e: KeyboardEvent) {
if (e.key === "Escape") onCancel();
}
document.addEventListener("keydown", handleEscape);
return () => document.removeEventListener("keydown", handleEscape);
}, [onCancel]);
return createPortal(
<div
className="fixed inset-0 z-[210] flex items-center justify-center bg-black/50"
onClick={(e) => {
if (e.target === e.currentTarget) onCancel();
}}
>
<div className="bg-[var(--card)] rounded-xl border border-[var(--border)] shadow-2xl w-full max-w-md mx-4">
<div className="flex items-center justify-between px-6 py-4 border-b border-[var(--border)]">
<h2 className="text-lg font-semibold flex items-center gap-2">
<Globe size={18} />
{t("feedback.consent.title")}
</h2>
<button
onClick={onCancel}
className="text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
aria-label={t("feedback.dialog.cancel")}
>
<X size={18} />
</button>
</div>
<div className="px-6 py-4 space-y-3 text-sm text-[var(--muted-foreground)]">
<p>{t("feedback.consent.body")}</p>
</div>
<div className="flex justify-end gap-2 px-6 py-4 border-t border-[var(--border)]">
<button
onClick={onCancel}
className="px-4 py-2 text-sm border border-[var(--border)] rounded-lg hover:bg-[var(--border)] transition-colors"
>
{t("feedback.dialog.cancel")}
</button>
<button
onClick={onAccept}
className="px-4 py-2 text-sm bg-[var(--primary)] text-[var(--primary-foreground)] rounded-lg hover:opacity-90 transition-opacity"
>
{t("feedback.consent.accept")}
</button>
</div>
</div>
</div>,
document.body,
);
}