@cranberry-money/shared-services 1.0.0
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.
- package/README.md +288 -0
- package/dist/adapters/MobileApiClient.d.ts +68 -0
- package/dist/adapters/MobileApiClient.d.ts.map +1 -0
- package/dist/adapters/MobileApiClient.js +240 -0
- package/dist/adapters/MobileTokenStorage.d.ts +43 -0
- package/dist/adapters/MobileTokenStorage.d.ts.map +1 -0
- package/dist/adapters/MobileTokenStorage.js +128 -0
- package/dist/adapters/WebApiClient.d.ts +28 -0
- package/dist/adapters/WebApiClient.d.ts.map +1 -0
- package/dist/adapters/WebApiClient.js +119 -0
- package/dist/adapters/WebTokenStorage.d.ts +38 -0
- package/dist/adapters/WebTokenStorage.d.ts.map +1 -0
- package/dist/adapters/WebTokenStorage.js +86 -0
- package/dist/auth/AuthManager.d.ts +81 -0
- package/dist/auth/AuthManager.d.ts.map +1 -0
- package/dist/auth/AuthManager.js +223 -0
- package/dist/auth/createAuthManager.d.ts +63 -0
- package/dist/auth/createAuthManager.d.ts.map +1 -0
- package/dist/auth/createAuthManager.js +103 -0
- package/dist/auth/useAuthManager.d.ts +66 -0
- package/dist/auth/useAuthManager.d.ts.map +1 -0
- package/dist/auth/useAuthManager.js +133 -0
- package/dist/core/BaseApiClient.d.ts +82 -0
- package/dist/core/BaseApiClient.d.ts.map +1 -0
- package/dist/core/BaseApiClient.js +89 -0
- package/dist/core/TokenStorage.d.ts +45 -0
- package/dist/core/TokenStorage.d.ts.map +1 -0
- package/dist/core/TokenStorage.js +23 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/query/QueryClient.d.ts +82 -0
- package/dist/query/QueryClient.d.ts.map +1 -0
- package/dist/query/QueryClient.js +136 -0
- package/dist/query/useAuth.d.ts +64 -0
- package/dist/query/useAuth.d.ts.map +1 -0
- package/dist/query/useAuth.js +144 -0
- package/dist/query/usePortfolios.d.ts +79 -0
- package/dist/query/usePortfolios.d.ts.map +1 -0
- package/dist/query/usePortfolios.js +172 -0
- package/dist/services/AuthService.d.ts +75 -0
- package/dist/services/AuthService.d.ts.map +1 -0
- package/dist/services/AuthService.js +83 -0
- package/dist/services/BaseService.d.ts +48 -0
- package/dist/services/BaseService.d.ts.map +1 -0
- package/dist/services/BaseService.js +51 -0
- package/dist/services/PortfolioService.d.ts +100 -0
- package/dist/services/PortfolioService.d.ts.map +1 -0
- package/dist/services/PortfolioService.js +68 -0
- package/package.json +56 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared portfolio React Query hooks
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent portfolio data management and operations
|
|
5
|
+
* with optimized caching and invalidation patterns.
|
|
6
|
+
*/
|
|
7
|
+
import { type UseMutationOptions } from '@tanstack/react-query';
|
|
8
|
+
import type { PortfolioService, Portfolio, CreatePortfolioPayload, UpdatePortfolioPayload, PortfolioListFilters } from '../services/PortfolioService';
|
|
9
|
+
export interface UsePortfolioServiceOptions {
|
|
10
|
+
portfolioService: PortfolioService;
|
|
11
|
+
}
|
|
12
|
+
export interface PortfolioMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, Error, TVariables>, 'mutationFn'> {
|
|
13
|
+
portfolioService: PortfolioService;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get all portfolios with filtering
|
|
17
|
+
*/
|
|
18
|
+
export declare function usePortfolios({ portfolioService }: UsePortfolioServiceOptions, filters?: PortfolioListFilters, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("..").PaginatedResponse<Portfolio>, Error>;
|
|
19
|
+
/**
|
|
20
|
+
* Get specific portfolio by ID
|
|
21
|
+
*/
|
|
22
|
+
export declare function usePortfolio({ portfolioService }: UsePortfolioServiceOptions, portfolioId: string, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<Portfolio, Error>;
|
|
23
|
+
/**
|
|
24
|
+
* Get portfolio holdings
|
|
25
|
+
*/
|
|
26
|
+
export declare function usePortfolioHoldings({ portfolioService }: UsePortfolioServiceOptions, portfolioId: string, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("..").AssetHolding[], Error>;
|
|
27
|
+
/**
|
|
28
|
+
* Get portfolio allocations
|
|
29
|
+
*/
|
|
30
|
+
export declare function usePortfolioAllocations({ portfolioService }: UsePortfolioServiceOptions, portfolioId: string, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("..").AssetAllocation[], Error>;
|
|
31
|
+
/**
|
|
32
|
+
* Get portfolio performance data
|
|
33
|
+
*/
|
|
34
|
+
export declare function usePortfolioPerformance({ portfolioService }: UsePortfolioServiceOptions, portfolioId: string, timeRange?: string, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("..").PerformanceData, Error>;
|
|
35
|
+
/**
|
|
36
|
+
* Create portfolio mutation
|
|
37
|
+
*/
|
|
38
|
+
export declare function useCreatePortfolio(options: PortfolioMutationOptions<Portfolio, CreatePortfolioPayload>): import("@tanstack/react-query").UseMutationResult<Portfolio, Error, CreatePortfolioPayload, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Update portfolio mutation
|
|
41
|
+
*/
|
|
42
|
+
export declare function useUpdatePortfolio(options: PortfolioMutationOptions<Portfolio, {
|
|
43
|
+
id: string;
|
|
44
|
+
data: UpdatePortfolioPayload;
|
|
45
|
+
}>): import("@tanstack/react-query").UseMutationResult<Portfolio, Error, {
|
|
46
|
+
id: string;
|
|
47
|
+
data: UpdatePortfolioPayload;
|
|
48
|
+
}, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Delete portfolio mutation
|
|
51
|
+
*/
|
|
52
|
+
export declare function useDeletePortfolio(options: PortfolioMutationOptions<void, string>): import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* Infinite query for portfolios (useful for large lists)
|
|
55
|
+
*/
|
|
56
|
+
export declare function useInfinitePortfolios({ portfolioService }: UsePortfolioServiceOptions, filters?: PortfolioListFilters): import("@tanstack/react-query").UseInfiniteQueryResult<import("@tanstack/query-core").InfiniteData<import("..").PaginatedResponse<Portfolio>, unknown>, Error>;
|
|
57
|
+
/**
|
|
58
|
+
* Composite hook for complete portfolio management
|
|
59
|
+
*/
|
|
60
|
+
export declare function usePortfolioManagement(serviceOptions: UsePortfolioServiceOptions, portfolioId?: string): {
|
|
61
|
+
portfolios: Portfolio[];
|
|
62
|
+
portfolio: Portfolio | undefined;
|
|
63
|
+
holdings: import("..").AssetHolding[];
|
|
64
|
+
allocations: import("..").AssetAllocation[];
|
|
65
|
+
isLoadingPortfolios: boolean;
|
|
66
|
+
isLoadingPortfolio: boolean;
|
|
67
|
+
isLoadingHoldings: boolean;
|
|
68
|
+
isLoadingAllocations: boolean;
|
|
69
|
+
isLoading: boolean;
|
|
70
|
+
portfoliosError: Error | null;
|
|
71
|
+
portfolioError: Error | null;
|
|
72
|
+
holdingsError: Error | null;
|
|
73
|
+
allocationsError: Error | null;
|
|
74
|
+
refetchPortfolios: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("..").PaginatedResponse<Portfolio>, Error>>;
|
|
75
|
+
refetchPortfolio: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<Portfolio, Error>>;
|
|
76
|
+
refetchHoldings: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("..").AssetHolding[], Error>>;
|
|
77
|
+
refetchAllocations: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("..").AssetAllocation[], Error>>;
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=usePortfolios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePortfolios.d.ts","sourceRoot":"","sources":["../../src/query/usePortfolios.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA2D,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACzH,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EACT,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAGtC,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED,MAAM,WAAW,wBAAwB,CAAC,KAAK,EAAE,UAAU,CAAE,SAC3D,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC;IAChE,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,OAAO,GAAE,oBAAyB,EAClC,OAAO,GAAE,OAAc,oGAQxB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,OAAc,oEAQxB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,OAAc,sFAQxB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,OAAc,yFAQxB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAAa,EACxB,OAAO,GAAE,OAAc,uFAQxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,CAAC,SAAS,EAAE,sBAAsB,CAAC,wGAqBtG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,CAAC,SAAS,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;QAAvC,MAAM;UAAQ,sBAAsB;YAsBzH;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,CAAC,IAAI,EAAE,MAAM,CAAC,mFAoBjF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,gBAAgB,EAAE,EAAE,0BAA0B,EAChD,OAAO,GAAE,oBAAyB,kKAgBnC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,0BAA0B,EAC1C,WAAW,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;EAiCrB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared portfolio React Query hooks
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent portfolio data management and operations
|
|
5
|
+
* with optimized caching and invalidation patterns.
|
|
6
|
+
*/
|
|
7
|
+
import { useQuery, useMutation, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
8
|
+
import { queryKeys, createQueryOptions } from './QueryClient';
|
|
9
|
+
/**
|
|
10
|
+
* Get all portfolios with filtering
|
|
11
|
+
*/
|
|
12
|
+
export function usePortfolios({ portfolioService }, filters = {}, enabled = true) {
|
|
13
|
+
return useQuery({
|
|
14
|
+
queryKey: queryKeys.portfolios.all(),
|
|
15
|
+
queryFn: () => portfolioService.getPortfolios(filters),
|
|
16
|
+
enabled,
|
|
17
|
+
...createQueryOptions.user('web'), // Adjust based on platform
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get specific portfolio by ID
|
|
22
|
+
*/
|
|
23
|
+
export function usePortfolio({ portfolioService }, portfolioId, enabled = true) {
|
|
24
|
+
return useQuery({
|
|
25
|
+
queryKey: queryKeys.portfolios.detail(portfolioId),
|
|
26
|
+
queryFn: () => portfolioService.getPortfolio(portfolioId),
|
|
27
|
+
enabled: enabled && !!portfolioId,
|
|
28
|
+
...createQueryOptions.user('web'),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get portfolio holdings
|
|
33
|
+
*/
|
|
34
|
+
export function usePortfolioHoldings({ portfolioService }, portfolioId, enabled = true) {
|
|
35
|
+
return useQuery({
|
|
36
|
+
queryKey: queryKeys.portfolios.holdings(portfolioId),
|
|
37
|
+
queryFn: () => portfolioService.getHoldings(portfolioId),
|
|
38
|
+
enabled: enabled && !!portfolioId,
|
|
39
|
+
...createQueryOptions.realtime('web'), // Holdings update frequently
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get portfolio allocations
|
|
44
|
+
*/
|
|
45
|
+
export function usePortfolioAllocations({ portfolioService }, portfolioId, enabled = true) {
|
|
46
|
+
return useQuery({
|
|
47
|
+
queryKey: queryKeys.portfolios.allocations(portfolioId),
|
|
48
|
+
queryFn: () => portfolioService.getAllocations(portfolioId),
|
|
49
|
+
enabled: enabled && !!portfolioId,
|
|
50
|
+
...createQueryOptions.user('web'),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get portfolio performance data
|
|
55
|
+
*/
|
|
56
|
+
export function usePortfolioPerformance({ portfolioService }, portfolioId, timeRange = '1Y', enabled = true) {
|
|
57
|
+
return useQuery({
|
|
58
|
+
queryKey: ['portfolios', portfolioId, 'performance', timeRange],
|
|
59
|
+
queryFn: () => portfolioService.getPerformance(portfolioId, timeRange),
|
|
60
|
+
enabled: enabled && !!portfolioId,
|
|
61
|
+
staleTime: 5 * 60 * 1000, // 5 minutes - performance data doesn't change frequently
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create portfolio mutation
|
|
66
|
+
*/
|
|
67
|
+
export function useCreatePortfolio(options) {
|
|
68
|
+
const queryClient = useQueryClient();
|
|
69
|
+
const { portfolioService, ...mutationOptions } = options;
|
|
70
|
+
return useMutation({
|
|
71
|
+
mutationFn: (data) => portfolioService.createPortfolio(data),
|
|
72
|
+
onSuccess: (newPortfolio, ...args) => {
|
|
73
|
+
// Add new portfolio to the cache
|
|
74
|
+
queryClient.setQueryData(queryKeys.portfolios.detail(newPortfolio.id), newPortfolio);
|
|
75
|
+
// Invalidate portfolios list to include new portfolio
|
|
76
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.portfolios.all() });
|
|
77
|
+
// Call user's onSuccess if provided
|
|
78
|
+
mutationOptions.onSuccess?.(newPortfolio, ...args);
|
|
79
|
+
},
|
|
80
|
+
...mutationOptions,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Update portfolio mutation
|
|
85
|
+
*/
|
|
86
|
+
export function useUpdatePortfolio(options) {
|
|
87
|
+
const queryClient = useQueryClient();
|
|
88
|
+
const { portfolioService, ...mutationOptions } = options;
|
|
89
|
+
return useMutation({
|
|
90
|
+
mutationFn: ({ id, data }) => portfolioService.updatePortfolio(id, data),
|
|
91
|
+
onSuccess: (updatedPortfolio, { id }, ...args) => {
|
|
92
|
+
// Update portfolio in cache
|
|
93
|
+
queryClient.setQueryData(queryKeys.portfolios.detail(id), updatedPortfolio);
|
|
94
|
+
// Invalidate portfolios list to reflect changes
|
|
95
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.portfolios.all() });
|
|
96
|
+
// Call user's onSuccess if provided
|
|
97
|
+
mutationOptions.onSuccess?.(updatedPortfolio, { id, data: { name: updatedPortfolio.name } }, ...args);
|
|
98
|
+
},
|
|
99
|
+
...mutationOptions,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Delete portfolio mutation
|
|
104
|
+
*/
|
|
105
|
+
export function useDeletePortfolio(options) {
|
|
106
|
+
const queryClient = useQueryClient();
|
|
107
|
+
const { portfolioService, ...mutationOptions } = options;
|
|
108
|
+
return useMutation({
|
|
109
|
+
mutationFn: (id) => portfolioService.deletePortfolio(id),
|
|
110
|
+
onSuccess: (_, portfolioId, ...args) => {
|
|
111
|
+
// Remove portfolio from cache
|
|
112
|
+
queryClient.removeQueries({ queryKey: queryKeys.portfolios.detail(portfolioId) });
|
|
113
|
+
queryClient.removeQueries({ queryKey: queryKeys.portfolios.holdings(portfolioId) });
|
|
114
|
+
queryClient.removeQueries({ queryKey: queryKeys.portfolios.allocations(portfolioId) });
|
|
115
|
+
// Invalidate portfolios list to reflect deletion
|
|
116
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.portfolios.all() });
|
|
117
|
+
// Call user's onSuccess if provided
|
|
118
|
+
mutationOptions.onSuccess?.(_, portfolioId, ...args);
|
|
119
|
+
},
|
|
120
|
+
...mutationOptions,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Infinite query for portfolios (useful for large lists)
|
|
125
|
+
*/
|
|
126
|
+
export function useInfinitePortfolios({ portfolioService }, filters = {}) {
|
|
127
|
+
return useInfiniteQuery({
|
|
128
|
+
queryKey: ['portfolios', 'infinite', filters],
|
|
129
|
+
queryFn: ({ pageParam = 1 }) => portfolioService.getPortfolios({ ...filters, page: pageParam }),
|
|
130
|
+
initialPageParam: 1,
|
|
131
|
+
getNextPageParam: (lastPage) => {
|
|
132
|
+
if (lastPage.next) {
|
|
133
|
+
const url = new URL(lastPage.next);
|
|
134
|
+
return Number(url.searchParams.get('page'));
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
},
|
|
138
|
+
...createQueryOptions.user('web'),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Composite hook for complete portfolio management
|
|
143
|
+
*/
|
|
144
|
+
export function usePortfolioManagement(serviceOptions, portfolioId) {
|
|
145
|
+
const portfoliosQuery = usePortfolios(serviceOptions);
|
|
146
|
+
const portfolioQuery = usePortfolio(serviceOptions, portfolioId || '', !!portfolioId);
|
|
147
|
+
const holdingsQuery = usePortfolioHoldings(serviceOptions, portfolioId || '', !!portfolioId);
|
|
148
|
+
const allocationsQuery = usePortfolioAllocations(serviceOptions, portfolioId || '', !!portfolioId);
|
|
149
|
+
return {
|
|
150
|
+
// Data
|
|
151
|
+
portfolios: portfoliosQuery.data?.results || [],
|
|
152
|
+
portfolio: portfolioQuery.data,
|
|
153
|
+
holdings: holdingsQuery.data || [],
|
|
154
|
+
allocations: allocationsQuery.data || [],
|
|
155
|
+
// Loading states
|
|
156
|
+
isLoadingPortfolios: portfoliosQuery.isLoading,
|
|
157
|
+
isLoadingPortfolio: portfolioQuery.isLoading,
|
|
158
|
+
isLoadingHoldings: holdingsQuery.isLoading,
|
|
159
|
+
isLoadingAllocations: allocationsQuery.isLoading,
|
|
160
|
+
isLoading: portfoliosQuery.isLoading || portfolioQuery.isLoading,
|
|
161
|
+
// Error states
|
|
162
|
+
portfoliosError: portfoliosQuery.error,
|
|
163
|
+
portfolioError: portfolioQuery.error,
|
|
164
|
+
holdingsError: holdingsQuery.error,
|
|
165
|
+
allocationsError: allocationsQuery.error,
|
|
166
|
+
// Refetch functions
|
|
167
|
+
refetchPortfolios: portfoliosQuery.refetch,
|
|
168
|
+
refetchPortfolio: portfolioQuery.refetch,
|
|
169
|
+
refetchHoldings: holdingsQuery.refetch,
|
|
170
|
+
refetchAllocations: allocationsQuery.refetch,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication service with React Query integration
|
|
3
|
+
*
|
|
4
|
+
* Provides authentication operations with proper query invalidation
|
|
5
|
+
* and state management across platforms.
|
|
6
|
+
*/
|
|
7
|
+
import type { BaseApiClient } from '../core/BaseApiClient';
|
|
8
|
+
import { BaseService } from './BaseService';
|
|
9
|
+
export interface SigninPayload {
|
|
10
|
+
email: string;
|
|
11
|
+
password: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SignupPayload {
|
|
14
|
+
email: string;
|
|
15
|
+
password: string;
|
|
16
|
+
first_name: string;
|
|
17
|
+
last_name: string;
|
|
18
|
+
}
|
|
19
|
+
export interface EmailVerificationPayload {
|
|
20
|
+
email: string;
|
|
21
|
+
verification_code: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TokenRefreshPayload {
|
|
24
|
+
refresh: string;
|
|
25
|
+
}
|
|
26
|
+
export interface TokenRefreshResponse {
|
|
27
|
+
access: string;
|
|
28
|
+
refresh: string;
|
|
29
|
+
}
|
|
30
|
+
export interface UserProfile {
|
|
31
|
+
id: string;
|
|
32
|
+
email: string;
|
|
33
|
+
first_name: string;
|
|
34
|
+
last_name: string;
|
|
35
|
+
is_verified: boolean;
|
|
36
|
+
is_signup_completed: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare class AuthService extends BaseService {
|
|
39
|
+
constructor(apiClient: BaseApiClient);
|
|
40
|
+
/**
|
|
41
|
+
* Sign in user
|
|
42
|
+
*/
|
|
43
|
+
signin(data: SigninPayload): Promise<unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Sign out user
|
|
46
|
+
*/
|
|
47
|
+
signout(): Promise<unknown>;
|
|
48
|
+
/**
|
|
49
|
+
* Sign up new user
|
|
50
|
+
*/
|
|
51
|
+
signup(data: SignupPayload): Promise<unknown>;
|
|
52
|
+
/**
|
|
53
|
+
* Verify email address
|
|
54
|
+
*/
|
|
55
|
+
verifyEmail(data: EmailVerificationPayload): Promise<unknown>;
|
|
56
|
+
/**
|
|
57
|
+
* Resend verification code
|
|
58
|
+
*/
|
|
59
|
+
resendVerificationCode(): Promise<unknown>;
|
|
60
|
+
/**
|
|
61
|
+
* Refresh authentication tokens
|
|
62
|
+
*/
|
|
63
|
+
refreshToken(data: TokenRefreshPayload): Promise<TokenRefreshResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* Get current user profile
|
|
66
|
+
*/
|
|
67
|
+
getProfile(): Promise<UserProfile>;
|
|
68
|
+
/**
|
|
69
|
+
* Check authentication status
|
|
70
|
+
*/
|
|
71
|
+
checkStatus(): Promise<{
|
|
72
|
+
authenticated: boolean;
|
|
73
|
+
}>;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=AuthService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthService.d.ts","sourceRoot":"","sources":["../../src/services/AuthService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,qBAAa,WAAY,SAAQ,WAAW;gBAC9B,SAAS,EAAE,aAAa;IAIpC;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,aAAa;IAKhC;;OAEG;IACG,OAAO;IAKb;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,aAAa;IAKhC;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,wBAAwB;IAKhD;;OAEG;IACG,sBAAsB;IAK5B;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAQ5E;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC;IAcxC;;OAEG;IACG,WAAW;;;CASlB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication service with React Query integration
|
|
3
|
+
*
|
|
4
|
+
* Provides authentication operations with proper query invalidation
|
|
5
|
+
* and state management across platforms.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseService } from './BaseService';
|
|
8
|
+
export class AuthService extends BaseService {
|
|
9
|
+
constructor(apiClient) {
|
|
10
|
+
super(apiClient, '/api');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Sign in user
|
|
14
|
+
*/
|
|
15
|
+
async signin(data) {
|
|
16
|
+
const response = await this.apiClient.post(this.buildEndpoint('signin/'), data);
|
|
17
|
+
return this.extractData(response);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sign out user
|
|
21
|
+
*/
|
|
22
|
+
async signout() {
|
|
23
|
+
const response = await this.apiClient.post(this.buildEndpoint('signout/'));
|
|
24
|
+
return this.extractData(response);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Sign up new user
|
|
28
|
+
*/
|
|
29
|
+
async signup(data) {
|
|
30
|
+
const response = await this.apiClient.post(this.buildEndpoint('signup/'), data);
|
|
31
|
+
return this.extractData(response);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Verify email address
|
|
35
|
+
*/
|
|
36
|
+
async verifyEmail(data) {
|
|
37
|
+
const response = await this.apiClient.post(this.buildEndpoint('email-verification/'), data);
|
|
38
|
+
return this.extractData(response);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resend verification code
|
|
42
|
+
*/
|
|
43
|
+
async resendVerificationCode() {
|
|
44
|
+
const response = await this.apiClient.post(this.buildEndpoint('resend-verification/'));
|
|
45
|
+
return this.extractData(response);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Refresh authentication tokens
|
|
49
|
+
*/
|
|
50
|
+
async refreshToken(data) {
|
|
51
|
+
const response = await this.apiClient.post(this.buildEndpoint('token/refresh/'), data);
|
|
52
|
+
return this.extractData(response);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get current user profile
|
|
56
|
+
*/
|
|
57
|
+
async getProfile() {
|
|
58
|
+
// Get the first user profile (current user's profile)
|
|
59
|
+
const response = await this.apiClient.get(this.buildEndpoint('user-profiles/'));
|
|
60
|
+
const profiles = this.extractData(response);
|
|
61
|
+
if (!profiles.results || profiles.results.length === 0) {
|
|
62
|
+
throw new Error('No user profile found');
|
|
63
|
+
}
|
|
64
|
+
const profile = profiles.results[0];
|
|
65
|
+
if (!profile) {
|
|
66
|
+
throw new Error('No user profile found');
|
|
67
|
+
}
|
|
68
|
+
return profile;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check authentication status
|
|
72
|
+
*/
|
|
73
|
+
async checkStatus() {
|
|
74
|
+
// Use the profile endpoint to check auth status
|
|
75
|
+
try {
|
|
76
|
+
await this.getProfile();
|
|
77
|
+
return { authenticated: true };
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return { authenticated: false };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base service class for all API services
|
|
3
|
+
*
|
|
4
|
+
* Provides common functionality and patterns for API interaction
|
|
5
|
+
* that can be shared across all domain services.
|
|
6
|
+
*/
|
|
7
|
+
import type { BaseApiClient, ApiResponse } from '../core/BaseApiClient';
|
|
8
|
+
export declare abstract class BaseService {
|
|
9
|
+
protected apiClient: BaseApiClient;
|
|
10
|
+
protected baseEndpoint: string;
|
|
11
|
+
constructor(apiClient: BaseApiClient, baseEndpoint: string);
|
|
12
|
+
/**
|
|
13
|
+
* Build endpoint URL relative to service base
|
|
14
|
+
*/
|
|
15
|
+
protected buildEndpoint(path?: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Extract data from API response
|
|
18
|
+
*/
|
|
19
|
+
protected extractData<T>(response: ApiResponse<T>): T;
|
|
20
|
+
/**
|
|
21
|
+
* Handle paginated responses
|
|
22
|
+
*/
|
|
23
|
+
protected handlePaginatedResponse<T>(response: ApiResponse<PaginatedResponse<T>>): PaginatedResponse<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Build query parameters from filters
|
|
26
|
+
*/
|
|
27
|
+
protected buildQueryParams(filters: Record<string, unknown>): Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Common paginated response interface
|
|
31
|
+
*/
|
|
32
|
+
export interface PaginatedResponse<T> {
|
|
33
|
+
count: number;
|
|
34
|
+
next: string | null;
|
|
35
|
+
previous: string | null;
|
|
36
|
+
results: T[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Common list filters interface
|
|
40
|
+
*/
|
|
41
|
+
export interface BaseListFilters {
|
|
42
|
+
page?: number;
|
|
43
|
+
page_size?: number;
|
|
44
|
+
ordering?: string;
|
|
45
|
+
search?: string;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=BaseService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseService.d.ts","sourceRoot":"","sources":["../../src/services/BaseService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAExE,8BAAsB,WAAW;IAC/B,SAAS,CAAC,SAAS,EAAE,aAAa,CAAC;IACnC,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC;gBAEnB,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM;IAK1D;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,GAAE,MAAW,GAAG,MAAM;IAMlD;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAIrD;;OAEG;IACH,SAAS,CAAC,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC;IAIvG;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAiBrF;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,CAAC,EAAE,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base service class for all API services
|
|
3
|
+
*
|
|
4
|
+
* Provides common functionality and patterns for API interaction
|
|
5
|
+
* that can be shared across all domain services.
|
|
6
|
+
*/
|
|
7
|
+
export class BaseService {
|
|
8
|
+
constructor(apiClient, baseEndpoint) {
|
|
9
|
+
this.apiClient = apiClient;
|
|
10
|
+
this.baseEndpoint = baseEndpoint;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build endpoint URL relative to service base
|
|
14
|
+
*/
|
|
15
|
+
buildEndpoint(path = '') {
|
|
16
|
+
const cleanBase = this.baseEndpoint.replace(/\/$/, '');
|
|
17
|
+
const cleanPath = path.replace(/^\//, '');
|
|
18
|
+
return cleanPath ? `${cleanBase}/${cleanPath}` : cleanBase;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract data from API response
|
|
22
|
+
*/
|
|
23
|
+
extractData(response) {
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Handle paginated responses
|
|
28
|
+
*/
|
|
29
|
+
handlePaginatedResponse(response) {
|
|
30
|
+
return response.data;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build query parameters from filters
|
|
34
|
+
*/
|
|
35
|
+
buildQueryParams(filters) {
|
|
36
|
+
const params = {};
|
|
37
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
38
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
if (value.length > 0) {
|
|
41
|
+
params[key] = value.join(',');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
params[key] = String(value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return params;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portfolio service with comprehensive CRUD operations
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the service pattern for domain-specific API operations
|
|
5
|
+
* with proper typing and error handling.
|
|
6
|
+
*/
|
|
7
|
+
import type { BaseApiClient } from '../core/BaseApiClient';
|
|
8
|
+
import { BaseService, type PaginatedResponse, type BaseListFilters } from './BaseService';
|
|
9
|
+
export interface Portfolio {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
total_value: number;
|
|
14
|
+
cash_balance: number;
|
|
15
|
+
created_at: string;
|
|
16
|
+
updated_at: string;
|
|
17
|
+
is_active: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface CreatePortfolioPayload {
|
|
20
|
+
name: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface UpdatePortfolioPayload {
|
|
24
|
+
name?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
is_active?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface PortfolioListFilters extends BaseListFilters {
|
|
29
|
+
is_active?: boolean;
|
|
30
|
+
min_value?: number;
|
|
31
|
+
max_value?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AssetHolding {
|
|
34
|
+
id: string;
|
|
35
|
+
instrument_id: string;
|
|
36
|
+
instrument_name: string;
|
|
37
|
+
instrument_symbol: string;
|
|
38
|
+
quantity: number;
|
|
39
|
+
market_value: number;
|
|
40
|
+
average_cost: number;
|
|
41
|
+
unrealized_pnl: number;
|
|
42
|
+
weight: number;
|
|
43
|
+
}
|
|
44
|
+
export interface AssetAllocation {
|
|
45
|
+
sector: string;
|
|
46
|
+
allocation: number;
|
|
47
|
+
market_value: number;
|
|
48
|
+
target_allocation?: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class PortfolioService extends BaseService {
|
|
51
|
+
constructor(apiClient: BaseApiClient);
|
|
52
|
+
/**
|
|
53
|
+
* Get all portfolios with optional filtering
|
|
54
|
+
*/
|
|
55
|
+
getPortfolios(filters?: PortfolioListFilters): Promise<PaginatedResponse<Portfolio>>;
|
|
56
|
+
/**
|
|
57
|
+
* Get specific portfolio by ID
|
|
58
|
+
*/
|
|
59
|
+
getPortfolio(id: string): Promise<Portfolio>;
|
|
60
|
+
/**
|
|
61
|
+
* Create new portfolio
|
|
62
|
+
*/
|
|
63
|
+
createPortfolio(data: CreatePortfolioPayload): Promise<Portfolio>;
|
|
64
|
+
/**
|
|
65
|
+
* Update existing portfolio
|
|
66
|
+
*/
|
|
67
|
+
updatePortfolio(id: string, data: UpdatePortfolioPayload): Promise<Portfolio>;
|
|
68
|
+
/**
|
|
69
|
+
* Delete portfolio
|
|
70
|
+
*/
|
|
71
|
+
deletePortfolio(id: string): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Get portfolio asset holdings
|
|
74
|
+
*/
|
|
75
|
+
getHoldings(portfolioId: string): Promise<AssetHolding[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Get portfolio asset allocation
|
|
78
|
+
*/
|
|
79
|
+
getAllocations(portfolioId: string): Promise<AssetAllocation[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Get portfolio performance data
|
|
82
|
+
*/
|
|
83
|
+
getPerformance(portfolioId: string, timeRange?: string): Promise<PerformanceData>;
|
|
84
|
+
}
|
|
85
|
+
export interface PerformanceData {
|
|
86
|
+
total_return: number;
|
|
87
|
+
total_return_percentage: number;
|
|
88
|
+
daily_returns: Array<{
|
|
89
|
+
date: string;
|
|
90
|
+
value: number;
|
|
91
|
+
return_percentage: number;
|
|
92
|
+
}>;
|
|
93
|
+
benchmark_comparison?: {
|
|
94
|
+
benchmark_name: string;
|
|
95
|
+
benchmark_return: number;
|
|
96
|
+
alpha: number;
|
|
97
|
+
beta: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=PortfolioService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortfolioService.d.ts","sourceRoot":"","sources":["../../src/services/PortfolioService.ts"],"names":[],"mappings":"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"}
|