121 lines
3.5 KiB
TypeScript
121 lines
3.5 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { authFetch, clearToken, getApiBase, getToken } from '../lib/auth'
|
|
|
|
type Profile = {
|
|
username?: string
|
|
}
|
|
|
|
export default function FeedbackPage() {
|
|
const router = useRouter()
|
|
const [profile, setProfile] = useState<Profile | null>(null)
|
|
const [category, setCategory] = useState('bug')
|
|
const [message, setMessage] = useState('')
|
|
const [status, setStatus] = useState<string | null>(null)
|
|
const [submitting, setSubmitting] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (!getToken()) {
|
|
router.push('/login')
|
|
return
|
|
}
|
|
const load = async () => {
|
|
try {
|
|
const baseUrl = getApiBase()
|
|
const response = await authFetch(`${baseUrl}/auth/me`)
|
|
if (!response.ok) {
|
|
clearToken()
|
|
router.push('/login')
|
|
return
|
|
}
|
|
const data = await response.json()
|
|
setProfile({ username: data?.username })
|
|
} catch (error) {
|
|
console.error(error)
|
|
}
|
|
}
|
|
void load()
|
|
}, [router])
|
|
|
|
const submit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault()
|
|
setStatus(null)
|
|
if (!message.trim()) {
|
|
setStatus('Please write a short message before sending.')
|
|
return
|
|
}
|
|
setSubmitting(true)
|
|
try {
|
|
const baseUrl = getApiBase()
|
|
const response = await authFetch(`${baseUrl}/feedback`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
type: category,
|
|
message: message.trim(),
|
|
}),
|
|
})
|
|
if (!response.ok) {
|
|
if (response.status === 401) {
|
|
clearToken()
|
|
router.push('/login')
|
|
return
|
|
}
|
|
const text = await response.text()
|
|
throw new Error(text || `Request failed: ${response.status}`)
|
|
}
|
|
setMessage('')
|
|
setStatus('Thanks! Your message has been sent.')
|
|
} catch (error) {
|
|
console.error(error)
|
|
setStatus('That did not send. Please try again.')
|
|
} finally {
|
|
setSubmitting(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main className="card">
|
|
<header className="how-hero">
|
|
<p className="eyebrow">Send feedback</p>
|
|
<h1>Help us improve Magent</h1>
|
|
<p className="lede">
|
|
Found a problem or have an idea? Send it here and we will see it right away.
|
|
</p>
|
|
</header>
|
|
|
|
<form className="auth-form" onSubmit={submit}>
|
|
<label htmlFor="feedback-user">Your username</label>
|
|
<input id="feedback-user" value={profile?.username ?? ''} readOnly />
|
|
|
|
<label htmlFor="feedback-type">What is this about?</label>
|
|
<select
|
|
id="feedback-type"
|
|
value={category}
|
|
onChange={(event) => setCategory(event.target.value)}
|
|
>
|
|
<option value="bug">Bug (something is broken)</option>
|
|
<option value="feature">Feature idea (new option)</option>
|
|
</select>
|
|
|
|
<label htmlFor="feedback-message">Tell us what happened</label>
|
|
<textarea
|
|
id="feedback-message"
|
|
rows={6}
|
|
value={message}
|
|
onChange={(event) => setMessage(event.target.value)}
|
|
placeholder="Write the details here..."
|
|
/>
|
|
|
|
{status && <div className="status-banner">{status}</div>}
|
|
|
|
<button type="submit" disabled={submitting}>
|
|
{submitting ? 'Sending...' : 'Send feedback'}
|
|
</button>
|
|
</form>
|
|
</main>
|
|
)
|
|
}
|