mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
feature: new dashboard workos auth for dashboard login, dashboard optional in site config, sync server for dashboard, workos and dashboard docs updated
This commit is contained in:
@@ -13,6 +13,7 @@ interface ContactFormProps {
|
||||
// Contact form component
|
||||
// Displays a form with name, email, and message fields
|
||||
// Submits to Convex which sends email via AgentMail
|
||||
// Includes honeypot field for bot protection
|
||||
export default function ContactForm({
|
||||
source,
|
||||
title,
|
||||
@@ -21,6 +22,7 @@ export default function ContactForm({
|
||||
const [name, setName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [message, setMessage] = useState("");
|
||||
const [honeypot, setHoneypot] = useState(""); // Honeypot field for bot detection
|
||||
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
|
||||
const [statusMessage, setStatusMessage] = useState("");
|
||||
|
||||
@@ -36,6 +38,17 @@ export default function ContactForm({
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Honeypot check: if filled, silently reject (bot detected)
|
||||
if (honeypot) {
|
||||
// Pretend success to not alert the bot
|
||||
setStatus("success");
|
||||
setStatusMessage("Thanks for your message! We'll get back to you soon.");
|
||||
setName("");
|
||||
setEmail("");
|
||||
setMessage("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
if (!name.trim()) {
|
||||
setStatus("error");
|
||||
@@ -103,6 +116,31 @@ export default function ContactForm({
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="contact-form__form">
|
||||
{/* Honeypot field: hidden from humans, visible to bots */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: "-9999px",
|
||||
top: "-9999px",
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
height: 0,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<label htmlFor="contact-website">Website</label>
|
||||
<input
|
||||
id="contact-website"
|
||||
type="text"
|
||||
name="website"
|
||||
tabIndex={-1}
|
||||
autoComplete="off"
|
||||
value={honeypot}
|
||||
onChange={(e) => setHoneypot(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="contact-form__field">
|
||||
<label htmlFor="contact-name" className="contact-form__label">
|
||||
Name
|
||||
|
||||
@@ -14,6 +14,7 @@ interface NewsletterSignupProps {
|
||||
// Newsletter signup component
|
||||
// Displays email input form for newsletter subscriptions
|
||||
// Integrates with Convex backend for subscriber management
|
||||
// Includes honeypot field for bot protection
|
||||
export default function NewsletterSignup({
|
||||
source,
|
||||
postSlug,
|
||||
@@ -21,6 +22,7 @@ export default function NewsletterSignup({
|
||||
description,
|
||||
}: NewsletterSignupProps) {
|
||||
const [email, setEmail] = useState("");
|
||||
const [honeypot, setHoneypot] = useState(""); // Honeypot field for bot detection
|
||||
const [status, setStatus] = useState<
|
||||
"idle" | "loading" | "success" | "error"
|
||||
>("idle");
|
||||
@@ -49,6 +51,15 @@ export default function NewsletterSignup({
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Honeypot check: if filled, silently reject (bot detected)
|
||||
if (honeypot) {
|
||||
// Pretend success to not alert the bot
|
||||
setStatus("success");
|
||||
setMessage("Thanks for subscribing!");
|
||||
setEmail("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!email.trim()) {
|
||||
setStatus("error");
|
||||
setMessage("Please enter your email.");
|
||||
@@ -88,6 +99,31 @@ export default function NewsletterSignup({
|
||||
<p className="newsletter-signup__success">{message}</p>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="newsletter-signup__form">
|
||||
{/* Honeypot field: hidden from humans, visible to bots */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: "-9999px",
|
||||
top: "-9999px",
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
height: 0,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<label htmlFor={`newsletter-fax-${source}`}>Fax</label>
|
||||
<input
|
||||
id={`newsletter-fax-${source}`}
|
||||
type="text"
|
||||
name="fax"
|
||||
tabIndex={-1}
|
||||
autoComplete="off"
|
||||
value={honeypot}
|
||||
onChange={(e) => setHoneypot(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
|
||||
Reference in New Issue
Block a user