Advertisement
Guest User

Untitled

a guest
Apr 24th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.66 KB | None | 0 0
  1. import React from "react";
  2. import {
  3. StyleSheet,
  4. View,
  5. Keyboard,
  6. AsyncStorage,
  7. Platform,
  8. NetInfo,
  9. DeviceEventEmitter,
  10. Alert,
  11. Animated,
  12. Easing,
  13. Dimensions
  14. } from "react-native";
  15. import BackgroundContainer from "../components/backgroundcontainer";
  16. import axios from "axios";
  17. import { apiConstants } from "../common/api";
  18. import Form from "../components/form";
  19. import FormTextInput from "../components/formtextinput";
  20. import ListItem from "../components/listitem";
  21. import Label from "../components/label";
  22. import { COLOR_WHITE, COLOR_RED } from "../common/colours";
  23. import ContactGroup from "../components/contactgroup";
  24. import OfflineMode from "../components/offlinemode";
  25. import BusinessCard from "../components/businesscard";
  26. import RNAdvertiseBle from "react-native-advertise-ble";
  27. import {
  28. Menu,
  29. MenuOptions,
  30. MenuOption,
  31. MenuTrigger,
  32. renderers
  33. } from "react-native-popup-menu";
  34. import Contacts from "react-native-contacts";
  35. import helpers from "../common/helpers";
  36. import { uuidConstants } from "../common/UUID";
  37. import { BtErrorCode, BtErrorCodeMessage } from "../common/BtErrorCodes";
  38. const { SlideInMenu } = renderers;
  39.  
  40. const screen = {
  41. height: Dimensions.get("window").height,
  42. width: Dimensions.get("window").width
  43. };
  44.  
  45. const cardWidth = screen.width - 40;
  46. const cardHeight = screen.height - 120;
  47.  
  48. class ContactsScreen extends React.Component {
  49. constructor(props) {
  50. super();
  51. this.getContacts = this.getContacts.bind(this);
  52. this.search = this.search.bind(this);
  53. this.cancelSearch = this.cancelSearch.bind(this);
  54. this.toggleMenu = this.toggleMenu.bind(this);
  55. this.deleteContact = this.deleteContact.bind(this);
  56. this.state = {
  57. search: "",
  58. contacts: [],
  59. originalContacts: [],
  60. menuIsOpen: false,
  61. selectedContact: {},
  62. advertising: false,
  63. data: null,
  64. deviceOnline: true,
  65. yCardPosition: new Animated.Value(cardHeight * -1)
  66. };
  67. }
  68.  
  69. componentWillMount() {
  70. NetInfo.isConnected.addEventListener(
  71. "connectionChange",
  72. this._handleConnectivityChange
  73. );
  74.  
  75. this.startAdvertising();
  76.  
  77. NetInfo.isConnected.fetch().done(isConnected => {
  78. this.setState({ deviceOnline: isConnected });
  79. this.getOfflineData().then(() => this.getContacts());
  80. });
  81. }
  82.  
  83. componentWillUnmount() {
  84. RNAdvertiseBle.stop();
  85.  
  86. NetInfo.removeEventListener(
  87. "connectionChange",
  88. this._handleConnectivityChange
  89. );
  90. }
  91.  
  92. componentDidMount() {
  93. DeviceEventEmitter.addListener("OnWriteReceived", this._onWriteReceived);
  94. }
  95.  
  96. _handleConnectivityChange = isConnected => {
  97. this.setState({ deviceOnline: isConnected });
  98.  
  99. if (!isConnected) {
  100. this.getOfflineData();
  101. } else {
  102. this.getContacts();
  103. }
  104. };
  105.  
  106. async getContacts() {
  107. let UserId = await AsyncStorage.getItem("UserId");
  108.  
  109. let url = apiConstants.baseUrl + "/CompanyContact.svc/GetCompanyUserContact";
  110. let data = {
  111. Authentication: apiConstants.authentication,
  112. pklId: UserId
  113. };
  114. axios
  115. .post(url, data)
  116. .then(this.success.bind(this))
  117. .catch(this.error.bind(this));
  118. }
  119.  
  120. async getOfflineData() {
  121. let data = await AsyncStorage.getItem("offline-contacts");
  122. data = JSON.parse(data);
  123.  
  124. if (data == null) {
  125. } else {
  126. this.setState({
  127. contacts: data.CompanyUserContactModel,
  128. originalContacts: data.CompanyUserContactModel
  129. });
  130. }
  131. }
  132.  
  133. async success(response) {
  134. let data = response.data;
  135.  
  136. AsyncStorage.setItem("offline-contacts", JSON.stringify(data));
  137.  
  138. if (data.Status.sStatus === apiConstants.apiResults.success) {
  139. this.downloadOfflineContacts();
  140.  
  141. this.setState({
  142. contacts: data.CompanyUserContactModel,
  143. originalContacts: data.CompanyUserContactModel
  144. });
  145. }
  146. }
  147.  
  148. error(response) {
  149. this.getOfflineData();
  150. }
  151.  
  152. search(text) {
  153. if (text !== "") {
  154. this.setState({ search: text });
  155. let contacts = Object.create(this.state.originalContacts);
  156. //search through the array
  157. let searchResults = contacts.filter(
  158. contact =>
  159. contact["sFirstname"].toLowerCase().includes(text.toLowerCase()) ||
  160. contact["sFirstname"].toLowerCase().includes(text.toLowerCase()) ||
  161. contact["sFullnmame"].toLowerCase().includes(text.toLowerCase())
  162. );
  163. this.setState({ contacts: searchResults });
  164. } else {
  165. this.setState({
  166. search: text,
  167. contacts: this.state.originalContacts
  168. });
  169. }
  170. }
  171.  
  172. cancelSearch() {
  173. this.setState({ search: "", contacts: this.state.originalContacts });
  174. Keyboard.dismiss();
  175. }
  176.  
  177. renderCancel() {
  178. if (this.state.search.length > 0) {
  179. return (
  180. <View style={styles.searchCancelContainer}>
  181. <Label color={COLOR_WHITE} onPress={() => this.cancelSearch()}>
  182. Cancel
  183. </Label>
  184. </View>
  185. );
  186. }
  187. }
  188.  
  189. toggleMenu(contact) {
  190. if (contact) {
  191. this.setState({
  192. menuIsOpen: !this.state.menuIsOpen,
  193. selectedContact: contact
  194. });
  195. } else {
  196. this.setState({ menuIsOpen: !this.state.menuIsOpen });
  197. }
  198. }
  199.  
  200. renderContacts() {
  201. //create groups of five
  202. let contactGroups = [],
  203. size = 5;
  204. let contacts = Object.create(this.state.contacts);
  205. while (contacts.length > 0) contactGroups.push(contacts.splice(0, size));
  206. return contactGroups.map((contactGroup, index) => {
  207. return (
  208. <ContactGroup
  209. key={index}
  210. isGroupEvenIndex={index % 2 == 0}
  211. contacts={contactGroup}
  212. navigation={this.props.navigation}
  213. onLongPress={this.toggleMenu}
  214. />
  215. );
  216. });
  217. }
  218.  
  219. saveContactToAddressBook(response) {
  220. let data = response.data.BusinessCardModel;
  221. let newContact = {
  222. emailAddresses: [
  223. {
  224. label: "work",
  225. email: data.sEmail
  226. }
  227. ],
  228. familyName: data.sLastname,
  229. givenName: data.sFirstname,
  230. company: data.sCompanyName,
  231. displayName: data.sFullname,
  232. jobTitle: data.sJobTitle,
  233. note: data.sBriefDescription,
  234. phoneNumbers: [
  235. {
  236. label: "mobile",
  237. number: data.sPhoneNumber
  238. },
  239. {
  240. label: "work",
  241. number: data.sCompanyPhone
  242. }
  243. ],
  244. hasThumbnail: true,
  245. thumbnailPath: data.sProfilePicFrontLink,
  246. urlAddresses: [
  247. {
  248. label: "work",
  249. url: data.sWebsiteUrl
  250. },
  251. {
  252. label: "other",
  253. url: data.sCardURLShort
  254. },
  255. {
  256. label: "other",
  257. url: data.sTwitterUrl
  258. },
  259. {
  260. label: "other",
  261. url: data.sFacebookUrl
  262. },
  263. {
  264. label: "other",
  265. url: `https://www.linkedin.com/in/${data.sLinkedInUrl}`
  266. }
  267. ]
  268. };
  269.  
  270. Contacts.openContactForm(newContact, err => {
  271. if (err) {
  272. //handle error opening contacts
  273. } else {
  274. this.toggleMenu();
  275. }
  276. });
  277. }
  278.  
  279. deleteContact(contact) {
  280. let url = apiConstants.baseUrl + "/CompanyContact.svc/RemoveCompanyContact";
  281. //post to server and pass in username and password
  282. let data = {
  283. Authentication: apiConstants.authentication,
  284. pklid: contact.pklid
  285. };
  286. axios
  287. .post(url, data)
  288. .then(this.deleteSuccess.bind(this))
  289. .catch(response => console.log(response));
  290. }
  291.  
  292. deleteSuccess(response) {
  293. this.getContacts();
  294. this.toggleMenu();
  295. }
  296.  
  297. renderOfflineMode() {
  298. if (this.state.deviceOnline === false) {
  299. return <OfflineMode />;
  300. }
  301. }
  302.  
  303. async startAdvertising() {
  304. const Firstname = await AsyncStorage.getItem("Firstname");
  305. const Lastname = await AsyncStorage.getItem("Lastname");
  306.  
  307. const FullName = `${Firstname} ${Lastname}`;
  308. const OperatingSystem = `${
  309. Platform.OS === "ios" ? "Apple Device" : "Android Device"
  310. }`;
  311. const NameCharacteristicData = `${FullName} - ${OperatingSystem}`;
  312.  
  313. RNAdvertiseBle.addService(uuidConstants.serviceUUID, true);
  314.  
  315. RNAdvertiseBle.addCharacteristicToService(
  316. uuidConstants.serviceUUID,
  317. uuidConstants.nameCharacteristicUUID,
  318. NameCharacteristicData,
  319. 1,
  320. 2
  321. );
  322.  
  323. RNAdvertiseBle.addCharacteristicToService(
  324. uuidConstants.serviceUUID,
  325. uuidConstants.receiveFileCharacteristicUUID,
  326. "",
  327. Platform.OS === "ios" ? 2 : 16, // different permission ints on ios
  328. 8
  329. );
  330.  
  331. RNAdvertiseBle.start()
  332. .then(res => {
  333. this.setState({ adertising: res });
  334. if (res.errorCode !== BtErrorCode.SUCCESS) {
  335. this.displayErrorMessage(res.errorCode);
  336. } else {
  337. console.log("Starting Advertising...");
  338. }
  339. })
  340. .catch(error => {
  341. console.log("Failed to start advertising...", res);
  342. });
  343. }
  344.  
  345. async displayErrorMessage(errorCode) {
  346. let notifiedAboutAdvertising = await AsyncStorage.getItem("errorBt");
  347. if (notifiedAboutAdvertising === null) {
  348. // TODO - make this json and specify which errors the user was notified about previously
  349. AsyncStorage.setItem("errorBt", "asdfghjkl");
  350. } else {
  351. return;
  352. }
  353.  
  354. switch (errorCode) {
  355. case BtErrorCode.NO_DEFAULT_ADAPTER:
  356. alert(BtErrorCodeMessage.NO_DEFAULT_ADAPTER);
  357. break;
  358. case BtErrorCode.MULTIPLE_ADVERTISING_NOT_SUPPORTED:
  359. alert(BtErrorCodeMessage.MULTIPLE_ADVERTISING_NOT_SUPPORTED);
  360. break;
  361. case BtErrorCode.ADVERTISING_NOT_SUPPORTED:
  362. alert(BtErrorCodeMessage.ADVERTISING_NOT_SUPPORTED);
  363. break;
  364. case BtErrorCode.ADVERTISING_COULD_NOT_START:
  365. alert(BtErrorCodeMessage.ADVERTISING_COULD_NOT_START);
  366. break;
  367. }
  368. }
  369.  
  370. /**
  371. * Event called when the device's receive file characteristic changes
  372. * @param {object} response The data written to the characteristic
  373. * @param {string} response.data.name The sender's full name
  374. * @param {string} response.data.userGuid The sender's GUID
  375. * @param {string} response.data.CompanyGuid The sender's company's GUID
  376. */
  377. _onWriteReceived = response => {
  378. console.log("Received characteristic", response);
  379.  
  380. if (Platform.OS !== "ios") {
  381. const ResponseJson = JSON.parse(response.data);
  382. const Contact = {
  383. sUserGuid: ResponseJson.userGuid,
  384. sCompanyGuid: ResponseJson.CompanyGuid
  385. };
  386. const AlertMessage = `${
  387. ResponseJson.name
  388. } has sent you their business card, would you like to receive it?`;
  389.  
  390. // Slide the card in
  391. this.animateCardSlideIn(Contact.sUserGuid, Contact.sCompanyGuid);
  392.  
  393. helpers.alertYesNo(
  394. "Business Card Incoming",
  395. AlertMessage,
  396. () => {
  397. // Accept button callback
  398. this.saveContact(Contact.sUserGuid);
  399. this.setState({
  400. yCardPosition: cardHeight * -1,
  401. data: null
  402. });
  403. },
  404. () => {
  405. // Cancel button callback
  406. this.setState({
  407. yCardPosition: cardHeight * -1,
  408. data: null
  409. });
  410. }
  411. );
  412. }
  413. };
  414.  
  415. saveContact(guid) {
  416. if (this.state.deviceOnline) {
  417. this.saveContactToServer(guid);
  418. } else {
  419. this.saveContactOffline(guid);
  420. }
  421. }
  422.  
  423. /**
  424. * Saves the new contact to the user's contact list in the database
  425. * @param {string} guid The sender's GUID
  426. */
  427. async saveContactToServer(guid) {
  428. let url = apiConstants.baseUrl + "/CompanyContact.svc/SaveCompanyContact";
  429. let userId = await AsyncStorage.getItem("UserId");
  430.  
  431. let data = {
  432. Authentication: apiConstants.authentication,
  433. NewContactsUserGuid: guid,
  434. OwnersUserId: userId
  435. };
  436. axios
  437. .post(url, data)
  438. .then(this.getContacts())
  439. .catch(err => console.log(err));
  440. }
  441.  
  442. /**
  443. * Saves contact in async storage
  444. * @param {string} guid The sender's GUID
  445. */
  446. async saveContactOffline(guid) {
  447. let data = await AsyncStorage.getItem("offline-contacts-storage");
  448.  
  449. // Adding a deliminator if the storage isn't empty
  450. if (data == null) {
  451. data = "";
  452. } else {
  453. data += "#";
  454. }
  455.  
  456. AsyncStorage.setItem("offline-contacts-storage", data + guid);
  457. }
  458.  
  459. async downloadOfflineContacts() {
  460. let data = await AsyncStorage.getItem("offline-contacts-storage");
  461. if (data == null) return;
  462.  
  463. const Split = data.split("#");
  464.  
  465. if (Split.length === 1) {
  466. this.saveContactToServer(data);
  467. } else {
  468. Split.forEach(item => {
  469. this.saveContactToServer(item);
  470. });
  471. }
  472.  
  473. AsyncStorage.removeItem("offline-contacts-storage");
  474. }
  475.  
  476. getBusinessCardForContact(contact) {
  477. let url = apiConstants.baseUrl + "/BusinessCard.svc/GetBusinessCard";
  478. //post to server and pass in username and password
  479. let data = {
  480. Authentication: apiConstants.authentication,
  481. sCompanyGuid: contact.sCompanyGuid,
  482. sUserGuid: contact.sUserGuid
  483. };
  484. axios
  485. .post(url, data)
  486. .then(this.saveContactToAddressBook.bind(this))
  487. .catch(this.businessCardError.bind(this));
  488. }
  489.  
  490. businessCardError() {
  491. console.log("There was an error saving this business card.");
  492. }
  493.  
  494. async animateCardSlideIn(userGuid, companyGuid) {
  495. this.getCard(userGuid, companyGuid);
  496. Animated.timing(this.state.yCardPosition, {
  497. toValue: 20,
  498. duration: 2000
  499. }).start();
  500. }
  501.  
  502. async getCard(userGuid, companyGuid) {
  503. let url = apiConstants.baseUrl + "/BusinessCard.svc/GetBusinessCard";
  504.  
  505. // Post to server and pass in username and password
  506. let data = {
  507. Authentication: apiConstants.authentication,
  508. sCompanyGuid: companyGuid,
  509. sUserGuid: userGuid
  510. };
  511. axios
  512. .post(url, data)
  513. .then(result => {
  514. this.setState({ data: result.data.BusinessCardModel });
  515. console.log("worked");
  516. })
  517. .catch(err => {
  518. console.log(err);
  519. });
  520. }
  521.  
  522. renderContactCard() {
  523. if (this.state.data == null) return null;
  524.  
  525. return (
  526. <Animated.View
  527. style={{
  528. position: "absolute",
  529. bottom: 0,
  530. left: 0,
  531. right: 0,
  532. justifyContent: "center",
  533. alignItems: "center",
  534. top: this.state.yCardPosition,
  535. zIndex: 99999
  536. }}>
  537. <BusinessCard
  538. width={cardWidth}
  539. height={cardHeight}
  540. data={this.state.data}
  541. isContact={null}
  542. navigation={this.props.navigation}
  543. />
  544. </Animated.View>
  545. );
  546. }
  547.  
  548. render() {
  549. return (
  550. <BackgroundContainer>
  551. {this.renderContactCard()}
  552. <View style={{ paddingTop: helpers.paddingTop }}>
  553. <Menu
  554. renderer={SlideInMenu}
  555. opened={this.state.menuIsOpen}
  556. onBackdropPress={() => this.toggleMenu()}>
  557. <MenuTrigger />
  558. <MenuOptions>
  559. <MenuOption>
  560. <ListItem
  561. header={`${
  562. this.state.selectedContact.sFirstname
  563. } ${this.state.selectedContact.sLastname} - ${
  564. this.state.selectedContact.sCompanyName
  565. }`}
  566. />
  567. </MenuOption>
  568. <MenuOption>
  569. <ListItem
  570. header={"Save to contacts"}
  571. showChevron
  572. onPress={() =>
  573. this.getBusinessCardForContact(
  574. this.state.selectedContact
  575. )
  576. }
  577. />
  578. </MenuOption>
  579. <MenuOption>
  580. <ListItem
  581. header={"Delete"}
  582. onPress={() =>
  583. this.deleteContact(this.state.selectedContact)
  584. }
  585. color={COLOR_RED}
  586. showChevron
  587. />
  588. </MenuOption>
  589. </MenuOptions>
  590. </Menu>
  591. {this.renderOfflineMode()}
  592. <View style={styles.searchContainer}>
  593. <View style={styles.searchInputContainer}>
  594. <FormTextInput
  595. autoCapitalize={false}
  596. placeholder="Search Contacts... "
  597. text={this.state.search}
  598. onChangeText={text => this.search(text)}
  599. />
  600. </View>
  601. {this.renderCancel()}
  602. </View>
  603. <Form style={{ marginTop: 0 }}>
  604. <View style={styles.contactsContainer}>
  605. {this.renderContacts()}
  606. </View>
  607. </Form>
  608. </View>
  609. </BackgroundContainer>
  610. );
  611. }
  612. }
  613.  
  614. const styles = StyleSheet.create({
  615. searchContainer: {
  616. flexDirection: "row",
  617. justifyContent: "flex-start",
  618. marginTop: 15,
  619. marginLeft: 12,
  620. marginRight: 12
  621. },
  622. searchInputContainer: {
  623. flex: 1,
  624. flexDirection: "column"
  625. },
  626. searchCancelContainer: {
  627. marginLeft: 5,
  628. marginBottom: 10,
  629. flexDirection: "row",
  630. alignItems: "center",
  631. justifyContent: "center"
  632. },
  633. contactsContainer: {
  634. flexDirection: "row",
  635. flexWrap: "wrap",
  636. marginBottom: 90
  637. }
  638. });
  639.  
  640. export default ContactsScreen;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement