@@ -520,8 +533,15 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps
)
+ // Settle-up and Balances both come from the one settlement request, so they
+ // share the notice that says the numbers are missing rather than zero.
+ function loadFailed() {
+ return
{t('common.unknownError')}
+ }
+
// ── shared settle-flow list ──────────────────────────────────────────────
function SettleFlows() {
+ if (settlementError) return loadFailed()
const flows = settlement?.flows || []
if (flows.length === 0) return (
diff --git a/client/src/components/Studio/SaveIndicator.tsx b/client/src/components/Studio/SaveIndicator.tsx
index 746880022..e0a9fe8a7 100644
--- a/client/src/components/Studio/SaveIndicator.tsx
+++ b/client/src/components/Studio/SaveIndicator.tsx
@@ -1,4 +1,4 @@
-import { AlertTriangle, Check, CloudOff, RefreshCw } from 'lucide-react'
+import { AlertTriangle, Check, CloudOff, Eye, RefreshCw } from 'lucide-react'
import type { BookRecord } from '@trek/shared'
import type { SaveState } from './useBookStore'
@@ -43,6 +43,20 @@ export function SaveIndicator({
)
}
+ if (state.status === 'readonly') {
+ /*
+ * Not an error and not retryable: this person was invited to read the
+ * journey, not to write it. Said once, plainly, and left standing — the
+ * alternative is an editor that looks like it is saving and is not.
+ */
+ return (
+