Beta: admin assets, resource download forms, and resource page redesign
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
interface ContactFields {
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
message: string
|
||||
messageType: string
|
||||
}
|
||||
|
||||
export default function ContactForm() {
|
||||
const navigate = useNavigate()
|
||||
const [fields, setFields] = useState<ContactFields>({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
email: '',
|
||||
message: '',
|
||||
messageType: 'question',
|
||||
})
|
||||
const [subscribe, setSubscribe] = useState(true)
|
||||
const [honey, setHoney] = useState('')
|
||||
const [status, setStatus] = useState<'idle' | 'submitting' | 'error'>('idle')
|
||||
const [errorMsg, setErrorMsg] = useState('')
|
||||
|
||||
function handleChange(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
|
||||
setFields(f => ({ ...f, [e.target.name]: e.target.value }))
|
||||
}
|
||||
|
||||
function handleSelectChange(e: ChangeEvent<HTMLSelectElement>) {
|
||||
setFields(f => ({ ...f, [e.target.name]: e.target.value }))
|
||||
}
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault()
|
||||
setStatus('submitting')
|
||||
setErrorMsg('')
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...fields, subscribe, _honey: honey }),
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}))
|
||||
setErrorMsg((data as { message?: string }).message ?? 'Something went wrong. Please try again.')
|
||||
setStatus('error')
|
||||
return
|
||||
}
|
||||
|
||||
navigate('/thanks')
|
||||
} catch {
|
||||
setErrorMsg('Could not connect. Please try again later.')
|
||||
setStatus('error')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="contact-form" onSubmit={handleSubmit} noValidate>
|
||||
<input
|
||||
type="text"
|
||||
className="contact-honeypot"
|
||||
tabIndex={-1}
|
||||
autoComplete="off"
|
||||
aria-hidden="true"
|
||||
value={honey}
|
||||
onChange={e => setHoney(e.target.value)}
|
||||
/>
|
||||
<label>
|
||||
First Name
|
||||
<input type="text" name="firstName" required autoComplete="given-name" value={fields.firstName} onChange={handleChange} />
|
||||
</label>
|
||||
<label>
|
||||
Last Name
|
||||
<input type="text" name="lastName" required autoComplete="family-name" value={fields.lastName} onChange={handleChange} />
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input type="email" name="email" required autoComplete="email" value={fields.email} onChange={handleChange} />
|
||||
</label>
|
||||
<label>
|
||||
Message Type
|
||||
<select name="messageType" value={fields.messageType} onChange={handleSelectChange}>
|
||||
<option value="question">Bible Question</option>
|
||||
<option value="testimony">Testimony</option>
|
||||
<option value="topic">Topic Request</option>
|
||||
<option value="general">General Message</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Message
|
||||
<textarea name="message" rows={6} required value={fields.message} onChange={handleChange} />
|
||||
</label>
|
||||
<label className="contact-consent">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={subscribe}
|
||||
onChange={e => setSubscribe(e.target.checked)}
|
||||
/>
|
||||
<span>Send me updates from Verse by Verse with Nate. I can unsubscribe anytime.</span>
|
||||
</label>
|
||||
{status === 'error' && <p className="contact-error">{errorMsg}</p>}
|
||||
<button type="submit" className="btn-primary" disabled={status === 'submitting'}>
|
||||
{status === 'submitting' ? 'Sending…' : 'Send Message'}
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user