Skip to content
This repository was archived by the owner on Sep 7, 2023. It is now read-only.

Commit e610b57

Browse files
authored
Merge pull request #1 from Wordcel/wordcel
added wordcel notification component
2 parents 7e10373 + 9846963 commit e610b57

16 files changed

Lines changed: 1870 additions & 8 deletions

File tree

packages/dialect-react-ui/components/NotificationsButton/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { useTheme } from '../common/providers/DialectThemeProvider';
88
import { useDialectUiId } from '../common/providers/DialectUiManagementProvider';
99
import type { Channel } from '../common/types';
1010
import IconButton from '../IconButton';
11-
import Notifications, { NotificationType } from '../Notifications';
11+
import WordcelNotifications, {
12+
NotificationType,
13+
} from '../WordcelNotifications';
1214

1315
const DEFAULT_POLLING_FOR_NOTIFICATIONS = 15000; // 15 sec refresh default
1416

@@ -87,7 +89,7 @@ function WrappedNotificationsButton(props: PropTypes): JSX.Element {
8789
// className="dt-w-full dt-h-full bg-white/10"
8890
// style={{ backdropFilter: 'blur(132px)' }}
8991
>
90-
<Notifications
92+
<WordcelNotifications
9193
channels={props.channels}
9294
notifications={props?.notifications}
9395
onModalClose={close}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import type { ThreadId } from '@dialectlabs/react-sdk';
2+
import clsx from 'clsx';
3+
import { useTheme } from '../common/providers/DialectThemeProvider';
4+
import { useRoute } from '../common/providers/Router';
5+
import IconButton from '../IconButton';
6+
import { RouteName } from './constants';
7+
8+
function Header(props: {
9+
isReady: boolean;
10+
isWeb3Enabled: boolean;
11+
onModalClose: () => void;
12+
onBackClick?: () => void;
13+
threadId?: ThreadId;
14+
}) {
15+
const { navigate, current } = useRoute();
16+
const { colors, textStyles, icons, header, notificationHeader } = useTheme();
17+
const isSettingsOpen = current?.name === RouteName.Settings;
18+
const openSettings = () => {
19+
navigate(RouteName.Settings);
20+
};
21+
const openThread = () => {
22+
if (!props.threadId) return;
23+
navigate(RouteName.Thread, {
24+
params: { threadId: props.threadId },
25+
});
26+
};
27+
28+
const BackButton = () => (
29+
<IconButton
30+
icon={<icons.back />}
31+
onClick={openThread}
32+
className="dt-mr-2 dt-py-1"
33+
/>
34+
);
35+
36+
const SettingsButton = () =>
37+
props.isReady && !isSettingsOpen ? (
38+
<IconButton icon={<icons.settings />} onClick={openSettings} />
39+
) : null;
40+
41+
const CloseButton = () => (
42+
<IconButton icon={<icons.x />} onClick={props.onModalClose} />
43+
);
44+
45+
const MasterBackButton = () =>
46+
props.onBackClick ? (
47+
<IconButton
48+
icon={<icons.back />}
49+
onClick={props.onBackClick}
50+
className="dt-mr-2 dt-py-1"
51+
/>
52+
) : null;
53+
54+
const headerIcons = (
55+
<>
56+
<div className="dt-flex">
57+
<SettingsButton />
58+
<div className="sm:dt-hidden dt-ml-3">
59+
<CloseButton />
60+
</div>
61+
</div>
62+
</>
63+
);
64+
65+
return (
66+
<>
67+
<div
68+
className={clsx(
69+
'dt-flex dt-flex-row dt-items-center dt-justify-between',
70+
header,
71+
notificationHeader
72+
)}
73+
>
74+
{isSettingsOpen ? (
75+
<div className="dt-flex dt-flex-row dt-items-center">
76+
{props.isWeb3Enabled && <BackButton />}
77+
{!props.isWeb3Enabled && <MasterBackButton />}
78+
<span className={clsx(textStyles.header, colors.accent)}>
79+
Notification Settings
80+
</span>
81+
</div>
82+
) : (
83+
<>
84+
<MasterBackButton />
85+
<span className={clsx(textStyles.header, colors.accent)}>
86+
Notifications
87+
</span>
88+
</>
89+
)}
90+
{headerIcons}
91+
</div>
92+
</>
93+
);
94+
}
95+
96+
export default Header;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export enum RouteName {
2+
SigningRequest = 'sign_wallet',
3+
TransactionSigning = 'transaction_signing',
4+
EncryptionRequest = 'encryption_request',
5+
Setup = 'setup_notifications',
6+
Main = 'main_notifications',
7+
Settings = 'settings_notifications',
8+
Thread = 'notifications_thread',
9+
CantDecrypt = 'cant_decrypt',
10+
FailingGate = 'failing_gate',
11+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import {
2+
AddressType,
3+
useDialectDapp,
4+
useNotificationChannelDappSubscription,
5+
useNotificationSubscriptions,
6+
useThread,
7+
} from '@dialectlabs/react-sdk';
8+
import clsx from 'clsx';
9+
import { useCallback, useEffect, useState } from 'react';
10+
import LoadingThread from '../../entities/LoadingThread';
11+
import ConnectionWrapper from '../../entities/wrappers/ConnectionWrapper';
12+
import ThreadEncyprionWrapper from '../../entities/wrappers/ThreadEncryptionWrapper';
13+
import WalletStatesWrapper from '../../entities/wrappers/WalletStatesWrapper';
14+
import GatedWrapper from '../common/GatedWrapper';
15+
import { useTheme } from '../common/providers/DialectThemeProvider';
16+
import { Route, Router, useRoute } from '../common/providers/Router';
17+
import type { Channel } from '../common/types';
18+
import { RouteName } from './constants';
19+
import Header from './Header';
20+
import NotificationsList from './screens/NotificationsList';
21+
import Settings from './screens/Settings';
22+
23+
export type NotificationType = {
24+
name: string;
25+
detail?: string;
26+
};
27+
28+
interface NotificationsProps {
29+
onModalClose: () => void;
30+
notifications?: NotificationType[];
31+
channels?: Channel[];
32+
onBackClick?: () => void;
33+
gatedView?: string | JSX.Element;
34+
pollingInterval?: number;
35+
}
36+
37+
const addressType = AddressType.Wallet;
38+
39+
function InnerNotifications(props: NotificationsProps): JSX.Element {
40+
const { dappAddress } = useDialectDapp();
41+
if (!dappAddress) {
42+
throw new Error('dapp address should be provided for notifications');
43+
}
44+
const { thread, isFetchingThread } = useThread({
45+
findParams: { otherMembers: [dappAddress] },
46+
});
47+
48+
const [isInitialRoutePicked, setInitialRoutePicked] = useState(false);
49+
50+
const subscription = useNotificationChannelDappSubscription({
51+
addressType,
52+
});
53+
54+
const { isFetching: isFetchingNotificationsSubscriptions } =
55+
useNotificationSubscriptions();
56+
57+
const { scrollbar } = useTheme();
58+
const { navigate } = useRoute();
59+
60+
const showThread = useCallback(() => {
61+
if (!thread) {
62+
return;
63+
}
64+
navigate(RouteName.Thread, {
65+
params: {
66+
threadId: thread.id,
67+
},
68+
});
69+
}, [navigate, thread]);
70+
71+
const showSettings = useCallback(() => {
72+
navigate(RouteName.Settings);
73+
}, [navigate]);
74+
75+
const isLoading =
76+
subscription.isFetchingSubscriptions ||
77+
isFetchingThread ||
78+
isFetchingNotificationsSubscriptions;
79+
80+
const isWeb3Enabled = subscription.enabled && Boolean(thread);
81+
82+
useEffect(
83+
function pickInitialRoute() {
84+
if (isInitialRoutePicked) {
85+
return;
86+
}
87+
88+
if (isLoading) {
89+
return;
90+
}
91+
92+
const shouldShowSettings = !isWeb3Enabled;
93+
94+
if (shouldShowSettings) {
95+
showSettings();
96+
setInitialRoutePicked(true);
97+
return;
98+
}
99+
100+
showThread();
101+
setInitialRoutePicked(true);
102+
},
103+
[isInitialRoutePicked, isLoading, isWeb3Enabled, showSettings, showThread]
104+
);
105+
106+
return (
107+
<div className="dt-h-full">
108+
<Header
109+
threadId={thread?.id}
110+
isWeb3Enabled={isWeb3Enabled}
111+
isReady={!isLoading}
112+
onModalClose={props.onModalClose}
113+
onBackClick={props.onBackClick}
114+
/>
115+
<div
116+
className={clsx(
117+
'dt-h-full dt-overflow-y-auto dt-pb-[3.5rem]',
118+
scrollbar
119+
)}
120+
>
121+
{isInitialRoutePicked ? (
122+
<>
123+
<Route name={RouteName.Settings}>
124+
<Settings
125+
channels={props.channels || []}
126+
notifications={props?.notifications}
127+
/>
128+
</Route>
129+
<Route name={RouteName.Thread}>
130+
<NotificationsList refreshInterval={props.pollingInterval} />
131+
</Route>
132+
</>
133+
) : (
134+
<LoadingThread />
135+
)}
136+
</div>
137+
</div>
138+
);
139+
}
140+
141+
export default function WordcelNotifications({
142+
gatedView,
143+
...props
144+
}: NotificationsProps) {
145+
const { dappAddress } = useDialectDapp();
146+
const { colors, modal } = useTheme();
147+
148+
const fallbackHeader = (
149+
<Header
150+
isReady={false}
151+
isWeb3Enabled={false}
152+
onBackClick={props.onBackClick}
153+
onModalClose={props.onModalClose}
154+
/>
155+
);
156+
157+
return (
158+
<div className="dialect dt-h-full">
159+
<div
160+
className={clsx(
161+
'dt-flex dt-flex-col dt-h-full dt-overflow-hidden',
162+
colors.textPrimary,
163+
colors.bg,
164+
modal
165+
)}
166+
>
167+
<Router>
168+
<WalletStatesWrapper header={fallbackHeader}>
169+
<ConnectionWrapper
170+
header={fallbackHeader}
171+
pollingInterval={props.pollingInterval}
172+
>
173+
<GatedWrapper gatedView={gatedView}>
174+
<ThreadEncyprionWrapper otherMemberPK={dappAddress}>
175+
<InnerNotifications {...props} />
176+
</ThreadEncyprionWrapper>
177+
</GatedWrapper>
178+
</ConnectionWrapper>
179+
</WalletStatesWrapper>
180+
</Router>
181+
</div>
182+
</div>
183+
);
184+
}

0 commit comments

Comments
 (0)