@dcl/hooks 1.1.1-20260129143559.commit-7ede5bb → 1.1.1-20260130165526.commit-e8ee72c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/esm/clients/index.d.ts +2 -0
- package/esm/clients/index.js +2 -0
- package/esm/clients/index.js.map +1 -0
- package/esm/clients/notifications/createNotificationsClient.d.ts +15 -0
- package/esm/clients/notifications/createNotificationsClient.js +55 -0
- package/esm/clients/notifications/createNotificationsClient.js.map +1 -0
- package/esm/clients/notifications/index.d.ts +2 -0
- package/esm/clients/notifications/index.js +2 -0
- package/esm/clients/notifications/index.js.map +1 -0
- package/esm/hooks/index.d.ts +2 -0
- package/esm/hooks/index.js +1 -0
- package/esm/hooks/index.js.map +1 -1
- package/esm/hooks/useNotifications/index.d.ts +3 -0
- package/esm/hooks/useNotifications/index.js +3 -0
- package/esm/hooks/useNotifications/index.js.map +1 -0
- package/esm/hooks/useNotifications/useNotifications.d.ts +12 -0
- package/esm/hooks/useNotifications/useNotifications.js +214 -0
- package/esm/hooks/useNotifications/useNotifications.js.map +1 -0
- package/esm/hooks/useNotifications/useNotifications.type.d.ts +47 -0
- package/esm/hooks/useNotifications/useNotifications.type.js +7 -0
- package/esm/hooks/useNotifications/useNotifications.type.js.map +1 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -1
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.js +2 -0
- package/esm/utils/index.js.map +1 -0
- package/esm/utils/storage.d.ts +39 -0
- package/esm/utils/storage.js +65 -0
- package/esm/utils/storage.js.map +1 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ npm install @dcl/hooks
|
|
|
21
21
|
- `useAsyncMemo`: Async version of useMemo
|
|
22
22
|
- `useInfiniteScroll`: Infinite scroll functionality for loading more content
|
|
23
23
|
- `useTranslation`: Simple and lightweight translation management
|
|
24
|
+
- `useNotifications`: Notification polling and modal state management
|
|
24
25
|
|
|
25
26
|
## Examples
|
|
26
27
|
|
|
@@ -703,6 +704,100 @@ function MyComponent() {
|
|
|
703
704
|
}
|
|
704
705
|
```
|
|
705
706
|
|
|
707
|
+
### useNotifications
|
|
708
|
+
|
|
709
|
+
The `useNotifications` hook manages notification polling, modal state, and onboarding flow. It uses Decentraland's notifications API by default.
|
|
710
|
+
|
|
711
|
+
Basic usage:
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
import { useNotifications } from '@dcl/hooks'
|
|
715
|
+
import type { AuthIdentity } from 'decentraland-crypto-fetch'
|
|
716
|
+
|
|
717
|
+
function NotificationsComponent() {
|
|
718
|
+
const identity: AuthIdentity = useAuthIdentity() // From your auth context
|
|
719
|
+
|
|
720
|
+
const {
|
|
721
|
+
notifications,
|
|
722
|
+
isLoading,
|
|
723
|
+
isModalOpen,
|
|
724
|
+
isNotificationsOnboarding,
|
|
725
|
+
handleNotificationsOpen,
|
|
726
|
+
handleOnBegin
|
|
727
|
+
} = useNotifications({
|
|
728
|
+
identity,
|
|
729
|
+
isNotificationsEnabled: !!identity,
|
|
730
|
+
notificationsUrl: 'https://notifications.decentraland.org' // or .zone for dev
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
if (isNotificationsOnboarding) {
|
|
734
|
+
return (
|
|
735
|
+
<div>
|
|
736
|
+
<h2>Welcome to Notifications!</h2>
|
|
737
|
+
<button onClick={handleOnBegin}>Get Started</button>
|
|
738
|
+
</div>
|
|
739
|
+
)
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return (
|
|
743
|
+
<div>
|
|
744
|
+
<button onClick={handleNotificationsOpen}>
|
|
745
|
+
Notifications ({notifications.filter(n => !n.read).length})
|
|
746
|
+
</button>
|
|
747
|
+
|
|
748
|
+
{isModalOpen && (
|
|
749
|
+
<ul>
|
|
750
|
+
{notifications.map(notification => (
|
|
751
|
+
<li key={notification.id}>
|
|
752
|
+
{notification.type} - {notification.read ? 'Read' : 'Unread'}
|
|
753
|
+
</li>
|
|
754
|
+
))}
|
|
755
|
+
</ul>
|
|
756
|
+
)}
|
|
757
|
+
</div>
|
|
758
|
+
)
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
With custom polling interval:
|
|
763
|
+
|
|
764
|
+
```typescript
|
|
765
|
+
const { notifications } = useNotifications({
|
|
766
|
+
identity,
|
|
767
|
+
isNotificationsEnabled: !!identity,
|
|
768
|
+
notificationsUrl: 'https://notifications.decentraland.org',
|
|
769
|
+
queryIntervalMs: 30000 // Poll every 30 seconds (default: 60000)
|
|
770
|
+
})
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
With notification type filtering:
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
const { notifications } = useNotifications({
|
|
777
|
+
identity,
|
|
778
|
+
isNotificationsEnabled: !!identity,
|
|
779
|
+
notificationsUrl: 'https://notifications.decentraland.org',
|
|
780
|
+
availableNotificationTypes: ['bid', 'sale', 'royalties']
|
|
781
|
+
})
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
With error handling:
|
|
785
|
+
|
|
786
|
+
`onError` is called when fetching fails, marking as read fails, or when
|
|
787
|
+
`notificationsUrl` is missing.
|
|
788
|
+
|
|
789
|
+
```typescript
|
|
790
|
+
const { notifications } = useNotifications({
|
|
791
|
+
identity,
|
|
792
|
+
isNotificationsEnabled: !!identity,
|
|
793
|
+
notificationsUrl: 'https://notifications.decentraland.org',
|
|
794
|
+
onError: (error) => {
|
|
795
|
+
console.error('Notification error:', error)
|
|
796
|
+
Sentry.captureException(error)
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
```
|
|
800
|
+
|
|
706
801
|
## License
|
|
707
802
|
|
|
708
803
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/clients/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NotificationsClient } from "../../hooks/useNotifications";
|
|
2
|
+
type NotificationsClientOptions = {
|
|
3
|
+
url: string;
|
|
4
|
+
limit?: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Creates a Decentraland notifications client.
|
|
8
|
+
*
|
|
9
|
+
* @param identity - The AuthIdentity for signing requests
|
|
10
|
+
* @param options - Configuration with required url
|
|
11
|
+
* @returns A NotificationsClient instance
|
|
12
|
+
*/
|
|
13
|
+
declare const createNotificationsClient: (identity: unknown, options: NotificationsClientOptions) => NotificationsClient;
|
|
14
|
+
export { createNotificationsClient };
|
|
15
|
+
export type { NotificationsClientOptions };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { signedFetchFactory, } from "decentraland-crypto-fetch";
|
|
2
|
+
const DEFAULT_NOTIFICATIONS_LIMIT = 50;
|
|
3
|
+
const parseNotification = (notification) => ({
|
|
4
|
+
...notification,
|
|
5
|
+
timestamp: Number(notification.timestamp),
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* Creates a Decentraland notifications client.
|
|
9
|
+
*
|
|
10
|
+
* @param identity - The AuthIdentity for signing requests
|
|
11
|
+
* @param options - Configuration with required url
|
|
12
|
+
* @returns A NotificationsClient instance
|
|
13
|
+
*/
|
|
14
|
+
const createNotificationsClient = (identity, options) => {
|
|
15
|
+
const authIdentity = identity;
|
|
16
|
+
const { url: baseUrl, limit = DEFAULT_NOTIFICATIONS_LIMIT } = options;
|
|
17
|
+
const signedFetch = signedFetchFactory();
|
|
18
|
+
const getNotifications = async () => {
|
|
19
|
+
const params = new URLSearchParams();
|
|
20
|
+
params.append("limit", String(limit));
|
|
21
|
+
const url = `${baseUrl}/notifications?${params.toString()}`;
|
|
22
|
+
const response = await signedFetch(url, {
|
|
23
|
+
identity: authIdentity,
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Failed to fetch notifications: ${response.status}`);
|
|
30
|
+
}
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
const notifications = data.notifications ?? [];
|
|
33
|
+
return notifications.map(parseNotification);
|
|
34
|
+
};
|
|
35
|
+
const markNotificationsAsRead = async (ids) => {
|
|
36
|
+
const url = `${baseUrl}/notifications/read`;
|
|
37
|
+
const response = await signedFetch(url, {
|
|
38
|
+
method: "PUT",
|
|
39
|
+
identity: authIdentity,
|
|
40
|
+
body: JSON.stringify({ notificationIds: ids }),
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`Failed to mark notifications as read: ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
getNotifications,
|
|
51
|
+
markNotificationsAsRead,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export { createNotificationsClient };
|
|
55
|
+
//# sourceMappingURL=createNotificationsClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createNotificationsClient.js","sourceRoot":"","sources":["../../../src/clients/notifications/createNotificationsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,GACnB,MAAM,2BAA2B,CAAA;AAMlC,MAAM,2BAA2B,GAAG,EAAE,CAAA;AAWtC,MAAM,iBAAiB,GAAG,CACxB,YAAkC,EAChB,EAAE,CAAC,CAAC;IACtB,GAAG,YAAY;IACf,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC;CAC1C,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,MAAM,yBAAyB,GAAG,CAChC,QAAiB,EACjB,OAAmC,EACd,EAAE;IACvB,MAAM,YAAY,GAAG,QAAwB,CAAA;IAC7C,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,GAAG,2BAA2B,EAAE,GAAG,OAAO,CAAA;IACrE,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;IAExC,MAAM,gBAAgB,GAAG,KAAK,IAAiC,EAAE;QAC/D,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;QACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAErC,MAAM,GAAG,GAAG,GAAG,OAAO,kBAAkB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAA;QAC3D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE;YACtC,QAAQ,EAAE,YAAY;YACtB,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QACtE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAClC,MAAM,aAAa,GAA2B,IAAI,CAAC,aAAa,IAAI,EAAE,CAAA;QAEtE,OAAO,aAAa,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAC7C,CAAC,CAAA;IAED,MAAM,uBAAuB,GAAG,KAAK,EAAE,GAAa,EAAiB,EAAE;QACrE,MAAM,GAAG,GAAG,GAAG,OAAO,qBAAqB,CAAA;QAC3C,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE;YACtC,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,YAAY;YACtB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;YAC9C,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,yCAAyC,QAAQ,CAAC,MAAM,EAAE,CAC3D,CAAA;QACH,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,gBAAgB;QAChB,uBAAuB;KACxB,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/clients/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA"}
|
package/esm/hooks/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type { AdvancedNavigatorUAData } from "./useAdvancedUserAgentData";
|
|
|
2
2
|
export type { AsyncMemoResult, AsyncMemoResultState } from "./useAsyncMemo";
|
|
3
3
|
export type { AsyncStateResult, AsyncStateResultState } from "./useAsyncState";
|
|
4
4
|
export type { UseInfiniteScrollOptions } from "./useInfiniteScroll";
|
|
5
|
+
export type { NotificationItem, NotificationsClient, NotificationsState, NotificationsUIState, UseNotificationsOptions, UseNotificationsResult, } from "./useNotifications";
|
|
5
6
|
export type { Translations, LanguageTranslations, TranslationState, TranslationOptions, TranslationResult, } from "./useTranslation";
|
|
6
7
|
export { useAdvancedUserAgentData } from "./useAdvancedUserAgentData";
|
|
7
8
|
export { useAnalytics } from "./useAnalytics";
|
|
@@ -11,6 +12,7 @@ export { useAsyncState, createAsyncStateState } from "./useAsyncState";
|
|
|
11
12
|
export { useAsyncTask } from "./useAsyncTask";
|
|
12
13
|
export { useAsyncTasks } from "./useAsyncTasks";
|
|
13
14
|
export { useInfiniteScroll } from "./useInfiniteScroll";
|
|
15
|
+
export { checkIsOnboarding, setOnboardingDone, useNotifications, } from "./useNotifications";
|
|
14
16
|
export { usePageTracking } from "./usePageTracking";
|
|
15
17
|
export { usePatchState } from "./usePatchState";
|
|
16
18
|
export { useTranslation } from "./useTranslation";
|
package/esm/hooks/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { useAsyncState, createAsyncStateState } from "./useAsyncState";
|
|
|
7
7
|
export { useAsyncTask } from "./useAsyncTask";
|
|
8
8
|
export { useAsyncTasks } from "./useAsyncTasks";
|
|
9
9
|
export { useInfiniteScroll } from "./useInfiniteScroll";
|
|
10
|
+
export { checkIsOnboarding, setOnboardingDone, useNotifications, } from "./useNotifications";
|
|
10
11
|
export { usePageTracking } from "./usePageTracking";
|
|
11
12
|
export { usePatchState } from "./usePatchState";
|
|
12
13
|
export { useTranslation } from "./useTranslation";
|
package/esm/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAqBA,QAAQ;AACR,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { checkIsOnboarding, setOnboardingDone, useNotifications, } from "./useNotifications";
|
|
2
|
+
export { NotificationActiveTab } from "./useNotifications.type";
|
|
3
|
+
export type { NotificationItem, NotificationsClient, NotificationsState, NotificationsUIState, UseNotificationsOptions, UseNotificationsResult, } from "./useNotifications.type";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/hooks/useNotifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UseNotificationsOptions, UseNotificationsResult } from "./useNotifications.type";
|
|
2
|
+
declare const checkIsOnboarding: () => boolean;
|
|
3
|
+
declare const setOnboardingDone: () => void;
|
|
4
|
+
/**
|
|
5
|
+
* Hook to manage notification polling and modal state.
|
|
6
|
+
* Uses Decentraland's notifications API.
|
|
7
|
+
*
|
|
8
|
+
* @param options - Configuration options for notifications polling and UI state.
|
|
9
|
+
* @returns Notifications state, modal state, and handlers.
|
|
10
|
+
*/
|
|
11
|
+
declare const useNotifications: (options: UseNotificationsOptions) => UseNotificationsResult;
|
|
12
|
+
export { checkIsOnboarding, setOnboardingDone, useNotifications };
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { NotificationActiveTab, } from "./useNotifications.type";
|
|
3
|
+
import { createNotificationsClient } from "../../clients/notifications";
|
|
4
|
+
import { getStorageItem, setStorageItem } from "../../utils/storage";
|
|
5
|
+
const DEFAULT_QUERY_INTERVAL_MS = 60000;
|
|
6
|
+
const ONBOARDING_KEY = "dcl_notifications_onboarding";
|
|
7
|
+
const checkIsOnboarding = () => {
|
|
8
|
+
const value = getStorageItem(ONBOARDING_KEY, null);
|
|
9
|
+
if (value === null) {
|
|
10
|
+
setStorageItem(ONBOARDING_KEY, true);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
const setOnboardingDone = () => {
|
|
16
|
+
setStorageItem(ONBOARDING_KEY, false);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Hook to manage notification polling and modal state.
|
|
20
|
+
* Uses Decentraland's notifications API.
|
|
21
|
+
*
|
|
22
|
+
* @param options - Configuration options for notifications polling and UI state.
|
|
23
|
+
* @returns Notifications state, modal state, and handlers.
|
|
24
|
+
*/
|
|
25
|
+
const useNotifications = (options) => {
|
|
26
|
+
const { identity, isNotificationsEnabled, notificationsUrl, availableNotificationTypes, queryIntervalMs = DEFAULT_QUERY_INTERVAL_MS, initialActiveTab = NotificationActiveTab.NEWEST, onError, renderProfile, } = options;
|
|
27
|
+
const [notificationsState, setNotificationsState] = useState({
|
|
28
|
+
isLoading: false,
|
|
29
|
+
notifications: [],
|
|
30
|
+
});
|
|
31
|
+
const [uiState, setUiState] = useState(() => ({
|
|
32
|
+
activeTab: initialActiveTab,
|
|
33
|
+
isOnboarding: checkIsOnboarding(),
|
|
34
|
+
isOpen: false,
|
|
35
|
+
}));
|
|
36
|
+
const [notificationsClient, setNotificationsClient] = useState(null);
|
|
37
|
+
const notificationsRef = useRef([]);
|
|
38
|
+
const notificationsClientRef = useRef(null);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
notificationsRef.current = notificationsState.notifications;
|
|
41
|
+
}, [notificationsState.notifications]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
notificationsClientRef.current = notificationsClient;
|
|
44
|
+
}, [notificationsClient]);
|
|
45
|
+
const availableNotifications = useMemo(() => {
|
|
46
|
+
if (!availableNotificationTypes) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return new Set(availableNotificationTypes);
|
|
50
|
+
}, [availableNotificationTypes]);
|
|
51
|
+
const fetchAndUpdateNotifications = useCallback((client) => {
|
|
52
|
+
return Promise.resolve()
|
|
53
|
+
.then(() => client.getNotifications())
|
|
54
|
+
.then((notificationsFetched) => {
|
|
55
|
+
const filteredNotifications = availableNotifications
|
|
56
|
+
? notificationsFetched.filter((notification) => availableNotifications.has(notification.type))
|
|
57
|
+
: notificationsFetched;
|
|
58
|
+
const hasReadNotifications = filteredNotifications.some((notification) => notification.read);
|
|
59
|
+
setNotificationsState((prevState) => ({
|
|
60
|
+
...prevState,
|
|
61
|
+
isLoading: false,
|
|
62
|
+
notifications: filteredNotifications,
|
|
63
|
+
}));
|
|
64
|
+
if (hasReadNotifications) {
|
|
65
|
+
setOnboardingDone();
|
|
66
|
+
setUiState((prevState) => prevState.isOnboarding
|
|
67
|
+
? { ...prevState, isOnboarding: false }
|
|
68
|
+
: prevState);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.catch((error) => {
|
|
72
|
+
const normalizedError = error instanceof Error ? error : new Error("Unknown error");
|
|
73
|
+
console.error("Error fetching notifications:", normalizedError);
|
|
74
|
+
if (onError) {
|
|
75
|
+
onError(normalizedError);
|
|
76
|
+
}
|
|
77
|
+
setNotificationsState((prevState) => ({
|
|
78
|
+
...prevState,
|
|
79
|
+
isLoading: false,
|
|
80
|
+
}));
|
|
81
|
+
});
|
|
82
|
+
}, [availableNotifications, onError]);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (!identity) {
|
|
85
|
+
setNotificationsClient(null);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (!notificationsUrl) {
|
|
89
|
+
const normalizedError = new Error("notificationsUrl is required");
|
|
90
|
+
console.error("Notifications URL missing:", normalizedError);
|
|
91
|
+
if (onError) {
|
|
92
|
+
onError(normalizedError);
|
|
93
|
+
}
|
|
94
|
+
setNotificationsClient(null);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const client = createNotificationsClient(identity, {
|
|
98
|
+
url: notificationsUrl,
|
|
99
|
+
});
|
|
100
|
+
setNotificationsClient(client);
|
|
101
|
+
if (!isNotificationsEnabled) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let cancelled = false;
|
|
105
|
+
setNotificationsState((prevState) => ({
|
|
106
|
+
...prevState,
|
|
107
|
+
isLoading: true,
|
|
108
|
+
}));
|
|
109
|
+
const pollNotifications = () => {
|
|
110
|
+
if (cancelled) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
fetchAndUpdateNotifications(client);
|
|
114
|
+
};
|
|
115
|
+
pollNotifications();
|
|
116
|
+
const intervalId = setInterval(pollNotifications, queryIntervalMs);
|
|
117
|
+
return () => {
|
|
118
|
+
cancelled = true;
|
|
119
|
+
clearInterval(intervalId);
|
|
120
|
+
};
|
|
121
|
+
}, [
|
|
122
|
+
identity,
|
|
123
|
+
isNotificationsEnabled,
|
|
124
|
+
notificationsUrl,
|
|
125
|
+
onError,
|
|
126
|
+
fetchAndUpdateNotifications,
|
|
127
|
+
queryIntervalMs,
|
|
128
|
+
]);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const isClosing = !uiState.isOpen;
|
|
131
|
+
if (!isClosing) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const currentNotifications = notificationsRef.current;
|
|
135
|
+
const currentClient = notificationsClientRef.current;
|
|
136
|
+
if (!currentClient) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const unreadNotificationsIds = currentNotifications
|
|
140
|
+
.filter((notification) => !notification.read)
|
|
141
|
+
.map((notification) => notification.id);
|
|
142
|
+
if (unreadNotificationsIds.length === 0) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let cancelled = false;
|
|
146
|
+
Promise.resolve()
|
|
147
|
+
.then(() => currentClient.markNotificationsAsRead(unreadNotificationsIds))
|
|
148
|
+
.then(() => {
|
|
149
|
+
if (cancelled) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
setNotificationsState((prevState) => ({
|
|
153
|
+
...prevState,
|
|
154
|
+
notifications: prevState.notifications.map((notification) => ({
|
|
155
|
+
...notification,
|
|
156
|
+
read: unreadNotificationsIds.includes(notification.id)
|
|
157
|
+
? true
|
|
158
|
+
: notification.read,
|
|
159
|
+
})),
|
|
160
|
+
}));
|
|
161
|
+
})
|
|
162
|
+
.catch((error) => {
|
|
163
|
+
if (cancelled) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const normalizedError = error instanceof Error ? error : new Error("Unknown error");
|
|
167
|
+
console.error("Error marking notifications as read:", normalizedError);
|
|
168
|
+
if (onError) {
|
|
169
|
+
onError(normalizedError);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
return () => {
|
|
173
|
+
cancelled = true;
|
|
174
|
+
};
|
|
175
|
+
}, [uiState.isOpen, onError]);
|
|
176
|
+
const handleOnBegin = useCallback(() => {
|
|
177
|
+
setOnboardingDone();
|
|
178
|
+
setUiState((prevState) => ({
|
|
179
|
+
...prevState,
|
|
180
|
+
isOnboarding: false,
|
|
181
|
+
}));
|
|
182
|
+
}, []);
|
|
183
|
+
const handleNotificationsOpen = useCallback(() => {
|
|
184
|
+
setUiState((prevState) => ({
|
|
185
|
+
...prevState,
|
|
186
|
+
isOpen: !prevState.isOpen,
|
|
187
|
+
}));
|
|
188
|
+
}, []);
|
|
189
|
+
const handleOnChangeModalTab = useCallback((tab) => {
|
|
190
|
+
setUiState((prevState) => ({
|
|
191
|
+
...prevState,
|
|
192
|
+
activeTab: tab,
|
|
193
|
+
}));
|
|
194
|
+
}, []);
|
|
195
|
+
const handleRenderProfile = useCallback((address) => {
|
|
196
|
+
if (!renderProfile) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
return renderProfile(address);
|
|
200
|
+
}, [renderProfile]);
|
|
201
|
+
return {
|
|
202
|
+
notifications: notificationsState.notifications,
|
|
203
|
+
isLoading: notificationsState.isLoading,
|
|
204
|
+
isModalOpen: uiState.isOpen,
|
|
205
|
+
modalActiveTab: uiState.activeTab,
|
|
206
|
+
isNotificationsOnboarding: uiState.isOnboarding,
|
|
207
|
+
handleOnBegin,
|
|
208
|
+
handleNotificationsOpen,
|
|
209
|
+
handleOnChangeModalTab,
|
|
210
|
+
handleRenderProfile,
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
export { checkIsOnboarding, setOnboardingDone, useNotifications };
|
|
214
|
+
//# sourceMappingURL=useNotifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNotifications.js","sourceRoot":"","sources":["../../../src/hooks/useNotifications/useNotifications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
declare enum NotificationActiveTab {
|
|
3
|
+
NEWEST = "newest",
|
|
4
|
+
READ = "read"
|
|
5
|
+
}
|
|
6
|
+
type NotificationItem = {
|
|
7
|
+
id: string;
|
|
8
|
+
type: string;
|
|
9
|
+
read: boolean;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
type NotificationsClient = {
|
|
13
|
+
getNotifications: () => Promise<NotificationItem[]>;
|
|
14
|
+
markNotificationsAsRead: (ids: string[]) => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
type NotificationsState = {
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
notifications: NotificationItem[];
|
|
19
|
+
};
|
|
20
|
+
type NotificationsUIState = {
|
|
21
|
+
activeTab: string;
|
|
22
|
+
isOnboarding: boolean;
|
|
23
|
+
isOpen: boolean;
|
|
24
|
+
};
|
|
25
|
+
type UseNotificationsOptions = {
|
|
26
|
+
identity?: unknown;
|
|
27
|
+
isNotificationsEnabled: boolean;
|
|
28
|
+
notificationsUrl: string;
|
|
29
|
+
availableNotificationTypes?: string[];
|
|
30
|
+
queryIntervalMs?: number;
|
|
31
|
+
initialActiveTab?: string;
|
|
32
|
+
onError?: (error: Error) => void;
|
|
33
|
+
renderProfile?: (address: string) => ReactNode;
|
|
34
|
+
};
|
|
35
|
+
type UseNotificationsResult = {
|
|
36
|
+
notifications: NotificationItem[];
|
|
37
|
+
isLoading: boolean;
|
|
38
|
+
isModalOpen: boolean;
|
|
39
|
+
modalActiveTab: string;
|
|
40
|
+
isNotificationsOnboarding: boolean;
|
|
41
|
+
handleOnBegin: () => void;
|
|
42
|
+
handleNotificationsOpen: () => void;
|
|
43
|
+
handleOnChangeModalTab: (tab: string) => void;
|
|
44
|
+
handleRenderProfile: (address: string) => ReactNode;
|
|
45
|
+
};
|
|
46
|
+
export { NotificationActiveTab };
|
|
47
|
+
export type { NotificationItem, NotificationsClient, NotificationsState, NotificationsUIState, UseNotificationsOptions, UseNotificationsResult, };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var NotificationActiveTab;
|
|
2
|
+
(function (NotificationActiveTab) {
|
|
3
|
+
NotificationActiveTab["NEWEST"] = "newest";
|
|
4
|
+
NotificationActiveTab["READ"] = "read";
|
|
5
|
+
})(NotificationActiveTab || (NotificationActiveTab = {}));
|
|
6
|
+
export { NotificationActiveTab };
|
|
7
|
+
//# sourceMappingURL=useNotifications.type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNotifications.type.js","sourceRoot":"","sources":["../../../src/hooks/useNotifications/useNotifications.type.ts"],"names":[],"mappings":"AAEA,IAAK,qBAGJ;AAHD,WAAK,qBAAqB;IACxB,0CAAiB,CAAA;IACjB,sCAAa,CAAA;AACf,CAAC,EAHI,qBAAqB,KAArB,qBAAqB,QAGzB;AAgDD,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
|
package/esm/index.d.ts
CHANGED
package/esm/index.js
CHANGED
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getStorageItem, removeStorageItem, setStorageItem } from "./storage";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves and parses a JSON value from localStorage.
|
|
3
|
+
* Returns the fallback value if the key doesn't exist, parsing fails,
|
|
4
|
+
* or localStorage throws an error.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The expected type of the stored value
|
|
7
|
+
* @param key - The localStorage key to retrieve
|
|
8
|
+
* @param fallback - The value to return if retrieval fails
|
|
9
|
+
* @returns The parsed value or the fallback
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const isEnabled = getStorageItem<boolean>('feature_enabled', false)
|
|
13
|
+
* const user = getStorageItem<User | null>('current_user', null)
|
|
14
|
+
*/
|
|
15
|
+
declare const getStorageItem: <T>(key: string, fallback: T) => T;
|
|
16
|
+
/**
|
|
17
|
+
* Stores a value in localStorage as JSON.
|
|
18
|
+
* Silently fails if localStorage throws an error.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of the value to store
|
|
21
|
+
* @param key - The localStorage key
|
|
22
|
+
* @param value - The value to store (will be JSON stringified)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* setStorageItem('feature_enabled', true)
|
|
26
|
+
* setStorageItem('current_user', { id: 1, name: 'John' })
|
|
27
|
+
*/
|
|
28
|
+
declare const setStorageItem: <T>(key: string, value: T) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Removes a key from localStorage.
|
|
31
|
+
* Silently fails if localStorage throws an error.
|
|
32
|
+
*
|
|
33
|
+
* @param key - The localStorage key to remove
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* removeStorageItem('current_user')
|
|
37
|
+
*/
|
|
38
|
+
declare const removeStorageItem: (key: string) => void;
|
|
39
|
+
export { getStorageItem, removeStorageItem, setStorageItem };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves and parses a JSON value from localStorage.
|
|
3
|
+
* Returns the fallback value if the key doesn't exist, parsing fails,
|
|
4
|
+
* or localStorage throws an error.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The expected type of the stored value
|
|
7
|
+
* @param key - The localStorage key to retrieve
|
|
8
|
+
* @param fallback - The value to return if retrieval fails
|
|
9
|
+
* @returns The parsed value or the fallback
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const isEnabled = getStorageItem<boolean>('feature_enabled', false)
|
|
13
|
+
* const user = getStorageItem<User | null>('current_user', null)
|
|
14
|
+
*/
|
|
15
|
+
const getStorageItem = (key, fallback) => {
|
|
16
|
+
try {
|
|
17
|
+
const value = localStorage.getItem(key);
|
|
18
|
+
if (value === null) {
|
|
19
|
+
return fallback;
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Stores a value in localStorage as JSON.
|
|
29
|
+
* Silently fails if localStorage throws an error.
|
|
30
|
+
*
|
|
31
|
+
* @template T - The type of the value to store
|
|
32
|
+
* @param key - The localStorage key
|
|
33
|
+
* @param value - The value to store (will be JSON stringified)
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* setStorageItem('feature_enabled', true)
|
|
37
|
+
* setStorageItem('current_user', { id: 1, name: 'John' })
|
|
38
|
+
*/
|
|
39
|
+
const setStorageItem = (key, value) => {
|
|
40
|
+
try {
|
|
41
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Ignore storage errors
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Removes a key from localStorage.
|
|
49
|
+
* Silently fails if localStorage throws an error.
|
|
50
|
+
*
|
|
51
|
+
* @param key - The localStorage key to remove
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* removeStorageItem('current_user')
|
|
55
|
+
*/
|
|
56
|
+
const removeStorageItem = (key) => {
|
|
57
|
+
try {
|
|
58
|
+
localStorage.removeItem(key);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore storage errors
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export { getStorageItem, removeStorageItem, setStorageItem };
|
|
65
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,cAAc,GAAG,CAAI,GAAW,EAAE,QAAW,EAAK,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAA;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,cAAc,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAQ,EAAE;IACxD,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAQ,EAAE;IAC9C,IAAI,CAAC;QACH,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC,CAAA;AAED,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/hooks",
|
|
3
|
-
"version": "1.1.1-
|
|
3
|
+
"version": "1.1.1-20260130165526.commit-e8ee72c",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "esm/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"test:coverage": "npm run test -- --coverage"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
+
"decentraland-crypto-fetch": "^2.0.1",
|
|
22
23
|
"react": "^18.0.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
"@types/ua-parser-js": "^0.7.39",
|
|
31
32
|
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
|
32
33
|
"@typescript-eslint/parser": "^7.15.0",
|
|
34
|
+
"decentraland-crypto-fetch": "^2.0.1",
|
|
33
35
|
"eslint": "^8.57.0",
|
|
34
36
|
"eslint-config-prettier": "^9.1.0",
|
|
35
37
|
"eslint-import-resolver-jest": "^3.0.2",
|
|
@@ -78,5 +80,5 @@
|
|
|
78
80
|
"<rootDir>/test/setup.ts"
|
|
79
81
|
]
|
|
80
82
|
},
|
|
81
|
-
"commit": "
|
|
83
|
+
"commit": "e8ee72cf8c4f5342c8da501151fad8310c495ad5"
|
|
82
84
|
}
|