fix(bookkeeping): journal search finds a voucher by its label, with a spinner while searching (#1808)
"Sök verifikationstext" only matched journal_entries.description, so typing A209 never returned voucher A209 itself: only other vouchers whose text mentioned it. Users read that as "the voucher is missing". A label-shaped needle (A209, a 209, A-209) now also matches voucher_series + voucher_number via a PostgREST OR (needle double-quoted so commas/parentheses stay literal); other needles keep the plain description ILIKE. parseVoucher accepts one space or hyphen between series and number. The search box shows a spinner while a server-side search is in flight; before, the only signal was the list dimming. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9622382579
commit
d4c42fd8db
@@ -176,12 +176,19 @@ describe('parseVoucher', () => {
|
||||
expect(parseVoucher(' a5 ')).toEqual({ series: 'A', number: 5 })
|
||||
})
|
||||
|
||||
it('accepts one space or hyphen between series and number (how users type it in search)', () => {
|
||||
expect(parseVoucher('A 209')).toEqual({ series: 'A', number: 209 })
|
||||
expect(parseVoucher('A-209')).toEqual({ series: 'A', number: 209 })
|
||||
expect(parseVoucher('a-1')).toEqual({ series: 'A', number: 1 })
|
||||
})
|
||||
|
||||
it('returns null for malformed input', () => {
|
||||
expect(parseVoucher('')).toBeNull()
|
||||
expect(parseVoucher('-')).toBeNull()
|
||||
expect(parseVoucher('123')).toBeNull()
|
||||
expect(parseVoucher('AA1')).toBeNull()
|
||||
expect(parseVoucher('A0')).toBeNull()
|
||||
expect(parseVoucher('A-1')).toBeNull()
|
||||
expect(parseVoucher('A--1')).toBeNull()
|
||||
expect(parseVoucher('A 1')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -107,15 +107,17 @@ export function formatVoucher(entry: {
|
||||
|
||||
/**
|
||||
* Parse a formatted voucher label back into its parts. Returns null when the
|
||||
* input does not match the expected shape (single uppercase letter followed
|
||||
* by a positive integer). Use for filter inputs / search.
|
||||
* input does not match the expected shape: a single letter followed by a
|
||||
* positive integer, optionally separated by one space or hyphen ("A209",
|
||||
* "a 209", "A-209"). Use for filter inputs / search: these are the shapes
|
||||
* users type when they look for a voucher by its number.
|
||||
*/
|
||||
export function parseVoucher(
|
||||
formatted: string,
|
||||
): { series: string; number: number } | null {
|
||||
if (typeof formatted !== 'string') return null
|
||||
const trimmed = formatted.trim().toUpperCase()
|
||||
const match = trimmed.match(/^([A-Z])(\d+)$/)
|
||||
const match = trimmed.match(/^([A-Z])[ -]?(\d+)$/)
|
||||
if (!match) return null
|
||||
const number = parseInt(match[2], 10)
|
||||
if (!Number.isFinite(number) || number <= 0) return null
|
||||
|
||||
Reference in New Issue
Block a user