Browse Source

sending data offline

master
analuizaff 2 years ago
parent
commit
8d91654a32
  1. 70
      src/App.js
  2. 7
      src/app.json
  3. 30
      src/app/api/Ingestion/sendFormAnswer.js
  4. BIN
      src/app/assets/appLogo.png
  5. 25
      src/app/components/forms/AssembleIngestionObject.js
  6. 2
      src/app/screens/AccountScreen.js
  7. 2
      src/app/screens/MapFeedScreen.js
  8. 2
      src/app/screens/MapFormScreen.js
  9. 2
      src/app/screens/PluviometerRegisterScreen.js
  10. 10
      src/app/screens/PluviometerSharingDataScreen.js
  11. 53
      src/app/screens/RainSharingDataScreen.js
  12. 17
      src/app/screens/RiverFloodSharingDataScreen.js
  13. 16
      src/app/screens/SharingDataScreen.js
  14. 21
      src/app/screens/SharingFloodZonesScreen.js
  15. 39
      src/app/utility/cache.js
  16. 18
      src/eas.json

70
src/App.js

@ -4,7 +4,10 @@ import { NavigationContainer } from "@react-navigation/native";
import navigationTheme from "./app/navigation/navigationTheme";
import "./app/config/globals.js";
import AppLoading from "expo-app-loading";
import FlashMessage from "react-native-flash-message";
import FlashMessage, {
showMessage,
hideMessage,
} from "react-native-flash-message";
import AppNavigator from "./app/navigation/AppNavigator";
import EventLocationProvider from "./app/context/EventLocationContext";
import CurrentLocationProvider from "./app/context/CurrentLocationContext";
@ -17,22 +20,76 @@ import { useFiltering } from "./app/hooks/useFiltering";
import NoInternetConnectionScreen from "./app/screens/NoInternetConnectionScreen";
import NetInfo, { useNetInfo } from "@react-native-community/netinfo";
import getPluviometerStation from "./app/hooks/usePluviometricStation";
import cache from "./app/utility/cache";
import sendFormAnswer from "./app/api/Ingestion/sendFormAnswer";
import { connect } from "formik";
import colors from "./app/config/colors";
import { dimensions } from "./app/config/dimensions";
export default function App() {
const [user, setUser] = useState();
const [pluviometerStation, setPluviometerStation] = useState(undefined);
const [isReady, setIsReady] = useState();
const [isReconnected, setIsReconnected] = useState(true);
const netInfo = useNetInfo();
function notImplemented(color, message, duration, autoHide) {
showMessage({
message: message,
autoHide: autoHide,
duration: duration,
type: "default",
backgroundColor: color, // background color
color: colors.black, // text color
textStyle: {
textAlign: "center",
alignSelf: "center",
fontSize: dimensions.text.default,
},
});
}
useEffect(async () => {
if (netInfo.isInternetReachable) {
const cachedForms = await cache.get("sendforms");
if (!isReconnected) {
notImplemented(
colors.greenWarning,
"Conexão à internet restabelecida",
3000,
true
);
setIsReconnected(true);
}
if (cachedForms) {
const arrayForms = JSON.parse(cachedForms);
arrayForms.forEach(async (element) => {
const isSent = await sendFormAnswer(
element,
netInfo.isInternetReachable,
null
);
if (isSent.ok) {
cache.clear("sendforms");
}
});
}
} else {
notImplemented(colors.blueWarning, "Sem conexão à internet", null, false);
setIsReconnected(false);
}
}, [netInfo.isInternetReachable]);
useEffect(() => {
if (user?.username != null) {
if (pluviometerStation == undefined) {
getPluviometerStation(user.id, setPluviometerStation);
}
authStorage.setUser(user);
}
else{
} else {
setPluviometerStation(undefined);
}
}, [user]);
@ -43,7 +100,6 @@ export default function App() {
}
}, [pluviometerStation]);
const restoreUser = async () => {
const storageUser = await authStorage.getUser();
if (storageUser) setUser(storageUser);
@ -59,9 +115,11 @@ export default function App() {
onError={(e) => console.log(e)}
/>
);
} else {
} else {
if (global.formsSockets === undefined)
global.formsSockets = useFiltering(global.location || global.defaultLocation);
global.formsSockets = useFiltering(
global.location || global.defaultLocation
);
return (
<AuthContext.Provider

7
src/app.json

@ -2,7 +2,7 @@
"expo": {
"name": "Dados à Prova d'Água",
"slug": "dados-a-prova-dagua",
"version": "1.0.2",
"version": "1.0.3",
"orientation": "portrait",
"icon": "./app/assets/icons/app-icon.png",
"splash": {
@ -25,10 +25,11 @@
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./app/assets/adaptive-icon.png",
"foregroundImage": "./app/assets/appLogo.png",
"backgroundColor": "#FFFFFF"
},
"package": "com.dadosaprovadagua.wpdmobileapp"
"package": "com.dadosaprovadagua.wpdmobileapp",
"versionCode": 3
},
"web": {
"favicon": "./app/assets/favicon.png"

30
src/app/api/Ingestion/sendFormAnswer.js

@ -1,15 +1,25 @@
import appIngestion from "./appIngestion";
import cache from "../../utility/cache";
const endpoint = "/api/wpdAppIngestion?";
async function sendFormAnswer(ingestionObject) {
// console.log(JSON.stringify(ingestionObject));
const response = await appIngestion.post(
endpoint,
JSON.stringify(ingestionObject)
);
return response;
}
async function sendFormAnswer(ingestionObject, connection, formName) {
if (connection) {
const response = await appIngestion.post(
endpoint,
JSON.stringify(ingestionObject)
);
return response;
} else {
const formArray = [];
const teste = await cache.get("sendforms");
if (teste) {
var object = JSON.parse(teste);
object.forEach((element) => formArray.push(element));
}
formArray.push(ingestionObject);
cache.store("sendforms", formArray);
return { ok: true };
}
}
export default sendFormAnswer;

BIN
src/app/assets/appLogo.png

After

Width: 400  |  Height: 400  |  Size: 72 KiB

25
src/app/components/forms/AssembleIngestionObject.js

@ -9,9 +9,15 @@ async function AssembleIngestionObject(
location,
date,
time,
address
address,
connection,
formName
) {
console.log(`----> Sending data: ${code} = ${situation} => ${moment().format('DD/MM, h:mm:ss:SSS')}`)
console.log(
`----> Sending data: ${code} = ${situation} => ${moment().format(
"DD/MM, h:mm:ss:SSS"
)}`
);
const ingestionObject = {
responseData: {
array_to_json: [
@ -34,7 +40,7 @@ async function AssembleIngestionObject(
},
};
return sendFormAnswer(ingestionObject);
return sendFormAnswer(ingestionObject, connection, formName);
}
const AssembleIngestionPluviometer = async ({
pluviometer,
@ -43,9 +49,14 @@ const AssembleIngestionPluviometer = async ({
user,
date,
time,
connection,
formName,
}) => {
console.log(`----> Sending data: PLUVIOMETER_FORM = ${pluviometer} => ${moment().format('DD/MM, h:mm:ss:SSS')}`)
console.log(
`----> Sending data: PLUVIOMETER_FORM = ${pluviometer} => ${moment().format(
"DD/MM, h:mm:ss:SSS"
)}`
);
const pluviometerObject = {
responseData: {
array_to_json: [
@ -68,8 +79,8 @@ const AssembleIngestionPluviometer = async ({
],
},
};
const a = await sendFormAnswer(pluviometerObject);
const a = await sendFormAnswer(pluviometerObject, connection, formName);
return a;
};

2
src/app/screens/AccountScreen.js

@ -191,7 +191,7 @@ function AccountScreen(props) {
return (
<View style={{flex:1, width: "100%"}}>
<ConnectionWarning />
{/* <ConnectionWarning /> */}
<Screen>
<ScrollView>
<View

2
src/app/screens/MapFeedScreen.js

@ -36,7 +36,7 @@ export default function MapFeedScreen(props) {
return (
<View style={{flex:1, width: "100%"}}>
<ConnectionWarning />
{/* <ConnectionWarning /> */}
{ (global.location) ? (
<View style={styles.container}>
<OpenStreetMap

2
src/app/screens/MapFormScreen.js

@ -27,7 +27,7 @@ const MapFormScreen = (props) => {
return street + number + district;
} else {
//Quando o usuário não da permissão de acesso da localização o geoCode retorna um array vazio
return "Erro ao carregar endereço";
return "Não foi possível carregar endereço";
}
};

2
src/app/screens/PluviometerRegisterScreen.js

@ -73,7 +73,7 @@ function LocationPicker({
<Text style={styles.subText}>
{pluviometer.address
? pluviometer.address
: "Erro ao carregar endereço"}
: "Não foi possível carregar endereço"}
</Text>
</View>
)}

10
src/app/screens/PluviometerSharingDataScreen.js

@ -15,6 +15,7 @@ import { formcode } from "../components/forms/FormsCode";
import { AssembleIngestionPluviometer } from "../components/forms/AssembleIngestionObject";
import OnSubmitAwaitModal from "../components/forms/OnSubmitAwaitModal";
import OnSubmitMessageModal from "../components/forms/OnSubmitMessageModal";
import { useNetInfo } from "@react-native-community/netinfo";
const dims = scaleDimsFromWidth(85, 85, 25);
@ -45,6 +46,9 @@ function PluviometerSharingDataScreen(props) {
const [showMessageModal, setShowMessageModal] = useState(false);
const [apiMessage, setApiMessage] = useState(null);
const connection = useNetInfo().isInternetReachable;
const formName = "pluviometer";
const sendForm = async ({
pluviometer,
description,
@ -52,6 +56,8 @@ function PluviometerSharingDataScreen(props) {
user,
date,
time,
connection,
formName,
}) => {
const isSent = await AssembleIngestionPluviometer({
pluviometer,
@ -60,6 +66,8 @@ function PluviometerSharingDataScreen(props) {
user,
date,
time,
connection,
formName,
});
if (isSent) {
setApiMessage(isSent.ok);
@ -86,7 +94,7 @@ function PluviometerSharingDataScreen(props) {
}}
onSubmit={(values) => {
setShowAwaitModal(true);
sendForm({ ...values, user, date, time }).then((isSent) => {
sendForm({ ...values, user, date, time, connection, formName }).then((isSent) => {
setShowAwaitModal(false);
setShowMessageModal(true);
});

53
src/app/screens/RainSharingDataScreen.js

@ -10,7 +10,11 @@ import colors from "../config/colors";
import { TouchableNativeFeedback } from "react-native-gesture-handler";
import { insertRainData } from "../database/databaseLoader";
import { showMessage } from "react-native-flash-message";
import { scaleDimsFromWidth, dimensions, screen_height } from "../config/dimensions";
import {
scaleDimsFromWidth,
dimensions,
screen_height,
} from "../config/dimensions";
import assets from "../config/assets";
import moment from "moment";
import { EventLocationContext } from "../context/EventLocationContext";
@ -21,6 +25,8 @@ import { formcode } from "../components/forms/FormsCode";
import OnSubmitAwaitModal from "../components/forms/OnSubmitAwaitModal";
import OnSubmitMessageModal from "../components/forms/OnSubmitMessageModal";
import { useNetInfo } from "@react-native-community/netinfo";
const validationSchema = Yup.object().shape({
images: Yup.array(),
description: Yup.string().label("Description"),
@ -49,7 +55,12 @@ function RainSharingDataScreen(props) {
const [showAwaitModal, setShowAwaitModal] = useState(false);
const [showMessageModal, setShowMessageModal] = useState(false);
const [apiMessage, setApiMessage] = useState(null);
const connection = useNetInfo().isInternetReachable;
const formName = "rain";
console.log(connection);
const sendForm = async (
{ images, description },
user,
@ -58,17 +69,21 @@ function RainSharingDataScreen(props) {
location,
date,
time,
address
address,
connection,
formName
) => {
const isSent = await AssembleIngestionObject(
{ images, description },
{ images, description, connection, formName },
user,
situation,
code,
location,
date,
time,
address
address,
connection,
formName
);
setApiMessage(isSent.ok);
@ -77,16 +92,14 @@ function RainSharingDataScreen(props) {
return (
<Screen style={styles.container}>
<OnSubmitAwaitModal
show={showAwaitModal}
/>
<OnSubmitMessageModal
show={showMessageModal}
setShow={setShowMessageModal}
sucess={apiMessage}
navigation={props.navigation}
/>
<ScrollView>
<OnSubmitAwaitModal show={showAwaitModal} />
<OnSubmitMessageModal
show={showMessageModal}
setShow={setShowMessageModal}
sucess={apiMessage}
navigation={props.navigation}
/>
<ScrollView>
<Form
initialValues={{
images: [],
@ -96,7 +109,7 @@ function RainSharingDataScreen(props) {
setError(true);
return;
}
setShowAwaitModal(true);
sendForm(
{
@ -108,11 +121,13 @@ function RainSharingDataScreen(props) {
location,
date,
time,
address
address,
connection,
formName
).then((isSent) => {
setShowAwaitModal(false);
setShowMessageModal(true)});
setShowAwaitModal(false);
setShowMessageModal(true);
});
}}
validationSchema={validationSchema}
>

17
src/app/screens/RiverFloodSharingDataScreen.js

@ -20,6 +20,7 @@ import { formcode } from "../components/forms/FormsCode";
import { AssembleIngestionObject } from "../components/forms/AssembleIngestionObject";
import OnSubmitMessageModal from "../components/forms/OnSubmitMessageModal";
import OnSubmitAwaitModal from "../components/forms/OnSubmitAwaitModal";
import { useNetInfo } from "@react-native-community/netinfo";
const validationSchema = Yup.object().shape({
images: Yup.array(),
@ -35,6 +36,9 @@ function RiverFloodSharingDataScreen(props) {
const context = useContext(EventLocationContext);
const connection = useNetInfo().isInternetReachable;
const formName = "riverFlood";
useEffect(() => {
context.defaultLocation();
}, []);
@ -58,7 +62,9 @@ function RiverFloodSharingDataScreen(props) {
location,
date,
time,
address
address,
connection,
formName
) => {
const isSent = await AssembleIngestionObject(
{ images, description },
@ -68,7 +74,9 @@ function RiverFloodSharingDataScreen(props) {
location,
date,
time,
address
address,
connection,
formName
);
setApiMessage(isSent.ok);
@ -109,7 +117,9 @@ function RiverFloodSharingDataScreen(props) {
location,
date,
time,
address
address,
connection,
formName
).then((isSent) => {
setShowAwaitModal(false);
setShowMessageModal(true);
@ -128,7 +138,6 @@ function RiverFloodSharingDataScreen(props) {
flexDirection="row"
justifyContent="center"
paddingBottom={16}
>
<View style={styles.imgs_row}>
<SvgLabeledButton

16
src/app/screens/SharingDataScreen.js

@ -7,14 +7,11 @@ import { dimensions } from "../config/dimensions";
import SvgLabeledButton from "../components/SvgLabeledButton";
import { AuthContext } from "../auth/context";
import { useNetInfo } from "@react-native-community/netinfo";
import ConnectionWarning from "../components/ConnectionWarning";
function SharingDataScreen({ navigation }) {
const authContext = useContext(AuthContext);
const [showLog, setShowLog] = useState(false);
const [showLogPluv, setShowLogPluv] = useState(false);
const [showConnectionWarning, setShowConnectionWarning] = useState(false);
const connection = useNetInfo().isConnected;
const isRegistered = authContext.user?.username != null;
const pluviometer = authContext.user?.pluviometer ? true : false;
@ -30,9 +27,8 @@ function SharingDataScreen({ navigation }) {
};
return (
<View style={{flex:1, width: "100%"}}>
<ConnectionWarning />
<View style={{ flex: 1, width: "100%" }}>
{/* <ConnectionWarning /> */}
<View style={styles.container}>
<ConfirmationModal
show={showLogPluv}
@ -68,7 +64,7 @@ function SharingDataScreen({ navigation }) {
onPress={() =>
navigation.navigate("FloodSharingData", { user: currentUser })
}
active={isRegistered && connection}
active={isRegistered}
inactiveOnPress={() => setShowLog(true)}
/>
@ -78,7 +74,7 @@ function SharingDataScreen({ navigation }) {
navigation.navigate("RainSharingData", { user: currentUser })
}
SvgImage={assets.rainLevel.RainIcon}
active={isRegistered && connection}
active={isRegistered}
inactiveOnPress={() => setShowLog(true)}
/>
</View>
@ -100,7 +96,7 @@ function SharingDataScreen({ navigation }) {
})
}
SvgImage={assets.PluviometricDataIcon}
active={isRegistered && pluviometer && connection}
active={isRegistered && pluviometer}
inactiveOnPress={() => {
setShowLog(!isRegistered),
setShowLogPluv(!pluviometer && isRegistered);
@ -113,7 +109,7 @@ function SharingDataScreen({ navigation }) {
navigation.navigate("RiverFloodData", { user: currentUser })
}
SvgImage={assets.riverLevel.RiverIcon}
active={isRegistered && connection}
active={isRegistered}
inactiveOnPress={() => setShowLog(true)}
/>
</View>

21
src/app/screens/SharingFloodZonesScreen.js

@ -19,6 +19,7 @@ import { formcode } from "../components/forms/FormsCode";
import { AssembleIngestionObject } from "../components/forms/AssembleIngestionObject";
import OnSubmitAwaitModal from "../components/forms/OnSubmitAwaitModal";
import OnSubmitMessageModal from "../components/forms/OnSubmitMessageModal";
import { useNetInfo } from "@react-native-community/netinfo";
const validationSchema = Yup.object().shape({
images: Yup.array(),
@ -39,6 +40,9 @@ function SharingFloodZonesScreen(props) {
const context = useContext(EventLocationContext);
const address = context.eventLocation;
const connection = useNetInfo().isInternetReachable;
const formName = "floodZones";
useEffect(() => {
context.defaultLocation();
}, []);
@ -56,7 +60,9 @@ function SharingFloodZonesScreen(props) {
location,
date,
time,
address
address,
connection,
formName
) => {
const isSent = await AssembleIngestionObject(
{ images, description },
@ -66,17 +72,18 @@ function SharingFloodZonesScreen(props) {
location,
date,
time,
address
address,
connection,
formName
);
setApiMessage(isSent.ok);
return apiMessage;
};
return (
<Screen style={styles.container}>
<OnSubmitAwaitModal show={showAwaitModal} />
<OnSubmitAwaitModal show={showAwaitModal} />
<OnSubmitMessageModal
show={showMessageModal}
setShow={setShowMessageModal}
@ -108,11 +115,13 @@ function SharingFloodZonesScreen(props) {
location,
date,
time,
address
address,
connection,
formName
).then((isSent) => {
setShowAwaitModal(false);
setShowMessageModal(true);
});
});
}}
validationSchema={validationSchema}
>

39
src/app/utility/cache.js

@ -10,9 +10,11 @@ const store = async (key, value) => {
value,
timestamp: Date.now(),
};
await AsyncStorage.setItem(prefix + key, JSON.stringify(value));
} catch (error) {}
// return true;
} catch (error) {
// return false;
}
};
const isExpired = (item) => {
@ -20,6 +22,15 @@ const isExpired = (item) => {
const storedTime = moment(item.timestamp);
return now.diff(storedTime, "minutes") > expiryInMinutes;
};
const clear = async (key) => {
try {
await AsyncStorage.removeItem(prefix + key);
return true;
} catch (error) {
console.log(error);
return false;
}
};
const get = async (key) => {
try {
@ -34,10 +45,34 @@ const get = async (key) => {
return value;
} catch (error) {
console.log(error);
return null;
}
};
const merge = async (key) => {
try {
await AsyncStorage.mergeItem(prefix + key, JSON.stringify(value));
} catch (error) {}
};
const getAllKeys = async () => {
let keys = [];
try {
keys = await AsyncStorage.getAllKeys();
return keys;
} catch (e) {
console.log(e);
}
// console.log(keys)
// example console.log result:
// ['@MyApp_user', '@MyApp_key']
};
export default {
store,
get,
merge,
clear,
getAllKeys,
};

18
src/eas.json

@ -0,0 +1,18 @@
{
"cli": {
"version": ">= 0.40.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}
Loading…
Cancel
Save