+25
atproto-notifications/package-lock.json
+25
atproto-notifications/package-lock.json
···
15
15
"psl": "^1.15.0",
16
16
"react": "^19.1.0",
17
17
"react-dom": "^19.1.0",
18
+
"react-error-boundary": "^6.0.0",
18
19
"react-router": "^7.6.3",
19
20
"react-time-ago": "^7.3.3",
20
21
"reactjs-popup": "^2.0.6"
···
36
37
"../lexicons": {
37
38
"version": "0.0.1",
38
39
"dependencies": {
40
+
"@atcute/client": "^4.0.3",
41
+
"@atcute/identity-resolver": "^1.1.3",
42
+
"jsonpath-plus": "^10.3.0",
39
43
"psl": "^1.15.0"
40
44
}
41
45
},
···
327
331
},
328
332
"peerDependencies": {
329
333
"@babel/core": "^7.0.0-0"
334
+
}
335
+
},
336
+
"node_modules/@babel/runtime": {
337
+
"version": "7.27.6",
338
+
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
339
+
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
340
+
"license": "MIT",
341
+
"engines": {
342
+
"node": ">=6.9.0"
330
343
}
331
344
},
332
345
"node_modules/@babel/template": {
···
3075
3088
},
3076
3089
"peerDependencies": {
3077
3090
"react": "^19.1.0"
3091
+
}
3092
+
},
3093
+
"node_modules/react-error-boundary": {
3094
+
"version": "6.0.0",
3095
+
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-6.0.0.tgz",
3096
+
"integrity": "sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==",
3097
+
"license": "MIT",
3098
+
"dependencies": {
3099
+
"@babel/runtime": "^7.12.5"
3100
+
},
3101
+
"peerDependencies": {
3102
+
"react": ">=16.13.1"
3078
3103
}
3079
3104
},
3080
3105
"node_modules/react-is": {
+1
atproto-notifications/package.json
+1
atproto-notifications/package.json
+8
atproto-notifications/src/components/Notification.css
+8
atproto-notifications/src/components/Notification.css
+10
atproto-notifications/src/components/Notification.tsx
+10
atproto-notifications/src/components/Notification.tsx
···
7
7
8
8
import './Notification.css';
9
9
10
+
export function fallbackRender({ error, resetErrorBoundary }) {
11
+
console.error('rendering fallback for error', error);
12
+
return (
13
+
<div className="notification error">
14
+
<p>sorry, something went wrong trying to show this notification</p>
15
+
<p><button onClick={resetErrorBoundary}>retry</button></p>
16
+
</div>
17
+
);
18
+
}
19
+
10
20
export function Notification({ app, group, source, source_record, source_did, subject, timestamp }) {
11
21
const [resolvedLink, setResolvedLink] = useState(null);
12
22
+5
-2
atproto-notifications/src/pages/Feed.tsx
+5
-2
atproto-notifications/src/pages/Feed.tsx
···
1
1
import { useCallback, useEffect, useState } from 'react';
2
+
import { ErrorBoundary } from 'react-error-boundary';
2
3
import Popup from 'reactjs-popup';
3
4
import { getNotifications, getSecondary } from '../db';
4
5
import { ButtonGroup } from '../components/Buttons';
5
6
import { NotificationSettings } from '../components/NotificationSettings';
6
-
import { Notification } from '../components/Notification';
7
+
import { Notification, fallbackRender } from '../components/Notification';
7
8
import { GetJson, PostJson } from '../components/Fetch';
8
9
import psl from 'psl';
9
10
import lexicons from 'lexicons';
···
232
233
233
234
<div className="feed-notifications">
234
235
{feed.map(([k, n]) => (
235
-
<Notification key={k} {...n} />
236
+
<ErrorBoundary key={k} fallbackRender={fallbackRender}>
237
+
<Notification {...n} />
238
+
</ErrorBoundary>
236
239
))}
237
240
</div>
238
241
</div>