@bytexbyte/nxtlinq-ai-agent-sdk 1.6.32 → 1.6.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"nxtlinq-api.d.ts","sourceRoot":"","sources":["../../src/api/nxtlinq-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAM1C,eAAO,MAAM,WAAW,GAAI,aAAa,YAAY,GAAG,SAAS,SAQhE,CAAC;AAibF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,KAAG,MAUpE,CAAC"}
1
+ {"version":3,"file":"nxtlinq-api.d.ts","sourceRoot":"","sources":["../../src/api/nxtlinq-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAM1C,eAAO,MAAM,WAAW,GAAI,aAAa,YAAY,GAAG,SAAS,SAQhE,CAAC;AA4eF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,KAAG,MAUpE,CAAC"}
@@ -106,6 +106,7 @@ const createAgentApi = () => ({
106
106
  customUserInfo: params.customUserInfo,
107
107
  customUsername: params.customUsername,
108
108
  message: params.message,
109
+ attachments: params.attachments,
109
110
  walletAddress: walletAddress || undefined,
110
111
  aitToken: aitToken || undefined,
111
112
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
@@ -295,7 +296,55 @@ const createAgentApi = () => ({
295
296
  console.error('Failed to update message content:', error);
296
297
  return { error: error instanceof Error ? error.message : 'Failed to update message content' };
297
298
  }
298
- }
299
+ },
300
+ uploadAttachment: async (params) => {
301
+ try {
302
+ const originalName = params.file.name;
303
+ const safeName = originalName.replace(/[^\x00-\x7F.a-zA-Z0-9_-]/g, '_').replace(/^\.+/, '') || 'file';
304
+ const fileForUpload = safeName !== originalName
305
+ ? new File([params.file], safeName, { type: params.file.type, lastModified: params.file.lastModified })
306
+ : params.file;
307
+ const form = new FormData();
308
+ form.append('file', fileForUpload);
309
+ form.append('pseudoId', params.pseudoId);
310
+ if (safeName !== originalName) {
311
+ form.append('originalName', originalName);
312
+ }
313
+ const walletAddress = typeof localStorage !== 'undefined' ? localStorage.getItem('walletAddress') : null;
314
+ const aitTokenRaw = typeof localStorage !== 'undefined' ? localStorage.getItem('nxtlinqAITServiceAccessToken') : null;
315
+ const aitToken = aitTokenRaw ? JSON.parse(aitTokenRaw) : null;
316
+ const headers = {
317
+ 'X-API-Key': params.apiKey,
318
+ 'X-API-Secret': params.apiSecret,
319
+ 'X-Wallet-Address': walletAddress || '',
320
+ 'X-AIT-Token': aitToken || '',
321
+ };
322
+ const response = await fetch(`${AI_AGENT_API_HOST}/api/upload`, {
323
+ method: 'POST',
324
+ headers,
325
+ body: form,
326
+ });
327
+ const text = await response.text();
328
+ let data;
329
+ try {
330
+ data = text ? JSON.parse(text) : {};
331
+ }
332
+ catch {
333
+ data = {};
334
+ }
335
+ if (!response.ok) {
336
+ return { error: data.error || response.statusText || 'Upload failed' };
337
+ }
338
+ if (!data.url) {
339
+ return { error: data.error || 'Upload failed' };
340
+ }
341
+ return data;
342
+ }
343
+ catch (e) {
344
+ console.error('Upload attachment failed:', e);
345
+ return { error: e instanceof Error ? e.message : 'Upload failed' };
346
+ }
347
+ },
299
348
  });
300
349
  // Permissions API module
301
350
  const createPermissionsApi = (apiKey, apiSecret) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBotContext.d.ts","sourceRoot":"","sources":["../../../src/components/context/ChatBotContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,EAEL,kBAAkB,EAClB,YAAY,EAEb,MAAM,uBAAuB,CAAC;AAM/B,eAAO,MAAM,UAAU,0BAMtB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAmuFlD,CAAC"}
