codex/broker-operations-ui #18
@ -1,5 +1,5 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { getBrokerOperations } from './broker';
|
import { getBrokerOperations, getBrokerPositions } from './broker';
|
||||||
|
|
||||||
describe('broker api', () => {
|
describe('broker api', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -24,4 +24,23 @@ describe('broker api', () => {
|
|||||||
expect.any(Object),
|
expect.any(Object),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('serializes positions query parameters', async () => {
|
||||||
|
vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({
|
||||||
|
data: {
|
||||||
|
data: { accountId: 'acc-1', items: [], nextCursor: null, hasNext: false, asOf: 'now' },
|
||||||
|
meta: { fromCache: false, cachedAt: null },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
} as Response);
|
||||||
|
|
||||||
|
await getBrokerPositions('acc-1', { cursor: 'pos-1', limit: 5 });
|
||||||
|
|
||||||
|
expect(fetch).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('/api/v1/broker/accounts/acc-1/positions?cursor=pos-1&limit=5'),
|
||||||
|
expect.any(Object),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type {
|
|||||||
BrokerAccount,
|
BrokerAccount,
|
||||||
BrokerOperationsPage,
|
BrokerOperationsPage,
|
||||||
BrokerPortfolio,
|
BrokerPortfolio,
|
||||||
|
BrokerPositionsPage,
|
||||||
} from './responses';
|
} from './responses';
|
||||||
|
|
||||||
export type BrokerOperationQuery = {
|
export type BrokerOperationQuery = {
|
||||||
@ -49,3 +50,16 @@ export function getBrokerOperations(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBrokerPositions(
|
||||||
|
accountId: string,
|
||||||
|
query: { cursor?: string; limit?: number } = {},
|
||||||
|
): Promise<{ data: BrokerPositionsPage; meta: ApiResponseMeta }> {
|
||||||
|
return request<BrokerPositionsPage>(
|
||||||
|
`/api/v1/broker/accounts/${encodeURIComponent(accountId)}/positions`,
|
||||||
|
{
|
||||||
|
cursor: query.cursor,
|
||||||
|
limit: query.limit ? String(query.limit) : undefined,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -299,7 +299,6 @@ export interface BrokerPortfolio {
|
|||||||
};
|
};
|
||||||
cash: BrokerMoney[];
|
cash: BrokerMoney[];
|
||||||
blockedCash: BrokerMoney[];
|
blockedCash: BrokerMoney[];
|
||||||
positions: BrokerPosition[];
|
|
||||||
asOf: string;
|
asOf: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +313,7 @@ export interface BrokerOperation {
|
|||||||
type: string;
|
type: string;
|
||||||
category: BrokerOperationCategory;
|
category: BrokerOperationCategory;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
name: string | null;
|
||||||
state: string | null;
|
state: string | null;
|
||||||
instrumentUid: string | null;
|
instrumentUid: string | null;
|
||||||
figi: string | null;
|
figi: string | null;
|
||||||
@ -336,3 +336,11 @@ export interface BrokerOperationsPage {
|
|||||||
hasNext: boolean;
|
hasNext: boolean;
|
||||||
asOf: string;
|
asOf: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BrokerPositionsPage {
|
||||||
|
accountId: string;
|
||||||
|
items: BrokerPosition[];
|
||||||
|
nextCursor: string | null;
|
||||||
|
hasNext: boolean;
|
||||||
|
asOf: string;
|
||||||
|
}
|
||||||
|
|||||||
18
apps/frontend/src/hooks/useBrokerPositions.ts
Normal file
18
apps/frontend/src/hooks/useBrokerPositions.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { keepPreviousData, useQuery } from '@tanstack/react-query';
|
||||||
|
import { getBrokerPositions } from '../api/broker';
|
||||||
|
import type { BrokerPositionsPage } from '../api/responses';
|
||||||
|
|
||||||
|
export function useBrokerPositions(
|
||||||
|
accountId: string | undefined,
|
||||||
|
query: { cursor?: string; limit?: number } = {},
|
||||||
|
) {
|
||||||
|
return useQuery<BrokerPositionsPage>({
|
||||||
|
queryKey: ['broker', 'positions', accountId, query],
|
||||||
|
enabled: Boolean(accountId),
|
||||||
|
queryFn: async () => (await getBrokerPositions(accountId!, query)).data,
|
||||||
|
staleTime: 60_000,
|
||||||
|
retry: 2,
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user