Skip to content

Commit

Permalink
Merge branch 'develop' into feature/make-form-header-sticky
Browse files Browse the repository at this point in the history
  • Loading branch information
dedenbangkit committed Jan 31, 2024
2 parents 8bf84de + fa0759f commit 20e28f5
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 151 deletions.
15 changes: 8 additions & 7 deletions app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import backgroundTask, {
defineSyncFormVersionTask,
} from './src/lib/background-task';
import crudJobs, { jobStatus, MAX_ATTEMPT } from './src/database/crud/crud-jobs';
import { ToastAndroid } from 'react-native';

export const setNotificationHandler = () =>
Notifications.setNotificationHandler({
Expand Down Expand Up @@ -135,18 +136,18 @@ const App = () => {
};

const handleInitDB = useCallback(async () => {
await conn.reset();
const db = conn.init;
const queries = tables.map((t) => {
const queryString = query.initialQuery(t.name, t.fields);
return conn.tx(db, queryString);
});
try {
await conn.reset();
const db = conn.init;
const queries = tables.map((t) => {
const queryString = query.initialQuery(t.name, t.fields);
return conn.tx(db, queryString);
});
await Promise.all(queries);
await handleInitConfig();
handleCheckSession();
} catch (error) {
console.error('[INITIAL DB]', error);
ToastAndroid.show(`[INITIAL DB]: ${error}`, ToastAndroid.LONG);
}
}, [handleInitConfig, handleCheckSession]);

Expand Down
2 changes: 1 addition & 1 deletion app/src/database/conn.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const removeDB = async () => {
}
}
} catch (error) {
console.error('[RESET DB]', error);
return Promise.reject(error);
}
};

Expand Down
12 changes: 7 additions & 5 deletions app/src/database/crud/crud-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ const configQuery = () => {
const id = 1;
return {
getConfig: async () => {
const { rows } = await conn.tx(db, query.read('config', { id }), [id]);
if (!rows.length) {
return false;
}
return rows._array[rows.length - 1];
try {
const { rows } = await conn.tx(db, query.read('config', { id }), [id]);
if (!rows.length) {
return false;
}
return rows._array[rows.length - 1];
} catch {}
},
addConfig: async (data = {}) => {
const insertQuery = query.insert('config', {
Expand Down
9 changes: 5 additions & 4 deletions app/src/lib/background-task.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ const registerBackgroundTask = async (TASK_NAME, settingsValue = null) => {
startOnBoot: true, // android only
});
} catch (err) {
console.error('Task Register failed:', err);
return Promise.reject(err);
}
};

const unregisterBackgroundTask = async (TASK_NAME) => {
try {
await BackgroundFetch.unregisterTaskAsync(TASK_NAME);
} catch (err) {
console.error('Task Unregister failed:', err);
return Promise.reject(err);
}
};

Expand Down Expand Up @@ -215,15 +215,16 @@ const syncFormSubmission = async (activeJob = {}) => {
await crudJobs.deleteJob(activeJob.id);
}
return res;
} catch (err) {
} catch (error) {
const { status: errorCode } = error?.response;
if (activeJob?.id) {
const updatePayload =
activeJob.attempt < MAX_ATTEMPT
? { status: jobStatus.FAILED, attempt: activeJob.attempt + 1 }
: { status: jobStatus.ON_PROGRESS, info: String(err) };
crudJobs.updateJob(activeJob.id, updatePayload);
}
console.error('[syncFormSubmission] Error: ', err);
return Promise.reject({ errorCode, message: error?.message });
}
};

