@rango-dev/widget-embedded 0.28.3-next.0 → 0.28.3-next.2

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.
Files changed (38) hide show
  1. package/dist/components/HeaderButtons/HeaderButtons.d.ts.map +1 -1
  2. package/dist/components/HeaderButtons/NotificationsBadge.d.ts +3 -0
  3. package/dist/components/HeaderButtons/NotificationsBadge.d.ts.map +1 -0
  4. package/dist/components/NotificationContent/NotificationContent.d.ts.map +1 -1
  5. package/dist/components/NotificationContent/NotificationContent.styles.d.ts +769 -0
  6. package/dist/components/NotificationContent/NotificationContent.styles.d.ts.map +1 -1
  7. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  8. package/dist/hooks/useBootstrap/useBootstrap.d.ts.map +1 -1
  9. package/dist/hooks/useSyncNotifications/index.d.ts +2 -0
  10. package/dist/hooks/useSyncNotifications/index.d.ts.map +1 -0
  11. package/dist/hooks/useSyncNotifications/useSyncNotifications.d.ts +2 -0
  12. package/dist/hooks/useSyncNotifications/useSyncNotifications.d.ts.map +1 -0
  13. package/dist/hooks/useWalletList.d.ts.map +1 -1
  14. package/dist/index.js +2 -2
  15. package/dist/index.js.map +4 -4
  16. package/dist/store/notification.d.ts +27 -7
  17. package/dist/store/notification.d.ts.map +1 -1
  18. package/dist/types/notification.d.ts +0 -1
  19. package/dist/types/notification.d.ts.map +1 -1
  20. package/dist/utils/swap.d.ts +2 -0
  21. package/dist/utils/swap.d.ts.map +1 -1
  22. package/dist/widget-embedded.build.json +1 -0
  23. package/package.json +2 -2
  24. package/src/components/HeaderButtons/HeaderButtons.tsx +3 -2
  25. package/src/components/HeaderButtons/{UnreadNotificationsBadge.tsx → NotificationsBadge.tsx} +3 -3
  26. package/src/components/NotificationContent/NotificationContent.styles.ts +17 -2
  27. package/src/components/NotificationContent/NotificationContent.tsx +28 -3
  28. package/src/components/SwapDetails/SwapDetails.tsx +5 -6
  29. package/src/containers/WidgetInfo/WidgetInfo.tsx +1 -1
  30. package/src/hooks/useBootstrap/useBootstrap.ts +2 -0
  31. package/src/hooks/useSyncNotifications/index.ts +1 -0
  32. package/src/hooks/useSyncNotifications/useSyncNotifications.ts +25 -0
  33. package/src/hooks/useWalletList.ts +7 -4
  34. package/src/store/notification.ts +62 -17
  35. package/src/types/notification.ts +0 -1
  36. package/src/utils/swap.ts +12 -0
  37. package/dist/components/HeaderButtons/UnreadNotificationsBadge.d.ts +0 -3
  38. package/dist/components/HeaderButtons/UnreadNotificationsBadge.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rango-dev/widget-embedded",
3
- "version": "0.28.3-next.0",
3
+ "version": "0.28.3-next.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "source": "./src/index.ts",
@@ -25,7 +25,7 @@
25
25
  "@lingui/core": "4.2.1",
26
26
  "@lingui/react": "4.2.1",
27
27
  "@rango-dev/logging-core": "^0.3.1-next.1",
28
- "@rango-dev/provider-all": "^0.33.3-next.0",
28
+ "@rango-dev/provider-all": "^0.33.3-next.1",
29
29
  "@rango-dev/queue-manager-core": "^0.26.0",
30
30
  "@rango-dev/queue-manager-rango-preset": "^0.33.3-next.0",
31
31
  "@rango-dev/queue-manager-react": "^0.26.0",
@@ -17,8 +17,8 @@ import { NotificationContent } from '../NotificationContent';
17
17
 
18
18
  import { HeaderButton } from './HeaderButtons.styles';
19
19
  import InProgressTransactionBadge from './InProgressTransactionBadge';
20
+ import { NotificationsBadge } from './NotificationsBadge';
20
21
  import { RefreshButton } from './RefreshButton';
