import React, { useState, useRef, useEffect } from 'react'; import { Box, Link, Typography, Avatar, SxProps, Tooltip, IconButton } from '@mui/material'; import { Divider, useTheme } from '@mui/material'; import DeleteIcon from '@mui/icons-material/Delete'; import { useMediaQuery } from '@mui/material'; import { Candidate, CandidateAI } from 'types/types'; import { CopyBubble } from 'components/CopyBubble'; import { rest } from 'lodash'; import { AIBanner } from 'components/ui/AIBanner'; import { useAuth } from 'hooks/AuthContext'; interface CandidateInfoProps { candidate: Candidate; sx?: SxProps; action?: string; elevation?: number; variant?: 'minimal' | 'small' | 'normal' | undefined; } const CandidateInfo: React.FC = (props: CandidateInfoProps) => { const { candidate } = props; const { user, apiClient } = useAuth(); const { sx, action = '', variant = 'normal' } = props; const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')) || variant === 'minimal'; const ai: CandidateAI | null = 'isAI' in candidate ? (candidate as CandidateAI) : null; const isAdmin = user?.isAdmin; // State for description expansion const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false); const [shouldShowMoreButton, setShouldShowMoreButton] = useState(false); const descriptionRef = useRef(null); // Check if description needs truncation useEffect(() => { if (descriptionRef.current && candidate.description) { const element = descriptionRef.current; // Check if the scrollHeight is greater than clientHeight (meaning content is truncated) setShouldShowMoreButton(element.scrollHeight > element.clientHeight); } }, [candidate.description]); const deleteCandidate = async (candidateId: string | undefined): Promise => { if (candidateId) { await apiClient.deleteCandidate(candidateId); } }; if (!candidate) { return No user loaded.; } return ( {ai && } .MuiTypography-root': { m: 0 }, }} > {action !== '' && {action}} {action === '' && ( {candidate.fullName} )} {`/u/${candidate.username}`} { event.stopPropagation(); }} tooltip="Copy link" content={`${window.location.origin}/u/{candidate.username}`} /> {!isMobile && variant === 'normal' && ( {candidate.description} {shouldShowMoreButton && ( { e.preventDefault(); e.stopPropagation(); setIsDescriptionExpanded(!isDescriptionExpanded); }} sx={{ color: theme.palette.primary.main, textDecoration: 'none', cursor: 'pointer', fontSize: '0.725rem', fontWeight: 500, mt: 0.5, display: 'block', '&:hover': { textDecoration: 'underline', }, }} > [{isDescriptionExpanded ? 'less' : 'more'}] )} )} {variant !== 'small' && variant !== 'minimal' && ( <> {candidate.location && ( Location: {candidate.location.city},{' '} {candidate.location.state || candidate.location.country} )} {candidate.email && ( Email: {candidate.email} )} {candidate.phone && ( Phone: {candidate.phone} )} )} {isAdmin && ai && ( { e.stopPropagation(); deleteCandidate(candidate.id); }} > )} ); }; export { CandidateInfo };