Expand Down
63 changes: 29 additions & 34 deletions app/src/pages/AuthForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,43 +95,38 @@ const AuthForm = ({ navigation }) => {
api
.post('/auth', { code: passcode })
.then(async (res) => {
try {
const { data } = res;
// save session
const bearerToken = data.syncToken;
api.setToken(bearerToken);

await crudConfig.updateConfig({ authenticationCode: passcode });
await cascades.createSqliteDir();
// update auth state
AuthState.update((s) => {
s.authenticationCode = passcode;
s.token = bearerToken;
});

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

await handleGetAllForms(data.formsUrl, userID);

// go to home page (form list)
setTimeout(() => {
navigation.navigate('Home', { newForms: true });
}, 500);
} catch (err) {
console.error(err);
}
const { data } = res;
// save session
const bearerToken = data.syncToken;
api.setToken(bearerToken);

await crudConfig.updateConfig({ authenticationCode: passcode });
await cascades.createSqliteDir();
// update auth state
AuthState.update((s) => {
s.authenticationCode = passcode;
s.token = bearerToken;
});

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

await handleGetAllForms(data.formsUrl, userID);

// go to home page (form list)
setTimeout(() => {
navigation.navigate('Home', { newForms: true });
}, 500);
})
.catch((err) => {
const { status: errStatus, message: errMessage } = err?.response;
if ([400, 401].includes(errStatus)) {
setError(trans.authErrorPasscode);
const { status: errorCode } = err?.response;
if ([400, 401].includes(errorCode)) {
setError(`${errorCode}: ${trans.authErrorPasscode}`);
} else {
console.log('errStatus', err?.message);
setError(errMessage);
setError(`${errorCode}: ${err?.message}`);
}
})
.finally(() => setLoading(false));
Expand Down
6 changes: 4 additions & 2 deletions app/src/pages/FormData.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ const FormDataPage = ({ navigation, route }) => {
} else {
await runSyncSubmision();
}
} catch (e) {
console.error('[Manual SyncFormSubmission]: ', e);
} catch (error) {
setData(data);
setSyncing(false);
ToastAndroid.show(`${error?.errorCode}: ${error?.message}`, ToastAndroid.LONG);
}
};

