diff --git a/src/app/dashboard/outcome-reviews/page.tsx b/src/app/dashboard/outcome-reviews/page.tsx new file mode 100644 index 0000000..aacb34c --- /dev/null +++ b/src/app/dashboard/outcome-reviews/page.tsx @@ -0,0 +1,190 @@ +'use client'; + +import { useState } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { apiFetch } from '../../../lib/api'; +import { useSession } from '../../../components/session-provider'; + +interface Decision { id: string; context: string; selectedOption: string | null; } +interface OutcomeReview { + id: string; title: string; decisionId: string | null; + periodStart: string | null; periodEnd: string | null; + actualOutcome: string | null; wasSuccessful: boolean | null; + lessonsLearned: string | null; nextSteps: string | null; + rating: number | null; createdAt: string; +} + +const STARS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +function RatingDisplay({ rating }: { rating: number | null }) { + if (!rating) return ; + const cls = rating >= 8 ? 'text-signal-ok' : rating >= 5 ? 'text-signal-warn' : 'text-signal-danger'; + return {rating}/10; +} + +export default function OutcomeReviewsPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + + const [showCreate, setShowCreate] = useState(false); + const [form, setForm] = useState({ + title: '', decisionId: '', periodStart: '', periodEnd: '', + actualOutcome: '', wasSuccessful: '', lessonsLearned: '', nextSteps: '', rating: '', + }); + const [expandedId, setExpandedId] = useState(null); + + const { data: reviews = [], isLoading } = useQuery({ + queryKey: ['outcome-reviews', tenantId], + queryFn: () => apiFetch('/v1/outcome-reviews', { tenantId }), + enabled: Boolean(tenantId), staleTime: 30_000, + }); + + const { data: decisions = [] } = useQuery({ + queryKey: ['dec-or', tenantId], + queryFn: () => apiFetch('/v1/decisions?limit=50', { tenantId }), + enabled: Boolean(tenantId), staleTime: 120_000, + }); + + const createMut = useMutation({ + mutationFn: (body: Record) => + apiFetch('/v1/outcome-reviews', { tenantId, method: 'POST', body }), + onSuccess: () => { + qc.invalidateQueries({ queryKey: ['outcome-reviews', tenantId] }); + setShowCreate(false); + setForm({ title: '', decisionId: '', periodStart: '', periodEnd: '', actualOutcome: '', wasSuccessful: '', lessonsLearned: '', nextSteps: '', rating: '' }); + }, + }); + + const successCount = reviews.filter((r) => r.wasSuccessful === true).length; + const failCount = reviews.filter((r) => r.wasSuccessful === false).length; + const avgRating = reviews.filter((r) => r.rating).reduce((s, r) => s + (r.rating ?? 0), 0) / (reviews.filter((r) => r.rating).length || 1); + + return ( +
+
+
+

Revizuiri Rezultate

+

+ {isLoading ? 'Se încarcă…' : `${reviews.length} revizuiri · ${successCount} ✓ · ${failCount} ✗${avgRating > 0 ? ` · Rating mediu: ${avgRating.toFixed(1)}/10` : ''}`} +

+
+ +
+ + {/* Create form */} + {showCreate && ( +
+

Revizuire nouă

+
+
+ setForm({ ...form, title: e.target.value })} + className="w-full rounded-lg border bg-card px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+ + + setForm({ ...form, periodStart: e.target.value })} + className="rounded-lg border bg-card px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> + setForm({ ...form, periodEnd: e.target.value })} + className="rounded-lg border bg-card px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+