diff --git a/hooks/useDeviceInfoCollector.js b/hooks/useDeviceInfoCollector.js new file mode 100644 index 0000000..aa7fe49 --- /dev/null +++ b/hooks/useDeviceInfoCollector.js @@ -0,0 +1,34 @@ +import {useEffect} from 'react'; +import {collectDeviceInfo} from '../lib/deviceinfo'; +// eslint-disable-next-line no-unused-vars +import {Api, Realm} from '../lib'; + +// This hook is used to collect device information and send it to the server. +// It's purpose is to backfill data on users that registered before the device information +// was added to the registration form. +export function useDeviceInfoCollector() { + useEffect(() => { + const checkNeedsUpdate = async () => { + const appUser = await Realm.getUser(); + if (!appUser) { + return; + } + if (appUser.hasDeviceInfoTracked) { + return; + } + const deviceInfo = collectDeviceInfo(); + // TODO: Uncomment this when the API is ready + // const updated = await Api.appUser.updatev2(appUser.account_id, { + // device_type: deviceInfo.deviceType, + // device_version: deviceInfo.deviceVersion, + // }); + await appUser.update({ + // Replace this with the return value + // of the API call. + device_type: deviceInfo.deviceType, + device_version: deviceInfo.deviceVersion, + }); + }; + checkNeedsUpdate(); + }, []); +} diff --git a/lib/api.js b/lib/api.js index ba979fd..52989ee 100644 --- a/lib/api.js +++ b/lib/api.js @@ -46,6 +46,43 @@ export default { sexual_orien_other, }); }, + createv2: function ( + account_id, + age, + device_model, + device_type, + device_version, + email, + firstName, + gender, + gender_other, + is_latino, + lastName, + race, + race_other, + sexual_orien, + sexual_orien_other, + zip, + ) { + return instance.post('/v2/appuser', { + account_id, + age, + device_model, + device_type, + device_version, + email, + firstName, + gender, + gender_other, + is_latino, + lastName, + race, + race_other, + sexual_orien, + sexual_orien_other, + zip, + }); + }, update: function (account_id, attributes) { const payload = _.pick(attributes, [ 'is_latino', @@ -59,6 +96,37 @@ export default { payload.account_id = account_id; return instance.put('appuser/create', payload); }, + updatev2: function (appuser, attributes) { + const { + device_model, + device_type, + device_version, + gender, + gender_other, + is_latino, + race, + race_other, + sexual_orien, + sexual_orien_other, + } = attributes; + const payload = { + account_id: appuser.id, + device_model, + device_type, + device_version, + gender, + gender_other, + is_latino, + race, + race_other, + sexual_orien, + sexual_orien_other, + }; + const updates = instance.patch('/v2/appuser', payload); + // pessimistically update the appuser. + appuser.update(updates); + return updates; + }, delete: function (account_id) { return instance.delete('appuser/delete', { data: {account_id: account_id}, diff --git a/lib/deviceinfo.js b/lib/deviceinfo.js new file mode 100644 index 0000000..4a28976 --- /dev/null +++ b/lib/deviceinfo.js @@ -0,0 +1,13 @@ +import {Platform} from 'react-native'; + +export function collectDeviceInfo() { + return { + deviceType: Platform.OS, // iOS or Android + // https://reactnative.dev/docs/platform#version + // number on Android, string on iOS + deviceVersion: `${Platform.Version}`, // OS version + // Collecting Device Model? e.g. Google Pixel, Samsung Galaxy, iPhone 12 + // Use react-native-device-info. Ticket for an eager developer to implement. + // deviceModel: '', + }; +} diff --git a/lib/realm.js b/lib/realm.js index 43ccf30..51d7486 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -21,6 +21,30 @@ class AppUser extends Realm.Object { this.sexual_orien ); } + // Temporary method to check if we have collected + // the device information from this user. + // This is because older users created before the update + // did not have the device information collected during sign up. + get hasDeviceInfoTracked() { + return Boolean( + // Switch each to && once we need + // to collect device model also. + this.device_type || this.device_version || this.device_model, + ); + } + + async update(attributes) { + return write(realm => { + realm.create( + 'AppUser', + { + id: this.id, + ...attributes, + }, + 'modified', + ); + }); + } } AppUser.schema = { @@ -42,6 +66,9 @@ AppUser.schema = { gender_other: 'string?', sexual_orien: 'string?', sexual_orien_other: 'string?', + device_model: 'string?', + device_type: 'string?', + device_version: 'string?', }, }; @@ -269,6 +296,9 @@ async function createUser(obj) { 'gender_other', 'sexual_orien', 'sexual_orien_other', + 'device_type', + 'device_version', + 'device_model', ]); if (!data.firstName && data.name) { data.firstName = data.name.split(' ')[0]; diff --git a/screens/main/home.js b/screens/main/home.js index 2ceba29..0cce2ef 100644 --- a/screens/main/home.js +++ b/screens/main/home.js @@ -22,6 +22,7 @@ import {GlobalStyles, Colors} from '../../styles'; import {StatBox, RecordedWalk} from '../../components'; import moment from 'moment'; import numeral from 'numeral'; +import {useDeviceInfoCollector} from '../../hooks/useDeviceInfoCollector'; export default function HomeScreen({navigation, route}) { const safeAreaInsets = useSafeArea(); @@ -40,6 +41,8 @@ export default function HomeScreen({navigation, route}) { const [activeWalk, setActiveWalk] = useState(null); const [hasGoals, setHasGoals] = useState(false); + useDeviceInfoCollector(); + async function saveStepsAndDistances() { const newContest = await Realm.getContest(); const today = moment().endOf('day'); diff --git a/screens/onboarding/signup.js b/screens/onboarding/signup.jsx similarity index 96% rename from screens/onboarding/signup.js rename to screens/onboarding/signup.jsx index 4e4c35c..de9030a 100644 --- a/screens/onboarding/signup.js +++ b/screens/onboarding/signup.jsx @@ -30,6 +30,7 @@ import {Api, Realm, Strings} from '../../lib'; import ContestRules from '../../assets/contestRules'; import Privacy from '../../assets/privacy'; import validZipCodes from '../../lib/validZipCodes'; +import {collectDeviceInfo} from '../../lib/deviceinfo'; export default function SignUpScreen({navigation, route}) { const {contest} = route.params; @@ -104,6 +105,10 @@ export default function SignUpScreen({navigation, route}) { setLoading(true); try { const settings = await Realm.getSettings(); + // eslint-disable-next-line no-unused-vars + const {deviceType, deviceVersion} = collectDeviceInfo(); + // TODO: swap over to .createv2 once the API is updated + // drill in device info. const response = await Api.appUser.create( firstName.trim(), lastName.trim(), @@ -117,11 +122,9 @@ export default function SignUpScreen({navigation, route}) { id: response.data.payload.account_id, }); setLoading(false); - if (user.isSurveyCompleted) { - navigation.navigate('SetYourStepGoal'); - } else { - navigation.navigate('LoHOrigin'); - } + navigation.navigate( + user.isSurveyCompleted ? 'SetYourStepGoal' : 'LoHOrigin', + ); } catch (error) { setLoading(false); setAlertTitle(Strings.common.serverErrorTitle);