datastake-daf 0.6.487 → 0.6.489

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.
@@ -0,0 +1,229 @@
1
+ import axios from 'axios';
2
+ import { cleanJSON } from '../../helpers/StringHelper.js';
3
+ import { assignParamsToUrl } from '../../helpers/urlHelpers.js';
4
+ import { getToken } from '../../helpers/Token.js';
5
+
6
+ /**
7
+ * Base HTTP Service Class
8
+ * Provides axios wrapper with token management, cancel tokens, and interceptors
9
+ */
10
+ export class BaseHTTPService {
11
+ constructor(config = {}) {
12
+ const {getHeaders, getBaseURL, onError, timeout = 300000, customAxiosConfig = {}} = config;
13
+
14
+ this.getToken = getToken || (() => null);
15
+ this.getHeaders = getHeaders || (() => ({}));
16
+ this.getBaseURL = getBaseURL || (() => null);
17
+ this.onError = onError || (() => null);
18
+ this.cleanJSON = cleanJSON;
19
+ this.timeout = timeout;
20
+ this.customAxiosConfig = customAxiosConfig;
21
+
22
+ // Init
23
+ this.cancelToken = {}
24
+ this.token = this.getToken();
25
+
26
+ this.setupAxios();
27
+ }
28
+
29
+ setupAxios() {
30
+ const headers = {
31
+ Authorization: `Bearer ${this.token}`,
32
+ ...this.getHeaders(),
33
+ };
34
+
35
+ this.api = axios.create({
36
+ baseURL: this.getBaseURL(),
37
+ headers,
38
+ timeout: this.timeout,
39
+ ...this.customAxiosConfig,
40
+ });
41
+
42
+ this.setupInterceptors();
43
+ }
44
+
45
+ setupInterceptors() {
46
+ this.api.interceptors.response.use((response) => response,
47
+ (error) => Promise.reject(error)
48
+ );
49
+
50
+ // Request interceptor - clean JSON data
51
+ this.api.interceptors.request.use(
52
+ (config) => {
53
+ if (['post', 'put', 'patch'].includes(config.method)) {
54
+ config.data = this.cleanJSON(config.data);
55
+ }
56
+
57
+ return config;
58
+ },
59
+ (error) => Promise.reject(error)
60
+ );
61
+ }
62
+
63
+ reloadAxios() {
64
+ const token = this.getToken();
65
+ this.token = token;
66
+
67
+ const options = {
68
+ baseURL: this.getBaseURL(),
69
+ timeout: this.timeout,
70
+ ...this.customAxiosConfig,
71
+ };
72
+
73
+ if (token) {
74
+ options.headers = {
75
+ Authorization: `Bearer ${token}`,
76
+ ...this.getHeaders(),
77
+ };
78
+ }
79
+
80
+ this.api = axios.create(options);
81
+ this.setupInterceptors();
82
+ }
83
+
84
+ async formatResponse(call) {
85
+ try {
86
+ const res = await call;
87
+ const { data, status, statusText } = res || {};
88
+ this.cancelToken = {};
89
+ return { data, status, statusText };
90
+ } catch (error) {
91
+ return Promise.reject(error);
92
+ }
93
+ }
94
+
95
+ apiPost(options) {
96
+ // Check if there are any previous pending requests
97
+ if (typeof this.cancelToken[options.url] != typeof undefined) {
98
+ try {
99
+ this.cancelToken[options.url].cancel("Operation canceled due to new request.");
100
+ } catch (e) {
101
+ console.log(e);
102
+ return {};
103
+ }
104
+ }
105
+
106
+ this.cancelToken[options.url] = axios.CancelToken.source();
107
+ const token = this.getToken();
108
+
109
+ if (token !== this.token || !token) {
110
+ this.reloadAxios();
111
+ }
112
+
113
+ return this.formatResponse(
114
+ this.api.post(options.url, options.data, {
115
+ baseURL: options.baseURL || this.getBaseURL(options),
116
+ cancelToken: this.cancelToken[options.url].token,
117
+ headers: {
118
+ Authorization: `Bearer ${this.getToken()}`,
119
+ ...this.getHeaders(),
120
+ ...(options?.headers || {}),
121
+ }
122
+ })
123
+ .catch((err) => this.onError(err))
124
+ );
125
+ }
126
+
127
+ apiGet(options) {
128
+ const token = this.getToken();
129
+
130
+ if (token !== this.token || !token) {
131
+ this.reloadAxios();
132
+ }
133
+
134
+ const { url, ...config } = options;
135
+
136
+ return this.formatResponse(
137
+ this.api.get(url, {
138
+ ...config,
139
+ baseURL: options.baseURL || this.getBaseURL(options),
140
+ headers: {
141
+ Authorization: `Bearer ${this.getToken()}`,
142
+ ...this.getHeaders(),
143
+ ...(config?.headers || {}),
144
+ }
145
+ })
146
+ .catch((err) => this.onError(err))
147
+ );
148
+ }
149
+
150
+ apiDelete(options) {
151
+ const token = this.getToken();
152
+
153
+ if (token !== this.token || !token) {
154
+ this.reloadAxios();
155
+ }
156
+
157
+ const { url, ...config } = options;
158
+
159
+ return this.formatResponse(
160
+ this.api.delete(url, {
161
+ ...config,
162
+ baseURL: options.baseURL || this.getBaseURL(options),
163
+ headers: {
164
+ Authorization: `Bearer ${this.getToken()}`,
165
+ ...this.getHeaders(),
166
+ ...(config?.headers || {}),
167
+ }
168
+ })
169
+ .catch((err) => this.onError(err))
170
+ );
171
+ }
172
+
173
+ apiPut(options) {
174
+ if (typeof this.cancelToken[options.url] != typeof undefined) {
175
+ try {
176
+ this.cancelToken[options.url].cancel("Operation canceled due to new request.");
177
+ } catch (e) {
178
+ console.log(e);
179
+ return {};
180
+ }
181
+ }
182
+
183
+ this.cancelToken[options.url] = axios.CancelToken.source();
184
+ const token = this.getToken();
185
+
186
+ if (token !== this.token || !token) {
187
+ this.reloadAxios();
188
+ }
189
+
190
+ return this.formatResponse(
191
+ this.api.put(options.url, options.data, {
192
+ cancelToken: this.cancelToken[options.url].token,
193
+ baseURL: options.baseURL || this.getBaseURL(options),
194
+ headers: {
195
+ Authorization: `Bearer ${this.getToken()}`,
196
+ ...this.getHeaders(),
197
+ ...(options?.headers || {}),
198
+ }
199
+ })
200
+ .catch((err) => this.onError(err, options.onUnauthorized))
201
+ );
202
+ }
203
+
204
+ apiPatch(options) {
205
+ const token = this.getToken();
206
+
207
+ if (token !== this.token || !token) {
208
+ this.reloadAxios();
209
+ }
210
+
211
+ return this.formatResponse(
212
+ this.api.patch(options.url, options.data, {
213
+ baseURL: options.baseURL || this.getBaseURL(options),
214
+ headers: {
215
+ Authorization: `Bearer ${this.getToken()}`,
216
+ ...this.getHeaders(),
217
+ ...(options?.headers || {}),
218
+ }
219
+ })
220
+ .catch((err) => this.onError(err))
221
+ );
222
+ }
223
+
224
+
225
+ // Utility method
226
+ assignParamsToUrl(path, params) {
227
+ return assignParamsToUrl(path, params);
228
+ }
229
+ }
@@ -0,0 +1,43 @@
1
+ export class ErrorHandler {
2
+ constructor(config = {}) {
3
+ this.store = config.store;
4
+ this.addToastAction = config.addToastAction;
5
+ this.formatData = config.formatData || this.defaultFormatData;
6
+ }
7
+
8
+ handle({stats, statusText, data}) {
9
+ if(this.store && this.addToastAction) {
10
+ this.store.dispatch(this.addToastAction({
11
+ title: statusText,
12
+ type: 'danger',
13
+ body: this.formatData(data),
14
+ }));
15
+ } else {
16
+ console.error('Error: ', {stats, statusText, data});
17
+ }
18
+ }
19
+
20
+ defaultFormatData(errors) {
21
+ if (!Array.isArray(errors)) {
22
+ return String(errors);
23
+ }
24
+
25
+ const e = [];
26
+ errors.forEach(error => {
27
+ if (error && typeof error === 'object' && error.constraints) {
28
+ Object.keys(error.constraints)
29
+ .forEach(key => e.push(error.constraints[key]));
30
+ } else if (typeof error === 'string') {
31
+ e.push(error);
32
+ } else {
33
+ e.push(JSON.stringify(error));
34
+ }
35
+ });
36
+
37
+ return e.join('\n');
38
+ }
39
+
40
+ static createInstance(config) {
41
+ return new ErrorHandler(config);
42
+ }
43
+ }
@@ -202,4 +202,15 @@ export const safeJsonParse = (value, fallback = value) => {
202
202
  console.warn('Failed to parse JSON:', value);
203
203
  return fallback;
204
204
  }