21
- import { UnreadNotificationsBadge } from './UnreadNotificationsBadge';
22
22
 
23
23
  export function HeaderButtons(props: HeaderButtonsPropTypes) {
24
24
  const {
@@ -52,6 +52,7 @@ export function HeaderButtons(props: HeaderButtonsPropTypes) {
52
52
  <Popover
53
53
  align="end"
54
54
  alignOffset={-88}
55
+ sideOffset={15}
55
56
  collisionPadding={{ right: 20, left: 20 }}
56
57
  container={getContainer()}
57
58
  content={<NotificationContent />}>
@@ -62,7 +63,7 @@ export function HeaderButtons(props: HeaderButtonsPropTypes) {
62
63
  content={i18n.t('Notifications')}>
63
64
  <HeaderButton size="small" variant="ghost">
64
65
  <NotificationsIcon size={18} color="black" />
65
- <UnreadNotificationsBadge />
66
+ <NotificationsBadge />
66
67
  </HeaderButton>
67
68
  </Tooltip>
68
69
  </div>
@@ -6,10 +6,10 @@ import { useNotificationStore } from '../../store/notification';
6
6
 
7
7
  import { NotificationsBadgeContainer } from './HeaderButtons.styles';
8
8
 
9
- export function UnreadNotificationsBadge() {
10
- const { getUnreadNotifications } = useNotificationStore();
9
+ export function NotificationsBadge() {
10
+ const { getNotifications } = useNotificationStore();
11
11
 
12
- const notificationsList = getUnreadNotifications();
12
+ const notificationsList = getNotifications();
13
13
 
14
14
  const notificationsCount = notificationsList.length;
15
15
 
@@ -1,4 +1,4 @@
1
- import { darkTheme, ListItemButton, styled } from '@rango-dev/ui';
1
+ import { Button, darkTheme, ListItemButton, styled } from '@rango-dev/ui';
2
2
 
3
3
  export const Container = styled('div', {
4
4
  padding: '$10',
@@ -7,6 +7,17 @@ export const Container = styled('div', {
7
7
  minHeight: '150px',
8
8
  });
9
9
 
10
+ export const Header = styled('div', {
11
+ padding: '0 $10',
12
+ display: 'flex',
13
+ justifyContent: 'space-between',
14
+ alignItems: 'center',
15
+ });
16
+
17
+ export const ClearAllButton = styled(Button, {
18
+ padding: '$5 !important',
19
+ });
20
+
10
21
  export const List = styled('ul', {
11
22
  padding: 0,
12
23
  margin: 0,
@@ -32,7 +43,7 @@ export const ListItem = styled(ListItemButton, {
32
43
 
33
44
  export const Images = styled('div', {
34
45
  display: 'flex',
35
- padding: 0,
46
+ padding: '0 0 0 $5',
36
47
  alignItems: 'center',
37
48
  alignSelf: 'stretch',
38
49
  });
@@ -46,3 +57,7 @@ export const NotFoundContainer = styled('div', {
46
57
  width: '100%',
47
58
  height: '150px',
48
59
  });
60
+
61
+ export const IconContainer = styled('span', {
62
+ paddingRight: '$8',
63
+ });
@@ -17,7 +17,10 @@ import { useNotificationStore } from '../../store/notification';
17
17
  import { areTokensEqual } from '../../utils/wallets';
18
18
 
19
19
  import {
20
+ ClearAllButton,
20
21
  Container,
22
+ Header,
23
+ IconContainer,
21
24
  Images,
22
25
  List,
23
26
  ListItem,
@@ -29,9 +32,9 @@ const MAX_NOTIFICATIONS_DISPLAYED = 4;
29
32
  export function NotificationContent() {
30
33
  const navigate = useNavigate();
31
34
 
32
- const { getUnreadNotifications } = useNotificationStore();
35
+ const { getNotifications, clearNotifications } = useNotificationStore();
33
36
 
34
- const notifications: Notification[] = getUnreadNotifications();
37
+ const notifications: Notification[] = getNotifications();
35
38
  const blockchains = useAppStore().blockchains();
36
39
  const tokens = useAppStore().tokens();
37
40
  const sortedNotification = notifications
@@ -44,6 +47,24 @@ export function NotificationContent() {
44
47
 
45
48
  return (
46
49
  <Container>
50
+ {sortedNotification.length > 0 && (
51
+ <>
52
+ <Header>
53
+ <Typography variant="label" size="medium">
54
+ {i18n.t('Notifications')}
55
+ </Typography>
56
+ <ClearAllButton
57
+ variant="ghost"
58
+ size="xsmall"
59
+ onClick={clearNotifications}>
60
+ <Typography variant="body" size="xsmall">
61
+ {i18n.t('Clear all')}
62
+ </Typography>
63
+ </ClearAllButton>
64
+ </Header>
65
+ <Divider direction="vertical" size={4} />
66
+ </>
67
+ )}
47
68
  {sortedNotification.length ? (
48
69
  <List>
49
70
  {sortedNotification.map((notificationItem, index) => {
@@ -103,7 +124,11 @@ export function NotificationContent() {
103
124
  </div>
104
125
  </Images>
105
126
  }
106
- end={<ChevronRightIcon size={12} color="gray" />}
127
+ end={
128
+ <IconContainer>
129
+ <ChevronRightIcon size={12} color="gray" />
130
+ </IconContainer>
131
+ }
107
132
  />
108
133
  </React.Fragment>
109
134
  );
@@ -96,21 +96,20 @@ export function SwapDetails(props: SwapDetailsProps) {
96
96
  setModalState(null);
97
97
  };
98
98
 
99
- const getUnreadNotifications =
100
- useNotificationStore.use.getUnreadNotifications();
101
- const setAsRead = useNotificationStore.use.setAsRead();
102
- const unreadNotifications = getUnreadNotifications();
99
+ const getNotifications = useNotificationStore.use.getNotifications();
100
+ const removeNotification = useNotificationStore.use.removeNotification();
101
+ const notifications = getNotifications();
103
102
  const currentStep = getCurrentStep(swap);
104
103
  const currentStepNetworkStatus = currentStep?.networkStatus;
105
104
 
106
105
  useEffect(() => {
107
- const existNotification = unreadNotifications.find(
106
+ const existNotification = notifications.find(
108
107
  (n) => n.requestId === swap.requestId
109
108
  );
110
109
  if (existNotification) {
111
110
  if (swap.status === 'success' || swap.status === 'failed') {
112
111
  setShowCompletedModal(swap.status);
113
- setAsRead(swap.requestId);
112
+ removeNotification(swap.requestId);
114
113
  } else if (showCompletedModal) {
115
114
  setShowCompletedModal(null);
116
115
  }
@@ -31,7 +31,7 @@ export function WidgetInfo(props: React.PropsWithChildren) {
31
31
  const swappers = useAppStore().swappers();
32
32
  const loadingStatus = useAppStore().fetchStatus;
33
33
  const resetLanguage = useLanguage().resetLanguage;
34
- const notifications = useNotificationStore().getUnreadNotifications();
34
+ const notifications = useNotificationStore().getNotifications();
35
35
 
36
36
  // eslint-disable-next-line react/jsx-no-constructed-context-values
37
37
  const value: WidgetInfoContextInterface = {
@@ -14,11 +14,13 @@ import { tabManager } from '../../store/ui';
14
14
  import { useFetchApiConfig } from '../useFetchApiConfig';
15
15
  import { useForceAutoConnect } from '../useForceAutoConnect';
16
16
  import { useSubscribeToWidgetEvents } from '../useSubscribeToWidgetEvents';
17
+ import { useSyncNotifications } from '../useSyncNotifications';
17
18
 
18
19
  export function useBootstrap() {
19
20
  useForceAutoConnect();
20
21
  globalFont();
21
22
  useSubscribeToWidgetEvents();
23
+ useSyncNotifications();
22
24
  const blockchains = useAppStore().blockchains();
23
25
  const { canSwitchNetworkTo } = useWallets();
24
26
  const [lastConnectedWalletWithNetwork, setLastConnectedWalletWithNetwork] =
@@ -0,0 +1 @@
1
+ export { useSyncNotifications } from './useSyncNotifications';
@@ -0,0 +1,25 @@
1
+ import { useManager } from '@rango-dev/queue-manager-react';
2
+ import { useEffect } from 'react';
3
+
4
+ import { useNotificationStore } from '../../store/notification';
5
+ import { getPendingSwaps } from '../../utils/queue';
6
+
7
+ export function useSyncNotifications() {
8
+ const { isSynced, syncNotifications } = useNotificationStore();
9
+ const { manager, state } = useManager();
10
+
11
+ useEffect(() => {
12
+ const shouldSyncNotifications =
13
+ useNotificationStore.persist.hasHydrated() &&
14
+ state.loadedFromPersistor &&
15
+ !isSynced;
16
+
17
+ if (shouldSyncNotifications) {
18
+ syncNotifications(getPendingSwaps(manager));
19
+ }
20
+ }, [
21
+ useNotificationStore.persist.hasHydrated(),
22
+ state.loadedFromPersistor,
23
+ isSynced,
24
+ ]);
25
+ }
@@ -56,7 +56,8 @@ export function useWalletList(params: Params) {
56
56
 
57
57
  wallets = detectMobileScreens()
58
58
  ? wallets.filter(
59
- (wallet) => wallet.showOnMobile || state(wallet.type).installed
59
+ (wallet) =>
60
+ wallet.showOnMobile !== false && state(wallet.type).installed
60
61
  )
61
62
  : wallets;
62
63
 
@@ -137,9 +138,11 @@ export function useWalletList(params: Params) {
137
138
  const isEvmWalletInstalledExceptDefault = wallets.filter(
138
139
  (wallet) =>
139
140
  wallet.state != WalletState.NOT_INSTALLED &&
140
- ![WalletTypes.DEFAULT, WalletTypes.WALLET_CONNECT_2].includes(
141
- wallet.type as WalletTypes
142
- ) &&
141
+ ![
142
+ WalletTypes.DEFAULT,
143
+ WalletTypes.WALLET_CONNECT_2,
144
+ WalletTypes.LEDGER,
145
+ ].includes(wallet.type as WalletTypes) &&
143
146
  getWalletInfo(wallet.type).supportedChains.filter(
144
147
  (blockchain) => blockchain.type == 'EVM'
145
148
  ).length > 0
@@ -1,26 +1,31 @@
1
1
  import type { Notification } from '../types/notification';
2
- import type {
3
- Route,
4
- RouteEvent,
5
- StepEvent,
6
- } from '@rango-dev/queue-manager-rango-preset';
7
2
 
3
+ import {
4
+ type PendingSwapWithQueueID,
5
+ type Route,
6
+ type RouteEvent,
7
+ type StepEvent,
8
+ } from '@rango-dev/queue-manager-rango-preset';
8
9
  import { create } from 'zustand';
9
10
  import { persist, subscribeWithSelector } from 'zustand/middleware';
10
11
 
11
12
  import createSelectors from './selectors';
12
13
 
13
14
  export interface NotificationState {
15
+ isSynced: boolean;
14
16
  notifications: Notification[];
15
17
  setNotification: (event: RouteEvent | StepEvent, route: Route) => void;
16
- setAsRead: (requestId: Notification['requestId']) => void;
17
- getUnreadNotifications: () => Notification[];
18
+ removeNotification: (requestId: Notification['requestId']) => void;
19
+ getNotifications: () => Notification[];
20
+ syncNotifications: (swaps: PendingSwapWithQueueID[]) => void;
21
+ clearNotifications: () => void;
18
22
  }
19
23
 
20
24
  export const useNotificationStore = createSelectors(
21
25
  create<NotificationState>()(
22
26
  persist(
23
27
  subscribeWithSelector((set, get) => ({
28
+ isSynced: false,
24
29
  notifications: [],
25
30
  setNotification: (event, route) => {
26
31
  const fromStep = route.steps[0];
@@ -29,7 +34,6 @@ export const useNotificationStore = createSelectors(
29
34
  const notification: Notification = {
30
35
  event,
31
36
  creationTime: Date.now(),
32
- read: false,
33
37
  requestId: route.requestId,
34
38
  route: {
35
39
  from: {
@@ -53,24 +57,65 @@ export const useNotificationStore = createSelectors(
53
57
  notifications: [...excludedList, notification],
54
58
  }));
55
59
  },
56
- setAsRead: (requestId) => {
60
+ removeNotification: (requestId) => {
57
61
  set((state) => ({
58
- notifications: state.notifications.map((notificationItem) =>
59
- notificationItem.requestId === requestId
60
- ? { ...notificationItem, read: true }
61
- : notificationItem
62
+ notifications: state.notifications.filter(
63
+ (notification) => notification.requestId !== requestId
62
64
  ),
63
65
  }));
64
66
  },
65
- getUnreadNotifications: () => {
66
- return get().notifications.filter(
67
- (notificationItem) => !notificationItem.read
68
- );
67
+ getNotifications: () => {
68
+ const { isSynced, notifications } = get();
69
+ return isSynced ? notifications : [];
70
+ },
71
+ syncNotifications: (swaps) => {
72
+ const { isSynced, notifications } = get();
73
+
74
+ if (!isSynced) {
75
+ const nextNotifications: Notification[] = [];
76
+ notifications.forEach((notification) => {
77
+ const swapExist = swaps.some(
78
+ (swap) => swap.swap.requestId === notification.requestId
79
+ );
80
+ if (swapExist) {
81
+ nextNotifications.push(notification);
82
+ }
83
+ });
84
+
85
+ set({ isSynced: true, notifications: nextNotifications });
86
+ }
69
87
  },
88
+ clearNotifications: () => set({ notifications: [] }),
70
89
  })),
90
+
71
91
  {
72
92
  name: 'notification',
73
93
  skipHydration: true,
94
+ partialize: ({ isSynced, ...otherProps }) => otherProps,
95
+ version: 1,
96
+ migrate: (persistedState, version) => {
97
+ if (version === 0) {
98
+ /**
99
+ * Eliminate the persistence of read notifications,
100
+ * and remove the "read" flag from other notifications to align with the current modifications in the notification store structure.
101
+ */
102
+ const oldNotifications = (
103
+ persistedState as {
104
+ notifications: (Notification & { read: boolean })[];
105
+ }
106
+ ).notifications;
107
+
108
+ (persistedState as NotificationState).notifications =
109
+ oldNotifications
110
+ .filter(
111
+ (notification: Notification & { read: boolean }) =>
112
+ !notification.read
113
+ )
114
+ .map(({ read, ...otherProps }) => otherProps);
115
+ }
116
+
117
+ return persistedState as NotificationState;
118
+ },
74
119
  }
75
120
  )
76
121
  )
@@ -21,6 +21,5 @@ type NotificationRoute = {
21
21
  export type Notification = Pick<Route, 'requestId'> & {
22
22
  event: RouteEvent | StepEvent;
23
23
  creationTime: number;
24
- read: boolean;
25
24
  route: NotificationRoute;
26
25
  };
package/src/utils/swap.ts CHANGED
@@ -23,6 +23,11 @@ import type {
23
23
  import type { PendingSwap, PendingSwapStep } from 'rango-types';
24
24
 
25
25
  import { i18n } from '@lingui/core';
26
+ import {
27
+ type RouteEvent,
28
+ RouteEventType,
29
+ type StepEvent,
30
+ } from '@rango-dev/queue-manager-rango-preset';
26
31
  import BigNumber from 'bignumber.js';
27
32
  import { PendingSwapNetworkStatus } from 'rango-types';
28
33
 
@@ -782,3 +787,10 @@ export function isTokensIdentical(tokenA: Token, tokenB: Token) {
782
787
  tokenA.address === tokenB.address
783
788
  );
784
789
  }
790
+
791
+ export function isSwapFinished(event: RouteEvent | StepEvent) {
792
+ return (
793
+ event.type === RouteEventType.FAILED ||
794
+ event.type === RouteEventType.SUCCEEDED
795
+ );
796
+ }
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- export declare function UnreadNotificationsBadge(): React.JSX.Element | null;
3
- //# sourceMappingURL=UnreadNotificationsBadge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"UnreadNotificationsBadge.d.ts","sourceRoot":"","sources":["../../../src/components/HeaderButtons/UnreadNotificationsBadge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,wBAAgB,wBAAwB,6BAmBvC"}