Files
tolaria/src/components/useEditorPdfExport.ts

158 lines
4.6 KiB
TypeScript
Raw Normal View History

2026-05-29 19:15:07 +02:00
import { useCallback, useEffect, useState, type MutableRefObject } from 'react'
import { translate, type AppLocale } from '../lib/i18n'
import { trackNotePdfExportFailed } from '../lib/productAnalytics'
import {
2026-05-31 14:43:15 +02:00
notePdfExportFilename,
2026-05-29 19:15:07 +02:00
printActiveNoteAsPdf,
type NotePdfExportSource,
} from '../utils/notePdfExport'
import type { VaultEntry } from '../types'
2026-05-31 14:43:15 +02:00
import { isMarkdownEntry } from '../utils/typeDefinitions'
2026-05-29 19:15:07 +02:00
interface EditorPdfExportTab {
entry: VaultEntry
}
interface UseEditorPdfExportParams {
activeTab: EditorPdfExportTab | null
diffMode: boolean
handleToggleDiffExclusive: () => void | Promise<void>
handleToggleRawExclusive: () => void
locale?: AppLocale
onToast?: (message: string | null) => void
pdfExportRef?: MutableRefObject<((source?: NotePdfExportSource) => void) | null>
rawMode: boolean
}
2026-05-31 14:43:15 +02:00
interface PreparePdfExportModeParams {
diffMode: boolean
handleToggleDiffExclusive: () => void | Promise<void>
handleToggleRawExclusive: () => void
rawMode: boolean
setPendingSource: (source: NotePdfExportSource | null) => void
source: NotePdfExportSource
}
interface PdfExportErrorParams {
error: unknown
locale: AppLocale
onToast?: (message: string | null) => void
}
interface PendingPdfExportParams {
activeTab: EditorPdfExportTab | null
diffMode: boolean
locale: AppLocale
onToast?: (message: string | null) => void
pendingSource: NotePdfExportSource | null
rawMode: boolean
setPendingSource: (source: NotePdfExportSource | null) => void
}
function isMarkdownTab(activeTab: EditorPdfExportTab | null): activeTab is EditorPdfExportTab {
return Boolean(activeTab && isMarkdownEntry(activeTab.entry))
2026-05-29 19:15:07 +02:00
}
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error)
}
2026-05-31 14:43:15 +02:00
function reportPdfExportError({ error, locale, onToast }: PdfExportErrorParams): void {
onToast?.(translate(locale, 'editor.exportPdf.failed', { error: errorMessage(error) }))
}
async function preparePdfExportMode({
2026-05-29 19:15:07 +02:00
diffMode,
handleToggleDiffExclusive,
handleToggleRawExclusive,
rawMode,
2026-05-31 14:43:15 +02:00
setPendingSource,
source,
}: PreparePdfExportModeParams): Promise<void> {
if (diffMode) await Promise.resolve(handleToggleDiffExclusive())
if (rawMode) handleToggleRawExclusive()
setPendingSource(source)
}
2026-05-29 19:15:07 +02:00
2026-05-31 14:43:15 +02:00
function usePendingPdfExport({
activeTab,
diffMode,
locale,
onToast,
pendingSource,
rawMode,
setPendingSource,
}: PendingPdfExportParams): void {
2026-05-29 19:15:07 +02:00
useEffect(() => {
if (!pendingSource || diffMode || rawMode || !isMarkdownTab(activeTab)) return
let cancelled = false
2026-05-31 14:43:15 +02:00
const defaultFilename = notePdfExportFilename(activeTab.entry.filename)
2026-05-29 19:15:07 +02:00
2026-05-31 14:43:15 +02:00
void printActiveNoteAsPdf({ defaultFilename, source: pendingSource })
2026-05-29 19:15:07 +02:00
.catch((error) => {
2026-05-31 14:43:15 +02:00
if (!cancelled) reportPdfExportError({ error, locale, onToast })
2026-05-29 19:15:07 +02:00
})
.finally(() => {
if (!cancelled) setPendingSource(null)
})
return () => {
cancelled = true
}
2026-05-31 14:43:15 +02:00
}, [activeTab, diffMode, locale, onToast, pendingSource, rawMode, setPendingSource])
}
2026-05-29 19:15:07 +02:00
2026-05-31 14:43:15 +02:00
function useRegisteredPdfExportHandler(
pdfExportRef: MutableRefObject<((source?: NotePdfExportSource) => void) | null> | undefined,
exportNoteAsPdf: (source?: NotePdfExportSource) => void,
): void {
2026-05-29 19:15:07 +02:00
useEffect(() => {
if (!pdfExportRef) return undefined
pdfExportRef.current = exportNoteAsPdf
return () => {
if (pdfExportRef.current === exportNoteAsPdf) {
pdfExportRef.current = null
}
}
}, [exportNoteAsPdf, pdfExportRef])
2026-05-31 14:43:15 +02:00
}
export function useEditorPdfExport({
activeTab,
diffMode,
handleToggleDiffExclusive,
handleToggleRawExclusive,
locale = 'en',
onToast,
pdfExportRef,
rawMode,
}: UseEditorPdfExportParams): (source?: NotePdfExportSource) => void {
const [pendingSource, setPendingSource] = useState<NotePdfExportSource | null>(null)
const exportNoteAsPdf = useCallback((source: NotePdfExportSource = 'breadcrumb') => {
if (!isMarkdownTab(activeTab)) {
trackNotePdfExportFailed(source, 'export_unavailable')
onToast?.(translate(locale, 'editor.exportPdf.unavailable'))
return
}
void preparePdfExportMode({
diffMode,
handleToggleDiffExclusive,
handleToggleRawExclusive,
rawMode,
setPendingSource,
source,
}).catch((error) => {
reportPdfExportError({ error, locale, onToast })
})
}, [activeTab, diffMode, handleToggleDiffExclusive, handleToggleRawExclusive, locale, onToast, rawMode])
usePendingPdfExport({ activeTab, diffMode, locale, onToast, pendingSource, rawMode, setPendingSource })
useRegisteredPdfExportHandler(pdfExportRef, exportNoteAsPdf)
2026-05-29 19:15:07 +02:00
return exportNoteAsPdf
}