import { useParams, useNavigate } from "react-router-dom"; import { useEffect, useState } from "react"; import { toast } from "@/hooks/use-toast"; import { useQueryClient } from "@tanstack/react-query"; import { SystemTracker } from "@/components/SystemTracker"; import { RegionMap } from "@/components/RegionMap"; import { Header } from "@/components/Header"; import { parseSignature, parseScannedPercentage } from "@/utils/signatureParser"; import { getSystemId } from "@/utils/systemApi"; import pb from "@/lib/pocketbase"; import { SigviewRecord as Signature, SignatureRecord, SignatureNoteRulesResponse, Collections } from "@/lib/pbtypes"; export const SystemView = () => { const { system, region } = useParams(); const navigate = useNavigate(); const queryClient = useQueryClient(); const [cleanMode, setCleanMode] = useState(false); if (!system) { navigate("/"); return null; } const saveSignature = async (signature: Signature): Promise => { console.log(signature); try { // Check if signature already exists let existingRecord: SignatureRecord | null = null; try { existingRecord = await pb.collection('signature').getFirstListItem(`identifier='${signature.identifier}' && system='${signature.system}'`); } catch (error) { console.log(`Signature ${signature.identifier} not found`); } const newScannedPercentage = parseScannedPercentage(signature.scanned); if (existingRecord) { const updatedSignature: Pick = { updated: new Date().toISOString() } // Existing record has no type and our new signature has a type if (!!!existingRecord.type && !!signature.type) updatedSignature.type = signature.type; // Existing record has no signame and our new signature has a signame if (!!!existingRecord.name && !!signature.signame) updatedSignature.name = signature.signame; // Update existing signature only if new scan percentage is higher const existingScannedPercentage = parseScannedPercentage(existingRecord.scanned); if (newScannedPercentage >= existingScannedPercentage) updatedSignature.scanned = signature.scanned; if (!!!existingRecord.note && !!signature.note) updatedSignature.note = signature.note; await pb.collection('signature').update(existingRecord.id, updatedSignature); console.log(`Updated signature ${signature.identifier}: ${existingScannedPercentage}% -> ${newScannedPercentage}%`); } else { // Create new signature await pb.collection('signature').create({ system: signature.system, identifier: signature.identifier, name: signature.signame, type: signature.type, dangerous: signature.dangerous, scanned: signature.scanned, note: signature.note }); console.log(`Created new signature ${signature.identifier} with ${newScannedPercentage}% scan`); } } catch (error) { console.error('Failed to save signature:', error); throw error; } }; const deleteSignature = async (signatureId: string): Promise => { try { await pb.collection('signature').delete(signatureId); // Invalidate queries to refresh the data queryClient.invalidateQueries({ queryKey: ['signatures', system] }); toast({ title: "Signature Deleted", description: "The signature has been successfully deleted.", }); } catch (error) { console.error('Failed to delete signature:', error); toast({ title: "Delete Failed", description: error instanceof Error ? error.message : "Failed to delete signature.", variant: "destructive" }); throw error; } }; const updateSignature = async (updatedSignature: Partial): Promise => { try { // Get the system ID for the current system const systemId = await getSystemId(system); console.log('Updating signature:', { identifier: updatedSignature.identifier, systemId, system, updatedSignature }); // Find the signature by identifier and system const existingRecord = await pb.collection('signature').getFirstListItem( `identifier='${updatedSignature.identifier}' && system='${systemId}'` ); console.log('Found existing record:', existingRecord); // Prepare update data const updateData: any = { updated: new Date().toISOString() }; if (updatedSignature.type !== undefined) { updateData.type = updatedSignature.type; } if (updatedSignature.signame !== undefined) { updateData.name = updatedSignature.signame; // Map signame to name field } if (updatedSignature.dangerous !== undefined) { updateData.dangerous = updatedSignature.dangerous; } if (updatedSignature.scanned !== undefined) { updateData.scanned = updatedSignature.scanned; } if (updatedSignature.note !== undefined) { updateData.note = updatedSignature.note; } console.log('Update data:', updateData); await pb.collection('signature').update(existingRecord.id, updateData); // Invalidate queries to refresh the data queryClient.invalidateQueries({ queryKey: ['signatures', system] }); toast({ title: "Signature Updated", description: "The signature has been successfully updated.", }); } catch (error) { console.error('Failed to update signature:', error); toast({ title: "Update Failed", description: error instanceof Error ? error.message : "Failed to update signature.", variant: "destructive" }); throw error; } }; const handlePaste = async (e: ClipboardEvent) => { const pastedText = e.clipboardData?.getData('text'); if (!pastedText?.trim()) return; const wasCleanMode = cleanMode; try { const systemId = await getSystemId(system); let rules: Array> = []; try { const list = await pb.collection(Collections.SignatureNoteRules).getFullList({ batch: 1000 }); rules = list.filter(r => r.enabled).map(r => ({ regex: r.regex, note: r.note, enabled: r.enabled })); } catch { } const lines = pastedText.trim().split('\n').filter(line => line.trim()); const parsedSignatures: Omit[] = []; // Parse all signatures for (const line of lines) { const parsed = parseSignature(line, rules); if (parsed) { parsedSignatures.push({ ...parsed, system: systemId, sysid: systemId, identifier: parsed.identifier }); } } if (parsedSignatures.length === 0) { toast({ title: "No Valid Signatures", description: "No valid signatures found in the pasted data. Signatures must follow the format: ABC-123.", variant: "destructive" }); return; } // If clean mode is enabled, delete signatures not in the pasted list if (wasCleanMode) { const existingSignatures = await pb.collection('signature').getFullList({ filter: `system='${systemId}'` }); const pastedIdentifiers = new Set(parsedSignatures.map(sig => sig.identifier)); const signaturesToDelete = existingSignatures.filter(sig => !pastedIdentifiers.has(sig.identifier)); for (const sig of signaturesToDelete) { await deleteSignature(sig.id); } if (signaturesToDelete.length > 0) { console.log(`Deleted ${signaturesToDelete.length} signatures not in pasted data`); } // Turn off clean mode after use // setCleanMode(false); } // Save all new/updated signatures for (const signature of parsedSignatures) { await saveSignature(signature as Signature); } // Invalidate queries to refresh the data queryClient.invalidateQueries({ queryKey: ['signatures', system] }); toast({ title: "Success", description: `${parsedSignatures.length} signatures processed.` }); } catch (error) { console.error('Failed to process signatures:', error); toast({ title: "Error", description: error instanceof Error ? error.message : "Failed to process signatures.", variant: "destructive" }); } }; useEffect(() => { document.addEventListener('paste', handlePaste); return () => { document.removeEventListener('paste', handlePaste); }; }, [system, cleanMode]); const breadcrumbs = [ { label: "Universe", path: "/" }, ...(region ? [{ label: region, path: `/regions/${region}` }] : []), { label: system } ]; return (
{/* Main content - signatures */}
{/* Regional overview map */}
{region ? (

{region} Region

Click systems to navigate • Current: {system}

) : (
No region information
Navigate from a region map to see regional overview
)}
); };