Ctrl K
ComunidadGuías…

lib/account-display.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
type MetadataValue = string | number | boolean | null | undefined;

export type UserIdentityLike = {
  email?: string | null;
  user_metadata?: Record<string, MetadataValue> | null;
  app_metadata?: Record<string, MetadataValue> | null;
};

const firstNameKeys = ["first_name", "given_name"];
const fullNameKeys = ["full_name", "name", "display_name"];
const usernameKeys = ["user_name", "preferred_username", "nickname"];
const avatarKeys = ["avatar_url", "picture", "image", "photo_url"];
const timezoneHeaders = ["x-vercel-ip-timezone", "cf-timezone", "x-timezone"];

function clean(value: unknown) {
  return typeof value === "string" ? value.trim() : "";
}

function firstToken(value: string) {
  const cleaned = value.trim().replace(/^@+/, "");
  if (!cleaned) return "";
  return cleaned.split(/[\s._-]+/).filter(Boolean)[0] ?? "";
}

function humanizeName(value: string) {
  const token = firstToken(value);
  if (!token) return "";
  if (token === token.toLowerCase() || token === token.toUpperCase()) {
    return `${token.charAt(0).toUpperCase()}${token.slice(1).toLowerCase()}`;
  }
  return token;
}

function firstMetadataValue(metadata: Record<string, MetadataValue> | null | undefined, keys: string[]) {
  for (const key of keys) {
    const value = clean(metadata?.[key]);
    if (value) return value;
  }
  return "";
}

function safeUrl(value: string) {
  if (!value) return "";
  try {
    const url = new URL(value);
    return url.protocol === "https:" || url.protocol === "http:" ? url.toString() : "";
  } catch {
    return "";
  }
}

export function accountDisplayName(user: UserIdentityLike | null | undefined) {
  const metadata = user?.user_metadata ?? {};
  const email = clean(user?.email);

  const providerName = firstMetadataValue(metadata, fullNameKeys);
  if (providerName) return providerName.replace(/^@+/, "");

  const username = firstMetadataValue(metadata, usernameKeys);
  if (username) return username.replace(/^@+/, "");

  if (email) return email.split("@")[0] ?? "";
  return "Builder";
}

export function accountFirstName(user: UserIdentityLike | null | undefined) {
  const metadata = user?.user_metadata ?? {};
  const email = clean(user?.email);

  const manualFirstName = firstMetadataValue(metadata, firstNameKeys);
  if (manualFirstName) return humanizeName(manualFirstName);

  const providerName = firstMetadataValue(metadata, fullNameKeys);
  if (providerName) return humanizeName(providerName);

  const username = firstMetadataValue(metadata, usernameKeys);
  if (username) return humanizeName(username);

  if (email) return humanizeName(email.split("@")[0] ?? "");
  return "Builder";
}

export function accountAvatarUrl(user: UserIdentityLike | null | undefined) {
  const metadata = user?.user_metadata ?? {};
  const appMetadata = user?.app_metadata ?? {};
  return safeUrl(firstMetadataValue(metadata, avatarKeys)) || safeUrl(firstMetadataValue(appMetadata, avatarKeys));
}

function validTimezone(value: string) {
  if (!value) return "";
  try {
    new Intl.DateTimeFormat("en", { timeZone: value }).format(new Date());
    return value;
  } catch {
    return "";
  }
}

export function timezoneFromHeaders(headersList: Headers) {
  for (const header of timezoneHeaders) {
    const timezone = validTimezone(headersList.get(header) ?? "");
    if (timezone) return timezone;
  }
  return "";
}

function hourForTimezone(date: Date, timezone?: string | null) {
  const hour = Number(
    new Intl.DateTimeFormat("en", {
      hour: "numeric",
      hour12: false,
      timeZone: validTimezone(timezone ?? "") || undefined,
    }).format(date)
  );

  return Number.isFinite(hour) ? hour % 24 : date.getHours();
}

export function timeGreeting(date = new Date(), timezone?: string | null) {
  const hour = hourForTimezone(date, timezone);

  if (hour >= 5 && hour < 12) return "Good morning";
  if (hour >= 12 && hour < 17) return "Good afternoon";
  if (hour >= 17 && hour < 22) return "Good evening";
  return "Good night";
}