Files
data-entry-app/frontend/src/lib/components/throughput/utils.ts
T

71 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-06-15 11:59:04 +12:00
import type { ThroughputEntry } from '$lib/types';
export type SortKey = 'date' | 'product' | 'packed' | 'total' | 'staff' | 'destination' | 'notes';
export type SortDirection = 'asc' | 'desc';
export type ConfettiPiece = {
left: number;
delay: number;
duration: number;
color: string;
rotate: number;
drift: number;
size: number;
};
export const CONFETTI_COLORS = ['#16a34a', '#f59e0b', '#3b82f6', '#ec4899', '#8b5cf6', '#ef4444'];
export function compareText(a: string | null | undefined, b: string | null | undefined) {
return (a ?? '').localeCompare(b ?? '', undefined, { sensitivity: 'base' });
}
export function compareDate(a: string | null | undefined, b: string | null | undefined) {
const aTime = a ? Date.parse(a) : Number.NEGATIVE_INFINITY;
const bTime = b ? Date.parse(b) : Number.NEGATIVE_INFINITY;
return aTime - bTime;
}
export function toISODate(d: Date): string {
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
export function ausToday(): Date {
const ymd = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Australia/Sydney',
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).format(new Date());
const [y, m, d] = ymd.split('-').map(Number);
return new Date(y, m - 1, d);
}
export function startOfWeekMonday(d: Date): Date {
const start = new Date(d.getFullYear(), d.getMonth(), d.getDate());
const dow = (start.getDay() + 6) % 7;
start.setDate(start.getDate() - dow);
return start;
}
export function addDays(d: Date, days: number): Date {
const next = new Date(d);
next.setDate(next.getDate() + days);
return next;
}
export function buildConfetti(colors = CONFETTI_COLORS): ConfettiPiece[] {
return Array.from({ length: 42 }, (_, i) => ({
left: Math.random() * 100,
delay: Math.random() * 1.2,
duration: 1 + Math.random() * 0.8,
color: colors[i % colors.length],
rotate: 220 + Math.random() * 360,
drift: (Math.random() - 0.5) * 60,
size: 6 + Math.random() * 6
}));
}
export function isStockEntry(entry: ThroughputEntry): boolean {
return entry.for_stock || (!entry.for_order && /stock/i.test(entry.notes ?? ''));
}