mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-01 01:33:12 +00:00
* 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
145 lines
3.1 KiB
TypeScript
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("");
|
|
}
|