Utilities
Utility functions and helpers for Lager Guru application.
Overview
Lager Guru provides utility functions for common operations like date formatting, zone distance calculations, inventory math, parsing, and formatting.
Date Helpers
Date Formatting
Format dates for display in various formats.
Location: src/lib/utils.ts (placeholder - implement as needed)
Example:
// Format date for display
function formatDate(date: Date | string): string {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}
// Format datetime
function formatDateTime(date: Date | string): string {
return new Date(date).toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
// Format relative time
function formatRelativeTime(date: Date | string): string {
const now = new Date();
const then = new Date(date);
const diff = now.getTime() - then.getTime();
const minutes = Math.floor(diff / 60000);
if (minutes < 1) return 'Just now';
if (minutes < 60) return `${minutes} minutes ago`;
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours} hours ago`;
const days = Math.floor(hours / 24);
return `${days} days ago`;
}Zone Distance Helpers
Calculate Zone Distance
Calculate Euclidean distance between two zones.
Location: Database function compute_zone_distance()
Usage:
import { supabase } from '@/integrations/supabase/client';
async function getZoneDistance(zoneAId: string, zoneBId: string): Promise<number | null> {
const { data, error } = await supabase.rpc('compute_zone_distance', {
zone_a_id: zoneAId,
zone_b_id: zoneBId
});
if (error) throw error;
return data;
}Update Zone Distance
Update or create zone distance record.
Location: Database function update_zone_distance()
Usage:
async function updateZoneDistance(
fromZoneId: string,
toZoneId: string,
distance: number
): Promise<void> {
const { error } = await supabase.rpc('update_zone_distance', {
from_zone_id: fromZoneId,
to_zone_id: toZoneId,
distance_value: distance
});
if (error) throw error;
}Inventory Math
Calculate Stock Levels
Calculate various inventory metrics.
Example:
// Calculate stock percentage
function calculateStockPercentage(
current: number,
min: number,
max: number
): number {
if (max === 0) return 0;
return Math.round((current / max) * 100);
}
// Check if low stock
function isLowStock(current: number, min: number): boolean {
return current <= min;
}
// Calculate reorder quantity
function calculateReorderQuantity(
current: number,
min: number,
max: number
): number {
return Math.max(0, max - current);
}Stock Movement Calculations
// Calculate total inbound
function calculateTotalInbound(movements: StockMovement[]): number {
return movements
.filter(m => m.type === 'inbound')
.reduce((sum, m) => sum + m.quantity, 0);
}
// Calculate total outbound
function calculateTotalOutbound(movements: StockMovement[]): number {
return movements
.filter(m => m.type === 'outbound')
.reduce((sum, m) => sum + m.quantity, 0);
}Parsing Functions
Parse Query Parameters
Parse and validate URL query parameters.
Example:
function parseQueryParams(searchParams: URLSearchParams) {
return {
page: parseInt(searchParams.get('page') || '1'),
limit: parseInt(searchParams.get('limit') || '50'),
status: searchParams.get('status') || undefined,
search: searchParams.get('search') || undefined
};
}Parse JSON Safely
Safely parse JSON with error handling.
Example:
function parseJSON<T>(json: string, defaultValue: T): T {
try {
return JSON.parse(json) as T;
} catch {
return defaultValue;
}
}Formatters
Format Currency
Format numbers as currency.
Example:
function formatCurrency(amount: number, currency: string = 'EUR'): string {
return new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: currency
}).format(amount);
}Format Number
Format numbers with thousand separators.
Example:
function formatNumber(num: number, decimals: number = 0): string {
return new Intl.NumberFormat('de-DE', {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals
}).format(num);
}Format SKU
Format SKU codes consistently.
Example:
function formatSKU(sku: string): string {
return sku.toUpperCase().trim().replace(/\s+/g, '-');
}Format Phone Number
Format phone numbers for display.
Example:
function formatPhoneNumber(phone: string): string {
// Remove all non-digits
const digits = phone.replace(/\D/g, '');
// Format as +49 XXX XXXXXXX (German format)
if (digits.length === 11 && digits.startsWith('49')) {
return `+${digits.slice(0, 2)} ${digits.slice(2, 5)} ${digits.slice(5)}`;
}
return phone;
}Validation Helpers
Validate Email
Validate email address format.
Example:
function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}Validate SKU
Validate SKU format.
Example:
function isValidSKU(sku: string): boolean {
// SKU must be alphanumeric, 3-50 characters
const skuRegex = /^[A-Z0-9-]{3,50}$/i;
return skuRegex.test(sku);
}Array Helpers
Group By
Group array items by a key.
Example:
function groupBy<T>(array: T[], key: keyof T): Record<string, T[]> {
return array.reduce((result, item) => {
const groupKey = String(item[key]);
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
return result;
}, {} as Record<string, T[]>);
}Sort By
Sort array by a key.
Example:
function sortBy<T>(array: T[], key: keyof T, direction: 'asc' | 'desc' = 'asc'): T[] {
return [...array].sort((a, b) => {
const aVal = a[key];
const bVal = b[key];
if (aVal < bVal) return direction === 'asc' ? -1 : 1;
if (aVal > bVal) return direction === 'asc' ? 1 : -1;
return 0;
});
}String Helpers
Truncate
Truncate string to specified length.
Example:
function truncate(str: string, length: number, suffix: string = '...'): string {
if (str.length <= length) return str;
return str.slice(0, length - suffix.length) + suffix;
}Slugify
Convert string to URL-friendly slug.
Example:
function slugify(str: string): string {
return str
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}Class Name Utilities
cn(...inputs)
Merge Tailwind CSS class names.
Source: src/lib/utils.ts
Usage:
import { cn } from '@/lib/utils';
function Button({ className, variant }: ButtonProps) {
return (
<button
className={cn(
'base-button-styles',
variant === 'primary' && 'bg-blue-500',
className
)}
>
Click me
</button>
);
}Type Guards
Type Checking
Check if value is of specific type.
Example:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function isNumber(value: unknown): value is number {
return typeof value === 'number' && !isNaN(value);
}
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}Error Handling
Safe Async
Wrap async functions with error handling.
Example:
async function safeAsync<T>(
fn: () => Promise<T>,
defaultValue: T
): Promise<T> {
try {
return await fn();
} catch (error) {
console.error('Error:', error);
return defaultValue;
}
}Related Documentation
- API Reference - Complete API documentation
- Hooks - Custom React hooks
- Integrations - External integrations