@visns-studio/visns-components 5.7.0 → 5.7.2
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/package.json +1 -4
- package/src/components/cms/DataGrid.jsx +2 -2
- package/src/components/crm/Autocomplete.jsx +161 -127
- package/src/components/crm/DataGrid.jsx +2 -2
- package/src/components/crm/Download.jsx +15 -4
- package/src/components/crm/Fetch.jsx +69 -16
- package/src/components/crm/Notification.jsx +237 -106
- package/src/components/crm/QuickAction.jsx +318 -91
- package/src/components/crm/generic/GenericDetail.jsx +43 -127
- package/src/components/crm/generic/NotificationList.jsx +76 -7
- package/src/components/crm/generic/styles/NotificationList.module.scss +90 -2
- package/src/components/crm/styles/DataGrid.module.scss +5 -0
- package/src/components/crm/styles/Notification.module.scss +313 -96
- package/src/components/crm/styles/QuickAction.module.scss +168 -46
- package/src/components/styles/global.css +5 -0
- package/src/utils/fetchUtil.js +242 -0
|
@@ -1,36 +1,99 @@
|
|
|
1
1
|
.quickActions {
|
|
2
2
|
width: 100%;
|
|
3
|
-
background: rgba(var(--bg-rgb), 0.
|
|
4
|
-
padding: var(--padding);
|
|
5
|
-
border-top: solid
|
|
6
|
-
border-bottom: solid 1px rgba(var(--primary-rgb), 0.
|
|
3
|
+
background: rgba(var(--bg-rgb), 0.98);
|
|
4
|
+
padding: 0.75rem var(--padding);
|
|
5
|
+
border-top: solid 3px rgba(var(--primary-rgb), 0.1);
|
|
6
|
+
border-bottom: solid 1px rgba(var(--primary-rgb), 0.15);
|
|
7
7
|
color: var(--paragraph-color);
|
|
8
8
|
display: flex;
|
|
9
|
-
flex-wrap:
|
|
9
|
+
flex-wrap: wrap;
|
|
10
10
|
align-items: center;
|
|
11
|
-
box-shadow: 0
|
|
11
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
12
|
+
overflow: visible; /* Ensure dropdowns are visible */
|
|
13
|
+
position: relative; /* Create a stacking context */
|
|
14
|
+
z-index: 100; /* Ensure proper stacking */
|
|
15
|
+
gap: 0.5rem; /* Add consistent spacing between elements */
|
|
16
|
+
|
|
17
|
+
.actionIcon {
|
|
18
|
+
width: 32px;
|
|
19
|
+
height: 32px;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
background-color: rgba(var(--primary-rgb), 0.08);
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
margin-right: 0.75rem;
|
|
26
|
+
position: relative;
|
|
27
|
+
color: rgba(var(--primary-rgb), 0.8);
|
|
28
|
+
transition: all 0.2s ease;
|
|
12
29
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
&:hover {
|
|
31
|
+
background-color: rgba(var(--primary-rgb), 0.12);
|
|
32
|
+
transform: scale(1.05);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&::after {
|
|
36
|
+
content: '';
|
|
37
|
+
position: absolute;
|
|
38
|
+
right: -0.5rem;
|
|
39
|
+
top: 50%;
|
|
40
|
+
transform: translateY(-50%);
|
|
41
|
+
height: 60%;
|
|
42
|
+
width: 1px;
|
|
43
|
+
background-color: rgba(var(--primary-rgb), 0.15);
|
|
44
|
+
}
|
|
18
45
|
}
|
|
19
46
|
|
|
20
47
|
> button {
|
|
21
48
|
appearance: none;
|
|
22
|
-
border: 1px solid rgba(var(--primary-rgb), 0.
|
|
23
|
-
border-radius: var(--br);
|
|
24
|
-
background:
|
|
49
|
+
border: 1px solid rgba(var(--primary-rgb), 0.2);
|
|
50
|
+
border-radius: var(--br, 4px);
|
|
51
|
+
background: rgba(var(--bg-rgb), 1);
|
|
25
52
|
width: max-content;
|
|
26
53
|
color: var(--paragraph-color);
|
|
27
|
-
padding: 0.
|
|
28
|
-
margin: 0 0.
|
|
29
|
-
|
|
54
|
+
padding: 0.4rem 0.8rem;
|
|
55
|
+
margin: 0 0.2rem;
|
|
56
|
+
font-size: 0.85rem;
|
|
57
|
+
font-weight: 500;
|
|
58
|
+
transition: all 0.2s ease;
|
|
59
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
min-height: 32px;
|
|
64
|
+
position: relative;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
|
|
67
|
+
&::before {
|
|
68
|
+
content: '';
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: 0;
|
|
71
|
+
left: 0;
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
background: linear-gradient(
|
|
75
|
+
to bottom,
|
|
76
|
+
rgba(var(--primary-rgb), 0.05),
|
|
77
|
+
transparent
|
|
78
|
+
);
|
|
79
|
+
opacity: 0;
|
|
80
|
+
transition: opacity 0.2s ease;
|
|
81
|
+
}
|
|
30
82
|
|
|
31
83
|
&:hover {
|
|
32
|
-
background: var(--
|
|
33
|
-
transform: translateY(-
|
|
84
|
+
background: rgba(var(--bg-rgb), 1);
|
|
85
|
+
transform: translateY(-1px);
|
|
86
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.08);
|
|
87
|
+
border-color: rgba(var(--primary-rgb), 0.3);
|
|
88
|
+
|
|
89
|
+
&::before {
|
|
90
|
+
opacity: 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&:active {
|
|
95
|
+
transform: translateY(0);
|
|
96
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
34
97
|
}
|
|
35
98
|
}
|
|
36
99
|
|
|
@@ -38,24 +101,34 @@
|
|
|
38
101
|
display: flex;
|
|
39
102
|
align-items: center;
|
|
40
103
|
background: transparent;
|
|
41
|
-
margin:
|
|
104
|
+
margin-left: auto; /* Push search to the right */
|
|
42
105
|
flex-grow: 1;
|
|
43
106
|
position: relative;
|
|
107
|
+
max-width: 300px; /* Limit width for better appearance */
|
|
108
|
+
overflow: visible; /* Allow dropdown to be visible */
|
|
44
109
|
|
|
45
110
|
input[type='text'] {
|
|
46
111
|
flex-grow: 1;
|
|
47
|
-
border:
|
|
112
|
+
border: 1px solid rgba(var(--primary-rgb), 0.2);
|
|
48
113
|
outline: none;
|
|
49
|
-
padding:
|
|
50
|
-
padding-right:
|
|
51
|
-
border-radius: var(--br);
|
|
114
|
+
padding: 0.5rem 0.75rem;
|
|
115
|
+
padding-right: 36px;
|
|
116
|
+
border-radius: var(--br, 4px);
|
|
52
117
|
height: 32px;
|
|
53
|
-
font-size:
|
|
118
|
+
font-size: 0.85rem;
|
|
54
119
|
width: 100%;
|
|
55
|
-
box-shadow:
|
|
120
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
121
|
+
transition: all 0.2s ease;
|
|
122
|
+
background-color: rgba(var(--bg-rgb), 1);
|
|
123
|
+
|
|
124
|
+
&::placeholder {
|
|
125
|
+
color: rgba(var(--paragraph-rgb), 0.5);
|
|
126
|
+
font-size: 0.85rem;
|
|
127
|
+
}
|
|
56
128
|
|
|
57
129
|
&:focus {
|
|
58
|
-
box-shadow: 0 0
|
|
130
|
+
box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.15);
|
|
131
|
+
border-color: rgba(var(--primary-rgb), 0.4);
|
|
59
132
|
}
|
|
60
133
|
}
|
|
61
134
|
|
|
@@ -65,35 +138,73 @@
|
|
|
65
138
|
display: flex;
|
|
66
139
|
align-items: center;
|
|
67
140
|
justify-content: center;
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
width: 24px;
|
|
143
|
+
height: 24px;
|
|
144
|
+
border-radius: 50%;
|
|
145
|
+
transition: background-color 0.2s ease;
|
|
146
|
+
|
|
147
|
+
&:hover {
|
|
148
|
+
background-color: rgba(var(--primary-rgb), 0.05);
|
|
149
|
+
}
|
|
68
150
|
}
|
|
69
151
|
|
|
70
152
|
.searchIcon {
|
|
71
|
-
width:
|
|
72
|
-
height:
|
|
153
|
+
width: 18px;
|
|
154
|
+
height: 18px;
|
|
155
|
+
color: rgba(var(--paragraph-rgb), 0.6);
|
|
156
|
+
transition: color 0.2s ease;
|
|
157
|
+
|
|
158
|
+
&:hover {
|
|
159
|
+
color: rgba(var(--primary-rgb), 0.8);
|
|
160
|
+
}
|
|
73
161
|
}
|
|
74
162
|
}
|
|
75
163
|
|
|
76
|
-
|
|
164
|
+
/* Search results styling */
|
|
165
|
+
:global(.AutocompletePlace-results) {
|
|
77
166
|
position: absolute;
|
|
78
167
|
top: 100%;
|
|
79
168
|
width: 100%;
|
|
80
|
-
background: var(--
|
|
81
|
-
box-shadow: 0
|
|
82
|
-
z-index:
|
|
169
|
+
background: var(--bg-color, white);
|
|
170
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
|
171
|
+
z-index: 9999; /* Ensure it appears on top */
|
|
83
172
|
max-height: 400px;
|
|
84
173
|
overflow-y: auto;
|
|
85
|
-
|
|
86
|
-
|
|
174
|
+
overflow-x: hidden; /* Prevent horizontal scrolling */
|
|
175
|
+
border-radius: calc(var(--br, 4px) - 1px);
|
|
176
|
+
margin-top: 6px;
|
|
177
|
+
border: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
178
|
+
scrollbar-width: thin;
|
|
179
|
+
scrollbar-color: rgba(var(--primary-rgb), 0.2) transparent;
|
|
180
|
+
|
|
181
|
+
&::-webkit-scrollbar {
|
|
182
|
+
width: 6px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&::-webkit-scrollbar-track {
|
|
186
|
+
background: transparent;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
&::-webkit-scrollbar-thumb {
|
|
190
|
+
background-color: rgba(var(--primary-rgb), 0.2);
|
|
191
|
+
border-radius: 3px;
|
|
192
|
+
}
|
|
87
193
|
}
|
|
88
194
|
|
|
89
195
|
.resultItem {
|
|
90
|
-
padding: 0.5rem
|
|
196
|
+
padding: 0.5rem 0.75rem;
|
|
91
197
|
cursor: pointer;
|
|
92
|
-
transition:
|
|
198
|
+
transition: all 0.15s ease;
|
|
199
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.05);
|
|
200
|
+
white-space: nowrap;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
text-overflow: ellipsis;
|
|
203
|
+
width: 100%;
|
|
93
204
|
|
|
94
205
|
&:hover {
|
|
95
|
-
background-color:
|
|
96
|
-
|
|
206
|
+
background-color: rgba(var(--primary-rgb), 0.05);
|
|
207
|
+
padding-left: 1rem;
|
|
97
208
|
}
|
|
98
209
|
|
|
99
210
|
&:last-child {
|
|
@@ -102,25 +213,36 @@
|
|
|
102
213
|
|
|
103
214
|
h3 {
|
|
104
215
|
margin: 0;
|
|
105
|
-
font-weight:
|
|
106
|
-
color: var(--header-color);
|
|
107
|
-
font-size:
|
|
216
|
+
font-weight: 600;
|
|
217
|
+
color: var(--header-color, #333);
|
|
218
|
+
font-size: 0.8rem;
|
|
219
|
+
padding-bottom: 6px;
|
|
220
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.08);
|
|
221
|
+
text-transform: uppercase;
|
|
222
|
+
letter-spacing: 0.03em;
|
|
108
223
|
}
|
|
109
224
|
|
|
110
225
|
p {
|
|
111
226
|
margin: 0.25rem 0 0;
|
|
112
227
|
color: var(--paragraph-color);
|
|
113
|
-
font-size:
|
|
228
|
+
font-size: 0.85rem;
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
overflow: hidden;
|
|
231
|
+
text-overflow: ellipsis;
|
|
232
|
+
line-height: 1.4;
|
|
114
233
|
}
|
|
115
234
|
|
|
116
235
|
&.selected {
|
|
117
|
-
background-color: rgba(var(--primary-rgb), 0.
|
|
236
|
+
background-color: rgba(var(--primary-rgb), 0.08);
|
|
237
|
+
font-weight: 500;
|
|
238
|
+
padding-left: 1rem;
|
|
239
|
+
border-left: 2px solid rgba(var(--primary-rgb), 0.5);
|
|
118
240
|
}
|
|
119
241
|
}
|
|
120
242
|
|
|
121
243
|
.resultItemDivider {
|
|
122
244
|
height: 1px;
|
|
123
|
-
background-color: var(--
|
|
124
|
-
margin: 0.25rem 0;
|
|
245
|
+
background-color: rgba(var(--primary-rgb), 0.08);
|
|
246
|
+
margin: 0.25rem 0.75rem;
|
|
125
247
|
}
|
|
126
248
|
}
|
|
@@ -223,6 +223,11 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
|
|
|
223
223
|
backdrop-filter: blur(3px);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
.modalWide {
|
|
227
|
+
width: 80vw !important;
|
|
228
|
+
max-width: 1200px !important;
|
|
229
|
+
}
|
|
230
|
+
|
|
226
231
|
.AutocompletePlace-results {
|
|
227
232
|
z-index: 999;
|
|
228
233
|
width: 500px;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch utility to replace axios with similar API
|
|
3
|
+
* Designed to work with Laravel backend
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates an axios-like response object from a fetch response
|
|
8
|
+
* @param {Response} response - The fetch Response object
|
|
9
|
+
* @param {any} data - The parsed response data
|
|
10
|
+
* @returns {Object} - An axios-like response object
|
|
11
|
+
*/
|
|
12
|
+
const createAxiosLikeResponse = async (response, data) => {
|
|
13
|
+
return {
|
|
14
|
+
data,
|
|
15
|
+
status: response.status,
|
|
16
|
+
statusText: response.statusText,
|
|
17
|
+
headers: response.headers,
|
|
18
|
+
config: {
|
|
19
|
+
url: response.url,
|
|
20
|
+
method: response.type,
|
|
21
|
+
},
|
|
22
|
+
request: null, // Not available in fetch
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Main fetch function that mimics axios API
|
|
28
|
+
* @param {Object|string} config - Axios-like config object or URL string
|
|
29
|
+
* @returns {Promise} - Promise that resolves to an axios-like response
|
|
30
|
+
*/
|
|
31
|
+
const fetchUtil = async (config) => {
|
|
32
|
+
// Handle string input (URL)
|
|
33
|
+
if (typeof config === 'string') {
|
|
34
|
+
config = { url: config };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
url,
|
|
39
|
+
method = 'GET',
|
|
40
|
+
headers = {},
|
|
41
|
+
data,
|
|
42
|
+
params,
|
|
43
|
+
responseType,
|
|
44
|
+
withCredentials = false,
|
|
45
|
+
} = config;
|
|
46
|
+
|
|
47
|
+
// Build request URL with query parameters
|
|
48
|
+
let requestUrl = url;
|
|
49
|
+
|
|
50
|
+
// Create local copies that we can modify
|
|
51
|
+
let paramsObj = params ? { ...params } : {};
|
|
52
|
+
let dataObj = data;
|
|
53
|
+
|
|
54
|
+
// For GET and HEAD requests, convert data to query parameters if it exists
|
|
55
|
+
if (
|
|
56
|
+
(method.toUpperCase() === 'GET' || method.toUpperCase() === 'HEAD') &&
|
|
57
|
+
dataObj &&
|
|
58
|
+
typeof dataObj === 'object' &&
|
|
59
|
+
!(dataObj instanceof FormData)
|
|
60
|
+
) {
|
|
61
|
+
// Merge data into params
|
|
62
|
+
Object.assign(paramsObj, dataObj);
|
|
63
|
+
// Remove data since we've moved it to params
|
|
64
|
+
dataObj = undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Add params to URL
|
|
68
|
+
if (Object.keys(paramsObj).length > 0) {
|
|
69
|
+
const queryParams = new URLSearchParams();
|
|
70
|
+
Object.entries(paramsObj).forEach(([key, value]) => {
|
|
71
|
+
if (value !== undefined && value !== null) {
|
|
72
|
+
queryParams.append(key, value);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const queryString = queryParams.toString();
|
|
76
|
+
if (queryString) {
|
|
77
|
+
requestUrl += (url.includes('?') ? '&' : '?') + queryString;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Set up headers
|
|
82
|
+
const requestHeaders = new Headers({
|
|
83
|
+
...headers,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// If not explicitly set and sending data, default to JSON
|
|
87
|
+
if (
|
|
88
|
+
dataObj &&
|
|
89
|
+
!requestHeaders.has('Content-Type') &&
|
|
90
|
+
!(dataObj instanceof FormData)
|
|
91
|
+
) {
|
|
92
|
+
requestHeaders.set('Content-Type', 'application/json');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add CSRF token for Laravel if available
|
|
96
|
+
const csrfToken = document
|
|
97
|
+
.querySelector('meta[name="csrf-token"]')
|
|
98
|
+
?.getAttribute('content');
|
|
99
|
+
if (csrfToken) {
|
|
100
|
+
// Laravel accepts the CSRF token in different headers
|
|
101
|
+
if (!requestHeaders.has('X-CSRF-TOKEN')) {
|
|
102
|
+
requestHeaders.set('X-CSRF-TOKEN', csrfToken);
|
|
103
|
+
}
|
|
104
|
+
if (!requestHeaders.has('X-XSRF-TOKEN')) {
|
|
105
|
+
requestHeaders.set('X-XSRF-TOKEN', csrfToken);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add X-Requested-With header for Laravel to recognize AJAX requests
|
|
110
|
+
if (!requestHeaders.has('X-Requested-With')) {
|
|
111
|
+
requestHeaders.set('X-Requested-With', 'XMLHttpRequest');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Handle credentials
|
|
115
|
+
const credentials = withCredentials ? 'include' : 'same-origin';
|
|
116
|
+
|
|
117
|
+
// Prepare request options
|
|
118
|
+
const requestOptions = {
|
|
119
|
+
method: method.toUpperCase(),
|
|
120
|
+
headers: requestHeaders,
|
|
121
|
+
credentials,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Add body for non-GET requests
|
|
125
|
+
if (method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD') {
|
|
126
|
+
// Handle Laravel's _method for PUT/PATCH/DELETE
|
|
127
|
+
if (['PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase())) {
|
|
128
|
+
if (dataObj instanceof FormData) {
|
|
129
|
+
dataObj.append('_method', method.toUpperCase());
|
|
130
|
+
requestOptions.method = 'POST';
|
|
131
|
+
} else if (dataObj && typeof dataObj === 'object') {
|
|
132
|
+
requestOptions.body = JSON.stringify({
|
|
133
|
+
...dataObj,
|
|
134
|
+
_method: method.toUpperCase(),
|
|
135
|
+
});
|
|
136
|
+
requestOptions.method = 'POST';
|
|
137
|
+
} else {
|
|
138
|
+
// If no data, create a body with just _method
|
|
139
|
+
requestOptions.body = JSON.stringify({
|
|
140
|
+
_method: method.toUpperCase(),
|
|
141
|
+
});
|
|
142
|
+
requestOptions.method = 'POST';
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
// For regular POST
|
|
146
|
+
if (dataObj instanceof FormData) {
|
|
147
|
+
requestOptions.body = dataObj;
|
|
148
|
+
} else if (dataObj !== undefined) {
|
|
149
|
+
requestOptions.body = JSON.stringify(dataObj);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const response = await fetch(requestUrl, requestOptions);
|
|
156
|
+
|
|
157
|
+
// Parse response based on content type or specified responseType
|
|
158
|
+
let responseData;
|
|
159
|
+
|
|
160
|
+
if (responseType === 'blob') {
|
|
161
|
+
responseData = await response.blob();
|
|
162
|
+
} else if (responseType === 'arraybuffer') {
|
|
163
|
+
responseData = await response.arrayBuffer();
|
|
164
|
+
} else if (responseType === 'text') {
|
|
165
|
+
responseData = await response.text();
|
|
166
|
+
} else {
|
|
167
|
+
// Default: try to parse as JSON, fallback to text
|
|
168
|
+
const contentType = response.headers.get('content-type');
|
|
169
|
+
if (contentType && contentType.includes('application/json')) {
|
|
170
|
+
responseData = await response.json();
|
|
171
|
+
} else {
|
|
172
|
+
responseData = await response.text();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const axiosLikeResponse = await createAxiosLikeResponse(
|
|
177
|
+
response,
|
|
178
|
+
responseData
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// Handle error responses (4xx, 5xx)
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
const error = new Error(response.statusText || 'Request failed');
|
|
184
|
+
error.response = axiosLikeResponse;
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return axiosLikeResponse;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// If the error already has a response property, it's from our code above
|
|
191
|
+
if (!error.response) {
|
|
192
|
+
// Network errors or other fetch errors
|
|
193
|
+
error.response = {
|
|
194
|
+
data: { message: error.message },
|
|
195
|
+
status: 0,
|
|
196
|
+
statusText: error.message,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// Add convenience methods to match axios API
|
|
204
|
+
['get', 'delete', 'head', 'options'].forEach((method) => {
|
|
205
|
+
fetchUtil[method] = (url, config = {}) => {
|
|
206
|
+
// If second parameter is data (object but not a config object with recognized properties)
|
|
207
|
+
if (
|
|
208
|
+
config &&
|
|
209
|
+
typeof config === 'object' &&
|
|
210
|
+
!config.headers &&
|
|
211
|
+
!config.params &&
|
|
212
|
+
!config.responseType &&
|
|
213
|
+
!config.withCredentials
|
|
214
|
+
) {
|
|
215
|
+
// It's likely data, not config
|
|
216
|
+
return fetchUtil({
|
|
217
|
+
method,
|
|
218
|
+
url,
|
|
219
|
+
params: config, // Use as query parameters
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return fetchUtil({
|
|
224
|
+
...config,
|
|
225
|
+
method,
|
|
226
|
+
url,
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
['post', 'put', 'patch'].forEach((method) => {
|
|
232
|
+
fetchUtil[method] = (url, data, config = {}) => {
|
|
233
|
+
return fetchUtil({
|
|
234
|
+
...config,
|
|
235
|
+
method,
|
|
236
|
+
url,
|
|
237
|
+
data,
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
export default fetchUtil;
|