import { useMemo, useState } from 'react'; import { Loader2 } from 'lucide-react'; import { BulkUpdateField } from '../../wailsjs/go/main/App'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from '@/components/ui/select'; type FieldKind = 'status' | 'text'; type FieldDef = { id: string; label: string; group: string; kind: FieldKind; upper?: boolean }; // Fields a bulk edit may target. status → Y/N/R/I dropdown; text → free input. // upper:true uppercases code-like values (callsign, grid, refs). The id matches // the backend BulkUpdateField whitelist. const FIELDS: FieldDef[] = [ // QSL / upload status { id: 'lotw_sent', label: 'LoTW sent', group: 'QSL / upload', kind: 'status' }, { id: 'lotw_rcvd', label: 'LoTW received', group: 'QSL / upload', kind: 'status' }, { id: 'eqsl_sent', label: 'eQSL sent', group: 'QSL / upload', kind: 'status' }, { id: 'eqsl_rcvd', label: 'eQSL received', group: 'QSL / upload', kind: 'status' }, { id: 'qsl_sent', label: 'Paper QSL sent', group: 'QSL / upload', kind: 'status' }, { id: 'qsl_rcvd', label: 'Paper QSL received', group: 'QSL / upload', kind: 'status' }, { id: 'qrz_upload', label: 'QRZ.com upload', group: 'QSL / upload', kind: 'status' }, { id: 'clublog_upload', label: 'Club Log upload', group: 'QSL / upload', kind: 'status' }, { id: 'hrdlog_upload', label: 'HRDLog upload', group: 'QSL / upload', kind: 'status' }, { id: 'qsl_via', label: 'QSL via', group: 'QSL / upload', kind: 'text' }, // My station / operator { id: 'station_callsign', label: 'Station callsign', group: 'My station', kind: 'text', upper: true }, { id: 'operator', label: 'Operator', group: 'My station', kind: 'text', upper: true }, { id: 'my_grid', label: 'My grid', group: 'My station', kind: 'text', upper: true }, { id: 'my_antenna', label: 'My antenna', group: 'My station', kind: 'text' }, { id: 'my_rig', label: 'My rig', group: 'My station', kind: 'text' }, { id: 'my_street', label: 'My street', group: 'My station', kind: 'text' }, { id: 'my_city', label: 'My city', group: 'My station', kind: 'text' }, { id: 'my_postal_code', label: 'My postal code', group: 'My station', kind: 'text' }, { id: 'my_country', label: 'My country', group: 'My station', kind: 'text' }, { id: 'my_state', label: 'My state', group: 'My station', kind: 'text', upper: true }, { id: 'my_cnty', label: 'My county', group: 'My station', kind: 'text' }, { id: 'my_iota', label: 'My IOTA', group: 'My station', kind: 'text', upper: true }, { id: 'my_sota_ref', label: 'My SOTA ref', group: 'My station', kind: 'text', upper: true }, { id: 'my_pota_ref', label: 'My POTA ref', group: 'My station', kind: 'text', upper: true }, { id: 'my_wwff_ref', label: 'My WWFF ref', group: 'My station', kind: 'text', upper: true }, { id: 'my_sig', label: 'My SIG', group: 'My station', kind: 'text' }, { id: 'my_sig_info', label: 'My SIG info', group: 'My station', kind: 'text' }, // Misc { id: 'comment', label: 'Comment', group: 'Misc', kind: 'text' }, { id: 'notes', label: 'Notes', group: 'Misc', kind: 'text' }, { id: 'rig', label: 'Rig (contacted)', group: 'Misc', kind: 'text' }, { id: 'ant', label: 'Antenna (contacted)', group: 'Misc', kind: 'text' }, ]; const STATUS_VALUES: { v: string; label: string }[] = [ { v: 'Y', label: 'Y — Yes / uploaded' }, { v: 'N', label: 'N — No' }, { v: 'R', label: 'R — Requested' }, { v: 'I', label: 'I — Ignore' }, { v: '_', label: '(blank — clear)' }, ]; const GROUPS = ['QSL / upload', 'My station', 'Misc']; type Props = { open: boolean; ids: number[]; onClose: () => void; onApplied: (n: number) => void; }; // BulkEditModal sets one QSL/upload status field to a chosen value across the // selected QSOs — e.g. flip a filtered batch of imported contacts from N to R // so they become eligible for upload. export function BulkEditModal({ open, ids, onClose, onApplied }: Props) { const [field, setField] = useState('hrdlog_upload'); const [statusValue, setStatusValue] = useState('R'); const [textValue, setTextValue] = useState(''); const [busy, setBusy] = useState(false); const [error, setError] = useState(''); const def = useMemo(() => FIELDS.find((f) => f.id === field) ?? FIELDS[0], [field]); const isStatus = def.kind === 'status'; const effectiveValue = isStatus ? (statusValue === '_' ? '' : statusValue) : textValue.trim(); async function apply() { setBusy(true); setError(''); try { const n = await BulkUpdateField(ids as any, field, effectiveValue); onApplied(Number(n) || 0); onClose(); } catch (e: any) { setError(String(e?.message ?? e)); } finally { setBusy(false); } } return ( { if (!o) onClose(); }}> Bulk edit field Set one field on the {ids.length} selected QSO{ids.length > 1 ? 's' : ''}. This overwrites the current value — there is no undo.
{isStatus ? ( ) : ( setTextValue(def.upper ? e.target.value.toUpperCase() : e.target.value)} /> )}
Will set {def.label} ={' '} {effectiveValue === '' ? '(blank)' : effectiveValue} on {ids.length} QSO{ids.length > 1 ? 's' : ''}.
{error &&
{error}
}
); }