fix(goldset): "tagged" = all 3 answers set + add rule-type help popover
Two UX fixes on the gold-set tagging page: 1. isTagged now requires is_holding AND correct_type AND quote_complete — not just is_holding. Previously, in "hide tagged" mode the card vanished the instant is_holding was clicked, so the type and quote-complete answers could never be set. The progress counter / "תויג" badge now reflect full tagging. 2. An info (ℹ) icon next to "הסוג הנכון" opens a popover explaining the six rule types (definition + the deciding test + an example each), so the tagger has the criteria in front of them while tagging. Verified: tsc --noEmit exits 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Check, X, ChevronDown, ChevronLeft } from "lucide-react";
|
import { Check, X, ChevronDown, ChevronLeft, Info } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||||
import {
|
import {
|
||||||
useGoldset, useGoldsetScore, useTagGoldset, useCreateGoldsetSample,
|
useGoldset, useGoldsetScore, useTagGoldset, useCreateGoldsetSample,
|
||||||
type GoldsetItem,
|
type GoldsetItem,
|
||||||
@@ -32,7 +33,10 @@ function cleanCitation(s: string | null | undefined): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isTagged(it: GoldsetItem): boolean {
|
function isTagged(it: GoldsetItem): boolean {
|
||||||
return it.is_holding !== null;
|
// Fully tagged only when ALL THREE answers are set — otherwise, in
|
||||||
|
// "hide tagged" mode, a card would vanish the moment is_holding is clicked,
|
||||||
|
// before correct_type / quote_complete can be set.
|
||||||
|
return it.is_holding !== null && it.quote_complete !== null && !!it.correct_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Score panel ──────────────────────────────────────────────────────────────
|
// ─── Score panel ──────────────────────────────────────────────────────────────
|
||||||
@@ -86,6 +90,82 @@ function ScorePanel({ batch }: { batch: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Rule-type help (info popover) ────────────────────────────────────────────
|
||||||
|
|
||||||
|
const TYPE_HELP: { label: string; def: string; test: string; example: string }[] = [
|
||||||
|
{
|
||||||
|
label: "מחייבת",
|
||||||
|
def: "העיקרון שהיה הכרחי להכרעה — ה-holding האמיתי. בר-הסתמכות מלא.",
|
||||||
|
test: "מבחן וומבו: הפוך את הכלל — אם התוצאה הייתה משתנה → מחייבת.",
|
||||||
|
example: "נטל ההוכחה בהיטל השבחה מוטל על הוועדה המקומית.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "פרשני",
|
||||||
|
def: "קביעה שמפרשת הוראת-חוק / מונח / תכנית (מה המשמעות של סעיף X).",
|
||||||
|
test: "עונה ל'מה פירוש הנורמה?' ולא ל'מה הדין?'.",
|
||||||
|
example: "תכלית הפטור לפי ס' 19(ב)(4) היא לעודד פעילות ציבורית.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "פרוצדורלי",
|
||||||
|
def: "כלל סדר-דין: מועדים, סמכות, זכות-עמידה, מיצוי הליכים, נטל.",
|
||||||
|
test: "עוסק ב'איך' מתנהל ההליך, לא במהות התכנונית.",
|
||||||
|
example: "המועד להגשת ערר הוא 30 יום.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "משכנע",
|
||||||
|
def: "אסמכתה לא-מחייבת את הערכאה — שכנוע בלבד.",
|
||||||
|
test: "מקור שאינו כובל: ועדת-ערר אחרת, דעת-מיעוט, ספרות.",
|
||||||
|
example: "ועדת ערר ירושלים מסתמכת על החלטת ועדת ערר ממחוז אחר.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "יישום",
|
||||||
|
def: "החלת כלל על עובדות התיק הספציפי — תלוי-עובדות, לא בר-הכללה (לרוב 'לא הלכה').",
|
||||||
|
test: "מכיל 'במקרה דנן', שמות-צדדים, סכומים, המבנה הקונקרטי.",
|
||||||
|
example: "במקרה דנן ההיתר בטל כי השומה שגתה ב-12,000 ₪.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "אמרת-אגב",
|
||||||
|
def: "נאמר אגב אורחא, לא הכרחי להכרעה; הערכאה לא הכריעה בו. לא מחייב.",
|
||||||
|
test: "מבחן וומבו הפוך: היפוך הכלל לא משנה את התוצאה. דגלים: 'למעלה מן הצורך', 'מבלי לקבוע מסמרות'.",
|
||||||
|
example: "אף שאיננו נדרשים להכריע, נעיר כי ייתכן ש...",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function RuleTypeHelp() {
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="inline-flex items-center text-ink-muted hover:text-gold-deep"
|
||||||
|
aria-label="הסבר על סוגי ההלכה"
|
||||||
|
title="הסבר על הסוגים"
|
||||||
|
>
|
||||||
|
<Info className="w-3.5 h-3.5" />
|
||||||
|
</button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent align="start" className="w-[min(92vw,560px)] max-h-[70vh] overflow-y-auto p-0">
|
||||||
|
<div className="p-3 border-b border-rule">
|
||||||
|
<p className="font-semibold text-navy text-sm">סוגי ההלכה — במה הם נבדלים</p>
|
||||||
|
<p className="text-[0.72rem] text-ink-muted mt-0.5">
|
||||||
|
כלל-אצבע: סימנת "הלכה" → לרוב מחייבת / פרשני / פרוצדורלי / משכנע. סימנת "לא" → לרוב יישום / אמרת-אגב.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ul className="divide-y divide-rule-soft">
|
||||||
|
{TYPE_HELP.map((t) => (
|
||||||
|
<li key={t.label} className="p-3 space-y-1" dir="rtl">
|
||||||
|
<div className="font-semibold text-navy text-sm">{t.label}</div>
|
||||||
|
<div className="text-[0.78rem] text-ink-soft leading-relaxed">{t.def}</div>
|
||||||
|
<div className="text-[0.72rem] text-ink-muted"><span className="font-medium">מבחן:</span> {t.test}</div>
|
||||||
|
<div className="text-[0.72rem] text-ink-muted"><span className="font-medium">דוגמה:</span> {t.example}</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Tag card ─────────────────────────────────────────────────────────────────
|
// ─── Tag card ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function TagCard({
|
function TagCard({
|
||||||
@@ -140,7 +220,10 @@ function TagCard({
|
|||||||
</div>
|
</div>
|
||||||
{/* correct_type */}
|
{/* correct_type */}
|
||||||
<div>
|
<div>
|
||||||
<div className="text-[0.7rem] text-ink-muted mb-1">הסוג הנכון</div>
|
<div className="text-[0.7rem] text-ink-muted mb-1 flex items-center gap-1">
|
||||||
|
הסוג הנכון
|
||||||
|
<RuleTypeHelp />
|
||||||
|
</div>
|
||||||
<div className="flex gap-1 flex-wrap">
|
<div className="flex gap-1 flex-wrap">
|
||||||
{TYPES.map((t) => (
|
{TYPES.map((t) => (
|
||||||
<Button key={t.value} size="sm"
|
<Button key={t.value} size="sm"
|
||||||
|
|||||||
Reference in New Issue
Block a user