feat: add fuzzy autocomplete and NL quick-add for invoice line items
- Description field now shows a fuzzy-matched dropdown of past line items (description, hours, rate) as you type via Fuse.js — zero server cost - Selecting a suggestion pre-fills description, hours, and rate in one click - NL quick-add bar lets you type e.g. "3hrs web design @120" + Enter to append a fully-parsed line item without clicking through fields - New tRPC query `getLineItemHistory` returns deduplicated past line items for the current user, ordered by recency - New `parseLineItem` utility handles hours/rate extraction via regex Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { useMemo } from "react";
|
||||
import Fuse from "fuse.js";
|
||||
import { api } from "~/trpc/react";
|
||||
|
||||
export interface LineItemSuggestion {
|
||||
description: string;
|
||||
hours: number;
|
||||
rate: number;
|
||||
}
|
||||
|
||||
export function useLineItemSuggestions() {
|
||||
const { data: history = [] } = api.invoices.getLineItemHistory.useQuery(undefined, {
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
const fuse = useMemo(
|
||||
() =>
|
||||
new Fuse(history, {
|
||||
keys: ["description"],
|
||||
threshold: 0.4,
|
||||
minMatchCharLength: 2,
|
||||
}),
|
||||
[history],
|
||||
);
|
||||
|
||||
function search(query: string): LineItemSuggestion[] {
|
||||
if (!query || query.length < 2) return history.slice(0, 6);
|
||||
return fuse.search(query, { limit: 6 }).map((r) => r.item);
|
||||
}
|
||||
|
||||
return { search, hasHistory: history.length > 0 };
|
||||
}
|
||||
Reference in New Issue
Block a user