Initial commit
This commit is contained in:
81
src/lib/format.ts
Normal file
81
src/lib/format.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { InventoryItem, ProductImage } from '../types'
|
||||
|
||||
const DAY_MS = 86_400_000
|
||||
|
||||
export function parseDate(value?: string | null): Date | null {
|
||||
if (!value) return null
|
||||
const date = new Date(value)
|
||||
return Number.isNaN(date.getTime()) ? null : date
|
||||
}
|
||||
|
||||
export function daysUntil(value?: string | null): number | null {
|
||||
const date = parseDate(value)
|
||||
if (!date) return null
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
date.setHours(0, 0, 0, 0)
|
||||
return Math.ceil((date.getTime() - today.getTime()) / DAY_MS)
|
||||
}
|
||||
|
||||
export function expiryLabel(value?: string | null): string {
|
||||
const days = daysUntil(value)
|
||||
if (days === null) return 'No expiry set'
|
||||
if (days < 0) return `Expired ${Math.abs(days)}d ago`
|
||||
if (days === 0) return 'Expires today'
|
||||
if (days === 1) return 'Expires tomorrow'
|
||||
return `Expires in ${days} days`
|
||||
}
|
||||
|
||||
export function expiryTone(value?: string | null): 'danger' | 'warning' | 'good' | 'neutral' {
|
||||
const days = daysUntil(value)
|
||||
if (days === null) return 'neutral'
|
||||
if (days < 0) return 'danger'
|
||||
if (days <= 3) return 'warning'
|
||||
return 'good'
|
||||
}
|
||||
|
||||
export function formatDate(value?: string | null): string {
|
||||
const date = parseDate(value)
|
||||
if (!date) return 'Not set'
|
||||
return new Intl.DateTimeFormat('en-GB', { day: 'numeric', month: 'short', year: 'numeric' }).format(date)
|
||||
}
|
||||
|
||||
export function toDateInput(value?: string | null): string {
|
||||
if (!value) return ''
|
||||
return value.slice(0, 10)
|
||||
}
|
||||
|
||||
export function toApiDate(value: string): string | undefined {
|
||||
return value ? `${value}T00:00:00` : undefined
|
||||
}
|
||||
|
||||
export function displayName(firstName?: string | null, lastName?: string | null, email?: string) {
|
||||
const name = [firstName, lastName].filter(Boolean).join(' ')
|
||||
return name || email || 'Keeply user'
|
||||
}
|
||||
|
||||
export function itemImage(item: InventoryItem): string | null {
|
||||
const images = item.itemLookupImages
|
||||
if (!Array.isArray(images)) return null
|
||||
const first = images[0] as ProductImage | string | undefined
|
||||
if (typeof first === 'string') return first
|
||||
if (!first || typeof first !== 'object') return null
|
||||
const url = first.url ?? first.image_url
|
||||
return typeof url === 'string' ? url : null
|
||||
}
|
||||
|
||||
export function productSize(value: unknown): string | null {
|
||||
if (typeof value === 'string' || typeof value === 'number') return String(value)
|
||||
if (value && typeof value === 'object') {
|
||||
const record = value as Record<string, unknown>
|
||||
const size = record.value ?? record.display ?? record.text
|
||||
if (typeof size === 'string' || typeof size === 'number') return String(size)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getInitials(firstName?: string | null, lastName?: string | null, email?: string) {
|
||||
const letters = [firstName, lastName].filter(Boolean).map((part) => String(part)[0])
|
||||
if (letters.length) return letters.join('').toUpperCase()
|
||||
return (email?.[0] ?? 'K').toUpperCase()
|
||||
}
|
||||
Reference in New Issue
Block a user