Skip to content

Commit 1e50146

Browse files
authored
feat: Add minimum bound for page size, group header props, and expose 'mark as read' functionality on click
1 parent 656e487 commit 1e50146

File tree

7 files changed

+114
-88
lines changed

7 files changed

+114
-88
lines changed

README.md

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ The `@sirenapp/react-inbox` sdk is a comprehensive and customizable React UI kit
66

77
## 1. Installation
88

9-
You can install the react sdk from npm
9+
You can install the react sdk from npm
1010

1111
```bash
1212
npm install @sirenapp/react-inbox
1313
```
14+
1415
or from yarn
1516

1617
```bash
@@ -22,7 +23,9 @@ yarn add @sirenapp/react-inbox
2223
- React v16.8+
2324

2425
## 2. Configuration
26+
2527
### 2.1 Initialization
28+
2629
Initialize the sdk with user token and recipient id. Wrap the provider around your App's root.
2730

2831
```js
@@ -37,15 +40,15 @@ const config = {
3740
```
3841

3942
### 2.2 Configure notification inbox
43+
4044
Once the provider is configured, next step is to configure the notification inbox
4145

4246
Inbox is a paginated list view for displaying notifications.
4347

4448
```js
45-
import { SirenInbox } from '@sirenapp/react-inbox';
49+
import { SirenInbox } from "@sirenapp/react-inbox";
4650

4751
<SirenInbox />
48-
4952
```
5053

5154
#### Props for the notification inbox
@@ -55,27 +58,25 @@ Below are optional props available for the inbox component:
5558
Prop | Description | Type | Default value |
5659
--- | --- | --- | --- |
5760
theme | Object for custom themes | Theme | {} |
58-
title | Title of the notification inbox | string | "Notifications" |
59-
loadMoreLabel | Text shown on the load more component | string | "Load More"
60-
hideHeader | Toggle to hide or show the header section | boolean | false |
61-
hideClearAll | Toggle to hide or show the clear all button | boolean | false |
61+
loadMoreLabel | Text shown on the load more component | string | "Load More" |
6262
hideBadge | Toggle to hide or show the badge | boolean | false |
6363
darkMode | Toggle to enable dark mode | boolean | false |
6464
itemsPerFetch | Number of notifications fetch per api request (have a max cap of 50) | number | 20 |
6565
windowViewOnly | Toggle to enable fit-to-screen window or modal view | boolean | false |
6666
notificationIcon | Option to use custom notification Icon | JSX Element | null |
67-
cardProps | Props for customizing the notification cards | { hideAvatar: boolean } | { hideAvatar: false } |
67+
inboxHeaderProps | Props for customizing the header.<br> title - Title of the notification inbox<br> hideHeader - Toggle to hide or show the header section.<br> hideClearAll - Toggle to hide or show the clear all button.<br> customHeader - Custom header component. | InboxHeaderProps| { title: '', hideHeader: false, hideClearAll: false, customHeader: null } |
68+
cardProps | Props for customizing the notification cards..<br> hideAvatar - Toggle to hide or show the avatar.<br> disableAutoMarkAsRead - Toggle to disable or enable the markAsRead functionality on card click | CardProps | { hideAvatar: false, disableAutoMarkAsRead: false } |
6869
customNotificationCard | Function for rendering custom notification cards | (notification)=> JSX Element | null |
6970
onNotificationCardClick | Custom click handler for notification cards | (notification)=> void | ()=>null |
7071
listEmptyComponent | Custom component for empty notification list | JSX Element | null |
71-
customHeader | Custom header component | JSX Element | null |
7272
customFooter | Custom footer component | JSX Element | null |
7373
customLoader | Custom loader component | JSX Element | null |
7474
loadMoreComponent | Custom load more component | JSX Element | null |
7575
customErrorWindow | Custom error window | JSX Element | null |
7676
onError | Callback for handling errors | (error: SirenErrorType)=> void | null |
7777

7878
## 3. Customization
79+
7980
### 3.1 Themes
8081

8182
Here are the available theme options:
@@ -101,7 +102,7 @@ type ThemeProps = {
101102
timerIcon?: string,
102103
clearAllIcon?: string,
103104
infiniteLoader?: string,
104-
windowShadowColor?: string
105+
windowShadowColor?: string,
105106
},
106107
badgeStyle?: {
107108
color?: string,
@@ -128,9 +129,10 @@ type ThemeProps = {
128129
loadMoreButton: {
129130
color?: string,
130131
background?: string,
131-
}
132+
},
132133
};
133134
```
135+
134136
### 3.2 Style options
135137

136138
Here are the custom style options for the notification inbox
@@ -187,6 +189,26 @@ Please note that the badgeStyle, window shadow and border props are only applica
187189
}
188190
```
189191

192+
#### CardProps
193+
194+
```js
195+
type CardProps = {
196+
hideAvatar?: boolean,
197+
disableAutoMarkAsRead?: boolean,
198+
};
199+
```
200+
201+
#### InboxHeaderProps
202+
203+
```js
204+
type InboxHeaderProps = {
205+
title?: string;
206+
hideHeader?: boolean,
207+
hideClearAll?: boolean,
208+
customHeader?: JSX.Element | null,
209+
};
210+
```
211+
190212
## 4. Hooks
191213

192214
`useSiren` is a hook that provides utility functions for modifying notifications.
@@ -229,43 +251,41 @@ function MyComponent() {
229251
}
230252
```
231253

