@react-navigation/native#useFocusEffect JavaScript Examples

The following examples show how to use @react-navigation/native#useFocusEffect. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: history.js    From turkce-sozluk with MIT License 6 votes vote down vote up
function HistoryView() {
  useFocusEffect(
    React.useCallback(() => {
      StatusBar.setBarStyle('dark-content')
    }, [])
  )

  return (
    <Box as={SafeAreaView} flex={1}>
      <Text>Arama Geçmişi</Text>
    </Box>
  )
}
Example #2
Source File: Search.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var { t } = useTranslation();
  var theme = useSelector(i => i.themes[i.theme])
  var input = React.useRef();
  var [value, setValue] = React.useState('');
  var [search, setSearch] = React.useState('');
  var [timeoutC, setTimeoutC] = React.useState(null);
  function onValue(val) {
    if (timeoutC) clearTimeout(timeoutC)
    setValue(val);
    setTimeoutC(setTimeout(() => {
      return setSearch(val);
    }, 500))
  }
  var dispatch = useDispatch();

  var reqData = {
    endpoint: 'user/find',
    data: { text: search },
    cuppazee: true
  }
  var users = useSelector(i => i.request_data[stringify(reqData)] ?? {})
  useFocusEffect(
    React.useCallback(() => {
      if (search.length >= 1) dispatch(request.add(reqData))
      return () => {
        if (search.length >= 1) dispatch(request.remove(reqData))
      };
    }, [search])
  );
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{ padding: 4, width: "100%" }}>
        <Card noPad cardStyle={{ flexDirection: "row", backgroundColor: "#fff", alignItems: "stretch" }}>
          <TextInput
            onSubmitEditing={() => setSearch(value)}
            ref={input}
            style={{ paddingHorizontal: 8, flex: 1, borderRadius: 8, borderBottomLeftRadius: 8, height: 40 }}
            onChangeText={onValue}
            value={value}
            returnKeyType="search"
          />
        </Card>
      </View>
      <View style={{ padding: 4 }}>
        <Card noPad>
          <View>
            {search.length < 3 && <Text allowFontScaling={false} style={{ textAlign: "center", ...font("bold"), fontSize: 16, color: theme.page_content.fg, marginVertical: 4 }}>Type in your Username</Text>}
            {search.length >= 3 && !users?.data?.users && <View style={{ height: 100, justifyContent: "center", alignItems: "center" }}>
              <ActivityIndicator size={32} color={theme.page_content.fg} />
            </View>}
            {users?.data?.users?.length === 0 && <Text allowFontScaling={false} style={{ textAlign: "center", ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{t('search:empty')}</Text>}
            {users?.data?.users?.slice?.(0, 20)?.map?.(i => <TouchableRipple onPress={() => navigation.navigate('CompetitionAuth', { username: i.username })}>
              <View key={i.clan_id} style={{ padding: 4, flexDirection: "row", alignItems: "center" }}>
                <Image style={{ height: 24, width: 24, marginRight: 8, marginLeft: 4, borderRadius: 12 }} source={{ uri: i.avatar ?? `https://munzee.global.ssl.fastly.net/images/avatars/ua${Number(i.user_id).toString(36)}.png` }} />
                <View style={{ flex: 1 }}>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 16, color: theme.page_content.fg }}>{i.username}</Text>
                  <Text allowFontScaling={false} style={{ ...font("bold"), fontSize: 12, color: theme.page_content.fg }}>#{i.user_id}</Text>
                </View>
                <MaterialCommunityIcons size={24} name="chevron-right" color={theme.page_content.fg} />
              </View>
            </TouchableRipple>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #3
Source File: detail.js    From turkce-sozluk with MIT License 5 votes vote down vote up
function DetailView({ route }) {
  const keyword = route.params?.keyword
  // const keyword = 'milliyet'

  const [data, setData] = React.useState(null)

  useFocusEffect(
    React.useCallback(() => {
      StatusBar.setBarStyle('dark-content')
    }, [])
  )

  const getDetailData = async () => {
    const response = await fetch(`https://sozluk.gov.tr/gts?ara=${keyword}`)
    const data = await response.json()
    setData(data[0])
  }

  React.useEffect(() => {
    getDetailData()
  }, [])

  return (
    <Box as={SafeAreaView} bg="softRed" flex={1}>
      <Box as={ScrollView} p={16}>
        <Box>
          <Text fontSize={32} fontWeight="bold">
            {keyword}
          </Text>
          {data?.telaffuz || data?.lisan ? (
            <Text color="textLight" mt={6}>
              {data?.telaffuz && data?.telaffuz} {data?.lisan}
            </Text>
          ) : null}
        </Box>
        <Box flexDirection="row" mt={24}>
          <ActionButton disabled={!data}>
            <Sound width={24} height={24} color={theme.colors.textLight} />
          </ActionButton>
          <ActionButton disabled={!data} ml={12}>
            <Favorite width={24} height={24} color={theme.colors.textLight} />
          </ActionButton>
          <ActionButton disabled={!data} ml="auto">
            <Hand width={24} height={24} color={theme.colors.textLight} />
            <ActionButtonTitle>Türk İşaret Dili</ActionButtonTitle>
          </ActionButton>
        </Box>
        <Box mt={32}>
          {data
            ? data.anlamlarListe.map(item => (
                <DetailSummaryItem
                  key={item.anlam_sira}
                  data={item}
                  border={item.anlam_sira !== '1'}
                />
              ))
            : [1, 2, 3].map(index => (
                <DetailSummaryItem key={index} border={index !== 1}>
                  <LoaderText />
                  <LoaderText width={200} mt={10} />
                </DetailSummaryItem>
              ))}
        </Box>
      </Box>
    </Box>
  )
}
Example #4
Source File: search.js    From turkce-sozluk with MIT License 5 votes vote down vote up
function SearchView({ navigation }) {
  const [isSearchFocus, setSearchFocus] = React.useState(false)
  const [homeData, setHomeData] = React.useState(null)

  const getHomeData = async () => {
    const response = await fetch('https://sozluk.gov.tr/icerik')
    const data = await response.json()
    setHomeData(data)
  }

  React.useEffect(() => {
    getHomeData()
  }, [])

  useFocusEffect(
    React.useCallback(() => {
      StatusBar.setBarStyle(isSearchFocus ? 'dark-content' : 'light-content')
    }, [isSearchFocus])
  )

  return (
    <Box as={SafeAreaView} bg="softRed" flex={1}>
      {/* Header */}
      <HomeSearch
        isSearchFocus={isSearchFocus}
        onSearchFocus={setSearchFocus}
      />

      {/* content */}
      <Box flex={1} bg="softRed" pt={isSearchFocus ? 0 : 26}>
        {isSearchFocus ? (
          <Box flex={1}>
            <SearchHistoryList data={DATA} />
          </Box>
        ) : (
          <Box px={16} py={40} flex={1}>
            <SuggestionCard
              data={homeData?.kelime[0]}
              title="Bir Kelime"
              onPress={() =>
                navigation.navigate('Detail', {
                  keyword: homeData?.kelime[0].madde
                })
              }
            />
            <SuggestionCard
              mt={40}
              data={homeData?.atasoz[0]}
              title="Bir Deyim - Atasözü"
              onPress={() =>
                navigation.navigate('Detail', {
                  keyword: homeData?.atasoz[0].madde
                })
              }
            />
          </Box>
        )}
      </Box>
    </Box>
  )
}
Example #5
Source File: useAPIRequest.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function useAPIRequest (reqData, includeStatus, waitForAll) {
  // Convert to Array if not already
  const isArray = Array.isArray(reqData);
  if(!isArray) reqData = [reqData];

  // Stringify RequestData
  const stringifiedData = reqData.map(i=>i?stringify({...i,extraData:undefined}):i);

  // Add Requests
  const dispatch = useDispatch();
  useFocusEffect(
    useCallback(() => {
      for(let req of reqData.filter(i=>i)) dispatch(request.add({...req,extraData:undefined}));
      return () => {
        for(let req of reqData.filter(i=>i)) dispatch(request.remove({...req,extraData:undefined}));
      };
    },[stringify(reqData)])
  )
  
  // Get Request Responses
  const raw_data = useSelector(i => stringifiedData.map(req=>req?i.request_data[req]:undefined));
  const [data,setData] = useState([]);

  useEffect(()=>{
    var d = [];
    var i = 0;
    for(let dat of raw_data) {
      if(waitForAll && raw_data.some(i=>!i)) {
        d.push(null);
      } else if(dat&&data[i]&&dat.id===data[i].id) {
        d.push(data[i]);
      } else if(dat&&dat.data&&reqData[i].function) {
        d.push({
          data: reqData[i].function(dat.data)
        })
      } else {
        d.push(dat);
      }
      i++;
    }
    setData(d);
  },[stringify([...raw_data.map(i=>i?.id),...reqData.map(i=>stringify(i?.extraData))])])

  if(includeStatus) {
    // If Input is not array, return first element of Array
    if(!isArray) return data[0] ? {
      data: data[0]?.data,
      status: data[0]?.status
    } : {
      data: undefined,
      status: "loading"
    };
  
    // Return Array
    return data.map(i=>i?({
      data: i?.data,
      status: i?.status
    }):({
      data: undefined,
      status: "loading"
    }));
  }

  // If Input is not array, return first element of Array
  if(!isArray) return data[0]?.data;

  // Return Array
  return data.map(i=>i?.data);
}
Example #6
Source File: Search.js    From Legacy with Mozilla Public License 2.0 5 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var {t} = useTranslation();
  var theme = useSelector(i=>i.themes[i.theme])
  var input = React.useRef();
  var [value,setValue] = React.useState('');
  var [search,setSearch] = React.useState('');
  var [timeoutC,setTimeoutC] = React.useState(null);
  function onValue(val) {
    if(timeoutC) clearTimeout(timeoutC)
    setValue(val);
    setTimeoutC(setTimeout(() => {
      return setSearch(val);
    }, 500))
  }
  var dispatch = useDispatch();
  var userBookmarks = useSelector(i => i.userBookmarks);
  function addUser(user) {
    dispatch(userBookmarksR(userBookmarks.concat([user])));
  }
  function removeUser(user) {
    dispatch(userBookmarksR(userBookmarks.filter(i=>i.user_id!=user.user_id)));
  }
  
  var reqData = {
    endpoint: 'user/find',
    data: {text:search}
  }
  var users = useSelector(i => i.request_data[stringify(reqData)] ?? {})
  useFocusEffect(
    React.useCallback(() => {
      if(search.length>=3) dispatch(request.add(reqData))
      return () => {
        if(search.length>=3) dispatch(request.remove(reqData))
      };
    }, [search])
  );
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{padding:4,width:"100%"}}>
        <Card noPad cardStyle={{flexDirection: "row", backgroundColor: "#fff", alignItems:"stretch"}}>
          <TextInput
            onSubmitEditing={()=>setSearch(value)}
            ref={input}
            style={{ paddingHorizontal: 8, flex: 1, borderRadius: 8, borderBottomLeftRadius: 8, height: 40 }}
            onChangeText={onValue}
            value={value}
            returnKeyType="search"
          />
          {/* <IconButton onPress={()=>setSearch(value)} style={{backgroundColor: theme.navigation.bg}} icon="magnify" color={theme.navigation.fg} /> */}
        </Card>
      </View>
      <View style={{padding:4}}>
        <Card noPad>
          <View>
            {search.length<3&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:user')}</Text>}
            {search.length>=3&&!users?.data?.users&&<View style={{height:100,justifyContent:"center",alignItems:"center"}}>
              <ActivityIndicator size={32} color={theme.page_content.fg} />
            </View>}
            {users?.data?.users?.length===0&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:empty')}</Text>}
            {users?.data?.users?.slice?.(0,20)?.map?.(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              {!userBookmarks.find(x=>x.user_id==i.user_id)&&<IconButton size={24} onPress={()=>addUser(i)} icon="bookmark-plus" color="#016930" />}
              {!!userBookmarks.find(x=>x.user_id==i.user_id)&&<IconButton size={24} onPress={()=>removeUser(i)} icon="bookmark-minus" color="#ff2222" />}
              <Image style={{height:24,width:24,marginRight:8,marginLeft:-8,borderRadius:12}} source={{uri:i.avatar??`https://munzee.global.ssl.fastly.net/images/avatars/ua${Number(i.user_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.username}</Text>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:12,color:theme.page_content.fg}}>#{i.user_id}</Text>
              </View>
              <IconButton size={24} onPress={()=>navigation.navigate('UserDetails',{ username: i.username })} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #7
Source File: Search.js    From Legacy with Mozilla Public License 2.0 4 votes vote down vote up
export default function SearchScreen({ navigation }) {
  var {t} = useTranslation();
  var theme = useSelector(i=>i.themes[i.theme])
  var input = React.useRef();
  var [value,setValue] = React.useState('');
  var [search,setSearch] = React.useState('');
  var [selectedClanGroup,setSelectedClanGroup] = React.useState(null);
  var [timeoutC,setTimeoutC] = React.useState(null);
  function onValue(val) {
    if(timeoutC) clearTimeout(timeoutC)
    setValue(val);
    setTimeoutC(setTimeout(() => {
      return setSearch(val);
    }, 500))
  }
  var dispatch = useDispatch();
  var clanBookmarks = useSelector(i => i.clanBookmarks);
  function addClan(clan) {
    dispatch(clanBookmarksR(clanBookmarks.concat([clan])));
  }
  function removeClan(clan) {
    dispatch(clanBookmarksR(clanBookmarks.filter(i=>i.clan_id!=clan.clan_id)));
  }
  var clansInGroup = [];
  if(groups.find(i=>i.title==selectedClanGroup)) {
    clansInGroup = groups.find(i=>i.title==selectedClanGroup).clans;
  }
  
  var reqData = {
    endpoint: `clan/list/v1`,
    data: {
      query: search,
      format: "list"
    },
    cuppazee: true
  }
  var clans = useSelector(i => i.request_data[stringify(reqData)] ?? {})
  useFocusEffect(
    React.useCallback(() => {
      if(search.length>=3) dispatch(request.add(reqData))
      return () => {
        if(search.length>=3) dispatch(request.remove(reqData))
      };
    }, [search])
  );
  return (
    <ScrollView
      contentContainerStyle={{ width: 600, maxWidth: "100%", alignItems: "stretch", flexDirection: "column", alignSelf: "center", padding: 4 }}
      style={{ flex: 1, backgroundColor: theme.page.bg }}>
      <View style={{padding:4,width:"100%"}}>
        <Card noPad cardStyle={{flexDirection: "row", backgroundColor: "#fff", alignItems:"stretch"}}>
          <TextInput
            onSubmitEditing={()=>setSearch(value)}
            ref={input}
            style={{ paddingHorizontal: 8, flex: 1, borderRadius: 8, borderBottomLeftRadius: 8, height: 40 }}
            onChangeText={onValue}
            value={value}
            returnKeyType="search"
          />
        </Card>
      </View>
      <View style={{padding:4}}>
        <Card noPad>
          <View>
            {!search&&<Text allowFontScaling={false} style={{textAlign:"center",...font("bold"),fontSize:16,color:theme.page_content.fg}}>{t('search:clan')}</Text>}
            {!!search&&!clans?.data&&<View style={{height:100,justifyContent:"center",alignItems:"center"}}>
              <ActivityIndicator size={32} color={theme.page_content.fg} />
            </View>}
            {(search?clans?.data?.slice?.(0,20):clansInGroup)?.map?.(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              {!clanBookmarks.find(x=>x.clan_id==i.clan_id)&&<IconButton size={24} onPress={()=>addClan(i)} icon="bookmark-plus" color="#016930" />}
              {!!clanBookmarks.find(x=>x.clan_id==i.clan_id)&&<IconButton size={24} onPress={()=>removeClan(i)} icon="bookmark-minus" color="#ff2222" />}
              <Image style={{height:24,width:24,marginRight:8,marginLeft:-8,borderRadius:12}} source={{uri:i.logo??`https://munzee.global.ssl.fastly.net/images/clan_logos/${Number(i.clan_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.name}</Text>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:12,color:theme.page_content.fg}}>{i.tagline}</Text>
              </View>
              <IconButton size={24} onPress={()=>navigation.navigate('Clan',{clanid:i.clan_id})} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
            {!search&&groups.map(i=><View key={i.clan_id} style={{padding: 4, flexDirection: "row", alignItems: "center"}}>
              <Image style={{height:32,width:32,marginHorizontal:8,borderRadius:8}} source={{uri:i.icon??`https://munzee.global.ssl.fastly.net/images/clan_logos/${Number(i.clan_id).toString(36)}.png`}} />
              <View style={{flex:1}}>
                <Text allowFontScaling={false} style={{...font("bold"),fontSize:16,color:theme.page_content.fg}}>{i.title}</Text>
              </View>
              <IconButton size={24} onPress={()=>setSelectedClanGroup(i.title)} icon="chevron-right" color={theme.page_content.fg} />
            </View>)}
          </View>
        </Card>
      </View>
    </ScrollView>
  );
}
Example #8
Source File: ChatListView.js    From WhatsApp-Clone with MIT License 4 votes vote down vote up
ChatListView = ({navigation}) => {
  var [state, dispatch] = useReducer(chatListReducer, initialChatListState);

  var {chatList, chatItem, refresh, userId} = state;

  useFocusEffect(
    React.useCallback(() => {
      getLatestChats();
    }, []),
  );

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

  useEffect(() => {
    if (refresh) {
      getLatestChats();
    }
  }, [refresh]);

  useEffect(() => {
    // console.log('Chat List Changed == ', JSON.stringify(chatList));
    if (chatItem != '') {
      renderChats();
    }
  }, [chatItem]);

  async function getUserId() {
    const userId = await getLocalData(constants.USER_ID);
    dispatch({type: constants.USER_ID, payload: userId});
    return userId;
  }

  const getLatestChats = async () => {
    await getUserId();
    getChatList()
      .then(res => {
        // console.log('RESPONSE => ' + JSON.stringify(res.data.data));
        if (res.status === 200) {
          dispatch({type: CHAT_LIST, payload: res.data.data});
        }
        dispatch({type: REFRESH, payload: false});
      })
      .catch(error => {
        console.log('ERROR ', error);
      });
  };

  async function renderChats() {
    let chatArray = chatList;
    console.log("Message CHAT Received => ", JSON.stringify(chatItem));

    var isMatch = false;
    if (chatArray.length > 0) {
      for (let i = 0; i < chatArray.length; i++) {
        const element = chatArray[i];
        if (chatItem && element.roomId === chatItem.roomId) {
          // Increment unread count
          chatItem = await calcUnreadCount(chatItem, element.chatUnreadCount);

          // Since chat item received is an object to convert it to array and they re initialise
          // if (chatItem.chat.length <= 0) {
          chatItem.chat = [chatItem.chat];
          // }
          console.log("Selected Chat Received => ", JSON.stringify(chatItem));
          chatArray[i] = chatItem;
          isMatch = true;
          break;
        }
      }

      if (!isMatch && chatItem.chatUnreadCount.type != 'reset') {
        // Increment unread count
        chatItem = await calcUnreadCount(chatItem, 0);

        // Since chat item received is an object to convert it to array and they re initialise
        // if (chatItem.chat.length <= 0) {
        chatItem.chat = [chatItem.chat];
        // }
        console.log("Selected Chat Received => ", JSON.stringify(chatItem));
        chatArray.push(chatItem);
      }

      console.log("Message CHAT AFTER Received => ", JSON.stringify(chatItem));

      dispatch({ type: CHAT_LIST, payload: chatArray });
      console.log(
        `FINAL CHAT ARRAY ${refresh} => `,
        "JSON.stringify(chatArray)"
      );
    } else {
      // For new chat
      if (chatItem.chatUnreadCount.type === "add") {
        dispatch({ type: REFRESH, payload: true });
      }
    }
  }

  function listenSocket() {
    // socket.removeListener(constants.CHAT_LIST);
    socket.on(constants.CHAT_LIST, chatItem => {
      dispatch({type: CHAT_ITEM, payload: chatItem});
    });
  }

  // function calcUnreadCount(chatItem, element) {
  //   // const userId = await getLocalData(constants.USER_ID);

  //   if (element.chatUnreadCount.length > 0) {
  //     for (let index = 0; index < element.chatUnreadCount.length; index++) {
  //       const data = element[index];
  //       if (data.userid != userId) {
  //         if (chatItem.chatUnreadCount.type === 'reset') {
  //           data.count = 0;
  //         } else if (chatItem.chatUnreadCount.type === 'add') {
  //           data.count = data.count + 1;
  //         }
  //         chatItem.chatUnreadCount = element.chatUnreadCount;
  //         break;
  //       }
  //     }
  //   }

  //   return chatItem;
  // }

  function calcUnreadCount(chatItem, originalCount) {
    // const userId = await getLocalData(constants.USER_ID);
    if (chatItem.chatUnreadCount.userId != userId) {
      if (chatItem.chatUnreadCount.type === 'reset') {
        chatItem.chatUnreadCount = 0;
      } else if (chatItem.chatUnreadCount.type === 'add') {
        chatItem.chatUnreadCount = originalCount ? originalCount + 1 : 1;
      } else {
        chatItem.chatUnreadCount = 0;
      }
    } else if (chatItem.chatUnreadCount.type === 'reset') {
      chatItem.chatUnreadCount = 0;
    } else {
      chatItem.chatUnreadCount = originalCount;
    }
    return chatItem;
  }

  return (
    <View style={{flex: 1}}>
      {chatList.length === 0 && <EmptyComponent message={'No Chats Found'} />}
      <FlatList
        data={chatList}
        extraData={refresh}
        keyExtractor={(item, index) => index.toString()}
        ItemSeparatorComponent={() => {
          return <_Divider />;
        }}
        renderItem={({item, index}) => {
          return (
            <ChatListItem item={item} navigation={navigation} userId={userId} />
          );
        }}
      />
      <Button
        active={true}
        rounded
        style={styles.btnView}
        onPress={() =>
          navigation.navigate(NAV_TYPES.CONTACTS_SCREEN, {chatList})
        }>
        <Image source={CHAT} style={styles.thumbView} />
      </Button>
    </View>
  );
}
Example #9
Source File: welcome.js    From intentional-walk with MIT License 4 votes vote down vote up
export default function WelcomeScreen({navigation}) {
  useFocusEffect(
    React.useCallback(() => {
      const onBackPress = () => {
        BackHandler.exitApp();
        return true;
      };
      BackHandler.addEventListener('hardwareBackPress', onBackPress);
      return () =>
        BackHandler.removeEventListener('hardwareBackPress', onBackPress);
    }),
  );

  const [language, setLanguage] = useState(null);
  const [isLoading, setLoading] = useState(false);
  const [showAlert, setShowAlert] = useState(false);

  const selectLanguage = lang => {
    setLanguage(lang);
    moment.locale(lang);
    Strings.setLanguage(lang);
    Realm.getSettings().then(settings =>
      Realm.write(() => (settings.lang = lang)),
    );
  };

  const continuePressed = () => {
    setLoading(true);
    Realm.updateContest()
      .then(contest => {
        setLoading(false);
        navigation.navigate('SignUp', {contest: contest.toObject()});
      })
      .catch(error => {
        setLoading(false);
        setShowAlert(true);
      });
  };

  return (
    <SafeAreaView style={GlobalStyles.container}>
      <ScrollView>
        <View style={styles.content}>
          <Text style={GlobalStyles.h1}>{Strings.common.welcome}</Text>
          <Text style={styles.subtitle}>{Strings.welcome.select}</Text>
          <Button
            style={styles.button}
            isToggle={true}
            isSelected={language === 'en'}
            onPress={() => selectLanguage('en')}>
            English
          </Button>
          <Button
            style={styles.button}
            isToggle={true}
            isSelected={language === 'es'}
            onPress={() => selectLanguage('es')}>
            Español
          </Button>
          <Button
            style={[styles.button, styles.lastButton]}
            isToggle={true}
            isSelected={language === 'zh-cn'}
            onPress={() => selectLanguage('zh-cn')}>
            中文
          </Button>
          {language && isLoading && (
            <View style={styles.loader}>
              <ActivityIndicator size="small" color={Colors.primary.purple} />
              <Text style={styles.loaderText}>{Strings.common.pleaseWait}</Text>
            </View>
          )}
          {language && !isLoading && (
            <Button style={styles.button} onPress={continuePressed}>
              {Strings.welcome.start}
            </Button>
          )}
        </View>
      </ScrollView>
      <Popup isVisible={showAlert} onClose={() => setShowAlert(false)}>
        <View style={GlobalStyles.centered}>
          <Text style={GlobalStyles.h1}>{Strings.common.serverErrorTitle}</Text>
          <Text style={[GlobalStyles.h2, GlobalStyles.alertText]}>
            {Strings.common.serverErrorMessage}
          </Text>
          <Button style={styles.button} onPress={() => setShowAlert(false)}>
            {Strings.common.okay}
          </Button>
        </View>
      </Popup>
    </SafeAreaView>
  );
}
Example #10
Source File: signup.js    From intentional-walk with MIT License 4 votes vote down vote up
export default function SignUpScreen({navigation, route}) {
  const {contest} = route.params;
  const [focus, setFocus] = useState('');

  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [email, setEmail] = useState('');
  const [zip, setZip] = useState('');
  const [age, setAge] = useState('');
  const [termsAgreed, setTermsAgreed] = useState(false);

  const [isLoading, setLoading] = useState(false);

  const [showAlert, setShowAlert] = useState(false);
  const [alertTitle, setAlertTitle] = useState('');
  const [alertMessage, setAlertMessage] = useState('');
  const [showPrivacyPolicy, setShowPrivacyPolicy] = useState(false);
  const [showContestRules, setShowContestRules] = useState(false);

  const screenDims = Dimensions.get('screen');
  const [privacyText, setPrivacyText] = useState();
  loadLocalResource(Privacy[Strings.getLanguage()]).then(text =>
    setPrivacyText(text),
  );
  const [contestRulesText, setContestRulesText] = useState();
  loadLocalResource(ContestRules[Strings.getLanguage()]).then(text =>
    setContestRulesText(text),
  );

  useFocusEffect(
    useCallback(() => {
      const onBackPress = () => {
        if (showAlert) {
          setShowAlert(false);
          return true;
        } else if (showPrivacyPolicy) {
          setShowPrivacyPolicy(false);
          return true;
        }
        return false;
      };
      BackHandler.addEventListener('hardwareBackPress', onBackPress);
      return () =>
        BackHandler.removeEventListener('hardwareBackPress', onBackPress);
    }),
  );

  async function onSubmit() {
    /// validate email
    if (!email.trim().match(/^[^@ ]+@[^. ]+(?:\.[^. ]+)+$/)) {
      setAlertTitle(Strings.signUp.emailAlertTitle);
      setAlertMessage(Strings.signUp.emailAlertMessage);
      setShowAlert(true);
      return;
    }
    /// validate zip-5 digits
    if (!zip.trim().match(/^\d{5}$/)) {
      setAlertTitle(Strings.signUp.zipAlertTitle);
      setAlertMessage(Strings.signUp.zipAlertMessage);
      setShowAlert(true);
      return;
    }
    //validate zip- sf resident
    else if (!validZipCodes.includes(zip.trim())) {
      setAlertTitle(Strings.signUp.zipRestrictionAlertTitle);
      setAlertMessage(Strings.signUp.zipRestrictionAlertMessage);
      setShowAlert(true);
      return;
    }
    /// validate age
    const parsedAge = parseInt(age, 10);
    if (isNaN(parsedAge) || parsedAge < 18) {
      setAlertTitle(Strings.signUp.ageAlertTitle);
      setAlertMessage(Strings.signUp.ageAlertMessage);
      setShowAlert(true);
      return;
    }
    setLoading(true);
    try {
      const settings = await Realm.getSettings();
      const response = await Api.appUser.create(
        firstName.trim(),
        lastName.trim(),
        email.trim(),
        zip.trim(),
        parsedAge,
        settings.accountId,
      );
      const user = await Realm.createUser({
        ...response.data.payload,
        id: response.data.payload.account_id,
      });
      setLoading(false);
      if (user.isSurveyCompleted) {
        navigation.navigate('Info');
      } else {
        navigation.navigate('LoHOrigin');
      }
    } catch (error) {
      setLoading(false);
      setAlertTitle(Strings.common.serverErrorTitle);
      setAlertMessage(Strings.common.serverErrorMessage);
      setShowAlert(true);
    }
  }

  function onPolicyPress() {
    setShowPrivacyPolicy(true);
  }

  function onContestRulesPress() {
    setShowContestRules(true);
  }

  function isValid() {
    return (
      firstName.trim() !== '' &&
      lastName.trim() !== '' &&
      email.trim() !== '' &&
      zip.trim() !== '' &&
      age.trim() !== '' &&
      termsAgreed
    );
  }

  return (
    <SafeAreaView style={GlobalStyles.container}>
      <KeyboardAwareScrollView style={GlobalStyles.container}>
        <View style={styles.content}>
          <Text style={GlobalStyles.h1}>{Strings.common.welcome}</Text>
          <View style={[styles.row, styles.logos]}>
            <Image
              source={require('../../assets/sfdph_logo.png')}
              style={[styles.logo, styles.sfdphLogo]}
            />
            <Image
              source={require('../../assets/sfgiants_logo.png')}
              style={[styles.logo, styles.giantsLogo]}
            />
          </View>
          <Text style={GlobalStyles.p1}>
            {Strings.formatString(
              Strings.signUp.about,
              Strings.formatString(
                Strings.common.range,
                moment(contest.start).format(Strings.common.rangeFrom),
                moment(contest.end).format(Strings.common.rangeTo),
              ),
            )}
          </Text>
          <View style={styles.row}>
            <Input
              onSubmitEditing={() => setFocus('last_name')}
              onChangeText={newValue => setFirstName(newValue)}
              style={styles.input}
              placeholder={Strings.signUp.firstName}
              autoCapitalize="words"
              autoCompleteType="name"
              returnKeyType="next"
              editable={!isLoading}
            />
            <View style={styles.spacer} />
            <Input
              focused={focus === 'last_name'}
              onSubmitEditing={() => setFocus('email')}
              onChangeText={newValue => setLastName(newValue)}
              style={styles.input}
              placeholder={Strings.signUp.lastName}
              autoCapitalize="words"
              autoCompleteType="name"
              returnKeyType="next"
              editable={!isLoading}
            />
          </View>
          <Input
            focused={focus === 'email'}
            onSubmitEditing={() => setFocus('zip')}
            onChangeText={newValue => setEmail(newValue)}
            placeholder={Strings.signUp.email}
            autoCompleteType="email"
            keyboardType="email-address"
            returnKeyType="next"
            editable={!isLoading}
          />
          <View style={styles.row}>
            <Input
              focused={focus === 'zip'}
              onSubmitEditing={() => setFocus('age')}
              onChangeText={newValue => setZip(newValue)}
              style={styles.input}
              placeholder={Strings.signUp.zipCode}
              keyboardType="number-pad"
              returnKeyType={Platform.select({ios: 'done', android: 'next'})}
              editable={!isLoading}
            />
            <View style={styles.spacer} />
            <Input
              focused={focus === 'age'}
              onSubmitEditing={() => setFocus('')}
              onChangeText={newValue => setAge(newValue)}
              style={styles.input}
              placeholder={Strings.signUp.age}
              keyboardType="number-pad"
              editable={!isLoading}
            />
          </View>
          <Text style={[GlobalStyles.p1, styles.requiredText]}>
            {Strings.signUp.required}
          </Text>
          <CheckBox
            style={styles.agreeCheckBox}
            checked={termsAgreed}
            onPress={() => setTermsAgreed(!termsAgreed)}
            editable={!isLoading}>
            <Text
              style={[GlobalStyles.p1, styles.agreeText]}
              onPress={() => setTermsAgreed(!termsAgreed)}>
              {Strings.formatString(
                Strings.signUp.agree,
                <Text style={styles.linkText} onPress={onPolicyPress}>
                  {Strings.signUp.policy}
                </Text>,
                <Text style={styles.linkText} onPress={onContestRulesPress}>
                  {Strings.signUp.contestRules}
                </Text>,
              )}
            </Text>
          </CheckBox>
          {isLoading && (
            <View style={styles.loader}>
              <ActivityIndicator size="small" color={Colors.primary.purple} />
              <Text style={styles.loaderText}>{Strings.common.pleaseWait}</Text>
            </View>
          )}
          {!isLoading && (
            <Button
              isEnabled={isValid()}
              style={styles.button}
              onPress={onSubmit}>
              {Strings.signUp.submit}
            </Button>
          )}
          <PaginationDots currentPage={1} totalPages={7} />
        </View>
      </KeyboardAwareScrollView>
      <Popup
        isVisible={showPrivacyPolicy}
        onClose={() => setShowPrivacyPolicy(false)}>
        <View>
          <ScrollText
            style={{height: Math.round((screenDims.height - 100) * 0.8)}}>
            <Logo style={styles.privacyLogo} />
            <Text style={GlobalStyles.h1}>{Strings.common.privacyPolicy}</Text>
            <Autolink text={privacyText} style={styles.privacyText} />
          </ScrollText>
        </View>
      </Popup>
      <Popup
        isVisible={showContestRules}
        onClose={() => setShowContestRules(false)}>
        <View>
          <ScrollText
            style={{height: Math.round((screenDims.height - 100) * 0.8)}}>
            <Logo style={styles.privacyLogo} />
            <Text style={GlobalStyles.h1}>{Strings.common.contestRules}</Text>
            <Autolink text={contestRulesText} style={styles.privacyText} />
          </ScrollText>
        </View>
      </Popup>
      <Popup isVisible={showAlert} onClose={() => setShowAlert(false)}>
        <View style={GlobalStyles.centered}>
          <Text style={GlobalStyles.h1}>{alertTitle}</Text>
          <Text style={[GlobalStyles.h2, styles.alertText]}>
            {alertMessage}
          </Text>
          <Button style={styles.button} onPress={() => setShowAlert(false)}>
            {Strings.common.okay}
          </Button>
        </View>
      </Popup>
    </SafeAreaView>
  );
}
Example #11
Source File: home.js    From intentional-walk with MIT License 4 votes vote down vote up
export default function HomeScreen({navigation}) {
  const safeAreaInsets = useSafeArea();

  const dateRef = useRef(moment().startOf('day'));
  const [date, setDate] = useState(dateRef.current);

  const [dailyWalks, setDailyWalks] = useState(null);
  const [todaysWalk, setTodaysWalk] = useState(null);
  const [totalSteps, setTotalSteps] = useState(null);

  const [contest, setContest] = useState(null);

  const [recordedWalks, setRecordedWalks] = useState(null);
  const [activeWalk, setActiveWalk] = useState(null);

  async function saveStepsAndDistances() {
    const newContest = await Realm.getContest();
    const today = moment().endOf('day');
    if (newContest) {
      let from = null;
      let to = null;
      /// check if we're in/after the contest period
      if (!newContest.isBeforeBaselineDate) {
        from = moment(newContest.startBaseline);
        /// check if we're in the contest period
        if (newContest.isAfterEndDate) {
          to = moment(newContest.end);
        } else {
          to = today;
        }
      }
      /// only save when within contest period
      if (from && to) {
        const newDailyWalks = await Fitness.getStepsAndDistances(from, to);
        if (newDailyWalks && newDailyWalks.length > 0) {
          /// get user account, then save to server...!
          const user = await Realm.getUser();
          if (user) {
            try {
              await Api.dailyWalk.create(newDailyWalks, user.id);
            } catch (error) {
              console.log(error);
            }
          }
        }
      }
    }
  }

  async function getStepsAndDistances(queryDate, currentDailyWalks) {
    setTodaysWalk(null);
    if (currentDailyWalks == null) {
      setDailyWalks(true);
      try {
        const newDailyWalks = await Fitness.getStepsAndDistances(
          moment(dateRef.current).startOf('month'),
          moment(dateRef.current).endOf('month'),
        );
        if (
          moment(dateRef.current)
            .startOf('month')
            .isSame(moment(queryDate).startOf('month'))
        ) {
          setDailyWalks(newDailyWalks);
          getStepsAndDistances(dateRef.current, newDailyWalks);
        }
      } catch (error) {
        console.log(error);
      }
    } else if (Array.isArray(currentDailyWalks)) {
      let newTodaysWalk = {
        steps: 0,
        distance: 0,
      };
      let from = moment(queryDate).startOf('day');
      let to = moment(from).endOf('day');
      for (let dailyWalk of currentDailyWalks) {
        if (
          from.isSameOrBefore(dailyWalk.date) &&
          to.isSameOrAfter(dailyWalk.date)
        ) {
          newTodaysWalk = dailyWalk;
          break;
        }
      }
      setTodaysWalk(newTodaysWalk);
    }
  }

  async function getTotalSteps() {
    setTotalSteps(null);
    /// get current contest
    const newContest = await Realm.getContest();
    const now = moment();
    let from = null,
      to = null;
    /// check if we're in/outside the contest period
    if (newContest && newContest.isDuringContest) {
      /// get total from start of contest until now
      from = moment(newContest.start);
      to = now;
    } else {
      /// get total from start of month
      from = moment().startOf('month');
      to = now;
    }
    if (from && to) {
      let newTotalSteps = 0;
      try {
        const steps = await Fitness.getSteps(from, to);
        for (let step of steps) {
          newTotalSteps += step.quantity;
        }
      } finally {
        setTotalSteps(newTotalSteps);
      }
    } else {
      /// no range, just show 0
      setTotalSteps(0);
    }
  }

  async function getRecordedWalks(queryDate) {
    const realm = await Realm.open();
    const newRecordedWalks = realm
      .objects('IntentionalWalk')
      .filtered(
        'start>=$0 AND end<$1',
        queryDate.toDate(),
        moment(queryDate).add(1, 'd').toDate(),
      )
      .sorted([['end', true]]);
    if (dateRef.current.isSame(queryDate)) {
      setRecordedWalks(newRecordedWalks);
    }
  }

  function setDateAndGetDailySteps(newDate) {
    const oldDate = dateRef.current;
    dateRef.current = newDate;
    setDate(newDate);

    let newDailyWalks = dailyWalks;
    if (!oldDate.startOf('month').isSame(moment(newDate).startOf('month'))) {
      newDailyWalks = null;
    }
    getStepsAndDistances(newDate, newDailyWalks);
    getRecordedWalks(newDate);
  }

  function refresh() {
    const today = moment().startOf('day');
    dateRef.current = moment(dateRef.current);
    if (dateRef.current.isAfter(today)) {
      dateRef.current = today;
    }
    setDate(dateRef.current);
    getStepsAndDistances(dateRef.current, null);
    getTotalSteps();
    getRecordedWalks(dateRef.current);
    saveStepsAndDistances();
  }

  /// one time setup for some data store listeners
  useEffect(() => {
    /// listen for an active walk
    let isFirstLoad = true;
    Realm.addCurrentWalkListener(walk => {
      setActiveWalk(walk);
      if (!isFirstLoad && walk == null) {
        /// if we've just finished a walk, then refresh to update step counts
        refresh();
      }
      isFirstLoad = false;
    });
    /// listen for updates to contest info
    Realm.addContestListener(newContest =>
      newContest ? setContest(newContest.toObject()) : null,
    );
    /// on cleanup, remove listeners
    return () => Realm.removeAllListeners();
  }, []);

  /// perform a bunch of other one-time checks/setup on app launch
  useEffect(() => {
    SplashScreen.hide();
    /// load settings
    Realm.getSettings().then(settings => {
      const lang = settings.lang;
      if (lang) {
        /// set language preference, if any
        Strings.setLanguage(lang);
        /// recreate the date in the current locale
        moment.locale(lang);
        dateRef.current = moment(dateRef.current);
        setDate(dateRef.current);
      }
    });
    /// get signed in user, if any
    Realm.getUser().then(user => {
      /// if no user, go to onboarding flow
      if (!user) {
        navigation.navigate('OnboardingStack');
      } else if (!user.isSurveyCompleted) {
        navigation.navigate('OnboardingStack', {
          screen: 'LoHOrigin',
          params: {initial: true},
        });
      }
    });
    /// check for updated contest info
    Realm.updateContest();
  }, []);

  useFocusEffect(
    React.useCallback(() => {
      refresh();
    }, []),
  );

  const today = moment().startOf('day');
  const isToday = date.isSame(today);

  return (
    <View style={GlobalStyles.container}>
      {!activeWalk && (
        <>
          <ScrollView>
            <View
              style={[
                GlobalStyles.content,
                {paddingBottom: safeAreaInsets.bottom + 20 + 17 + 10 + 54},
              ]}>
              <DateNavigator
                style={styles.marginBottom}
                date={date}
                setDate={setDateAndGetDailySteps}
              />
              {contest && contest.isBeforeStartDate && (
                <View style={styles.marginBottom}>
                  <Text style={styles.alertText}>
                    {Strings.home.getReadyAlert1}
                  </Text>
                  <Text style={styles.alertText}>
                    {Strings.formatString(
                      Strings.home.getReadyAlert2,
                      moment(contest.start).format(Strings.common.date),
                    )}
                  </Text>
                </View>
              )}
              {contest && contest.isDuringContest && (
                <View style={styles.marginBottom}>
                  <Text style={styles.alertText}>
                    {Strings.formatString(
                      Strings.home.currentAlert,
                      moment(contest.start).format(Strings.common.date),
                      moment(contest.end).format(Strings.common.date),
                    )}
                  </Text>
                </View>
              )}
              {contest && contest.isWeekAfterEndDate && (
                <View style={styles.marginBottom}>
                  <Text style={styles.alertText}>
                    {Strings.formatString(Strings.home.congratsAlert)}
                  </Text>
                </View>
              )}
              {contest &&
                contest.isAfterEndDate &&
                !contest.isWeekAfterEndDate && (
                  <View style={styles.marginBottom}>
                    <Text style={styles.alertText}>
                      {Strings.formatString(Strings.home.noContestAlert)}
                    </Text>
                  </View>
                )}
              <View style={styles.row}>
                <StatBox
                  mainText={
                    todaysWalk ? numeral(todaysWalk.steps).format('0,0') : ' '
                  }
                  subText={
                    isToday ? Strings.home.stepsToday : Strings.common.steps
                  }
                  icon="directions-walk"
                  iconSize={140}
                  iconStyle={styles.walkIcon}
                  style={[
                    styles.stepsBox,
                    styles.box,
                    isToday ? null : styles.stepsBoxRounded,
                  ]}
                  boxColor={Colors.accent.teal}
                />
                <StatBox
                  mainText={
                    todaysWalk
                      ? numeral(todaysWalk.distance * 0.000621371).format(
                          '0,0.0',
                        )
                      : ' '
                  }
                  mainTextSuffix={Strings.home.milesSuffix}
                  subText={
                    isToday ? Strings.home.milesToday : Strings.common.miles
                  }
                  icon="swap-calls"
                  iconSize={200}
                  iconStyle={styles.milesIcon}
                  style={[
                    styles.milesBox,
                    styles.box,
                    isToday ? null : styles.milesBoxRounded,
                  ]}
                  boxColor={Colors.primary.lightGreen}
                />
              </View>
              <View
                style={[styles.row, isToday ? null : styles.hidden]}
                pointerEvents={isToday ? 'auto' : 'none'}>
                <StatBox
                  mainText={
                    totalSteps != null ? numeral(totalSteps).format('0,0') : ' '
                  }
                  subText={
                    contest && contest.isDuringContest
                      ? Strings.home.overallStepTotal
                      : Strings.home.stepsThisMonth
                  }
                  icon="star-border"
                  iconSize={200}
                  style={[styles.overallBox, styles.box]}
                  boxColor={Colors.accent.orange}
                />
              </View>
              <View
                style={[styles.row, isToday ? null : styles.hidden]}
                pointerEvents={isToday ? 'auto' : 'none'}>
                <TouchableOpacity
                  style={styles.box}
                  onPress={() => navigation.navigate('WhereToWalk')}>
                  <View style={styles.walkBox}>
                    <Text style={styles.walkText}>
                      {Strings.home.whereToWalk}
                    </Text>
                    <Icon
                      style={styles.walkChevron}
                      name="chevron-right"
                      size={30}
                    />
                  </View>
                </TouchableOpacity>
              </View>
              <View style={[styles.subtitle]}>
                <Text style={styles.subtitleHeader}>
                  {Strings.home.myRecordedWalks}
                </Text>
                <Text
                  style={styles.subtitleLink}
                  onPress={() => navigation.navigate('RecordedWalks')}>
                  {Strings.home.allRecordedWalks}
                </Text>
              </View>
              {recordedWalks && recordedWalks.length === 0 && (
                <RecordedWalk
                  title={
                    isToday ? Strings.common.noWalksYet : Strings.common.noWalks
                  }
                  subtitle={isToday ? Strings.home.noWalksYetText : null}
                />
              )}
              {recordedWalks &&
                recordedWalks.length > 0 &&
                recordedWalks.map(walk => (
                  <RecordedWalk key={walk.id} walk={walk} />
                ))}
            </View>
          </ScrollView>
          <View
            pointerEvents={isToday ? 'box-none' : 'none'}
            style={[
              styles.recordContainer,
              {paddingBottom: safeAreaInsets.bottom},
              isToday ? null : styles.hidden,
            ]}>
            <TouchableOpacity onPress={() => Realm.startWalk()}>
              <Image
                style={styles.recordButton}
                source={require('../../assets/record.png')}
              />
            </TouchableOpacity>
            <Text style={styles.recordText}>{Strings.home.recordAWalk}</Text>
          </View>
        </>
      )}
      {activeWalk && (
        <Recorder
          style={[styles.recorder, {paddingBottom: safeAreaInsets.bottom}]}
          activeWalk={activeWalk}
        />
      )}
    </View>
  );
}
Example #12
Source File: TelaInicial.js    From aglomerou with GNU General Public License v3.0 4 votes vote down vote up
TelaInicial = ({ navigation }) => {
  const [modalVisible, setModalVisible] = useState(false);
  const [registrado, setRegistrado] = useState(false);

  const fecharModal = () => {
    setModalVisible(!modalVisible);
    navegarPaginas('Mapa');
  };

  const navegarPaginas = (destino) => {
    console.log(destino);
    navigation.navigate(destino);
  };

  // verifica se o dispositivo já está registrado
  useFocusEffect(() => {
    let mounted = true;
    async function buscaRegistro() {
      const registro = await verificaRegistrado();

      if (registro === true) {
        setRegistrado(true);
      }
    }

    if (mounted) {
      buscaRegistro();
    }
    return () => {
      mounted = false;
    };
  }, []);

  return (
    <>
      <View style={styles.container}>
        <Image style={styles.logo} source={logo} />
        <Text style={styles.welcomeText}>Seja bem vindo(a)!</Text>
        <View style={styles.infoBoxContainer}>
          <Text style={styles.infoBoxText}>
            O <Text style={styles.boldText}>Aglomerou?</Text> coleta dados de
            localização dos dispositivos de forma{' '}
            <Text style={styles.boldText}>completamente anônima</Text> e exibe
            pra você em tempo real pontos de aglomeração espalhados pela cidade.
          </Text>
        </View>
        <Image
          style={styles.splash}
          source={inicialSplash}
          resizeMode="contain"
        />
        <TouchableOpacity
          style={styles.button}
          onPress={() => {
            console.log('REGISTER:?', registrado);
            registrado
              ? navigation.navigate('Mapa')
              : setModalVisible(!modalVisible);
          }}
        >
          <View style={styles.buttonContainer}>
            <View style={styles.buttonIconContainer}>
              <Fa name="sign-in-alt" size={22} color="#fff" />
            </View>
            <View style={styles.buttonTextContainer}>
              <Text style={styles.buttonText}>entrar</Text>
            </View>
          </View>
        </TouchableOpacity>
        <Text style={styles.infoText}>
          O "Aglomerou?" se preocupa com a sua privacidade. Nenhum dado pessoal
          será coletado durante o uso do app!
        </Text>
      </View>
      <ModalRegistroPermissoes
        modalVisible={modalVisible}
        fecharModal={fecharModal}
        navegarPaginas={navegarPaginas}
      />
    </>
  );
}
Example #13
Source File: index.js    From puente-reactnative-collect with MIT License 4 votes vote down vote up
DataCollection = ({ navigation }) => {
  const [scrollViewScroll, setScrollViewScroll] = useState();
  const [loading, setLoading] = useState(false);
  const [settings, setSettings] = useState(false);

  const [view, setView] = useState('Root');

  const [selectedForm, setSelectedForm] = useState('id');
  const [selectedAsset, setSelectedAsset] = useState(null);

  const [customForm, setCustomForm] = useState();
  const [pinnedForms, setPinnedForms] = useState([]);

  const [selectPerson, setSelectPerson] = useState();
  const [surveyee, setSurveyee] = useState({});

  const [surveyingOrganization, setSurveyingOrganization] = useState('');
  const [surveyingUser, setSurveyingUser] = useState();

  const { onLogout } = useContext(UserContext);

  useFocusEffect(
    useCallback(() => {
      const fetchData = async () => {
        getData('currentUser').then((user) => {
          setSurveyingUser(`${user.firstname || ''} ${user.lastname || ''}`);
          setSurveyingOrganization(user.organization || surveyingOrganization);
        });
        getData('pinnedForms').then((forms) => {
          if (forms) setPinnedForms(forms);
        });
      };

      fetchData();
    }, [surveyingUser, surveyingOrganization])
  );

  const navigateToRoot = async () => {
    setView('Root');
  };

  const navigateToNewRecord = async (formTag, surveyeePerson) => {
    setView('Forms');
    setSurveyee(surveyeePerson || surveyee);
    setSelectedForm(formTag || 'id');
  };

  const navigateToGallery = async () => {
    setView('Gallery');
  };

  const navigateToNewAssets = async () => {
    setView('Assets');
    setSelectedAsset({});
  };

  const navigateToViewAllAssets = async () => {
    setView('Assets');
    setSelectedAsset(null);
  };

  const navigateToCustomForm = async (form, surveyeePerson) => {
    setView('Forms');
    setSurveyee(surveyeePerson || surveyee);
    setSelectedForm('custom');
    setCustomForm(form || '');
  };

  const navigateToFindRecords = async () => {
    setView('Find Records');
  };

  const logOut = () => onLogout().then(() => navigation.navigate('Sign In'));

  return (
    <View
      style={layout.screenContainer}
      onStartShouldSetResponderCapture={() => {
        setScrollViewScroll(true);
      }}
    >
      <Header
        view={view}
        setView={setView}
        setSettings={setSettings}
      />
      <KeyboardAvoidingView
        enabled
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={{ flex: 1 }}
      >
        {loading === true
        && <ActivityIndicator />}
        <ScrollView keyboardShouldPersistTaps="never" scrollEnabled={scrollViewScroll}>
          {settings === true ? (
            <SettingsView
              setView={setView}
              setSettings={setSettings}
              logOut={logOut}
              surveyingOrganization={surveyingOrganization}
              scrollViewScroll={scrollViewScroll}
              setScrollViewScroll={setScrollViewScroll}
            />
          ) : (
            <View>
              { view === 'Root' && (
                <View>
                  <MapView organization={surveyingOrganization} />
                  <View style={styles.screenFlexRowWrap}>
                    <View style={styles.cardContainer}>
                      <Card style={styles.cardSmallStyle} onPress={() => navigateToNewRecord()}>
                        <NewRecordSVG height={70} style={styles.svg} />
                        <Text style={styles.text}>{I18n.t('dataCollection.newRecord')}</Text>
                      </Card>
                      <Card style={styles.cardSmallStyle} onPress={navigateToFindRecords}>
                        <FindRecordSVG height={65} style={styles.svg} />
                        <Text style={styles.text}>{I18n.t('dataCollection.findRecord')}</Text>
                      </Card>
                    </View>
                    <Card style={styles.cardSmallStyle} onPress={navigateToGallery}>
                      <ComingSoonSVG height={65} style={styles.svg} />
                      <Text style={styles.text}>{I18n.t('dataCollection.viewAll')}</Text>
                    </Card>
                    <View style={styles.cardContainer}>
                      <Card style={styles.cardSmallStyle} onPress={navigateToNewAssets}>
                        <ResearchSVG height={70} width={70} style={styles.svg} />
                        <Text style={styles.text}>{I18n.t('dataCollection.newAsset')}</Text>
                      </Card>
                      <Card style={styles.cardSmallStyle} onPress={navigateToViewAllAssets}>
                        <ResearchSVG height={70} width={70} style={styles.svg} />
                        <Text style={styles.text}>{I18n.t('dataCollection.viewAssets')}</Text>
                      </Card>
                    </View>
                  </View>
                </View>
              )}
              {view === 'Forms' && (
                <View>
                  <Button icon="arrow-left" width={100} onPress={navigateToRoot}>
                    <Text>{I18n.t('dataCollection.back')}</Text>
                  </Button>
                  <Forms
                    style={layout.line}
                    navigation={navigation}
                    scrollViewScroll={scrollViewScroll}
                    setScrollViewScroll={setScrollViewScroll}
                    navigateToGallery={navigateToGallery}
                    navigateToNewRecord={navigateToNewRecord}
                    navigateToRoot={navigateToRoot}
                    navigateToCustomForm={navigateToCustomForm}
                    selectedForm={selectedForm}
                    setSelectedForm={setSelectedForm}
                    surveyingUser={surveyingUser}
                    surveyingOrganization={surveyingOrganization}
                    surveyee={surveyee}
                    setSurveyee={setSurveyee}
                    customForm={customForm}
                    setView={setView}
                    pinnedForms={pinnedForms}
                  />
                </View>
              )}
              {view === 'Assets' && (
                <View>
                  <Button icon="arrow-left" width={100} onPress={navigateToRoot}>
                    <Text>{I18n.t('dataCollection.back')}</Text>
                  </Button>
                  <Assets
                    surveyingOrganization={surveyingOrganization}
                    surveyingUser={surveyingUser}
                    selectedAsset={selectedAsset}
                    setSelectedAsset={setSelectedAsset}
                    navigateToNewAssets={navigateToNewAssets}
                    navigateToViewAllAssets={navigateToViewAllAssets}
                    scrollViewScroll={scrollViewScroll}
                    setScrollViewScroll={setScrollViewScroll}
                  />
                </View>
              )}
              {view === 'Gallery' && (
                <View>
                  <Button icon="arrow-left" width={100} onPress={navigateToRoot}>
                    <Text>{I18n.t('dataCollection.back')}</Text>
                  </Button>
                  <FormGallery
                    navigation={navigation}
                    navigateToNewRecord={navigateToNewRecord}
                    puenteForms={puenteForms}
                    navigateToCustomForm={navigateToCustomForm}
                    setLoading={setLoading}
                    surveyingOrganization={surveyingOrganization}
                    pinnedForms={pinnedForms}
                    setPinnedForms={setPinnedForms}
                  />
                </View>
              )}
              {view === 'Find Records'
                && (
                  <View>
                    {!selectPerson && (
                      <Button icon="arrow-left" width={100} onPress={navigateToRoot}>
                        <Text>{I18n.t('dataCollection.back')}</Text>
                      </Button>
                    )}
                    <FindResidents
                      selectPerson={selectPerson}
                      setSelectPerson={setSelectPerson}
                      organization={surveyingOrganization}
                      puenteForms={puenteForms}
                      navigateToNewRecord={navigateToNewRecord}
                      surveyee={surveyee}
                      setSurveyee={setSurveyee}
                      navigateToRoot={navigateToRoot}
                      setView={setView}
                    />
                  </View>
                )}
            </View>
          )}
        </ScrollView>
      </KeyboardAvoidingView>
    </View>
  );
}
Example #14
Source File: VimeoVideo.js    From UltimateApp with MIT License 4 votes vote down vote up
VimeoVideo = ({ vimeoId, sounds, shouldPlay }) => {
  const videoElem = useRef(null);
  const [isBuffering, setBuffer] = useState(true);
  const [error, setError] = useState();

  useEffect(() => {
    const vimeoUrlSource = `https://player.vimeo.com/video/${vimeoId}/config`;
    let aborted = false;
    setBuffer(true);
    setError(null);

    fetch(vimeoUrlSource)
      .then((res) => res.json())
      .then((res) => {
        const videoArray = res.request.files.progressive;
        const videoVimeoQuality = videoArray.find((videoObject) => videoObject.quality === '540p');
        if (videoVimeoQuality) {
          return videoVimeoQuality.url;
        }
      })
      .then((url) => {
        if (aborted) return;
        return videoElem.current.loadAsync({
          uri: url,
        });
      })
      .catch((e) => {
        if (aborted) return;
        setError(e);
        setBuffer(false);
      });

    return () => (aborted = true);
  }, [vimeoId]);

  // Stop playing the video on screen change
  useFocusEffect(
    React.useCallback(() => {
      return () => {
        videoElem.current?.pauseAsync();
      };
    }, []),
  );

  const playVideoLoaded = () => {
    Audio.setAudioModeAsync({
      playsInSilentModeIOS: true,
    });
    videoElem.current.setStatusAsync({
      rate: 1.0,
      isMuted: !sounds,
      resizeMode: ResizeMode.CONTAIN,
      shouldPlay: shouldPlay || false,
      isLooping: true,
    });

    setBuffer(false);
  };

  const renderBufferIcon = () => {
    return (
      <View style={styles.spinnerStyle}>
        <ActivityIndicator animating color={theme.COLOR_SECONDARY} size="large" />
        <Text>{I18n.t('vimeoVideo.loading')}</Text>
      </View>
    );
  };

  const renderError = () => {
    return (
      <View style={styles.spinnerStyle}>
        <Text>{I18n.t('vimeoVideo.error')}</Text>
      </View>
    );
  };

  return (
    <View style={styles.videoContainer}>
      {error && renderError()}
      {isBuffering && renderBufferIcon()}
      <Video
        ref={videoElem}
        resizeMode={ResizeMode.CONTAIN}
        useNativeControls
        style={{ width: '100%', height: 250 }}
        onLoadStart={() => setBuffer(true)}
        onLoad={playVideoLoaded}
        onFullscreenUpdate={async ({ fullscreenUpdate }) => {
          if (fullscreenUpdate === VideoFullscreenUpdate.PLAYER_WILL_PRESENT) {
            await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE_LEFT);
          }
          if (fullscreenUpdate === VideoFullscreenUpdate.PLAYER_WILL_DISMISS) {
            await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT);
          }
        }}
      />
    </View>
  );
}
Example #15
Source File: VideoDemo.js    From react-native-tv-demo with MIT License 4 votes vote down vote up
VideoDemo = () => {
  let hideOverlayTimer = null;

  const navigation = useNavigation();

  // Init Refs
  const playerRef = useRef(null);
  const playPauseButtonRef = useRef(null);

  // Context
  const [appContext, setAppContext] = useContext(AppContext);

  // State
  const [source, setSource] = useState(sampleVideoSource);
  const [videoEventStack, setVideoEventStack] = useState([]);
  const [videoDuration, setVideoDuration] = useState(0);
  const [videoTime, setVideoTime] = useState(0);
  const [isReady, setIsReady] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);

  // State Refs
  const [pausedRef, isPaused, setPaused] = useStateRef(true);
  const [overlayRef, isOverlayVisible, setIsOverlayVisible] = useStateRef(true);
  const [fullscreenRef, isFullscreen, setIsFullscreen] = useStateRef(false);

  useFocusEffect(
    useCallback(() => {
      // Listen to back button
      const backHandler = BackHandler.addEventListener(
        'hardwareBackPress',
        backHandlerListener,
      );
      // Listen to TV events
      const tvEventHandler = new TVEventHandler();
      tvEventHandler.enable(null, tvEventListener);
      // Clean up
      return () => {
        // Pause playback
        if (!isPaused()) {
          setPaused(true);
        }
        // Clean timeout
        if (hideOverlayTimer) {
          clearTimeout(hideOverlayTimer);
        }
        // Remove backHandler
        backHandler.remove();
        // Remove TV event listener
        if (tvEventHandler) {
          tvEventHandler.disable();
        }
      };
    }, []),
  );

  useFocusEffect(
    useCallback(() => {
      // Prevent react navigation to handle back button is player is fullscreen
      return navigation.addListener('beforeRemove', (e) => {
        if (isFullscreen()) {
          e.preventDefault();
        }
      });
    }, []),
  );

  useEffect(() => {
    // Toggle menu
    setAppContext({menuVisible: !isFullscreen()});
  }, [fullscreenRef.current]);

  function toggleFullscreen() {
    pushVideoEventStack(isFullscreen() ? 'exitFullscreen' : 'enterFullscreen');
    // Toggle fullscreen
    setIsFullscreen(!isFullscreen());
  }

  function setOverlayVisible() {
    console.log('setOverlayVisible', isOverlayVisible());
    if (isOverlayVisible() === false) {
      setIsOverlayVisible(true);
      if (playPauseButtonRef) {
        playPauseButtonRef.current.focus();
      }
    }
    setOverlayHiddenAfterDelay();
  }

  function setOverlayHidden() {
    if (isOverlayVisible() === true && !isPaused()) {
      setIsOverlayVisible(false);
    }
  }

  function setOverlayHiddenAfterDelay() {
    console.log('setOverlayHiddenAfterDelay');
    if (hideOverlayTimer) {
      clearTimeout(hideOverlayTimer);
    }
    hideOverlayTimer = setTimeout(setOverlayHidden, 4000);
  }

  function backHandlerListener() {
    console.log('backHandleListener => got back button event');
    if (isFullscreen()) {
      toggleFullscreen();
    }
    return true;
  }

  function tvEventListener(component, event) {
    //console.log('VideoDemo.tvEventListener()', event);
    if (event.eventKeyAction === 0) {
      // Show overlay
      setOverlayVisible();
      // Toggle play / pause
      if (event.eventType === 'playPause') {
        setPaused(!isPaused());
      }
    }
  }

  // Video Events

  function pushVideoEventStack(event, params) {
    let eventStr = event + '(' + (params ? JSON.stringify(params) : '') + ')';
    console.log('Video event: ' + eventStr);
    const eventLines = isFullscreen() ? EVENT_LINES_FULLSCREEN : EVENT_LINES;
    setVideoEventStack((oldVideoEventStack) =>
      [...oldVideoEventStack, eventStr].slice(eventLines * -1),
    );
  }

  function onReadyForDisplay() {
    setIsReady(true);
    pushVideoEventStack('onReadyForDisplay');
  }

  function onLoad(data) {
    setIsLoading(false);
    setVideoDuration(data.duration);
    pushVideoEventStack('onLoad', data);
  }

  function onLoadStart(data) {
    setIsLoading(true);
    pushVideoEventStack('onLoadStart', data);
  }

  function onPlaybackRateChange(data) {
    setIsPlaying(data.playbackRate > 0);
    pushVideoEventStack('onPlaybackRateChange', data);
  }

  function onProgress(data) {
    setVideoTime(data.currentTime);
    pushVideoEventStack('onProgress', data);
  }

  function onEnd() {
    setVideoTime(0);
    setPaused(true);
    setIsPlaying(false);
    pushVideoEventStack('onEnd');
    setOverlayVisible();
  }

  function onError(error) {
    pushVideoEventStack('onError', error);
  }

  function formatTime(time) {
    let seconds = parseInt(time, 10);
    let hours = Math.floor(seconds / 3600);
    let minutes = Math.floor((seconds - hours * 3600) / 60);
    seconds = seconds - hours * 3600 - minutes * 60;
    let timeFormat = '';
    if (hours > 0) {
      if (hours < 10) {
        hours = '0' + hours;
      }
      timeFormat += hours + ':';
    }
    if (minutes < 10) {
      minutes = '0' + minutes;
    }
    if (seconds < 10) {
      seconds = '0' + seconds;
    }
    // Fix NaN
    if (isNaN(minutes)) {
      minutes = '-';
    }
    if (isNaN(seconds)) {
      seconds = '-';
    }
    timeFormat += minutes + ':' + seconds;
    return timeFormat;
  }

  return (
    <View style={[Style.styles.right, isFullscreen() && styles.fullscreen]}>
      {!isFullscreen() && (
        <View style={Style.styles.header}>
          <Text style={Style.styles.headerText}>{'Video Demo'}</Text>
        </View>
      )}
      <View style={[Style.styles.content, isFullscreen() && styles.fullscreen]}>
        <View
          style={
            isFullscreen()
              ? styles.videoContainerFullscreen
              : styles.videoContainer
          }>
          <VideoContainer
            ref={playerRef}
            source={source}
            paused={isPaused()}
            onReadyForDisplay={onReadyForDisplay}
            onLoadStart={onLoadStart}
            onLoad={onLoad}
            onPlaybackRateChange={onPlaybackRateChange}
            onProgress={onProgress}
            onEnd={onEnd}
            onError={onError}
          />
          <View
            style={
              isOverlayVisible()
                ? styles.videoOverlayVisible
                : styles.videoOverlayHidden
            }>
            <View style={styles.videoOverlayBackground} />
            <View style={styles.videoEvents}>
              <Text style={styles.videoEventsText}>
                {'Video Events:\n' + videoEventStack.join('\n')}
              </Text>
            </View>
            <VideoProgressBar
              duration={videoDuration}
              time={videoTime}
              style={styles.progressBar}
              seek={(seconds) => {
                playerRef.current.seek(seconds);
              }}
            />
            <View style={styles.videoControls}>
              <FocusableHighlight
                nativeID={'play_pause_button'}
                ref={playPauseButtonRef}
                onPress={(e) => {
                  if (e.eventKeyAction === 0 && e.eventType === 'select') {
                    setPaused(!isPaused());
                  }
                }}
                style={styles.videoControl}
                hasTVPreferredFocus={true}
                underlayColor={Style.buttonFocusedColor}>
                <Text style={styles.videoControlText}>
                  {isPaused() ? 'Play' : 'Pause'}
                </Text>
              </FocusableHighlight>
              <FocusableHighlight
                nativeID={'fullscreen_button'}
                onPress={(e) => {
                  if (e.eventKeyAction === 0 && e.eventType === 'select') {
                    toggleFullscreen();
                  }
                }}
                style={styles.videoControl}
                underlayColor={Style.buttonFocusedColor}>
                <Text style={styles.videoControlText}>
                  {isFullscreen() ? 'Exit Fullscreen' : 'Enter Fullscreen'}
                </Text>
              </FocusableHighlight>
              <View style={styles.videoTime}>
                <Text style={styles.videoTimeText}>
                  {formatTime(videoTime) + ' / ' + formatTime(videoDuration)}
                </Text>
              </View>
            </View>
          </View>
        </View>
      </View>
    </View>
  );
}
Example #16
Source File: EventsDemo.js    From react-native-tv-demo with MIT License 4 votes vote down vote up
EventsDemo = () => {
  const [tvEventStack, setTvEventStack] = useState([]);
  const [componentEventStack, setComponentEventStack] = useState([]);

  useFocusEffect(
    useCallback(() => {
      // Listen to back button
      const backHandler = BackHandler.addEventListener(
        'hardwareBackPress',
        backEventListener,
      );
      // Enabled TVEventHandler
      const tvEventHandler = new TVEventHandler();
      tvEventHandler.enable(null, tvEventListener);
      // Clean up
      return () => {
        // Remove BackHandler
        backHandler.remove();
        // Disable TVEventHandler
        tvEventHandler.disable();
      };
    }, []),
  );

  function backEventListener(event) {
    // Just add some logs here as navigation will change screen
    console.log('backEventListener received hardwareBackPress event');
    console.log(JSON.stringify(event));
  }

  function tvEventListener(component, event) {
    //console.log('tvEventListener:', event.eventType);
    setTvEventStack((oldTvEventStack) =>
      [...oldTvEventStack, JSON.stringify(event)].slice(EVENT_LINES * -1),
    );
  }

  function componentEventListener(event) {
    if (!event.eventType) {
      return;
    }
    //console.log('componentEventListener:', event.eventType);
    setComponentEventStack((oldComponentEventStack) =>
      [...oldComponentEventStack, JSON.stringify(event)].slice(
        EVENT_LINES * -1,
      ),
    );
  }

  return (
    <View style={Style.styles.right}>
      <View style={Style.styles.header}>
        <Text style={Style.styles.headerText}>{'Events Demo'}</Text>
      </View>
      <View style={Style.styles.content}>
        <View style={styles.buttons}>
          <FocusableHighlight
            nativeID={'events_left_button'}
            onPress={componentEventListener}
            onFocus={componentEventListener}
            onBlur={componentEventListener}
            style={styles.button}
            underlayColor={Style.buttonFocusedColor}>
            <Text style={styles.buttonText}>{'Left Button'}</Text>
          </FocusableHighlight>
          <FocusableHighlight
            nativeID={'events_middle_button'}
            onPress={componentEventListener}
            onFocus={componentEventListener}
            onBlur={componentEventListener}
            style={styles.button}
            hasTVPreferredFocus={true}
            underlayColor={Style.buttonFocusedColor}>
            <Text style={styles.buttonText}>{'Middle Button'}</Text>
          </FocusableHighlight>
          <FocusableHighlight
            nativeID={'events_right_button'}
            onPress={componentEventListener}
            onFocus={componentEventListener}
            onBlur={componentEventListener}
            style={styles.button}
            underlayColor={Style.buttonFocusedColor}>
            <Text style={styles.buttonText}>{'Right Button'}</Text>
          </FocusableHighlight>
        </View>
        <Text style={[styles.eventHeader, styles.tvEventHeader]}>
          TVEventHandler events
        </Text>
        <Text style={styles.eventType} numberOfLines={EventsDemo.EVENT_LINES}>
          {tvEventStack.join('\n')}
        </Text>
        <Text style={styles.eventHeader}>TouchableHighlight events</Text>
        <Text style={styles.eventType} numberOfLines={EventsDemo.EVENT_LINES}>
          {componentEventStack.join('\n')}
        </Text>
      </View>
    </View>
  );
}
Example #17
Source File: StatusView.js    From WhatsApp-Clone with MIT License 4 votes vote down vote up
StatusView = ({navigation}) => {
  var [state, dispatch] = useReducer(statusReducer, statusState);

  var {statusData, recentStatusList, viewedStatusList, refresh} = state;

  useFocusEffect(
    React.useCallback(() => {
      getUserStatusFromAPI(dispatch);
    }, []),
  );

  useEffect(() => {
    listenSocket();

    // return () => {
    //   alert('STATUS DISCONNECTED');
    //   socket.removeListener(constants.USER_STATUS);
    // };
  }, []);

  function listenSocket() {
    // socket.removeListener(constants.CHAT_LIST);
    socket.on(constants.USER_STATUS, async statusModel => {
      const id = await getLocalData(constants.USER_ID);
      if (statusModel.userId != id) {
        console.log('STATUS RECEIVED');
        getUserStatusFromAPI(dispatch);
      }
    });
  }

  return (
    <Container>
      <ScrollView nestedScrollEnabled style={{flex: 1, paddingBottom: 200}}>
        <View>
          <MyStatusView
            navigation={navigation}
            statusData={statusData}
            isUser 
            isBorder={false}
          />
          {recentStatusList.length > 0 && (
            <View>
              <_Divider style={{borderBottomWidth: 5}} />
              <Text style={[DEFAULT_STYLES.poppinsSemiBold, styles.userTime]}>
                RECENT UPDATES
              </Text>
              <RecentStatusView
                navigation={navigation}
                statusData={recentStatusList}
              />
            </View>
          )}
          {viewedStatusList.length > 0 && (
            <View>
              <_Divider style={{borderBottomWidth: 5}} />
              <Text style={[DEFAULT_STYLES.poppinsSemiBold, styles.userTime]}>
                VIEWED UPDATES
              </Text>
              <ViewedStatusView
                navigation={navigation}
                statusData={viewedStatusList}
              />
            </View>
          )}
        </View>
      </ScrollView>

      <View
        style={{
          flexDirection: 'column',
          position: 'absolute',
          bottom: 20,
          right: 20,
        }}>
        <Button
          rounded
          style={{
            backgroundColor: APP_BG_COLOR,
            width: 50,
            alignSelf: 'center',
            height: 50,
          }}>
          <Icon
            style={{color: TEXT_SUBTITLE, fontSize: 22}}
            name="pencil"
            type="MaterialCommunityIcons"
          />
        </Button>
        <Button
          rounded
          color={GREEN}
          style={styles.btnView}
          onPress={() => {
            navigation.navigate(NAV_TYPES.CAMERA_VIEW, {});
          }}>
          <Thumbnail circular source={ADD_STATUS} style={styles.thumbView} />
        </Button>
      </View>

      {/* <Fab
        active={true}
        direction="up"
        style={{backgroundColor: '#5067FF', position: 'absolute'}}
        position="bottomRight">
        <Thumbnail source={ADD_STATUS} />
        <Button style={{backgroundColor: '#EEF5F6'}}>
          <Icon
            style={{color: TEXT_SUBTITLE, fontSize: 24}}
            name="pencil"
            type="MaterialCommunityIcons"
          />
        </Button>
      </Fab> */}
    </Container>
  );
}
Example #18
Source File: daySurvey.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
DaySurvey = ({ navigation, route }) => {
  const [diaryData, setDiaryData] = useContext(DiaryDataContext);

  const [questions, setQuestions] = useState([]);
  const [answers, setAnswers] = useState({});
  const questionToxic = {
    id: "TOXIC",
    label: "Avez-vous consommé des substances aujourd'hui ?",
  };
  const questionContext = {
    id: "CONTEXT",
    label: "Ajoutez une note générale sur votre journée",
  };

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const q = await buildSurveyData();
        if (q) {
          setQuestions(q);
        }
      })();
    }, [])
  );

  useEffect(() => {
    //init the survey if there is already answers
    Object.keys(route?.params?.currentSurvey?.answers || {})?.forEach((key) => {
      const score = getScoreWithState({
        patientState: route?.params?.currentSurvey?.answers,
        category: key,
      });
      const cleanedQuestionId = key.split("_")[0];
      if (questions.find((q) => q.id === cleanedQuestionId)) {
        toggleAnswer({ key: cleanedQuestionId, value: score });
        handleChangeUserComment({
          key: cleanedQuestionId,
          userComment: route?.params?.currentSurvey?.answers[cleanedQuestionId]?.userComment,
        });
      }
    });
    if ((route?.params?.currentSurvey?.answers || {})[questionToxic.id]) {
      toggleAnswer({
        key: questionToxic.id,
        value: route?.params?.currentSurvey?.answers[questionToxic?.id]?.value,
      });
      handleChangeUserComment({
        key: questionToxic.id,
        userComment: route?.params?.currentSurvey?.answers[questionToxic?.id]?.userComment,
      });
    }
    if ((route?.params?.currentSurvey?.answers || {})[questionContext.id]) {
      handleChangeUserComment({
        key: questionContext.id,
        userComment: route?.params?.currentSurvey?.answers[questionContext?.id]?.userComment,
      });
    }
  }, [route?.params?.currentSurvey?.answers, questions, questionToxic.id, questionContext?.id]);

  const toggleAnswer = async ({ key, value }) => {
    setAnswers((prev) => {
      return {
        ...prev,
        [key]: { ...prev[key], value },
      };
    });
  };

  const handleChangeUserComment = ({ key, userComment }) => {
    setAnswers((prev) => {
      return {
        ...prev,
        [key]: { ...prev[key], userComment },
      };
    });
  };

  const submitDay = async ({ redirectBack = false }) => {
    const prevCurrentSurvey = route.params?.currentSurvey;
    const currentSurvey = {
      date: prevCurrentSurvey?.date,
      answers: { ...prevCurrentSurvey.answers, ...answers },
    };
    setDiaryData(currentSurvey);
    logEvents.logFeelingAdd();
    logEvents.logFeelingAddComment(
      Object.keys(answers).filter(
        (key) => ![questionToxic.id, questionContext.id].includes(key) && answers[key].userComment
      )?.length
    );
    logEvents.logFeelingAddContext(answers[questionContext.id]?.userComment ? 1 : 0);
    logEvents.logFeelingResponseToxic(answers[questionToxic.id]?.value ? 1 : 0);

    if (route.params?.redirect) {
      alertNoDataYesterday({
        date: prevCurrentSurvey?.date,
        diaryData,
        navigation,
      });
      return navigation.navigate("tabs");
    }

    if (redirectBack) {
      return navigation.goBack();
    }

    const medicalTreatmentStorage = await localStorage.getMedicalTreatment();
    if (medicalTreatmentStorage?.length === 0) {
      alertNoDataYesterday({
        date: prevCurrentSurvey?.date,
        diaryData,
        navigation,
      });
      return navigation.navigate("tabs");
    }

    navigation.navigate("drugs", {
      currentSurvey,
      editingSurvey: route.params?.editingSurvey,
    });
  };

  const renderQuestion = () => {
    if (isYesterday(parseISO(route.params?.currentSurvey?.date)))
      return "Comment s'est passée la journée d'hier ?";
    if (isToday(parseISO(route.params?.currentSurvey?.date))) return "Comment s'est passée votre journée ?";
    let relativeDate = formatRelativeDate(route.params?.currentSurvey?.date);
    relativeDate = `le ${relativeDate}`;
    return `Comment s'est passé ${relativeDate} ?`;
  };

  return (
    <SafeAreaView style={styles.safe}>
      <BackButton onPress={() => submitDay({ redirectBack: true })} />
      <KeyboardAvoidingView behavior={Platform.OS === "ios" ? "position" : "height"} style={{ flex: 1 }}>
        <ScrollView
          style={styles.container}
          keyboardDismissMode="on-drag"
          onScrollBeginDrag={Keyboard.dismiss}
        >
          <TouchableOpacity
            onPress={() => {
              navigation.navigate("symptoms");
              logEvents.logSettingsSymptomsFromSurvey();
            }}
          >
            <View style={styles.linkContainer}>
              <Text style={styles.link}>Ajouter ou retirer des indicateurs de mon questionnaire</Text>
              <View style={styles.linkButtonContainer}>
                <ArrowUpSvg color="#fff" />
              </View>
            </View>
          </TouchableOpacity>
          <Text style={styles.question}>{renderQuestion()}</Text>
          {questions.map((q, i) => (
            <Question
              key={i}
              question={q}
              onPress={toggleAnswer}
              selected={answers[q.id]?.value}
              explanation={q.explanation}
              onChangeUserComment={handleChangeUserComment}
              userComment={answers[q.id]?.userComment}
            />
          ))}
          <InputQuestion
            question={questionContext}
            onPress={toggleAnswer}
            selected={answers[questionContext.id]?.value}
            explanation={questionContext.explanation}
            onChangeUserComment={handleChangeUserComment}
            userComment={answers[questionContext.id]?.userComment}
            placeholder="Contexte, évènements, comportement de l’entourage..."
          />
          <QuestionYesNo
            question={questionToxic}
            onPress={toggleAnswer}
            selected={answers[questionToxic.id]?.value}
            explanation={questionToxic.explanation}
            isLast
            onChangeUserComment={handleChangeUserComment}
            userComment={answers[questionToxic.id]?.userComment}
          />
          <View style={styles.divider} />
          <View style={styles.buttonWrapper}>
            <Button onPress={submitDay} title="Valider" />
          </View>
          <Text style={styles.subtitle}>
            Retrouvez toutes vos notes dans l'onglet &quot;Mon&nbsp;journal&quot;
          </Text>
        </ScrollView>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}
