82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
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()
|
|
}
|