232-
#### useSiren functions
254+
### useSiren functions
233255

234-
| Functions | Parameters | Type | Description |
235-
| ----------------------------- | ----------------- |---------| ----------------------------------------------------------- |
236-
| markNotificationsAsReadByDate | startDate | ISO date string | Sets the read status of notifications to true until the given date. |
237-
| markAsRead | id | string | Set read status of a notification to true |
238-
| deleteNotification | id | string | Delete a notification by id |
239-
| deleteNotificationsByDate | startDate | ISO date string| Delete all notifications until given date |
240-
| markNotificationsAsViewed | startDate | ISO date string | Sets the viewed status of notifications to true until the given date |
256+
Functions | Parameters | Type | Description |
257+
----------|------------|-------|------------|
258+
markNotificationsAsReadByDate | startDate | ISO date string | Sets the read status of notifications to true until the given date |
259+
markAsRead | id | string | Set read status of a notification to true |
260+
deleteNotification | id | string | Delete a notification by id |
261+
deleteNotificationsByDate | startDate | ISO date string | Delete all notifications until given date |
262+
markNotificationsAsViewed | startDate | ISO date string |Sets the viewed status of notifications to true until the given date |
241263

242264
## 5. Error codes
243265

244266
Given below are all possible error codes thrown by sdk.
245267

246-
| Error code | Description |
247-
| ------------------------- | ------------------------------------------------------------------|
248-
| INVALID_TOKEN | The token passed in the provider is invalid |
249-
| INVALID_RECIPIENT_ID | The recipient id passed in the provider is invalid |
250-
| TOKEN_VERIFICATION_FAILED | Verification of the given tokens has failed |
251-
| GENERIC_API_ERROR | Occurrence of an unexpected api error |
252-
| OUTSIDE_SIREN_CONTEXT | Attempting to invoke the functions outside the siren inbox context|
253-
| MISSING_PARAMETER | The required parameter is missing |
268+
Error code | Description |
269+
------------------------- | ------------------------------------------------------------------|
270+
INVALID_TOKEN | The token passed in the provider is invalid |
271+
INVALID_RECIPIENT_ID | The recipient id passed in the provider is invalid |
272+
TOKEN_VERIFICATION_FAILED | Verification of the given tokens has failed |
273+
GENERIC_API_ERROR | Occurrence of an unexpected api error |
274+
OUTSIDE_SIREN_CONTEXT | Attempting to invoke the functions outside the siren inbox context|
275+
MISSING_PARAMETER | The required parameter is missing |
254276

255277
## Example
256278

257279
Here's a basic example to help you get started
258280

259281
```js
260-
261-
import React from 'react';
262-
import {SirenInbox,SirenProvider} from '@sirenapp/react-inbox';
282+
import React from "react";
283+
import { SirenInbox, SirenProvider } from "@sirenapp/react-inbox";
263284

264285
function App(): React.JSX.Element {
265-
266286
const config = {
267-
userToken: 'your_user_token',
268-
recipientId: 'your_recipient_id',
287+
userToken: "your_user_token",
288+
recipientId: "your_recipient_id",
269289
};
270290

271291
return (
@@ -278,15 +298,18 @@ function App(): React.JSX.Element {
278298
export default App;
279299

280300
export function MyContainer(): React.JSX.Element {
281-
282301
return (
283302
<div>
284303
<SirenInbox
285304
title="Notifications"
286305
hideHeader={false}
287306
darkMode={false}
288-
cardProps={{hideAvatar: false}}
307+
cardProps={{
308+
hideAvatar: false,
309+
disableAutoMarkAsRead: false,
310+
}}
289311
/>
290312
</div>
291313
);
292-
}
314+
}
315+
```