Expand Down
10 changes: 4 additions & 6 deletions app/src/pages/FormPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,9 @@ const FormPage = ({ navigation, route }) => {
}
refreshForm();
navigation.navigate('Home', { ...route?.params });
} catch (err) {
console.error(err);
} catch (error) {
if (Platform.OS === 'android') {
ToastAndroid.show(trans.errorSaveDatapoint, ToastAndroid.LONG);
ToastAndroid.show(`SQL: ${error}`, ToastAndroid.LONG);
}
}
};
Expand Down Expand Up @@ -192,10 +191,9 @@ const FormPage = ({ navigation, route }) => {
}
refreshForm();
navigation.navigate('Home', { ...route?.params });
} catch (err) {
console.error(err);
} catch (error) {
if (Platform.OS === 'android') {
ToastAndroid.show(trans.errorSubmitted, ToastAndroid.LONG);
ToastAndroid.show(`SQL: ${error}`, ToastAndroid.LONG);
}
}
};
Expand Down
10 changes: 4 additions & 6 deletions app/src/pages/GetStarted.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ const GetStarted = ({ navigation }) => {
const trans = i18n.text(activeLang);

const getConfig = useCallback(async () => {
try {
const config = await crudConfig.getConfig();
if (config) {
setCurrentConfig(config);
}
} catch (error) {}
const config = await crudConfig.getConfig();
if (config) {
setCurrentConfig(config);
}
}, []);

const isServerURLDefined = useMemo(() => {
Expand Down
4 changes: 2 additions & 2 deletions app/src/pages/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ const Home = ({ navigation, route }) => {
.filter((r) => r?.userId === currentUserId);
setData(forms);
setloading(false);
} catch {
} catch (error) {
if (Platform.OS === 'android') {
ToastAndroid.show(trans.errorFormsNotLoaded, ToastAndroid.SHORT);
ToastAndroid.show(`SQL: ${error}`, ToastAndroid.SHORT);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions backend/api/v1/v1_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ def to_data_frame(self):
"updated_by":
self.updated_by.get_full_name() if self.updated_by else None,
"created_at":
self.created.strftime("%B %d, %Y"),
self.created.strftime("%B %d, %Y %I:%M %p"),
"updated_at":
self.updated.strftime("%B %d, %Y") if self.updated else None,
self.updated.strftime("%B %d, %Y %I:%M %p")
if self.updated else None,
}
for a in self.data_answer.order_by(
'question__question_group_id',
Expand Down
2 changes: 2 additions & 0 deletions backend/api/v1/v1_data/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,7 @@ def create(self, validated_data):
administration=data.get("administration"),
geo=data.get("geo"),
created_by=data.get("created_by"),
created=data.get("submitedAt") or timezone.now(),
)

for answer in validated_data.get("answer"):
Expand Down Expand Up @@ -1185,6 +1186,7 @@ def create(self, validated_data):
value=value,
options=option,
created_by=self.context.get("user"),
created=data.get("submitedAt") or timezone.now(),
)

# save to form data
Expand Down
1 change: 1 addition & 0 deletions backend/api/v1/v1_data/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def seed_approved_data(data):
administration=data.administration,
geo=data.geo,
created_by=data.created_by,
created=data.created,
)
data.data = form_data
data.approved = True
Expand Down
2 changes: 1 addition & 1 deletion backend/rtmis/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'
TIME_ZONE = 'Africa/Nairobi'

USE_I18N = True

Expand Down
5 changes: 4 additions & 1 deletion backend/utils/functions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from django.utils import timezone
from api.v1.v1_data.models import Answers, AnswerHistory
from api.v1.v1_forms.constants import QuestionTypes


def update_date_time_format(date):
if date:
# date = timezone.datetime.strptime(date, "%Y-%m-%d").date()
return date.date().strftime('%B %d, %Y')
if not timezone.is_naive(date):
return timezone.localtime(date).strftime("%Y-%m-%d %I:%M %p")
return date.strftime("%Y-%m-%d %I:%M %p")
return None


Expand Down
58 changes: 56 additions & 2 deletions frontend/src/components/filters/AdministrationDropdown.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import "./style.scss";
import { Select, Space } from "antd";
import { Select, Space, Checkbox, Row, Col } from "antd";
import PropTypes from "prop-types";
import { store, api } from "../../lib";
import { useCallback } from "react";
Expand All @@ -16,9 +16,12 @@ const AdministrationDropdown = ({
currentId = null,
onChange,
limitLevel = false,
isSelectAllVillage = false,
selectedAdministrations = [],
...props
}) => {
const { user, administration, levels } = store.useState((state) => state);
const [checked, setChecked] = useState(false);
/**
* Get lowest level administrator from maxLevel.
* otherwise, sort asc by level and get the last item from levels global state
Expand Down Expand Up @@ -49,6 +52,15 @@ const AdministrationDropdown = ({
fetchUserAdmin();
}, [fetchUserAdmin, persist]);

useEffect(() => {
const multiadministration = administration?.find(
(admLevel) => admLevel.level === lowestLevel.level - 1
)?.children;
if (multiadministration?.length === selectedAdministrations?.length) {
setChecked(true);
}
}, [administration, selectedAdministrations, lowestLevel.level]);

const handleChange = async (e, index) => {
if (!e) {
return;
Expand All @@ -73,6 +85,39 @@ const AdministrationDropdown = ({
}
};

const handleSelectAllVillage = (e) => {
if (e.target.checked) {
setChecked(true);
let admItems = null;
const multiadministration = administration?.find(
(admLevel) => admLevel.level === lowestLevel.level - 1
)?.children;
admItems = multiadministration;
if (selectedAdministrations.length === admItems.length) {
return;
}
store.update((s) => {
s.administration = s.administration.concat(admItems);
});
if (onChange) {
const _values = admItems.map((item) => item.id);
onChange(_values);
}
} else {
setChecked(false);
store.update((s) => {
s.administration = s.administration.filter(
(data) => data.level <= lowestLevel.level - 1
);
});
if (onChange) {
onChange(
administration.filter((data) => data.level <= lowestLevel.level - 1)
);
}
}
};

const handleClear = (index) => {
store.update((s) => {
s.administration.length = index + 1;
Expand Down Expand Up @@ -151,6 +196,15 @@ const AdministrationDropdown = ({
);
}
})}
{isSelectAllVillage && maxLevel === 5 && (
<Row className="form-row">
<Col span={24}>
<Checkbox onChange={handleSelectAllVillage} checked={checked}>
Select all village
</Checkbox>
</Col>
</Row>
)}
</Space>
);
}
Expand Down
Loading

0 comments on commit 20e28f5

Please sign in to comment.