@@ -18,6 +18,7 @@ import { CodeNode, CodeHighlightNode } from "@lexical/code";
1818import { LinkNode } from "@lexical/link" ;
1919import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode" ;
2020import type { EditorState , SerializedEditorState } from "lexical" ;
21+ import * as Sentry from "@sentry/nextjs" ;
2122import { editorTheme } from "@/components/editor/theme" ;
2223import { SlashCommandPlugin } from "@/components/editor/slash-command-plugin" ;
2324import { FloatingToolbarPlugin } from "@/components/editor/floating-toolbar-plugin" ;
@@ -42,9 +43,9 @@ function validateUrl(url: string): boolean {
4243}
4344
4445export function Editor ( { pageId, initialContent } : EditorProps ) {
45- const [ saveStatus , setSaveStatus ] = useState < "idle" | "saving" | "saved" > (
46- "idle"
47- ) ;
46+ const [ saveStatus , setSaveStatus ] = useState <
47+ "idle" | "saving" | "saved" | "error"
48+ > ( "idle" ) ;
4849 const saveTimerRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
4950 const lastSavedRef = useRef < string > (
5051 initialContent ? JSON . stringify ( initialContent ) : ""
@@ -82,7 +83,8 @@ export function Editor({ pageId, initialContent }: EditorProps) {
8283 lastSavedRef . current = serialized ;
8384 setSaveStatus ( "saved" ) ;
8485 } else {
85- setSaveStatus ( "idle" ) ;
86+ Sentry . captureException ( error ) ;
87+ setSaveStatus ( "error" ) ;
8688 }
8789 } , SAVE_DEBOUNCE_MS ) ;
8890 } ,
@@ -97,12 +99,16 @@ export function Editor({ pageId, initialContent }: EditorProps) {
9799 } ;
98100 } , [ ] ) ;
99101
100- // Reset "saved" indicator after 2 seconds
102+ // Reset "saved" indicator after 2 seconds; retry save on error after 3 seconds
101103 useEffect ( ( ) => {
102104 if ( saveStatus === "saved" ) {
103105 const timer = setTimeout ( ( ) => setSaveStatus ( "idle" ) , 2000 ) ;
104106 return ( ) => clearTimeout ( timer ) ;
105107 }
108+ if ( saveStatus === "error" ) {
109+ const timer = setTimeout ( ( ) => setSaveStatus ( "idle" ) , 5000 ) ;
110+ return ( ) => clearTimeout ( timer ) ;
111+ }
106112 } , [ saveStatus ] ) ;
107113
108114 const initialConfig = {
@@ -119,7 +125,7 @@ export function Editor({ pageId, initialContent }: EditorProps) {
119125 HorizontalRuleNode ,
120126 ] ,
121127 onError : ( error : Error ) => {
122- console . error ( "Lexical error:" , error ) ;
128+ Sentry . captureException ( error ) ;
123129 } ,
124130 editorState : initialContent
125131 ? JSON . stringify ( initialContent )
@@ -167,6 +173,9 @@ export function Editor({ pageId, initialContent }: EditorProps) {
167173 < div className = "mt-2 h-5 text-xs text-muted-foreground" >
168174 { saveStatus === "saving" && "Saving..." }
169175 { saveStatus === "saved" && "Saved" }
176+ { saveStatus === "error" && (
177+ < span className = "text-destructive" > Save failed</ span >
178+ ) }
170179 </ div >
171180 </ div >
172181 ) ;
0 commit comments