All files / src/features/GiveConversation/components ThreadItem.tsx

93.75% Statements 15/16
66.66% Branches 10/15
83.33% Functions 5/6
100% Lines 14/14

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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                              3x                                               45x 45x 45x 45x 45x       99x   45x 45x     1x                                                                                       3x                 3x 273x 45x                  
import { Stack } from "@mui/material";
import GiveText from "@shared/Text/GiveText";
import GiveTruncateText from "@shared/Text/GiveTruncateText";
import { styled } from "@theme/v2/Provider";
import { ConversationCounterVariant, User } from "../types";
import { Box } from "@mui/material";
import CounterCircle from "./CounterCircle";
import { useConversationContext } from "../ConversationProvider";
import { usePreciseTimeFormat } from "@utils/date.helpers";
import { every, isEmpty } from "lodash";
import { ParsedTextRenderer } from "./ParsedTextRenderer";
import { getFallbackString } from "../utils";
import FloatingAvatars from "./FloatingAvatars";
import { useCustomThemeV2 } from "@theme/hooks/useCustomThemeV2";
 
const textCommonProps = { fontSize: "14px" };
interface Props {
  title: string;
  body: string;
  date: number;
  id: number;
  primaryUser: User;
  secondaryUser?: User;
  count?: number;
  counterVariant?: ConversationCounterVariant;
  taskID?: number;
}
 
export default function ThreadItem({
  primaryUser,
  secondaryUser,
  title,
  body,
  date,
  id,
  count,
  counterVariant,
  taskID,
}: Props) {
  const { openThread, searchState } = useConversationContext();
  const { formatPreciseTime } = usePreciseTimeFormat();
  const { isMobileView } = useCustomThemeV2();
  const primaryFallbackString = getFallbackString(primaryUser);
  const secondaryFallbackString = secondaryUser
    ? getFallbackString(secondaryUser)
    : "";
 
  const areAllValuesEmpty = every(secondaryUser, (value) => isEmpty(value));
  //if is a conversation without a message body => is a document uploaded without message
  const usedBody = body ? body : "Documents Attached";
  return (
    <Wrapper
      direction="row"
      onClick={() => openThread(id, title, taskID, count || 0)}
      id={`thread-${id?.toString()}`}
      data-testid="give-conversation-thread-list-item"
      isMobileView={isMobileView}
    >
      <FloatingAvatars
        primaryImageURL={primaryUser.imageURL}
        primaryFallbackString={primaryFallbackString}
        {...(!areAllValuesEmpty && {
          secondaryFallbackString: secondaryFallbackString,
          secondaryImageURL: secondaryUser?.imageURL,
        })}
      />
      <Stack gap="8px" flex={1}>
        <GiveTruncateText variant="bodyS" fontWeight={500} lineClamp={1}>
          <ParsedTextRenderer
            text={title}
            searchWord={searchState.searchValue}
            sx={{ ...textCommonProps, fontWeight: 500 }}
            mentionedTextSx={{ ...textCommonProps, fontWeight: 500 }}
            searchMatchTextSx={textCommonProps}
            id={id}
          />
        </GiveTruncateText>
        <GiveTruncateText useParse lineClamp={2} variant="bodyS">
          <ParsedTextRenderer
            text={usedBody}
            sx={textCommonProps}
            mentionedTextSx={textCommonProps}
            searchMatchTextSx={textCommonProps}
          />
        </GiveTruncateText>
 
        <GiveText variant="bodyXS" color="secondary">
          {date && formatPreciseTime(date * 1000)}
        </GiveText>
      </Stack>
      {!!count && !!counterVariant && (
        <CounterCircle count={count} variant={counterVariant} capped />
      )}
    </Wrapper>
  );
}
 
const FloatingImageWrapper = styled(Box)(({ theme }) => ({
  position: "absolute",
  zIndex: 2,
  top: "8px",
  left: "8px",
  borderRadius: "40px",
  border: `1px solid ${theme.palette.surface?.primary}`,
}));
 
const Wrapper = styled(Stack, {
  shouldForwardProp: (prop) => prop !== "isMobileView",
})<{ isMobileView?: boolean }>(({ theme, isMobileView }) => ({
  padding: isMobileView ? "16px 20px" : "16px 12px",
  gap: "12px",
  borderBottom: `1px solid ${theme.palette.border?.primary}`,
  "&:hover": {
    backgroundColor: theme.palette.primitive?.transparent["darken-2"],
    cursor: "pointer",
  },
}));