diff --git a/backend/app/services/connection.py b/backend/app/services/connection.py index e169e5a..ab6e838 100644 --- a/backend/app/services/connection.py +++ b/backend/app/services/connection.py @@ -126,19 +126,15 @@ def create_person_from_connection( async def detach_umbral_contact(person: Person) -> None: - """Convert an umbral contact back to a standard contact. Does NOT commit.""" + """Convert an umbral contact back to a standard contact. Does NOT commit. + + Preserves all person data (name, email, phone, etc.) so the user does not + lose contact information when a connection is severed. Only unlinks the + umbral association — the person becomes a standard contact. + """ person.linked_user_id = None person.is_umbral_contact = False person.category = None - # Clear all shareable fields — they were populated from the connection - # Preserve first_name from existing name so the contact is not left blank - fallback_name = person.first_name or person.name or None - for field in SHAREABLE_FIELDS: - if hasattr(person, field): - setattr(person, field, None) - person.first_name = fallback_name - # Recompute display name - person.name = fallback_name or "Removed Contact" def extract_ntfy_config(settings: Settings) -> dict | None: """Extract ntfy config values into a plain dict safe for use after session close.""" diff --git a/frontend/src/components/connections/ConnectionRequestCard.tsx b/frontend/src/components/connections/ConnectionRequestCard.tsx index a0b19bf..366fff6 100644 --- a/frontend/src/components/connections/ConnectionRequestCard.tsx +++ b/frontend/src/components/connections/ConnectionRequestCard.tsx @@ -15,7 +15,8 @@ interface ConnectionRequestCardProps { } export default function ConnectionRequestCard({ request, direction }: ConnectionRequestCardProps) { - const { respond, isResponding, cancelRequest, isCancelling } = useConnections(); + const { respond, cancelRequest, isCancelling } = useConnections(); + const [isResponding, setIsResponding] = useState(false); const [resolved, setResolved] = useState(false); // Clean up invisible DOM element after fade-out transition @@ -29,6 +30,7 @@ export default function ConnectionRequestCard({ request, direction }: Connection if (hidden) return null; const handleRespond = async (action: 'accept' | 'reject') => { + setIsResponding(true); try { await respond({ requestId: request.id, action }); setResolved(true); @@ -41,6 +43,8 @@ export default function ConnectionRequestCard({ request, direction }: Connection } else { toast.error(getErrorMessage(err, 'Failed to respond')); } + } finally { + setIsResponding(false); } };