diff --git a/src/components/settings/ContactsSettings.tsx b/src/components/settings/ContactsSettings.tsx index 2b4a0f99..3076b4b7 100644 --- a/src/components/settings/ContactsSettings.tsx +++ b/src/components/settings/ContactsSettings.tsx @@ -3,12 +3,12 @@ import { Alert, Share, Text, View, StyleSheet, Pressable, TextInput } from 'reac import * as FileSystem from 'expo-file-system/legacy'; import * as Sharing from 'expo-sharing'; import { - Download, Upload, Plus, Pencil, Trash2, Check, X, BookUser, + Download, Upload, Plus, Pencil, Trash2, Check, X, BookUser, Star, } from 'lucide-react-native'; import { SettingsSection, SettingItem, ToggleSwitch } from './settings-section'; import Button from '../Button'; import Dialog from '../Dialog'; -import { ContactImportSheet } from '../contacts'; +import { ContactImportSheet, AddressBookPickerSheet } from '../contacts'; import { useSettingsStore } from '../../stores/settings-store'; import { useContactsStore, selectAddressBooksWithCount } from '../../stores/contacts-store'; import { contactsToVCard } from '../../lib/vcard'; @@ -35,9 +35,13 @@ export function ContactsSettings() { const createAddressBook = useContactsStore((s) => s.createAddressBook); const renameAddressBook = useContactsStore((s) => s.renameAddressBook); const deleteAddressBook = useContactsStore((s) => s.deleteAddressBook); + const setDefaultAddressBook = useContactsStore((s) => s.setDefaultAddressBook); + const getDefaultAddressBookId = useContactsStore((s) => s.getDefaultAddressBookId); const [exporting, setExporting] = React.useState(false); const [importOpen, setImportOpen] = React.useState(false); + const [importTargetOpen, setImportTargetOpen] = React.useState(false); + const [importTargetBookId, setImportTargetBookId] = React.useState(null); const [editingId, setEditingId] = React.useState(null); const [editName, setEditName] = React.useState(''); @@ -51,7 +55,21 @@ export function ContactsSettings() { exportable.length === 0 ? 'No contacts to export' : `Export ${exportable.length} contact${exportable.length === 1 ? '' : 's'} as a single vCard file.`; - const importTargetBookId = books[0]?.id ?? null; + // Imports land in the account's default book unless the user picks another. + const resolvedImportTarget = importTargetBookId ?? getDefaultAddressBookId(); + const importTargetName = books.find((b) => b.id === resolvedImportTarget)?.name; + + const handleSetDefault = async (id: string) => { + if (busy) return; + setBusy(true); + try { + await setDefaultAddressBook(id); + } catch (err) { + Alert.alert('Could not set default', err instanceof Error ? err.message : 'Unknown error'); + } finally { + setBusy(false); + } + }; const handleExport = async () => { if (exportable.length === 0 || exporting) return; @@ -196,17 +214,36 @@ export function ContactsSettings() { ) : ( <> - {book.name} + + {book.isShared && book.accountName ? `${book.name} (${book.accountName})` : book.name} + {book.count} contact{book.count === 1 ? '' : 's'} + {book.isDefault ? ' ยท Default' : ''} + {!book.isShared && ( + { if (!book.isDefault) void handleSetDefault(book.id); }} + hitSlop={6} + style={styles.iconBtn} + disabled={!!book.isDefault} + accessibilityLabel={book.isDefault ? 'Default address book' : 'Set as default'} + > + + + )} {book.myRights?.mayWrite !== false && ( startRename(book.id, book.name)} hitSlop={6} style={styles.iconBtn}> )} - {book.myRights?.mayDelete !== false && books.length > 1 && ( + {/* The default book and shared books cannot be deleted (the server rejects it). */} + {book.myRights?.mayDelete !== false && !book.isDefault && !book.isShared && books.length > 1 && ( setDeleteTarget({ id: book.id, name: book.name, count: book.count })} hitSlop={6} @@ -269,17 +306,26 @@ export function ContactsSettings() { setImportOpen(false)} - targetBookId={importTargetBookId} - targetBookName={books[0]?.name} + targetBookId={resolvedImportTarget} + targetBookName={importTargetName} + onChangeTarget={books.length > 1 ? () => setImportTargetOpen(true) : undefined} onImported={() => { void fetchContacts(); }} /> + setImportTargetOpen(false)} + currentBookId={resolvedImportTarget} + title="Import into address book" + onPick={(id) => { setImportTargetBookId(id); setImportTargetOpen(false); }} + /> + 0 ? ` Its ${deleteTarget.count} contact${deleteTarget.count === 1 ? '' : 's'} will be removed from this book.` : ''} This cannot be undone.` + ? `Delete "${deleteTarget.name}"?${deleteTarget.count > 0 ? ` Its ${deleteTarget.count} contact${deleteTarget.count === 1 ? '' : 's'} will be deleted with it.` : ''} This cannot be undone.` : '' } variant="destructive"