1
+ {"version":3,"file":"ChatBotContext.d.ts","sourceRoot":"","sources":["../../../src/components/context/ChatBotContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,EAEL,kBAAkB,EAClB,YAAY,EAEb,MAAM,uBAAuB,CAAC;AAM/B,eAAO,MAAM,UAAU,0BAMtB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA2vFlD,CAAC"}
@@ -24,7 +24,7 @@ export const ChatBotProvider = ({ onMessage, onError, onToolUse, presetMessages
24
24
  // AI Model related attributes
25
25
  onModelChange,
26
26
  // Storage mode configuration
27
- useSessionStorage: useSessionStorageMode = false,
27
+ storageMode = "local-storage",
28
28
  // Wallet verification configuration
29
29
  requireWalletIDVVerification = true, isSemiAutomaticMode = false,
30
30
  // Custom user identity information
@@ -45,11 +45,11 @@ customError, }) => {
45
45
  apiKey,
46
46
  apiSecret
47
47
  });
48
- // Session-level data (always use sessionStorage when useSessionStorageMode is true)
49
- const [messages, setMessages] = useSessionStorageMode
50
- ? useSessionStorage('chatbot-messages', [])
51
- : React.useState([]);
52
- const [isOpen, setIsOpen] = useSessionStorageMode
48
+ // Messages: Use storage based on storageMode to support cross-tab sync (local-storage) or session isolation (session-storage)
49
+ const [messages, setMessages] = storageMode === "local-storage"
50
+ ? useLocalStorage('chatbot-messages', [])
51
+ : useSessionStorage('chatbot-messages', []);
52
+ const [isOpen, setIsOpen] = storageMode === "session-storage"
53
53
  ? useSessionStorage('chatbot-is-open', false)
54
54
  : React.useState(false);
55
55
  const [inputValue, setInputValue] = React.useState('');
@@ -69,12 +69,13 @@ customError, }) => {
69
69
  // Persistent data (always use localStorage)
70
70
  const [nxtlinqAITServiceAccessToken, setNxtlinqAITServiceAccessToken] = useLocalStorage('nxtlinqAITServiceAccessToken', '');
71
71
  const [pseudoId, setPseudoId] = useLocalStorage('pseudoId', uuidv4());
72
- // UI state (use session storage when useSessionStorageMode is true)
73
- const [suggestions, setSuggestions] = useSessionStorageMode
74
- ? useSessionStorage('chatbot-suggestions', presetMessages)
75
- : React.useState(presetMessages);
72
+ // Suggestions: Use storage based on storageMode to support cross-tab sync (local-storage) or session isolation (session-storage)
73
+ const [suggestions, setSuggestions] = storageMode === "local-storage"
74
+ ? useLocalStorage('chatbot-suggestions', presetMessages)
75
+ : useSessionStorage('chatbot-suggestions', presetMessages);
76
76
  const [isAITEnabling, setIsAITEnabling] = React.useState(false);
77
77
  const [isAwaitingMicGesture, setIsAwaitingMicGesture] = React.useState(false);
78
+ // autoSendEnabled: Always use localStorage (do not sync across tabs to avoid conflicts with speech-to-text)
78
79
  const [autoSendEnabled, setAutoSendEnabled] = useLocalStorage('chatbot-auto-send-enabled', true);
79
80
  // Speech related state
80
81
  const [textToSpeechEnabled, setTextToSpeechEnabled] = useLocalStorage('chatbot-text-to-speech-enabled', false);
@@ -465,7 +466,7 @@ customError, }) => {
465
466
  if (typeof window === 'undefined') {
466
467
  return;
467
468
  }
468
- if (!useSessionStorageMode) {
469
+ if (storageMode !== "session-storage") {
469
470
  sessionStorage.removeItem(MIC_ENABLED_SESSION_KEY);
470
471
  hasSyncedMicStateRef.current = false;
471
472
  return;
@@ -479,7 +480,7 @@ customError, }) => {
479
480
  catch (error) {
480
481
  console.warn('Failed to persist recording state to sessionStorage:', error);
481
482
  }
482
- }, [isMicEnabled, useSessionStorageMode]);
483
+ }, [isMicEnabled, storageMode]);
483
484
  React.useEffect(() => {
484
485
  if (typeof window === 'undefined') {
485
486
  return;
@@ -490,7 +491,7 @@ customError, }) => {
490
491
  autoStartGestureCleanupRef.current = null;
491
492
  }
492
493
  };
