Skip to content

Commit 311bebc

Browse files
feat: Add media thumbnail support
1 parent 9095252 commit 311bebc

File tree

9 files changed

+73
-17
lines changed

9 files changed

+73
-17
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

src/assets/failedImageDark.png

2.66 KB
Loading

src/assets/failedImageLight.png

2.66 KB
Loading

src/components/card.tsx

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ const Card = (props: NotificationCardProps): ReactElement => {
4747
disableAutoMarkAsRead,
4848
hideDelete = false,
4949
onAvatarClick,
50-
deleteIcon = null
50+
deleteIcon = null,
51+
hideMediaThumbnail = false,
52+
onMediaThumbnailClick
5153
} = cardProps;
5254
const { markAsReadById } = useSiren();
5355

@@ -57,18 +59,26 @@ const Card = (props: NotificationCardProps): ReactElement => {
5759
return darkMode ? require('../assets/emptyDark.png') : require('../assets/emptyLight.png');
5860
};
5961

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

6679
useEffect(() => {
67-
setImageSource(
68-
notification?.message?.avatar?.imageUrl?.length > 0
69-
? { uri: notification.message?.avatar?.imageUrl }
70-
: emptyState()
71-
);
80+
setImageSource(avatarUrl?.length > 0 ? { uri: avatarUrl } : emptyState());
81+
setMediaSource(thumbnailUrl?.length > 0 ? { uri: thumbnailUrl } : failedState());
7282
}, [notification, darkMode]);
7383

7484
const cardClick = (): void => {
@@ -80,10 +90,18 @@ const Card = (props: NotificationCardProps): ReactElement => {
8090
setImageSource(emptyState());
8191
};
8292

93+
const onErrorMedia = (): void => {
94+
setMediaSource(failedState());
95+
};
96+
8397
const avatarClick = () => {
8498
if (onAvatarClick) onAvatarClick(notification);
8599
};
86100

101+
const mediaClick = () => {
102+
if (onMediaThumbnailClick) onMediaThumbnailClick(notification);
103+
};
104+
87105
const renderAvatar = useMemo((): JSX.Element => {
88106
return (
89107
<View style={style.cardIconContainer}>
@@ -104,6 +122,18 @@ const Card = (props: NotificationCardProps): ReactElement => {
104122
);
105123
}, [styles, darkMode, imageSource, onAvatarClick]);
106124

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

@@ -151,9 +181,14 @@ const Card = (props: NotificationCardProps): ReactElement => {
151181
{notification.message?.subHeader}
152182
</Text>
153183
)}
154-
<Text numberOfLines={2} style={[style.cardDescription, styles.cardDescription]}>
155-
{notification.message?.body}
156-
</Text>
184+
{Boolean(notification.message?.body) && (
185+
<Text numberOfLines={2} style={[style.cardDescription, styles.cardDescription]}>
186+
{notification.message?.body}
187+
</Text>
188+
)}
189+
{!hideMediaThumbnail &&
190+
Boolean(notification.message?.thumbnailUrl) &&
191+
renderMediaThumbnail}
157192
<View style={style.dateContainer}>
158193
<TimerIcon styles={styles} />
159194
<Text style={[style.dateStyle, styles.dateStyle]}>
@@ -228,6 +263,14 @@ const style = StyleSheet.create({
228263
},
229264
transparent: {
230265
backgroundColor: 'transparent'
266+
},
267+
mediaContainer: {
268+
width: '100%',
269+
height: 130,
270+
borderRadius: 6,
271+
marginBottom: 10,
272+
overflow: 'hidden',
273+
backgroundColor: '#D3D3D3'
231274
}
232275
});
233276

src/components/sirenInbox.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ const SirenInbox = (props: SirenInboxProps): ReactElement => {
7777
cardProps = {
7878
hideAvatar: false,
7979
disableAutoMarkAsRead: false,
80-
hideDelete: false
80+
hideDelete: false,
81+
hideMediaThumbnail: false,
8182
},
8283
listEmptyComponent = null,
8384
headerProps = {},

src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ type CardProps = {
8585
disableAutoMarkAsRead?: boolean;
8686
deleteIcon?: JSX.Element;
8787
hideDelete?: boolean;
88+
hideMediaThumbnail?: boolean;
89+
onMediaThumbnailClick?: (notification: NotificationDataType) => void;
8890
};
8991

9092
/**
@@ -245,4 +247,5 @@ export type StyleProps = {
245247
skeltonLoaderColor: ViewStyle;
246248
highlighted: ViewStyle;
247249
backIcon: ViewStyle;
250+
mediaContainer: ViewStyle;
248251
};

src/utils/commonUtils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,5 +277,8 @@ export const applyTheme = (
277277
theme.windowHeader?.titleColor ||
278278
theme.colors?.textColor ||
279279
DefaultTheme[mode].windowHeader.titleColor
280-
}
280+
},
281+
mediaContainer: {
282+
backgroundColor: DefaultTheme[mode].notificationCard.mediaContainerBackground
283+
},
281284
});

src/utils/constants.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export const COLORS = {
99
deleteIcon: '#34405499',
1010
timerIcon: '#667185',
1111
clearAllIcon: '#667185',
12-
infiniteLoader: '#F56630'
12+
infiniteLoader: '#F56630',
13+
imageBackground: '#F0F2F5'
1314
},
1415
dark: {
1516
primaryColor: '#FA9874',
@@ -21,7 +22,8 @@ export const COLORS = {
2122
deleteIcon: '#D0D5DD',
2223
timerIcon: '#98A2B3',
2324
clearAllIcon: '#D0D5DD',
24-
infiniteLoader: '#F56630'
25+
infiniteLoader: '#F56630',
26+
imageBackground: '#4C4C4C'
2527
}
2628
};
2729

src/utils/defaultTheme.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const defaultTheme = {
3030
subTitleColor: COLORS[ThemeMode.LIGHT].textColor,
3131
descriptionColor: COLORS[ThemeMode.LIGHT].textColor,
3232
dateColor: COLORS[ThemeMode.LIGHT].textColor,
33+
mediaContainerBackground: COLORS[ThemeMode.LIGHT].imageBackground,
3334
}
3435
},
3536
dark: {
@@ -60,7 +61,8 @@ const defaultTheme = {
6061
titleColor: COLORS[ThemeMode.DARK].textColor,
6162
subTitleColor: COLORS[ThemeMode.DARK].textColor,
6263
descriptionColor: COLORS[ThemeMode.DARK].textColor,
63-
dateColor: COLORS[ThemeMode.DARK].dateColor
64+
dateColor: COLORS[ThemeMode.DARK].dateColor,
65+
mediaContainerBackground: COLORS[ThemeMode.DARK].imageBackground,
6466
}
6567
}
6668
};

0 commit comments

Comments
 (0)