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
|
|
|
|
|
}
|