Example #19
Source File: index.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
Suivi = ({ navigation, setPlusVisible, startSurvey }) => {
  const [chartType, setChartType] = React.useState("Frises");
  const [fromDate, setFromDate] = React.useState(beforeToday(30));
  const [toDate, setToDate] = React.useState(beforeToday(0));
  const [focusedScores, setFocusedScores] = React.useState([1, 2, 3, 4, 5]);
  const [showTraitement, setShowTraitement] = React.useState(true);
  const [aUnTraiement, setAUnTraitement] = React.useState(false);
  const [showHint, setShowHint] = React.useState(false);

  useFocusEffect(
    React.useCallback(() => {
      logEvents.logOpenPageSuivi(chartType);
    }, [chartType])
  );
  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const medicalTreatmentStorage = await localStorage.getMedicalTreatment();
        if (medicalTreatmentStorage.length === 0) {
          setAUnTraitement(false);
          setShowTraitement(false);
        } else {
          setAUnTraitement(true);
        }
      })();
    }, [])
  );

  if (!toDate || !fromDate) return null;

  const renderChart = (chart) => {
    switch (chart) {
      case "Statistiques":
        return <ChartPie fromDate={fromDate} toDate={toDate} navigation={navigation} />;
      case "Courbes":
        return <Courbes navigation={navigation} />;
      case "Déclencheurs":
        return <Evenements navigation={navigation} fromDate={fromDate} toDate={toDate} />;
      case "Frises":
      default:
        return (
          <ChartFrise
            navigation={navigation}
            fromDate={fromDate}
            toDate={toDate}
            focusedScores={focusedScores}
            showTraitement={showTraitement}
            showHint={showHint}
            onCloseHint={() => {
              setShowHint(false);
              logEvents.logSuiviShowLegendeInformationPriseDeTraitement(0); // 0 = masquer, 1 = afficher
            }}
            setShowHint={setShowHint}
            aUnTraiement={aUnTraiement}
            setShowTraitement={setShowTraitement}
          />
        );
    }
  };

  return (
    <>
      <SafeAreaView style={styles.safe}>
        <View style={styles.headerContainerNavigation}>
          <Header title="Mes analyses" navigation={navigation} />
        </View>
        <View style={styles.headerContainer}>
          <ChartPicker
            // onAfterPress={() => setChartType(nextChartType(chartType))}
            // onBeforePress={() => setChartType(prevChartType(chartType))}
            // title={chartType}
            onChange={(e) => setChartType(e)}
            ongletActif={chartType}
          />
          {chartType !== "Courbes" ? (
            <RangeDate
              fromDate={fromDate}
              toDate={toDate}
              onChangeFromDate={setFromDate}
              onChangeToDate={setToDate}
            />
          ) : null}
          {chartType === "Frises" ? (
            <View style={styles.containerScorePickerFrise}>
              <ScorePicker
                focusedScores={focusedScores}
                onPress={(i) => {
                  if (focusedScores.includes(i)) {
                    setFocusedScores((e) => e.filter((x) => x !== i));
                  } else {
                    setFocusedScores((e) => [...e, i]);
                  }
                  //events
                  logEvents.logSuiviEditScoreFrise(i);
                }}
              />
              <View style={styles.verticalDivider} />
              <View style={styles.hintContainer}>
                <TouchableOpacity
                  onPress={() => {
                    if (aUnTraiement) {
                      setShowTraitement((e) => !e);
                      logEvents.logSuiviShowPriseDeTraitement(showTraitement ? 0 : 1); // 0 = masquer, 1 = afficher
                    } else {
                      setShowHint((e) => !e);
                    }
                  }}
                >
                  <View
                    style={[
                      styles.selectionContainer,
                      !aUnTraiement && styles.noTraitementSelectionContainer,
                      showTraitement && styles.activeSelectionContainer,
                    ]}
                  >
                    <Icon
                      icon="DrugsSvg"
                      color={!aUnTraiement || showTraitement ? "#FFFFFF" : "#58C8D2"}
                      width={20}
                      height={20}
                      styleContainer={styles.icon}
                    />
                  </View>
                </TouchableOpacity>
                <TouchableOpacity
                  onPress={async () => {
                    await AsyncStorage.setItem("@AT_LEAST_VIEW_ONE_TIME_HINT_FRISE", "true");
                    setShowHint((e) => !e);
                    logEvents.logSuiviShowLegendeInformationPriseDeTraitement(showHint ? 0 : 1); // 0 = masquer, 1 = afficher
                  }}
                >
                  <View style={[styles.infoHintContainer, showHint && styles.activeInfoHintContainer]}>
                    <Text style={[styles.infoHintText, showHint && styles.activeInfoHintText]}>i</Text>
                  </View>
                </TouchableOpacity>
              </View>
            </View>
          ) : null}
        </View>
        {renderChart(chartType)}
      </SafeAreaView>
      <FloatingPlusButton shadow onPress={startSurvey} plusPosition={0} />
    </>
  );
}
Example #20
Source File: index.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
Events = ({ navigation, fromDate, toDate, focusedScores }) => {
  const [diaryData] = React.useContext(DiaryDataContext);
  const [activeCategories, setActiveCategories] = React.useState();
  const [isEmpty, setIsEmpty] = React.useState();
  const chartDates = getArrayOfDatesFromTo({ fromDate, toDate });
  const [symptom, setSymptom] = React.useState("ANXIETY");
  const [event, setEvent] = React.useState("ALL");
  const [score, setScore] = React.useState([5]);

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const q = await buildSurveyData();
        if (q) {
          setActiveCategories(q.map((e) => e.id));
          setSymptom(q[0].id);
        }
      })();
    }, [])
  );

  // React.useEffect(() => {
  //   console.log("✍️ ~ symptom", symptom);
  // }, [symptom]);

  const memoizedCallback = React.useCallback(() => {
    if (!symptom) return [];
    // console.log("SYMPTOME", symptom);
    if (!score || !score.length) return [];
    const targetScore = score[0];
    // console.log("score", score);
    if (!event) return [];
    // console.log("event", event);
    return chartDates.map((date) => {
      let infoDate = { date };
      // console.log("✍️ ~ date", date);
      const dayData = diaryData[date];
      if (!dayData) {
        // console.log("no dayData");
        return {};
      }
      const categoryState = diaryData[date][symptom];
      // console.log("✍️ ~ categoryState", categoryState);
      if (!categoryState) {
        // console.log("categoryState");
        return {};
      }
      if (diaryData[date][symptom]?.value !== targetScore) {
        return {};
      }

      // { label: "Tous les évènement", value: "ALL" },
      // { label: "Contexte de la journée", value: "CONTEXT" },
      // { label: "Précisions élément", value: "USER_COMMENT" },
      // { label: "Traitements", value: "POSOLOGY" },
      // { label: "Substances", value: "TOXIC" },

      if (dayData?.CONTEXT?.userComment) infoDate = { ...infoDate, CONTEXT: dayData?.CONTEXT?.userComment };
      if (categoryState?.userComment) infoDate = { ...infoDate, USER_COMMENT: categoryState?.userComment };

      // console.log("✍️ ~ infoDate", infoDate);

      return infoDate;

      // -------
      // the following code is for the retrocompatibility
      // -------

      // get the name and the suffix of the category
      // const [categoryName, suffix] = symptom.split("_");
      // let categoryStateIntensity = null;
      // if (suffix && suffix === "FREQUENCE") {
      //   // if it's one category with the suffix 'FREQUENCE' :
      //   // add the intensity (default level is 3 - for the frequence 'never')
      //   categoryStateIntensity = diaryData[date][`${categoryName}_INTENSITY`] || { level: 3 };
      //   return { value: categoryState.level + categoryStateIntensity.level - 2 };
      // }
      // return { value: categoryState.level - 1 };
    });
  }, [symptom, score, event, chartDates, diaryData]);

  const startSurvey = async () => {
    const symptoms = await localStorage.getSymptoms();
    logEvents.logFeelingStart();
    if (!symptoms) {
      navigation.navigate("symptoms", {
        showExplanation: true,
        redirect: "select-day",
      });
    } else {
      navigation.navigate("select-day");
    }
  };

  const renderDate = (d) => {
    if (isYesterday(parseISO(d))) return "hier";
    if (isToday(parseISO(d))) return "aujourd'hui";
    let relativeDate = formatRelativeDate(d);
    return `le ${relativeDate}`;
  };

  if (isEmpty) {
    return (
      <View style={styles.emptyContainer}>
        <View style={styles.subtitleContainer}>
          <Icon icon="InfoSvg" width={25} height={25} color={colors.LIGHT_BLUE} />
          <Text style={styles.subtitle}>
            Des <Text style={styles.bold}>Évènements</Text> apparaîtront au fur et à mesure de vos saisies
            quotidiennes.
          </Text>
        </View>
        <Button title="Commencer à saisir" onPress={startSurvey} />
      </View>
    );
  }
  return (
    <>
      <View style={styles.filterContainer}>
        <View style={styles.filterItemContainer}>
          <Text style={styles.text}>Afficher tous les évènements associés à</Text>
          {/* <SelectEvent
            options={activeCategories}
            onChange={setEvent}
            placeholder="Choisir évènement"
            value={event}
          /> */}
        </View>
        <View style={styles.filterItemContainer}>
          {/* <Text>associé(s)&nbsp;à</Text> */}
          <SelectSymptom
            options={activeCategories}
            onChange={setSymptom}
            onOpen={logEvents.logSuiviEditSymptom}
            placeholder="Sélectionner un élément"
            value={symptom}
          />
        </View>
        <View style={styles.containerScorePickerFrise}>
          <ScorePicker
            focusedScores={score}
            onPress={(i) => {
              setScore([i]);
              logEvents.logSuiviEditScoreEvents(i);
            }}
          />
        </View>
      </View>
      <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
        {memoizedCallback()?.filter((x) => x.date)?.length === 0 && (
          <Text style={styles.noDataMessage}>
            Aucun évènement à afficher entre {renderDate(formatDay(fromDate))} et{" "}
            {renderDate(formatDay(toDate))}.
          </Text>
        )}
        {memoizedCallback()
          ?.filter((x) => x.date)
          ?.sort((a, b) => {
            const ad = a.date.split("/").reverse().join("");
            const bd = b.date.split("/").reverse().join("");
            return bd.localeCompare(ad);
          })
          ?.map((d) => {
            return (
              <Card
                key={d.date}
                event={event}
                date={d.date}
                context={d.CONTEXT}
                userComment={d.USER_COMMENT}
              />
            );
          })}
      </ScrollView>
    </>
  );
}
Example #21
Source File: chartPie.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
ChartPie = ({ navigation, fromDate, toDate }) => {
  const [diaryData] = React.useContext(DiaryDataContext);
  const [activeCategories, setActiveCategories] = React.useState([]);
  const [chartDates, setChartDates] = React.useState([]);
  const [isEmpty, setIsEmpty] = React.useState();

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const q = await buildSurveyData();
        if (q) {
          setActiveCategories(q.map((e) => e.id));
        }
      })();
    }, [])
  );

  React.useEffect(() => {
    if (!fromDate || !toDate) return;
    setChartDates(getArrayOfDatesFromTo({ fromDate, toDate }));
  }, [fromDate, toDate]);

  React.useEffect(() => {
    if (!activeCategories || activeCategories.length === 0) return;
    const empty = !activeCategories.reduce((showing, categoryId) => {
      return Boolean(isChartVisible(categoryId)) || showing;
    }, false);
    setIsEmpty(empty);
  }, [activeCategories, isChartVisible]);

  const isChartVisible = React.useCallback(
    (categoryId) => {
      let visible = false;
      chartDates.forEach((date) => {
        if (!diaryData[date]) {
          return;
        }
        if (!diaryData[date][categoryId]) {
          return;
        }
        visible = true;
      });
      return visible;
    },
    [diaryData, chartDates]
  );

  const startSurvey = async () => {
    const symptoms = await localStorage.getSymptoms();
    logEvents.logFeelingStart();
    if (!symptoms) {
      navigation.navigate("symptoms", {
        showExplanation: true,
        redirect: "select-day",
      });
    } else {
      navigation.navigate("select-day");
    }
  };

  const getTitle = (cat) => {
    const category = displayedCategories[cat] || cat;
    const [categoryName, suffix] = category.split("_");
    if (suffix && suffix === "FREQUENCE") {
      return categoryName;
    }
    return category;
  };

  const computeChartData = (categoryId) => {
    return chartDates.map((date) => {
      const dayData = diaryData[date];
      if (!dayData) {
        return 0;
      }
      const categoryState = diaryData[date][categoryId];
      if (!categoryState) {
        return 0;
      }
      if (categoryState?.value) return categoryState.value;
      if (categoryState?.value === false) return categoryState.value;

      // -------
      // the following code is for the retrocompatibility
      // -------

      // get the name and the suffix of the category
      const [categoryName, suffix] = categoryId.split("_");
      let categoryStateIntensity = null;
      if (suffix && suffix === "FREQUENCE") {
        // if it's one category with the suffix 'FREQUENCE' :
        // add the intensity (default level is 3 - for the frequence 'never')
        categoryStateIntensity = diaryData[date][`${categoryName}_INTENSITY`] || { level: 3 };
        return categoryState.level + categoryStateIntensity.level - 2;
      }
      return categoryState.level - 1;
    });
  };

  if (isEmpty) {
    return (
      <View style={styles.emptyContainer}>
        <View style={styles.subtitleContainer}>
          <Icon icon="InfoSvg" width={25} height={25} color={colors.LIGHT_BLUE} />
          <Text style={styles.subtitle}>
            Des <Text style={styles.bold}>statistiques</Text> apparaîtront au fur et à mesure de vos saisies
            quotidiennes.
          </Text>
        </View>
        <Button title="Commencer à saisir" onPress={startSurvey} />
      </View>
    );
  }

  return (
    <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
      {activeCategories?.map((categoryId) => (
        <Pie
          title={getTitle(categoryId)}
          key={categoryId}
          data={computeChartData(categoryId)}
          fromDate={fromDate}
          toDate={toDate}
        />
      ))}
      <View style={styles.divider} />
      <PieYesNo
        title="Ai-je pris correctement mon traitement quotidien ?"
        data={computeChartData("PRISE_DE_TRAITEMENT")}
      />
      <PieYesNo
        title='Ai-je pris un "si besoin" ?'
        data={computeChartData("PRISE_DE_TRAITEMENT_SI_BESOIN")}
      />
    </ScrollView>
  );
}
Example #22
Source File: chartFrise.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
ChartFrise = ({
  navigation,
  fromDate,
  toDate,
  focusedScores,
  showTraitement,
  showHint,
  onCloseHint,
  aUnTraiement,
  setShowHint,
  setShowTraitement,
}) => {
  const [diaryData] = React.useContext(DiaryDataContext);
  const [activeCategories, setActiveCategories] = React.useState();
  const [isEmpty, setIsEmpty] = React.useState();
  const chartDates = getArrayOfDatesFromTo({ fromDate, toDate });

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const q = await buildSurveyData();
        if (q) {
          setActiveCategories(q.map((e) => e.id));
        }
      })();
    }, [])
  );

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const viewHint = await AsyncStorage.getItem("@AT_LEAST_VIEW_ONE_TIME_HINT_FRISE");
        if (viewHint !== "true") {
          setShowHint(true);
          setShowTraitement(true);
        } else {
          setShowHint(false);
        }
      })();
    }, [setShowHint, setShowTraitement])
  );

  React.useEffect(() => {
    if (!activeCategories) return;
    const empty = !activeCategories.reduce((showing, categoryId) => {
      return Boolean(isChartVisible(categoryId)) || showing;
    }, false);
    setIsEmpty(empty);
  }, [activeCategories, isChartVisible]);

  const isChartVisible = React.useCallback(
    (categoryId) => {
      let visible = false;
      chartDates.forEach((date) => {
        if (!diaryData[date]) {
          return;
        }
        if (!diaryData[date][categoryId]) {
          return;
        }
        visible = true;
      });
      return visible;
    },
    [diaryData, chartDates]
  );

  const startSurvey = async () => {
    const symptoms = await localStorage.getSymptoms();
    logEvents.logFeelingStart();
    if (!symptoms) {
      navigation.navigate("symptoms", {
        showExplanation: true,
        redirect: "select-day",
      });
    } else {
      navigation.navigate("select-day");
    }
  };

  const getTitle = (cat) => {
    const category = displayedCategories[cat] || cat;
    const [categoryName, suffix] = category.split("_");
    if (suffix && suffix === "FREQUENCE") {
      return categoryName;
    }
    return category;
  };

  const computeChartData = (categoryId) => {
    return chartDates.map((date) => {
      const dayData = diaryData[date];
      if (!dayData) {
        return {};
      }
      const categoryState = diaryData[date][categoryId];
      if (!categoryState) {
        return {};
      }
      if (categoryState?.value !== null || categoryState?.value !== undefined) return categoryState;

      // -------
      // the following code is for the retrocompatibility
      // -------

      // get the name and the suffix of the category
      const [categoryName, suffix] = categoryId.split("_");
      let categoryStateIntensity = null;
      if (suffix && suffix === "FREQUENCE") {
        // if it's one category with the suffix 'FREQUENCE' :
        // add the intensity (default level is 3 - for the frequence 'never')
        categoryStateIntensity = diaryData[date][`${categoryName}_INTENSITY`] || { level: 3 };
        return { value: categoryState.level + categoryStateIntensity.level - 2 };
      }
      return { value: categoryState.level - 1 };
    });
  };

  if (isEmpty) {
    return (
      <View style={styles.emptyContainer}>
        <View style={styles.subtitleContainer}>
          <Icon icon="InfoSvg" width={25} height={25} color={colors.LIGHT_BLUE} />
          <Text style={styles.subtitle}>
            Des <Text style={styles.bold}>frises</Text> apparaîtront au fur et à mesure de vos saisies
            quotidiennes.
          </Text>
        </View>
        <Button title="Commencer à saisir" onPress={startSurvey} />
      </View>
    );
  }

  return (
    <>
      {showHint ? (
        <View style={styles.mainHintContainer}>
          <View style={styles.hintTriangleContainer}>
            <TriangleWithBorderTop
              style={styles.triangle}
              borderColor="#AEEDF8"
              strokeWidth={6}
              width={20}
              height={20}
            />
          </View>
          <View style={styles.hintContainer}>
            <View style={styles.hintTitleContainer}>
              <Text style={styles.hintTitle}>Corrélez la prise de votre traitement avec vos frises</Text>
              <TouchableOpacity
                style={styles.close}
                onPress={async () => {
                  await AsyncStorage.setItem("@AT_LEAST_VIEW_ONE_TIME_HINT_FRISE", "true");
                  onCloseHint();
                }}
              >
                <Icon icon="CrossSvg" width={15} height={15} color={colors.BLUE} />
              </TouchableOpacity>
            </View>
            <Frise
              focusedScores={[]}
              data={[
                { value: 1 },
                { value: 2 },
                { value: 3 },
                { value: 1 },
                { value: 3 },
                { value: 1 },
                { value: 4 },
                { value: 5 },
                { value: 5 },
                { value: 4 },
                { value: 4 },
                { value: 3 },
                { value: 4 },
                { value: 4 },
              ]}
              showTraitement
              priseDeTraitement={[
                {},
                { value: false },
                {},
                { value: true },
                { value: true },
                { value: true },
                { value: true },
                { value: true },
                { value: true },
                { value: true },
                { value: true },
                {},
                { value: false },
                {},
              ]}
              priseDeTraitementSiBesoin={[
                {},
                { value: false },
                {},
                { value: false },
                { value: false },
                { value: true },
                { value: true },
                { value: false },
                { value: false },
                { value: true },
                { value: true },
                {},
                { value: false },
                {},
              ]}
            />
            <View>
              <View
                style={{ display: "flex", flexDirection: "row", alignItems: "center", marginVertical: 5 }}
              >
                <View style={[styles.hintSquare, { backgroundColor: "#5956E8", marginRight: 15 }]} />
                <Text style={styles.hintLegend}>Prise correcte du traitement</Text>
              </View>
              <View
                style={{ display: "flex", flexDirection: "row", alignItems: "center", marginVertical: 5 }}
              >
                <View style={[styles.hintSquare, { backgroundColor: "#E575F8", marginRight: 15 }]} />
                <Text style={styles.hintLegend}>Prise incomplète/oubli du traitement</Text>
              </View>
              <View
                style={{ display: "flex", flexDirection: "row", alignItems: "center", marginVertical: 5 }}
              >
                <View
                  style={[
                    {
                      height: 4,
                      width: 4,
                      borderRadius: 2,
                      backgroundColor: "#5956E8",
                      marginRight: 21,
                      marginLeft: 5,
                    },
                  ]}
                />
                <Text style={styles.hintLegend}>Prise dun "si besoin"</Text>
              </View>
              {!aUnTraiement ? (
                <View>
                  <TouchableOpacity style={styles.button} onPress={() => navigation.navigate("drugs")}>
                    <View style={styles.buttonPlusContainer}>
                      <Plus opacity={1} color="white" width={19} height={19} />
                    </View>
                    <Text style={styles.textAjouter}>Ajouter votre traitement</Text>
                  </TouchableOpacity>
                </View>
              ) : null}
            </View>
          </View>
        </View>
      ) : null}
      <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
        {activeCategories?.map((categoryId) => (
          <Frise
            focusedScores={focusedScores}
            title={getTitle(categoryId)}
            key={categoryId}
            data={computeChartData(categoryId)}
            showTraitement={showTraitement}
            priseDeTraitement={computeChartData("PRISE_DE_TRAITEMENT")}
            priseDeTraitementSiBesoin={computeChartData("PRISE_DE_TRAITEMENT_SI_BESOIN")}
          />
        ))}
      </ScrollView>
    </>
  );
}
Example #23
Source File: recapCompletion.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
RecapCompletion = ({ navigation }) => {
  const [diaryData] = React.useContext(DiaryDataContext);
  const [startDay, setStartDay] = React.useState(new Date(Date.now()));

  const startSurvey = (offset) => {
    logEvents.logFeelingStartFromRecap(offset);
    const date = formatDay(beforeToday(offset));

    const blackListKeys = ["becks", "NOTES"];
    const filtered = Object.keys(diaryData[date] || [])
      .filter((key) => !blackListKeys.includes(key))
      .reduce((obj, key) => {
        obj[key] = diaryData[date][key];
        return obj;
      }, {});

    const dayIsDone = Object.keys(filtered).length !== 0;

    const answers = diaryData[date] || {};
    const currentSurvey = { date, answers };
    return navigation.navigate("day-survey", {
      currentSurvey,
      editingSurvey: dayIsDone,
    });
  };

  useFocusEffect(
    React.useCallback(() => {
      setStartDay(new Date(Date.now()));
    }, [])
  );

  return (
    <View style={styles.safe}>
      <Text style={[styles.title, styles.separatorBottom]}>
        Complétez les 7 derniers jours pour un meilleur suivi
      </Text>
      <View style={styles.fil} />
      <View style={styles.buttonsContainer}>
        {[...Array(7)].map((_, i) => {
          const value = formatDay(subDays(startDay, i));
          let label = firstLetterUppercase(getFirst3LetterWeekDay(value));
          const blackListKeys = ["becks", "NOTES"];
          const filtered = Object.keys(diaryData[value] || [])
            .filter((key) => !blackListKeys.includes(key))
            .reduce((obj, key) => {
              obj[key] = diaryData[value][key];
              return obj;
            }, {});

          const dayIsDone = Object.keys(filtered).length !== 0;
          const isToday = i === 0;

          return (
            <TouchableOpacity key={i} onPress={() => startSurvey(i)}>
              <View style={styles.answer}>
                <View style={styles.answerLabel}>
                  {dayIsDone ? (
                    <RoundButtonIcon
                      backgroundColor="#5DEE5A"
                      iconColor="#fff"
                      borderWidth={0.5}
                      borderColor="#5DEE5A"
                      icon="validate"
                      visible={true}
                      medium
                      styleContainer={{ marginHorizontal: 0 }}
                    />
                  ) : (
                    <RoundButtonIcon
                      backgroundColor="#E7F6F8"
                      iconColor={colors.LIGHT_BLUE}
                      borderWidth={0.5}
                      borderColor={colors.LIGHT_BLUE}
                      icon="small-plus"
                      visible={true}
                      medium
                      styleContainer={{ marginHorizontal: 0 }}
                    />
                  )}
                  <View style={isToday ? styles.dayLabelTodayContainer : styles.dayLabelContainer}>
                    <Text style={isToday ? styles.dayLabelToday : styles.dayLabel}>{label}</Text>
                  </View>
                </View>
              </View>
            </TouchableOpacity>
          );
        })}
      </View>
    </View>
  );
}
Example #24
Source File: index.js    From monsuivipsy with Apache License 2.0 4 votes vote down vote up
Status = ({ navigation, startSurvey }) => {
  const [diaryData] = useContext(DiaryDataContext);
  const [NPSvisible, setNPSvisible] = useState(false);
  const [page, setPage] = useState(1);
  const [bannerProNPSVisible, setBannerProNPSVisible] = useState(true);
  const [ongletActif, setOngletActif] = useState("all");
  const scrollRef = React.useRef();

  React.useEffect(() => {
    scrollRef.current?.scrollTo({
      y: 0,
      animated: false,
    });
  }, [ongletActif]);

  // ****************
  // BEGIN - MASQUAGE DU HEADER AU SCROLL
  const headerHeight = 50;
  const scrollY = React.useRef(new Animated.Value(0));
  const handleScroll = Animated.event(
    [
      {
        nativeEvent: {
          contentOffset: { y: scrollY.current },
        },
      },
    ],
    {
      useNativeDriver: true,
    }
  );

  const scrollYClampedForHeader = Animated.diffClamp(scrollY.current, 0, headerHeight);

  let translateX = scrollY.current.interpolate({
    inputRange: [0, 100],
    outputRange: [80, 0],
    extrapolateRight: "clamp",
  });

  const translateY = scrollYClampedForHeader.interpolate({
    inputRange: [0, headerHeight],
    outputRange: [0, -headerHeight],
  });

  const opacity = translateY.interpolate({
    inputRange: [-headerHeight, 0],
    outputRange: [0, 1],
  });

  // FIN - MASQUAGE DU HEADER AU SCROLL
  // ****************

  useEffect(() => {
    (async () => {
      const onboardingStep = await localStorage.getOnboardingStep();
      const onboardingIsDone = await localStorage.getOnboardingDone();

      //if ONBOARDING_DONE is true, do nothing
      if (onboardingIsDone) {
        return;
      } else {
        const isFirstAppLaunch = await localStorage.getIsFirstAppLaunch();
        if (isFirstAppLaunch !== "false") {
          navigation.navigate("onboarding", {
            screen: onboardingStep || "OnboardingPresentation",
          });
        }
      }
    })();
  }, [navigation]);

  useFocusEffect(
    React.useCallback(() => {
      (async () => {
        const bannerProNPSDone = await localStorage.getNpsProContact();
        const supported = await localStorage.getSupported();
        setBannerProNPSVisible(supported === "PRO" && !bannerProNPSDone);
      })();
    }, [])
  );

  const noData = () => !Object.keys(diaryData).some((key) => diaryData[key]);

  const renderJournalEntrees = () => {
    return (
      <>
        {Object.keys(diaryData)
          .sort((a, b) => {
            a = a.split("/").reverse().join("");
            b = b.split("/").reverse().join("");
            return b.localeCompare(a);
          })
          .slice(0, LIMIT_PER_PAGE * page)
          .map((date) => (
            <View key={date}>
              <View style={styles.dateContainer}>
                <View style={styles.dateDot} />
                {canEdit(date) ? (
                  <Text style={styles.dateLabel}>{formatDateThread(date)}</Text>
                ) : (
                  <TouchableOpacity
                    style={styles.item}
                    onPress={() => navigation.navigate("too-late", { date })}
                  >
                    <Text style={styles.dateLabel}>{formatDateThread(date)}</Text>
                  </TouchableOpacity>
                )}
              </View>
              <StatusItem date={date} patientState={diaryData[date]} navigation={navigation} />
            </View>
          ))}
        <Bubble diaryData={diaryData} navigation={navigation} />
        <ContributeCard onPress={() => setNPSvisible(true)} />
        {Object.keys(diaryData)?.length > LIMIT_PER_PAGE * page && (
          <TouchableOpacity onPress={() => setPage(page + 1)} style={styles.versionContainer}>
            <Text style={styles.arrowDownLabel}>Voir plus</Text>
            <ArrowUpSvg style={styles.arrowDown} color={colors.BLUE} />
          </TouchableOpacity>
        )}
      </>
    );
  };

  const renderOnglet = (onglet) => {
    if (onglet === "all") {
      // display only LIMIT_PER_PAGE days
      // button that will display LIMIT_PER_PAGE more each time
      return (
        <View style={styles.container}>
          {bannerProNPSVisible ? (
            <BannerProNPS onClose={() => setBannerProNPSVisible(false)} />
          ) : (
            <>
              <RecapCompletion navigation={navigation} />
              <View style={styles.divider} />
              {renderJournalEntrees()}
            </>
          )}
        </View>
      );
    }
    if (onglet === "NOTES") {
      return <Diary hideDeader />;
    }
    return null;
  };

  return (
    <>
      <SafeAreaView style={[styles.safe]}>
        <Animated.View style={{ flex: 1 }}>
          <NPS forceView={NPSvisible} close={() => setNPSvisible(false)} />
          {/* todo : add this ? to make this component scrollable
            { transform: [{ translateY }] }
          */}
          <Animated.View style={[styles.headerContainer]}>
            {/* todo : add this ? to make this component scrollable
            style={{ opacity }}
          */}
            <Animated.View>
              <Header title="Mes entrées" navigation={navigation} />
            </Animated.View>
            <TabPicker ongletActif={ongletActif} onChange={setOngletActif} />
          </Animated.View>
          {noData() ? (
            <NoData navigation={navigation} />
          ) : (
            <>
              <Animated.ScrollView
                alwaysBounceHorizontal={false}
                alwaysBounceVertical={false}
                ref={scrollRef}
                bounces={false}
                style={styles.scrollView}
                contentContainerStyle={styles.scrollContainer}
                onScroll={handleScroll}
                showsVerticalScrollIndicator={false}
              >
                {renderOnglet(ongletActif)}
              </Animated.ScrollView>
            </>
          )}
        </Animated.View>
      </SafeAreaView>
      <FloatingPlusButton shadow onPress={startSurvey} plusPosition={translateX} />
    </>
  );
}
Example #25
Source File: index.js    From guardioes-app with Apache License 2.0 4 votes vote down vote up
Rumor = ({ navigation }) => {
    const { token, location, getCurrentLocation } = useUser()

    const [title, setTitle] = useState('')
    const [description, setDescription] = useState('')
    const [confirmedCases, setConfirmedCases] = useState(0)
    const [confirmedDeaths, setConfirmedDeaths] = useState(0)
    const [region, setRegion] = useState(location)
    const [modalVisible, setModalVisible] = useState(false)
    const [showMarker, setShowMarker] = useState(false)
    const [showAlert, setShowAlert] = useState(false)
    const [showProgressBar, setShowProgressBar] = useState(true)

    const eventInput = useRef()
    const casesInput = useRef()
    const deathsInput = useRef()

    useFocusEffect(
        useCallback(() => {
            getCurrentLocation()
        }, [])
    )

    const sendRumor = async () => {
        Keyboard.dismiss()

        const newRumor = {
            title,
            description,
            confirmed_cases: confirmedCases,
            confirmed_deaths: confirmedDeaths,
            latitude: region.latitude,
            longitude: region.longitude,
        }

        if (!validRumor(newRumor, showMarker)) return
        setShowAlert(true)

        const response = await createRumor({ rumor: newRumor }, token)

        if (response.status === 201) {
            setShowProgressBar(false)
        } else {
            Alert.alert(translate('register.geralError'))
            setShowAlert(false)
        }
    }

    return (
        <Container>
            <KeyboardScrollView>
                <Modal
                    transparent
                    visible={modalVisible}
                    onRequestClose={() => {
                        setModalVisible(!modalVisible)
                    }}
                >
                    <MapView
                        style={{ flex: 1 }}
                        region={region}
                        customMapStyle={mapStyle} // Android
                        userInterfaceStyle='dark' // iOS
                        showsUserLocation
                        onPress={(e) => {
                            console.warn(
                                'Show Marker',
                                e.nativeEvent.coordinate.latitude,
                                e.nativeEvent.coordinate.longitude
                            )

                            setShowMarker(true)
                            // When user scrolls through the map and clicks, the map goes back to where the
                            // the user is, thus is required userLatitude and userLongitude to be changed as well
                            setRegion({
                                ...region,
                                latitude: e.nativeEvent.coordinate.latitude,
                                longitude: e.nativeEvent.coordinate.longitude,
                            })
                        }}
                    >
                        {showMarker ? (
                            <Marker
                                coordinate={{
                                    latitude: region.latitude,
                                    longitude: region.longitude,
                                }}
                            />
                        ) : null}
                    </MapView>

                    <ExitMap
                        onPress={() => {
                            setShowMarker(false)
                            setRegion({
                                ...region,
                                latitude: location.latitude,
                                longitude: location.longitude,
                            })
                            setModalVisible(false)
                        }}
                    >
                        <Feather
                            name='x'
                            size={scale(25)}
                            color='#ffffff'
                            style={styles.icons}
                        />
                    </ExitMap>
                    {showMarker ? (
                        <ConfirmMap onPress={() => setModalVisible(false)}>
                            <Feather
                                name='check'
                                size={scale(25)}
                                color='#ffffff'
                                style={styles.icons}
                            />
                        </ConfirmMap>
                    ) : null}
                </Modal>

                <FormInline>
                    <FormLabel>Título:</FormLabel>
                    <NormalInput
                        maxLength={100}
                        onSubmitEditing={() => eventInput.current.focus()}
                        onChangeText={(text) => setTitle(text)}
                    />
                </FormInline>
                <FormInline>
                    <FormLabel>Descrição:</FormLabel>
                    <NormalInput
                        multiline
                        maxLength={300}
                        ref={eventInput}
                        onSubmitEditing={() => casesInput.current.focus()}
                        onChangeText={(text) => setDescription(text)}
                    />
                </FormInline>

                <FormGroup>
                    <FormGroupChild>
                        <FormLabel>Número de Casos:</FormLabel>
                        <NormalInput
                            keyboardType='number-pad'
                            ref={casesInput}
                            onSubmitEditing={() => deathsInput.current.focus()}
                            onChangeText={(text) => setConfirmedCases(text)}
                        />
                    </FormGroupChild>

                    <FormGroupChild>
                        <FormLabel>Número de Mortes:</FormLabel>
                        <NormalInput
                            keyboardType='number-pad'
                            ref={deathsInput}
                            onChangeText={(text) => setConfirmedDeaths(text)}
                        />
                    </FormGroupChild>
                </FormGroup>

                <FormGroup>
                    <FormGroupChild>
                        <FormLabel>Localização:</FormLabel>
                        <Button
                            onPress={() => {
                                Keyboard.dismiss()
                                setModalVisible(true)
                            }}
                        >
                            <MapFormMarker>
                                <MapFormText>Marcar no Mapa</MapFormText>
                                {showMarker ? (
                                    <Feather
                                        name='check-circle'
                                        size={scale(20)}
                                        color='#348EAC'
                                    />
                                ) : (
                                    <Feather
                                        name='x-circle'
                                        size={scale(20)}
                                        color='#c4c4c4'
                                    />
                                )}
                            </MapFormMarker>
                        </Button>
                    </FormGroupChild>
                </FormGroup>

                <Button onPress={() => sendRumor()}>
                    <SendContainer>
                        <SendText>Enviar</SendText>
                    </SendContainer>
                </Button>
            </KeyboardScrollView>

            <CoolAlert
                show={showAlert}
                showProgress={showProgressBar}
                title={
                    showProgressBar ? (
                        translate('badReport.messages.sending')
                    ) : (
                        <Text>
                            {translate('badReport.messages.thanks')}{' '}
                            {Emojis.tada}
                        </Text>
                    )
                }
                message={
                    showProgressBar ? null : (
                        <Text>{translate('rumor.rumorSent')}</Text>
                    )
                }
                closeOnTouchOutside={false}
                closeOnHardwareBackPress={false}
                showConfirmButton={!showProgressBar}
                confirmText={translate('badReport.messages.confirmText')}
                onConfirmPressed={() => navigation.goBack()}
                onDismiss={() => setShowAlert(false)}
            />
        </Container>
    )
}
Example #26
Source File: index.js    From guardioes-app with Apache License 2.0 4 votes vote down vote up
Maps = () => {
    const {
        isOffline,
        token,
        getCurrentLocation,
        getAppTip,
        hideAppTip,
        getCacheData,
    } = useUser()

    const [isLoading, setIsLoading] = useState(true)
    const [region, setRegion] = useState(initialRegion)
    const [mapKey, setMapKey] = useState(0)
    const [showAlert, setShowAlert] = useState(false)
    const [showUserLocation, setShowUserLocation] = useState(false)
    const [weekSurveys, setWeekSurveys] = useState([])
    const [filteredSurveys, setFilteredSurveys] = useState([])
    const [showPolygon, setShowPolygon] = useState(false)
    const [polygonState, setPolygonState] = useState('Federal District')

    useFocusEffect(
        useCallback(() => {
            getMapPins()
        }, [])
    )

    useEffect(() => {
        if (getAppTip('mapTip')) {
            setShowAlert(true)
        }
    }, [])

    const getMapPins = async () => {
        const local = await getCurrentLocation()

        if (local.error === 0) {
            setRegion(local)
            setShowUserLocation(true)
            setMapKey(mapKey + 1)
        }

        if (!isOffline && isLoading) {
            const localPin = await getCacheData('localPin', false)
            await getSurveys(localPin)
        }
    }

    const getSurveys = async (localPin) => {
        // Get Week Surveys
        const response = await getWeekSurveys(token)

        if (response.status === 200) {
            if (localPin) {
                setWeekSurveys([...response.data.surveys, localPin])
            } else {
                setWeekSurveys(response.data.surveys)
            }

            setIsLoading(false)
            // getSurveyPerState() // Logica que filtra casos de covid
        }
    }

    const hideAlert = async () => {
        setShowAlert(false)
        hideAppTip('mapTip')
    }

    const getSurveyPerState = async () => {
        const dataFilterd = []
        let reportsInState = 0
        let badReportsInState = 0
        let covidCasesInState = 0

        weekSurveys.forEach((data) => {
            if (data.state === polygonState) {
                reportsInState += 1
                if (data.symptom && data.symptom.length) {
                    badReportsInState += 1
                    if (
                        data.symptom.includes('Febre') &&
                        (data.symptom.includes('DordeGarganta') ||
                            data.symptom.includes('DificuldadeParaRespirar') ||
                            data.symptom.includes('Tosse') ||
                            data.symptom.includes('Cansaco') ||
                            data.symptom.includes('Mal-estar'))
                    ) {
                        dataFilterd.push(data)
                        covidCasesInState += 1
                    }
                }
            }
        })

        setFilteredSurveys(dataFilterd)
    }

    const CoordInsidePolygon = (point, vs) => {
        // ray-casting algorithm based on
        // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

        const x = point[0]
        const y = point[1]

        let inside = false
        for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {
            const xi = vs[i][0]
            const yi = vs[i][1]
            const xj = vs[j][0]
            const yj = vs[j][1]

            const intersect =
                yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
            if (intersect) inside = !inside
        }

        return inside
    }

    const PolygonColor = (numCase, maxCase) => {
        let colorR = 0
        let colorG = 0

        if (numCase === 0) {
            fillColor = 'rgba(0, 0, 0, 0.0)'
        } else if (numCase <= maxCase / 2) {
            colorR = (255 * numCase) / (maxCase / 2)
            fillColor = `rgba(${parseInt(colorR, 10)}, 255, 0, 0.5)`
        } else {
            colorG = 255 - (255 * numCase) / maxCase
            fillColor = `rgba(255, ${parseInt(colorG, 10)}, 0, 0.5)`
        }
        return fillColor
    }

    const coordsFilter = () => {
        const markers = []
        weekSurveys.forEach((mark) => {
            markers.push({
                location: {
                    latitude: mark.latitude,
                    longitude: mark.longitude,
                },
                symptoms: mark.symptom && mark.symptom.length > 0,
            })
        })
        return markers
    }

    const renderGoodMarker = (data) => (
        <Marker
            key={data.id || Math.random()}
            coordinate={data.location}
            image={greenMarker}
            tracksViewChanges={false}
        />
    )

    const renderBadMarker = (data) => (
        <Marker
            key={data.id || Math.random()}
            coordinate={data.location}
            image={redMarker}
            tracksViewChanges={false}
        />
    )

    return (
        <>
            <SafeAreaView style={{ flex: 0, backgroundColor: '#348EAC' }} />
            <Container>
                <ClusteredMapView
                    key={mapKey} // Updates Map
                    showsUserLocation={showUserLocation}
                    style={styles.map}
                    data={coordsFilter()}
                    initialRegion={region}
                    customMapStyle={mapStyle} // Android
                    userInterfaceStyle='dark' // iOS
                    renderMarker={{
                        good: renderGoodMarker,
                        bad: renderBadMarker,
                    }}
                    CLUSTER_SIZE_DIVIDER={CLUSTER_SIZE_DIVIDER} // The log of number of points in cluster by this constant's base defines cluster image size
                    screenSizeClusterPercentage={0.13} // Cluster occupies 13% of screen
                />
                <CoolAlert
                    show={showAlert}
                    message={translate('maps.guide')}
                    showConfirmButton
                    confirmText={translate('maps.confirmGuide')}
                    onConfirmPressed={() => hideAlert()}
                />
                {/*
                <ButtonMapChange
                    onPress={() => {
                        !showPolygon
                            ? setShowPolygon(true)
                            : setShowPolygon(false)
                    }}
                >
                    <TextMapChange>
                        Visualizar {!showPolygon ? 'Poligonos' : 'Mapa'}
                    </TextMapChange>
                </ButtonMapChange>
                */}
            </Container>
        </>
    )
}
Example #27
Source File: index.js    From guardioes-app with Apache License 2.0 4 votes vote down vote up
Home = ({ navigation }) => {
    const {
        isLoading,
        isOffline,
        signOut,
        token,
        user,
        storeUser,
        avatar,
        location,
        getCurrentLocation,
        group,
        households,
        storeHouseholds,
        householdAvatars,
        surveys,
        storeSurveys,
        getAppTip,
        hideAppTip,
        lastForm,
        getCacheData,
        storeCacheData,
        updateUserScore,
        loadSecondaryData,
        selectUser,
        getCurrentUserInfo,
    } = useUser()

    const [showTermsConsent, setShowTermsConsent] = useState(false)
    const [hasForm, setHasForm] = useState(false)
    const [hasBadReports, setHasBadReports] = useState(false)
    const [modalVisible, setModalVisible] = useState(false)
    const [showAlert, setShowAlert] = useState(false)
    const [showProgressBar, setShowProgressBar] = useState(false)
    const [alertTitle, setAlertTitle] = useState(null)
    const [alertMessage, setAlertMessage] = useState(null)
    const [inviteSurveillance, setInviteSurveillance] = useState(false)

    const person = getCurrentUserInfo()

    useFocusEffect(
        useCallback(() => {
            getUserAlerts()
        }, [surveys, lastForm])
    )

    useEffect(() => {
        if (!isLoading) {
            fetchData()
        }
    }, [isLoading])

    useEffect(() => {
        showOfflineAlert(isOffline)
    }, [isOffline])

    useEffect(() => {
        if (
            !user.is_vigilance &&
            group.group_manager &&
            group.group_manager.vigilance_email
        ) {
            setInviteSurveillance(true)
        }
    }, [group])

    const fetchData = async () => {
        await loadSecondaryData()

        verifyUserTermsConsent()
        getCurrentLocation()
        getCacheSurveys()
    }

    const verifyUserTermsConsent = () => {
        const currentPolicyTerms = terms.version
        const userPolicyTerms = user.policy_version

        if (userPolicyTerms < currentPolicyTerms) {
            setShowTermsConsent(true)
        }
    }

    const updateUserTermsConsent = async () => {
        setShowTermsConsent(false)

        const policy = {
            policy_version: terms.version,
        }

        const response = await updateUser({ user: policy }, user.id, token)

        if (response.status === 200) {
            console.warn(response.status)
            storeUser(response.data.user)
        }
    }

    const getCacheSurveys = async () => {
        const surveysCache = await getCacheData('surveysData', false)

        if (surveysCache) {
            storeSurveys(surveysCache)
        }
    }

    const getUserAlerts = () => {
        const todayDate = new Date()
        const lastWeek = new Date()

        lastWeek.setDate(todayDate.getDate() - 7)
        lastWeek.setHours(0, 0, 0, 0)

        const lastFormDate = new Date(lastForm)

        if (!lastForm || lastFormDate.getTime() < lastWeek.getTime()) {
            setHasForm(true)
        } else {
            setHasForm(false)
        }

        const userLastSurveys = surveys.filter(
            (survey) =>
                survey &&
                new Date(survey.created_at).getTime() >= lastWeek.getTime()
        )

        let badReports = 0

        if (userLastSurveys.length > 0) {
            userLastSurveys.forEach((survey) => {
                if (person.is_household) {
                    if (
                        survey.symptom.length > 0 &&
                        survey.household &&
                        survey.household.id === person.id
                    ) {
                        badReports += 1
                    }
                } else if (survey.symptom.length > 0 && !survey.household) {
                    badReports += 1
                }
            })
        }

        setHasBadReports(badReports > 2)
    }

    const getHouseholds = async () => {
        const response = await getUserHouseholds(user.id, token)

        if (response.status === 200) {
            storeHouseholds(response.data.households)
        }
    }

    const showTermsPolicy = () => {
        Alert.alert(
            terms.title,
            terms.text,
            [
                {
                    text: terms.disagree,
                    onPress: () => signOut(),
                    style: 'cancel',
                },
                {
                    text: terms.agree,
                    onPress: () => updateUserTermsConsent(),
                },
            ],
            { cancelable: false }
        )
    }

    const showOfflineAlert = (show) => {
        if (show) {
            setAlertTitle(
                <Text>
                    {translate('home.offlineTitle')} {Emojis.cloud}
                </Text>
            )
            setAlertMessage(
                `${translate('home.offlineMessage')}\n${translate(
                    'home.offlineMessage2'
                )}`
            )
            setShowAlert(true)
        } else {
            setShowAlert(false)
        }
    }

    const showLoadingAlert = () => {
        setAlertMessage(null)
        setShowAlert(true)
        setShowProgressBar(true)
    }

    const showConfirmation = (status, body) => {
        const message = getSurveyConfirmation(status, body)

        setAlertTitle(
            <Text>
                {message.alertTitle} {message.emojiTitle}
            </Text>
        )
        setAlertMessage(
            <Text>
                {message.alertMessage} {message.emojiMessage}
            </Text>
        )

        setShowProgressBar(false)
        console.log(message.alertMessage)
    }

    const sendSurvey = async () => {
        // Send Survey GOOD CHOICE
        showLoadingAlert()

        let local = {}
        if (location.error !== 0) {
            local = await getCurrentLocation()
        } else {
            local = location
        }

        const householdID = person.is_household ? person.id : null
        const survey = {
            household_id: householdID,
            latitude: local.latitude,
            longitude: local.longitude,
            symptom: [],
            created_at: moment().local().toISOString(),
        }

        const response = await createSurvey({ survey }, user.id, token)
        showConfirmation(response.status, response.data)

        updateUserScore()
        if (response.status === 201) {
            if (inviteSurveillance) {
                showSurveillanceInvite(
                    person.name,
                    { status: response.status, body: response.data },
                    showConfirmation,
                    navigation
                )
            }

            await storeCacheData('localPin', survey)

            const newSurveys = surveys.slice()
            newSurveys.push(response.data.survey)
            storeSurveys(newSurveys)
        }
    }

    if (isLoading) {
        return <ScreenLoader />
    }

    return (
        <>
            <SafeAreaView style={{ flex: 0, backgroundColor: '#348EAC' }} />
            <StatusBar backgroundColor='#348EAC' barStyle='light-content' />
            <Container>
                <ScrollViewStyled>
                    <Background>
                        <UserView>
                            <MenuBars onPress={() => navigation.openDrawer()}>
                                <SimpleLineIcons
                                    name='menu'
                                    size={26}
                                    color='#ffffff'
                                />
                            </MenuBars>
                            <NamesContainer>
                                <TextName>
                                    {translate('home.hello') +
                                        getNameParts(person.name)}
                                </TextName>
                                <AppName>
                                    {translate('home.nowAGuardian')}
                                </AppName>
                            </NamesContainer>
                            <Avatar
                                containerStyle={styles.avatar}
                                size={scale(58)}
                                source={handleAvatar(person.avatar)}
                                title={getInitials(person.name)}
                                editButton={{
                                    name: null,
                                    type: 'feather',
                                    style: styles.avatarDot,
                                }}
                                showEditButton
                                activeOpacity={0.5}
                                rounded
                                onPress={() => {
                                    getHouseholds()
                                    setModalVisible(true)
                                }}
                            />
                        </UserView>
                    </Background>

                    <StatusContainer>
                        <TextStyle>
                            {translate('home.userHowYouFelling')}
                        </TextStyle>
                        <StatusBemMal>
                            <Bem
                                disabled={isOffline}
                                onPress={() => sendSurvey()}
                            >
                                <StatusText>
                                    {translate('report.goodChoice')}
                                </StatusText>
                            </Bem>
                            <Mal
                                disabled={isOffline}
                                onPress={() => navigation.navigate('BadReport')}
                            >
                                <StatusText>
                                    {translate('report.badChoice')}
                                </StatusText>
                            </Mal>
                        </StatusBemMal>
                    </StatusContainer>

                    <Tips>{translate('home.alerts')}</Tips>

                    {user.doses < 3 && getAppTip('vaccination') ? (
                        <TipButton
                            onPress={() => navigation.navigate('Vacinacao')}
                        >
                            <UserTip
                                icon={
                                    <FontAwesome5
                                        name='syringe'
                                        size={scale(46)}
                                        color='#ffffff'
                                    />
                                }
                                title={translate('home.vaccination')}
                                message={translate('home.vaccinationData')}
                                onClose={() => hideAppTip('vaccination')}
                                isCloseable
                            />
                        </TipButton>
                    ) : null}

                    {group.form_id && hasForm ? (
                        <TipButton
                            onPress={() => navigation.navigate('BioSeguranca')}
                        >
                            <UserTip
                                icon={
                                    <SimpleLineIcons
                                        name='bubble'
                                        size={scale(46)}
                                        color='#ffffff'
                                    />
                                }
                                title={translate('home.bioSecurity')}
                                message={translate('home.bioSecurityQuestions')}
                                alert
                            />
                        </TipButton>
                    ) : null}

                    <TipButton>
                        <UserTip
                            icon={
                                <SimpleLineIcons
                                    name={
                                        hasBadReports ? 'exclamation' : 'check'
                                    }
                                    size={scale(46)}
                                    color='#ffffff'
                                />
                            }
                            title={translate('home.statusLast7Days')}
                            message={
                                hasBadReports
                                    ? translate('home.statusLast7DaysBad')
                                    : translate('home.statusLast7DaysGood')
                            }
                            alert={hasBadReports}
                        />
                    </TipButton>
                </ScrollViewStyled>

                <Modal
                    animationType='fade'
                    transparent
                    visible={modalVisible}
                    onRequestClose={() => {
                        setModalVisible(!modalVisible)
                    }}
                >
                    <Users>
                        <UserSelector>
                            <UserScroll>
                                <UserWrapper>
                                    <Button
                                        onPress={async () => {
                                            setModalVisible(!modalVisible)
                                            await selectUser(user)
                                            getUserAlerts()
                                        }}
                                    >
                                        <Avatar
                                            size={scale(60)}
                                            source={handleAvatar(avatar)}
                                            title={getInitials(user.user_name)}
                                            rounded
                                        />
                                        <UserName>
                                            {getNameParts(user.user_name, true)}
                                        </UserName>
                                    </Button>
                                </UserWrapper>
                                {households.map((household) => (
                                    <UserWrapper key={household.id}>
                                        <Button
                                            onPress={async () => {
                                                setModalVisible(!modalVisible)
                                                await selectUser(household)
                                                getUserAlerts()
                                            }}
                                        >
                                            <Avatar
                                                size={scale(60)}
                                                source={handleAvatar(
                                                    householdAvatars[
                                                        household.id
                                                    ]
                                                )}
                                                title={getInitials(
                                                    household.description
                                                )}
                                                rounded
                                            />
                                            <UserName>
                                                {getNameParts(
                                                    household.description,
                                                    true
                                                )}
                                            </UserName>
                                        </Button>
                                    </UserWrapper>
                                ))}
                                <UserWrapper>
                                    <Button
                                        onPress={() => {
                                            setModalVisible(!modalVisible)
                                            navigation.navigate('NovoPerfil')
                                        }}
                                    >
                                        <Feather
                                            name='plus'
                                            size={scale(60)}
                                            color='#c4c4c4'
                                        />
                                        <UserName>
                                            {translate('home.addProfile')}
                                        </UserName>
                                    </Button>
                                </UserWrapper>
                            </UserScroll>
                        </UserSelector>
                    </Users>
                </Modal>

                <CoolAlert
                    show={showTermsConsent}
                    title={translate('useTerms.consentTitle')}
                    message={translate('useTerms.consentMessage')}
                    closeOnTouchOutside={false}
                    closeOnHardwareBackPress={false}
                    showConfirmButton
                    confirmText={translate('useTerms.seeTerms')}
                    onConfirmPressed={() => showTermsPolicy()}
                />
                <CoolAlert
                    show={showAlert}
                    showProgress={showProgressBar}
                    title={
                        showProgressBar
                            ? translate('badReport.messages.sending')
                            : alertTitle
                    }
                    message={alertMessage}
                    closeOnTouchOutside={!showProgressBar}
                    closeOnHardwareBackPress={false}
                    showConfirmButton={!showProgressBar}
                    confirmText={translate('badReport.messages.confirmText')}
                    onConfirmPressed={() => setShowAlert(false)}
                    onDismiss={() => setShowAlert(false)}
                />
            </Container>
        </>
    )
}
Example #28
Source File: index.js    From guardioes-app with Apache License 2.0 4 votes vote down vote up
Dicas = () => {
    const { isOffline, token, getCacheData, storeCacheData } = useUser()

    const [isLoading, setIsLoading] = useState(true)
    const [modalVisible, setModalVisible] = useState(false)
    const [contents, setContents] = useState([])
    const [contentSelected, setContentSelected] = useState({})

    useFocusEffect(
        useCallback(() => {
            getAppContents()
        }, [isOffline])
    )

    const sortContents = (contents = []) => {
        contents.sort(
            (a, b) =>
                new Date(b.updated_at).getTime() -
                new Date(a.updated_at).getTime()
        )
        return contents
    }

    const getAppContents = async () => {
        if (!isOffline) {
            const response = await getContents(token)

            if (response.status === 200) {
                const appContents = sortContents(response.data.contents)
                setContents(appContents)
                setIsLoading(false)

                await storeCacheData('contentsData', appContents)
            }
        } else {
            const contentsCache = await getCacheData('contentsData', false)

            if (contentsCache) {
                setContents(contentsCache)
            }
            setIsLoading(false)
        }
    }

    const getContentIcon = (icon) => {
        const size = scale(50)

        switch (icon) {
            case 'bed':
                return <BedIcon height={size} width={size} />
            case 'doctor':
                return <DoctorIcon height={size} width={size} />
            case 'germ':
                return <GermIcon height={size} width={size} />
            case 'helpline':
                return <HelplineIcon height={size} width={size} />
            case 'homework':
                return <HomeworkIcon height={size} width={size} />
            case 'hospital':
                return <HospitalIcon height={size} width={size} />
            case 'insect':
                return <InsectIcon height={size} width={size} />
            case 'mask':
                return <MaskIcon height={size} width={size} />
            case 'no-flight':
                return <NoFlightIcon height={size} width={size} />
            case 'protection':
                return <ProtectionIcon height={size} width={size} />
            case 'sick':
                return <SickIcon height={size} width={size} />
            case 'tent':
                return <TentIcon height={size} width={size} />
            case 'thermometer':
                return <ThermometerIcon height={size} width={size} />
            case 'vaccine':
                return <VaccineIcon height={size} width={size} />
            case 'virus':
                return <VirusIcon height={size} width={size} />
            case 'wash':
                return <WashIcon height={size} width={size} />
            default:
                return <SickIcon height={size} width={size} />
        }
    }

    if (isLoading) {
        return <ScreenLoader />
    }

    return (
        <>
            <SafeAreaView style={{ flex: 0, backgroundColor: '#348EAC' }} />
            <Container>
                <ScrollViewStyled>
                    <TitleWrapper>
                        <Title>{translate('advices.title')}</Title>
                        <SubTitle>{translate('advices.subtitle')}</SubTitle>
                    </TitleWrapper>

                    <AdvicesView>
                        {contents.map((content) => (
                            <Touch
                                key={content.id}
                                onPress={() => {
                                    if (content.content_type === 'redirect') {
                                        redirectAlert(
                                            advicesText.redirect.title,
                                            advicesText.redirect.text,
                                            content.source_link
                                        )
                                    } else {
                                        setContentSelected({
                                            title: content.title,
                                            body: content.body,
                                            source_link: content.source_link,
                                        })
                                        setModalVisible(true)
                                    }
                                }}
                            >
                                <Advice>
                                    <AdviceTitle numberOfLines={3}>
                                        {content.title}
                                    </AdviceTitle>
                                    <AdviceIcon>
                                        {getContentIcon(content.icon)}
                                    </AdviceIcon>
                                </Advice>
                            </Touch>
                        ))}
                        {contents.length === 0 ? (
                            <Touch>
                                <Advice>
                                    <AdviceTitle numberOfLines={3}>
                                        {translate('advices.empty')}
                                    </AdviceTitle>
                                    <AdviceIcon>
                                        {getContentIcon('virus')}
                                    </AdviceIcon>
                                </Advice>
                            </Touch>
                        ) : null}
                    </AdvicesView>
                </ScrollViewStyled>

                <Modal
                    animationType='fade'
                    transparent
                    visible={modalVisible}
                    onRequestClose={
                        () => setModalVisible(!modalVisible) // Exit to modal view
                    }
                >
                    <SafeAreaView style={{ flex: 1 }}>
                        <DetailsContainer>
                            <Details>
                                <DetailsIcon>
                                    <TouchableOpacity
                                        onPress={() => setModalVisible(false)}
                                    >
                                        <Feather
                                            name='arrow-left-circle'
                                            size={scale(35)}
                                            color='#348eac'
                                        />
                                    </TouchableOpacity>
                                </DetailsIcon>

                                <DetailsTitleWrapper>
                                    <DetailsTitle>
                                        {contentSelected.title}
                                    </DetailsTitle>
                                </DetailsTitleWrapper>

                                <DetailsBodyText>
                                    {contentSelected.body}
                                </DetailsBodyText>
                            </Details>

                            <DetailsSeeMore>
                                <DetailsButton
                                    onPress={() =>
                                        redirectAlert(
                                            translate('advices.moreInformations'),
                                            translate('advices.redirectPermission'),
                                            contentSelected.source_link
                                        )
                                    }
                                >
                                    <DetailsButtonLabel>
                                        {translate('advices.more')}
                                    </DetailsButtonLabel>
                                </DetailsButton>
                            </DetailsSeeMore>
                        </DetailsContainer>
                    </SafeAreaView>
                </Modal>
            </Container>
        </>
    )
}
Example #29
Source File: index.js    From guardioes-app with Apache License 2.0 4 votes vote down vote up
Diario = () => {
    const {
        isOffline,
        token,
        user,
        surveys,
        storeSurveys,
        getCacheData,
        getCurrentUserInfo,
    } = useUser()

    const [isLoading, setIsLoading] = useState(true)
    const [personAge, setPersonAge] = useState(13)
    const [allDatesMarked, setAllDatesMarked] = useState([])
    const [datesMarked, setDatesMarked] = useState([])
    const [daysMarked, setDaysMarked] = useState(0)
    const [daysMissing, setDaysMissing] = useState(0)
    const [daysGood, setDaysGood] = useState(0)
    const [daysBad, setDaysBad] = useState(0)
    const [percentGood, setPercentGood] = useState(0)
    const [percentBad, setPercentBad] = useState(0)
    const [percentMissing, setPercentMissing] = useState(100)

    const person = getCurrentUserInfo()

    useFocusEffect(
        useCallback(() => {
            getSurveys()
            getPersonAge()
        }, [isOffline])
    )

    useEffect(() => {
        defineMarkedDates()
    }, [surveys])

    useEffect(() => {
        getUserParticipation()
    }, [daysMarked])

    const getSurveys = async () => {
        if (!isOffline) {
            const response = await getUserSurveys(user.id, token)

            if (response.status === 200) {
                storeSurveys(response.data.surveys)
                setIsLoading(false)
            }
        } else {
            const surveysCache = await getCacheData('surveysData', false)

            if (surveysCache) {
                storeSurveys(surveysCache)
            }
            setIsLoading(false)
        }
    }

    const getPersonAge = () => {
        const todayDate = new Date()
        const birthDate = new Date(person.birthdate)

        birthDate.setHours(0, 0, 0, 0)

        const diff = todayDate.getTime() - birthDate.getTime()
        const personAge = Math.floor(diff / (1000 * 60 * 60 * 24 * 365))

        setPersonAge(personAge)
    }

    const defineMarkedDates = () => {
        const markedDatesGood = []
        const markedDatesBad = []
        const markedDatesAll = []

        surveys.forEach((survey) => {
            if (!person.is_household) {
                if (!survey.household) {
                    if (survey.symptom && survey.symptom.length) {
                        // BadReport
                        markedDatesBad.push(
                            survey.created_at.split('T', 1).toString()
                        )
                        markedDatesAll.push(survey)
                    } else {
                        // GoodReport
                        markedDatesGood.push(
                            survey.created_at.split('T', 1).toString()
                        )
                    }
                }
            } else if (survey.household && survey.household.id === person.id) {
                if (survey.symptom && survey.symptom.length) {
                    // Household BadReport
                    markedDatesBad.push(
                        survey.created_at.split('T', 1).toString()
                    )
                    markedDatesAll.push(survey)
                } else {
                    // Household GoodReport
                    markedDatesGood.push(
                        survey.created_at.split('T', 1).toString()
                    )
                }
            }
        })

        setAllDatesMarked(markedDatesAll)

        const BadReports = markedDatesBad.reduce(
            (c, v) =>
                Object.assign(c, {
                    [v]: { selected: true, selectedColor: '#F18F01' },
                }),
            {}
        )
        const GoodReports = markedDatesGood.reduce(
            (c, v) =>
                Object.assign(c, {
                    [v]: { selected: true, selectedColor: '#5DD39E' },
                }),
            {}
        )

        Object.assign(GoodReports, BadReports)

        const daysMarked = Object.keys(GoodReports).length
        const daysBad = Object.keys(BadReports).length
        const daysGood = daysMarked - daysBad

        setDatesMarked(GoodReports)
        setDaysMarked(daysMarked)
        setDaysGood(daysGood)
        setDaysBad(daysBad)
    }

    const getUserParticipation = () => {
        const todayDate = new Date()
        const createdDate = new Date(person.created_at)

        createdDate.setHours(0, 0, 0, 0)

        const diff = todayDate.getTime() - createdDate.getTime()
        const daysTotal = Math.ceil(diff / (1000 * 60 * 60 * 24))
        const daysMissing = daysTotal - daysMarked

        const percentGood = ((daysGood / daysTotal) * 100).toFixed(0)
        const percentBad = ((daysBad / daysTotal) * 100).toFixed(0)
        const percentMissing = ((daysMissing / daysTotal) * 100).toFixed(0)

        setDaysMissing(daysMissing)
        setPercentGood(percentGood)
        setPercentBad(percentBad)
        setPercentMissing(percentMissing)
    }

    const handleCalendarArrows = (direction) => {
        if (direction === 'left') {
            return (
                <Feather name='chevron-left' size={scale(25)} color='#c4c4c4' />
            )
        }
        return <Feather name='chevron-right' size={scale(25)} color='#c4c4c4' />
    }

    if (isLoading) {
        return <ScreenLoader />
    }

    const chartData = [
        {
            key: 1,
            value: daysGood,
            svg: { fill: '#5DD39E' },
            arc: { cornerRadius: 8 },
        },
        {
            key: 2,
            value: daysBad,
            svg: { fill: '#F18F01' },
            arc: { cornerRadius: 8 },
        },
        {
            key: 3,
            value: daysMissing,
            svg: { fill: '#c4c4c4' },
            arc: { cornerRadius: 8 },
        },
    ]

    return (
        <>
            <SafeAreaView style={{ flex: 0, backgroundColor: '#348EAC' }} />
            <Container>
                <ScrollViewStyled>
                    <UserData>
                        <AvatarContainer>
                            <Avatar
                                containerStyle={{
                                    borderColor: '#ffffff',
                                    borderWidth: 3,
                                }}
                                size={scale(50)}
                                source={handleAvatar(person.avatar)}
                                title={getInitials(person.name)}
                                rounded
                            />
                        </AvatarContainer>
                        <UserInfo>
                            <UserName>
                                {getNameParts(person.name, true)}
                            </UserName>
                            <UserDetails>
                                {personAge === 1
                                    ? personAge + translate('diary.year')
                                    : personAge + translate('diary.years')}
                            </UserDetails>
                        </UserInfo>
                    </UserData>
                    <UserDash>
                        <SliderContainer>
                            <SwiperStyled showPagination disableGesture={false}>
                                <ChartContainer>
                                    <UserChart>
                                        <CalendarStyled
                                            current={moment().format(
                                                'YYYY-MM-DD'
                                            )}
                                            markedDates={datesMarked}
                                            onDayPress={(day) => {
                                                allDatesMarked.map(
                                                    (symptomMarker) => {
                                                        if (
                                                            symptomMarker.bad_since ===
                                                            day.dateString
                                                        ) {
                                                            console.warn(
                                                                symptomMarker.symptom
                                                            )
                                                        }
                                                    }
                                                )
                                            }}
                                            renderArrow={(direction) =>
                                                handleCalendarArrows(direction)
                                            }
                                        />
                                    </UserChart>
                                </ChartContainer>
                                <ChartContainer>
                                    <UserChart>
                                        <ChartTitle>
                                            {translate('diary.statisticsTitle')}
                                        </ChartTitle>
                                        <Chart>
                                            <PieChart
                                                style={{
                                                    height: 170,
                                                    marginBottom: scale(12),
                                                }}
                                                outerRadius='100%'
                                                innerRadius='15%'
                                                data={chartData}
                                            />
                                        </Chart>
                                        <LabelContainer>
                                            <View>
                                                <LabelWrapper>
                                                    <ChartLabelGreen />
                                                    <ChartLabel>
                                                        {percentGood}
                                                        {translate(
                                                            'diary.goodPercent'
                                                        )}
                                                    </ChartLabel>
                                                </LabelWrapper>
                                                <LabelWrapper>
                                                    <ChartLabelOrange />
                                                    <ChartLabel>
                                                        {percentBad}
                                                        {translate(
                                                            'diary.badPercent'
                                                        )}
                                                    </ChartLabel>
                                                </LabelWrapper>
                                                <LabelWrapper>
                                                    <ChartLabelGray />
                                                    <ChartLabel>
                                                        {percentMissing}
                                                        {translate(
                                                            'diary.notInformed'
                                                        )}
                                                    </ChartLabel>
                                                </LabelWrapper>
                                            </View>
                                        </LabelContainer>
                                    </UserChart>
                                </ChartContainer>
                            </SwiperStyled>
                        </SliderContainer>

                        <UserReports>
                            <ReportsTitleWrapper>
                                <ReportsTitle>
                                    {translate('diary.participations')}
                                </ReportsTitle>
                                <ReportsSubtitle>
                                    Total: {daysMarked}
                                </ReportsSubtitle>
                            </ReportsTitleWrapper>

                            <ReportsAll>
                                <ReportsWell>
                                    <HappyIcon
                                        height={scale(45)}
                                        width={scale(45)}
                                        fill='#ffffff'
                                    />
                                    <ReportData>
                                        <ReportDataTitle>
                                            {translate('diary.good')}
                                        </ReportDataTitle>
                                        <ReportDataInfo>
                                            {daysGood === 1
                                                ? daysGood +
                                                  translate('diary.report')
                                                : daysGood +
                                                  translate('diary.reports')}
                                        </ReportDataInfo>
                                    </ReportData>
                                </ReportsWell>

                                <ReportsIll>
                                    <SadIcon
                                        height={scale(45)}
                                        width={scale(45)}
                                        fill='#ffffff'
                                    />
                                    <ReportData>
                                        <ReportDataTitle>
                                            {translate('diary.bad')}
                                        </ReportDataTitle>
                                        <ReportDataInfo>
                                            {daysBad === 1
                                                ? daysBad +
                                                  translate('diary.report')
                                                : daysBad +
                                                  translate('diary.reports')}
                                        </ReportDataInfo>
                                    </ReportData>
                                </ReportsIll>
                            </ReportsAll>
                        </UserReports>
                    </UserDash>
                </ScrollViewStyled>
            </Container>
        </>
    )
}