@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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 "Mon journal"
</Text>
</ScrollView>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Example #19
Source File: index.js From monsuivipsy with Apache License 2.0 | 4 votes |
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 |
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) à</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 |
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 |
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 d’un "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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
</>
)
}