Vectrum
Sign In
45 lines · 1.7 KB · TypeScript
import Link from "next/link";
import { answerInvitationAction } from "@/app/actions/orgs";
import { timeAgo } from "@/lib/format";
import { ROLE_INFO } from "@/lib/org-roles";
import type { OrgInvitation } from "@/lib/orgs";
import { ActionButton } from "./action-button";
import { CheckIcon } from "./icons";
import { ListRow } from "./settings-plate";
import { Avatar, avatarUrl, Box, Label } from "./ui";

/** Invitations to join organizations, for the person invited: accept (and land on the organization) or decline. */
export function OrgInvitations({ invitations }: { invitations: OrgInvitation[] }) {
  if (!invitations.length) return null;
  return (
    <Box>
      {invitations.map((inv) => (
        <ListRow
          key={inv.id}
          lead={<Avatar name={inv.org.name || inv.org.username} src={avatarUrl(inv.org)} size={32} />}
          title={
            <>
              <span>
                {inv.invitedBy ? `@${inv.invitedBy} invited you to join` : "You’re invited to join"}{" "}
                <Link href={`/${inv.org.username}`} className="hover:underline">
                  {inv.org.username}
                </Link>
              </span>
              <Label tone="accent">{ROLE_INFO[inv.role].title}</Label>
            </>
          }
          meta={
            <span className="type-meta text-ink3">
              {ROLE_INFO[inv.role].description} Sent {timeAgo(inv.createdAt)}.
            </span>
          }
        >
          <ActionButton action={answerInvitationAction.bind(null, inv.id, false)}>Decline</ActionButton>
          <ActionButton action={answerInvitationAction.bind(null, inv.id, true)} variant="primary" icon={<CheckIcon />}>
            Join
          </ActionButton>
        </ListRow>
      ))}
    </Box>
  );
}