diff --git a/src/components/ContactModal.jsx b/src/components/ContactModal.jsx index fdb1a0c..dc6e07e 100644 --- a/src/components/ContactModal.jsx +++ b/src/components/ContactModal.jsx @@ -1,242 +1,278 @@ -import { useState, useEffect, useCallback } from 'react' -import { X, Trash2 } from 'lucide-react' -import toast from 'react-hot-toast' -import { useStore } from '../store' -import { createContact, updateContact, deleteContact, fetchContacts } from '../api' - -const CATEGORIES = ['family', 'friend', 'business', 'emergency', 'ham', 'bug-out', 'favorite'] - -export default function ContactModal() { - const editingContact = useStore((s) => s.editingContact) - const clearEditingContact = useStore((s) => s.clearEditingContact) - const setContacts = useStore((s) => s.setContacts) - - const [form, setForm] = useState({}) - const [saving, setSaving] = useState(false) - - useEffect(() => { - if (editingContact) { - setForm({ - label: editingContact.label || '', - name: editingContact.name || '', - call_sign: editingContact.call_sign || '', - phone: editingContact.phone || '', - email: editingContact.email || '', - category: editingContact.category || '', - notes: editingContact.notes || '', - show_proximity: editingContact.show_proximity || false, - lat: editingContact.lat ?? null, - lon: editingContact.lon ?? null, - osm_type: editingContact.osm_type || null, - osm_id: editingContact.osm_id || null, - address: editingContact.address || '', - }) - } - }, [editingContact]) - - const close = useCallback(() => clearEditingContact(), [clearEditingContact]) - - useEffect(() => { - if (!editingContact) return - const onKey = (e) => { if (e.key === 'Escape') close() } - document.addEventListener('keydown', onKey) - return () => document.removeEventListener('keydown', onKey) - }, [editingContact, close]) - - if (!editingContact) return null - - const isEdit = editingContact.id != null - - const setField = (key, val) => setForm((f) => ({ ...f, [key]: val })) - - const refreshContacts = async () => { - const data = await fetchContacts() - if (!data?.auth && Array.isArray(data)) setContacts(data) - else if (Array.isArray(data)) setContacts(data) - } - - const handleSave = async () => { - if (!form.label?.trim()) { - toast.error('Label is required') - return - } - setSaving(true) - try { - const payload = { ...form, label: form.label.trim() } - if (payload.show_proximity === false) payload.show_proximity = false - const result = isEdit - ? await updateContact(editingContact.id, payload) - : await createContact(payload) - if (result?.auth === false) { - toast.error('Sign in to save contacts') - setSaving(false) - return - } - if (result?._status === 409 || result?.error?.includes('Home/Work')) { - toast.error('You already have a Home/Work contact') - setSaving(false) - return - } - toast.success(isEdit ? 'Contact updated' : 'Contact saved') - await refreshContacts() - close() - } catch (e) { - toast.error(e.message) - } finally { - setSaving(false) - } - } - - const handleDelete = async () => { - if (!confirm('Delete this contact? You can restore it from the dashboard.')) return - setSaving(true) - try { - await deleteContact(editingContact.id) - toast('Contact deleted') - await refreshContacts() - close() - } catch (e) { - toast.error(e.message) - } finally { - setSaving(false) - } - } - - const hasGeo = form.lat != null && form.lon != null - - return ( -
{ if (e.target === e.currentTarget) close() }}> -
- {/* Header */} -
-

- {isEdit ? 'Edit Contact' : 'Save Contact'} -

- -
- - {/* Label with quick-fill */} -
- -
- {['Home', 'Work'].map((l) => ( - - ))} -
- setField('label', e.target.value)} - placeholder="e.g. Home, Work, Mom, Bug Out" - /> -
- - {/* Category */} -
- - setField('category', e.target.value)} - placeholder="family, friend, emergency..." - /> - - {CATEGORIES.map((c) => -
- - {/* Name + Call Sign */} -
-
- - setField('name', e.target.value)} /> -
-
- - setField('call_sign', e.target.value)} /> -
-
- - {/* Phone + Email */} -
-
- - setField('phone', e.target.value)} type="tel" /> -
-
- - setField('email', e.target.value)} type="email" /> -
-
- - {/* Notes */} -
- -