196 lines · 7.5 KB
import { useState } from "react";
import { Link } from "@tanstack/react-router";
import { editComment } from "~/fns/issues";
import { useAction } from "~/hooks/use-action";
import { useViewer } from "~/hooks/use-viewer";
import { ReactionBar } from "./ReactionBar";
import { MarkdownEditor } from "./MarkdownEditor";
import { Avatar, Badge, Markdown, RelativeTime } from "./ui/Primitives";
import { Button } from "./ui/Button";
import type { getIssue } from "~/fns/issues";
import type { JsonValue } from "~/lib/types";
import { pullEventText } from "~/lib/pull-event-text";

type TimelineItem = Awaited<ReturnType<typeof getIssue>>["timeline"][number];

const REVIEW_COPY: Record<string, { label: string; tone: "green" | "red" | "neutral" }> = {
  approved: { label: "approved these changes", tone: "green" },
  changes_requested: { label: "requested changes", tone: "red" },
  commented: { label: "reviewed", tone: "neutral" },
  dismissed: { label: "review dismissed", tone: "neutral" },
};

function list(value: JsonValue | undefined): string {
  return Array.isArray(value) ? value.map(String).join(", ") : typeof value === "string" ? value : "";
}

function eventText(kind: string, data: { [key: string]: JsonValue }): string {
  switch (kind) {
    case "closed":
      return data.commit ? `closed this in ${String(data.commit).slice(0, 7)}` : "closed this";
    case "reopened":
      return "reopened this";
    case "renamed":
      return `changed the title from “${list(data.from)}” to “${list(data.to)}”`;
    case "labeled":
      return `set labels: ${list(data.labels) || "none"}`;
    case "assigned":
      return `set assignees: ${list(data.usernames) || "none"}`;
    case "merged":
      return `merged commit ${String(data.sha ?? "").slice(0, 7)} (${list(data.method)})`;