refactor(frontend): migrate entities/portfolio to FSD
This commit is contained in:
parent
9c115f0e16
commit
946383bde0
@ -1,93 +1,11 @@
|
||||
import { request } from './client';
|
||||
import type { AnalyticsResponse, Portfolio, PortfolioDetail, Position } from './responses';
|
||||
|
||||
export function getPortfolios(): Promise<{
|
||||
data: Portfolio[];
|
||||
meta: { cachedAt: string | null; fromCache: boolean };
|
||||
}> {
|
||||
return request<Portfolio[]>('/api/v1/portfolios');
|
||||
}
|
||||
|
||||
export function getPortfolio(
|
||||
id: number,
|
||||
): Promise<{ data: PortfolioDetail; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<PortfolioDetail>(`/api/v1/portfolios/${id}`);
|
||||
}
|
||||
|
||||
export function createPortfolio(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
currency?: string;
|
||||
}): Promise<{ data: Portfolio; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Portfolio>('/api/v1/portfolios', undefined, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updatePortfolio(
|
||||
id: number,
|
||||
data: { name?: string; description?: string; currency?: string },
|
||||
): Promise<{ data: Portfolio; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Portfolio>(`/api/v1/portfolios/${id}`, undefined, {
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function deletePortfolio(
|
||||
id: number,
|
||||
): Promise<{ data: null; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<null>(`/api/v1/portfolios/${id}`, undefined, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
export function addPosition(
|
||||
portfolioId: number,
|
||||
data: {
|
||||
secid: string;
|
||||
quantity: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
},
|
||||
): Promise<{ data: Position; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Position>(`/api/v1/portfolios/${portfolioId}/positions`, undefined, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updatePosition(
|
||||
portfolioId: number,
|
||||
positionId: number,
|
||||
data: {
|
||||
quantity?: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
},
|
||||
): Promise<{ data: Position; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Position>(`/api/v1/portfolios/${portfolioId}/positions/${positionId}`, undefined, {
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function removePosition(
|
||||
portfolioId: number,
|
||||
positionId: number,
|
||||
): Promise<{ data: null; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<null>(`/api/v1/portfolios/${portfolioId}/positions/${positionId}`, undefined, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
export function getPortfolioAnalytics(
|
||||
portfolioId: number,
|
||||
): Promise<{ data: AnalyticsResponse; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<AnalyticsResponse>(`/api/v1/portfolios/${portfolioId}/analytics`);
|
||||
}
|
||||
export {
|
||||
getPortfolios,
|
||||
getPortfolio,
|
||||
createPortfolio,
|
||||
updatePortfolio,
|
||||
deletePortfolio,
|
||||
addPosition,
|
||||
updatePosition,
|
||||
removePosition,
|
||||
getPortfolioAnalytics,
|
||||
} from '../entities/portfolio/api/portfolioApi';
|
||||
|
||||
98
apps/frontend/src/entities/portfolio/api/portfolioApi.ts
Normal file
98
apps/frontend/src/entities/portfolio/api/portfolioApi.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { request } from '@/shared/api/client';
|
||||
import type {
|
||||
AnalyticsResponse,
|
||||
Portfolio,
|
||||
PortfolioDetail,
|
||||
Position,
|
||||
} from '@/shared/api/responses';
|
||||
|
||||
export function getPortfolios(): Promise<{
|
||||
data: Portfolio[];
|
||||
meta: { cachedAt: string | null; fromCache: boolean };
|
||||
}> {
|
||||
return request<Portfolio[]>('/api/v1/portfolios');
|
||||
}
|
||||
|
||||
export function getPortfolio(
|
||||
id: number,
|
||||
): Promise<{ data: PortfolioDetail; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<PortfolioDetail>(`/api/v1/portfolios/${id}`);
|
||||
}
|
||||
|
||||
export function createPortfolio(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
currency?: string;
|
||||
}): Promise<{ data: Portfolio; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Portfolio>('/api/v1/portfolios', undefined, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updatePortfolio(
|
||||
id: number,
|
||||
data: { name?: string; description?: string; currency?: string },
|
||||
): Promise<{ data: Portfolio; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Portfolio>(`/api/v1/portfolios/${id}`, undefined, {
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function deletePortfolio(
|
||||
id: number,
|
||||
): Promise<{ data: null; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<null>(`/api/v1/portfolios/${id}`, undefined, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
export function addPosition(
|
||||
portfolioId: number,
|
||||
data: {
|
||||
secid: string;
|
||||
quantity: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
},
|
||||
): Promise<{ data: Position; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Position>(`/api/v1/portfolios/${portfolioId}/positions`, undefined, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updatePosition(
|
||||
portfolioId: number,
|
||||
positionId: number,
|
||||
data: {
|
||||
quantity?: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
},
|
||||
): Promise<{ data: Position; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<Position>(`/api/v1/portfolios/${portfolioId}/positions/${positionId}`, undefined, {
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function removePosition(
|
||||
portfolioId: number,
|
||||
positionId: number,
|
||||
): Promise<{ data: null; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<null>(`/api/v1/portfolios/${portfolioId}/positions/${positionId}`, undefined, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
export function getPortfolioAnalytics(
|
||||
portfolioId: number,
|
||||
): Promise<{ data: AnalyticsResponse; meta: { cachedAt: string | null; fromCache: boolean } }> {
|
||||
return request<AnalyticsResponse>(`/api/v1/portfolios/${portfolioId}/analytics`);
|
||||
}
|
||||
16
apps/frontend/src/entities/portfolio/index.ts
Normal file
16
apps/frontend/src/entities/portfolio/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export { usePortfolio } from './model/usePortfolio';
|
||||
export { usePortfolios } from './model/usePortfolios';
|
||||
export { usePortfolioAnalytics } from './model/usePortfolioAnalytics';
|
||||
export { usePortfolioMutations } from './model/usePortfolioMutations';
|
||||
export { usePositionMutations } from './model/usePositionMutations';
|
||||
export {
|
||||
getPortfolios,
|
||||
getPortfolio,
|
||||
createPortfolio,
|
||||
updatePortfolio,
|
||||
deletePortfolio,
|
||||
addPosition,
|
||||
updatePosition,
|
||||
removePosition,
|
||||
getPortfolioAnalytics,
|
||||
} from './api/portfolioApi';
|
||||
17
apps/frontend/src/entities/portfolio/model/usePortfolio.ts
Normal file
17
apps/frontend/src/entities/portfolio/model/usePortfolio.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolio } from '../api/portfolioApi';
|
||||
import type { PortfolioDetail } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolio(id: number) {
|
||||
return useQuery<PortfolioDetail>({
|
||||
queryKey: ['portfolio', id],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolio(id);
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolioAnalytics } from '../api/portfolioApi';
|
||||
import type { AnalyticsResponse } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolioAnalytics(portfolioId: number) {
|
||||
return useQuery<AnalyticsResponse>({
|
||||
queryKey: ['portfolio', portfolioId, 'analytics'],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolioAnalytics(portfolioId);
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
enabled: !!portfolioId,
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { createPortfolio, updatePortfolio, deletePortfolio } from '../api/portfolioApi';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export function usePortfolioMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const create = useMutation({
|
||||
mutationFn: (data: { name: string; description?: string; currency?: string }) =>
|
||||
createPortfolio(data),
|
||||
onSuccess: (res) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
navigate(`/portfolios/${res.data.id}`);
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: number;
|
||||
data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
currency?: string;
|
||||
};
|
||||
}) => updatePortfolio(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', id] });
|
||||
},
|
||||
});
|
||||
|
||||
const remove = useMutation({
|
||||
mutationFn: (id: number) => deletePortfolio(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
navigate('/portfolios');
|
||||
},
|
||||
});
|
||||
|
||||
return { create, update, remove };
|
||||
}
|
||||
16
apps/frontend/src/entities/portfolio/model/usePortfolios.ts
Normal file
16
apps/frontend/src/entities/portfolio/model/usePortfolios.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolios } from '../api/portfolioApi';
|
||||
import type { Portfolio } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolios() {
|
||||
return useQuery<Portfolio[]>({
|
||||
queryKey: ['portfolios'],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolios();
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { addPosition, updatePosition, removePosition } from '../api/portfolioApi';
|
||||
import type { PortfolioDetail } from '@/shared/api/responses';
|
||||
|
||||
export function usePositionMutations(portfolioId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const add = useMutation({
|
||||
mutationFn: (data: {
|
||||
secid: string;
|
||||
quantity: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
}) => addPosition(portfolioId, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation({
|
||||
mutationFn: ({
|
||||
positionId,
|
||||
data,
|
||||
}: {
|
||||
positionId: number;
|
||||
data: {
|
||||
quantity?: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
};
|
||||
}) => updatePosition(portfolioId, positionId, data),
|
||||
onMutate: async ({ positionId, data }) => {
|
||||
await queryClient.cancelQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
const previous = queryClient.getQueryData<{ data: PortfolioDetail }>([
|
||||
'portfolio',
|
||||
portfolioId,
|
||||
]);
|
||||
queryClient.setQueryData(['portfolio', portfolioId], (old: any) => {
|
||||
if (!old) return old;
|
||||
return {
|
||||
...old,
|
||||
positions: old.positions.map((p: any) =>
|
||||
p.id === positionId
|
||||
? {
|
||||
...p,
|
||||
...(data.quantity !== undefined ? { quantity: data.quantity } : {}),
|
||||
...(data.buyPrice !== undefined ? { buyPrice: data.buyPrice } : {}),
|
||||
...(data.buyDate !== undefined ? { buyDate: data.buyDate } : {}),
|
||||
}
|
||||
: p,
|
||||
),
|
||||
};
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, context) => {
|
||||
if (context?.previous) {
|
||||
queryClient.setQueryData(['portfolio', portfolioId], context.previous);
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
const remove = useMutation({
|
||||
mutationFn: (positionId: number) => removePosition(portfolioId, positionId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
return { add, update, remove };
|
||||
}
|
||||
@ -1,17 +1 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolio } from '../api/portfolio';
|
||||
import type { PortfolioDetail } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolio(id: number) {
|
||||
return useQuery<PortfolioDetail>({
|
||||
queryKey: ['portfolio', id],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolio(id);
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
export { usePortfolio } from '../entities/portfolio/model/usePortfolio';
|
||||
|
||||
@ -1,17 +1 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolioAnalytics } from '../api/portfolio';
|
||||
import type { AnalyticsResponse } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolioAnalytics(portfolioId: number) {
|
||||
return useQuery<AnalyticsResponse>({
|
||||
queryKey: ['portfolio', portfolioId, 'analytics'],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolioAnalytics(portfolioId);
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
enabled: !!portfolioId,
|
||||
});
|
||||
}
|
||||
export { usePortfolioAnalytics } from '../entities/portfolio/model/usePortfolioAnalytics';
|
||||
|
||||
@ -1,45 +1 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { createPortfolio, updatePortfolio, deletePortfolio } from '../api/portfolio';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export function usePortfolioMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const create = useMutation({
|
||||
mutationFn: (data: { name: string; description?: string; currency?: string }) =>
|
||||
createPortfolio(data),
|
||||
onSuccess: (res) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
navigate(`/portfolios/${res.data.id}`);
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: number;
|
||||
data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
currency?: string;
|
||||
};
|
||||
}) => updatePortfolio(id, data),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', id] });
|
||||
},
|
||||
});
|
||||
|
||||
const remove = useMutation({
|
||||
mutationFn: (id: number) => deletePortfolio(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolios'] });
|
||||
navigate('/portfolios');
|
||||
},
|
||||
});
|
||||
|
||||
return { create, update, remove };
|
||||
}
|
||||
export { usePortfolioMutations } from '../entities/portfolio/model/usePortfolioMutations';
|
||||
|
||||
@ -1,16 +1 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPortfolios } from '../api/portfolio';
|
||||
import type { Portfolio } from '@/shared/api/responses';
|
||||
|
||||
export function usePortfolios() {
|
||||
return useQuery<Portfolio[]>({
|
||||
queryKey: ['portfolios'],
|
||||
queryFn: async () => {
|
||||
const res = await getPortfolios();
|
||||
return res.data;
|
||||
},
|
||||
staleTime: 900_000,
|
||||
retry: 2,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
export { usePortfolios } from '../entities/portfolio/model/usePortfolios';
|
||||
|
||||
@ -1,78 +1 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { addPosition, updatePosition, removePosition } from '../api/portfolio';
|
||||
import type { PortfolioDetail } from '@/shared/api/responses';
|
||||
|
||||
export function usePositionMutations(portfolioId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const add = useMutation({
|
||||
mutationFn: (data: {
|
||||
secid: string;
|
||||
quantity: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
}) => addPosition(portfolioId, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation({
|
||||
mutationFn: ({
|
||||
positionId,
|
||||
data,
|
||||
}: {
|
||||
positionId: number;
|
||||
data: {
|
||||
quantity?: number;
|
||||
buyPrice?: number;
|
||||
buyDate?: string;
|
||||
notes?: string;
|
||||
tags?: string[];
|
||||
};
|
||||
}) => updatePosition(portfolioId, positionId, data),
|
||||
onMutate: async ({ positionId, data }) => {
|
||||
await queryClient.cancelQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
const previous = queryClient.getQueryData<{ data: PortfolioDetail }>([
|
||||
'portfolio',
|
||||
portfolioId,
|
||||
]);
|
||||
queryClient.setQueryData(['portfolio', portfolioId], (old: any) => {
|
||||
if (!old) return old;
|
||||
return {
|
||||
...old,
|
||||
positions: old.positions.map((p: any) =>
|
||||
p.id === positionId
|
||||
? {
|
||||
...p,
|
||||
...(data.quantity !== undefined ? { quantity: data.quantity } : {}),
|
||||
...(data.buyPrice !== undefined ? { buyPrice: data.buyPrice } : {}),
|
||||
...(data.buyDate !== undefined ? { buyDate: data.buyDate } : {}),
|
||||
}
|
||||
: p,
|
||||
),
|
||||
};
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, context) => {
|
||||
if (context?.previous) {
|
||||
queryClient.setQueryData(['portfolio', portfolioId], context.previous);
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
const remove = useMutation({
|
||||
mutationFn: (positionId: number) => removePosition(portfolioId, positionId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
|
||||
},
|
||||
});
|
||||
|
||||
return { add, update, remove };
|
||||
}
|
||||
export { usePositionMutations } from '../entities/portfolio/model/usePositionMutations';
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
import { usePortfolio } from '../../hooks/usePortfolio';
|
||||
import { usePortfolioMutations } from '../../hooks/usePortfolioMutations';
|
||||
import { usePositionMutations } from '../../hooks/usePositionMutations';
|
||||
import {
|
||||
usePortfolio,
|
||||
usePortfolioMutations,
|
||||
usePositionMutations,
|
||||
} from '../../entities/portfolio';
|
||||
import { PortfolioForm } from '../../components/portfolios/PortfolioForm';
|
||||
import { PortfolioSummary } from '../../components/portfolios/PortfolioSummary';
|
||||
import { AnalyticsSummary } from '../../components/portfolios/AnalyticsSummary';
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { usePortfolios } from '../../hooks/usePortfolios';
|
||||
import { usePortfolioMutations } from '../../hooks/usePortfolioMutations';
|
||||
import { usePortfolios, usePortfolioMutations } from '../../entities/portfolio';
|
||||
import { PortfolioCard } from '../../components/portfolios/PortfolioCard';
|
||||
import { PortfolioForm } from '../../components/portfolios/PortfolioForm';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user