import React, { useEffect, useRef, useState } from "react"; import { Box, Link, Typography, Avatar, Grid, SxProps, CardActions, Chip, Stack, CardHeader, Button, LinearProgress, IconButton, Tooltip, Card, CardContent, Divider, useTheme, useMediaQuery, TextField, Dialog, DialogTitle, DialogContent, DialogActions, Tabs, Tab, } from "@mui/material"; import PrintIcon from "@mui/icons-material/Print"; import { Delete as DeleteIcon, Restore as RestoreIcon, Save as SaveIcon, Edit as EditIcon, Description as DescriptionIcon, Work as WorkIcon, Person as PersonIcon, Schedule as ScheduleIcon, Visibility as VisibilityIcon, VisibilityOff as VisibilityOffIcon, } from "@mui/icons-material"; import PreviewIcon from "@mui/icons-material/Preview"; import EditDocumentIcon from "@mui/icons-material/EditDocument"; import { useReactToPrint } from "react-to-print"; import { useAuth } from "hooks/AuthContext"; import { useAppState } from "hooks/GlobalContext"; import { StyledMarkdown } from "components/StyledMarkdown"; import { Resume } from "types/types"; import { BackstoryTextField } from "components/BackstoryTextField"; import { JobInfo } from "./JobInfo"; interface ResumeInfoProps { resume: Resume; sx?: SxProps; action?: string; elevation?: number; variant?: "minimal" | "small" | "normal" | "all" | null; } const ResumeInfo: React.FC = (props: ResumeInfoProps) => { const { setSnack } = useAppState(); const { resume } = props; const { user, apiClient } = useAuth(); const { sx, action = "", elevation = 1, variant = "normal" } = props; const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down("md")) || variant === "minimal"; const isAdmin = user?.isAdmin; const [activeResume, setActiveResume] = useState({ ...resume }); const [isContentExpanded, setIsContentExpanded] = useState(false); const [shouldShowMoreButton, setShouldShowMoreButton] = useState(false); const [deleted, setDeleted] = useState(false); const [editDialogOpen, setEditDialogOpen] = useState(false); const [printDialogOpen, setPrintDialogOpen] = useState(false); const [editContent, setEditContent] = useState(""); const [saving, setSaving] = useState(false); const contentRef = useRef(null); const [tabValue, setTabValue] = useState("markdown"); const printContentRef = useRef(null); const reactToPrintFn = useReactToPrint({ contentRef: printContentRef, pageStyle: "@page { margin: 10px; }", }); useEffect(() => { if (resume && resume.id !== activeResume?.id) { setActiveResume(resume); } }, [resume, activeResume]); // Check if content needs truncation useEffect(() => { if (contentRef.current && resume.resume) { const element = contentRef.current; setShouldShowMoreButton(element.scrollHeight > element.clientHeight); } }, [resume.resume]); const deleteResume = async (id: string | undefined) => { if (id) { try { await apiClient.deleteResume(id); setDeleted(true); setSnack("Resume deleted successfully."); } catch (error) { setSnack("Failed to delete resume."); } } }; const handleReset = async () => { setActiveResume({ ...resume }); }; const handleSave = async () => { setSaving(true); try { const result = await apiClient.updateResume( activeResume.id || "", editContent ); const updatedResume = { ...activeResume, resume: editContent, updatedAt: new Date(), }; setActiveResume(updatedResume); setSnack("Resume updated successfully."); } catch (error) { setSnack("Failed to update resume."); } finally { setSaving(false); } }; const handleEditOpen = () => { setEditContent(activeResume.resume); setEditDialogOpen(true); }; if (!resume) { return No resume provided.; } const formatDate = (date: Date | undefined) => { if (!date) return "N/A"; return new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit", }).format(date); }; const handleTabChange = (event: React.SyntheticEvent, newValue: string) => { if (newValue === "print") { reactToPrintFn(); return; } setTabValue(newValue); }; return ( {/* Header Information */} {activeResume.candidate && ( Candidate )} {activeResume.candidate?.fullName || activeResume.candidateId} {activeResume.job && ( <> Job {activeResume.job.title} at {activeResume.job.company} )} Timeline Created: {formatDate(activeResume.createdAt)} Updated: {formatDate(activeResume.updatedAt)} Resume ID: {activeResume.id} {/* Resume Content */} {activeResume.resume && ( } sx={{ p: 0, pb: 1 }} action={ isAdmin && ( ) } /> {activeResume.resume} {shouldShowMoreButton && variant !== "all" && ( )} )} {variant === "all" && activeResume.resume && ( )} {/* Admin Controls */} {isAdmin && ( { e.stopPropagation(); handleEditOpen(); }} > { e.stopPropagation(); deleteResume(activeResume.id); }} > { e.stopPropagation(); handleReset(); }} > {saving && ( Saving resume... )} )} {/* Print Dialog */} {}} //setPrintDialogOpen(false)} maxWidth="lg" fullWidth fullScreen={true} > {/* Edit Dialog */} setEditDialogOpen(false)} maxWidth="lg" fullWidth disableEscapeKeyDown={true} fullScreen={true} > Edit Resume Content Resume for{" "} {activeResume.candidate?.fullName || activeResume.candidateId},{" "} {activeResume.job?.title || "No Job Title Assigned"},{" "} {activeResume.job?.company || "No Company Assigned"} Resume ID: # {activeResume.id} Last saved:{" "} {activeResume.updatedAt ? new Date(activeResume.updatedAt).toLocaleString() : "N/A"} } label="Markdown" /> } label="Preview" /> } label="Job" /> } label="Print" /> *:not(.Scrollable)": { flexShrink: 0 /* Prevent shrinking */, }, position: "relative", }} > {tabValue === "markdown" && ( setEditContent(value)} style={{ position: "relative", // maxHeight: "100%", height: "100%", width: "100%", display: "flex", minHeight: "100%", flexGrow: 1, flex: 1 /* Take remaining space in some-container */, overflowY: "auto" /* Scroll if content overflows */, }} placeholder="Enter resume content..." /> )} {tabValue === "preview" && ( <> )} {tabValue === "job" && activeResume.job && ( )} ); }; export { ResumeInfo };