• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

akvo / nmis-mobile / 5713781609

31 Jul 2023 10:50AM UTC coverage: 79.711% (+0.2%) from 79.531%
5713781609

push

github

ifirmawan
[#98] Revert GetStarted snapshot to main

624 of 831 branches covered (75.09%)

Branch coverage included in aggregate %.

1305 of 1589 relevant lines covered (82.13%)

17.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.83
/app/src/pages/FormData.js
1
import React, { useState, useEffect, useMemo } from 'react';
2
import { Button, Dialog, Text } from '@rneui/themed';
3
import { View, ActivityIndicator, StyleSheet } from 'react-native';
4
import Icon from 'react-native-vector-icons/Ionicons';
5

6
import { UserState } from '../store';
7
import { BaseLayout } from '../components';
8
import { crudDataPoints } from '../database/crud';
9
import { i18n, backgroundTask } from '../lib';
10
import { UIState } from '../store';
11

12
const convertMinutesToHHMM = (minutes) => {
3✔
13
  const hours = Math.floor(minutes / 60);
13✔
14
  const remainingMinutes = Math.round(minutes % 60);
13✔
15

16
  const formattedHours = String(hours).padStart(2, '0');
13✔
17
  const formattedMinutes = String(remainingMinutes).padStart(2, '0');
13✔
18

19
  return `${formattedHours}h ${formattedMinutes}m`;
13✔
20
};
21

22
const syncButtonElement = ({
3✔
23
  showSubmitted,
24
  handleSyncButtonOnPress,
25
  disabled,
26
  syncSettings = true,
×
27
}) => {
28
  if (!showSubmitted || !syncSettings) {
29✔
29
    return {
13✔
30
      rightComponent: false,
31
    };
32
  }
33
  return {
16✔
34
    rightComponent: (
35
      <Button
36
        type="clear"
37
        disabled={disabled}
38
        onPress={handleSyncButtonOnPress}
39
        testID="button-to-trigger-sync"
40
      >
41
        <Icon name="sync" size={18} />
42
      </Button>
43
    ),
44
  };
45
};
46

47
const FormData = ({ navigation, route }) => {
3✔
48
  const formId = route?.params?.id;
29✔
49
  const showSubmitted = route?.params?.showSubmitted || false;
29✔
50
  const { lang: activeLang, networkType } = UIState.useState((s) => s);
29✔
51
  const trans = i18n.text(activeLang);
29✔
52
  const { id: activeUserId, syncWifiOnly } = UserState.useState((s) => s);
29✔
53
  const [search, setSearch] = useState(null);
29✔
54
  const [data, setData] = useState([]);
29✔
55
  const [showConfirmationSyncDialog, setShowConfirmationSyncDialog] = useState(false);
29✔
56
  const [syncing, setSyncing] = useState(false);
29✔
57

58
  const syncSettings =
59
    (networkType === 'wifi' && syncWifiOnly) || (networkType !== 'wifi' && !syncWifiOnly);
29!
60

61
  const goBack = () => {
29✔
62
    navigation.navigate('ManageForm', { ...route?.params });
×
63
  };
64

65
  const fetchData = async () => {
29✔
66
    const submitted = showSubmitted ? 1 : 0;
12✔
67
    let results = await crudDataPoints.selectDataPointsByFormAndSubmitted({
12✔
68
      form: formId,
69
      submitted,
70
      user: activeUserId,
71
    });
72
    results = results.map((res) => {
12✔
73
      const createdAt = new Date(res.createdAt).toLocaleDateString('en-GB');
13✔
74
      const syncedAt = res.syncedAt ? new Date(res.syncedAt).toLocaleDateString('en-GB') : '-';
13✔
75
      let subtitlesTemp = [
13✔
76
        `${trans.createdLabel}${createdAt}`,
77
        `${trans.surveyDurationLabel}${convertMinutesToHHMM(res.duration)}`,
78
      ];
79
      if (showSubmitted) {
13✔
80
        subtitlesTemp = [...subtitlesTemp, `${trans.syncLabel}${syncedAt}`];
6✔
81
      }
82
      return {
13✔
83
        ...res,
84
        subtitles: subtitlesTemp,
85
      };
86
    });
87
    setData(results);
12✔
88
  };
89

90
  useEffect(() => {
29✔
91
    fetchData();
11✔
92
  }, []);
93

94
  const filteredData = useMemo(() => {
29✔
95
    return data.filter(
25✔
96
      (d) => (search && d?.name?.toLowerCase().includes(search.toLowerCase())) || !search,
13✔
97
    );
98
  }, [data, search]);
99

100
  const handleFormDataListAction = (id) => {
29✔
101
    if (showSubmitted) {
1!
102
      return null;
×
103
    }
104
    return navigation.navigate('FormPage', {
1✔
105
      ...route?.params,
106
      dataPointId: id,
107
      newSubmission: false,
108
    });
109
  };
110

111
  const enableSyncButton = useMemo(() => {
29✔
112
    return data.filter((d) => !d.syncedAt).length > 0;
24✔
113
  }, [data]);
114

115
  const handleSyncButtonOnPress = () => {
29✔
116
    setShowConfirmationSyncDialog(true);
2✔
117
  };
118

119
  const handleOnSync = async () => {
29✔
120
    setShowConfirmationSyncDialog(false);
1✔
121
    setData([]);
1✔
122
    setSyncing(true);
1✔
123
    await backgroundTask.syncFormSubmission();
1✔
124
    await fetchData();
1✔
125
    setSyncing(false);
1✔
126
  };
127

128
  return (
29✔
129
    <BaseLayout
130
      title={route?.params?.name}
131
      search={{
132
        show: true,
133
        placeholder: trans.formDataSearch,
134
        value: search,
135
        action: setSearch,
136
      }}
137
      leftComponent={
138
        <Button type="clear" onPress={goBack} testID="arrow-back-button">
139
          <Icon name="arrow-back" size={18} />
140
        </Button>
141
      }
142
      {...syncButtonElement({
143
        showSubmitted,
144
        handleSyncButtonOnPress,
145
        disabled: !enableSyncButton,
146
        syncSettings,
147
      })}
148
    >
149
      {syncing ? (
29✔
150
        <View style={styles.loadingContainer} testID="sync-loading">
151
          <ActivityIndicator />
152
        </View>
153
      ) : (
154
        <BaseLayout.Content
155
          data={filteredData}
156
          action={handleFormDataListAction}
157
          testID="data-point-list"
158
        />
159
      )}
160

161
      {/* confirmation dialog to sync */}
162
      <Dialog visible={showConfirmationSyncDialog} testID="sync-confirmation-dialog">
163
        <Text testID="sync-confirmation-text">{trans.confirmSync}</Text>
164
        <Dialog.Actions>
165
          <Dialog.Button
166
            title={trans.buttonOk}
167
            onPress={handleOnSync}
168
            testID="sync-confirmation-ok"
169
          />
170
          <Dialog.Button
171
            title={trans.buttonCancel}
172
            onPress={() => setShowConfirmationSyncDialog(false)}
1✔
173
            testID="sync-confirmation-cancel"
174
          />
175
        </Dialog.Actions>
176
      </Dialog>
177
    </BaseLayout>
178
  );
179
};
180

181
const styles = StyleSheet.create({
3✔
182
  loadingContainer: {
183
    flex: 1,
184
    flexDirection: 'column',
185
    justifyContent: 'center',
186
  },
187
});
188

189
export default FormData;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc