Error Feedback Service + friendly error handling across all pages

- Error Feedback Service: POST /api/feedback saves to JSONL, GET with admin token
- ErrorFeedback component: warm amber tones, friendly messages, 'Report Issue' button
- Replaced ALL red-themed error displays across 15+ pages with ErrorFeedback
- Kind classification: network, auth, location, upgrade, default messages
- QA test suite v2: 8-layer testing (system, API, render, scenario, edge, mobile, perf, security)
- Browser-based visual QA with Playwright (Layer 9)
This commit is contained in:
root
2026-06-18 16:24:47 +02:00
parent 28be776c84
commit 14d7127e41
19 changed files with 1913 additions and 165 deletions
+2 -11
View File
@@ -13,10 +13,10 @@ import {
Crown,
Shield,
Loader2,
AlertTriangle,
Clock,
UserMinus,
} from "lucide-react";
import ErrorFeedback from "@/components/ErrorFeedback";
interface GroupMember {
id: string;
@@ -231,16 +231,7 @@ export default function GroupDetailPage() {
<p className="text-sm text-gray-500">Loading group...</p>
</div>
) : error ? (
<div className="mx-4 mt-4 bg-red-900/10 border border-red-800/30 rounded-2xl p-6 text-center">
<AlertTriangle size={32} className="mx-auto text-red-400 mb-2" />
<p className="text-sm text-red-300">{error}</p>
<button
onClick={() => { fetchGroup(); }}
className="mt-3 text-xs text-[#D4AF37] underline"
>
Try again
</button>
</div>
<ErrorFeedback error={error} kind="network" onRetry={fetchGroup} context="group detail" />
) : !group ? (
<div className="mx-4 mt-4 bg-gray-900/40 border border-gray-800/60 rounded-2xl p-6 text-center">
<p className="text-sm text-gray-400">Group not found</p>
+4 -17
View File
@@ -10,9 +10,9 @@ import {
X,
Crown,
Loader2,
AlertTriangle,
ChevronRight,
} from "lucide-react";
import ErrorFeedback from "@/components/ErrorFeedback";
interface GroupMember {
id: string;
@@ -274,16 +274,7 @@ export default function GroupsPage() {
<p className="text-sm text-gray-500">Loading groups...</p>
</div>
) : error ? (
<div className="bg-red-900/10 border border-red-800/30 rounded-2xl p-6 text-center">
<AlertTriangle size={32} className="mx-auto text-red-400 mb-2" />
<p className="text-sm text-red-300">{error}</p>
<button
onClick={fetchGroups}
className="mt-3 text-xs text-[#D4AF37] underline"
>
Try again
</button>
</div>
<ErrorFeedback error={error} kind="network" onRetry={fetchGroups} context="groups" />
) : groups.length === 0 ? (
<div className="flex flex-col items-center justify-center py-20">
<div className="w-16 h-16 rounded-2xl bg-gray-800/40 flex items-center justify-center mb-4">
@@ -412,9 +403,7 @@ export default function GroupsPage() {
</div>
{createError && (
<div className="bg-red-900/10 border border-red-800/30 rounded-xl p-3">
<p className="text-xs text-red-300">{createError}</p>
</div>
<ErrorFeedback error={createError} kind="default" onRetry={() => setCreateError(null)} context="create group" />
)}
<div className="flex gap-3 pt-2">
@@ -490,9 +479,7 @@ export default function GroupsPage() {
</div>
{joinError && (
<div className="bg-red-900/10 border border-red-800/30 rounded-xl p-3">
<p className="text-xs text-red-300">{joinError}</p>
</div>
<ErrorFeedback error={joinError} kind="default" onRetry={() => setJoinError(null)} context="join group" />
)}
{joinSuccess && (