// SendEQSLModal — per-QSO eQSL flow: render the default template with the // QSO's data, show the exact card, send it as a JPEG e-mail attachment on // explicit confirmation (never automatic). On success the backend stamps // eqsl_sent and emits "qsl:sent" so the grid refreshes. import { useEffect, useRef, useState } from 'react'; import { Loader2, Mail, CheckCircle2 } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { QSLDefaultTemplateID, RenderEQSL, SendEQSL, } from '../../../wailsjs/go/main/App'; import type { RenderModel } from './qslTypes'; import { loadCardAssets, type CardAssets } from './qslAssets'; import { CardPreview } from './CardPreview'; import { rasterizeCard } from './rasterize'; interface Props { open: boolean; qsoId: number | null; onClose: () => void; onOpenDesigner: () => void; } export function SendEQSLModal({ open, qsoId, onClose, onOpenDesigner }: Props) { const [model, setModel] = useState(null); const [assets, setAssets] = useState(null); const [templateId, setTemplateId] = useState(0); const [busy, setBusy] = useState(false); const [sent, setSent] = useState(false); const [error, setError] = useState(''); const svgEl = useRef(null); useEffect(() => { if (!open || !qsoId) return; setModel(null); setAssets(null); setSent(false); setError(''); void (async () => { try { const tid = await QSLDefaultTemplateID(); setTemplateId(tid); if (!tid) return; // no template yet — offer the designer below const m = JSON.parse(await RenderEQSL(qsoId, tid)) as RenderModel; setModel(m); setAssets(await loadCardAssets(m.template, tid)); } catch (e) { setError(String(e)); } })(); }, [open, qsoId]); async function send() { if (!qsoId || !model || !svgEl.current) return; setBusy(true); setError(''); try { const card = model.template.card; const jpeg = await rasterizeCard(svgEl.current, card.w, card.h, 'image/jpeg'); await SendEQSL(qsoId, templateId, jpeg); setSent(true); // Auto-close shortly after the success tick (the grid refreshes on the // qsl:sent event); the user doesn't need to dismiss it manually. window.setTimeout(onClose, 1100); } catch (e) { setError(String(e)); } finally { setBusy(false); } } return ( !v && onClose()}> Send OpsLog QSL by e-mail
{error && (
{error}
)} {open && !templateId && !error && (

No QSL template yet — design one first (drop a few photos, pick a layout).

)} {templateId > 0 && !model && !error && (
Preparing the card…
)} {model && assets && (
{ svgEl.current = el; }} />
)}
{sent ? (
OpsLog QSL sent.
) : ( <> )}
); }