✨ feat(notif): add new notification components for local and remote notifications
📦 new(NotifElementLocal.tsx): add component to handle local notifications 📦 new(NotifElementRemote.tsx): add component to handle remote notifications 📦 new(NotifList.tsx): add component to list notifications 📦 new(NotifView.tsx): add main view for notifications 📦 new(NotifViewLocal.tsx): add view for local notifications 📦 new(NotifViewRemote.tsx): add view for remote notifications 🔧 refactor: use react-native-toast-notifications for user feedback 🔧 refactor: use redux for state management 🔧 refactor: use axios for HTTP requests 🔧 refactor: use react-native-paper for UI components 🔧 refactor: use expo-clipboard for clipboard interactions 🎯 goal: improve user experience by providing local and remote notifications
This commit is contained in:
		
							parent
							
								
									ba5d2697c5
								
							
						
					
					
						commit
						504b83386d
					
				
							
								
								
									
										58
									
								
								src/components/notif/NotifElementLocal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/components/notif/NotifElementLocal.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | import axios from 'axios'; | ||||||
|  | import {View} from 'react-native'; | ||||||
|  | import IconVector from 'react-native-vector-icons/FontAwesome5'; | ||||||
|  | import { useToast } from "react-native-toast-notifications"; | ||||||
|  | import * as Clipboard from 'expo-clipboard';  | ||||||
|  | import { Avatar, Card, Text } from 'react-native-paper'; | ||||||
|  | import { store } from '../../redux/store'; | ||||||
|  | import { Button } from 'react-native-paper'; | ||||||
|  | 
 | ||||||
