- Version history with add-version dialog and history display - Expiration date with expired/expiring-soon visual indicators - Legal status and usage notes fields - Delete confirmation dialog - updatedAt timestamp support - Image preview in version history Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
87 lines
3.3 KiB
TypeScript
87 lines
3.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
import { useStorage } from '@/core/storage';
|
|
import { v4 as uuid } from 'uuid';
|
|
import type { SignatureAsset, SignatureAssetType, AssetVersion } from '../types';
|
|
|
|
const PREFIX = 'sig:';
|
|
|
|
export interface SignatureFilters {
|
|
search: string;
|
|
type: SignatureAssetType | 'all';
|
|
}
|
|
|
|
export function useSignatures() {
|
|
const storage = useStorage('digital-signatures');
|
|
const [assets, setAssets] = useState<SignatureAsset[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [filters, setFilters] = useState<SignatureFilters>({ search: '', type: 'all' });
|
|
|
|
const refresh = useCallback(async () => {
|
|
setLoading(true);
|
|
const keys = await storage.list();
|
|
const results: SignatureAsset[] = [];
|
|
for (const key of keys) {
|
|
if (key.startsWith(PREFIX)) {
|
|
const item = await storage.get<SignatureAsset>(key);
|
|
if (item) results.push(item);
|
|
}
|
|
}
|
|
results.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
setAssets(results);
|
|
setLoading(false);
|
|
}, [storage]);
|
|
|
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
useEffect(() => { refresh(); }, [refresh]);
|
|
|
|
const addAsset = useCallback(async (data: Omit<SignatureAsset, 'id' | 'createdAt' | 'updatedAt'>) => {
|
|
const now = new Date().toISOString();
|
|
const asset: SignatureAsset = { ...data, id: uuid(), createdAt: now, updatedAt: now };
|
|
await storage.set(`${PREFIX}${asset.id}`, asset);
|
|
await refresh();
|
|
return asset;
|
|
}, [storage, refresh]);
|
|
|
|
const updateAsset = useCallback(async (id: string, updates: Partial<SignatureAsset>) => {
|
|
const existing = assets.find((a) => a.id === id);
|
|
if (!existing) return;
|
|
const updated: SignatureAsset = {
|
|
...existing, ...updates,
|
|
id: existing.id, createdAt: existing.createdAt,
|
|
updatedAt: new Date().toISOString(),
|
|
};
|
|
await storage.set(`${PREFIX}${id}`, updated);
|
|
await refresh();
|
|
}, [storage, refresh, assets]);
|
|
|
|
const addVersion = useCallback(async (assetId: string, imageUrl: string, notes: string) => {
|
|
const existing = assets.find((a) => a.id === assetId);
|
|
if (!existing) return;
|
|
const version: AssetVersion = { id: uuid(), imageUrl, notes, createdAt: new Date().toISOString() };
|
|
const updatedVersions = [...existing.versions, version];
|
|
await updateAsset(assetId, { imageUrl, versions: updatedVersions });
|
|
}, [assets, updateAsset]);
|
|
|
|
const removeAsset = useCallback(async (id: string) => {
|
|
await storage.delete(`${PREFIX}${id}`);
|
|
await refresh();
|
|
}, [storage, refresh]);
|
|
|
|
const updateFilter = useCallback(<K extends keyof SignatureFilters>(key: K, value: SignatureFilters[K]) => {
|
|
setFilters((prev) => ({ ...prev, [key]: value }));
|
|
}, []);
|
|
|
|
const filteredAssets = assets.filter((a) => {
|
|
if (filters.type !== 'all' && a.type !== filters.type) return false;
|
|
if (filters.search) {
|
|
const q = filters.search.toLowerCase();
|
|
return a.label.toLowerCase().includes(q) || a.owner.toLowerCase().includes(q);
|
|
}
|
|
return true;
|
|
});
|
|
|
|
return { assets: filteredAssets, allAssets: assets, loading, filters, updateFilter, addAsset, updateAsset, addVersion, removeAsset, refresh };
|
|
}
|