Files
policy-ui/.claude/skills/vue/references/utils-client.md
HaimKortovich a2eb1f3789 Add nuxt-skills and update auto quotes to use new policy API structure
- Add nuxt-skills (vue, nuxt, nuxt-ui) to .claude/skills/
- Create useCustomerSelection() composable for managing insured/buyer selection
- Create usePolicyApi() composable for policy API operations
- Update auto quote components to use insured/buyer instead of client
- Update vehicle fields: remove valorVehiculo, add market_value, requested_value, rc_limits
- Make chassis_number and engine_number optional
- Update auto quote types and composables to match new API structure
- Update auto quote page to submit to policy API with new structure
2026-04-27 14:56:53 -05:00

3.3 KiB

Client Utilities

Pure functions for formatting, validation, transformation, and parsing.

Quick Reference

Category Examples
Formatters formatCurrency, formatDate, formatBytes
Validators isValidEmail, isValidUrl, isValidPhone
Transformers slugify, truncate, capitalize
Parsers parseQuery, parseJSON, parseDate

Rules

Pure functions:

  • Same input → same output
  • No side effects
  • No external state mutation
  • No API calls, no refs, no reactive

When NOT to use utils:

  • Stateful logic → use composables
  • Vue-specific → use composables
  • Component logic → keep in component
  • API calls → use queries

Structure

// utils/formatters.ts
export function formatCurrency(amount: number, currency = 'USD'): string {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
  }).format(amount)
}

export function formatRelativeTime(date: Date): string {
  const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
  const diff = date.getTime() - Date.now()
  const days = Math.floor(diff / (1000 * 60 * 60 * 24))
  return rtf.format(days, 'day')
}

Naming: Descriptive verbs (formatCurrency, validateEmail, parseQuery) Organization: Group by category (formatters.ts, validators.ts) Exports: Named exports only

Examples by Category

Formatters:

// utils/formatters.ts
export function formatBytes(bytes: number): string { ... }
export function formatPhone(phone: string): string { ... }

Validators:

// utils/validators.ts
export function isValidEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email)
}

export function isValidUrl(url: string): boolean {
  try { new URL(url); return true }
  catch { return false }
}

Transformers:

// utils/transformers.ts
export function slugify(text: string): string {
  return text.toLowerCase()
    .replace(/[^\w\s-]/g, '')
    .replace(/\s+/g, '-')
}

export function truncate(text: string, length: number): string {
  return text.length > length ? `${text.slice(0, length)}...` : text
}

Parsers:

// utils/parsers.ts
export function parseQuery(search: string): Record<string, string> {
  return Object.fromEntries(new URLSearchParams(search))
}

export function parseJSON<T>(json: string, fallback: T): T {
  try { return JSON.parse(json) }
  catch { return fallback }
}

Common Mistakes

Side effects (not pure):

// ❌ Wrong - mutates external state
let count = 0
export function increment() {
  count++
  return count
}

// ✅ Correct - pure
export function add(a: number, b: number): number {
  return a + b
}

Using utils for stateful logic:

// ❌ Wrong - should be composable
export function useCounter() { ... }

// ✅ Correct - pure transformation
export function formatCount(count: number): string { ... }

Organization

Flat for small projects:

utils/
├── formatters.ts
├── validators.ts
└── transformers.ts

Nested for large projects:

utils/
├── formatters/
│   ├── date.ts
│   ├── currency.ts
│   └── index.ts
└── validators/
    ├── email.ts
    └── index.ts