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:
Djalim Simaila 2024-04-04 13:01:24 +02:00
parent ba5d2697c5
commit 504b83386d
6 changed files with 283 additions and 0 deletions

View 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>
);
}

View 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>);
}

View 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()}
/>
;
}
}

View 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>
)
}
</>
)
}

View 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>
);
}

View 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>;
}