✨ 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