Fix QA review findings: per-card responding state, preserve data on detach
C-01: ConnectionRequestCard now uses local isResponding state instead of shared hook boolean, so accepting one card doesn't disable all others. C-03: detach_umbral_contact no longer wipes person data (name, email, phone, etc.) when a connection is severed. The person becomes a standard contact with all data preserved, preventing data loss for pre-existing contacts that were linked to connections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
aeb30afbce
commit
3fe344c3a0
@ -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."""
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user