@cranberry-money/shared-services 1.0.1 → 1.2.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/dist/api/apiClient.d.ts +25 -0
- package/dist/api/apiClient.d.ts.map +1 -0
- package/dist/api/apiClient.js +35 -0
- package/dist/api/types.d.ts +51 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +4 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/services/accounts/constants.d.ts +24 -0
- package/dist/services/accounts/constants.d.ts.map +1 -0
- package/dist/services/accounts/constants.js +30 -0
- package/dist/services/accounts/index.d.ts +7 -0
- package/dist/services/accounts/index.d.ts.map +1 -0
- package/dist/services/accounts/index.js +6 -0
- package/dist/services/accounts/service.d.ts +11 -0
- package/dist/services/accounts/service.d.ts.map +1 -0
- package/dist/services/accounts/service.js +19 -0
- package/dist/services/accounts/types.d.ts +15 -0
- package/dist/services/accounts/types.d.ts.map +1 -0
- package/dist/services/accounts/types.js +4 -0
- package/dist/services/auth/constants.d.ts +30 -0
- package/dist/services/auth/constants.d.ts.map +1 -0
- package/dist/services/auth/constants.js +37 -0
- package/dist/services/auth/index.d.ts +8 -0
- package/dist/services/auth/index.d.ts.map +1 -0
- package/dist/services/auth/index.js +7 -0
- package/dist/services/auth/service.d.ts +8 -0
- package/dist/services/auth/service.d.ts.map +1 -0
- package/dist/services/auth/service.js +23 -0
- package/dist/services/auth/types.d.ts +38 -0
- package/dist/services/auth/types.d.ts.map +1 -0
- package/dist/services/auth/types.js +1 -0
- package/dist/services/auth/utils.d.ts +46 -0
- package/dist/services/auth/utils.d.ts.map +1 -0
- package/dist/services/auth/utils.js +113 -0
- package/dist/services/portfolios/constants.d.ts +45 -0
- package/dist/services/portfolios/constants.d.ts.map +1 -0
- package/dist/services/portfolios/constants.js +57 -0
- package/dist/services/portfolios/index.d.ts +8 -0
- package/dist/services/portfolios/index.d.ts.map +1 -0
- package/dist/services/portfolios/index.js +7 -0
- package/dist/services/portfolios/service.d.ts +7 -0
- package/dist/services/portfolios/service.d.ts.map +1 -0
- package/dist/services/portfolios/service.js +19 -0
- package/dist/services/portfolios/types.d.ts +29 -0
- package/dist/services/portfolios/types.d.ts.map +1 -0
- package/dist/services/portfolios/types.js +1 -0
- package/dist/services/portfolios/utils.d.ts +5 -0
- package/dist/services/portfolios/utils.d.ts.map +1 -0
- package/dist/services/portfolios/utils.js +26 -0
- package/package.json +3 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-agnostic API client factory
|
|
3
|
+
* Supports both web and mobile environments
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiClientConfig {
|
|
6
|
+
baseURL: string;
|
|
7
|
+
withCredentials?: boolean;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export declare const createApiClient: (config: ApiClientConfig) => import("axios").AxiosInstance;
|
|
11
|
+
/**
|
|
12
|
+
* Web API client factory (for blueberry/strawberry)
|
|
13
|
+
*/
|
|
14
|
+
export declare const createWebApiClient: (baseURL?: string) => import("axios").AxiosInstance;
|
|
15
|
+
/**
|
|
16
|
+
* Mobile API client factory (for blackberry)
|
|
17
|
+
*/
|
|
18
|
+
export declare const createMobileApiClient: (baseURL: string) => import("axios").AxiosInstance;
|
|
19
|
+
/**
|
|
20
|
+
* Default web API client instance
|
|
21
|
+
* This maintains compatibility with existing blueberry services
|
|
22
|
+
*/
|
|
23
|
+
export declare const webApiClient: import("axios").AxiosInstance;
|
|
24
|
+
export default webApiClient;
|
|
25
|
+
//# sourceMappingURL=apiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/api/apiClient.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,eAAO,MAAM,eAAe,GAAI,QAAQ,eAAe,kCAStD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,kCAKlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,MAAM,kCAKpD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,+BAAuB,CAAC;AAEjD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
export const createApiClient = (config) => {
|
|
3
|
+
return axios.create({
|
|
4
|
+
baseURL: config.baseURL,
|
|
5
|
+
headers: {
|
|
6
|
+
'Content-Type': 'application/json',
|
|
7
|
+
...config.headers,
|
|
8
|
+
},
|
|
9
|
+
withCredentials: config.withCredentials ?? true,
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Web API client factory (for blueberry/strawberry)
|
|
14
|
+
*/
|
|
15
|
+
export const createWebApiClient = (baseURL) => {
|
|
16
|
+
return createApiClient({
|
|
17
|
+
baseURL: baseURL || (typeof window !== 'undefined' && window.ENV?.VITE_API_URL) || '',
|
|
18
|
+
withCredentials: true,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Mobile API client factory (for blackberry)
|
|
23
|
+
*/
|
|
24
|
+
export const createMobileApiClient = (baseURL) => {
|
|
25
|
+
return createApiClient({
|
|
26
|
+
baseURL,
|
|
27
|
+
withCredentials: false, // Mobile doesn't use cookies
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Default web API client instance
|
|
32
|
+
* This maintains compatibility with existing blueberry services
|
|
33
|
+
*/
|
|
34
|
+
export const webApiClient = createWebApiClient();
|
|
35
|
+
export default webApiClient;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common API types shared across all services
|
|
3
|
+
*/
|
|
4
|
+
export interface FormErrors {
|
|
5
|
+
[key: string]: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface PaginatedResponse<T> {
|
|
8
|
+
count: number;
|
|
9
|
+
next: string | null;
|
|
10
|
+
previous: string | null;
|
|
11
|
+
results: T[];
|
|
12
|
+
}
|
|
13
|
+
export interface PaginationParams {
|
|
14
|
+
page?: number;
|
|
15
|
+
page_size?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface OrderingParams {
|
|
18
|
+
ordering?: string;
|
|
19
|
+
order_by?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Base filters interface for API requests
|
|
23
|
+
*/
|
|
24
|
+
export interface BaseListFilters extends PaginationParams, OrderingParams {
|
|
25
|
+
search?: string;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Common date range filters
|
|
30
|
+
*/
|
|
31
|
+
export interface DateRangeFilters {
|
|
32
|
+
date_from?: string;
|
|
33
|
+
date_to?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Standard API response wrapper
|
|
37
|
+
*/
|
|
38
|
+
export interface ApiResponse<T> {
|
|
39
|
+
data: T;
|
|
40
|
+
status: number;
|
|
41
|
+
statusText: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Error response structure
|
|
45
|
+
*/
|
|
46
|
+
export interface ApiErrorResponse {
|
|
47
|
+
detail?: string;
|
|
48
|
+
errors?: FormErrors;
|
|
49
|
+
message?: string;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACzB;AAED,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,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,gBAAgB,EAAE,cAAc;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,9 +7,14 @@ export * from './adapters/WebTokenStorage';
|
|
|
7
7
|
export * from './adapters/WebApiClient';
|
|
8
8
|
export * from './adapters/MobileTokenStorage';
|
|
9
9
|
export * from './adapters/MobileApiClient';
|
|
10
|
+
export { createApiClient, createWebApiClient, createMobileApiClient, webApiClient } from './api/apiClient';
|
|
11
|
+
export type { FormErrors, PaginationParams, OrderingParams, DateRangeFilters, ApiErrorResponse } from './api/types';
|
|
10
12
|
export * from './services/BaseService';
|
|
11
13
|
export * from './services/AuthService';
|
|
12
14
|
export * from './services/PortfolioService';
|
|
15
|
+
export * as AccountsService from './services/accounts';
|
|
16
|
+
export * as AuthService from './services/auth';
|
|
17
|
+
export * as PortfoliosService from './services/portfolios';
|
|
13
18
|
export * from './query/QueryClient';
|
|
14
19
|
export * from './query/useAuth';
|
|
15
20
|
export * from './query/usePortfolios';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAG3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAG3C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACb,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAGrB,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAG5C,OAAO,KAAK,eAAe,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,WAAW,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAG3D,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,10 +9,16 @@ export * from './adapters/WebTokenStorage';
|
|
|
9
9
|
export * from './adapters/WebApiClient';
|
|
10
10
|
export * from './adapters/MobileTokenStorage';
|
|
11
11
|
export * from './adapters/MobileApiClient';
|
|
12
|
-
//
|
|
12
|
+
// New functional API client
|
|
13
|
+
export { createApiClient, createWebApiClient, createMobileApiClient, webApiClient } from './api/apiClient';
|
|
14
|
+
// Legacy class-based services (keep for backwards compatibility)
|
|
13
15
|
export * from './services/BaseService';
|
|
14
16
|
export * from './services/AuthService';
|
|
15
17
|
export * from './services/PortfolioService';
|
|
18
|
+
// New functional domain services
|
|
19
|
+
export * as AccountsService from './services/accounts';
|
|
20
|
+
export * as AuthService from './services/auth';
|
|
21
|
+
export * as PortfoliosService from './services/portfolios';
|
|
16
22
|
// React Query integration
|
|
17
23
|
export * from './query/QueryClient';
|
|
18
24
|
export * from './query/useAuth';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account-related constants for shared services.
|
|
3
|
+
*
|
|
4
|
+
* These constants should match the backend constants in bilberry/accounts/constants.py
|
|
5
|
+
* to ensure consistency across the application stack.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SOURCE_OF_FUNDS_SALARY = "salary";
|
|
8
|
+
export declare const SOURCE_OF_FUNDS_SAVINGS = "savings";
|
|
9
|
+
export declare const SOURCE_OF_FUNDS_INHERITANCE = "inheritance";
|
|
10
|
+
export declare const SOURCE_OF_FUNDS_GIFT = "gift";
|
|
11
|
+
export declare const SOURCE_OF_FUNDS_OTHER = "other";
|
|
12
|
+
export declare const SOURCE_OF_FUNDS_LABEL_SALARY = "Salary";
|
|
13
|
+
export declare const SOURCE_OF_FUNDS_LABEL_SAVINGS = "Savings";
|
|
14
|
+
export declare const SOURCE_OF_FUNDS_LABEL_INHERITANCE = "Inheritance";
|
|
15
|
+
export declare const SOURCE_OF_FUNDS_LABEL_GIFT = "Gift";
|
|
16
|
+
export declare const SOURCE_OF_FUNDS_LABEL_OTHER = "Other";
|
|
17
|
+
export declare const SOURCE_OF_FUNDS_OPTIONS: {
|
|
18
|
+
value: string;
|
|
19
|
+
label: string;
|
|
20
|
+
}[];
|
|
21
|
+
export declare const API_ENDPOINTS: {
|
|
22
|
+
readonly ACCOUNTS: "/api/accounts/";
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/services/accounts/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,eAAO,MAAM,sBAAsB,WAAW,CAAC;AAC/C,eAAO,MAAM,uBAAuB,YAAY,CAAC;AACjD,eAAO,MAAM,2BAA2B,gBAAgB,CAAC;AACzD,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAG7C,eAAO,MAAM,4BAA4B,WAAW,CAAC;AACrD,eAAO,MAAM,6BAA6B,YAAY,CAAC;AACvD,eAAO,MAAM,iCAAiC,gBAAgB,CAAC;AAC/D,eAAO,MAAM,0BAA0B,SAAS,CAAC;AACjD,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAGnD,eAAO,MAAM,uBAAuB;;;GAMnC,CAAC;AAGF,eAAO,MAAM,aAAa;;CAEhB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account-related constants for shared services.
|
|
3
|
+
*
|
|
4
|
+
* These constants should match the backend constants in bilberry/accounts/constants.py
|
|
5
|
+
* to ensure consistency across the application stack.
|
|
6
|
+
*/
|
|
7
|
+
// Source of funds constants
|
|
8
|
+
export const SOURCE_OF_FUNDS_SALARY = 'salary';
|
|
9
|
+
export const SOURCE_OF_FUNDS_SAVINGS = 'savings';
|
|
10
|
+
export const SOURCE_OF_FUNDS_INHERITANCE = 'inheritance';
|
|
11
|
+
export const SOURCE_OF_FUNDS_GIFT = 'gift';
|
|
12
|
+
export const SOURCE_OF_FUNDS_OTHER = 'other';
|
|
13
|
+
// Source of funds label constants
|
|
14
|
+
export const SOURCE_OF_FUNDS_LABEL_SALARY = 'Salary';
|
|
15
|
+
export const SOURCE_OF_FUNDS_LABEL_SAVINGS = 'Savings';
|
|
16
|
+
export const SOURCE_OF_FUNDS_LABEL_INHERITANCE = 'Inheritance';
|
|
17
|
+
export const SOURCE_OF_FUNDS_LABEL_GIFT = 'Gift';
|
|
18
|
+
export const SOURCE_OF_FUNDS_LABEL_OTHER = 'Other';
|
|
19
|
+
// Source of funds options
|
|
20
|
+
export const SOURCE_OF_FUNDS_OPTIONS = [
|
|
21
|
+
{ value: SOURCE_OF_FUNDS_SALARY, label: SOURCE_OF_FUNDS_LABEL_SALARY },
|
|
22
|
+
{ value: SOURCE_OF_FUNDS_SAVINGS, label: SOURCE_OF_FUNDS_LABEL_SAVINGS },
|
|
23
|
+
{ value: SOURCE_OF_FUNDS_INHERITANCE, label: SOURCE_OF_FUNDS_LABEL_INHERITANCE },
|
|
24
|
+
{ value: SOURCE_OF_FUNDS_GIFT, label: SOURCE_OF_FUNDS_LABEL_GIFT },
|
|
25
|
+
{ value: SOURCE_OF_FUNDS_OTHER, label: SOURCE_OF_FUNDS_LABEL_OTHER },
|
|
26
|
+
];
|
|
27
|
+
// API Endpoints
|
|
28
|
+
export const API_ENDPOINTS = {
|
|
29
|
+
ACCOUNTS: '/api/accounts/',
|
|
30
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/accounts/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account API service functions.
|
|
3
|
+
*/
|
|
4
|
+
import type { PaginatedResponse } from '../../api/types';
|
|
5
|
+
import type { Account, AccountPayload } from './types';
|
|
6
|
+
export type PaginatedAccounts = PaginatedResponse<Account>;
|
|
7
|
+
export declare const getAccounts: () => Promise<import("axios").AxiosResponse<PaginatedAccounts, any>>;
|
|
8
|
+
export declare const createAccount: (data: AccountPayload) => Promise<import("axios").AxiosResponse<Account, any>>;
|
|
9
|
+
export declare const updateAccount: (uuid: string, data: Partial<AccountPayload>) => Promise<import("axios").AxiosResponse<Account, any>>;
|
|
10
|
+
export declare const getAccountByUuid: (uuid: string) => Promise<import("axios").AxiosResponse<Account, any>>;
|
|
11
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/services/accounts/service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGvD,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAG3D,eAAO,MAAM,WAAW,sEAEvB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,cAAc,yDAEjD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,yDAExE,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,yDAE5C,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account API service functions.
|
|
3
|
+
*/
|
|
4
|
+
import { webApiClient } from '../../api/apiClient';
|
|
5
|
+
import { API_ENDPOINTS } from './constants';
|
|
6
|
+
// Fetch list of user accounts
|
|
7
|
+
export const getAccounts = () => {
|
|
8
|
+
return webApiClient.get(API_ENDPOINTS.ACCOUNTS);
|
|
9
|
+
};
|
|
10
|
+
export const createAccount = (data) => {
|
|
11
|
+
return webApiClient.post(API_ENDPOINTS.ACCOUNTS, data);
|
|
12
|
+
};
|
|
13
|
+
export const updateAccount = (uuid, data) => {
|
|
14
|
+
return webApiClient.patch(`${API_ENDPOINTS.ACCOUNTS}${uuid}/`, data);
|
|
15
|
+
};
|
|
16
|
+
// Get account by UUID
|
|
17
|
+
export const getAccountByUuid = (uuid) => {
|
|
18
|
+
return webApiClient.get(`${API_ENDPOINTS.ACCOUNTS}${uuid}/`);
|
|
19
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account-related types and interfaces.
|
|
3
|
+
*/
|
|
4
|
+
export interface Account {
|
|
5
|
+
uuid: string;
|
|
6
|
+
accountNumber: string | null;
|
|
7
|
+
accountType: string;
|
|
8
|
+
activationDate: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface AccountPayload {
|
|
11
|
+
accountType: string;
|
|
12
|
+
name: string;
|
|
13
|
+
userProfile: string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/accounts/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAGD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication API constants
|
|
3
|
+
*/
|
|
4
|
+
export declare const API_ENDPOINTS: {
|
|
5
|
+
readonly SIGNIN: "/api/signin/";
|
|
6
|
+
readonly SIGNOUT: "/api/signout/";
|
|
7
|
+
readonly SIGNUP: "/api/signup/";
|
|
8
|
+
readonly EMAIL_VERIFICATION: "/api/email-verification/";
|
|
9
|
+
readonly RESEND_VERIFICATION: "/api/resend-verification/";
|
|
10
|
+
readonly TOKEN_REFRESH: "/api/token/refresh/";
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_TOKEN_REFRESH_BUFFER_MINUTES = 5;
|
|
13
|
+
export declare const MILLISECONDS_PER_MINUTE: number;
|
|
14
|
+
export declare const MINUTES_PER_HOUR = 60;
|
|
15
|
+
export declare const HOURS_PER_DAY = 24;
|
|
16
|
+
export declare const TIME_LABEL_EXPIRED = "Expired";
|
|
17
|
+
export declare const TIME_LABEL_MINUTE = "minute";
|
|
18
|
+
export declare const TIME_LABEL_MINUTES = "minutes";
|
|
19
|
+
export declare const TIME_LABEL_HOUR = "hour";
|
|
20
|
+
export declare const TIME_LABEL_HOURS = "hours";
|
|
21
|
+
export declare const TIME_LABEL_DAY = "day";
|
|
22
|
+
export declare const TIME_LABEL_DAYS = "days";
|
|
23
|
+
export declare const TIME_LABEL_HOUR_SHORT = "h";
|
|
24
|
+
export declare const TIME_LABEL_MINUTE_SHORT = "m";
|
|
25
|
+
export declare const TIME_LABEL_DAY_SHORT = "d";
|
|
26
|
+
export declare const DEFAULT_UNKNOWN_VALUE = "Unknown";
|
|
27
|
+
export declare const DEFAULT_ERROR_MESSAGE = "An error occurred";
|
|
28
|
+
export declare const TOKEN_STORAGE_KEY_ACCESS = "access_token";
|
|
29
|
+
export declare const TOKEN_STORAGE_KEY_REFRESH = "refresh_token";
|
|
30
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/services/auth/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,aAAa;;;;;;;CAYhB,CAAC;AAGX,eAAO,MAAM,oCAAoC,IAAI,CAAC;AACtD,eAAO,MAAM,uBAAuB,QAAY,CAAC;AACjD,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,aAAa,KAAK,CAAC;AAGhC,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,eAAO,MAAM,cAAc,QAAQ,CAAC;AACpC,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAGxC,eAAO,MAAM,qBAAqB,YAAY,CAAC;AAC/C,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAGzD,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD,eAAO,MAAM,yBAAyB,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication API constants
|
|
3
|
+
*/
|
|
4
|
+
// API Endpoints
|
|
5
|
+
export const API_ENDPOINTS = {
|
|
6
|
+
// Authentication
|
|
7
|
+
SIGNIN: '/api/signin/',
|
|
8
|
+
SIGNOUT: '/api/signout/',
|
|
9
|
+
SIGNUP: '/api/signup/',
|
|
10
|
+
// Verification
|
|
11
|
+
EMAIL_VERIFICATION: '/api/email-verification/',
|
|
12
|
+
RESEND_VERIFICATION: '/api/resend-verification/',
|
|
13
|
+
// Token management
|
|
14
|
+
TOKEN_REFRESH: '/api/token/refresh/',
|
|
15
|
+
};
|
|
16
|
+
// Token management constants
|
|
17
|
+
export const DEFAULT_TOKEN_REFRESH_BUFFER_MINUTES = 5;
|
|
18
|
+
export const MILLISECONDS_PER_MINUTE = 60 * 1000;
|
|
19
|
+
export const MINUTES_PER_HOUR = 60;
|
|
20
|
+
export const HOURS_PER_DAY = 24;
|
|
21
|
+
// Time labels
|
|
22
|
+
export const TIME_LABEL_EXPIRED = 'Expired';
|
|
23
|
+
export const TIME_LABEL_MINUTE = 'minute';
|
|
24
|
+
export const TIME_LABEL_MINUTES = 'minutes';
|
|
25
|
+
export const TIME_LABEL_HOUR = 'hour';
|
|
26
|
+
export const TIME_LABEL_HOURS = 'hours';
|
|
27
|
+
export const TIME_LABEL_DAY = 'day';
|
|
28
|
+
export const TIME_LABEL_DAYS = 'days';
|
|
29
|
+
export const TIME_LABEL_HOUR_SHORT = 'h';
|
|
30
|
+
export const TIME_LABEL_MINUTE_SHORT = 'm';
|
|
31
|
+
export const TIME_LABEL_DAY_SHORT = 'd';
|
|
32
|
+
// Default values
|
|
33
|
+
export const DEFAULT_UNKNOWN_VALUE = 'Unknown';
|
|
34
|
+
export const DEFAULT_ERROR_MESSAGE = 'An error occurred';
|
|
35
|
+
// Storage keys
|
|
36
|
+
export const TOKEN_STORAGE_KEY_ACCESS = 'access_token';
|
|
37
|
+
export const TOKEN_STORAGE_KEY_REFRESH = 'refresh_token';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SigninPayload, SignupPayload, EmailVerificationPayload, TokenRefreshResponse, TokenRefreshPayload } from './types';
|
|
2
|
+
export declare const signin: (data: SigninPayload) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
3
|
+
export declare const signout: () => Promise<import("axios").AxiosResponse<any, any>>;
|
|
4
|
+
export declare const signup: (data: SignupPayload) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
5
|
+
export declare const verifyEmail: (data: EmailVerificationPayload) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
6
|
+
export declare const resendVerificationCode: () => Promise<import("axios").AxiosResponse<any, any>>;
|
|
7
|
+
export declare const refreshToken: (data: TokenRefreshPayload) => Promise<import("axios").AxiosResponse<TokenRefreshResponse, any>>;
|
|
8
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/services/auth/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAGjB,eAAO,MAAM,MAAM,GAAI,MAAM,aAAa,qDAEzC,CAAC;AAEF,eAAO,MAAM,OAAO,wDAEnB,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,MAAM,aAAa,qDAEzC,CAAC;AAGF,eAAO,MAAM,WAAW,GAAI,MAAM,wBAAwB,qDAEzD,CAAC;AAEF,eAAO,MAAM,sBAAsB,wDAElC,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,MAAM,mBAAmB,sEAErD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { webApiClient } from '../../api/apiClient';
|
|
2
|
+
import { API_ENDPOINTS } from './constants';
|
|
3
|
+
// Authentication services
|
|
4
|
+
export const signin = (data) => {
|
|
5
|
+
return webApiClient.post(API_ENDPOINTS.SIGNIN, data);
|
|
6
|
+
};
|
|
7
|
+
export const signout = () => {
|
|
8
|
+
return webApiClient.post(API_ENDPOINTS.SIGNOUT);
|
|
9
|
+
};
|
|
10
|
+
export const signup = (data) => {
|
|
11
|
+
return webApiClient.post(API_ENDPOINTS.SIGNUP, data);
|
|
12
|
+
};
|
|
13
|
+
// Email verification services
|
|
14
|
+
export const verifyEmail = (data) => {
|
|
15
|
+
return webApiClient.post(API_ENDPOINTS.EMAIL_VERIFICATION, data);
|
|
16
|
+
};
|
|
17
|
+
export const resendVerificationCode = () => {
|
|
18
|
+
return webApiClient.post(API_ENDPOINTS.RESEND_VERIFICATION);
|
|
19
|
+
};
|
|
20
|
+
// Token refresh services
|
|
21
|
+
export const refreshToken = (data) => {
|
|
22
|
+
return webApiClient.post(API_ENDPOINTS.TOKEN_REFRESH, data);
|
|
23
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface SigninPayload {
|
|
2
|
+
email: string;
|
|
3
|
+
password: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SignupPayload {
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
passwordConfirm: string;
|
|
9
|
+
}
|
|
10
|
+
export interface EmailVerificationPayload {
|
|
11
|
+
token: string;
|
|
12
|
+
}
|
|
13
|
+
export interface TokenRefreshResponse {
|
|
14
|
+
access: string;
|
|
15
|
+
refresh: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TokenRefreshPayload {
|
|
18
|
+
refresh: string;
|
|
19
|
+
}
|
|
20
|
+
export interface TokenRefreshError {
|
|
21
|
+
response?: {
|
|
22
|
+
status: number;
|
|
23
|
+
data?: {
|
|
24
|
+
detail?: string;
|
|
25
|
+
message?: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
message?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface TokenInfo {
|
|
31
|
+
token: string | null;
|
|
32
|
+
payload: Record<string, unknown>;
|
|
33
|
+
isValid: boolean;
|
|
34
|
+
remainingTime: string;
|
|
35
|
+
isExpired: boolean;
|
|
36
|
+
expirationTime: Date | null;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/auth/types.ts"],"names":[],"mappings":"AACA,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,eAAe,EAAE,MAAM,CAAC;CACzB;AAGD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE;YACL,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TokenRefreshError } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a token has expired based on its expiration timestamp
|
|
4
|
+
*/
|
|
5
|
+
export declare const isTokenExpired: (expiresAt: string) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Check if a token will expire within a specified number of minutes
|
|
8
|
+
*/
|
|
9
|
+
export declare const isTokenExpiringSoon: (expiresAt: string, minutesBeforeExpiry?: number) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Get the remaining time until token expiry in minutes
|
|
12
|
+
*/
|
|
13
|
+
export declare const getTimeUntilExpiry: (expiresAt: string) => number;
|
|
14
|
+
/**
|
|
15
|
+
* Format the time until expiry in a human-readable format
|
|
16
|
+
*/
|
|
17
|
+
export declare const formatTimeUntilExpiry: (expiresAt: string) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Parse device information from user agent string
|
|
20
|
+
*/
|
|
21
|
+
export declare const parseDeviceInfo: (userAgent: string) => {
|
|
22
|
+
browser: string;
|
|
23
|
+
os: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Check if token refresh was successful
|
|
27
|
+
*/
|
|
28
|
+
export declare const isRefreshSuccess: (response: {
|
|
29
|
+
status?: number;
|
|
30
|
+
data?: {
|
|
31
|
+
access?: string;
|
|
32
|
+
refresh?: string;
|
|
33
|
+
};
|
|
34
|
+
}) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get error message from token refresh error
|
|
37
|
+
*/
|
|
38
|
+
export declare const getRefreshErrorMessage: (error: TokenRefreshError) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Create an auto-refresh handler for tokens
|
|
41
|
+
*/
|
|
42
|
+
export declare const createAutoRefreshHandler: (refreshCallback: () => Promise<void>, checkInterval?: number) => {
|
|
43
|
+
start: () => void;
|
|
44
|
+
stop: () => void;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/services/auth/utils.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,KAAG,OAIlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,MAAM,EACjB,sBAAqB,MAA6C,KACjE,OAMF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,KAAG,MAUtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,MAkBzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM,KAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAwBhF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C,KAAG,OAEH,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,iBAAiB,KAAG,MAWjE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,GACnC,iBAAiB,MAAM,OAAO,CAAC,IAAI,CAAC,EACpC,gBAAe,MAAc;;;CAkB9B,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { DEFAULT_TOKEN_REFRESH_BUFFER_MINUTES, MILLISECONDS_PER_MINUTE, MINUTES_PER_HOUR, HOURS_PER_DAY, TIME_LABEL_EXPIRED, TIME_LABEL_MINUTE, TIME_LABEL_MINUTES, TIME_LABEL_HOUR, TIME_LABEL_HOURS, TIME_LABEL_DAY, TIME_LABEL_DAYS, DEFAULT_UNKNOWN_VALUE, DEFAULT_ERROR_MESSAGE, } from './constants';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a token has expired based on its expiration timestamp
|
|
4
|
+
*/
|
|
5
|
+
export const isTokenExpired = (expiresAt) => {
|
|
6
|
+
const expirationTime = new Date(expiresAt).getTime();
|
|
7
|
+
const currentTime = Date.now();
|
|
8
|
+
return currentTime >= expirationTime;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Check if a token will expire within a specified number of minutes
|
|
12
|
+
*/
|
|
13
|
+
export const isTokenExpiringSoon = (expiresAt, minutesBeforeExpiry = DEFAULT_TOKEN_REFRESH_BUFFER_MINUTES) => {
|
|
14
|
+
const expirationTime = new Date(expiresAt).getTime();
|
|
15
|
+
const currentTime = Date.now();
|
|
16
|
+
const bufferTime = minutesBeforeExpiry * MILLISECONDS_PER_MINUTE;
|
|
17
|
+
return currentTime + bufferTime >= expirationTime;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Get the remaining time until token expiry in minutes
|
|
21
|
+
*/
|
|
22
|
+
export const getTimeUntilExpiry = (expiresAt) => {
|
|
23
|
+
const expirationTime = new Date(expiresAt).getTime();
|
|
24
|
+
const currentTime = Date.now();
|
|
25
|
+
const remainingTime = expirationTime - currentTime;
|
|
26
|
+
if (remainingTime <= 0) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
return Math.floor(remainingTime / MILLISECONDS_PER_MINUTE);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Format the time until expiry in a human-readable format
|
|
33
|
+
*/
|
|
34
|
+
export const formatTimeUntilExpiry = (expiresAt) => {
|
|
35
|
+
const minutesRemaining = getTimeUntilExpiry(expiresAt);
|
|
36
|
+
if (minutesRemaining <= 0) {
|
|
37
|
+
return TIME_LABEL_EXPIRED;
|
|
38
|
+
}
|
|
39
|
+
if (minutesRemaining < MINUTES_PER_HOUR) {
|
|
40
|
+
return minutesRemaining === 1 ? `1 ${TIME_LABEL_MINUTE}` : `${minutesRemaining} ${TIME_LABEL_MINUTES}`;
|
|
41
|
+
}
|
|
42
|
+
const hoursRemaining = Math.floor(minutesRemaining / MINUTES_PER_HOUR);
|
|
43
|
+
if (hoursRemaining < HOURS_PER_DAY) {
|
|
44
|
+
return hoursRemaining === 1 ? `1 ${TIME_LABEL_HOUR}` : `${hoursRemaining} ${TIME_LABEL_HOURS}`;
|
|
45
|
+
}
|
|
46
|
+
const daysRemaining = Math.floor(hoursRemaining / HOURS_PER_DAY);
|
|
47
|
+
return daysRemaining === 1 ? `1 ${TIME_LABEL_DAY}` : `${daysRemaining} ${TIME_LABEL_DAYS}`;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Parse device information from user agent string
|
|
51
|
+
*/
|
|
52
|
+
export const parseDeviceInfo = (userAgent) => {
|
|
53
|
+
const browser = userAgent.includes('Chrome')
|
|
54
|
+
? 'Chrome'
|
|
55
|
+
: userAgent.includes('Firefox')
|
|
56
|
+
? 'Firefox'
|
|
57
|
+
: userAgent.includes('Safari')
|
|
58
|
+
? 'Safari'
|
|
59
|
+
: userAgent.includes('Edge')
|
|
60
|
+
? 'Edge'
|
|
61
|
+
: DEFAULT_UNKNOWN_VALUE;
|
|
62
|
+
const os = userAgent.includes('Windows')
|
|
63
|
+
? 'Windows'
|
|
64
|
+
: userAgent.includes('Mac')
|
|
65
|
+
? 'macOS'
|
|
66
|
+
: userAgent.includes('Linux')
|
|
67
|
+
? 'Linux'
|
|
68
|
+
: userAgent.includes('Android')
|
|
69
|
+
? 'Android'
|
|
70
|
+
: userAgent.includes('iOS')
|
|
71
|
+
? 'iOS'
|
|
72
|
+
: DEFAULT_UNKNOWN_VALUE;
|
|
73
|
+
return { browser, os };
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Check if token refresh was successful
|
|
77
|
+
*/
|
|
78
|
+
export const isRefreshSuccess = (response) => {
|
|
79
|
+
return !!(response?.status === 200 && response?.data?.access && response?.data?.refresh);
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Get error message from token refresh error
|
|
83
|
+
*/
|
|
84
|
+
export const getRefreshErrorMessage = (error) => {
|
|
85
|
+
if (error.response?.data?.detail) {
|
|
86
|
+
return error.response.data.detail;
|
|
87
|
+
}
|
|
88
|
+
if (error.response?.data?.message) {
|
|
89
|
+
return error.response.data.message;
|
|
90
|
+
}
|
|
91
|
+
if (error.message) {
|
|
92
|
+
return error.message;
|
|
93
|
+
}
|
|
94
|
+
return DEFAULT_ERROR_MESSAGE;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Create an auto-refresh handler for tokens
|
|
98
|
+
*/
|
|
99
|
+
export const createAutoRefreshHandler = (refreshCallback, checkInterval = 60000) => {
|
|
100
|
+
let intervalId = null;
|
|
101
|
+
const start = () => {
|
|
102
|
+
if (intervalId)
|
|
103
|
+
return;
|
|
104
|
+
intervalId = setInterval(refreshCallback, checkInterval);
|
|
105
|
+
};
|
|
106
|
+
const stop = () => {
|
|
107
|
+
if (intervalId) {
|
|
108
|
+
clearInterval(intervalId);
|
|
109
|
+
intervalId = null;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return { start, stop };
|
|
113
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portfolio-related constants for shared services.
|
|
3
|
+
*
|
|
4
|
+
* These constants should match the backend constants in bilberry/portfolios/constants.py
|
|
5
|
+
* to ensure consistency across the application stack.
|
|
6
|
+
*/
|
|
7
|
+
export declare const INVESTMENT_HORIZON_SHORT = "short";
|
|
8
|
+
export declare const INVESTMENT_HORIZON_MEDIUM = "medium";
|
|
9
|
+
export declare const INVESTMENT_HORIZON_LONG = "long";
|
|
10
|
+
export declare const INVESTMENT_HORIZON_LABEL_SHORT = "Short-term (0\u20133 yrs)";
|
|
11
|
+
export declare const INVESTMENT_HORIZON_LABEL_MEDIUM = "Medium-term (3\u20137 yrs)";
|
|
12
|
+
export declare const INVESTMENT_HORIZON_LABEL_LONG = "Long-term (7+ yrs)";
|
|
13
|
+
export declare const INVESTMENT_HORIZON_OPTIONS: {
|
|
14
|
+
value: string;
|
|
15
|
+
label: string;
|
|
16
|
+
}[];
|
|
17
|
+
export declare const RISK_TOLERANCE_LOW = "low";
|
|
18
|
+
export declare const RISK_TOLERANCE_MEDIUM = "medium";
|
|
19
|
+
export declare const RISK_TOLERANCE_HIGH = "high";
|
|
20
|
+
export declare const RISK_TOLERANCE_LABEL_LOW = "Low";
|
|
21
|
+
export declare const RISK_TOLERANCE_LABEL_MEDIUM = "Medium";
|
|
22
|
+
export declare const RISK_TOLERANCE_LABEL_HIGH = "High";
|
|
23
|
+
export declare const RISK_TOLERANCE_OPTIONS: {
|
|
24
|
+
value: string;
|
|
25
|
+
label: string;
|
|
26
|
+
}[];
|
|
27
|
+
export declare const INVESTMENT_EXPERIENCE_NONE = "none";
|
|
28
|
+
export declare const INVESTMENT_EXPERIENCE_SOME = "some";
|
|
29
|
+
export declare const INVESTMENT_EXPERIENCE_EXTENSIVE = "extensive";
|
|
30
|
+
export declare const INVESTMENT_EXPERIENCE_LABEL_NONE = "No experience";
|
|
31
|
+
export declare const INVESTMENT_EXPERIENCE_LABEL_SOME = "Some experience";
|
|
32
|
+
export declare const INVESTMENT_EXPERIENCE_LABEL_EXTENSIVE = "Extensive";
|
|
33
|
+
export declare const INVESTMENT_EXPERIENCE_OPTIONS: {
|
|
34
|
+
value: string;
|
|
35
|
+
label: string;
|
|
36
|
+
}[];
|
|
37
|
+
export declare const API_ENDPOINTS: {
|
|
38
|
+
readonly PORTFOLIOS: "/api/portfolios/";
|
|
39
|
+
readonly PORTFOLIO_TEMPLATES: "/api/portfolio-templates/";
|
|
40
|
+
readonly PORTFOLIO_TEMPLATES_RECOMMENDED: "/api/portfolio-templates/recommended/";
|
|
41
|
+
readonly ASSET_ALLOCATIONS: "/api/asset-allocations/";
|
|
42
|
+
readonly ASSET_HOLDINGS: "/api/asset-holdings/";
|
|
43
|
+
readonly ASSET_HOLDING_SNAPSHOTS: "/api/asset-holding-snapshots/";
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/services/portfolios/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAChD,eAAO,MAAM,yBAAyB,WAAW,CAAC;AAClD,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAG9C,eAAO,MAAM,8BAA8B,8BAAyB,CAAC;AACrE,eAAO,MAAM,+BAA+B,+BAA0B,CAAC;AACvE,eAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAGlE,eAAO,MAAM,0BAA0B;;;GAItC,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAG1C,eAAO,MAAM,wBAAwB,QAAQ,CAAC;AAC9C,eAAO,MAAM,2BAA2B,WAAW,CAAC;AACpD,eAAO,MAAM,yBAAyB,SAAS,CAAC;AAGhD,eAAO,MAAM,sBAAsB;;;GAIlC,CAAC;AAGF,eAAO,MAAM,0BAA0B,SAAS,CAAC;AACjD,eAAO,MAAM,0BAA0B,SAAS,CAAC;AACjD,eAAO,MAAM,+BAA+B,cAAc,CAAC;AAG3D,eAAO,MAAM,gCAAgC,kBAAkB,CAAC;AAChE,eAAO,MAAM,gCAAgC,oBAAoB,CAAC;AAClE,eAAO,MAAM,qCAAqC,cAAc,CAAC;AAGjE,eAAO,MAAM,6BAA6B;;;GAIzC,CAAC;AAGF,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portfolio-related constants for shared services.
|
|
3
|
+
*
|
|
4
|
+
* These constants should match the backend constants in bilberry/portfolios/constants.py
|
|
5
|
+
* to ensure consistency across the application stack.
|
|
6
|
+
*/
|
|
7
|
+
// Investment horizon constants
|
|
8
|
+
export const INVESTMENT_HORIZON_SHORT = 'short';
|
|
9
|
+
export const INVESTMENT_HORIZON_MEDIUM = 'medium';
|
|
10
|
+
export const INVESTMENT_HORIZON_LONG = 'long';
|
|
11
|
+
// Investment horizon label constants
|
|
12
|
+
export const INVESTMENT_HORIZON_LABEL_SHORT = 'Short-term (0–3 yrs)';
|
|
13
|
+
export const INVESTMENT_HORIZON_LABEL_MEDIUM = 'Medium-term (3–7 yrs)';
|
|
14
|
+
export const INVESTMENT_HORIZON_LABEL_LONG = 'Long-term (7+ yrs)';
|
|
15
|
+
// Investment horizon options
|
|
16
|
+
export const INVESTMENT_HORIZON_OPTIONS = [
|
|
17
|
+
{ value: INVESTMENT_HORIZON_SHORT, label: INVESTMENT_HORIZON_LABEL_SHORT },
|
|
18
|
+
{ value: INVESTMENT_HORIZON_MEDIUM, label: INVESTMENT_HORIZON_LABEL_MEDIUM },
|
|
19
|
+
{ value: INVESTMENT_HORIZON_LONG, label: INVESTMENT_HORIZON_LABEL_LONG },
|
|
20
|
+
];
|
|
21
|
+
// Risk tolerance constants
|
|
22
|
+
export const RISK_TOLERANCE_LOW = 'low';
|
|
23
|
+
export const RISK_TOLERANCE_MEDIUM = 'medium';
|
|
24
|
+
export const RISK_TOLERANCE_HIGH = 'high';
|
|
25
|
+
// Risk tolerance label constants
|
|
26
|
+
export const RISK_TOLERANCE_LABEL_LOW = 'Low';
|
|
27
|
+
export const RISK_TOLERANCE_LABEL_MEDIUM = 'Medium';
|
|
28
|
+
export const RISK_TOLERANCE_LABEL_HIGH = 'High';
|
|
29
|
+
// Risk tolerance options
|
|
30
|
+
export const RISK_TOLERANCE_OPTIONS = [
|
|
31
|
+
{ value: RISK_TOLERANCE_LOW, label: RISK_TOLERANCE_LABEL_LOW },
|
|
32
|
+
{ value: RISK_TOLERANCE_MEDIUM, label: RISK_TOLERANCE_LABEL_MEDIUM },
|
|
33
|
+
{ value: RISK_TOLERANCE_HIGH, label: RISK_TOLERANCE_LABEL_HIGH },
|
|
34
|
+
];
|
|
35
|
+
// Investment experience constants
|
|
36
|
+
export const INVESTMENT_EXPERIENCE_NONE = 'none';
|
|
37
|
+
export const INVESTMENT_EXPERIENCE_SOME = 'some';
|
|
38
|
+
export const INVESTMENT_EXPERIENCE_EXTENSIVE = 'extensive';
|
|
39
|
+
// Investment experience label constants
|
|
40
|
+
export const INVESTMENT_EXPERIENCE_LABEL_NONE = 'No experience';
|
|
41
|
+
export const INVESTMENT_EXPERIENCE_LABEL_SOME = 'Some experience';
|
|
42
|
+
export const INVESTMENT_EXPERIENCE_LABEL_EXTENSIVE = 'Extensive';
|
|
43
|
+
// Investment experience options
|
|
44
|
+
export const INVESTMENT_EXPERIENCE_OPTIONS = [
|
|
45
|
+
{ value: INVESTMENT_EXPERIENCE_NONE, label: INVESTMENT_EXPERIENCE_LABEL_NONE },
|
|
46
|
+
{ value: INVESTMENT_EXPERIENCE_SOME, label: INVESTMENT_EXPERIENCE_LABEL_SOME },
|
|
47
|
+
{ value: INVESTMENT_EXPERIENCE_EXTENSIVE, label: INVESTMENT_EXPERIENCE_LABEL_EXTENSIVE },
|
|
48
|
+
];
|
|
49
|
+
// API Endpoints
|
|
50
|
+
export const API_ENDPOINTS = {
|
|
51
|
+
PORTFOLIOS: '/api/portfolios/',
|
|
52
|
+
PORTFOLIO_TEMPLATES: '/api/portfolio-templates/',
|
|
53
|
+
PORTFOLIO_TEMPLATES_RECOMMENDED: '/api/portfolio-templates/recommended/',
|
|
54
|
+
ASSET_ALLOCATIONS: '/api/asset-allocations/',
|
|
55
|
+
ASSET_HOLDINGS: '/api/asset-holdings/',
|
|
56
|
+
ASSET_HOLDING_SNAPSHOTS: '/api/asset-holding-snapshots/',
|
|
57
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/portfolios/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Portfolio, PaginatedPortfolios, PortfolioPayload, RebalancingTradesGenerationResponse } from './types';
|
|
2
|
+
export declare const getPortfolios: () => Promise<import("axios").AxiosResponse<PaginatedPortfolios, any>>;
|
|
3
|
+
export declare const createPortfolio: (data: PortfolioPayload) => Promise<import("axios").AxiosResponse<Portfolio, any>>;
|
|
4
|
+
export declare const updatePortfolio: (uuid: string, data: Partial<PortfolioPayload>) => Promise<import("axios").AxiosResponse<Portfolio, any>>;
|
|
5
|
+
export declare const getPortfolioByUuid: (uuid: string) => Promise<import("axios").AxiosResponse<Portfolio, any>>;
|
|
6
|
+
export declare const generateRebalancingTrades: (portfolioUuid: string) => Promise<import("axios").AxiosResponse<RebalancingTradesGenerationResponse, any>>;
|
|
7
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/services/portfolios/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mCAAmC,EAAE,MAAM,SAAS,CAAC;AAGrH,eAAO,MAAM,aAAa,wEAEzB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,gBAAgB,2DAErD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,2DAE5E,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,2DAE9C,CAAC;AAGF,eAAO,MAAM,yBAAyB,GAAI,eAAe,MAAM,qFAI9D,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { webApiClient } from '../../api/apiClient';
|
|
2
|
+
import { API_ENDPOINTS } from './constants';
|
|
3
|
+
// Portfolio CRUD operations
|
|
4
|
+
export const getPortfolios = () => {
|
|
5
|
+
return webApiClient.get(API_ENDPOINTS.PORTFOLIOS);
|
|
6
|
+
};
|
|
7
|
+
export const createPortfolio = (data) => {
|
|
8
|
+
return webApiClient.post(API_ENDPOINTS.PORTFOLIOS, data);
|
|
9
|
+
};
|
|
10
|
+
export const updatePortfolio = (uuid, data) => {
|
|
11
|
+
return webApiClient.patch(`${API_ENDPOINTS.PORTFOLIOS}${uuid}/`, data);
|
|
12
|
+
};
|
|
13
|
+
export const getPortfolioByUuid = (uuid) => {
|
|
14
|
+
return webApiClient.get(`${API_ENDPOINTS.PORTFOLIOS}${uuid}/`);
|
|
15
|
+
};
|
|
16
|
+
// Portfolio rebalancing operations
|
|
17
|
+
export const generateRebalancingTrades = (portfolioUuid) => {
|
|
18
|
+
return webApiClient.post(`${API_ENDPOINTS.PORTFOLIOS}${portfolioUuid}/generate-rebalancing-trades/`);
|
|
19
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PaginatedResponse } from '../../api/types';
|
|
2
|
+
export interface Portfolio {
|
|
3
|
+
uuid: string;
|
|
4
|
+
account: string;
|
|
5
|
+
name: string;
|
|
6
|
+
template: string | null;
|
|
7
|
+
marketValue: string;
|
|
8
|
+
createdAt?: string;
|
|
9
|
+
updatedAt?: string;
|
|
10
|
+
}
|
|
11
|
+
export type PaginatedPortfolios = PaginatedResponse<Portfolio>;
|
|
12
|
+
export interface PortfolioPayload {
|
|
13
|
+
account: string;
|
|
14
|
+
name: string;
|
|
15
|
+
template?: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface RebalancingTradesGenerationResponse {
|
|
18
|
+
status: string;
|
|
19
|
+
message: string;
|
|
20
|
+
tradeCount?: number;
|
|
21
|
+
buyTradeCount?: number;
|
|
22
|
+
sellTradeCount?: number;
|
|
23
|
+
totalTradeValue?: number;
|
|
24
|
+
netCashImpact?: number;
|
|
25
|
+
availableCash?: number;
|
|
26
|
+
requiredMinimum?: number;
|
|
27
|
+
errorType?: 'business_logic' | 'permission' | 'server';
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/portfolios/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,mCAAmC;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,gBAAgB,GAAG,YAAY,GAAG,QAAQ,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const formatPortfolioValue: (value: string | number) => string;
|
|
2
|
+
export declare const calculateTotalValue: (marketValue: string | number, cashBalance: string | number) => number;
|
|
3
|
+
export declare const getMarketAllocation: (marketValue: string | number, totalValue: string | number) => number;
|
|
4
|
+
export declare const getCashAllocation: (cashBalance: string | number, totalValue: string | number) => number;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/services/portfolios/utils.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,GAAG,MAAM,KAAG,MAQ7D,CAAC;AAGF,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,aAAa,MAAM,GAAG,MAAM,KAAG,MAIhG,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,YAAY,MAAM,GAAG,MAAM,KAAG,MAI/F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,YAAY,MAAM,GAAG,MAAM,KAAG,MAI7F,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Portfolio formatting utilities
|
|
2
|
+
export const formatPortfolioValue = (value) => {
|
|
3
|
+
const numValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
4
|
+
return new Intl.NumberFormat('en-AU', {
|
|
5
|
+
style: 'currency',
|
|
6
|
+
currency: 'AUD',
|
|
7
|
+
minimumFractionDigits: 2,
|
|
8
|
+
maximumFractionDigits: 2,
|
|
9
|
+
}).format(numValue);
|
|
10
|
+
};
|
|
11
|
+
// Portfolio calculation utilities
|
|
12
|
+
export const calculateTotalValue = (marketValue, cashBalance) => {
|
|
13
|
+
const market = typeof marketValue === 'string' ? parseFloat(marketValue || '0') : marketValue;
|
|
14
|
+
const cash = typeof cashBalance === 'string' ? parseFloat(cashBalance || '0') : cashBalance;
|
|
15
|
+
return market + cash;
|
|
16
|
+
};
|
|
17
|
+
export const getMarketAllocation = (marketValue, totalValue) => {
|
|
18
|
+
const market = typeof marketValue === 'string' ? parseFloat(marketValue || '0') : marketValue;
|
|
19
|
+
const total = typeof totalValue === 'string' ? parseFloat(totalValue || '0') : totalValue;
|
|
20
|
+
return total > 0 ? (market / total) * 100 : 0;
|
|
21
|
+
};
|
|
22
|
+
export const getCashAllocation = (cashBalance, totalValue) => {
|
|
23
|
+
const cash = typeof cashBalance === 'string' ? parseFloat(cashBalance || '0') : cashBalance;
|
|
24
|
+
const total = typeof totalValue === 'string' ? parseFloat(totalValue || '0') : totalValue;
|
|
25
|
+
return total > 0 ? (cash / total) * 100 : 0;
|
|
26
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cranberry-money/shared-services",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Shared API services and client for MyPortfolio platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@cranberry-money/shared-constants": "^1.0.1",
|
|
25
|
-
"@cranberry-money/shared-types": "^1.0.1"
|
|
25
|
+
"@cranberry-money/shared-types": "^1.0.1",
|
|
26
|
+
"axios": "^1.7.0"
|
|
26
27
|
},
|
|
27
28
|
"peerDependencies": {
|
|
28
29
|
"@tanstack/react-query": ">=5.0.0",
|