Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion frontend/src/app/hooks/useApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export const queryKeys = {
liquidatable: () => ["loans", "liquidatable"] as const,
borrowerPage: (address: string, params: Record<string, unknown>) =>
["loans", "borrower", address, params] as const,
// Prefix key that matches all borrowerPage entries for an address regardless of pagination params
borrowerPagePrefix: (address: string) => ["loans", "borrower", address] as const,
},
remittances: {
all: () => ["remittances"] as const,
Expand Down Expand Up @@ -858,6 +860,7 @@ export function useCreateLoan(
>,
) {
const queryClient = useQueryClient();
const walletAddress = useUserStore((s) => s.user?.walletAddress);

return useMutation<Loan & { txHash?: string }, Error, Omit<Loan, "id" | "createdAt" | "status">>({
mutationFn: (data) =>
Expand All @@ -866,8 +869,13 @@ export function useCreateLoan(
body: JSON.stringify(data),
}),
onSuccess: () => {
// Invalidate the loans list so it refetches with the new entry
queryClient.invalidateQueries({ queryKey: queryKeys.loans.all() });
// Also invalidate borrowerLoans.byAddress so both borrower-loan lists stay consistent (#1219)
if (walletAddress) {
queryClient.invalidateQueries({
queryKey: queryKeys.borrowerLoans.byAddress(walletAddress),
});
}
},
...options,
});
Expand Down Expand Up @@ -1556,6 +1564,10 @@ export function useRepayLoan() {
queryClient.invalidateQueries({
queryKey: queryKeys.borrowerLoans.byAddress(borrowerAddress),
});
// Also invalidate paginated borrower loans (borrowerPage) so both namespaces stay in sync (#1219)
queryClient.invalidateQueries({
queryKey: queryKeys.loans.borrowerPagePrefix(borrowerAddress),
});
queryClient.invalidateQueries({ queryKey: queryKeys.pool.stats() });
},
});
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/hooks/useLoanStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export function useLoanStream(loanId: string | undefined): RealtimeStatus {
queryClient.invalidateQueries({
queryKey: queryKeys.borrowerLoans.byAddress(borrowerAddress),
});
// Also invalidate paginated borrower loans so both namespaces stay in sync (#1219)
queryClient.invalidateQueries({
queryKey: queryKeys.loans.borrowerPagePrefix(borrowerAddress),
});
}
}, [borrowerAddress, loanId, queryClient]);

Expand Down
34 changes: 7 additions & 27 deletions frontend/src/app/hooks/useRepaymentOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useWallet } from "../components/providers/WalletProvider";
import {
useDepositToPool,
usePoolStats,
useRepayLoan,
useWithdrawFromPool,
submitPoolTransaction,
} from "./useApi";
Expand All @@ -46,11 +47,11 @@ export function useRepaymentOperation(options?: {
onSuccess?: (result: RepaymentOperationResult) => void;
onError?: (error: Error) => void;
}) {
const queryClient = useQueryClient();
const uid = useId();
const transactionId = `repayment-${uid}`;
const transaction = useTransaction(transactionId);
const [error, setError] = useState<string | null>(null);
const repayLoan = useRepayLoan();

const executeRepayment = useCallback(
async ({
Expand All @@ -62,37 +63,16 @@ export function useRepaymentOperation(options?: {
setError(null);

try {
// Step 1: Build unsigned transaction
transaction.updateProgress(20, "Building transaction...");
await new Promise((resolve) => setTimeout(resolve, 300));
transaction.updateProgress(20, "Submitting repayment...");

// Step 2: Sign transaction (new signing state)
transaction.sign("Waiting for wallet signature...");
await new Promise((resolve) => setTimeout(resolve, 500));
// useRepayLoan handles the full submit flow with optimistic cache updates
const response = await repayLoan.mutateAsync({ loanId, amount, borrowerAddress });
const txHash = response.txHash ?? String(loanId);

// Step 3: Submit to network (new submitted state)
const txHash = `tx_${Date.now()}`;
transaction.submit(txHash, "Transaction submitted, waiting for confirmation...");
await new Promise((resolve) => setTimeout(resolve, 300));

// Step 4: Poll for confirmation (new confirming state)
transaction.confirm("Confirming transaction...");
await new Promise((resolve) => setTimeout(resolve, 500));

// Mark complete
transaction.complete(txHash);

// Invalidate related queries
queryClient.invalidateQueries({
queryKey: ["loans"],
});
queryClient.invalidateQueries({
queryKey: ["borrowerLoans", borrowerAddress],
});
queryClient.invalidateQueries({
queryKey: ["pool", "stats"],
});

const result = { txHash, status: "success" as const };
options?.onSuccess?.(result);
return result;
Expand All @@ -104,7 +84,7 @@ export function useRepaymentOperation(options?: {
throw err;
}
},
[transaction, queryClient, options],
[transaction, repayLoan, options],
);

return {
Expand Down
Loading