import { BaseBoxShapeUtil, HTMLContainer, TLBaseShape, } from "tldraw" import React, { useState, useRef, useEffect, useMemo, useCallback } from "react" import { StandardizedToolWrapper } from "../components/StandardizedToolWrapper" type IFathomTranscript = TLBaseShape< "FathomTranscript", { w: number h: number meetingId: string meetingTitle: string meetingUrl: string summary: string transcript: Array<{ speaker: string text: string timestamp: string }> actionItems: Array<{ text: string assignee?: string dueDate?: string }> isExpanded: boolean showTranscript: boolean showActionItems: boolean } > export class FathomTranscriptShape extends BaseBoxShapeUtil { static override type = "FathomTranscript" as const // Fathom Transcript theme color: Blue (same as FathomMeetings) static readonly PRIMARY_COLOR = "#3b82f6" getDefaultProps(): IFathomTranscript["props"] { return { w: 600, h: 400, meetingId: "", meetingTitle: "", meetingUrl: "", summary: "", transcript: [], actionItems: [], isExpanded: false, showTranscript: true, showActionItems: true, } } component(shape: IFathomTranscript) { const { w, h, meetingId, meetingTitle, meetingUrl, summary, transcript, actionItems, isExpanded, showTranscript, showActionItems } = shape.props const [isHovering, setIsHovering] = useState(false) const [isMinimized, setIsMinimized] = useState(false) const isSelected = this.editor.getSelectedShapeIds().includes(shape.id) const toggleExpanded = useCallback(() => { this.editor.updateShape({ id: shape.id, type: 'FathomTranscript', props: { ...shape.props, isExpanded: !isExpanded } }) }, [shape.id, shape.props, isExpanded]) const toggleTranscript = useCallback(() => { this.editor.updateShape({ id: shape.id, type: 'FathomTranscript', props: { ...shape.props, showTranscript: !showTranscript } }) }, [shape.id, shape.props, showTranscript]) const toggleActionItems = useCallback(() => { this.editor.updateShape({ id: shape.id, type: 'FathomTranscript', props: { ...shape.props, showActionItems: !showActionItems } }) }, [shape.id, shape.props, showActionItems]) const formatTimestamp = (timestamp: string) => { // Convert timestamp to readable format const seconds = parseInt(timestamp) const minutes = Math.floor(seconds / 60) const remainingSeconds = seconds % 60 return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}` } const buttonStyle: React.CSSProperties = { padding: '4px 8px', fontSize: '10px', border: '1px solid #ccc', borderRadius: '4px', backgroundColor: 'white', cursor: 'pointer', } // Custom header content with meeting info and toggle buttons const headerContent = (
🎥 Fathom Meeting {meetingId && #{meetingId}}
) const handleMinimize = () => { setIsMinimized(!isMinimized) } const handleClose = () => { this.editor.deleteShape(shape.id) } const contentStyle: React.CSSProperties = { padding: '16px', flex: 1, overflow: 'auto', color: 'black', fontSize: '12px', lineHeight: '1.4', cursor: 'pointer', transition: 'background-color 0.2s ease', display: 'flex', flexDirection: 'column', gap: '12px', } const transcriptEntryStyle: React.CSSProperties = { marginBottom: '8px', padding: '8px', backgroundColor: '#f8f9fa', borderRadius: '4px', borderLeft: '3px solid #007bff', } const actionItemStyle: React.CSSProperties = { marginBottom: '6px', padding: '6px', backgroundColor: '#fff3cd', borderRadius: '4px', borderLeft: '3px solid #ffc107', } return (
{/* Meeting Title */}

{meetingTitle || 'Untitled Meeting'}

{meetingUrl && ( e.stopPropagation()} > View in Fathom → )}
{/* Summary */} {summary && (

📋 Summary

{summary}
)} {/* Action Items */} {showActionItems && actionItems.length > 0 && (

✅ Action Items ({actionItems.length})

{actionItems.map((item, index) => (
{item.text}
{item.assignee && (
👤 {item.assignee}
)} {item.dueDate && (
📅 {item.dueDate}
)}
))}
)} {/* Transcript */} {showTranscript && transcript.length > 0 && (

💬 Transcript ({transcript.length} entries)

{transcript.map((entry, index) => (
{entry.speaker} {formatTimestamp(entry.timestamp)}
{entry.text}
))}
)} {/* Empty state */} {!summary && transcript.length === 0 && actionItems.length === 0 && (
No meeting data available
)}
) } indicator(shape: IFathomTranscript) { return } }