493
- if (!useSessionStorageMode) {
494
+ if (storageMode !== "session-storage") {
494
495
  cleanupAutoStartListeners();
495
496
  pendingMicAutoStartRef.current = false;
496
497
  setIsAwaitingMicGesture(false);
@@ -627,7 +628,7 @@ customError, }) => {
627
628
  pendingMicAutoStartRef.current = false;
628
629
  setIsAwaitingMicGesture(false);
629
630
  };
630
- }, [useSessionStorageMode, startRecording]);
631
+ }, [storageMode, startRecording]);
631
632
  const [notification, setNotification] = React.useState({
632
633
  show: false,
633
634
  type: 'info',
@@ -1341,9 +1342,10 @@ customError, }) => {
1341
1342
  autoSend: true
1342
1343
  })));
1343
1344
  }, []);
1344
- // Updated sendMessage function to support different AI models
1345
- const sendMessage = async (content, retryCount = 0, isPresetMessage = false) => {
1346
- if (!content.trim() || isLoading)
1345
+ // Updated sendMessage function to support different AI models and attachments
1346
+ const sendMessage = async (content, retryCount = 0, isPresetMessage = false, attachments) => {
1347
+ const hasContent = content.trim() || (attachments && attachments.length > 0);
1348
+ if (!hasContent || isLoading)
1347
1349
  return;
1348
1350
  const currentModel = getCurrentModel();
1349
1351
  // Initialize with current model, will be updated with actual model from backend response
@@ -1353,9 +1355,10 @@ customError, }) => {
1353
1355
  if (retryCount === 0 && !isPresetMessage) {
1354
1356
  const userMessage = {
1355
1357
  id: Date.now().toString(),
1356
- content,
1358
+ content: content || (attachments && attachments.length > 0 ? `已上傳 ${attachments.length} 個檔案` : ''),
1357
1359
  role: 'user',
1358
1360
  timestamp: new Date().toISOString(),
1361
+ attachments: attachments,
1359
1362
  metadata: {
1360
1363
  model: currentModel.value,
1361
1364
  permissions: permissions,
@@ -1367,6 +1370,13 @@ customError, }) => {
1367
1370
  }
1368
1371
  setIsLoading(true);
1369
1372
  try {
1373
+ // Prepare attachments for API
1374
+ const apiAttachments = attachments?.map(att => ({
1375
+ type: att.type,
1376
+ url: att.url,
1377
+ name: att.name,
1378
+ mimeType: att.mimeType
1379
+ }));
1370
1380
  const response = await nxtlinqApi.agent.sendMessage({
1371
1381
  model: currentModel.value,
1372
1382
  apiKey,
@@ -1375,7 +1385,8 @@ customError, }) => {
1375
1385
  externalId: localStorage.getItem('walletAddress') || undefined,
1376
1386
  customUserInfo,
1377
1387
  customUsername,
1378
- message: content,
1388
+ message: content || (attachments && attachments.length > 0 ? `已上傳 ${attachments.length} 個檔案` : ''),
1389
+ attachments: apiAttachments,
1379
1390
  });
1380
1391
  // Get the actual model used from response (may differ due to fallback)
1381
1392
  actualModelUsed = response.model || currentModel.value;
@@ -1786,7 +1797,7 @@ customError, }) => {
1786
1797
  }
1787
1798
  };
1788
1799
  // Handle submit