example/src/App.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const App: React.FC = () => {
3737
const [showCustomNotificationCard, setShowCustomNotificationCard] =
3838
useState(false);
3939

40-
const { markNotificationsAsReadByDate, markAsRead } = useSiren();
40+
const { markNotificationsAsReadByDate } = useSiren();
4141

4242
const renderListEmpty = () => {
4343
return (
@@ -248,25 +248,26 @@ const App: React.FC = () => {
248248

249249
return (
250250
<div>
251-
<SirenInbox
252-
title="Siren Notifications"
253-
hideHeader={hideHeader}
251+
<SirenInbox
252+
inboxHeaderProps={{
253+
title:"Siren Notifications",
254+
hideHeader: hideHeader,
255+
customHeader: showCustomHeader ? renderCustomHeader() : undefined
256+
}}
254257
darkMode={sdkDarkModeEnabled}
255258
cardProps={{ hideAvatar: hideAvatar, showMedia: true }}
256259
theme={windowThemes[windowThemeIndex]}
257260
customFooter={showCustomFooter ? renderCustomFooter() : undefined}
258261
listEmptyComponent={
259262
showCustomEmptyComponent ? renderListEmpty() : undefined
260263
}
261-
customHeader={showCustomHeader ? renderCustomHeader() : undefined}
262264
customNotificationCard={
263265
showCustomNotificationCard
264266
? (notification: any) => renderCustomNotificationCard(notification)
265267
: undefined
266268
}
267-
onNotificationCardClick={(notification: { id: any; }) => {
269+
onNotificationCardClick={() => {
268270
console.log("click on notification");
269-
markAsRead(notification.id);
270271
}}
271272
onError={(error: any) => {
272273
console.log(`error: ${error}`);

src/components/Card.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import defaultAvatarLight from "../assets/light/defaultAvatarLight.png";
88
import type { NotificationCardProps } from "../types";
99
import { generateElapsedTimeText } from "../utils/commonUtils";
1010
import "../styles/card.css";
11+
import useSiren from "../utils/sirenHook";
1112

1213
/**
1314
* Card component represents an individual notification card in the notification list.
@@ -51,7 +52,10 @@ const Card: FC<NotificationCardProps> = ({
5152
}) => {
5253
const { id, createdAt, message, isRead } = notification;
5354
const { avatar, header, subHeader, body } = message;
54-
55+
const { hideAvatar, disableAutoMarkAsRead } = cardProps ?? {};
56+
const {
57+
markAsRead
58+
} = useSiren();
5559
const onDelete = (event: React.MouseEvent) => {
5660
deleteNotificationById(id);
5761
event.stopPropagation();
@@ -69,20 +73,23 @@ const Card: FC<NotificationCardProps> = ({
6973
backgroundColor: styles.activeCardMarker.backgroundColor,
7074
};
7175

76+
const handleNotificationCardClick = () => {
77+
onNotificationCardClick && onNotificationCardClick(notification);
78+
!disableAutoMarkAsRead && markAsRead(notification.id);
79+
}
80+
7281
return (
7382
<div
7483
style={cardContainerStyle}
7584
className={`${
76-
cardProps?.hideAvatar
85+
hideAvatar
7786
? "siren-sdk-hide-avatar-card-container"
7887
: "siren-sdk-card-container"
7988
}`}
80-
onClick={() =>
81-
onNotificationCardClick && onNotificationCardClick(notification)
82-
}
89+
onClick={handleNotificationCardClick}
8390
data-testid={`card-${notification.id}`}
8491
>
85-
{!cardProps?.hideAvatar && (
92+
{!hideAvatar && (
8693
<div
8794
style={{
8895
...styles.cardIconRound,

src/components/SirenInbox.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,27 @@ import NotificationButton from "./SirenNotificationIcon";
44
import SirenPanel from "./SirenPanel";
55
import { useSirenContext } from "./SirenProvider";
66
import type { SirenProps } from "../types";
7-
import { Constants } from "../utils";
87
import { applyTheme, calculateModalPosition } from "../utils/commonUtils";
9-
import { BadgeType, MAXIMUM_ITEMS_PER_FETCH, ThemeMode } from "../utils/constants";
8+
import {
9+
BadgeType,
10+
MAXIMUM_ITEMS_PER_FETCH,
11+
ThemeMode,
12+
} from "../utils/constants";
1013
import "../styles/sirenInbox.css";
1114

12-
const { DEFAULT_WINDOW_TITLE } = Constants;
1315
/**
1416
* SirenInbox Component
1517
* @param {Object} props - Props for the SirenInbox component
1618
* @param {Theme} props.theme - The theme for the SirenInbox component
17-
* @param {string} props.title - The title of the notification panel.
1819
* @param {string} [props.title] - The title for the SirenInbox component
1920
* @param {boolean} [props.windowViewOnly=false] - Flag indicating if the window is view-only
20-
* @param {boolean} [props.hideHeader] - Flag indicating if the header should be hidden
21-
* @param {boolean} [props.hideClearAll] - Flag indicating if the clear all button should be hidden
2221
* @param {boolean} [props.hideBadge] - Flag indicating if the badge should be hidden
22+
* @param {CardProps} [props.inboxHeaderProps] - Object containing props related to the inbox header
2323
* @param {boolean} [props.darkMode] - Flag indicating if the component is in dark mode
2424
* @param {CardProps} [props.cardProps] - Additional props for the card component
2525
* @param {ReactNode} [props.notificationIcon] - The notification icon for the window
2626
* @param {JSX.Element} [props.listEmptyComponent] - JSX element for rendering when the list is empty
2727
* @param {JSX.Element} [props.customFooter] - Custom footer JSX element for the window
28-
* @param {JSX.Element} [props.customHeader] - Custom header JSX element for the window
2928
* @param {Function} [props.customNotificationCard] - Function to render custom notification card
3029
* @param {Function} [props.onNotificationCardClick] - Handler for notification card click event
3130
* @param {Function} [props.onError] - Handler for error events
@@ -40,17 +39,14 @@ const { DEFAULT_WINDOW_TITLE } = Constants;
4039
const SirenInbox: FC<SirenProps> = ({
4140
theme,
4241
customStyles,
43-
title = DEFAULT_WINDOW_TITLE,
4442
windowViewOnly = false,
45-
hideHeader,
4643
hideBadge = false,
47-
hideClearAll = false,
4844
darkMode = false,
45+
inboxHeaderProps,
4946
cardProps,
5047
notificationIcon,
5148
listEmptyComponent,
5249
customFooter,
53-
customHeader,
5450
customLoader,
5551
customErrorWindow,
5652
loadMoreComponent,
@@ -59,8 +55,13 @@ const SirenInbox: FC<SirenProps> = ({
5955
onError,
6056
itemsPerFetch = 20,
6157
}) => {
62-
const notificationsPerPage =
63-
itemsPerFetch > MAXIMUM_ITEMS_PER_FETCH ? MAXIMUM_ITEMS_PER_FETCH : itemsPerFetch;
58+
const notificationsPerPage = Math.max(
59+
0,
60+
itemsPerFetch > MAXIMUM_ITEMS_PER_FETCH
61+
? MAXIMUM_ITEMS_PER_FETCH
62+
: itemsPerFetch
63+
);
64+
6465
const [isModalOpen, setIsModalOpen] = useState(false);
6566
const { siren } = useSirenContext();
6667
const iconRef = useRef<HTMLDivElement>(null);
@@ -158,20 +159,17 @@ const SirenInbox: FC<SirenProps> = ({
158159
data-testid="siren-panel"
159160
>
160161
<SirenPanel
161-
title={title}
162162
styles={styles}
163163
noOfNotificationsPerFetch={notificationsPerPage}
164-
hideHeader={hideHeader}
165164
hideBadge={hideBadge}
165+
inboxHeaderProps={inboxHeaderProps}
166166
cardProps={cardProps}
167167
customFooter={customFooter}
168-
customHeader={customHeader}
169168
customNotificationCard={customNotificationCard}
170169
onNotificationCardClick={onNotificationCardClick}
171170
onError={onError}
172171
listEmptyComponent={listEmptyComponent}
173172
fullScreen={windowViewOnly}
174-
hideClearAll={hideClearAll}
175173
customLoader={customLoader}
176174
loadMoreComponent={loadMoreComponent}
177175
darkMode={darkMode}

0 commit comments

Comments
 (0)