Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
dedenbangkit committed Jan 19, 2024
2 parents 7de241f + c7a5ac6 commit 78e84e6
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 88 deletions.
59 changes: 55 additions & 4 deletions app/App.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
import React from 'react';
import React, { useCallback, useEffect } from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import NetInfo from '@react-native-community/netinfo';
import * as Notifications from 'expo-notifications';
import * as TaskManager from 'expo-task-manager';
import * as BackgroundFetch from 'expo-background-fetch';

import Navigation from './src/navigation';
import { conn, query, tables } from './src/database';
import { UIState, AuthState, UserState, BuildParamsState } from './src/store';
import { crudUsers, crudConfig } from './src/database/crud';
import { api } from './src/lib';
import { NetworkStatusBar } from './src/components';
import { NetworkStatusBar, SyncService } from './src/components';
import backgroundTask, {
SYNC_FORM_SUBMISSION_TASK_NAME,
SYNC_FORM_VERSION_TASK_NAME,
defineSyncFormSubmissionTask,
defineSyncFormVersionTask,
} from './src/lib/background-task';

const db = conn.init;

export const setNotificationHandler = () =>
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});

setNotificationHandler();
defineSyncFormVersionTask();

TaskManager.defineTask(SYNC_FORM_SUBMISSION_TASK_NAME, async () => {
try {
await backgroundTask.syncFormSubmission();
return BackgroundFetch.BackgroundFetchResult.NewData;
} catch (err) {
console.error(`[${SYNC_FORM_SUBMISSION_TASK_NAME}] Define task manager failed`, err);
return BackgroundFetch.Result.Failed;
}
});

