cre-sync/lib/utils/index.ts
BusyBee3333 4e6467ffb0 Add CRESync CRM application with Setup page
- Build complete Next.js CRM for commercial real estate
- Add authentication with JWT sessions and role-based access
- Add GoHighLevel API integration for contacts, conversations, opportunities
- Add AI-powered Control Center with tool calling
- Add Setup page with onboarding checklist (/setup)
- Add sidebar navigation with Setup menu item
- Fix type errors in onboarding API, GHL services, and control center tools
- Add Prisma schema with SQLite for local development
- Add UI components with clay morphism design system

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:30:55 -05:00

92 lines
2.1 KiB
TypeScript

import { type ClassValue, clsx } from "clsx";
/**
* Utility function to merge class names
*/
export function cn(...inputs: ClassValue[]) {
return clsx(inputs);
}
/**
* Format currency values
*/
export function formatCurrency(
amount: number,
currency: string = "USD",
locale: string = "en-US"
): string {
return new Intl.NumberFormat(locale, {
style: "currency",
currency,
}).format(amount);
}
/**
* Format date values
*/
export function formatDate(
date: Date | string,
options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "numeric",
}
): string {
const d = typeof date === "string" ? new Date(date) : date;
return d.toLocaleDateString("en-US", options);
}
/**
* Format relative time (e.g., "2 hours ago")
*/
export function formatRelativeTime(date: Date | string): string {
const d = typeof date === "string" ? new Date(date) : date;
const now = new Date();
const diffInSeconds = Math.floor((now.getTime() - d.getTime()) / 1000);
if (diffInSeconds < 60) return "just now";
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} minutes ago`;
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)} hours ago`;
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)} days ago`;
return formatDate(d);
}
/**
* Truncate text with ellipsis
*/
export function truncate(text: string, length: number = 100): string {
if (text.length <= length) return text;
return text.slice(0, length) + "...";
}
/**
* Generate a random ID
*/
export function generateId(length: number = 8): string {
return Math.random()
.toString(36)
.substring(2, 2 + length);
}
/**
* Debounce function
*/
export function debounce<T extends (...args: unknown[]) => unknown>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout;
return (...args: Parameters<T>) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
}
/**
* Sleep/delay function
*/
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}