feat:更换反馈服务提供商

This commit is contained in:
hzm
2026-02-03 23:48:46 +08:00
parent 652f379f98
commit cb3e15a628
3 changed files with 43 additions and 89 deletions

View File

@@ -2,7 +2,6 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { motion, AnimatePresence, Reorder } from 'framer-motion'; import { motion, AnimatePresence, Reorder } from 'framer-motion';
import { useForm, ValidationError } from '@formspree/react';
import Announcement from "./components/Announcement"; import Announcement from "./components/Announcement";
function PlusIcon(props) { function PlusIcon(props) {
@@ -130,16 +129,42 @@ function Stat({ label, value, delta }) {
} }
function FeedbackModal({ onClose }) { function FeedbackModal({ onClose }) {
const [state, handleSubmit] = useForm("xdadgvjd"); const [submitting, setSubmitting] = useState(false);
const [succeeded, setSucceeded] = useState(false);
const [error, setError] = useState("");
const onSubmit = (e) => { const onSubmit = async (e) => {
const form = e?.target; e.preventDefault();
const nicknameInput = form?.elements?.namedItem?.('nickname'); setSubmitting(true);
if (nicknameInput && typeof nicknameInput.value === 'string') { setError("");
const v = nicknameInput.value.trim();
if (!v) nicknameInput.value = '匿名'; const formData = new FormData(e.target);
const nickname = formData.get("nickname")?.trim();
if (!nickname) {
formData.set("nickname", "匿名");
}
// Web3Forms Access Key
formData.append("access_key", "c390fbb1-77e0-4aab-a939-caa75edc7319");
formData.append("subject", "基估宝 - 用户反馈");
try {
const response = await fetch("https://api.web3forms.com/submit", {
method: "POST",
body: formData
});
const data = await response.json();
if (data.success) {
setSucceeded(true);
} else {
setError(data.message || "提交失败,请稍后再试");
}
} catch (err) {
setError("网络错误,请检查您的连接");
} finally {
setSubmitting(false);
} }
return handleSubmit(e);
}; };
return ( return (
@@ -170,7 +195,7 @@ function FeedbackModal({ onClose }) {
</button> </button>
</div> </div>
{state.succeeded ? ( {succeeded ? (
<div className="success-message" style={{ textAlign: 'center', padding: '20px 0' }}> <div className="success-message" style={{ textAlign: 'center', padding: '20px 0' }}>
<div style={{ fontSize: '48px', marginBottom: 16 }}>🎉</div> <div style={{ fontSize: '48px', marginBottom: 16 }}>🎉</div>
<h3 style={{ marginBottom: 8 }}>感谢您的反馈</h3> <h3 style={{ marginBottom: 8 }}>感谢您的反馈</h3>
@@ -193,7 +218,6 @@ function FeedbackModal({ onClose }) {
placeholder="匿名" placeholder="匿名"
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
<ValidationError prefix="Nickname" field="nickname" errors={state.errors} className="error-text" />
</div> </div>
<div className="form-group" style={{ marginBottom: 20 }}> <div className="form-group" style={{ marginBottom: 20 }}>
@@ -208,11 +232,16 @@ function FeedbackModal({ onClose }) {
placeholder="请描述您遇到的问题或建议..." placeholder="请描述您遇到的问题或建议..."
style={{ width: '100%', minHeight: '120px', padding: '12px', resize: 'vertical' }} style={{ width: '100%', minHeight: '120px', padding: '12px', resize: 'vertical' }}
/> />
<ValidationError prefix="Message" field="message" errors={state.errors} className="error-text" />
</div> </div>
<button className="button" type="submit" disabled={state.submitting} style={{ width: '100%' }}> {error && (
{state.submitting ? '发送中...' : '提交反馈'} <div className="error-text" style={{ marginBottom: 16, textAlign: 'center' }}>
{error}
</div>
)}
<button className="button" type="submit" disabled={submitting} style={{ width: '100%' }}>
{submitting ? '发送中...' : '提交反馈'}
</button> </button>
</form> </form>
)} )}

74
package-lock.json generated
View File

@@ -8,37 +8,12 @@
"name": "real-time-fund", "name": "real-time-fund",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@formspree/react": "^3.0.0",
"framer-motion": "^12.29.2", "framer-motion": "^12.29.2",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1" "react-dom": "18.3.1"
} }
}, },
"node_modules/@formspree/core": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@formspree/core/-/core-4.0.0.tgz",
"integrity": "sha512-geNlUut5nME1Ztej5Pzx1BrlQ1fFIcJYIqmF+Vm0jaUbpZxjXvt7SDOGeQVkuxn80QJiIHlwBGGjSBFjPX/KDw==",
"license": "MIT",
"dependencies": {
"@stripe/stripe-js": "^5.7.0"
}
},
"node_modules/@formspree/react": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@formspree/react/-/react-3.0.0.tgz",
"integrity": "sha512-8PufBZ4l13VmCp9xTGQXwyF6mZtYSecqgTlFuMo5Fbe4Q6zUk7PMU2uKOwIaytZyTyJgFVCvdbpQElPPBKYNLw==",
"license": "MIT",
"dependencies": {
"@formspree/core": "^4.0.0",
"@stripe/react-stripe-js": "^3.1.1",
"@stripe/stripe-js": "^5.7.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0"
}
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "14.2.5", "version": "14.2.5",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz",
@@ -189,29 +164,6 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/@stripe/react-stripe-js": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-3.10.0.tgz",
"integrity": "sha512-UPqHZwMwDzGSax0ZI7XlxR3tZSpgIiZdk3CiwjbTK978phwR/fFXeAXQcN/h8wTAjR4ZIAzdlI9DbOqJhuJdeg==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.7.2"
},
"peerDependencies": {
"@stripe/stripe-js": ">=1.44.1 <8.0.0",
"react": ">=16.8.0 <20.0.0",
"react-dom": ">=16.8.0 <20.0.0"
}
},
"node_modules/@stripe/stripe-js": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-5.10.0.tgz",
"integrity": "sha512-PTigkxMdMUP6B5ISS7jMqJAKhgrhZwjprDqR1eATtFfh0OpKVNp110xiH+goeVdrJ29/4LeZJR4FaHHWstsu0A==",
"license": "MIT",
"engines": {
"node": ">=12.16"
}
},
"node_modules/@swc/counter": { "node_modules/@swc/counter": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
@@ -400,15 +352,6 @@
} }
} }
}, },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -443,17 +386,6 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/react": { "node_modules/react": {
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -479,12 +411,6 @@
"react": "^18.3.1" "react": "^18.3.1"
} }
}, },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.23.2", "version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",

View File

@@ -8,7 +8,6 @@
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"@formspree/react": "^3.0.0",
"framer-motion": "^12.29.2", "framer-motion": "^12.29.2",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",