diff --git a/src/App.js b/src/App.js index 2a81ae2..f3b8b7a 100644 --- a/src/App.js +++ b/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 ( formArray.push(element)); + } + formArray.push(ingestionObject); + cache.store("sendforms", formArray); + return { ok: true }; + } +} export default sendFormAnswer; diff --git a/src/app/assets/appLogo.png b/src/app/assets/appLogo.png new file mode 100644 index 0000000..4bb1444 Binary files /dev/null and b/src/app/assets/appLogo.png differ diff --git a/src/app/components/forms/AssembleIngestionObject.js b/src/app/components/forms/AssembleIngestionObject.js index 1fa26b4..107a8ba 100644 --- a/src/app/components/forms/AssembleIngestionObject.js +++ b/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; }; diff --git a/src/app/screens/AccountScreen.js b/src/app/screens/AccountScreen.js index b2e190b..20a7416 100644 --- a/src/app/screens/AccountScreen.js +++ b/src/app/screens/AccountScreen.js @@ -191,7 +191,7 @@ function AccountScreen(props) { return ( - + {/* */} - + {/* */} { (global.location) ? ( { 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"; } }; diff --git a/src/app/screens/PluviometerRegisterScreen.js b/src/app/screens/PluviometerRegisterScreen.js index b675665..ff99255 100644 --- a/src/app/screens/PluviometerRegisterScreen.js +++ b/src/app/screens/PluviometerRegisterScreen.js @@ -73,7 +73,7 @@ function LocationPicker({ {pluviometer.address ? pluviometer.address - : "Erro ao carregar endereço"} + : "Não foi possível carregar endereço"} )} diff --git a/src/app/screens/PluviometerSharingDataScreen.js b/src/app/screens/PluviometerSharingDataScreen.js index 8a80543..99eed19 100644 --- a/src/app/screens/PluviometerSharingDataScreen.js +++ b/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); }); diff --git a/src/app/screens/RainSharingDataScreen.js b/src/app/screens/RainSharingDataScreen.js index 69dae1d..31acbd8 100644 --- a/src/app/screens/RainSharingDataScreen.js +++ b/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 ( - - - + + +
{ - setShowAwaitModal(false); - setShowMessageModal(true)}); - + setShowAwaitModal(false); + setShowMessageModal(true); + }); }} validationSchema={validationSchema} > diff --git a/src/app/screens/RiverFloodSharingDataScreen.js b/src/app/screens/RiverFloodSharingDataScreen.js index 1091763..31a6ead 100644 --- a/src/app/screens/RiverFloodSharingDataScreen.js +++ b/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} - > - - + + {/* */} 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)} /> @@ -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)} /> diff --git a/src/app/screens/SharingFloodZonesScreen.js b/src/app/screens/SharingFloodZonesScreen.js index e6b063a..8e2afb0 100644 --- a/src/app/screens/SharingFloodZonesScreen.js +++ b/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 ( - + { setShowAwaitModal(false); setShowMessageModal(true); - }); + }); }} validationSchema={validationSchema} > diff --git a/src/app/utility/cache.js b/src/app/utility/cache.js index 61a1a2d..952728c 100644 --- a/src/app/utility/cache.js +++ b/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, }; diff --git a/src/eas.json b/src/eas.json new file mode 100644 index 0000000..6355467 --- /dev/null +++ b/src/eas.json @@ -0,0 +1,18 @@ +{ + "cli": { + "version": ">= 0.40.0" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal" + }, + "production": {} + }, + "submit": { + "production": {} + } +}