const App = () => {
const serverURLState = BuildParamsState.useState((s) => s.serverURL);
const syncValue = BuildParamsState.useState((s) => s.dataSyncInterval);
Expand Down Expand Up @@ -64,7 +95,7 @@ const App = () => {
console.info('[CONFIG] Server URL', serverURL);
};

React.useEffect(() => {
useEffect(() => {
const queries = tables.map((t) => {
const queryString = query.initialQuery(t.name, t.fields);
return conn.tx(db, queryString);
Expand All @@ -78,7 +109,7 @@ const App = () => {
});
}, []);

React.useEffect(() => {
useEffect(() => {
const unsubscribe = NetInfo.addEventListener((state) => {
UIState.update((s) => {
s.online = state.isConnected;
Expand All @@ -91,10 +122,30 @@ const App = () => {
};
}, []);

const handleOnRegisterTask = useCallback(async () => {
try {
const allTasks = await TaskManager.getRegisteredTasksAsync();
console.log('allTasks', allTasks);
allTasks.forEach(async (a) => {
if ([SYNC_FORM_SUBMISSION_TASK_NAME, SYNC_FORM_VERSION_TASK_NAME].includes(a.taskName)) {
console.info(`[${a.taskName}] IS REGISTERED`);
await backgroundTask.registerBackgroundTask(a.taskName);
}
});
} catch (error) {
console.error('TASK REGISTER ERROR', error);
}
}, []);

useEffect(() => {
handleOnRegisterTask();
}, [handleOnRegisterTask]);

return (
<SafeAreaProvider>
<Navigation testID="navigation-element" />
<NetworkStatusBar />
<SyncService />
</SafeAreaProvider>
);
};
Expand Down
21 changes: 21 additions & 0 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"expo-file-system": "~15.2.2",
"expo-image-picker": "~14.1.1",
"expo-location": "~15.1.1",
"expo-network": "~5.2.1",
"expo-notifications": "~0.18.1",
"expo-splash-screen": "~0.18.2",
"expo-sqlite": "^11.1.1",
Expand All @@ -41,15 +42,15 @@
"pullstate": "^1.25.0",
"react": "18.2.0",
"react-native": "0.71.8",
"react-native-background-actions": "^3.0.1",
"react-native-element-dropdown": "^2.9.0",
"react-native-material-menu": "^2.0.0",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "^4.5.0",
"react-native-screens": "~3.20.0",
"react-native-vector-icons": "^9.2.0",
"react-native-webview": "11.26.0",
"yup": "^1.2.0",
"expo-network": "~5.2.1"
"yup": "^1.2.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
35 changes: 35 additions & 0 deletions app/src/components/SyncService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useCallback, useEffect } from 'react';
import { BuildParamsState, UIState } from '../store';
import { backgroundTask } from '../lib';
/**
* This sync only works in the foreground service
*/
const SyncService = () => {
const isOnline = UIState.useState((s) => s.online);
const syncInterval = BuildParamsState.useState((s) => s.dataSyncInterval);
const syncInSecond = parseInt(syncInterval) * 1000;

const onSync = useCallback(async () => {
await backgroundTask.syncFormSubmission();
}, []);

useEffect(() => {
if (!syncInSecond || !isOnline) {
return;
}

const syncTimer = setInterval(() => {
// Perform sync operation
onSync();
}, syncInSecond);

return () => {
// Clear the interval when the component unmounts
clearInterval(syncTimer);
};
}, [syncInSecond, isOnline, onSync]);

return null; // This is a service component, no rendering is needed
};

export default SyncService;
1 change: 1 addition & 0 deletions app/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as Image } from './Image';
export { default as CenterLayout } from './CenterLayout';
export { default as LogoutButton } from './LogoutButton';
export { default as NetworkStatusBar } from './NetworkStatusBar';
export { default as SyncService } from './SyncService';
54 changes: 43 additions & 11 deletions app/src/lib/background-task.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const syncFormVersion = async ({
// update previous form latest value to 0
await crudForms.updateForm({ ...form });
console.info('[syncForm]Updated Forms...', form.id);
const savedForm = await crudForms.addForm({ ...form, formJSON: formRes?.data });
const savedForm = await crudForms.addForm({
...form,
userId: session?.id,
formJSON: formRes?.data,
});
console.info('[syncForm]Saved Forms...', form.id);
return savedForm;
});
Expand All @@ -51,10 +55,13 @@ const syncFormVersion = async ({
}
};

const registerBackgroundTask = async (TASK_NAME, minimumInterval = 3600) => {
const registerBackgroundTask = async (TASK_NAME, settingsValue = null) => {
try {
const config = await crudConfig.getConfig();
const syncInterval = settingsValue || parseInt(config?.syncInterval) || 3600;
console.log('syncInterval', syncInterval);
await BackgroundFetch.registerTaskAsync(TASK_NAME, {
minimumInterval: minimumInterval,
minimumInterval: syncInterval,
stopOnTerminate: false, // android only,
startOnBoot: true, // android only
});
Expand All @@ -71,16 +78,10 @@ const unregisterBackgroundTask = async (TASK_NAME) => {
}
};

const backgroundTaskStatus = async (TASK_NAME, minimumInterval = 3600) => {
const backgroundTaskStatus = async (TASK_NAME) => {
const status = await BackgroundFetch.getStatusAsync();
const isRegistered = await TaskManager.isTaskRegisteredAsync(TASK_NAME);
const config = await crudConfig.getConfig();
const intervalValue = config?.syncInterval || minimumInterval;

if (BackgroundFetch.BackgroundFetchStatus?.[status] === 'Available' && !isRegistered) {
await registerBackgroundTask(TASK_NAME, intervalValue);
}
console.log(`[${TASK_NAME}] Status`, status, isRegistered, minimumInterval);
console.info(`[${TASK_NAME}] Status`, status, isRegistered);
};

const handleOnUploadPhotos = async (data) => {
Expand Down Expand Up @@ -208,4 +209,35 @@ const backgroundTaskHandler = () => {
};

const backgroundTask = backgroundTaskHandler();

export const SYNC_FORM_VERSION_TASK_NAME = 'sync-form-version';

export const SYNC_FORM_SUBMISSION_TASK_NAME = 'sync-form-submission';

export const defineSyncFormVersionTask = () =>
TaskManager.defineTask(SYNC_FORM_VERSION_TASK_NAME, async () => {
try {
await syncFormVersion({
sendPushNotification: notification.sendPushNotification,
showNotificationOnly: true,
});
return BackgroundFetch.BackgroundFetchResult.NewData;
} catch (err) {
console.error(`[${SYNC_FORM_VERSION_TASK_NAME}] Define task manager failed`, err);
return BackgroundFetch.Result.Failed;
}
});

export const defineSyncFormSubmissionTask = () => {
TaskManager.defineTask(SYNC_FORM_SUBMISSION_TASK_NAME, async () => {
try {
await syncFormSubmission();
return BackgroundFetch.BackgroundFetchResult.NewData;
} catch (err) {
console.error(`[${SYNC_FORM_SUBMISSION_TASK_NAME}] Define task manager failed`, err);
return BackgroundFetch.Result.Failed;
}
});
};

export default backgroundTask;
Loading

0 comments on commit 78e84e6

Please sign in to comment.