import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { mergeSubmissionPresets } from '@shared/builtin-templates' import { useBookStore } from '@renderer/stores/useBookStore' import { useEditStore } from '@renderer/stores/useEditStore' import { useSettingsStore } from '@renderer/stores/useSettingsStore' import { useAppStore } from '@renderer/stores/useAppStore' import { useExportStore } from '@renderer/stores/useExportStore' import { ipcCall } from '@renderer/lib/ipc-client' export function ExportModal(): React.JSX.Element | null { const { t } = useTranslation() const open = useExportStore((s) => s.open) const close = useExportStore((s) => s.close) const showToast = useAppStore((s) => s.showToast) const bookId = useBookStore((s) => s.currentBookId) const chapters = useBookStore((s) => s.chapters) const target = useEditStore((s) => s.target) const customPresets = useSettingsStore((s) => s.submissionPresets) const defaultPresetId = useSettingsStore((s) => s.defaultSubmissionPresetId ?? 'builtin-webnovel') const presets = useMemo(() => mergeSubmissionPresets(customPresets ?? []), [customPresets]) const chapterId = target?.kind === 'chapter' ? target.id : null const chapter = chapterId ? chapters.find((c) => c.id === chapterId) : null const [presetId, setPresetId] = useState(defaultPresetId) const [preview, setPreview] = useState('') const [loading, setLoading] = useState(false) useEffect(() => { if (!open) return setPresetId(defaultPresetId) }, [open, defaultPresetId]) useEffect(() => { if (!open || !bookId || !chapterId) { setPreview('') return } setLoading(true) void ipcCall(() => window.electronAPI.export.formatChapter(bookId, chapterId, presetId)) .then((text) => setPreview(text.slice(0, 500))) .catch(() => setPreview('')) .finally(() => setLoading(false)) }, [open, bookId, chapterId, presetId]) const handleCopy = async (): Promise => { if (!bookId || !chapterId) return const text = await ipcCall(() => window.electronAPI.export.formatChapter(bookId, chapterId, presetId) ) await ipcCall(() => window.electronAPI.export.copyClipboard(text)) showToast(t('export.copied')) } const handleSaveTxt = async (): Promise => { if (!bookId || !chapterId || !chapter) return const text = await ipcCall(() => window.electronAPI.export.formatChapter(bookId, chapterId, presetId) ) const defaultName = `${chapter.title}.txt` const saved = await ipcCall(() => window.electronAPI.export.saveTxt(text, defaultName)) if (saved) { showToast(t('export.saved', { path: saved })) } } if (!open) return null return ( ) }