All files / src/features/Events/EventDetail/host AssignHostRow.tsx

100% Statements 7/7
100% Branches 8/8
100% Functions 3/3
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80                  1x 1x                                   1x 95x                                                     2x                             95x                
import { Stack } from "@mui/material";
import { CheckIcon } from "@phosphor-icons/react";
import { ACTION_DENY_MESSAGE } from "@constants/permissions";
import GiveButton from "@shared/Button/GiveButton";
import GiveTooltip from "@shared/Tooltip/GiveTooltip";
import { GiveMemberNameCell } from "@features/Settings/Team/components/GiveMemberNameCell";
import { styled } from "@theme/v2/Provider";
import { AssignableHostRow } from "./host.types";
 
export const ASSIGNED_LABEL = "Assigned";
export const ASSIGN_LABEL = "Assign";
 
type Props = {
  row: AssignableHostRow;
  /** True while this row's own assign/unassign call is in flight. */
  isPending: boolean;
  canAssign: boolean;
  onToggle: (row: AssignableHostRow) => void;
};
 
/**
 * One row of the Assign Host modal (frame 8181-61190): the host's identity and
 * the single control that both assigns and unassigns them.
 *
 * There is no separate unassign action by design — the mockup gives the
 * assigned row's "✓ Assigned" the unassign click, so the row's state is also
 * its affordance.
 */
const AssignHostRow = ({ row, isPending, canAssign, onToggle }: Props) => {
  return (
    <Row direction="row" alignItems="center" gap="12px">
      {/* The same identity block the Host tab's rows draw, at the modal's
          smaller pairing — one component, so the two lists cannot drift. */}
      <GiveMemberNameCell
        size="sm"
        imageURL={row.imageURL}
        firstName={row.name}
        email={row.email}
        // A host with no name on file leads with their email here, so the name
        // line is dropped rather than rendered blank: this row is not a table
        // column that has to keep the email in a fixed position.
        fallbackToEmail
      />
      <GiveTooltip
        disableHoverListener={canAssign}
        title={ACTION_DENY_MESSAGE}
        fluidWidth
      >
        <GiveButton
          // Ghost + check for the assigned state, outline for the invitation to
          // act — the two read as state and action rather than two buttons.
          variant={row.isAssigned ? "ghost" : "outline"}
          size="small"
          label={row.isAssigned ? ASSIGNED_LABEL : ASSIGN_LABEL}
          startIcon={row.isAssigned ? <CheckIcon size={16} /> : undefined}
          disabled={!canAssign || isPending}
          onClick={() => onToggle(row)}
          sx={{ whiteSpace: "nowrap", flexShrink: 0 }}
          data-testid={`assign-host-action-${row.id}`}
        />
      </GiveTooltip>
    </Row>
  );
};
 
export default AssignHostRow;
 
/**
 * The mockup's 54px row: 8px/12px insets around a 38px identity block, with the
 * rows separated by a 4px gap rather than a rule.
 */
const Row = styled(Stack)(({ theme }) => ({
  minHeight: "54px",
  padding: "8px 12px",
  borderRadius: "8px",
  "&:hover": {
    backgroundColor: theme.palette.surface?.secondary,
  },
}));