Skip to content

Commit

Permalink
Merge pull request #1087 from akvo/feature/1084-administration-sqlite…
Browse files Browse the repository at this point in the history
…-datapoints-ync

Feature/1084 administration sqlite datapoints ync
  • Loading branch information
dedenbangkit committed Jan 30, 2024
2 parents 4484fd0 + 1b6403a commit bb2dc65
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 26 deletions.
8 changes: 5 additions & 3 deletions app/src/database/crud/crud-forms.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { conn, query } from '../';
import crudUsers from './crud-users';

const db = conn.init;

Expand Down Expand Up @@ -69,9 +70,10 @@ const formsQuery = () => {
const updateQuery = query.update('forms', { formId }, { latest: latest });
return await conn.tx(db, updateQuery, [formId]);
},
getMyForms: async ({ id }) => {
const sqlQuery = 'SELECT id, name FROM forms WHERE id = $1';
const { rows } = await conn.tx(db, sqlQuery, [id]);
getMyForms: async () => {
const session = await crudUsers.getActiveUser();
const sqlQuery = 'SELECT id, name FROM forms WHERE userId = ?';
const { rows } = await conn.tx(db, sqlQuery, [session.id]);

if (!rows.length) {
return {};
Expand Down
17 changes: 17 additions & 0 deletions app/src/database/crud/crud-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ const usersQuery = () => {
const { rows } = await conn.tx(db, query.read('users', { password: passcode }), [passcode]);
return rows;
},
getUserAdministrationListChunk: async (userId, start, end) => {
try {
const sqlQuery = 'SELECT administrationList FROM users WHERE id = ?';
const { rows } = await conn.tx(db, sqlQuery, [userId]);

if (!rows.length || !rows._array[0].administrationList) {
return [];
}

const fullList = JSON.parse(rows._array[0].administrationList);
const chunk = fullList.slice(start, end);
return chunk;
} catch (error) {
console.error('Get user administration list chunk:', error);
return [];
}
},
};
};

Expand Down
1 change: 1 addition & 0 deletions app/src/database/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const tables = [
password: 'TEXT',
active: 'TINYINT',
token: 'TEXT',
administrationList: 'TEXT',
},
},
{
Expand Down
7 changes: 6 additions & 1 deletion app/src/pages/AuthForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const AuthForm = ({ navigation }) => {
active: 1,
token: data?.syncToken,
password: data?.passcode,
administrationList: data.administrationList,
});
UserState.update((s) => {
s.id = newUserId;
Expand Down Expand Up @@ -108,7 +109,11 @@ const AuthForm = ({ navigation }) => {
s.token = bearerToken;
});

const userID = await handleActiveUser({ ...data, passcode });
const userID = await handleActiveUser({
...data,
passcode,
administrationList: JSON.stringify(data.administrations),
});

await handleGetAllForms(data.formsUrl, userID);

Expand Down
87 changes: 69 additions & 18 deletions app/src/pages/DataSync/AdministrationList.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,76 @@
import React, { useState, useEffect } from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';
import { ActivityIndicator, FlatList, StyleSheet } from 'react-native';
import { ListItem, Button } from '@rneui/themed';
import { BaseLayout } from '../../components';
import { UIState } from '../../store';
import { UIState, UserState } from '../../store';
import { i18n } from '../../lib';
import Icon from 'react-native-vector-icons/Ionicons';
import { crudUsers } from '../../database/crud';
const PAGE_SIZE = 50; // Adjust as needed

const FormSelection = ({ navigation, route }) => {
const params = route?.params || null;
const [filteredData, setFilteredData] = useState([]);
const [search, setSearch] = useState('');
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const activeLang = UIState.useState((s) => s.lang);
const trans = i18n.text(activeLang);

const { id: currentUserId } = UserState.useState((s) => s);

const loadMoreData = async () => {
if (loading || !hasMore) return;
setLoading(true);

const start = data.length;
const end = start + PAGE_SIZE;
const newData = await crudUsers.getUserAdministrationListChunk(currentUserId, start, end);

if (newData.length < PAGE_SIZE) {
setHasMore(false);
}

const updatedData = [...data, ...newData];
setData(updatedData);
filterData(search, updatedData);

setLoading(false);
};

const filterData = (searchText, list) => {
const searchWords = searchText
.toLowerCase()
.split(' ')
.filter((word) => word.trim() !== '');
const filtered = list.filter((item) => {
return searchWords.every((word) => item.name.toLowerCase().includes(word));
});
setFilteredData(filtered);
};

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

useEffect(() => {
filterData(search, data);
}, [search, data]);

const renderItem = ({ item }) => (
<ListItem bottomDivider containerStyle={styles.listItemContainer}>
<ListItem.Content>
<ListItem.Title>{item.name.replaceAll(/\|/g, ', ')}</ListItem.Title>
</ListItem.Content>
<Button
icon={<Icon name="sync" size={24} color="orange" />}
buttonStyle={styles.syncButton}
onPress={() => console.log('Sync button pressed')}
/>
</ListItem>
);

return (
<BaseLayout
title={trans.administrationListPageTitle}
Expand All @@ -23,22 +82,14 @@ const FormSelection = ({ navigation, route }) => {
action: setSearch,
}}
>
<ScrollView>
<View>
<ListItem bottomDivider containerStyle={styles.listItemContainer}>
<ListItem.Content>
<ListItem.Title>sda</ListItem.Title>
<ListItem.Subtitle>Total Datapoints: 2</ListItem.Subtitle>
<ListItem.Subtitle>Last synced date: 2</ListItem.Subtitle>
</ListItem.Content>
<Button
icon={<Icon name="sync" size={24} color="orange" />}
buttonStyle={styles.syncButton}
onPress={() => console.log('Sync button pressed')}
/>
</ListItem>
</View>
</ScrollView>
<FlatList
data={filteredData}
keyExtractor={(item, index) => index.toString()}
renderItem={renderItem}
onEndReached={loadMoreData}
onEndReachedThreshold={0.5}
ListFooterComponent={loading ? <ActivityIndicator size="large" /> : null}
/>
</BaseLayout>
);
};
Expand Down
6 changes: 2 additions & 4 deletions app/src/pages/DataSync/ForSelection.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { ScrollView, View } from 'react-native';
import { ListItem } from '@rneui/themed';
import { BaseLayout } from '../../components';
import { UIState, UserState } from '../../store';
import { UIState } from '../../store';
import { i18n } from '../../lib';
import { crudForms } from '../../database/crud';

Expand All @@ -11,12 +11,10 @@ const FormSelection = ({ navigation }) => {
const activeLang = UIState.useState((s) => s.lang);
const trans = i18n.text(activeLang);

const { id: currentUserId } = UserState.useState((s) => s);

useEffect(() => {
const fetchForms = async () => {
try {
const formsData = await crudForms.getMyForms({ id: currentUserId });
const formsData = await crudForms.getMyForms();
setForms(formsData);
} catch (error) {
console.error('Error fetching forms:', error);
Expand Down

0 comments on commit bb2dc65

Please sign in to comment.