@@ -18,7 +18,6 @@ import {
1818 fetchPut ,
1919 proxyFetchDelete ,
2020 proxyFetchGet ,
21- proxyFetchPut ,
2221} from '@/api/http' ;
2322import useChatStoreAdapter from '@/hooks/useChatStoreAdapter' ;
2423import { generateUniqueId , replayActiveTask } from '@/lib' ;
@@ -29,7 +28,7 @@ import { AgentStep, ChatTaskStatus } from '@/types/constants';
2928import { TriangleAlert } from 'lucide-react' ;
3029import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
3130import { useTranslation } from 'react-i18next' ;
32- import { useNavigate , useSearchParams } from 'react-router-dom' ;
31+ import { useLocation , useNavigate , useSearchParams } from 'react-router-dom' ;
3332import { toast } from 'sonner' ;
3433import BottomBox from './BottomBox' ;
3534import { HeaderBox } from './HeaderBox' ;
@@ -43,12 +42,11 @@ export default function ChatBox(): JSX.Element {
4342
4443 const { t } = useTranslation ( ) ;
4544 const textareaRef = useRef < HTMLTextAreaElement > ( null ) ;
46- const [ hasModel , setHasModel ] = useState ( true ) ;
45+ const [ hasModel , setHasModel ] = useState ( false ) ;
46+ const [ isConfigLoaded , setIsConfigLoaded ] = useState ( false ) ;
4747 const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
48- const [ privacy , setPrivacy ] = useState < any > ( false ) ;
4948 const [ _hasSearchKey , setHasSearchKey ] = useState < any > ( false ) ;
5049 const scrollTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
51- // const [privacyDialogOpen, setPrivacyDialogOpen] = useState(false);
5250 const { modelType } = useAuthStore ( ) ;
5351 const [ useCloudModelInDev , setUseCloudModelInDev ] = useState ( false ) ;
5452 useEffect ( ( ) => {
@@ -62,13 +60,43 @@ export default function ChatBox(): JSX.Element {
6260 setUseCloudModelInDev ( false ) ;
6361 }
6462 } , [ modelType ] ) ;
65- useEffect ( ( ) => {
66- proxyFetchGet ( '/api/user/privacy' )
67- . then ( ( res ) => {
68- setPrivacy ( res . all_required_granted ) ;
69- } )
70- . catch ( ( err ) => console . error ( 'Failed to fetch settings:' , err ) ) ;
7163
64+ const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
65+ const share_token = searchParams . get ( 'share_token' ) ;
66+ const skill_prompt = searchParams . get ( 'skill_prompt' ) ;
67+
68+ const handleSendRef = useRef <
69+ ( ( messageStr ?: string , taskId ?: string ) => Promise < void > ) | null
70+ > ( null ) ;
71+
72+ const navigate = useNavigate ( ) ;
73+ const location = useLocation ( ) ;
74+
75+ // Shared function to check model configuration
76+ const checkModelConfig = useCallback ( async ( ) => {
77+ try {
78+ if ( modelType === 'cloud' ) {
79+ // For cloud model, check if API key exists
80+ const res = await proxyFetchGet ( '/api/user/key' ) ;
81+ setHasModel ( ! ! res . value ) ;
82+ } else if ( modelType === 'local' || modelType === 'custom' ) {
83+ // For local/custom model, check if provider exists
84+ const res = await proxyFetchGet ( '/api/providers' , { prefer : true } ) ;
85+ const providerList = res . items || [ ] ;
86+ setHasModel ( providerList . length > 0 ) ;
87+ } else {
88+ setHasModel ( false ) ;
89+ }
90+ } catch ( err ) {
91+ console . error ( 'Failed to check model config:' , err ) ;
92+ setHasModel ( false ) ;
93+ } finally {
94+ setIsConfigLoaded ( true ) ;
95+ }
96+ } , [ modelType ] ) ;
97+
98+ // Check model config on mount and when modelType changes
99+ useEffect ( ( ) => {
72100 proxyFetchGet ( '/api/configs' )
73101 . then ( ( configsRes ) => {
74102 const configs = Array . isArray ( configsRes ) ? configsRes : [ ] ;
@@ -81,34 +109,29 @@ export default function ChatBox(): JSX.Element {
81109 if ( _hasApiKey && _hasApiId ) setHasSearchKey ( true ) ;
82110 } )
83111 . catch ( ( err ) => console . error ( 'Failed to fetch configs:' , err ) ) ;
84- } , [ ] ) ;
85112
86- // Refresh privacy status when dialog closes
87- // useEffect(() => {
88- // if (!privacyDialogOpen) {
89- // proxyFetchGet("/api/user/privacy")
90- // .then((res) => {
91- // let _privacy = 0;
92- // Object.keys(res).forEach((key) => {
93- // if (!res[key]) {
94- // _privacy++;
95- // return;
96- // }
97- // });
98- // setPrivacy(_privacy === 0 ? true : false);
99- // })
100- // .catch((err) => console.error("Failed to fetch settings:", err));
101- // }
102- // }, [privacyDialogOpen]);
103- const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
104- const share_token = searchParams . get ( 'share_token' ) ;
105- const skill_prompt = searchParams . get ( 'skill_prompt' ) ;
113+ checkModelConfig ( ) ;
114+ } , [ modelType , checkModelConfig ] ) ;
106115
107- const handleSendRef = useRef <
108- ( ( messageStr ?: string , taskId ?: string ) => Promise < void > ) | null
109- > ( null ) ;
116+ // Re-check model config when returning from settings page
117+ useEffect ( ( ) => {
118+ // Check when location changes (user navigates)
119+ if ( location . pathname === '/' ) {
120+ checkModelConfig ( ) ;
121+ }
122+ } , [ location . pathname , checkModelConfig ] ) ;
110123
111- const navigate = useNavigate ( ) ;
124+ // Also check when window gains focus (user returns from settings)
125+ useEffect ( ( ) => {
126+ const handleFocus = ( ) => {
127+ checkModelConfig ( ) ;
128+ } ;
129+
130+ window . addEventListener ( 'focus' , handleFocus ) ;
131+ return ( ) => {
132+ window . removeEventListener ( 'focus' , handleFocus ) ;
133+ } ;
134+ } , [ checkModelConfig ] ) ;
112135
113136 // Task time tracking
114137 const [ taskTime , setTaskTime ] = useState (
@@ -226,17 +249,15 @@ export default function ChatBox(): JSX.Element {
226249
227250 if ( isTaskBusy ) return true ;
228251
229- // Standard checks - check model first, then privacy
252+ // Standard checks - check model
230253 if ( ! hasModel ) return true ;
231- if ( ! privacy ) return true ;
232254 if ( useCloudModelInDev ) return true ;
233255 if ( task . isContextExceeded ) return true ;
234256
235257 return false ;
236258 } , [
237259 chatStore ?. activeTaskId ,
238260 chatStore ?. tasks ,
239- privacy ,
240261 hasModel ,
241262 useCloudModelInDev ,
242263 isTaskBusy ,
@@ -257,10 +278,6 @@ export default function ChatBox(): JSX.Element {
257278 navigate ( '/history?tab=agents' ) ;
258279 return ;
259280 }
260- if ( ! privacy ) {
261- toast . error ( 'Please accept the privacy policy first.' ) ;
262- return ;
263- }
264281
265282 let _token : string = token . split ( '__' ) [ 0 ] ;
266283 let taskId : string = token . split ( '__' ) [ 1 ] ;
@@ -290,7 +307,7 @@ export default function ChatBox(): JSX.Element {
290307 }
291308 }
292309 } ,
293- [ chatStore , projectStore . activeProjectId , hasModel , privacy , navigate ]
310+ [ chatStore , projectStore . activeProjectId , hasModel , navigate ]
294311 ) ;
295312
296313 // Handle skill_prompt from URL - pre-fill message when navigating from Skills page
@@ -358,16 +375,12 @@ export default function ChatBox(): JSX.Element {
358375 const _taskId = taskId || chatStore . activeTaskId ;
359376 if ( message . trim ( ) === '' && ! messageStr ) return ;
360377
361- // Check model first, then privacy
378+ // Check model configuration
362379 if ( ! hasModel ) {
363380 toast . error ( 'Please select a model first.' ) ;
364381 navigate ( '/history?tab=agents' ) ;
365382 return ;
366383 }
367- if ( ! privacy ) {
368- toast . error ( 'Please accept the privacy policy first.' ) ;
369- return ;
370- }
371384 const tempMessageContent = messageStr || message ;
372385
373386 if ( executionId && projectStore . activeProjectId ) {
@@ -542,23 +555,6 @@ export default function ChatBox(): JSX.Element {
542555 setMessage ( '' ) ;
543556 }
544557 } else {
545- if ( ! privacy ) {
546- const API_FIELDS = [
547- 'take_screenshot' ,
548- 'access_local_software' ,
549- 'access_your_address' ,
550- 'password_storage' ,
551- ] ;
552- const requestData = {
553- [ API_FIELDS [ 0 ] ] : true ,
554- [ API_FIELDS [ 1 ] ] : true ,
555- [ API_FIELDS [ 2 ] ] : true ,
556- [ API_FIELDS [ 3 ] ] : true ,
557- } ;
558- proxyFetchPut ( '/api/user/privacy' , requestData ) ;
559- setPrivacy ( true ) ;
560- }
561-
562558 setTimeout ( ( ) => {
563559 scrollToBottom ( ) ;
564560 } , 200 ) ;
@@ -670,11 +666,11 @@ export default function ChatBox(): JSX.Element {
670666 } , [ projectStore ] ) ;
671667
672668 useEffect ( ( ) => {
673- // Wait for both config and privacy to be loaded before handling share token
674- if ( share_token ) {
669+ // Wait for config to be loaded before handling share token
670+ if ( share_token && isConfigLoaded ) {
675671 handleSendShare ( share_token ) ;
676672 }
677- } , [ share_token , handleSendShare ] ) ;
673+ } , [ share_token , isConfigLoaded , handleSendShare ] ) ;
678674
679675 if ( ! chatStore ) {
680676 return < div > Loading...</ div > ;
@@ -1053,7 +1049,6 @@ export default function ChatBox(): JSX.Element {
10531049 disabled : isInputDisabled ,
10541050 textareaRef : textareaRef ,
10551051 allowDragDrop : true ,
1056- privacy : privacy ,
10571052 useCloudModelInDev : useCloudModelInDev ,
10581053 } }
10591054 />
@@ -1076,61 +1071,7 @@ export default function ChatBox(): JSX.Element {
10761071 </ div >
10771072 </ div >
10781073 ) : null }
1079- { hasModel && ! privacy ? (
1080- < div className = "flex items-center gap-2" >
1081- < div
1082- onClick = { ( e ) => {
1083- const target = e . target as HTMLElement ;
1084- if ( target . tagName === 'A' ) {
1085- return ;
1086- }
1087- const API_FIELDS = [
1088- 'take_screenshot' ,
1089- 'access_local_software' ,
1090- 'access_your_address' ,
1091- 'password_storage' ,
1092- ] ;
1093- const requestData = {
1094- [ API_FIELDS [ 0 ] ] : true ,
1095- [ API_FIELDS [ 1 ] ] : true ,
1096- [ API_FIELDS [ 2 ] ] : true ,
1097- [ API_FIELDS [ 3 ] ] : true ,
1098- } ;
1099- proxyFetchPut ( '/api/user/privacy' , requestData ) ;
1100- setPrivacy ( true ) ;
1101- } }
1102- className = "flex cursor-pointer items-center gap-1 rounded-md bg-surface-information px-sm py-xs"
1103- >
1104- < TriangleAlert
1105- size = { 20 }
1106- className = "text-icon-information"
1107- />
1108- < span className = "flex-1 text-xs font-medium leading-[20px] text-text-information" >
1109- { t ( 'layout.by-messaging-eigent' ) } { ' ' }
1110- < a
1111- href = "https://www.eigent.ai/terms-of-use"
1112- target = "_blank"
1113- className = "text-text-information underline"
1114- onClick = { ( e ) => e . stopPropagation ( ) }
1115- rel = "noreferrer"
1116- >
1117- { t ( 'layout.terms-of-use' ) }
1118- </ a > { ' ' }
1119- { t ( 'layout.and' ) } { ' ' }
1120- < a
1121- href = "https://www.eigent.ai/privacy-policy"
1122- target = "_blank"
1123- className = "text-text-information underline"
1124- onClick = { ( e ) => e . stopPropagation ( ) }
1125- rel = "noreferrer"
1126- >
1127- { t ( 'layout.privacy-policy' ) }
1128- </ a >
1129- .
1130- </ span >
1131- </ div >
1132- </ div >
1133- ) : (
1074+ { hasModel && (
11341075 < div className = "mr-2 flex flex-col items-center gap-2" >
11351076 { [
11361077 {
@@ -1210,7 +1151,6 @@ export default function ChatBox(): JSX.Element {
12101151 disabled : isInputDisabled ,
12111152 textareaRef : textareaRef ,
12121153 allowDragDrop : hasAnyMessages ,
1213- privacy : hasAnyMessages ? privacy : true ,
12141154 useCloudModelInDev : useCloudModelInDev ,
12151155 } }
12161156 />
0 commit comments