✨ 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