Skip to content

Commit 63f762e

Browse files
Merge pull request #60 from KeyValueSoftwareSystems/dev
refactor: Update realtime fetch logic and rename functions, Add media thumbnail support, Add unique identifier for PubSub events in SirenProvider
2 parents 3acabd5 + d91d1d5 commit 63f762e

20 files changed

+247
-140
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [1.0.0] - 2024-03-26
5+
## 1.1.0
6+
7+
### Added
8+
- Added support for custom delete icon and a flag to toggle the visibility of the delete icon.
9+
- Added functionality to display thumbnail URL previews for media content.
10+
- Exposed avatar click property.
11+
- Implemented specific error code mapping.
12+
- Enhanced style and theme customizations.
13+
14+
## 1.0.0
615

716
### Added
817

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ theme | Object for custom themes | Theme | {} |
112112
customStyles | Object for custom styling | CustomStyleProps | {} |
113113
darkMode | Toggle to enable dark mode| boolean | false |
114114
itemsPerFetch | Number of notifications fetch per api request (have a max cap of 50) | number | 20 |
115-
cardProps | Props for customizing the card | CardProps | { hideAvatar: false, disableAutoMarkAsRead: false, hideDelete: false, deleteIcon: JSX.Element, onAvatarClick: ()=> null } |
115+
cardProps | Props for customizing the card | CardProps | { hideAvatar: false, disableAutoMarkAsRead: false, hideDelete: false, deleteIcon: JSX.Element, onAvatarClick: ()=> null, hideMediaThumbnailL: false, onMediaThumbnailClick: ()=> null} |
116116
customCard | Function for rendering custom card | (notification)=> JSX Element | null |
117117
onCardClick | Custom click handler for card | (notification)=> void | ()=>null |
118118
listEmptyComponent | Custom component for empty list | JSX Element | null |
@@ -200,7 +200,7 @@ Here are the custom style options for the notification inbox:
200200
deleteIcon?:{
201201
size?: number
202202
};
203-
dateIcon?:{
203+
timerIcon?:{
204204
size?: number
205205
};
206206
clearAllIcon?:{
@@ -216,6 +216,8 @@ Here are the custom style options for the notification inbox:
216216
disableAutoMarkAsRead?: boolean;
217217
deleteIcon?: JSX.Element;
218218
hideDelete?: boolean;
219+
hideMediaThumbnail?: boolean;
220+
onMediaThumbnailClick?: (notification: NotificationDataType) => void;
219221
};
220222
```
221223

@@ -246,10 +248,6 @@ function MyComponent() {
246248
markAsReadById(id);
247249
}
248250

249-
function handleDeleteNotification(id) {
250-
deleteById(id);
251-
}
252-
253251
return (
254252
{/* Your component logic */}
255253
);

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"@react-navigation/bottom-tabs": "^6.5.14",
1414
"@react-navigation/native": "^6.1.12",
1515
"@react-navigation/native-stack": "^6.9.20",
16-
"@sirenapp/react-native-inbox": "^1.0.0",
16+
"@sirenapp/react-native-inbox": "^1.1.0",
1717
"react": "18.2.0",
1818
"react-native": "0.73.4",
1919
"react-native-modal": "^13.0.1",

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@
7878
],
7979
"dependencies": {
8080
"pubsub-js": "^1.9.4",
81-
"@sirenapp/js-sdk": "^1.0.0"
81+
"@sirenapp/js-sdk": "^1.1.0"
8282
}
8383
}

src/assets/failedImageDark.png

2.66 KB
Loading

src/assets/failedImageLight.png

2.66 KB
Loading

src/components/card.tsx

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Animated, Image, StyleSheet, Text, TouchableOpacity, View } from 'react
44
import type { NotificationCardProps } from '../types';
55
import { CommonUtils, useSiren } from '../utils';
66
import { eventTypes, events } from '../utils/constants';
7+
import { useSirenContext } from './sirenProvider';
78
import CloseIcon from './closeIcon';
89
import TimerIcon from './timerIcon';
910

@@ -47,28 +48,39 @@ const Card = (props: NotificationCardProps): ReactElement => {
4748
disableAutoMarkAsRead,
4849
hideDelete = false,
4950
onAvatarClick,
50-
deleteIcon = null
51+
deleteIcon = null,
52+
hideMediaThumbnail = false,
53+
onMediaThumbnailClick
5154
} = cardProps;
5255
const { markAsReadById } = useSiren();
56+
const { id: providerId } = useSirenContext();
5357

5458
const opacity = useRef(new Animated.Value(1)).current;
5559

5660
const emptyState = () => {
5761
return darkMode ? require('../assets/emptyDark.png') : require('../assets/emptyLight.png');
5862
};
5963

64+
const failedState = () => {
65+
return darkMode
66+
? require('../assets/failedImageDark.png')
67+
: require('../assets/failedImageLight.png');
68+
};
69+
70+
const avatarUrl = notification?.message?.avatar?.imageUrl || '';
71+
const thumbnailUrl = notification?.message?.thumbnailUrl || '';
72+
6073
const [imageSource, setImageSource] = useState(
61-
notification?.message?.avatar?.imageUrl?.length > 0
62-
? { uri: notification.message?.avatar?.imageUrl }
63-
: emptyState()
74+
avatarUrl?.length > 0 ? { uri: avatarUrl } : emptyState()
75+
);
76+
77+
const [mediaSource, setMediaSource] = useState(
78+
thumbnailUrl?.length > 0 ? { uri: thumbnailUrl } : emptyState()
6479
);
6580

6681
useEffect(() => {
67-
setImageSource(
68-
notification?.message?.avatar?.imageUrl?.length > 0
69-
? { uri: notification.message?.avatar?.imageUrl }
70-
: emptyState()
71-
);
82+
setImageSource(avatarUrl?.length > 0 ? { uri: avatarUrl } : emptyState());
83+
setMediaSource(thumbnailUrl?.length > 0 ? { uri: thumbnailUrl } : failedState());
7284
}, [notification, darkMode]);
7385

7486
const cardClick = (): void => {
@@ -80,10 +92,18 @@ const Card = (props: NotificationCardProps): ReactElement => {
8092
setImageSource(emptyState());
8193
};
8294

95+
const onErrorMedia = (): void => {
96+
setMediaSource(failedState());
97+
};
98+
8399
const avatarClick = () => {
84100
if (onAvatarClick) onAvatarClick(notification);
85101
};
86102

103+
const mediaClick = () => {
104+
if (onMediaThumbnailClick) onMediaThumbnailClick(notification);
105+
};
106+
87107
const renderAvatar = useMemo((): JSX.Element => {
88108
return (
89109
<View style={style.cardIconContainer}>
@@ -104,6 +124,18 @@ const Card = (props: NotificationCardProps): ReactElement => {
104124
);
105125
}, [styles, darkMode, imageSource, onAvatarClick]);
106126

127+
const renderMediaThumbnail = useMemo((): JSX.Element => {
128+
return (
129+
<TouchableOpacity
130+
style={[style.mediaContainer, styles.mediaContainer]}
131+
disabled={Boolean(!onMediaThumbnailClick)}
132+
onPress={mediaClick}
133+
>
134+
<Image source={mediaSource} resizeMode='cover' style={style.icon} onError={onErrorMedia} />
135+
</TouchableOpacity>
136+
);
137+
}, [darkMode, mediaSource, onMediaThumbnailClick]);
138+
107139
const onDeleteItem = async (): Promise<void> => {
108140
const isSuccess = await onDelete(notification.id, false);
109141

@@ -115,7 +147,7 @@ const Card = (props: NotificationCardProps): ReactElement => {
115147
}).start(() => {
116148
const payload = { id: notification.id, action: eventTypes.DELETE_ITEM };
117149

118-
PubSub.publish(events.NOTIFICATION_LIST_EVENT, JSON.stringify(payload));
150+
PubSub.publish(`${events.NOTIFICATION_LIST_EVENT}${providerId}`, JSON.stringify(payload));
119151
});
120152
};
121153

@@ -141,19 +173,28 @@ const Card = (props: NotificationCardProps): ReactElement => {
141173
<Text numberOfLines={2} style={[styles.cardTitle, style.cardTitle]}>
142174
{notification.message?.header}
143175
</Text>
144-
{!hideDelete &&
145-
(deleteIcon || (
146-
<CloseIcon onDelete={onDeleteItem} notification={notification} styles={styles} />
147-
))}
176+
{!hideDelete && (
177+
<CloseIcon
178+
onDelete={onDeleteItem}
179+
customIcon={deleteIcon}
180+
notification={notification}
181+
styles={styles}
182+
/>
183+
)}
148184
</View>
149185
{Boolean(notification.message?.subHeader) && (
150186
<Text numberOfLines={2} style={[style.cardSubTitle, styles.cardSubTitle]}>
151187
{notification.message?.subHeader}
152188
</Text>
153189
)}
154-
<Text numberOfLines={2} style={[style.cardDescription, styles.cardDescription]}>
155-
{notification.message?.body}
156-
</Text>
190+
{Boolean(notification.message?.body) && (
191+
<Text numberOfLines={2} style={[style.cardDescription, styles.cardDescription]}>
192+
{notification.message?.body}
193+
</Text>
194+
)}
195+
{!hideMediaThumbnail &&
196+
Boolean(notification.message?.thumbnailUrl) &&
197+
renderMediaThumbnail}
157198
<View style={style.dateContainer}>
158199
<TimerIcon styles={styles} />
159200
<Text style={[style.dateStyle, styles.dateStyle]}>
@@ -228,6 +269,14 @@ const style = StyleSheet.create({
228269
},
229270
transparent: {
230271
backgroundColor: 'transparent'
272+
},
273+
mediaContainer: {
274+
width: '100%',
275+
height: 130,
276+
borderRadius: 6,
277+
marginBottom: 10,
278+
overflow: 'hidden',
279+
backgroundColor: '#D3D3D3'
231280
}
232281
});
233282

src/components/closeIcon.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import type { StyleProps } from '../types';
88
const CloseIcon = ({
99
notification,
1010
styles,
11+
customIcon,
1112
onDelete
1213
}: {
1314
notification: NotificationDataType;
1415
styles: Partial<StyleProps>;
16+
customIcon?: ReactElement | null;
1517
onDelete: (id: string) => void;
1618
}): ReactElement => {
1719
const icon: JSX.Element[] = [];
@@ -36,7 +38,7 @@ const CloseIcon = ({
3638
testID='delete-button'
3739
accessibilityLabel={`siren-notification-delete${notification.id}`}
3840
>
39-
<>{icon}</>
41+
<>{customIcon || icon}</>
4042
</TouchableOpacity>
4143
);
4244
};

0 commit comments

Comments
 (0)