Flatlogic Bot 83cdb092cd 7
2026-05-15 19:17:21 +00:00

241 lines
5.8 KiB
TypeScript

import Link from 'next/link';
import React from 'react';
import BaseIcon from '../BaseIcon';
export const actionButtonClassName =
'inline-flex items-center justify-center rounded-[8px] border px-4 py-2 text-sm font-medium';
export const inputClassName =
'w-full rounded-[10px] border border-slate-200 bg-white px-4 py-3 text-[14px] text-slate-900 outline-none transition-colors placeholder:text-slate-400 focus:border-slate-300';
export const textAreaClassName = `${inputClassName} min-h-[132px] resize-y leading-6`;
export function formatDateTime(value?: string | null) {
if (!value) {
return 'No date';
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return value;
}
return date.toLocaleString('en-US', {
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
month: 'short',
year: 'numeric',
});
}
export function formatShortDate(value?: string | null) {
if (!value) {
return 'No activity yet';
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return value;
}
return date.toLocaleString('en-US', {
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
month: 'short',
});
}
export function formatRole(value?: string | null) {
if (!value) {
return 'Unknown';
}
return value
.replace(/_/g, ' ')
.replace(/\b\w/g, (letter) => letter.toUpperCase());
}
export function formatName(person: any) {
if (!person) {
return 'No user';
}
const fullName = [person.firstName, person.lastName].filter(Boolean).join(' ').trim();
if (fullName) {
return fullName;
}
if (person.email) {
return person.email;
}
if (person.name) {
return person.name;
}
if (person.title) {
return person.title;
}
return 'Unnamed record';
}
export function formatMoney(value: any) {
const number = Number(value || 0);
if (!number) {
return '$0.00';
}
return `$${number.toFixed(2)}`;
}
export function formatTokens(value: any) {
const number = Number(value || 0);
if (!number) {
return '0';
}
return number.toLocaleString('en-US');
}
export function EntityIntro({
backHref,
backLabel,
description,
kicker,
title,
}: {
backHref: string;
backLabel: string;
description: string;
kicker: string;
title: string;
}) {
return (
<div className="rounded-[12px] border border-slate-200 bg-white px-6 py-6">
<Link className="inline-flex items-center gap-2 text-[12px] font-medium text-slate-500" href={backHref}>
{backLabel}
</Link>
<p className="mt-4 text-[11px] font-medium uppercase tracking-[0.28em] text-slate-400">{kicker}</p>
<h1 className="mt-3 text-[2rem] font-semibold tracking-[-0.04em] text-slate-900">{title}</h1>
<p className="mt-3 max-w-3xl text-sm leading-6 text-slate-500">{description}</p>
</div>
);
}
export function EntitySection({
children,
description,
icon,
title,
}: {
children: React.ReactNode;
description: string;
icon: string;
title: string;
}) {
return (
<div className="rounded-[12px] border border-slate-200 bg-white px-6 py-6">
<div className="mb-5 flex items-start gap-3">
<div className="mt-0.5 inline-flex h-10 w-10 items-center justify-center rounded-[10px] border border-slate-200 bg-slate-50 text-slate-600">
<BaseIcon path={icon} size={20} />
</div>
<div>
<p className="text-[15px] font-medium text-slate-900">{title}</p>
<p className="mt-1 text-sm leading-6 text-slate-500">{description}</p>
</div>
</div>
{children}
</div>
);
}
export function EntityValueCard({
label,
value,
}: {
label: string;
value: React.ReactNode;
}) {
return (
<div className="rounded-[10px] border border-slate-200 px-4 py-3">
<p className="text-[11px] font-medium uppercase tracking-[0.18em] text-slate-400">{label}</p>
<div className="mt-2 text-[15px] leading-6 text-slate-900">{value}</div>
</div>
);
}
export function EntityLinkCard({
description,
href,
icon,
label,
value,
}: {
description: string;
href?: string;
icon: string;
label: string;
value: string;
}) {
const content = (
<div className="rounded-[10px] border border-slate-200 px-4 py-3 transition-colors hover:border-slate-300">
<div className="flex items-start gap-3">
<div className="mt-0.5 inline-flex h-9 w-9 items-center justify-center rounded-[10px] border border-slate-200 bg-slate-50 text-slate-600">
<BaseIcon path={icon} size={18} />
</div>
<div className="min-w-0">
<p className="text-[11px] font-medium uppercase tracking-[0.18em] text-slate-400">{label}</p>
<p className="mt-2 text-[15px] font-medium text-slate-900">{value}</p>
<p className="mt-1 text-[13px] leading-6 text-slate-500">{description}</p>
</div>
</div>
</div>
);
if (!href) {
return content;
}
return <Link href={href}>{content}</Link>;
}
export function EntityAsideCard({
children,
title,
}: {
children: React.ReactNode;
title: string;
}) {
return (
<div className="rounded-[12px] border border-slate-200 bg-white px-5 py-5">
<p className="text-[11px] font-medium uppercase tracking-[0.28em] text-slate-400">{title}</p>
<div className="mt-4">{children}</div>
</div>
);
}
export function EntityEmptyState({
description,
title,
}: {
description: string;
title: string;
}) {
return (
<div className="rounded-[12px] border border-dashed border-slate-200 bg-slate-50 px-6 py-12 text-center">
<p className="text-[11px] font-medium uppercase tracking-[0.2em] text-slate-400">No data</p>
<h2 className="mt-3 text-[22px] font-semibold tracking-[-0.03em] text-slate-900">{title}</h2>
<p className="mt-3 text-[14px] leading-6 text-slate-500">{description}</p>
</div>
);
}