diff --git a/desktop/index.html b/desktop/index.html
index 5309a15..bffc3a7 100644
--- a/desktop/index.html
+++ b/desktop/index.html
@@ -9,6 +9,13 @@
dev vs. production rules cleanly. -->
DChain
diff --git a/desktop/src/sections/messages/Conversation.tsx b/desktop/src/sections/messages/Conversation.tsx
index a354191..bf1c8c5 100644
--- a/desktop/src/sections/messages/Conversation.tsx
+++ b/desktop/src/sections/messages/Conversation.tsx
@@ -98,12 +98,13 @@ export function Conversation({ address }: { address: string }): React.ReactEleme
}
};
- const name = contact?.username ? `@${contact.username}`
+ const name = (contact?.username ? `@${contact.username}`
: contact?.alias
? contact.alias
: isSelf
? 'Saved Messages'
- : shortAddr(address, 8);
+ : shortAddr(address || '', 8)) || shortAddr(address || '', 8);
+ const firstLetter = (name || '?').replace(/^@/, '').charAt(0).toUpperCase() || '?';
return (
@@ -118,12 +119,18 @@ export function Conversation({ address }: { address: string }): React.ReactEleme
color: '#fff', fontWeight: 700, fontSize: 14,
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
- {isSelf ? '★' : name.replace(/^@/, '').charAt(0).toUpperCase()}
+ {isSelf ? '★' : firstLetter}
-
{name}
-
- {shortAddr(address, 6)}
+
{name}
+
+ {shortAddr(address || '', 6)}
diff --git a/desktop/src/shell/PaneBoundary.tsx b/desktop/src/shell/PaneBoundary.tsx
new file mode 100644
index 0000000..a83c237
--- /dev/null
+++ b/desktop/src/shell/PaneBoundary.tsx
@@ -0,0 +1,62 @@
+// PaneBoundary — ErrorBoundary scoped to one Shell pane. A crash in
+// the Conversation component shouldn't black-out the whole window; it
+// should leave NavBar + List + StatusBar usable so the operator can
+// switch sections and report the bug. Resets when the keyed section
+// changes.
+
+import React from 'react';
+
+interface Props {
+ /** Used as React key at the callsite; also shown in the panic copy. */
+ sectionName: string;
+ children: React.ReactNode;
+}
+
+interface State {
+ error: Error | null;
+}
+
+export class PaneBoundary extends React.Component {
+ state: State = { error: null };
+
+ static getDerivedStateFromError(error: Error): State {
+ return { error };
+ }
+
+ componentDidCatch(error: Error, info: React.ErrorInfo): void {
+ console.error(`[PaneBoundary:${this.props.sectionName}]`, error, info);
+ }
+
+ render(): React.ReactNode {
+ if (!this.state.error) return this.props.children;
+ return (
+
+
+ {this.props.sectionName} crashed
+
+
+ {this.state.error.message}
+
+
+ {this.state.error.stack}
+
+
+
+ );
+ }
+}
diff --git a/desktop/src/shell/Shell.tsx b/desktop/src/shell/Shell.tsx
index 4d22e0f..29a161e 100644
--- a/desktop/src/shell/Shell.tsx
+++ b/desktop/src/shell/Shell.tsx
@@ -24,6 +24,7 @@ import { TitleBar } from './TitleBar';
import { NavBar } from './NavBar';
import { StatusBar } from './StatusBar';
import { UpdateBanner } from './UpdateBanner';
+import { PaneBoundary } from './PaneBoundary';
import { MessagesList, MessagesDetail } from '@/sections/messages';
import { FeedList, FeedDetail } from '@/sections/feed';
import { WalletList, WalletDetail } from '@/sections/wallet';
@@ -51,10 +52,14 @@ export function Shell(): React.ReactElement {
borderRight: '1px solid #1f1f1f',
overflowY: 'auto',
}}>
-
+
+
+