BILDIT-Platform / react-native-bildit-flybuy

React Native FlyBuy module. Supports Core, Pickup, Notify, and Presence Native SDK APIs.
9 stars 6 forks source link

FlyBuyCore.configure called more than once #55

Closed sangamivivek closed 1 year ago

sangamivivek commented 1 year ago

Describe the bug

Getting 'FlyBuyCore.configure called more than once' error on app start, eventhough we are calling it only once and also this error is inconsistent. versions: "react-native": "0.64.2", "react-native-bildit-flybuy": "2.1.1",

Screenshots

Screenshot_1692624254

Config code snippet on App.tsx

useAsyncEffect(async () => { if (Platform.OS === 'ios') { FlyBuy.Core.configure(iosToken); } else { FlyBuy.Core.configure(androidToken); } FlyBuy.Pickup.configure(); }, []);

sangamivivek commented 1 year ago

@mohanenm

mohanenm commented 1 year ago

@sangamivivek by inconsistent, do you mean it sometimes throws this error and sometimes does not?

sangamivivek commented 1 year ago

yes @mohanenm ,while closing and opening the app it sometimes throws this error and sometimes does not

addingama commented 1 year ago

@sangamivivek can you try moving the configure outside component?

Maybe on your index.js file

mohanenm commented 1 year ago

Not sure if this is helpful, but The example in the bildit repo calls configure within a React.useEffect block. According to this SO post, passing an empty array in useEffect makes sure it is called only once. I think the combination of useEffect with the array ensures it is called only once when the app starts and synchronously so it happens before any other flybuy method calls.

mohanenm commented 1 year ago

@addingama What would moving it out of the component do?

We are still running into this error when force closing and reopening the app.

mohanenm commented 1 year ago

The weird thing is that this problem is solved by removing the call to FlyBuy.Pickup.onPermissionChanged();...however, when they remove that call we stop getting location updates.

addingama commented 1 year ago

Can you share the index.js and App.tsx content?

mohanenm commented 1 year ago

@sangamivivek ^

sangamivivek commented 1 year ago

@addingama Index.js

import React from 'react'; import { AppRegistry } from 'react-native'; import App from './src/App'; import { name as appName } from './app.json';

AppRegistry.registerComponent(appName, () => App);

Below is the FlyBuy Config snippet in App.tsx

useAsyncEffect(async () => { await fetchRemoteConfig(); const remotevalue = await getAllRemoteValues(); QuantumMetric.QuantumMetricLibrary.sendEvent(79, JSON.stringify(remotevalue)); const iosToken = await RemoteConfig.getRemoteValue('flybuy_token_ios') const androidToken = await RemoteConfig.getRemoteValue('flybuy_token_android') let versionConfig = await RemoteConfig.getRemoteValue('version_check'); let flags = await RemoteConfig.getRemoteValue('feature_flags'); if ('force_update' in flags && flags.force_update) { checkVersion(versionConfig) } await notifee.createChannel({ id: 'default', name: 'TSC Notifications', lights: false, vibration: true, importance: AndroidImportance.HIGH, }); if (Platform.OS === 'ios') { FlyBuy.Core.configure(iosToken); } else { FlyBuy.Core.configure(androidToken); } FlyBuy.Pickup.configure(); let basketIdStore = await getItemFromPersistance(BASKET_ID_PERSISTANT_KEY); if(basketIdStore==null){ persistItem(GROUP_ORDER_PERSISTANT_KEY, false); } if (Platform.OS === 'ios') { if (!Settings.get('hasRunBefore')) { Settings.set({ hasRunBefore: true }); clearData(); persistItem(ALREADY_LAUNCHED, false); }else{
persistItem(ALREADY_LAUNCHED, true);
} } }, []);

useEffect(() => { AppState.addEventListener("change",handleStateChange); let unsub = messaging().onMessage(async (remoteMessage) => { if (remoteMessage?.message_source === 'flybuy') { FlyBuy.Core.handleRemoteNotification(remoteMessage.data); } else if (remoteMessage?.data?.message_source === 'flybuy') { FlyBuy.Core.handleRemoteNotification(remoteMessage.data); } else { let now: Date = new Date(); const {actiontype, action, payload} = remoteMessage.data ?? {}; let notificationData: NotifeeNotification = { title: remoteMessage.notification?.title ?? '', body: remoteMessage.notification?.body ?? payload ?? '', android: { channelId: 'default', pressAction: {id: 'default', mainComponent: 'TSC'}, }, data:remoteMessage.data }; if (actiontype && action) { notificationData['data'] = {actiontype, action}; } notifee.displayNotification(notificationData); }

  if((remoteMessage.notification?.title || remoteMessage.notification?.body) && AppState.currentState === "active"){
  let notificationData: NotifeeNotification = {
    title: remoteMessage.notification?.title,
    body: remoteMessage.notification?.body,
    android: {
      channelId: 'default',
      pressAction: {id: 'default', mainComponent: 'TSC'},
    },
    data:remoteMessage.data
  };
  notifee.displayNotification(notificationData);
  }
});
return () => {
  unsub();
  AppState.removeEventListener("change", handleStateChange)
};

}, []);

