Add notification viewed sync and header badge dot

This commit is contained in:
Adolfo Reyna
2026-02-20 22:15:07 -05:00
parent cc9ca1d075
commit 0ba5d7bd0d
3 changed files with 55 additions and 2 deletions

7
API.js
View File

@@ -310,6 +310,13 @@ const API = {
} }
return postCall("/user/myProfile", {profile, data}); return postCall("/user/myProfile", {profile, data});
}, },
markNotificationsViewed() {
if (CurrentProfile) {
delete userNameCache[CurrentProfile];
delete failedProfileCache[CurrentProfile];
}
return postCall("/user/notifications/viewed", {});
},
searchProfiles(query){ searchProfiles(query){
return getCall("/user/search", query ? {query} : {}).then((data)=>{ return getCall("/user/search", query ? {query} : {}).then((data)=>{
if(data.status == "ok"){ if(data.status == "ok"){

26
App.js
View File

@@ -273,6 +273,12 @@ const MainNavigation = ({ route }) => {
} }
export default function App() { export default function App() {
const appState = useSnapshot(GlobalState);
const viewer = appState.me || {};
const hasUnviewedNotifications = Array.isArray(viewer?.notifications)
? viewer.notifications.some((n) => n && n.viewed !== true)
: false;
return ( return (
<PaperProvider settings={{ <PaperProvider settings={{
icon: props => <MaterialIcons {...props} />, icon: props => <MaterialIcons {...props} />,
@@ -295,7 +301,25 @@ export default function App() {
props.navigation.navigate("SongPlayer"); props.navigation.navigate("SongPlayer");
}} /> }} />
<Appbar.Action icon="search" onPress={() => { props.navigation.navigate("Search") }} /> <Appbar.Action icon="search" onPress={() => { props.navigation.navigate("Search") }} />
<Appbar.Action icon="notifications" onPress={() => { props.navigation.navigate("Notifications") }} /> <Appbar.Action
icon={({ size, color }) => (
<View style={{ width: size, height: size, justifyContent: "center", alignItems: "center" }}>
<MaterialIcons name="notifications" size={size} color={color} />
{hasUnviewedNotifications ? (
<View style={{
position: "absolute",
top: 2,
right: 0,
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: "#d93025",
}} />
) : <></>}
</View>
)}
onPress={() => { props.navigation.navigate("Notifications") }}
/>
</Appbar.Header> </Appbar.Header>
) )
}, },

View File

@@ -6,10 +6,32 @@ import SinglePost from '../components/SinglePostComponent';
import Moment from 'moment'; import Moment from 'moment';
import { useSnapshot } from 'valtio'; import { useSnapshot } from 'valtio';
import GlobalState from '../contexts/GlobalState.js'; import GlobalState from '../contexts/GlobalState.js';
import API from '../API.js';
import { useFocusEffect } from '@react-navigation/native';
let NotificationsView = ({ navigation, route }) => { let NotificationsView = ({ navigation, route }) => {
const gState = useSnapshot(GlobalState); const gState = useSnapshot(GlobalState);
const viewer = gState.me; const viewer = gState.me;
useFocusEffect(
React.useCallback(() => {
let active = true;
const markViewed = async () => {
const notifications = Array.isArray(viewer?.notifications) ? viewer.notifications : [];
const hasUnviewed = notifications.some((n) => n && n.viewed !== true);
if (!hasUnviewed) return;
const result = await API.markNotificationsViewed();
if (!active || result?.status !== "ok") return;
if (!GlobalState.me.notifications) GlobalState.me.notifications = [];
GlobalState.me.notifications = GlobalState.me.notifications.map((n) => ({ ...n, viewed: true }));
};
markViewed();
return () => {
active = false;
};
}, [viewer?.notifications?.length])
);
const renderNotification = (({ item }) => { const renderNotification = (({ item }) => {
const gotToPost = () => { const gotToPost = () => {
navigation.navigate('SinglePost', { postid: item.postid }); navigation.navigate('SinglePost', { postid: item.postid });
@@ -17,7 +39,7 @@ let NotificationsView = ({ navigation, route }) => {
return ( return (
<Card style={{ margin: 3 }} onPress={gotToPost}> <Card style={{ margin: 3 }} onPress={gotToPost}>
<Card.Content> <Card.Content>
<Text>{item.body}</Text> <Text style={{ fontWeight: item.viewed ? 'normal' : '700' }}>{item.body}</Text>
<Text style={{ fontWeight: 'normal', fontSize: 12 }}> <Text style={{ fontWeight: 'normal', fontSize: 12 }}>
{" " + Moment(item.ts).fromNow()} {" " + Moment(item.ts).fromNow()}
</Text> </Text>