feat(web): TODO-002 feedback form in settings page via @bytelyst/feedback-client
This commit is contained in:
parent
8bddbec43c
commit
0242ca85ff
@ -2,7 +2,8 @@
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { ArrowLeft, Volume2, Bell, Palette, Trash2, Minimize2, User, LogOut } from 'lucide-react';
|
||||
import { ArrowLeft, Volume2, Bell, Palette, Trash2, Minimize2, User, LogOut, MessageSquarePlus } from 'lucide-react';
|
||||
import { feedbackClient } from '@/lib/feedback';
|
||||
import { URGENCY_ORDER, getUrgencyConfig } from '@/lib/urgency';
|
||||
import { previewSound } from '@/lib/sounds';
|
||||
import { getNotificationPermission, requestNotificationPermission } from '@/lib/notifications';
|
||||
@ -33,6 +34,10 @@ export default function SettingsPage() {
|
||||
const [showChangePw, setShowChangePw] = useState(false);
|
||||
const [showDeleteAccount, setShowDeleteAccount] = useState(false);
|
||||
const [deleteConfirmPw, setDeleteConfirmPw] = useState('');
|
||||
const [feedbackType, setFeedbackType] = useState<'bug' | 'feature' | 'praise'>('feature');
|
||||
const [feedbackText, setFeedbackText] = useState('');
|
||||
const [feedbackSubmitting, setFeedbackSubmitting] = useState(false);
|
||||
const [feedbackSuccess, setFeedbackSuccess] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
@ -489,6 +494,74 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Feedback */}
|
||||
<section className="mb-8">
|
||||
<h2 className="flex items-center gap-2 text-base font-semibold mb-4" style={{ color: 'var(--cm-text-primary)' }}>
|
||||
<MessageSquarePlus size={18} /> Feedback
|
||||
</h2>
|
||||
<div
|
||||
className="rounded-xl border p-4"
|
||||
style={{ backgroundColor: 'var(--cm-surface-card)', borderColor: 'var(--cm-border)' }}
|
||||
>
|
||||
{feedbackSuccess ? (
|
||||
<p className="text-sm font-medium" style={{ color: 'var(--cm-gentle)' }}>
|
||||
Thank you for your feedback!
|
||||
</p>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<div className="flex gap-2">
|
||||
{(['feature', 'bug', 'praise'] as const).map((t) => (
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setFeedbackType(t)}
|
||||
aria-label={`Feedback type: ${t}`}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer"
|
||||
style={{
|
||||
backgroundColor: feedbackType === t ? 'var(--cm-accent)' : 'var(--cm-surface-muted)',
|
||||
color: feedbackType === t ? 'var(--cm-white)' : 'var(--cm-text-secondary)',
|
||||
}}
|
||||
>
|
||||
{t === 'feature' ? 'Feature Request' : t === 'bug' ? 'Bug Report' : 'Praise'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<textarea
|
||||
value={feedbackText}
|
||||
onChange={(e) => setFeedbackText(e.target.value)}
|
||||
placeholder="Tell us what you think..."
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 rounded-lg text-sm outline-none resize-none"
|
||||
style={{
|
||||
backgroundColor: 'var(--cm-surface-muted)',
|
||||
color: 'var(--cm-text-primary)',
|
||||
border: '1px solid var(--cm-border)',
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (!feedbackText.trim()) return;
|
||||
setFeedbackSubmitting(true);
|
||||
try {
|
||||
await feedbackClient.submitWithScreenshot({ type: feedbackType, title: feedbackText.trim().slice(0, 100), body: feedbackText.trim(), platform: 'web' });
|
||||
setFeedbackSuccess(true);
|
||||
setFeedbackText('');
|
||||
setTimeout(() => setFeedbackSuccess(false), 4000);
|
||||
} catch {
|
||||
// fail silently — feedback is best-effort
|
||||
}
|
||||
setFeedbackSubmitting(false);
|
||||
}}
|
||||
disabled={feedbackSubmitting || !feedbackText.trim()}
|
||||
className="w-full px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-40"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
{feedbackSubmitting ? 'Sending...' : 'Send Feedback'}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* About */}
|
||||
<section>
|
||||
<div
|
||||
|
||||
Loading…
Reference in New Issue
Block a user