205
- };
205
+ };
206
+
207
+ export const cleanJSON = (json) => {
208
+ for (let key in json) {
209
+ if (json[key] === undefined) {
210
+ json[key] = null;
211
+ } /*else if (typeof json[key] === 'object')
212
+ json[key] = cleanJSON(json[key]);
213
+ */
214
+ }
215
+ return json;
216
+ }
@@ -0,0 +1,97 @@
1
+ import { message } from 'antd';
2
+
3
+ /**
4
+ * Generic error handler factory for axios requests
5
+ * Highly configurable to adapt to different project needs
6
+ */
7
+ export const createErrorHandler = (config = {}) => {
8
+ const {
9
+ onUnauthorized,
10
+ handleError,
11
+ getStorageManager,
12
+ checkTokenValidity = true,
13
+ unauthorizedRedirect = '/',
14
+ tokenStorageKey = 'token',
15
+ handleNetworkError = true,
16
+ } = config;
17
+
18
+ return (error, customOnUnauthorized) => {
19
+ // Handle cases where error.response doesn't exist (network errors)
20
+ if (!error.response) {
21
+ if (handleNetworkError && handleError) {
22
+ handleError({
23
+ status: 0,
24
+ statusText: "Network Error",
25
+ data: ["Please check your internet connection."],
26
+ });
27
+ }
28
+ return Promise.reject(error);
29
+ }
30
+
31
+ const { status, statusText, data: { errors, message } = {} } = error.response || { data: {} };
32
+
33
+ // Handle 401 Unauthorized
34
+ if (status === 401) {
35
+ if (checkTokenValidity && getStorageManager) {
36
+ const token = getStorageManager().get(tokenStorageKey);
37
+ if (token) {
38
+ if (typeof customOnUnauthorized === 'function') {
39
+ customOnUnauthorized();
40
+ } else if (typeof onUnauthorized === 'function') {
41
+ onUnauthorized();
42
+ } else {
43
+ getStorageManager().clearOne(tokenStorageKey);
44
+ if (typeof window !== 'undefined') {
45
+ window.location.href = unauthorizedRedirect;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ // Handle 4xx and 5xx errors
53
+ if (status >= 400 && status <= 500) {
54
+ if (handleError) {
55
+ handleError({
56
+ status,
57
+ statusText: message || statusText,
58
+ data: errors || []
59
+ });
60
+ }
61
+ }
62
+
63
+ return Promise.reject(error);
64
+ };
65
+ };
66
+
67
+ /**
68
+ * Simple error handler using antd message component
69
+ * Useful for quick error notifications
70
+ */
71
+ export const handleError = (err) => {
72
+ const errorMessage = err?.response?.data?.message ||
73
+ err?.message ||
74
+ 'An error occurred';
75
+ message.error(errorMessage);
76
+ };
77
+
78
+ /**
79
+ * Success message handler
80
+ */
81
+ export const handleSuccess = (msg) => {
82
+ message.success(msg || 'Operation successful');
83
+ };
84
+
85
+ /**
86
+ * Warning message handler
87
+ */
88
+ export const handleWarning = (msg) => {
89
+ message.warning(msg || 'Warning');
90
+ };
91
+
92
+ /**
93
+ * Info message handler
94
+ */
95
+ export const handleInfo = (msg) => {
96
+ message.info(msg);
97
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Utility functions for URL manipulation
3
+ */
4
+
5
+ /**
6
+ * Assigns parameters to URL path
7
+ * Example: assignParamsToUrl('/users/{id}/posts/{postId}', { id: 1, postId: 2 })
8
+ * Returns: '/users/1/posts/2'
9
+ */
10
+ export const assignParamsToUrl = (path, params) => {
11
+ let paramsPath = path;
12
+ const matches = path.match(/\{\w+\}/gm);
13
+
14
+ if (matches) {
15
+ for (let param of matches) {
16
+ const key = param.match(/\w+/)[0];
17
+ paramsPath = paramsPath.replace(/\{\w+\}/, params[key]);
18
+ }
19
+ }
20
+
21
+ return paramsPath;
22
+ };
23
+
24
+ /**
25
+ * Build query string from object
26
+ * Example: buildQueryString({ page: 1, limit: 10 })
27
+ * Returns: '?page=1&limit=10'
28
+ */
29
+ export const buildQueryString = (params) => {
30
+ const query = Object.keys(params)
31
+ .filter(key => params[key] !== null && params[key] !== undefined)
32
+ .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
33
+ .join('&');
34
+
35
+ return query ? `?${query}` : '';
36
+ };
package/src/index.js CHANGED
@@ -71,6 +71,7 @@ export { default as KeyIndicatorsDetails } from "./@daf/core/components/Dashboar
71
71
  export { default as DetailsSection } from "./@daf/core/components/Dashboard/Widget/DetailsSection/index.jsx";
72
72
  export { default as SDGWidget } from "./@daf/core/components/Dashboard/Widget/SDGWidget/index.jsx";
73
73
  export { default as ComponentWithFocus } from "./@daf/core/components/Dashboard/ComponentWithFocus/index.jsx";
74
+ export { default as ComponentWithHoverFocus } from "./@daf/core/components/Dashboard/ComponentWithFocus/HoverFocus/index.jsx";
74
75
  export { default as ProjectWidget } from "./@daf/core/components/Dashboard/Widget/ProjectWidget/index.jsx";
75
76
  export { default as WidgetCard } from "./@daf/core/components/Dashboard/Widget/WidgetCard/index.js";
76
77
  export { default as CarouselWidget } from "./@daf/core/components/Dashboard/Widget/CarouselWidget/index.jsx";
@@ -0,0 +1,2 @@
1
+ export { BaseHTTPService } from './@daf/services/BaseHTTPService.js';
2
+ export { ErrorHandler } from './@daf/services/ErrorHandler.js';
package/src/utils.js CHANGED
@@ -9,7 +9,7 @@ export { renderTooltip, renderTooltipJsx } from './@daf/utils/tooltip'
9
9
  export { getRangeOfTicks } from './helpers/chart'
10
10
 
11
11
  export { propHasValue } from './helpers/deepFind'
12
- export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse } from './helpers/StringHelper'
12
+ export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse, cleanJSON } from './helpers/StringHelper'
13
13
  export { getNkey, groupSubsections, getImageUploadViewValue } from './@daf/core/components/ViewForm/helper'
14
14
  export { renderRows } from './@daf/core/components/Table/helper'
15
15
  export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted } from './helpers/Forms'
@@ -39,4 +39,11 @@ export { captureElementsAsImages, captureComponentsAsImages } from './helpers/co
39
39
 
40
40
  export { createDocument } from './@daf/core/components/Document/WordDocument/createDocument.js'
41
41
 
42
- export { processConfig, fetchImageAsBuffer } from './helpers/docHelper.js'
42
+ export { processConfig, fetchImageAsBuffer } from './helpers/docHelper.js'
43
+
44
+ export { getToken } from './helpers/Token.js';
45
+ export { StorageManager } from './helpers/StorageManager.js';
46
+
47
+ export { assignParamsToUrl, buildQueryString } from './helpers/urlHelpers.js';
48
+
49
+ export { createErrorHandler, handleError, handleSuccess, handleWarning, handleInfo } from './helpers/errorHandling.js';