Created
January 19, 2023 22:53
-
-
Save zhelezkov/ceb7b96fed645cb5e3dd919eea45c03b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DeviceInfo from 'react-native-device-info'; | |
import { | |
getNotificationsToken, | |
getNotificationsPermission, | |
onNotificationTokenChange, | |
PushNotificationStatus, | |
firebaseNotificationsAuthStatusToBoolean, | |
getNotificationsPermissionString, | |
} from '@src/notifications'; | |
import * as Sentry from '@sentry/react-native'; | |
import { Severity } from '@sentry/react-native'; | |
import auth from '@react-native-firebase/auth'; | |
import { fetcher } from '@src/fetcher'; | |
import { createEffect, createEvent } from 'effector'; | |
import { debounce } from 'patronum'; | |
// update device on app open(useful since notification token might be changed) | |
// update device on user change(useful to attach device to customer) | |
auth().onAuthStateChanged(() => updateDevice()); | |
// update device in case of notification token has changed during app runtime | |
onNotificationTokenChange(() => updateDevice()); | |
export const updateDevice = createEvent(); | |
const updateDeviceFx = createEffect(async () => { | |
const [deviceInfo, pushPermission, notificationsToken] = await Promise.all([ | |
collectDeviceInfo(), | |
getNotificationsPermission(), | |
getNotificationsToken(), | |
]); | |
const notificationsEnabled = | |
firebaseNotificationsAuthStatusToBoolean(pushPermission); | |
const pushPermissionHumanReadable = | |
getNotificationsPermissionString(pushPermission); | |
await patchCustomerDevice({ | |
uniqueDeviceId: deviceInfo.deviceId, | |
notificationsToken: notificationsToken, | |
notificationsEnabled: notificationsEnabled, | |
pushPermission: pushPermissionHumanReadable, | |
additionalInfo: deviceInfo.additionalInfo, | |
}); | |
}); | |
updateDeviceFx.failData.watch((err) => Sentry.captureException(err)); | |
debounce({ | |
source: updateDevice, | |
target: updateDeviceFx, | |
timeout: 1488, | |
}); | |
interface PathCustomerDeviceParams { | |
uniqueDeviceId: string; | |
notificationsToken?: string | null; | |
notificationsEnabled?: boolean; | |
pushPermission?: PushNotificationStatus; | |
additionalInfo?: Record<string, any>; | |
} | |
async function patchCustomerDevice({ | |
uniqueDeviceId, | |
notificationsToken, | |
notificationsEnabled, | |
pushPermission, | |
additionalInfo, | |
}: PathCustomerDeviceParams): Promise<unknown> { | |
const endpoint = auth().currentUser | |
? 'v1/customer/me/device' | |
: 'v1/customer/device'; | |
return fetcher.patch(endpoint, { | |
json: { | |
nativeId: uniqueDeviceId, | |
fcmRegistrationToken: notificationsToken, | |
pushNotificationsEnabled: notificationsEnabled, | |
pushPermission: pushPermission, | |
additionalInfo: additionalInfo, | |
}, | |
}); | |
} | |
async function collectDeviceInfo(): Promise<{ | |
deviceId: string; | |
additionalInfo: Record<string, any>; | |
}> { | |
const apiLevel = DeviceInfo.getApiLevel(); | |
const baseOs = DeviceInfo.getBaseOs(); | |
const bootLoader = DeviceInfo.getBootloader(); | |
const carrier = DeviceInfo.getCarrier(); | |
const device = DeviceInfo.getDevice(); | |
const display = DeviceInfo.getDisplay(); | |
const deviceName = DeviceInfo.getDeviceName(); | |
const deviceToken = DeviceInfo.getDeviceToken(); | |
const firstInstallTime = DeviceInfo.getFirstInstallTime(); | |
const fingerprint = DeviceInfo.getFingerprint(); | |
const fontScale = DeviceInfo.getFontScale(); | |
const hardware = DeviceInfo.getHardware(); | |
const hostname = DeviceInfo.getHost(); | |
const installerPackageName = DeviceInfo.getInstallerPackageName(); | |
const installerReferrer = DeviceInfo.getInstallReferrer(); | |
const instanceId = DeviceInfo.getInstanceId(); | |
const lastUpdateTime = DeviceInfo.getLastUpdateTime(); | |
const macAddress = DeviceInfo.getMacAddress(); | |
const manufacturer = DeviceInfo.getManufacturer(); | |
const product = DeviceInfo.getProduct(); | |
const buildId = DeviceInfo.getBuildId(); | |
const uniqueId = DeviceInfo.syncUniqueId(); | |
const isEmulator = DeviceInfo.isEmulator(); | |
const isTabletMode = DeviceInfo.isTabletMode(); | |
const hasGms = DeviceInfo.hasGms(); | |
const hasHms = DeviceInfo.hasHms(); | |
const systemAvailableFeatures = DeviceInfo.getSystemAvailableFeatures(); | |
const availableLocationProviders = DeviceInfo.getAvailableLocationProviders(); | |
const diskCapacity = DeviceInfo.getTotalDiskCapacity(); | |
const isLocationEnabled = DeviceInfo.isLocationEnabled(); | |
const userAgent = DeviceInfo.getUserAgent(); | |
const brand = DeviceInfo.getBrand(); | |
const manufacturerDeviceId = DeviceInfo.getDeviceId(); | |
const systemName = DeviceInfo.getSystemName(); | |
const systemVersion = DeviceInfo.getSystemVersion(); | |
const hasNotch = DeviceInfo.hasNotch(); | |
const isTablet = DeviceInfo.isTablet(); | |
const deviceType = DeviceInfo.getDeviceType(); | |
const all = Object.entries({ | |
apiLevel, | |
baseOs, | |
bootLoader, | |
carrier, | |
device, | |
display, | |
deviceName, | |
deviceToken, | |
firstInstallTime, | |
fingerprint, | |
fontScale, | |
hardware, | |
hostname, | |
installerPackageName, | |
installerReferrer, | |
instanceId, | |
lastUpdateTime, | |
macAddress, | |
manufacturer, | |
product, | |
buildId, | |
uniqueId, | |
isEmulator, | |
isTabletMode, | |
hasGms, | |
hasHms, | |
systemAvailableFeatures, | |
availableLocationProviders, | |
diskCapacity, | |
isLocationEnabled, | |
userAgent, | |
}).map(([key, promise]) => | |
promise | |
.then((value) => ({ key, status: 'fulfilled', value })) | |
.catch((value) => ({ key, status: 'rejected', value })), | |
); | |
const allData = Object.fromEntries( | |
(await Promise.all(all)) | |
.filter((it) => { | |
if (it.status === 'rejected') { | |
Sentry.captureMessage( | |
'unable to resolve device info param', | |
(scope) => { | |
scope.setLevel(Severity.Warning); | |
scope.setContext('device_info_reject', { | |
key: it.key, | |
value: it.value, | |
}); | |
return scope; | |
}, | |
); | |
} | |
return it.status === 'fulfilled'; | |
}) | |
.map((it) => [it.key, it.value]), | |
); | |
return { | |
deviceId: allData.uniqueId as string, | |
additionalInfo: { | |
...allData, | |
brand, | |
manufacturerDeviceId, | |
systemName, | |
systemVersion, | |
hasNotch, | |
isTablet, | |
deviceType, | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment