Skip to content

Commit 66cdf8c

Browse files
committed
get rid of zustand store for portfolio and refactor suggestStore
1 parent 0d9af38 commit 66cdf8c

10 files changed

Lines changed: 224 additions & 607 deletions

File tree

listen-interface/src/components/Chat.tsx

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { usePrivy } from "@privy-io/react-auth";
2-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2+
import { useCallback, useEffect, useRef, useState } from "react";
33
import { useTranslation } from "react-i18next";
44
import { useChat } from "../contexts/ChatContext";
55
import { useModal } from "../contexts/ModalContext";
66
import { useSettingsStore } from "../store/settingsStore";
7-
import { useSuggestStore } from "../store/suggestStore";
7+
import { useSuggestions } from "../hooks/useSuggestions";
8+
import { useSolanaPortfolio } from "../hooks/useSolanaPortfolio";
9+
import { useEvmPortfolio } from "../hooks/useEvmPortfolio";
10+
import { useWalletStore } from "../store/walletStore";
811
import {
912
ParToolCallSchema,
1013
RigToolCall,
@@ -55,18 +58,45 @@ export function Chat({ selectedChatId }: { selectedChatId?: string }) {
5558
nestedAgentOutput,
5659
} = useChat();
5760

61+
const { displaySuggestions, chatType } = useSettingsStore();
62+
63+
// Get wallet addresses
5864
const {
59-
getSuggestions,
60-
isLoading: isSuggestionsLoading,
61-
fetchSuggestions,
62-
} = useSuggestStore();
65+
solanaAddress,
66+
evmAddress,
67+
eoaSolanaAddress,
68+
eoaEvmAddress,
69+
activeWallet,
70+
} = useWalletStore();
71+
72+
// Get current addresses based on active wallet
73+
const currentSolanaAddress =
74+
activeWallet === "listen"
75+
? solanaAddress
76+
: activeWallet === "eoaSolana"
77+
? eoaSolanaAddress
78+
: null;
79+
80+
const currentEvmAddress =
81+
activeWallet === "listen"
82+
? evmAddress
83+
: activeWallet === "eoaEvm"
84+
? eoaEvmAddress
85+
: null;
6386

64-
const { displaySuggestions } = useSettingsStore();
87+
// Get portfolio data
88+
const { data: solanaPortfolio = [] } = useSolanaPortfolio(currentSolanaAddress);
89+
const { data: evmPortfolio = [] } = useEvmPortfolio(currentEvmAddress);
90+
91+
// Combine portfolios
92+
const combinedPortfolio = [...(solanaPortfolio || []), ...(evmPortfolio || [])];
6593

66-
// Memoize the suggestions selector
67-
const suggestions = useMemo(() => {
68-
return urlParams.chatId ? getSuggestions(urlParams.chatId) : [];
69-
}, [urlParams.chatId, getSuggestions]);
94+
const {
95+
suggestions,
96+
isLoading: isSuggestionsLoading,
97+
fetchSuggestions,
98+
clearSuggestions,
99+
} = useSuggestions(urlParams.chatId || "");
70100

71101
const lastUserMessageRef = useRef<HTMLDivElement>(null);
72102
const [inputMessage, setInputMessage] = useState("");
@@ -133,10 +163,10 @@ export function Chat({ selectedChatId }: { selectedChatId?: string }) {
133163
}
134164
setInputMessage("");
135165
if (urlParams.chatId) {
136-
useSuggestStore.getState().clearSuggestions(urlParams.chatId);
166+
clearSuggestions();
137167
}
138168
},
139-
[sendMessage, setMessages, urlParams.chatId]
169+
[sendMessage, setMessages, urlParams.chatId, clearSuggestions]
140170
);
141171

142172
// Focus the input field when creating a new chat
@@ -264,9 +294,9 @@ export function Chat({ selectedChatId }: { selectedChatId?: string }) {
264294

265295
if (shouldFetchSuggestions) {
266296
fetchSuggestions(
267-
urlParams.chatId,
268297
messages,
269-
getAccessToken,
298+
combinedPortfolio,
299+
chatType,
270300
i18n.language
271301
);
272302
}
@@ -278,6 +308,10 @@ export function Chat({ selectedChatId }: { selectedChatId?: string }) {
278308
suggestions.length,
279309
getAccessToken,
280310
i18n.language,
311+
fetchSuggestions,
312+
combinedPortfolio,
313+
chatType,
314+
displaySuggestions,
281315
]);
282316

283317
if (IS_DISABLED) {

listen-interface/src/components/ChatContainer.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ReactNode } from "react";
22
import { useTranslation } from "react-i18next";
33
import { useSettingsStore } from "../store/settingsStore";
4-
import { useSuggestStore } from "../store/suggestStore";
4+
import { useSuggestions } from "../hooks/useSuggestions";
55
import { ChatInput } from "./ChatInput";
66
import { NewChatTiles } from "./NewChatTiles";
77
import { SuggestionTiles } from "./SuggestionTiles";
@@ -36,9 +36,8 @@ export function ChatContainer({
3636
chatId,
3737
}: ChatContainerProps) {
3838
const { t } = useTranslation();
39-
const { getSuggestions, lastMessageHadSpecialTags } = useSuggestStore();
4039
const { displaySuggestions } = useSettingsStore();
41-
const suggestions = chatId ? getSuggestions(chatId) : [];
40+
const { suggestions, lastMessageHadSpecialTags } = useSuggestions(chatId || "");
4241

4342
const RECOMMENDED_QUESTIONS_TILES = [
4443
{

listen-interface/src/components/MessageRenderer.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo } from "react";
22
import { useTranslation } from "react-i18next";
33
import { processMessageWithAllTags, tagHandlers } from "../process-tags";
44
import { useSettingsStore } from "../store/settingsStore";
5-
import { useSuggestStore } from "../store/suggestStore";
5+
import { useSuggestions } from "../hooks/useSuggestions";
66
import {
77
ParToolResultSchema,
88
ToolCallSchema,
@@ -68,7 +68,9 @@ export function MessageRendererBase({
6868
}) {
6969
const { t } = useTranslation();
7070
const { debugMode } = useSettingsStore();
71-
const { setLastMessageHadSpecialTags } = useSuggestStore();
71+
// We need chatId for the hook, but it's not passed to MessageRenderer
72+
// For now, we'll use an empty string as MessageRenderer doesn't fetch suggestions
73+
const { setLastMessageHadSpecialTags } = useSuggestions("");
7274

7375
if (debugMode && msg.direction === "incoming") {
7476
return (

listen-interface/src/hooks/useEoaExecution.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { Connection, VersionedTransaction } from "@solana/web3.js";
33
import { type EIP1193Provider } from "viem";
44
import { ensureApprovals } from "../lib/approvals";
55
import { swapStepToTransaction } from "../lib/eoa-tx";
6-
import { usePortfolioStore } from "../store/portfolioStore";
6+
import { useInvalidatePortfolio } from "./useInvalidatePortfolio";
77
import { SwapOrderAction } from "../types/pipeline";
88
import { waitForTransaction } from "../utils/transactionMonitor";
99

1010
export function useEoaExecution() {
1111
const { wallets: evmWallets } = useWallets();
1212
const { wallets: solanaWallets } = useSolanaWallets();
13-
const { refreshPortfolio } = usePortfolioStore();
13+
const { refreshPortfolio } = useInvalidatePortfolio();
1414

1515
const handleEoaSolana = async (
1616
action: SwapOrderAction,
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { useQueryClient } from "@tanstack/react-query";
2+
import { useCallback } from "react";
3+
import { useWalletStore } from "../store/walletStore";
4+
5+
export function useInvalidatePortfolio() {
6+
const queryClient = useQueryClient();
7+
const {
8+
solanaAddress,
9+
evmAddress,
10+
eoaSolanaAddress,
11+
eoaEvmAddress,
12+
activeWallet,
13+
} = useWalletStore();
14+
15+
const invalidatePortfolio = useCallback(
16+
async (invalidateAll?: boolean) => {
17+
const invalidations = [];
18+
19+
if (invalidateAll) {
20+
// Invalidate all portfolio queries
21+
if (solanaAddress) {
22+
invalidations.push(
23+
queryClient.invalidateQueries({
24+
queryKey: ["solana-portfolio", solanaAddress],
25+
})
26+
);
27+
}
28+
if (evmAddress) {
29+
invalidations.push(
30+
queryClient.invalidateQueries({
31+
queryKey: ["evm-portfolio", evmAddress],
32+
}),
33+
queryClient.invalidateQueries({
34+
queryKey: ["hyperliquid-portfolio", evmAddress],
35+
})
36+
);
37+
}
38+
if (eoaSolanaAddress) {
39+
invalidations.push(
40+
queryClient.invalidateQueries({
41+
queryKey: ["solana-portfolio", eoaSolanaAddress],
42+
})
43+
);
44+
}
45+
if (eoaEvmAddress) {
46+
invalidations.push(
47+
queryClient.invalidateQueries({
48+
queryKey: ["evm-portfolio", eoaEvmAddress],
49+
}),
50+
queryClient.invalidateQueries({
51+
queryKey: ["hyperliquid-portfolio", eoaEvmAddress],
52+
})
53+
);
54+
}
55+
} else {
56+
// Invalidate only active wallet queries
57+
const currentSolanaAddress =
58+
activeWallet === "listen"
59+
? solanaAddress
60+
: activeWallet === "eoaSolana"
61+
? eoaSolanaAddress
62+
: null;
63+
64+
const currentEvmAddress =
65+
activeWallet === "listen"
66+
? evmAddress
67+
: activeWallet === "eoaEvm"
68+
? eoaEvmAddress
69+
: null;
70+
71+
if (currentSolanaAddress) {
72+
invalidations.push(
73+
queryClient.invalidateQueries({
74+
queryKey: ["solana-portfolio", currentSolanaAddress],
75+
})
76+
);
77+
}
78+
if (currentEvmAddress) {
79+
invalidations.push(
80+
queryClient.invalidateQueries({
81+
queryKey: ["evm-portfolio", currentEvmAddress],
82+
}),
83+
queryClient.invalidateQueries({
84+
queryKey: ["hyperliquid-portfolio", currentEvmAddress],
85+
})
86+
);
87+
}
88+
}
89+
90+
await Promise.all(invalidations);
91+
},
92+
[
93+
queryClient,
94+
solanaAddress,
95+
evmAddress,
96+
eoaSolanaAddress,
97+
eoaEvmAddress,
98+
activeWallet,
99+
]
100+
);
101+
102+
return { refreshPortfolio: invalidatePortfolio };
103+
}

listen-interface/src/hooks/usePipelines.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { usePrivy } from "@privy-io/react-auth";
22
import { useQuery } from "@tanstack/react-query";
33
import { useEffect, useRef } from "react";
44
import { config } from "../config";
5-
import { usePortfolioStore } from "../store/portfolioStore";
5+
import { useInvalidatePortfolio } from "./useInvalidatePortfolio";
66
import { ExtendedPipelineResponse, ExtendedPipelineSchema } from "../types/api";
77
import { waitForTransaction } from "../utils/transactionMonitor";
88
import { useIsAuthenticated } from "./useIsAuthenticated";
@@ -18,7 +18,7 @@ const MONITORING_TX_HASHES = new Set<string>();
1818
export const usePipelines = () => {
1919
const { isAuthenticated } = useIsAuthenticated();
2020
const { getAccessToken, ready } = usePrivy();
21-
const refreshPortfolio = usePortfolioStore((state) => state.refreshPortfolio);
21+
const { refreshPortfolio } = useInvalidatePortfolio();
2222

2323
// Use a local ref for debounce timing
2424
const pendingRefreshTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { useCallback } from "react";
2+
import { usePrivy } from "@privy-io/react-auth";
3+
import { useSuggestStore } from "../store/suggestStore";
4+
import { Message } from "../types/message";
5+
import { PortfolioItem } from "../lib/types";
6+
7+
export function useSuggestions(chatId: string) {
8+
const { getAccessToken } = usePrivy();
9+
const {
10+
getSuggestions,
11+
fetchSuggestions,
12+
clearSuggestions,
13+
isLoading,
14+
error,
15+
lastMessageHadSpecialTags,
16+
setLastMessageHadSpecialTags,
17+
} = useSuggestStore();
18+
19+
const suggestions = getSuggestions(chatId);
20+
21+
const fetchSuggestionsWithPortfolio = useCallback(
22+
async (
23+
messages: Message[],
24+
portfolio: PortfolioItem[],
25+
chatType: string,
26+
locale?: string
27+
) => {
28+
return fetchSuggestions(
29+
chatId,
30+
messages,
31+
getAccessToken,
32+
portfolio,
33+
chatType,
34+
locale
35+
);
36+
},
37+
[chatId, fetchSuggestions, getAccessToken]
38+
);
39+
40+
const clear = useCallback(() => {
41+
clearSuggestions(chatId);
42+
}, [chatId, clearSuggestions]);
43+
44+
return {
45+
suggestions,
46+
fetchSuggestions: fetchSuggestionsWithPortfolio,
47+
clearSuggestions: clear,
48+
isLoading,
49+
error,
50+
lastMessageHadSpecialTags,
51+
setLastMessageHadSpecialTags,
52+
};
53+
}

listen-interface/src/hooks/useWaitForTransaction.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Connection, TransactionSignature } from "@solana/web3.js";
22
import { useQuery, useQueryClient } from "@tanstack/react-query";
3-
import { usePortfolioStore } from "../store/portfolioStore";
3+
import { useInvalidatePortfolio } from "./useInvalidatePortfolio";
44

55
interface TransactionResult {
66
success: boolean;
@@ -13,7 +13,7 @@ export const useWaitForTransaction = (
1313
) => {
1414
const connection = new Connection(import.meta.env.VITE_RPC_URL);
1515
const queryClient = useQueryClient();
16-
const { refreshPortfolio } = usePortfolioStore();
16+
const { refreshPortfolio } = useInvalidatePortfolio();
1717

1818
return useQuery<TransactionResult>({
1919
queryKey: ["transaction", signature],

0 commit comments

Comments
 (0)