GitFOSS
.ts
TypeScript
(application/typescript)
// 1st-party
import type { ReactIsland } from "@ethicdevs/react-monolith";
// 3rd-party
import React, { useCallback, useMemo, useState } from "react";
// app
import type { RepositoryObject } from "../types";
import { Grid } from "../components/Grid";

export interface RepositoryCommitSummaryLineProps {
  orgSlug: string;
  repoSlug: string;
  commit: RepositoryObject;
}

const MAX_COMMIT_LINE_LENGTH = 60;
const TRAILING_CHAR = " ...";
const TRAILING_CHAR_LENGTH = TRAILING_CHAR.length;

const RepositoryCommitSummaryLine: ReactIsland<RepositoryCommitSummaryLineProps> =
  ({ orgSlug, repoSlug, commit }) => {
    const [isFullSubjectShown, setIsFullSubjectShown] =
      useState<boolean>(false);

    const toggleFullSubjectVisibility = useCallback(
      (ev: React.MouseEvent<HTMLSpanElement>) => {
        ev.preventDefault();
        setIsFullSubjectShown((prevVisibility) => !prevVisibility);
      },
      [setIsFullSubjectShown]
    );

    const isSubjectTooLongForDisplay = useMemo(
      () => commit.subject.length > MAX_COMMIT_LINE_LENGTH,
      [commit.subject.length]
    );

    const subject = useMemo(
      () =>
        isSubjectTooLongForDisplay
          ? `${commit.subject.substring(
              0,
              MAX_COMMIT_LINE_LENGTH - TRAILING_CHAR_LENGTH
            )}`
          : commit.subject,
      [commit.subject]
    );

    return (
      <Grid.Row gap={8} alignItems={"flex-start"}>
        <Grid.Col fluid>
          <strong>{commit.author.name}</strong>
          <span style={{ flex: 1 }}>
            <a href={`/${orgSlug}/${repoSlug}/show/${commit.commit}`}>
              {subject}
            </a>
            {isSubjectTooLongForDisplay ? (
              <span onClick={toggleFullSubjectVisibility}>{TRAILING_CHAR}</span>
            ) : null}
          </span>
          {isFullSubjectShown ? <code>{commit.subject}</code> : null}
        </Grid.Col>
        <Grid.Col flex={"0 0 205px"} alignItems={"flex-end"}>
          <span>
            <a href={`/${orgSlug}/${repoSlug}/show/${commit.commit}`}>
              {commit.abbreviated_commit}
            </a>
            {commit.abbreviated_parent.trim() != "" ? (
              <a href={`/${orgSlug}/${repoSlug}/show/${commit.parent}`}>
                {` (parent ${commit.abbreviated_parent})`}
              </a>
            ) : null}
          </span>
          <span>{new Date(commit.author.date).toLocaleString()}</span>
        </Grid.Col>
      </Grid.Row>
    );
  };

RepositoryCommitSummaryLine.displayName = "RepositoryCommitSummaryLine";
export default RepositoryCommitSummaryLine;