893de0a2c330

feat: wire feedback form to Web3Forms (temporary, pre-Vesper) (v3.6.62)

time
2026-05-20 11:18 UTC · 5 months ago
machine
koh2
parent
a0f34330d095
3 files manifest.firefox.json+1 −1manifest.json+1 −1src/popup/views/Settings.tsx+41 −35
manifest.firefox.json+1 −1
@@ -2,7 +2,7 @@22   "_comment_audio_capture": "Firefox does not honor the Chrome 'audioCapture' optional_permission — getUserMedia in WebExtensions is gated solely by the runtime permission prompt. Microphone access for chirp pairing works from the popup under the existing '<all_urls>' host permission; no manifest entry is required or accepted here.",33   "manifest_version": 3,44   "name": "Peach",5-  "version": "3.6.61",5+  "version": "3.6.62",66   "description": "Zero-knowledge password manager",77   "browser_specific_settings": {88     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "3.6.61",4+  "version": "3.6.62",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

src/popup/views/Settings.tsx+41 −35
@@ -1,4 +1,4 @@1-import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js";1+import { createEffect, createMemo, createSignal, For, Match, onMount, Show, Switch } from "solid-js";22 import { sendMessage } from "../App";33 import { PeachMark } from "../components/PeachMark";44 import { StackDeck } from "../components/settings/StackDeck";@@ -22,6 +22,7 @@2222   type ShortcutAction,2323 } from "../../shared/shortcuts";2424 import { isNativePlatform, nativePlugin } from "../../shared/native";25+import { WEB3FORMS_KEY } from "../../shared/config";2526 2627 interface LicenseInfo {2728   valid: boolean;@@ -285,8 +286,8 @@285286 286287   const [fbCategory, setFbCategory] = createSignal("Bug report");287288   const [fbMessage, setFbMessage] = createSignal("");288-  const [fbSubmitting, setFbSubmitting] = createSignal(false);289-  const [fbResult, setFbResult] = createSignal<"success" | "error" | null>(null);289+  type FeedbackState = 'idle' | 'sending' | 'sent' | 'error';290+  const [feedbackState, setFeedbackState] = createSignal<FeedbackState>('idle');290291 291292   createEffect(() => {292293     if (props.upgradeHighlight) {@@ -576,25 +577,36 @@576577   }577578 578579   async function handleSubmitFeedback() {579-    if (!fbMessage().trim() || fbSubmitting()) return;580-    setFbSubmitting(true);581-    setFbResult(null);582-    const res = await sendMessage({583-      type: "SUBMIT_FEEDBACK",584-      payload: {585-        category: fbCategory(),586-        message: fbMessage().trim(),587-        version,588-        browser: navigator.userAgent,589-      },590-    }) as { ok: boolean; error?: string };591-    setFbSubmitting(false);592-    if (res.ok) {593-      setFbResult("success");594-      setFbMessage("");595-      setTimeout(() => setFbResult(null), 4000);596-    } else {597-      setFbResult("error");580+    if (!fbMessage().trim()) return;581+582+    setFeedbackState('sending');583+584+    try {585+      const res = await fetch('https://api.web3forms.com/submit', {586+        method: 'POST',587+        headers: { 'Content-Type': 'application/json' },588+        body: JSON.stringify({589+          access_key: WEB3FORMS_KEY,590+          subject: `Peach Feedback — ${fbCategory()}`,591+          message: fbMessage(),592+          from_name: 'Peach User',593+          // Honeypot — leave blank594+          botcheck: '',595+        }),596+      });597+598+      if (!res.ok) throw new Error(`HTTP ${res.status}`);599+      const data = await res.json() as { success: boolean; message?: string };600+      if (!data.success) throw new Error(data.message ?? 'unknown error');601+602+      setFeedbackState('sent');603+      setFbMessage('');604+      setFbCategory(FEEDBACK_CATEGORIES[0]);605+      setTimeout(() => setFeedbackState('idle'), 4000);606+    } catch (err) {607+      console.error('[feedback]', err);608+      setFeedbackState('error');609+      setTimeout(() => setFeedbackState('idle'), 4000);598610     }599611   }600612 @@ -1707,23 +1719,17 @@17071719             Version {version} · will be included automatically17081720           </p>17091721 1710-          <Show when={fbResult() === "success"}>1711-            <p class="peach-feedback-result peach-feedback-result--ok">1712-              Sent — thank you1713-            </p>1714-          </Show>1715-          <Show when={fbResult() === "error"}>1716-            <p class="peach-feedback-result peach-feedback-result--err">1717-              Failed to send — try again1718-            </p>1719-          </Show>1720-17211722           <button17221723             class="peach-btn peach-btn--accent peach-btn--sm peach-feedback-submit"1724+            disabled={!fbMessage().trim() || feedbackState() === 'sending'}17231725             onClick={() => void handleSubmitFeedback()}1724-            disabled={fbSubmitting() || !fbMessage().trim()}17251726           >1726-            {fbSubmitting() ? "Sending..." : "Send feedback"}1727+            <Switch>1728+              <Match when={feedbackState() === 'idle'}>Send</Match>1729+              <Match when={feedbackState() === 'sending'}>Sending…</Match>1730+              <Match when={feedbackState() === 'sent'}>Sent ✓</Match>1731+              <Match when={feedbackState() === 'error'}>Failed — try again</Match>1732+            </Switch>17271733           </button>17281734 17291735           <p class="peach-feedback-anon">

view file