backstory/frontend/src/components/ui/CandidateInfo.tsx

160 lines
5.0 KiB
TypeScript

import React from 'react';
import { Box, Link, Typography, Avatar, Grid, SxProps } from '@mui/material';
import {
Card,
CardContent,
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';
import { DeleteConfirmation } from '../DeleteConfirmation';
interface CandidateInfoProps {
candidate: Candidate;
sx?: SxProps;
action?: string;
elevation?: number;
variant?: "small" | "normal" | null
};
const CandidateInfo: React.FC<CandidateInfoProps> = (props: CandidateInfoProps) => {
const { candidate } = props;
const { user, apiClient } = useAuth();
const {
sx,
action = '',
elevation = 1,
variant = "normal"
} = props;
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const ai: CandidateAI | null = ('isAI' in candidate) ? candidate as CandidateAI : null;
const isAdmin = user?.isAdmin;
const deleteCandidate = async (candidateId: string | undefined) => {
if (candidateId) {
await apiClient.deleteCandidate(candidateId);
}
}
if (!candidate) {
return <Box>No user loaded.</Box>;
}
return (
<Box
sx={{
display: "flex",
borderColor: 'transparent',
borderWidth: 2,
borderStyle: 'solid',
transition: 'all 0.3s ease',
flexGrow: 1,
p: isMobile ? 1 : 3,
height: '100%',
flexDirection: 'column',
alignItems: 'stretch',
position: "relative",
overflow: "hidden",
...sx
}}
{...rest}
>
{ai && <AIBanner />}
<Box sx={{ display: "flex", flexDirection: "row" }}>
<Avatar
src={candidate.profileImage ? `/api/1.0/candidates/profile/${candidate.username}` : ''}
alt={`${candidate.fullName}'s profile`}
sx={{
alignSelf: "flex-start",
width: isMobile ? 40 : 80,
height: isMobile ? 40 : 80,
border: '2px solid #e0e0e0',
}}
/>
<Box sx={{ ml: 1 }}>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
mb: 1
}}>
<Box>
<Box sx={{
display: "flex",
flexDirection: isMobile ? "column" : "row",
alignItems: "left",
gap: 1, "& > .MuiTypography-root": { m: 0 }
}}>
{
action !== '' &&
<Typography variant="body1">{action}</Typography>
}
{action === '' &&
<Typography variant="h5" component="h1"
sx={{
fontWeight: 'bold',
whiteSpace: 'nowrap'
}}>
{candidate.fullName}
</Typography>
}
</Box>
<Box sx={{ fontSize: "0.75rem", alignItems: "center" }} >
<Link href={`/u/${candidate.username}`}>{`/u/${candidate.username}`}</Link>
<CopyBubble
onClick={(event: any) => { event.stopPropagation() }}
tooltip="Copy link" content={`${window.location.origin}/u/{candidate.username}`} />
{isAdmin && ai &&
<DeleteConfirmation
onDelete={() => { deleteCandidate(candidate.id); }}
sx={{ minWidth: 'auto', px: 2, maxHeight: "min-content", color: "red" }}
action="delete"
label="user"
title="Delete AI user"
icon=<DeleteIcon />
message={`Are you sure you want to delete ${candidate.username}? This action cannot be undone.`}
/>}
</Box>
</Box>
</Box>
{(!isMobile || variant !== "small") && <Typography variant="body1" color="text.secondary">
{candidate.description}
</Typography>}
{variant !== "small" && <>
<Divider sx={{ my: 2 }} />
{candidate.location &&
<Typography variant="body2" sx={{ mb: 1 }}>
<strong>Location:</strong> {candidate.location.city}, {candidate.location.state || candidate.location.country}
</Typography>
}
{candidate.email &&
<Typography variant="body2" sx={{ mb: 1 }}>
<strong>Email:</strong> {candidate.email}
</Typography>
}
{candidate.phone && <Typography variant="body2">
<strong>Phone:</strong> {candidate.phone}
</Typography>
}
</>}
</Box>
</Box>
</Box>
);
};
export { CandidateInfo };