1import { PermissionStatus, UnavailabilityError, uuid } from 'expo-modules-core'; 2import { Platform, Share } from 'react-native'; 3import ExpoContacts from './ExpoContacts'; 4export { PermissionStatus }; 5/** 6 * Returns whether the Contacts API is enabled on the current device. This method does not check the app permissions. 7 * @returns A promise that fulfills with a `boolean`, indicating whether the Contacts API is available on the current device. It always resolves to `false` on web. 8 */ 9export async function isAvailableAsync() { 10 return !!ExpoContacts.getContactsAsync; 11} 12export async function shareContactAsync(contactId, message, shareOptions = {}) { 13 if (Platform.OS === 'ios') { 14 const url = await writeContactToFileAsync({ 15 id: contactId, 16 }); 17 return await Share.share({ 18 url, 19 message, 20 }, shareOptions); 21 } 22 else if (!ExpoContacts.shareContactAsync) { 23 throw new UnavailabilityError('Contacts', 'shareContactAsync'); 24 } 25 return await ExpoContacts.shareContactAsync(contactId, message); 26} 27/** 28 * Return a list of contacts that fit a given criteria. You can get all of the contacts by passing no criteria. 29 * @param contactQuery Object used to query contacts. 30 * @return A promise that fulfills with `ContactResponse` object returned from the query. 31 * @example 32 * ```js 33 * const { data } = await Contacts.getContactsAsync({ 34 * fields: [Contacts.Fields.Emails], 35 * }); 36 * 37 * if (data.length > 0) { 38 * const contact = data[0]; 39 * console.log(contact); 40 * } 41 * ``` 42 */ 43export async function getContactsAsync(contactQuery = {}) { 44 if (!ExpoContacts.getContactsAsync) { 45 throw new UnavailabilityError('Contacts', 'getContactsAsync'); 46 } 47 return await ExpoContacts.getContactsAsync(contactQuery); 48} 49export async function getPagedContactsAsync(contactQuery = {}) { 50 const { pageSize, ...nOptions } = contactQuery; 51 if (pageSize && pageSize <= 0) { 52 throw new Error('Error: Contacts.getPagedContactsAsync: `pageSize` must be greater than 0'); 53 } 54 return await getContactsAsync({ 55 ...nOptions, 56 pageSize, 57 }); 58} 59/** 60 * Used for gathering precise data about a contact. Returns a contact matching the given `id`. 61 * @param id The ID of a system contact. 62 * @param fields If specified, the fields defined will be returned. When skipped, all fields will be returned. 63 * @return A promise that fulfills with `Contact` object with ID matching the input ID, or `undefined` if there is no match. 64 * @example 65 * ```js 66 * const contact = await Contacts.getContactByIdAsync('161A368D-D614-4A15-8DC6-665FDBCFAE55'); 67 * if (contact) { 68 * console.log(contact); 69 * } 70 * ``` 71 */ 72export async function getContactByIdAsync(id, fields) { 73 if (!ExpoContacts.getContactsAsync) { 74 throw new UnavailabilityError('Contacts', 'getContactsAsync'); 75 } 76 if (id == null) { 77 throw new Error('Error: Contacts.getContactByIdAsync: Please pass an ID as a parameter'); 78 } 79 else { 80 const results = await ExpoContacts.getContactsAsync({ 81 pageSize: 1, 82 pageOffset: 0, 83 fields, 84 id, 85 }); 86 if (results && results.data && results.data.length > 0) { 87 return results.data[0]; 88 } 89 } 90 return undefined; 91} 92/** 93 * Creates a new contact and adds it to the system. 94 * > **Note**: For Android users, the Expo Go app does not have the required `WRITE_CONTACTS` permission to write to Contacts. 95 * > You will need to create a [development build](/develop/development-builds/create-a-build/) and add permission in there manually to use this method. 96 * @param contact A contact with the changes you wish to persist. The `id` parameter will not be used. 97 * @param containerId @tag-ios The container that will parent the contact. 98 * @return A promise that fulfills with ID of the new system contact. 99 * @example 100 * ```js 101 * const contact = { 102 * [Contacts.Fields.FirstName]: 'Bird', 103 * [Contacts.Fields.LastName]: 'Man', 104 * [Contacts.Fields.Company]: 'Young Money', 105 * }; 106 * const contactId = await Contacts.addContactAsync(contact); 107 * ``` 108 */ 109export async function addContactAsync(contact, containerId) { 110 if (!ExpoContacts.addContactAsync) { 111 throw new UnavailabilityError('Contacts', 'addContactAsync'); 112 } 113 const noIdContact = removeIds(contact); 114 return await ExpoContacts.addContactAsync(noIdContact, containerId); 115} 116/** 117 * Mutate the information of an existing contact. Due to an iOS bug, `nonGregorianBirthday` field cannot be modified. 118 * > **info** On Android, you can use [`presentFormAsync`](#contactspresentformasynccontactid-contact-formoptions) to make edits to contacts. 119 * @param contact A contact object including the wanted changes. 120 * @return A promise that fulfills with ID of the updated system contact if mutation was successful. 121 * @example 122 * ```js 123 * const contact = { 124 * id: '161A368D-D614-4A15-8DC6-665FDBCFAE55', 125 * [Contacts.Fields.FirstName]: 'Drake', 126 * [Contacts.Fields.Company]: 'Young Money', 127 * }; 128 * await Contacts.updateContactAsync(contact); 129 * ``` 130 * @platform ios 131 */ 132export async function updateContactAsync(contact) { 133 if (!ExpoContacts.updateContactAsync) { 134 throw new UnavailabilityError('Contacts', 'updateContactAsync'); 135 } 136 return await ExpoContacts.updateContactAsync(contact); 137} 138// @needs-audit 139/** 140 * Delete a contact from the system. 141 * @param contactId ID of the contact you want to delete. 142 * @example 143 * ```js 144 * await Contacts.removeContactAsync('161A368D-D614-4A15-8DC6-665FDBCFAE55'); 145 * ``` 146 * @platform ios 147 */ 148export async function removeContactAsync(contactId) { 149 if (!ExpoContacts.removeContactAsync) { 150 throw new UnavailabilityError('Contacts', 'removeContactAsync'); 151 } 152 return await ExpoContacts.removeContactAsync(contactId); 153} 154/** 155 * Query a set of contacts and write them to a local URI that can be used for sharing. 156 * @param contactQuery Used to query contact you want to write. 157 * @return A promise that fulfills with shareable local URI, or `undefined` if there was no match. 158 * @example 159 * ```js 160 * const localUri = await Contacts.writeContactToFileAsync({ 161 * id: '161A368D-D614-4A15-8DC6-665FDBCFAE55', 162 * }); 163 * Share.share({ url: localUri, message: 'Call me!' }); 164 * ``` 165 */ 166export async function writeContactToFileAsync(contactQuery = {}) { 167 if (!ExpoContacts.writeContactToFileAsync) { 168 throw new UnavailabilityError('Contacts', 'writeContactToFileAsync'); 169 } 170 return await ExpoContacts.writeContactToFileAsync(contactQuery); 171} 172// @needs-audit 173/** 174 * Present a native form for manipulating contacts. 175 * @param contactId The ID of a system contact. 176 * @param contact A contact with the changes you want to persist. 177 * @param formOptions Options for the native editor. 178 * @example 179 * ```js 180 * await Contacts.presentFormAsync('161A368D-D614-4A15-8DC6-665FDBCFAE55'); 181 * ``` 182 */ 183export async function presentFormAsync(contactId, contact, formOptions = {}) { 184 if (!ExpoContacts.presentFormAsync) { 185 throw new UnavailabilityError('Contacts', 'presentFormAsync'); 186 } 187 if (Platform.OS === 'ios') { 188 const adjustedOptions = formOptions; 189 if (contactId) { 190 if (contact) { 191 contact = undefined; 192 console.log('Expo.Contacts.presentFormAsync: You should define either a `contact` or a `contactId` but not both.'); 193 } 194 if (adjustedOptions.isNew !== undefined) { 195 console.log('Expo.Contacts.presentFormAsync: `formOptions.isNew` is not supported with `contactId`'); 196 } 197 } 198 return await ExpoContacts.presentFormAsync(contactId, contact, adjustedOptions); 199 } 200 else { 201 return await ExpoContacts.presentFormAsync(contactId, contact, formOptions); 202 } 203} 204// iOS Only 205/** 206 * Add a group to a container. 207 * @param groupId The group you want to target. 208 * @param containerId The container you want to add membership to. 209 * @example 210 * ```js 211 * await Contacts.addExistingGroupToContainerAsync( 212 * '161A368D-D614-4A15-8DC6-665FDBCFAE55', 213 * '665FDBCFAE55-D614-4A15-8DC6-161A368D' 214 * ); 215 * ``` 216 * @platform ios 217 */ 218export async function addExistingGroupToContainerAsync(groupId, containerId) { 219 if (!ExpoContacts.addExistingGroupToContainerAsync) { 220 throw new UnavailabilityError('Contacts', 'addExistingGroupToContainerAsync'); 221 } 222 return await ExpoContacts.addExistingGroupToContainerAsync(groupId, containerId); 223} 224/** 225 * Create a group with a name, and add it to a container. If the container is undefined, the default container will be targeted. 226 * @param name Name of the new group. 227 * @param containerId The container you to add membership to. 228 * @return A promise that fulfills with ID of the new group. 229 * @example 230 * ```js 231 * const groupId = await Contacts.createGroupAsync('Sailor Moon'); 232 * ``` 233 * @platform ios 234 */ 235export async function createGroupAsync(name, containerId) { 236 if (!ExpoContacts.createGroupAsync) { 237 throw new UnavailabilityError('Contacts', 'createGroupAsync'); 238 } 239 name = name || uuid.v4(); 240 if (!containerId) { 241 containerId = await getDefaultContainerIdAsync(); 242 } 243 return await ExpoContacts.createGroupAsync(name, containerId); 244} 245/** 246 * Change the name of an existing group. 247 * @param groupName New name for an existing group. 248 * @param groupId ID of the group you want to edit. 249 * @example 250 * ```js 251 * await Contacts.updateGroupName('Expo Friends', '161A368D-D614-4A15-8DC6-665FDBCFAE55'); 252 * ``` 253 * @platform ios 254 */ 255export async function updateGroupNameAsync(groupName, groupId) { 256 if (!ExpoContacts.updateGroupNameAsync) { 257 throw new UnavailabilityError('Contacts', 'updateGroupNameAsync'); 258 } 259 return await ExpoContacts.updateGroupNameAsync(groupName, groupId); 260} 261// @needs-audit 262/** 263 * Delete a group from the device. 264 * @param groupId ID of the group you want to remove. 265 * @example 266 * ```js 267 * await Contacts.removeGroupAsync('161A368D-D614-4A15-8DC6-665FDBCFAE55'); 268 * ``` 269 * @platform ios 270 */ 271export async function removeGroupAsync(groupId) { 272 if (!ExpoContacts.removeGroupAsync) { 273 throw new UnavailabilityError('Contacts', 'removeGroupAsync'); 274 } 275 return await ExpoContacts.removeGroupAsync(groupId); 276} 277// @needs-audit 278/** 279 * Add a contact as a member to a group. A contact can be a member of multiple groups. 280 * @param contactId ID of the contact you want to edit. 281 * @param groupId ID for the group you want to add membership to. 282 * @example 283 * ```js 284 * await Contacts.addExistingContactToGroupAsync( 285 * '665FDBCFAE55-D614-4A15-8DC6-161A368D', 286 * '161A368D-D614-4A15-8DC6-665FDBCFAE55' 287 * ); 288 * ``` 289 * @platform ios 290 */ 291export async function addExistingContactToGroupAsync(contactId, groupId) { 292 if (!ExpoContacts.addExistingContactToGroupAsync) { 293 throw new UnavailabilityError('Contacts', 'addExistingContactToGroupAsync'); 294 } 295 return await ExpoContacts.addExistingContactToGroupAsync(contactId, groupId); 296} 297// @needs-audit 298/** 299 * Remove a contact's membership from a given group. This will not delete the contact. 300 * @param contactId ID of the contact you want to remove. 301 * @param groupId ID for the group you want to remove membership of. 302 * @example 303 * ```js 304 * await Contacts.removeContactFromGroupAsync( 305 * '665FDBCFAE55-D614-4A15-8DC6-161A368D', 306 * '161A368D-D614-4A15-8DC6-665FDBCFAE55' 307 * ); 308 * ``` 309 * @platform ios 310 */ 311export async function removeContactFromGroupAsync(contactId, groupId) { 312 if (!ExpoContacts.removeContactFromGroupAsync) { 313 throw new UnavailabilityError('Contacts', 'removeContactFromGroupAsync'); 314 } 315 return await ExpoContacts.removeContactFromGroupAsync(contactId, groupId); 316} 317// @needs-audit 318/** 319 * Query and return a list of system groups. 320 * @param groupQuery Information regarding which groups you want to get. 321 * @example 322 * ```js 323 * const groups = await Contacts.getGroupsAsync({ groupName: 'sailor moon' }); 324 * const allGroups = await Contacts.getGroupsAsync({}); 325 * ``` 326 * @return A promise that fulfills with array of groups that fit the query. 327 * @platform ios 328 */ 329export async function getGroupsAsync(groupQuery) { 330 if (!ExpoContacts.getGroupsAsync) { 331 throw new UnavailabilityError('Contacts', 'getGroupsAsync'); 332 } 333 return await ExpoContacts.getGroupsAsync(groupQuery); 334} 335/** 336 * Get the default container's ID. 337 * @return A promise that fulfills with default container ID. 338 * @example 339 * ```js 340 * const containerId = await Contacts.getDefaultContainerIdAsync(); 341 * ``` 342 * @platform ios 343 */ 344export async function getDefaultContainerIdAsync() { 345 if (!ExpoContacts.getDefaultContainerIdentifierAsync) { 346 throw new UnavailabilityError('Contacts', 'getDefaultContainerIdentifierAsync'); 347 } 348 return await ExpoContacts.getDefaultContainerIdentifierAsync(); 349} 350/** 351 * Query a list of system containers. 352 * @param containerQuery Information used to gather containers. 353 * @return A promise that fulfills with array of containers that fit the query. 354 * @example 355 * ```js 356 * const allContainers = await Contacts.getContainersAsync({ 357 * contactId: '665FDBCFAE55-D614-4A15-8DC6-161A368D', 358 * }); 359 * ``` 360 * @platform ios 361 */ 362export async function getContainersAsync(containerQuery) { 363 if (!ExpoContacts.getContainersAsync) { 364 throw new UnavailabilityError('Contacts', 'getContainersAsync'); 365 } 366 return await ExpoContacts.getContainersAsync(containerQuery); 367} 368/** 369 * Checks user's permissions for accessing contacts data. 370 * @return A promise that resolves to a [PermissionResponse](#permissionresponse) object. 371 */ 372export async function getPermissionsAsync() { 373 if (!ExpoContacts.getPermissionsAsync) { 374 throw new UnavailabilityError('Contacts', 'getPermissionsAsync'); 375 } 376 return await ExpoContacts.getPermissionsAsync(); 377} 378/** 379 * Asks the user to grant permissions for accessing contacts data. 380 * @return A promise that resolves to a [PermissionResponse](#permissionresponse) object. 381 */ 382export async function requestPermissionsAsync() { 383 if (!ExpoContacts.requestPermissionsAsync) { 384 throw new UnavailabilityError('Contacts', 'requestPermissionsAsync'); 385 } 386 return await ExpoContacts.requestPermissionsAsync(); 387} 388/** @private */ 389function removeIds(contact) { 390 const updatedContact = { ...contact }; 391 if (contact.id && __DEV__) { 392 console.warn(`You have set an id = ${contact.id} for the contact. This value will be ignored, because the id will be generated by the OS`); 393 delete updatedContact.id; 394 } 395 for (const key of Object.keys(contact)) { 396 if (Array.isArray(contact[key])) { 397 updatedContact[key] = contact[key].map((item, index) => { 398 if (item.id) { 399 __DEV__ && 400 console.warn(`You have set an id "${item.id}" at index "${index}" for the key "${key}" of the contact. This value will be ignored, because the id will be generated by the OS`); 401 return { ...item, id: null }; 402 } 403 return item; 404 }); 405 } 406 } 407 return updatedContact; 408} 409/** 410 * Possible fields to retrieve for a contact. 411 */ 412export var Fields; 413(function (Fields) { 414 Fields["ID"] = "id"; 415 Fields["ContactType"] = "contactType"; 416 Fields["Name"] = "name"; 417 Fields["FirstName"] = "firstName"; 418 Fields["MiddleName"] = "middleName"; 419 Fields["LastName"] = "lastName"; 420 Fields["MaidenName"] = "maidenName"; 421 Fields["NamePrefix"] = "namePrefix"; 422 Fields["NameSuffix"] = "nameSuffix"; 423 Fields["Nickname"] = "nickname"; 424 Fields["PhoneticFirstName"] = "phoneticFirstName"; 425 Fields["PhoneticMiddleName"] = "phoneticMiddleName"; 426 Fields["PhoneticLastName"] = "phoneticLastName"; 427 Fields["Birthday"] = "birthday"; 428 /** 429 * @platform ios 430 */ 431 Fields["NonGregorianBirthday"] = "nonGregorianBirthday"; 432 Fields["Emails"] = "emails"; 433 Fields["PhoneNumbers"] = "phoneNumbers"; 434 Fields["Addresses"] = "addresses"; 435 /** 436 * @platform ios 437 */ 438 Fields["SocialProfiles"] = "socialProfiles"; 439 Fields["InstantMessageAddresses"] = "instantMessageAddresses"; 440 Fields["UrlAddresses"] = "urlAddresses"; 441 Fields["Company"] = "company"; 442 Fields["JobTitle"] = "jobTitle"; 443 Fields["Department"] = "department"; 444 Fields["ImageAvailable"] = "imageAvailable"; 445 Fields["Image"] = "image"; 446 Fields["RawImage"] = "rawImage"; 447 Fields["ExtraNames"] = "extraNames"; 448 Fields["Note"] = "note"; 449 Fields["Dates"] = "dates"; 450 Fields["Relationships"] = "relationships"; 451})(Fields || (Fields = {})); 452/** 453 * This format denotes the common calendar format used to specify how a date is calculated in `nonGregorianBirthday` fields. 454 */ 455export var CalendarFormats; 456(function (CalendarFormats) { 457 CalendarFormats["Gregorian"] = "gregorian"; 458 /** 459 * @platform ios 460 */ 461 CalendarFormats["Buddhist"] = "buddhist"; 462 /** 463 * @platform ios 464 */ 465 CalendarFormats["Chinese"] = "chinese"; 466 /** 467 * @platform ios 468 */ 469 CalendarFormats["Coptic"] = "coptic"; 470 /** 471 * @platform ios 472 */ 473 CalendarFormats["EthiopicAmeteMihret"] = "ethiopicAmeteMihret"; 474 /** 475 * @platform ios 476 */ 477 CalendarFormats["EthiopicAmeteAlem"] = "ethiopicAmeteAlem"; 478 /** 479 * @platform ios 480 */ 481 CalendarFormats["Hebrew"] = "hebrew"; 482 /** 483 * @platform ios 484 */ 485 CalendarFormats["ISO8601"] = "iso8601"; 486 /** 487 * @platform ios 488 */ 489 CalendarFormats["Indian"] = "indian"; 490 /** 491 * @platform ios 492 */ 493 CalendarFormats["Islamic"] = "islamic"; 494 /** 495 * @platform ios 496 */ 497 CalendarFormats["IslamicCivil"] = "islamicCivil"; 498 /** 499 * @platform ios 500 */ 501 CalendarFormats["Japanese"] = "japanese"; 502 /** 503 * @platform ios 504 */ 505 CalendarFormats["Persian"] = "persian"; 506 /** 507 * @platform ios 508 */ 509 CalendarFormats["RepublicOfChina"] = "republicOfChina"; 510 /** 511 * @platform ios 512 */ 513 CalendarFormats["IslamicTabular"] = "islamicTabular"; 514 /** 515 * @platform ios 516 */ 517 CalendarFormats["IslamicUmmAlQura"] = "islamicUmmAlQura"; 518})(CalendarFormats || (CalendarFormats = {})); 519/** 520 * @platform ios 521 */ 522export var ContainerTypes; 523(function (ContainerTypes) { 524 /** 525 * A local non-iCloud container. 526 */ 527 ContainerTypes["Local"] = "local"; 528 /** 529 * In association with email server. 530 */ 531 ContainerTypes["Exchange"] = "exchange"; 532 /** 533 * With cardDAV protocol used for sharing. 534 */ 535 ContainerTypes["CardDAV"] = "cardDAV"; 536 /** 537 * Unknown container. 538 */ 539 ContainerTypes["Unassigned"] = "unassigned"; 540})(ContainerTypes || (ContainerTypes = {})); 541export var SortTypes; 542(function (SortTypes) { 543 /** 544 * The user default method of sorting. 545 * @platform android 546 */ 547 SortTypes["UserDefault"] = "userDefault"; 548 /** 549 * Sort by first name in ascending order. 550 */ 551 SortTypes["FirstName"] = "firstName"; 552 /** 553 * Sort by last name in ascending order. 554 */ 555 SortTypes["LastName"] = "lastName"; 556 /** 557 * No sorting should be applied. 558 */ 559 SortTypes["None"] = "none"; 560})(SortTypes || (SortTypes = {})); 561export var ContactTypes; 562(function (ContactTypes) { 563 /** 564 * Contact is a human. 565 */ 566 ContactTypes["Person"] = "person"; 567 /** 568 * Contact is group or company. 569 */ 570 ContactTypes["Company"] = "company"; 571})(ContactTypes || (ContactTypes = {})); 572//# sourceMappingURL=Contacts.js.map