feat(registratura): fix thread clear, close via conex entry
- Fix threadParentId clear: always show "Sterge" button even when parent not found in allEntries - Bigger clear button with text label instead of tiny X icon - Fallback display when parent not in current list (shows truncated ID) - Close via conex: table/detail "Inchide" now creates a new reply entry that closes the original - Header shows "Conex la BTG-XXX" + "Inchide originala" badge when closing via conex - After saving the new conex entry, parent is auto-closed with resolution "finalizat" - onClose signature changed from (id: string) to (entry: RegistryEntry) across table + detail Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,8 @@ export function RegistraturaModule() {
|
|||||||
const [viewingEntry, setViewingEntry] = useState<RegistryEntry | null>(null);
|
const [viewingEntry, setViewingEntry] = useState<RegistryEntry | null>(null);
|
||||||
/** Entry to reply to (conex) — pre-sets threadParentId in new form */
|
/** Entry to reply to (conex) — pre-sets threadParentId in new form */
|
||||||
const [replyToEntry, setReplyToEntry] = useState<RegistryEntry | null>(null);
|
const [replyToEntry, setReplyToEntry] = useState<RegistryEntry | null>(null);
|
||||||
|
/** If set, the parent entry will be closed after saving the new conex entry */
|
||||||
|
const [closesEntryId, setClosesEntryId] = useState<string | null>(null);
|
||||||
const [closingId, setClosingId] = useState<string | null>(null);
|
const [closingId, setClosingId] = useState<string | null>(null);
|
||||||
const [linkCheckId, setLinkCheckId] = useState<string | null>(null);
|
const [linkCheckId, setLinkCheckId] = useState<string | null>(null);
|
||||||
|
|
||||||
@@ -138,6 +140,25 @@ export function RegistraturaModule() {
|
|||||||
data: Omit<RegistryEntry, "id" | "number" | "createdAt" | "updatedAt">,
|
data: Omit<RegistryEntry, "id" | "number" | "createdAt" | "updatedAt">,
|
||||||
) => {
|
) => {
|
||||||
await addEntry(data);
|
await addEntry(data);
|
||||||
|
// If this new entry closes a parent, close the parent automatically
|
||||||
|
if (closesEntryId) {
|
||||||
|
const parentEntry = allEntries.find((e) => e.id === closesEntryId);
|
||||||
|
if (parentEntry && parentEntry.status === "deschis") {
|
||||||
|
const closureInfo: ClosureInfo = {
|
||||||
|
resolution: "finalizat",
|
||||||
|
reason: "Inchis prin inregistrare conex",
|
||||||
|
closedBy: "",
|
||||||
|
closedAt: new Date().toISOString(),
|
||||||
|
hadActiveDeadlines:
|
||||||
|
(parentEntry.trackedDeadlines ?? []).some(
|
||||||
|
(d) => d.resolution === "pending",
|
||||||
|
),
|
||||||
|
};
|
||||||
|
await updateEntry(closesEntryId, { closureInfo });
|
||||||
|
await closeEntry(closesEntryId, false);
|
||||||
|
}
|
||||||
|
setClosesEntryId(null);
|
||||||
|
}
|
||||||
setReplyToEntry(null);
|
setReplyToEntry(null);
|
||||||
setViewMode("list");
|
setViewMode("list");
|
||||||
};
|
};
|
||||||
@@ -157,6 +178,16 @@ export function RegistraturaModule() {
|
|||||||
|
|
||||||
const handleReply = (entry: RegistryEntry) => {
|
const handleReply = (entry: RegistryEntry) => {
|
||||||
setReplyToEntry(entry);
|
setReplyToEntry(entry);
|
||||||
|
setClosesEntryId(null);
|
||||||
|
setViewingEntry(null);
|
||||||
|
setEditingEntry(null);
|
||||||
|
setViewMode("add");
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Close entry via conex: create reply entry that closes the parent */
|
||||||
|
const handleCloseViaConex = (entry: RegistryEntry) => {
|
||||||
|
setReplyToEntry(entry);
|
||||||
|
setClosesEntryId(entry.id);
|
||||||
setViewingEntry(null);
|
setViewingEntry(null);
|
||||||
setEditingEntry(null);
|
setEditingEntry(null);
|
||||||
setViewMode("add");
|
setViewMode("add");
|
||||||
@@ -217,6 +248,7 @@ export function RegistraturaModule() {
|
|||||||
setViewMode("list");
|
setViewMode("list");
|
||||||
setEditingEntry(null);
|
setEditingEntry(null);
|
||||||
setReplyToEntry(null);
|
setReplyToEntry(null);
|
||||||
|
setClosesEntryId(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Dashboard deadline resolve/chain handlers ──
|
// ── Dashboard deadline resolve/chain handlers ──
|
||||||
@@ -394,7 +426,7 @@ export function RegistraturaModule() {
|
|||||||
onView={handleView}
|
onView={handleView}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onClose={handleCloseRequest}
|
onClose={handleCloseViaConex}
|
||||||
onReply={handleReply}
|
onReply={handleReply}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -416,6 +448,11 @@ export function RegistraturaModule() {
|
|||||||
<Badge variant="outline" className="text-xs text-blue-600 border-blue-300">
|
<Badge variant="outline" className="text-xs text-blue-600 border-blue-300">
|
||||||
Raspuns
|
Raspuns
|
||||||
</Badge>
|
</Badge>
|
||||||
|
{closesEntryId && (
|
||||||
|
<Badge variant="outline" className="text-xs text-green-600 border-green-300">
|
||||||
|
Inchide originala
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -467,7 +504,7 @@ export function RegistraturaModule() {
|
|||||||
if (!open) setViewingEntry(null);
|
if (!open) setViewingEntry(null);
|
||||||
}}
|
}}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onClose={handleCloseRequest}
|
onClose={handleCloseViaConex}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onReply={handleReply}
|
onReply={handleReply}
|
||||||
allEntries={allEntries}
|
allEntries={allEntries}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ interface RegistryEntryDetailProps {
|
|||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
onEdit: (entry: RegistryEntry) => void;
|
onEdit: (entry: RegistryEntry) => void;
|
||||||
onClose: (id: string) => void;
|
onClose: (entry: RegistryEntry) => void;
|
||||||
onDelete: (id: string) => void;
|
onDelete: (id: string) => void;
|
||||||
/** Create a new entry linked as reply (conex) to this entry */
|
/** Create a new entry linked as reply (conex) to this entry */
|
||||||
onReply?: (entry: RegistryEntry) => void;
|
onReply?: (entry: RegistryEntry) => void;
|
||||||
@@ -224,7 +224,7 @@ export function RegistryEntryDetail({
|
|||||||
className="text-green-600 border-green-300 hover:bg-green-50 dark:border-green-700 dark:hover:bg-green-950/30"
|
className="text-green-600 border-green-300 hover:bg-green-50 dark:border-green-700 dark:hover:bg-green-950/30"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
onClose(entry.id);
|
onClose(entry);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CheckCircle2 className="mr-1.5 h-3.5 w-3.5" /> Inchide
|
<CheckCircle2 className="mr-1.5 h-3.5 w-3.5" /> Inchide
|
||||||
|
|||||||
@@ -1311,28 +1311,38 @@ export function RegistryEntryForm({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</Label>
|
</Label>
|
||||||
{threadParent && (
|
{threadParentId && (
|
||||||
<div className="mt-1.5 flex items-center gap-2 rounded border border-primary/30 bg-primary/5 px-2 py-1.5 text-sm">
|
<div className="mt-1.5 flex items-center gap-2 rounded border border-primary/30 bg-primary/5 px-2 py-1.5 text-sm">
|
||||||
<Badge
|
{threadParent ? (
|
||||||
variant={
|
<>
|
||||||
threadParent.direction === "intrat" ? "default" : "secondary"
|
<Badge
|
||||||
}
|
variant={
|
||||||
className="text-[10px]"
|
threadParent.direction === "intrat" ? "default" : "secondary"
|
||||||
>
|
}
|
||||||
{threadParent.direction === "intrat" ? "↓" : "↑"}
|
className="text-[10px]"
|
||||||
</Badge>
|
>
|
||||||
<span className="font-mono text-xs">{threadParent.number}</span>
|
{threadParent.direction === "intrat" ? "\u2193" : "\u2191"}
|
||||||
<span className="truncate text-muted-foreground text-xs">
|
</Badge>
|
||||||
{threadParent.subject}
|
<span className="font-mono text-xs">{threadParent.number}</span>
|
||||||
</span>
|
<span className="truncate text-muted-foreground text-xs">
|
||||||
|
{threadParent.subject}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span className="text-xs text-muted-foreground italic">
|
||||||
|
Legat de o inregistrare (ID: {threadParentId.slice(0, 8)}...)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="ml-auto h-6 w-6 p-0"
|
className="ml-auto h-7 px-2 text-xs text-destructive hover:text-destructive"
|
||||||
onClick={() => setThreadParentId("")}
|
onClick={() => setThreadParentId("")}
|
||||||
|
title="Sterge legatura"
|
||||||
>
|
>
|
||||||
<X className="h-3.5 w-3.5" />
|
<X className="h-3.5 w-3.5 mr-0.5" />
|
||||||
|
Sterge
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ interface RegistryTableProps {
|
|||||||
onView: (entry: RegistryEntry) => void;
|
onView: (entry: RegistryEntry) => void;
|
||||||
onEdit: (entry: RegistryEntry) => void;
|
onEdit: (entry: RegistryEntry) => void;
|
||||||
onDelete: (id: string) => void;
|
onDelete: (id: string) => void;
|
||||||
onClose: (id: string) => void;
|
onClose: (entry: RegistryEntry) => void;
|
||||||
/** Create a new entry linked as reply (conex) to this entry */
|
/** Create a new entry linked as reply (conex) to this entry */
|
||||||
onReply?: (entry: RegistryEntry) => void;
|
onReply?: (entry: RegistryEntry) => void;
|
||||||
}
|
}
|
||||||
@@ -495,7 +495,7 @@ export function RegistryTable({
|
|||||||
className="h-7 w-7 text-green-600"
|
className="h-7 w-7 text-green-600"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onClose(entry.id);
|
onClose(entry);
|
||||||
}}
|
}}
|
||||||
title="Inchide"
|
title="Inchide"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user