|  | export default function NotifElementLocal({title,content}:{title:string;content: string}){ | ||||||
|  | 
 | ||||||
|  |   const toast = useToast(); | ||||||
|  |   function onCopy() { | ||||||
|  |     Clipboard.setStringAsync(content) | ||||||
|  |       .then(()=>{ | ||||||
|  |         toast.show('copied "'+content+'" into the clipboard'); | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function sendToRemote() {  | ||||||
|  |     axios.put("https://notifysync.simailadjalim.fr/notification",{ | ||||||
|  |       title:title, | ||||||
|  |       content:content, | ||||||
|  |       deviceName:"TestNative", | ||||||
|  |       token: store.getState().user.token | ||||||
|  |     },{ | ||||||
|  |       headers: {'Content-Type': 'multipart/form-data'}} | ||||||
|  |     ).then((response,status)=>{ | ||||||
|  |         toast.show('the notification was sent to the server'); | ||||||
|  |     }).catch(response => { | ||||||
|  |       toast.show('error'); | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |   return ( | ||||||
|  |     <View | ||||||
|  |       style={{ | ||||||
|  |         flex: 1, | ||||||
|  |         margin: 10, | ||||||
|  |         flexDirection: 'row', | ||||||
|  |         justifyContent: 'space-between', | ||||||
|  |         alignItems: 'center', | ||||||
|  |       }}> | ||||||
|  |       <Card style={{width:"100%"}} onPress={onCopy}> | ||||||
|  |         <Card.Title title={title} right={() =>  | ||||||
|  |           <Button mode="contained" onPress={() => sendToRemote()} > | ||||||
|  |             <IconVector name="paper-plane" size={20} color="black"  /> | ||||||
|  |           </Button> | ||||||
|  |           } | ||||||
|  |         /> | ||||||
|  |         <Card.Content> | ||||||
|  |           <Text variant="bodyMedium">{content}</Text> | ||||||
|  |         </Card.Content> | ||||||
|  |       </Card> | ||||||
|  |     </View> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										34
									
								
								src/components/notif/NotifElementRemote.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/components/notif/NotifElementRemote.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | import { View  } from 'react-native'; | ||||||
|  | import * as Clipboard from 'expo-clipboard'; | ||||||
|  | import { useToast } from "react-native-toast-notifications"; | ||||||
|  | import { Card, Text, Button } from 'react-native-paper'; | ||||||
|  | 
 | ||||||
|  | export default function NotifElementRemote({title,content,timestamp,deviceName}:{title:string;content:string;timestamp:number;deviceName:string}){ | ||||||
|  |    | ||||||
|  |   const toast = useToast(); | ||||||
|  | 
 | ||||||
|  |   function onCopy() { | ||||||
|  |     Clipboard.setStringAsync(content) | ||||||
|  |     .then(()=>{ | ||||||
|  |         toast.show('copied "'+content+'" into the clipboard'); | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const date= new Date(timestamp*1000); | ||||||
|  |   return(  | ||||||
|  |   <View style={{flex:1, | ||||||
|  |                 padding:10, | ||||||
|  |                 width:"100%", | ||||||
|  |                 flexDirection:'row', | ||||||
|  |                 justifyContent:'center', | ||||||
|  |                 alignItems:'center'}}> | ||||||
|  |     <Card style={{width:"100%"}} onPress={onCopy} > | ||||||
|  |         <Card.Title title={title}/> | ||||||
|  |         <Card.Content> | ||||||
|  |           <Text variant="bodyMedium">{content}</Text> | ||||||
|  |           <Text variant="bodyMedium">{date.getHours() + ":" + date.getMinutes() + ", "+ date.toDateString()}</Text> | ||||||
|  |           <Text variant="bodyMedium">{deviceName}</Text> | ||||||
|  |         </Card.Content> | ||||||
|  |     </Card> | ||||||
|  |   </View>); | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/components/notif/NotifList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/components/notif/NotifList.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | import React from 'react'; | ||||||
|  | import {FlatList, ScrollView} from 'react-native'; | ||||||
|  | import { nanoid } from '@reduxjs/toolkit'; | ||||||
|  | import NotifElementLocal from './NotifElementLocal'; | ||||||
|  | import NotifElementRemote from './NotifElementRemote'; | ||||||
|  | 
 | ||||||
|  | export default function NotifList({type,notifs}:{type:string,notifs:Array<object>}) {   | ||||||
|  |    if (type === 'local') { | ||||||
|  |      return <FlatList | ||||||
|  |          data={notifs} | ||||||
|  |          renderItem={({item}) => <NotifElementLocal title={item.title} content={item.content} />} | ||||||
|  |          keyExtractor={item => nanoid()} | ||||||
|  |        /> | ||||||
|  |    } else { | ||||||
|  |      return <FlatList | ||||||
|  |          data={notifs} | ||||||
|  |          renderItem={({item}) => <NotifElementRemote title={item.title} content={item.content} deviceName={item.device_name} timestamp={item.timestamp}/>} | ||||||
|  |          keyExtractor={item => nanoid()} | ||||||
|  |        /> | ||||||
|  |      ; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										58
									
								
								src/components/notif/NotifView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/components/notif/NotifView.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | import React from "react"; | ||||||
|  | import { useWindowDimensions, ScrollView, View } from "react-native"; | ||||||
|  | import { Searchbar, Button } from "react-native-paper" | ||||||
|  | import NotifViewLocal from "./NotifViewLocal"; | ||||||
|  | import NotifViewRemote from "./NotifViewRemote"; | ||||||
|  | import { ps } from "../../utils"; | ||||||
|  | import { createMaterialTopTabNavigator } from "@react-navigation/material-top-tabs"; | ||||||
|  | 
 | ||||||
|  | export default function NotifView(){ | ||||||
|  |    | ||||||
|  |   const [searchQuery, setSearchQuery] = React.useState(''); | ||||||
|  |   const {height, width} = useWindowDimensions(); | ||||||
|  | 
 | ||||||
|  |   const Tab = createMaterialTopTabNavigator(); | ||||||
|  |   let layout = "" | ||||||
|  | 
 | ||||||
|  |   if (width < 600) layout = "compact"; | ||||||
|  |   else if (width < 1200 ) layout = "medium"; | ||||||
|  |   else layout = "expanded"; | ||||||
|  |   return ( <> | ||||||
|  |   <View style={{flexDirection:"row",justifyContent:"center",alignItems:"center", gap:5, margin:ps(4)}}>  | ||||||
|  |    {layout == "compact" ?   | ||||||
|  |     <Button children={<></>} icon="dots-vertical" mode="contained" style={{width:"auto"}} onPress={() => console.log('Pressed')}/> | ||||||
|  |     : <></>} | ||||||
|  |     <Searchbar | ||||||
|  |         placeholder="Notifications" | ||||||
|  |         onChangeText={setSearchQuery} | ||||||
|  |         value={searchQuery} | ||||||
|  |         style={{ | ||||||
|  |           flex:1 | ||||||
|  |         }} | ||||||
|  |       /> | ||||||
|  |   </View> | ||||||
|  |       { | ||||||
|  |         layout == "compact"? ( | ||||||
|  |           <Tab.Navigator tabBarPosition="bottom"> | ||||||
|  |             <Tab.Screen name="Local" options={{title: 'local'}}> | ||||||
|  |               {() => ( | ||||||
|  |                 <NotifViewLocal/> | ||||||
|  |               )} | ||||||
|  |             </Tab.Screen> | ||||||
|  |             <Tab.Screen name="Remote" options={{title: 'distant'}}> | ||||||
|  |               {()=> ( | ||||||
|  |                 <NotifViewRemote/> | ||||||
|  |               )} | ||||||
|  |             </Tab.Screen> | ||||||
|  |           </Tab.Navigator> | ||||||
|  |         ):( | ||||||
|  |             <ScrollView contentContainerStyle={{flexDirection:"row",justifyContent:"center",height:"100%",padding:ps(30)}}> | ||||||
|  |               <NotifViewLocal/> | ||||||
|  |               <NotifViewRemote/> | ||||||
|  |             </ScrollView> | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|  |   </> | ||||||
|  |    | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								src/components/notif/NotifViewLocal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/components/notif/NotifViewLocal.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | import React from 'react'; | ||||||
|  | import {ScrollView, View, Text, useWindowDimensions} from 'react-native'; | ||||||
|  | import { Button } from 'react-native-paper'; | ||||||
|  | import NotifList from './NotifList'; | ||||||
|  | import { useDispatch } from 'react-redux'; | ||||||
|  | import { localClipAddToList, localNotifAddToList } from '../../redux/reducers'; | ||||||
|  | import { useToast } from 'react-native-toast-notifications'; | ||||||
|  | import * as Clipboard from 'expo-clipboard'; | ||||||
|  | import { ps } from '../../utils'; | ||||||
|  | import { store } from '../../redux/store'; | ||||||
|  | 
 | ||||||
|  | export default function NotifViewLocal({}){ | ||||||
|  |   const [notifs, setNotifs] = React.useState(store.getState().localNotif.localNotif); | ||||||
|  |   const dispatch = useDispatch(); | ||||||
|  |   const toast = useToast(); | ||||||
|  |   const {height,width} = useWindowDimensions(); | ||||||
|  | 
 | ||||||
|  |   function getSignOutBtn() { | ||||||
|  |     return <Button mode="elevated" onPress={() => {}}>Sign out</Button> | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async function addToLocal(dispatch) { | ||||||
|  |     Clipboard.getStringAsync() | ||||||
|  |     .then(value =>{ | ||||||
|  |       let newNotif = {"title":"placeholder title","content":"placeholder content"}; | ||||||
|  |       console.log(value); | ||||||
|  |       dispatch(localNotifAddToList(newNotif)); | ||||||
|  |       setNotifs([...notifs,newNotif]); | ||||||
|  |       toast.show('added "'+value+'" into history'); | ||||||
|  |     }) | ||||||
|  |     .catch((error)=>{ | ||||||
|  |       console.log(error); | ||||||
|  |       toast.show("could not retreive last notification :(") | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <View style={{ | ||||||
|  |         width:"100%", | ||||||
|  |         height:"100%", | ||||||
|  |         flex:1, | ||||||
|  |         margin: width > 600 ? ps(10) : 0  | ||||||
|  |     }}> | ||||||
|  |       <Button | ||||||
|  |           mode="elevated" | ||||||
|  |           onPress={() => { | ||||||
|  |             console.log("TODO"); | ||||||
|  |             dispatch(addToLocal); | ||||||
|  |           }} | ||||||
|  |         > | ||||||
|  |          importer la derniere notification  | ||||||
|  |         </Button> | ||||||
|  |       <ScrollView> | ||||||
|  |         <NotifList | ||||||
|  |           type={"local"} | ||||||
|  |           notifs={notifs} | ||||||
|  |         /> | ||||||
|  |       </ScrollView> | ||||||
|  |       </View> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										48
									
								
								src/components/notif/NotifViewRemote.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/components/notif/NotifViewRemote.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | import React from 'react'; | ||||||
|  | import axios from 'axios'; | ||||||
|  | import { ScrollView,View, Text, useWindowDimensions } from 'react-native'; | ||||||
|  | import NotifListfrom from './NotifList'; | ||||||
|  | import { store } from '../../redux/store'; | ||||||
|  | import { useToast } from 'react-native-toast-notifications'; | ||||||
|  | import { Button } from 'react-native-paper'; | ||||||
|  | import { ps } from '../../utils'; | ||||||
|  | import NotifList from './NotifList'; | ||||||
|  | import { useDispatch } from 'react-redux'; | ||||||
|  | import { remoteNotifAddToList } from '../../redux/reducers'; | ||||||
|  | 
 | ||||||
|  | export default function NotifViewRemote(){ | ||||||
|  |   const [clips,setClips] = React.useState(store.getState().remoteNotif.remoteNotif); | ||||||
|  |   const toast = useToast(); | ||||||
|  |   const dispatch = useDispatch(); | ||||||
|  | 
 | ||||||
|  |   const {height,width} = useWindowDimensions(); | ||||||
|  | 
 | ||||||
|  |   async function getNotif(dispatch) { | ||||||
|  |     axios.get("http://notifysync.simailadjalim.fr/notification?token="+store.getState().user.token) | ||||||
|  |       .then((response,status) => { | ||||||
|  |         let remoteNotif = Object.values(response["data"]['notifications']); | ||||||
|  |         setClips(remoteNotif); | ||||||
|  |         dispatch(remoteNotifAddToList(remoteNotif)); | ||||||
|  |         toast.show("fetched latest notifications from remote"); | ||||||
|  |       }) | ||||||
|  |       .catch(response =>{ | ||||||
|  |         console.log(response); | ||||||
|  |         toast.show("failed to fetch latest notifications"); | ||||||
|  |       }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return <View style={{ | ||||||
|  |         width:"100%", | ||||||
|  |         height:"100%", | ||||||
|  |         flex:1, | ||||||
|  |         margin: width > 600 ? ps(10) : 0  | ||||||
|  |     }}>  | ||||||
|  |     <Button mode="elevated" onPress={() => dispatch(getNotif)}> | ||||||
|  |       Refresh  | ||||||
|  |     </Button> | ||||||
|  |     <ScrollView>  | ||||||
|  |       <NotifList type="remote" notifs={clips} /> | ||||||
|  |     </ScrollView> | ||||||
|  |   </View>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user