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.Col fluid nowrap>
        <Grid.Row gap={8} alignItems={"flex-start"}>
          <Grid.Col fluid>
            <strong>{commit.author.name}</strong>
            <span style={{ marginTop: 8 }}>
              <a href={`/${orgSlug}/${repoSlug}/show/${commit.commit}`}>
                {subject}
              </a>
              {isSubjectTooLongForDisplay ? (
                <span onClick={toggleFullSubjectVisibility}>
                  {TRAILING_CHAR}
                </span>
              ) : null}
            </span>
          </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 style={{ marginTop: 8 }}>
              {new Date(commit.author.date).toLocaleString()}
            </span>
          </Grid.Col>
        </Grid.Row>
        {isFullSubjectShown ? (
          <code style={{ marginTop: 8 }}>{commit.subject}</code>
        ) : null}
      </Grid.Col>
    );
  };

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