lookups.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. /**
  2. * The codes this person opened and the words they searched for lately on
  3. * the fault code pages, kept in this browser like the search palette's
  4. * recent picks. Shown on the lookup page before anything is typed, so the
  5. * code a technician is chasing all day is one click away.
  6. */
  7. const KEY = 'torqvoice.faultCodes.recent'
  8. const MAX = 10
  9. /** A lookup as it is recorded: a code that was opened, or words that were searched. */
  10. export type NewLookup =
  11. | { kind: 'code'; code: string; title: string | null }
  12. | { kind: 'words'; query: string }
  13. export type RecentLookup = NewLookup & { at: number }
  14. const sameAs = (a: RecentLookup, b: NewLookup) =>
  15. a.kind === 'code' && b.kind === 'code'
  16. ? a.code === b.code
  17. : a.kind === 'words' && b.kind === 'words'
  18. ? a.query.toLowerCase() === b.query.toLowerCase()
  19. : false
  20. function valid(x: unknown): x is RecentLookup {
  21. if (!x || typeof x !== 'object') return false
  22. const r = x as Record<string, unknown>
  23. if (typeof r.at !== 'number') return false
  24. if (r.kind === 'code') return typeof r.code === 'string'
  25. if (r.kind === 'words') return typeof r.query === 'string'
  26. return false
  27. }
  28. export function readRecentLookups(): RecentLookup[] {
  29. try {
  30. const raw = window.localStorage.getItem(KEY)
  31. if (!raw) return []
  32. const parsed: unknown = JSON.parse(raw)
  33. return Array.isArray(parsed) ? parsed.filter(valid).slice(0, MAX) : []
  34. } catch {
  35. return []
  36. }
  37. }
  38. /** Puts a lookup first, once: opening P0420 again moves it to the top. */
  39. export function pushRecentLookup(lookup: NewLookup): RecentLookup[] {
  40. const next: RecentLookup[] = [
  41. { ...lookup, at: Date.now() },
  42. ...readRecentLookups().filter((r) => !sameAs(r, lookup)),
  43. ].slice(0, MAX)
  44. try {
  45. window.localStorage.setItem(KEY, JSON.stringify(next))
  46. } catch {
  47. // Private mode or a full store: the page works without a memory.
  48. }
  49. return next
  50. }
  51. export function clearRecentLookups(): void {
  52. try {
  53. window.localStorage.removeItem(KEY)
  54. } catch {
  55. // Nothing to clear.
  56. }
  57. }