Initial commit

This commit is contained in:
2026-07-22 14:08:50 +01:00
commit 16e7684f3b
32 changed files with 6508 additions and 0 deletions

81
src/lib/format.ts Normal file
View 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()
}