1789
- const handleSubmit = async (e) => {
1800
+ const handleSubmit = async (e, attachments) => {
1790
1801
  e.preventDefault();
1791
1802
  if (isStopRecordingOnSend) {
1792
1803
  while (isMicEnabledRef.current) {
@@ -1802,7 +1813,8 @@ customError, }) => {
1802
1813
  }
1803
1814
  if (!textInputRef.current)
1804
1815
  return;
1805
- if (!textInputRef.current.value.trim() || isLoading)
1816
+ const hasContent = textInputRef.current.value.trim() || (attachments && attachments.length > 0);
1817
+ if (!hasContent || isLoading)
1806
1818
  return;
1807
1819
  // 如果此時有語音自動發送的計時器,優先取消,避免與手動發送同內容時重複送出
1808
1820
  if (autoSendTimerRef.current) {
@@ -1833,7 +1845,7 @@ customError, }) => {
1833
1845
  return;
1834
1846
  }
1835
1847
  try {
1836
- await sendMessage(textInputRef.current.value);
1848
+ await sendMessage(textInputRef.current.value, 0, false, attachments);
1837
1849
  }
1838
1850
  catch (error) {
1839
1851
  console.error('Failed to send message:', error);
@@ -1946,6 +1958,17 @@ customError, }) => {
1946
1958
  window.addEventListener('pointerdown', handleUserGesture, { once: true });
1947
1959
  return () => window.removeEventListener('pointerdown', handleUserGesture);
1948
1960
  }, [requiresGesture, textToSpeechEnabled, retryTtsWithGesture]);
1961
+ const uploadAttachment = React.useCallback(async (file) => {
1962
+ const result = await nxtlinqApi.agent.uploadAttachment({
1963
+ apiKey,
1964
+ apiSecret,
1965
+ pseudoId,
1966
+ file,
1967
+ });
1968
+ if ('error' in result)
1969
+ return result;
1970
+ return { url: result.url };
1971
+ }, [nxtlinqApi, apiKey, apiSecret, pseudoId]);
1949
1972
  // Handle preset message
