1- import React , { useRef , useState , useEffect } from 'react' ;
1+ import React , { useRef , useState , useEffect , useCallback } from 'react' ;
22import dynamic from 'next/dynamic' ;
33import { useTranslation } from 'react-i18next' ;
44
@@ -39,8 +39,6 @@ export const AppConfigSection: React.FC = () => {
3939 // Add user input state tracking
4040 const isUserTypingAppName = useRef ( false ) ;
4141 const isUserTypingDescription = useRef ( false ) ;
42- const appNameUpdateTimer = useRef < NodeJS . Timeout | null > ( null ) ;
43- const descriptionUpdateTimer = useRef < NodeJS . Timeout | null > ( null ) ;
4442
4543 // Avatar-related state
4644 const [ isAvatarModalOpen , setIsAvatarModalOpen ] = useState ( false ) ;
@@ -67,6 +65,22 @@ export const AppConfigSection: React.FC = () => {
6765
6866 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
6967
68+ const triggerAutoSave = useCallback ( ( ) => {
69+ const runSave = async ( ) => {
70+ try {
71+ const ok = await configService . saveConfigToBackend ( getConfig ( ) as any ) ;
72+ if ( ! ok ) {
73+ message . error ( t ( "setup.page.error.saveConfig" ) ) ;
74+ }
75+ } catch ( error ) {
76+ message . error ( t ( "setup.page.error.saveConfig" ) ) ;
77+ log . error ( "Failed to auto save app configuration" , error ) ;
78+ }
79+ } ;
80+
81+ void runSave ( ) ;
82+ } , [ getConfig , message , t ] ) ;
83+
7084 // Add configuration change listener, synchronize local state when config is loaded from backend
7185 useEffect ( ( ) => {
7286 const handleConfigChanged = ( event : any ) => {
@@ -139,18 +153,6 @@ export const AppConfigSection: React.FC = () => {
139153 } ;
140154 } , [ ] ) ;
141155
142- // Clean up timers
143- useEffect ( ( ) => {
144- return ( ) => {
145- if ( appNameUpdateTimer . current ) {
146- clearTimeout ( appNameUpdateTimer . current ) ;
147- }
148- if ( descriptionUpdateTimer . current ) {
149- clearTimeout ( descriptionUpdateTimer . current ) ;
150- }
151- } ;
152- } , [ ] ) ;
153-
154156 // Handle basic app config changes
155157 const handleAppNameChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
156158 const newAppName = e . target . value ;
@@ -162,25 +164,12 @@ export const AppConfigSection: React.FC = () => {
162164 setAppNameError ( false ) ;
163165 }
164166
165- // Clear previous timer
166- if ( appNameUpdateTimer . current ) {
167- clearTimeout ( appNameUpdateTimer . current ) ;
168- }
169-
170- // Set debounced update
171- appNameUpdateTimer . current = setTimeout ( ( ) => {
172- updateAppConfig ( { appName : newAppName } ) ;
173- isUserTypingAppName . current = false ;
174- } , 500 ) ;
175167 } ;
176168
177169 const handleAppNameBlur = ( ) => {
178- // Clear timer, update immediately
179- if ( appNameUpdateTimer . current ) {
180- clearTimeout ( appNameUpdateTimer . current ) ;
181- }
182170 updateAppConfig ( { appName : localAppName } ) ;
183171 isUserTypingAppName . current = false ;
172+ triggerAutoSave ( ) ;
184173 } ;
185174
186175 const handleDescriptionChange = (
@@ -189,26 +178,12 @@ export const AppConfigSection: React.FC = () => {
189178 const newDescription = e . target . value ;
190179 isUserTypingDescription . current = true ;
191180 setLocalAppDescription ( newDescription ) ;
192-
193- // Clear previous timer
194- if ( descriptionUpdateTimer . current ) {
195- clearTimeout ( descriptionUpdateTimer . current ) ;
196- }
197-
198- // Set debounced update
199- descriptionUpdateTimer . current = setTimeout ( ( ) => {
200- updateAppConfig ( { appDescription : newDescription } ) ;
201- isUserTypingDescription . current = false ;
202- } , 500 ) ;
203181 } ;
204182
205183 const handleDescriptionBlur = ( ) => {
206- // Clear timer, update immediately
207- if ( descriptionUpdateTimer . current ) {
208- clearTimeout ( descriptionUpdateTimer . current ) ;
209- }
210184 updateAppConfig ( { appDescription : localAppDescription } ) ;
211185 isUserTypingDescription . current = false ;
186+ triggerAutoSave ( ) ;
212187 } ;
213188
214189 // Open avatar selection modal
0 commit comments