sangamivivek commented 1 year ago

@addingama @mohanenm code snippet that calls the FlyBuy.Pickup.onPermissionChanged() method during order confirmation.

const createOrder = async (sitId, mode, pid, timeplaced, readytime,cafeData) => {     const vehicleDetails: any = await getItemFromPersistance(       VEHICLE_DATA_PERSISTANT_KEY,     );     const CUSTOMER_INFO = {       name:         user && Object.keys(user).length           ? user?.firstName ?? ''           : cartStore?.guestUser?.firstName ?? '',       carType: vehicleDetails?.model ?? '',       carColor: vehicleDetails?.color ?? '',       licensePlate: '',       phone:         user && Object.keys(user).length           ? user?.phone ?? ''           : cartStore?.guestUser?.phone ?? '',     };             const format = timeplaced?.split(' ');     const timePlaced =       format[0].slice(0, 4) +       '/' +       format[0].slice(4, 6) +       '/' +       format[0].slice(6);       const formatReady = readytime?.split(' ');     const readyTime =       formatReady[0].slice(0, 4) +       '-' +       formatReady[0].slice(4, 6) +       '-' +       formatReady[0].slice(6);       const cafeutc = cafeData;     let offsetformat = "'" + cafeutc?.utcoffset + "'";     const offset = offsetformat.split('');           let dateOffset;     let endTimeOffset;     const endTimeformat = readyTime + 'T' + formatReady[1] + ':11.000Z';       if (cafeutc?.utcoffset < 0) {         if (isNaN(offset[4])) {           dateOffset = moment(new Date())             .add(offset[2], 'hours')             .format('YYYY-MM-DD HH:mm');           endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')             .add(offset[2], 'hours')             .format('YYYY-MM-DD HH:mm');         } else {           if (isNaN(offset[5])) {             dateOffset = moment(new Date())               .add(offset[2], 'hours')               .add(offset[4] + 0, 'minutes')               .format('YYYY-MM-DD HH:mm');             endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')               .add(offset[2], 'hours')               .add(offset[4] + 0, 'minutes')               .format('YYYY-MM-DD HH:mm');           } else {             dateOffset = moment(new Date())               .add(offset[2], 'hours')               .add(offset[4] + offset[5], 'minutes')               .format('YYYY-MM-DD HH:mm');             endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')               .add(offset[2], 'hours')               .add(offset[4] + offset[5], 'minutes')               .format('YYYY-MM-DD HH:mm');           }         }         // dateOffset =         //   dateOffset.split('-').join('/').replace(' ', 'T') + '.000Z';         // endTimeOffset =         //   endTimeOffset.split('-').join('/').replace(' ', 'T') + '.000Z';         dateOffset = dateOffset.replace(' ', 'T') + ':00.000Z';         endTimeOffset = endTimeOffset.replace(' ', 'T') + ':00.000Z';         } else {         if (isNaN(offset[4])) {           dateOffset = moment(new Date())             .subtract(offset[2], 'hours')             .format('YYYY-MM-DD HH:mm');           endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')             .subtract(offset[2], 'hours')             .format('YYYY-MM-DD HH:mm');         } else {           if (isNaN(offset[5])) {             dateOffset = moment(new Date())               .subtract(offset[2], 'hours')               .subtract(offset[4] + 0, 'minutes')               .format('YYYY-MM-DD HH:mm');             endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')               .subtract(offset[2], 'hours')               .subtract(offset[4] + 0, 'minutes')               .format('YYYY-MM-DD HH:mm');           } else {             dateOffset = moment(new Date())               .subtract(offset[2], 'hours')               .subtract(offset[4] + offset[5], 'minutes')               .format('YYYY-MM-DD HH:mm');             endTimeOffset = moment(endTimeformat,'YYYY-MM-DD HH:mm')               .subtract(offset[2], 'hours')               .subtract(offset[4] + offset[5], 'minutes')               .format('YYYY-MM-DD HH:mm');           }         }         dateOffset = dateOffset.replace(' ', 'T') + ':00.000Z';         endTimeOffset = endTimeOffset.replace(' ', 'T') + ':00.000Z';       }     let pickupWindow:any;          pickupWindow = {         start: endTimeOffset,         end: endTimeOffset,       };     setLoading(true);     FlyBuy.Core.Customer.getCurrentCustomer()     .then((customerResult) => {       FlyBuy.Core.Orders.createOrder({         siteId: sitId,         pid: pid,         customerInfo: CUSTOMER_INFO,         pickupWindow: pickupWindow,         orderState: OrderStateType.CREATED,         pickupType: mode       }).then((order) => {         setLoading(false);         setOrders(order);         if(Platform.OS === "android")           FlyBuy.Pickup.onPermissionChanged();       }).catch((e)=>{         // logError(EVENTNAME.SDK_ERROR,e,"getCurrentCustomer_createorder")         setLoading(false);       });     })     .catch((e) => {       FlyBuy.Core.Customer.createCustomer(CUSTOMER_INFO).then(         (customer) => {           FlyBuy.Core.Orders.createOrder({             siteId: sitId,             pid: pid,             customerInfo: CUSTOMER_INFO,             pickupWindow: pickupWindow,             orderState: OrderStateType.CREATED,             pickupType: mode           }).then((order) => {             setLoading(false);             setOrders(order);             if(Platform.OS === "android")               FlyBuy.Pickup.onPermissionChanged();           }).catch((e)=>{             // logError(EVENTNAME.SDK_ERROR,e,"createCustomer_createorder")             setLoading(false);           });                  },       );     });       fetchOrders();   };     const fetchOrders = async () => {    FlyBuy.Core.Orders.fetchOrders()         .then((orders) => {             const filter = orders.find(               (o) => o.partnerIdentifier === route?.params?.oloid,             );             setOrders(filter);         })         .catch((err) => {           // logError(EVENTNAME.SDK_ERROR,err,"fetchOrders")           setLoading(false);         });   };

mohanenm commented 1 year ago

@addingama any thoughts?

mohanenm commented 1 year ago

@addingama Just following up on this once more, not quite sure what is happening here, but think it might be related to the wrapper.

addingama commented 1 year ago

Hi, @sangamivivek I can't do much with minimum reproduction repository.

If it's not happening on the sample app, then it's likely not the wrapper issue.

I don't see any updated status related to the changes that I requested.

Call the configure outside any react component

If this is happening on dev and it's not always reproduced, then there is a high chance the App.js is re-mounted and calling the configure again.

Please try create a release build and see if it's crashing or not.

sangamivivek commented 1 year ago

Thanks @addingama We will try and let you know if any issues.

sangamivivek commented 1 year ago

Hi @addingama and @mohanenm,

We have tested both approaches, testing in release build and calling the configure in index.js outside the react component. Unfortunately the error still persists.

To provide a clear overview of the issue. Initially the same codebase works perfectly with react-native-bildit-flybuy version 1.0.4 , however when upgrading to latest version 2.1.1 iOS works fine but android is throwing an error.

Here are the only Changes made in codebase to update the wrapper:

  1. Added in android/app/build.gradle

    implementation ("androidx.appcompat:appcompat:1.3.1") { version { strictly '1.3.1' } }

  2. Added In Android Manifest.xml

    android:fullBackupContent="false" tools:replace="android:allowBackup, android:usesCleartextTraffic, android:fullBackupContent"

  3. Added Kotlin version in android /build.gradle

kotlinVersion = "1.6.0"

Please let me know if you require any additional information or if there are other steps we should consider to resolve this issue.

mohanenm commented 1 year ago

@addingama I recreated it in the development app. It is only happening to me when I select always authorized permissions though.

cc: @sangamivivek

mohanenm commented 1 year ago

I am only able to recreate it when android location permissions are set to “Allow all the time” and FlyBuy.Pickup.onPermissionChanged(); is called.

FlyBuy.Pickup.onPermissionChanged() can be implemented when denying location permissions or allowing while-in-use permissions just fine, but breaks with “Allow all the time”. If I removeFlyBuy.Pickup.onPermissionChanged(), allow all the time permissions work fine. Similar to @sangamivivek, I console.logged core.configure and confirmed it only gets called once.

Code snippet:

const createOrder = () => {

    console.log(Platform.OS)

    FlyBuy.Pickup.onPermissionChanged();

    FlyBuy.Core.Orders.createOrder({

      siteId: SITE_ID,

      pid: NEW_PID.toString(),

      customerInfo: CUSTOMER_INFO,

      pickupType: PickupType.CURBSIDE

    })

      .then((order) => console.log('order', order))

      .catch((err) => console.log(err));
  }; 
addingama commented 1 year ago

@sangamivivek please try version 2.1.3 I've added small changes to prevent crashes

sangamivivek commented 1 year ago

@addingama Thank you for the update. I've installed version 2.1.3, and so far, it's been working well without any crashes. We'll continue to monitor and conduct thorough QA testing. If we happen to come across any issues, we'll let you know. Thanks again! cc: @mohanenm