1950
1973
  const handlePresetMessage = (message) => {
1951
1974
  // If preset is configured as auto-send, avoid duplicate sends when user clicks repeatedly
@@ -2530,6 +2553,7 @@ customError, }) => {
2530
2553
  playTextToSpeech,
2531
2554
  stopTextToSpeech,
2532
2555
  retryTtsWithGesture,
2556
+ uploadAttachment,
2533
2557
  // Additional properties for PermissionForm
2534
2558
  onSave: savePermissions,
2535
2559
  onConnectWallet: () => connectWallet(false),
@@ -2554,7 +2578,7 @@ customError, }) => {
2554
2578
  onVerifyWallet,
2555
2579
  permissionGroup,
2556
2580
  onModelChange,
2557
- useSessionStorage: useSessionStorageMode,
2581
+ storageMode,
2558
2582
  requireWalletIDVVerification,
2559
2583
  isSemiAutomaticMode,
2560
2584
  customUserInfo,
@@ -53,7 +53,7 @@ export interface ChatBotProps {
53
53
  permissionGroup?: string;
54
54
  children?: React.ReactNode;
55
55
  onModelChange?: (model: AIModel) => void;
56
- useSessionStorage?: boolean;
56
+ storageMode?: "session-storage" | "local-storage";
57
57
  requireWalletIDVVerification?: boolean;
58
58
  isSemiAutomaticMode?: boolean;
59
59
  customUserInfo?: Record<string, any>;
@@ -115,7 +115,7 @@ export interface ChatBotContextType {
115
115
  connectWallet: (autoShowSignInMessage?: boolean) => Promise<string | false | undefined>;
116
116
  signInWallet: (autoShowSuccessMessage?: boolean) => Promise<void>;
117
117
  sendMessage: (content: string, retryCount?: number) => Promise<void>;
118
- handleSubmit: (e: React.FormEvent) => Promise<void>;
118
+ handleSubmit: (e: React.FormEvent, attachments?: import('../../types/ait-api').Attachment[]) => Promise<void>;
119
119
  handlePresetMessage: (message: PresetMessage) => void;
120
120
  savePermissions: (newPermissions?: string[]) => Promise<void>;
121
121
  enableAIT: (toolName: string) => Promise<boolean>;
@@ -133,6 +133,11 @@ export interface ChatBotContextType {
133
133
  playTextToSpeech: (text: string) => Promise<void>;
134
134
  stopTextToSpeech: () => void;
135
135
  retryTtsWithGesture?: () => Promise<void>;
136
+ uploadAttachment: (file: File) => Promise<{
137
+ url: string;
138
+ } | {
139
+ error: string;
140
+ }>;
136
141
  onSave: (newPermissions?: string[]) => Promise<void>;
137
142
  onConnectWallet: () => Promise<string | false | undefined>;
138
143
  onSignIn: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBotTypes.d.ts","sourceRoot":"","sources":["../../../src/components/types/ChatBotTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChatBotTypes.d.ts","sourceRoot":"","sources":["../../../src/components/types/ChatBotTypes.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- /** @jsxImportSource @emotion/react */
2
1
  import * as React from 'react';
3
2
  export declare const ChatBotUI: React.FC;
4
3
  //# sourceMappingURL=ChatBotUI.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBotUI.d.ts","sourceRoot":"","sources":["../../../src/components/ui/ChatBotUI.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA8F/B,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAooB7B,CAAC"}
1
+ {"version":3,"file":"ChatBotUI.d.ts","sourceRoot":"","sources":["../../../src/components/ui/ChatBotUI.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA4F/B,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAwrB7B,CAAC"}
@@ -1,19 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  /** @jsxImportSource @emotion/react */
3
- import * as React from 'react';
4
3
  import { css } from '@emotion/react';
4
+ import * as React from 'react';
5
+ import { useDraggable } from '../../core/lib/useDraggable';
6
+ import useLocalStorage from '../../core/lib/useLocalStorage';
7
+ import { useResizable } from '../../core/lib/useResizable';
8
+ import * as walletTextUtils from '../../core/utils/walletTextUtils';
5
9
  import { useChatBot } from '../context/ChatBotContext';
6
- import { PermissionForm } from './PermissionForm';
7
- import { MessageList } from './MessageList';
8
10
  import { MessageInput } from './MessageInput';
9
- import { PresetMessages } from './PresetMessages';
11
+ import { MessageList } from './MessageList';
10
12
  import { ModelSelector } from './ModelSelector';
11
- import * as walletTextUtils from '../../core/utils/walletTextUtils';
12
- import { useResizable } from '../../core/lib/useResizable';
13
- import { useDraggable } from '../../core/lib/useDraggable';
14
- import useLocalStorage from '../../core/lib/useLocalStorage';
15
- import { sdkContainer, floatingButton, chatWindow, chatHeader, headerTitle, headerButton, closeButton, modalOverlay, idvBanner, idvBannerTitle, idvBannerText, idvVerifyButton, idvDismissButton, loadingSpinner, successToast, errorToast, warningToast, infoToast, toastCloseButton } from './styles/isolatedStyles';
16
- import { resizeHandle } from './styles/isolatedStyles';
13
+ import { PermissionForm } from './PermissionForm';
14
+ import { PresetMessages } from './PresetMessages';
15
+ import { chatHeader, chatWindow, closeButton, errorToast, floatingButton, headerButton, headerTitle, idvBanner, idvBannerText, idvBannerTitle, idvDismissButton, idvVerifyButton, infoToast, loadingSpinner, modalOverlay, resizeHandle, sdkContainer, successToast, toastCloseButton, warningToast } from './styles/isolatedStyles';
17
16
  // Toast Notification Component
18
17
  const ToastNotification = ({ type, message, onClose, isChatOpen = false }) => {
19
18
  const getToastStyles = () => {
@@ -71,10 +70,62 @@ export const ChatBotUI = () => {
71
70
  const [showIDVSuggestion, setShowIDVSuggestion] = React.useState(true);
72
71
  const [dismissUntil, setDismissUntil] = React.useState(null);
73
72
  const [timeRemaining, setTimeRemaining] = React.useState('');
73
+ const countdownIntervalRef = React.useRef(null);
74
74
  // Check if there's a berifyme token in URL (indicating recent berifyme verification)
75
75
  const urlParams = new URLSearchParams(window.location.search);
76
76
  const hasBerifymeToken = urlParams.get('token') && urlParams.get('method') === 'berifyme';
77
77
  const isWalletVerifiedWithBerifyme = walletInfo?.id && walletInfo?.method === 'berifyme';
78
+ // Helper function to update IDV suggestion state based on storage value
79
+ const updateIDVSuggestionState = React.useCallback((dismissedValue) => {
80
+ // Clear any existing countdown interval
81
+ if (countdownIntervalRef.current) {
82
+ clearInterval(countdownIntervalRef.current);
83
+ countdownIntervalRef.current = null;
84
+ }
85
+ if (dismissedValue) {
86
+ const dismissTime = parseInt(dismissedValue);
87
+ const now = Date.now();
88
+ const timeLeft = dismissTime - now;
89
+ if (timeLeft > 0) {
90
+ setShowIDVSuggestion(false);
91
+ setDismissUntil(dismissTime);
92
+ // Calculate initial time remaining immediately
93
+ const hours = Math.floor(timeLeft / (1000 * 60 * 60));
94
+ const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
95
+ setTimeRemaining(`${hours}h ${minutes}m`);
96
+ // Set up countdown interval to update time remaining every minute
97
+ countdownIntervalRef.current = setInterval(() => {
98
+ const remaining = dismissTime - Date.now();
99
+ if (remaining > 0) {
100
+ const hours = Math.floor(remaining / (1000 * 60 * 60));
101
+ const minutes = Math.floor((remaining % (1000 * 60 * 60)) / (1000 * 60));
102
+ setTimeRemaining(`${hours}h ${minutes}m`);
103
+ }
104
+ else {
105
+ setShowIDVSuggestion(true);
106
+ setDismissUntil(null);
107
+ setTimeRemaining('');
108
+ localStorage.removeItem('idv-suggestion-dismissed');
109
+ if (countdownIntervalRef.current) {
110
+ clearInterval(countdownIntervalRef.current);
111
+ countdownIntervalRef.current = null;
112
+ }
113
+ }
114
+ }, 60000);
115
+ }
116
+ else {
117
+ localStorage.removeItem('idv-suggestion-dismissed');
118
+ setShowIDVSuggestion(true);
119
+ setDismissUntil(null);
120
+ setTimeRemaining('');
121
+ }
122
+ }
123
+ else {
124
+ setShowIDVSuggestion(true);
125
+ setDismissUntil(null);
126
+ setTimeRemaining('');
127
+ }
128
+ }, []);
78
129
  // Check if IDV suggestion should be shown
79
130
  React.useEffect(() => {
80
131
  const shouldShowBanner = hitAddress &&
@@ -91,42 +142,7 @@ export const ChatBotUI = () => {
91
142
  !isNeedSignInWithWallet;
92
143
  if (shouldShowBannerAfterDelay) {
93
144
  const dismissed = localStorage.getItem('idv-suggestion-dismissed');
94
- if (dismissed) {
95
- const dismissTime = parseInt(dismissed);
96
- const now = Date.now();
97
- const timeLeft = dismissTime - now;
98
- if (timeLeft > 0) {
99
- setShowIDVSuggestion(false);
100
- setDismissUntil(dismissTime);
101
- const countdownTimer = setInterval(() => {
102
- const remaining = dismissTime - Date.now();
103
- if (remaining > 0) {
104
- const hours = Math.floor(remaining / (1000 * 60 * 60));
105
- const minutes = Math.floor((remaining % (1000 * 60 * 60)) / (1000 * 60));
106
- setTimeRemaining(`${hours}h ${minutes}m`);
107
- }
108
- else {
109
- setShowIDVSuggestion(true);
110
- setDismissUntil(null);
111
- setTimeRemaining('');
112
- localStorage.removeItem('idv-suggestion-dismissed');
113
- clearInterval(countdownTimer);
114
- }
115
- }, 60000);
116
- return () => clearInterval(countdownTimer);
117
- }
118
- else {
119
- localStorage.removeItem('idv-suggestion-dismissed');
120
- setShowIDVSuggestion(true);
121
- setDismissUntil(null);
122
- setTimeRemaining('');
123
- }
124
- }
125
- else {
126
- setShowIDVSuggestion(true);
127
- setDismissUntil(null);
128
- setTimeRemaining('');
129
- }
145
+ updateIDVSuggestionState(dismissed);
130
146
  }
131
147
  else {
132
148
  setShowIDVSuggestion(false);
@@ -134,7 +150,14 @@ export const ChatBotUI = () => {
134
150
  setTimeRemaining('');
135
151
  }
136
152
  }, 1000);
137
- return () => clearTimeout(timer);
153
+ return () => {
154
+ clearTimeout(timer);
155
+ // Clear countdown interval on cleanup
156
+ if (countdownIntervalRef.current) {
157
+ clearInterval(countdownIntervalRef.current);
158
+ countdownIntervalRef.current = null;
159
+ }
160
+ };
138
161
  }
139
162
  else {
140
163
  // Don't show when:
@@ -144,13 +167,39 @@ export const ChatBotUI = () => {
144
167
  setDismissUntil(null);
145
168
  setTimeRemaining('');
146
169
  }
147
- }, [hitAddress, walletInfo, isNeedSignInWithWallet, props.requireWalletIDVVerification]);
170
+ }, [hitAddress, walletInfo, isNeedSignInWithWallet, props.requireWalletIDVVerification, updateIDVSuggestionState]);
148
171
  const handleDismissIDV = () => {
149
172
  const dismissSeconds = props.idvBannerDismissSeconds || 86400;
150
173
  const dismissTime = Date.now() + (dismissSeconds * 1000);
151
174
  localStorage.setItem('idv-suggestion-dismissed', dismissTime.toString());
152
175
  setShowIDVSuggestion(false);
153
176
  setDismissUntil(dismissTime);
177
+ // Calculate and set initial time remaining
178
+ const initialHours = Math.floor(dismissSeconds / 3600);
179
+ const initialMinutes = Math.floor((dismissSeconds % 3600) / 60);
180
+ setTimeRemaining(`${initialHours}h ${initialMinutes}m`);
181
+ // Set up countdown interval
182
+ if (countdownIntervalRef.current) {
183
+ clearInterval(countdownIntervalRef.current);
184
+ }
185
+ countdownIntervalRef.current = setInterval(() => {
186
+ const remaining = dismissTime - Date.now();
187
+ if (remaining > 0) {
188
+ const remainingHours = Math.floor(remaining / (1000 * 60 * 60));
189
+ const remainingMinutes = Math.floor((remaining % (1000 * 60 * 60)) / (1000 * 60));
190
+ setTimeRemaining(`${remainingHours}h ${remainingMinutes}m`);
191
+ }
192
+ else {
193
+ setShowIDVSuggestion(true);
194
+ setDismissUntil(null);
195
+ setTimeRemaining('');
196
+ localStorage.removeItem('idv-suggestion-dismissed');
197
+ if (countdownIntervalRef.current) {
198
+ clearInterval(countdownIntervalRef.current);
199
+ countdownIntervalRef.current = null;
200
+ }
201
+ }
202
+ }, 60000);
154
203
  const hours = Math.floor(dismissSeconds / 3600);
155
204
  const minutes = Math.floor((dismissSeconds % 3600) / 60);
156
205
  const timeText = hours > 0
@@ -1 +1 @@
1
- {"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/ui/MessageInput.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EA2LhC,CAAC"}
1
+ {"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/ui/MessageInput.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EA6ehC,CAAC"}