feat: standardize correspondent and tag types with usage count

This commit is contained in:
2025-12-04 13:11:52 +01:00
parent 225f810513
commit e8f578eb48
4 changed files with 37 additions and 36 deletions
@@ -1,22 +1,11 @@
import { useCallback, useState } from 'react';
import type { FormEvent, KeyboardEvent } from 'react';
interface CorrespondentUsage {
total?: number;
[key: string]: unknown;
}
interface CorrespondentEntry {
id?: string;
name?: string;
usage?: CorrespondentUsage;
[key: string]: unknown;
}
import type { Correspondent } from '../types/documents';
export interface CorrespondentsPanelProps {
correspondents?: CorrespondentEntry[];
correspondents?: Correspondent[];
onRefresh?: () => void | Promise<void>;
onCreate: (payload: { name: string }) => Promise<CorrespondentEntry | void>;
onCreate: (payload: { name: string }) => Promise<Correspondent | void>;
onUpdate: (id: string, payload: { name: string }) => Promise<void>;
onDelete: (id: string) => Promise<void>;
onNotify?: (message: string, variant?: string) => void;
@@ -37,7 +26,7 @@ function CorrespondentsPanel({
const [creating, setCreating] = useState(false);
const [deletingId, setDeletingId] = useState<string | null>(null);
const startEdit = useCallback((correspondent: CorrespondentEntry) => {
const startEdit = useCallback((correspondent: Correspondent) => {
setEditingId(correspondent.id);
setDraftName(correspondent.name);
}, []);
@@ -68,7 +57,7 @@ function CorrespondentsPanel({
}, [editingId, draftName, onUpdate, cancelEdit, onNotify]);
const handleDelete = useCallback(
async (correspondent: CorrespondentEntry) => {
async (correspondent: Correspondent) => {
if (!correspondent?.id) return;
setDeletingId(correspondent.id);
try {
@@ -121,12 +110,12 @@ function CorrespondentsPanel({
[handleSave, cancelEdit],
);
const renderUsage = useCallback((usage?: CorrespondentUsage) => {
if (!usage) {
const renderUsage = useCallback((correspondent: Correspondent) => {
const count = correspondent.usage_count;
if (count == null || !Number.isFinite(count)) {
return '0';
}
const total = Number.isFinite(usage.total) ? Number(usage.total) : 0;
return total.toString();
return count.toString();
}, []);
return (
@@ -195,7 +184,7 @@ function CorrespondentsPanel({
<span>{correspondent.name}</span>
)}
</td>
<td className="numeric">{renderUsage(correspondent.usage)}</td>
<td className="numeric">{renderUsage(correspondent)}</td>
<td className="actions">
{isEditing ? (
<div className="tags-table__edit-controls">
@@ -1,4 +1,5 @@
import { MutableRefObject, useCallback, useState } from 'react';
import type { Correspondent } from '../../types/documents';
type ApiClient = {
get: (path: string) => Promise<{ data: unknown }>;
@@ -7,12 +8,6 @@ type ApiClient = {
delete: (path: string) => Promise<{ data: unknown }>;
};
interface CorrespondentEntry {
id?: string;
name?: string;
[key: string]: unknown;
}
interface UseCorrespondentsOptions {
apiClient: ApiClient;
notifyApiError: (error: unknown, fallback: string) => void;
@@ -28,7 +23,7 @@ const useCorrespondents = ({
tenantIdRef,
mapDocumentCaches,
}: UseCorrespondentsOptions) => {
const [correspondents, setCorrespondents] = useState<CorrespondentEntry[]>([]);
const [correspondents, setCorrespondents] = useState<Correspondent[]>([]);
const refreshCorrespondents = useCallback(async () => {
const requestTenantId = tenantIdRef.current;
+2 -8
View File
@@ -1,5 +1,6 @@
import { MutableRefObject, useCallback, useState } from 'react';
import type { TagId, TenantId } from '../../types/identifiers';
import type { Tag } from '../../types/documents';
type ApiClient = {
get: (path: string) => Promise<{ data: unknown }>
@@ -12,13 +13,6 @@ interface TagManagerInterface {
buildPayload: (input: { label?: string; color?: string | null }) => { label: string; color: string | null };
}
interface TagEntry {
id?: TagId;
label?: string;
color?: string | null;
[key: string]: unknown;
}
interface UseTagsOptions {
apiClient: ApiClient;
notifyApiError: (error: unknown, fallback: string) => void;
@@ -38,7 +32,7 @@ const useTags = ({
setActiveTagFilters,
mapDocumentCaches,
}: UseTagsOptions) => {
const [tags, setTags] = useState<TagEntry[]>([]);
const [tags, setTags] = useState<Tag[]>([]);
const refreshTags = useCallback(async () => {
const requestTenantId = tenantIdRef.current;
+23
View File
@@ -14,6 +14,29 @@ export interface DocumentCorrespondent {
count?: number;
}
/**
* A tag entity as returned by the API (includes usage_count).
* Use DocumentTag for the embedded version on documents.
*/
export interface Tag {
id?: Identifier;
label?: string;
color?: string | null;
usage_count?: number;
[key: string]: unknown;
}
/**
* A correspondent entity as returned by the API.
* Use DocumentCorrespondent for the embedded version on documents.
*/
export interface Correspondent {
id?: Identifier;
name?: string;
usage_count?: number;
[key: string]: unknown;
}
export interface DocumentVersion {
assets?: Record<string, Asset> | Asset[] | null;
metadata?: Record<string, unknown> & { page_count?: number } | null;