shoc-frontend-new/src/lib/time-utils.ts
Alexandre Brandizzi 45909e7aa6
Complete vendor operations roadmap frontend (#52)
* feat(vendors): complete operations roadmap frontend

* test(vendors): cover work order assignment flow

* fix(vendors): address review feedback

* fix(vendors): prevent stale preference saves

* fix(vendors): require truthful appointment bounds
2026-07-24 18:10:45 -03:00

145 lines
3.1 KiB
TypeScript

export function timeSince(dateString: string): string {
if (!dateString) {
return "";
}
const d = new Date(dateString.endsWith("Z") ? dateString : `${dateString}Z`);
if (Number.isNaN(d.getTime())) {
return "";
}
const diffMs = Date.now() - d.getTime();
const mins = Math.floor(diffMs / 60000);
if (mins < 1) {
return "just now";
}
if (mins < 60) {
return `${mins}m ago`;
}
const hours = Math.floor(mins / 60);
if (hours < 24) {
return `${hours}h ago`;
}
const days = Math.floor(hours / 24);
if (days < 7) {
return `${days}d ago`;
}
return `${Math.floor(days / 7)}w ago`;
}
export function timeBetween(startStr: string, endStr: string): string {
if (!startStr || !endStr) {
return "";
}
const start = new Date(startStr.endsWith("Z") ? startStr : `${startStr}Z`);
const end = new Date(endStr.endsWith("Z") ? endStr : `${endStr}Z`);
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
return "";
}
const diffMs = end.getTime() - start.getTime();
const mins = Math.floor(diffMs / 60000);
if (mins < 60) {
return `${mins}m`;
}
const hours = Math.floor(mins / 60);
if (hours < 24) {
return `${hours}h`;
}
return `${Math.floor(hours / 24)}d`;
}
export function waitTimeColor(dateString: string): "green" | "yellow" | "red" | "" {
if (!dateString) {
return "";
}
const d = new Date(dateString.endsWith("Z") ? dateString : `${dateString}Z`);
const hours = (Date.now() - d.getTime()) / 3600000;
if (hours < 4) {
return "green";
}
if (hours < 24) {
return "yellow";
}
return "red";
}
export function formatDateTime(value: string): string {
if (!value) {
return "";
}
const normalized = value.endsWith("Z") ? value : `${value}Z`;
const date = new Date(normalized);
if (Number.isNaN(date.getTime())) {
return value;
}
const datePart = date.toLocaleDateString("en-CA");
const timePart = date.toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
const tz = date.toLocaleTimeString(undefined, { timeZoneName: "short" }).split(" ").pop();
return `${datePart} ${timePart} ${tz ?? ""}`.trim();
}
export function getWaitTimeTextClass(color: "green" | "yellow" | "red" | ""): string | undefined {
if (color === "green") {
return "text-green-600";
}
if (color === "yellow") {
return "text-yellow-600";
}
if (color === "red") {
return "text-red-600";
}
return undefined;
}
export function toDateInputValue(value: string | null | undefined): string {
if (!value) {
return "";
}
return value.split("T")[0] ?? value;
}
export function toDateTimeLocalInputValue(value: string | null | undefined): string {
if (!value) {
return "";
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return "";
}
const pad = (part: number) => String(part).padStart(2, "0");
return [
date.getFullYear(),
"-",
pad(date.getMonth() + 1),
"-",
pad(date.getDate()),
"T",
pad(date.getHours()),
":",
pad(date.getMinutes()),
].join("");
}