drf-react-by-schema 0.2.1 → 0.3.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.
@@ -1,13 +1,14 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import Box from '@mui/material/Box';
3
+ import { GridRowId } from '@mui/x-data-grid';
3
4
 
4
5
  import DataGridBySchemaEditable from './DataGridBySchemaEditable';
5
6
  import DataTotals, { SumRowsType } from './DataTotals';
6
7
  import { Layout } from '../styles';
7
- // import CONSTANTS from '../constants';
8
- import { GridEnrichedBySchemaColDef, Item, SchemaType } from '../utils';
9
- import { DataSchemaColumnsType, getGenericModelList, getGenericModelListProps } from '../api';
10
- import { DRFReactBySchemaContext, DRFReactBySchemaContextType } from '../context/DRFReactBySchemaProvider';
8
+ import { GridEnrichedBySchemaColDef, Item, SchemaType, DataSchemaColumnsType } from '../utils';
9
+ import { getGenericModelList, getGenericModelListProps } from '../api';
10
+ import { DRFReactBySchemaContext } from '../context/DRFReactBySchemaContext';
11
+ import { APIWrapperContext } from '../context/APIWrapperContext';
11
12
 
12
13
  interface GenericModelListProps {
13
14
  columnFields: string[];
@@ -20,9 +21,8 @@ interface GenericModelListProps {
20
21
  sumRows?: SumRowsType;
21
22
  isAutoHeight?: boolean;
22
23
  model: string;
23
- handleLoading: (p: any) => void;
24
24
  forceReload: boolean;
25
- LinkComponent: React.ReactNode;
25
+ LinkComponent?: React.ReactNode;
26
26
  }
27
27
 
28
28
  const GenericModelList = ({
@@ -36,24 +36,30 @@ const GenericModelList = ({
36
36
  sumRows,
37
37
  isAutoHeight = true,
38
38
  model,
39
- handleLoading,
40
39
  forceReload = false,
41
40
  LinkComponent = null
42
41
  }: GenericModelListProps) => {
43
- const { serverEndPoint, isInBatches, firstBatchLength }:DRFReactBySchemaContextType = DRFReactBySchemaContext
44
- ? React.useContext(DRFReactBySchemaContext) as DRFReactBySchemaContextType
45
- : { serverEndPoint: null };
46
- if (!serverEndPoint) {
42
+ const context = React.useContext(DRFReactBySchemaContext);
43
+ const apiContext = React.useContext(APIWrapperContext);
44
+ if (!context.serverEndPoint || !apiContext) {
47
45
  console.error('Error: There is no endpoint defined in DRFReactBySchemaProvider!');
48
46
  return (<></>);
49
47
  }
48
+ const {
49
+ serverEndPoint,
50
+ isInBatches,
51
+ firstBatchLength
52
+ } = context;
53
+ const {
54
+ handleLoading
55
+ } = apiContext;
50
56
  interface dataProps {
51
57
  data: Item[];
52
58
  schema: SchemaType;
53
59
  columns: GridEnrichedBySchemaColDef[]
54
60
  };
55
61
  const [data, setData] = useState<DataSchemaColumnsType | boolean>(false);
56
- const [visibleRows, setVisibleRows] = useState<string[]>([]);
62
+ const [visibleRows, setVisibleRows] = useState<GridRowId[]>([]);
57
63
  const [hideFooterPagination, setHideFooterPagination] = useState(false);
58
64
 
59
65
  const finalCustomColumnOperations = (column: GridEnrichedBySchemaColDef) => {
@@ -116,7 +122,7 @@ const GenericModelList = ({
116
122
 
117
123
  return (
118
124
  <>
119
- {data && typeof data !== 'boolean' && data.columns &&
125
+ {typeof data !== 'boolean' && data.columns &&
120
126
  <>
121
127
  <Box sx={Layout.dataGridWithTabs}>
122
128
  <DataGridBySchemaEditable
@@ -131,7 +137,11 @@ const GenericModelList = ({
131
137
  hideFooterPagination={hideFooterPagination}
132
138
  customColumnOperations={finalCustomColumnOperations}
133
139
  customLinkDestination={customLinkDestination}
134
- setVisibleRows={setVisibleRows}
140
+ setVisibleRows={(newVisibleRows:GridRowId[]) => {
141
+ if (JSON.stringify(newVisibleRows) !== JSON.stringify(visibleRows)) {
142
+ setVisibleRows(newVisibleRows);
143
+ }
144
+ }}
135
145
  onDataChange={newData => {
136
146
  setData({
137
147
  ...data,
@@ -0,0 +1,168 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import Box from '@mui/material/Box';
3
+ import { GridRowId } from '@mui/x-data-grid';
4
+
5
+ import DataGridBySchemaEditable from './DataGridBySchemaEditable';
6
+ import DataTotals from './DataTotals';
7
+ import { DRFReactBySchemaContext } from '../context/DRFReactBySchemaContext';
8
+ import { APIWrapperContext } from '../context/APIWrapperContext';
9
+ import { DataSchemaColumnsType, GridEnrichedBySchemaColDef, Id, Item } from '../utils';
10
+ import { getGenericModelList } from '../api';
11
+ import { SumRowsType } from './DataTotals';
12
+ import { Layout } from '../styles';
13
+
14
+ interface GenericRelatedModelListProps {
15
+ model: string;
16
+ id: Id;
17
+ relatedModel: string;
18
+ columnFields: string[];
19
+ creatableFields: string[];
20
+ hiddenFields: string[];
21
+ usuaria?: Item | null;
22
+ minWidthFields?: Record<string, number>;
23
+ indexField?: string;
24
+ addExistingModel?: string;
25
+ onProcessRow?: (p: any) => void;
26
+ sumRows?: SumRowsType;
27
+ customColumnOperations?: (column: GridEnrichedBySchemaColDef) => GridEnrichedBySchemaColDef;
28
+ isEditable?: boolean;
29
+ isAutoHeight?: boolean;
30
+ isInBatches?: boolean;
31
+ indexFieldBasePath?: string;
32
+ LinkComponent?: React.ReactNode;
33
+ };
34
+
35
+ export default function GenericRelatedModelList ({
36
+ model,
37
+ id,
38
+ relatedModel,
39
+ columnFields,
40
+ creatableFields,
41
+ hiddenFields,
42
+ usuaria,
43
+ minWidthFields,
44
+ indexField = '',
45
+ addExistingModel = '',
46
+ onProcessRow,
47
+ sumRows,
48
+ customColumnOperations,
49
+ isEditable = true,
50
+ isAutoHeight = false,
51
+ indexFieldBasePath,
52
+ LinkComponent
53
+ }:GenericRelatedModelListProps) {
54
+ const context = React.useContext(DRFReactBySchemaContext);
55
+ const apiContext = React.useContext(APIWrapperContext);
56
+ if (!context.serverEndPoint || !apiContext) {
57
+ console.error('Error: There is no endpoint defined in DRFReactBySchemaProvider!');
58
+ return (<></>);
59
+ }
60
+ const {
61
+ serverEndPoint,
62
+ isInBatches,
63
+ firstBatchLength,
64
+ } = context;
65
+ const {
66
+ onEditRelatedModelSave,
67
+ onDeleteRelatedModel
68
+ } = apiContext;
69
+
70
+ const [data, setData] = useState<DataSchemaColumnsType | boolean>(false);
71
+ const [visibleRows, setVisibleRows] = useState<GridRowId[]>([]);
72
+ const [hideFooterPagination, setHideFooterPagination] = useState(false);
73
+
74
+ const finalCustomColumnOperations = (column:GridEnrichedBySchemaColDef) => {
75
+ if (minWidthFields) {
76
+ if (Object.prototype.hasOwnProperty.call(minWidthFields, column.field)) {
77
+ column.minWidth = minWidthFields[column.field];
78
+ }
79
+ }
80
+
81
+ if (customColumnOperations) {
82
+ return customColumnOperations(column);
83
+ }
84
+
85
+ return column;
86
+ };
87
+
88
+ const loadObjectList = async () => {
89
+ const loadParams = {
90
+ model,
91
+ serverEndPoint,
92
+ id,
93
+ relatedModel,
94
+ columnFields,
95
+ hiddenFields,
96
+ creatableFields,
97
+ isInBatches
98
+ };
99
+ const loadedData = await getGenericModelList(loadParams);
100
+ if (loadedData) {
101
+ setData(loadedData);
102
+ if (isInBatches && loadedData.data.length === firstBatchLength) {
103
+ setHideFooterPagination(true);
104
+ getGenericModelList({
105
+ ...loadParams,
106
+ loadedSchema: loadedData.schema
107
+ }).then(lastBatchData => {
108
+ if (lastBatchData) {
109
+ setData({
110
+ ...loadedData,
111
+ data: [
112
+ ...loadedData.data,
113
+ ...lastBatchData.data
114
+ ]
115
+ });
116
+ }
117
+ setHideFooterPagination(false);
118
+ });
119
+ }
120
+ return;
121
+ }
122
+ console.log('error retrieving data!');
123
+ };
124
+
125
+ useEffect(() => {
126
+ loadObjectList();
127
+ }, []);
128
+
129
+ return (
130
+ <>
131
+ {typeof data !== 'boolean' && data.columns &&
132
+ <>
133
+ <Box sx={Layout.dataGridFixedHeight}>
134
+ <DataGridBySchemaEditable
135
+ data={data.data}
136
+ columns={data.columns}
137
+ schema={data.schema}
138
+ model={relatedModel}
139
+ indexField={indexField}
140
+ indexFieldBasePath={indexFieldBasePath}
141
+ addExistingModel={addExistingModel}
142
+ isEditable={isEditable}
143
+ modelParent={model}
144
+ modelParentId={id}
145
+ customColumnOperations={finalCustomColumnOperations}
146
+ setVisibleRows={setVisibleRows}
147
+ isAutoHeight={isAutoHeight}
148
+ hideFooterPagination={hideFooterPagination}
149
+ onProcessRow={onProcessRow}
150
+ onDataChange={newData => {
151
+ setData({
152
+ ...data,
153
+ data: newData
154
+ });
155
+ }}
156
+ LinkComponent={LinkComponent}
157
+ />
158
+ </Box>
159
+ <DataTotals
160
+ data={data.data}
161
+ sumRows={sumRows}
162
+ visibleRows={visibleRows}
163
+ />
164
+ </>
165
+ }
166
+ </>
167
+ );
168
+ }
@@ -0,0 +1,447 @@
1
+ import React, { useState, useReducer, useEffect, useRef } from 'react';
2
+ import {
3
+ Id,
4
+ Item,
5
+ reducer,
6
+ SchemaType,
7
+ populateValues,
8
+ buildGenericYupValidationSchema,
9
+ getTmpId,
10
+ isTmpId
11
+ } from '../utils';
12
+
13
+ import DialogJSONSchemaForm from '../components/DialogJSONSchemaForm';
14
+ import DialogActions from '../components/DialogActions';
15
+ import { DRFReactBySchemaContext, DRFReactBySchemaContextType } from './DRFReactBySchemaContext';
16
+ import {
17
+ isLoggedIn,
18
+ getAutoComplete,
19
+ getGenericModel,
20
+ updateDataBySchema,
21
+ addExistingRelatedModel,
22
+ deleteData,
23
+ getJSONSchema,
24
+ createOrUpdateJSONSchema
25
+ } from '../api';
26
+ import { AxiosResponse } from 'axios';
27
+ import {
28
+ APIWrapperContext,
29
+ DialogType,
30
+ LoadSinglePageDataProps,
31
+ OnDeleteRelatedModelType,
32
+ OnEditModelType,
33
+ OnEditRelatedModelType,
34
+ PageFormType,
35
+ SnackBarType
36
+ } from './APIWrapperContext';
37
+
38
+ interface APIWrapperProps {
39
+ setLoading: React.Dispatch<React.SetStateAction<boolean>>;
40
+ handleLoading: (p: boolean) => void;
41
+ setSnackBar: React.Dispatch<React.SetStateAction<SnackBarType>>;
42
+ setDialog: React.Dispatch<React.SetStateAction<DialogType>>;
43
+ children: React.ReactNode;
44
+ };
45
+
46
+ function APIWrapper ({
47
+ setLoading,
48
+ handleLoading,
49
+ setSnackBar,
50
+ setDialog,
51
+ children
52
+ }:APIWrapperProps) {
53
+ const { serverEndPoint } = DRFReactBySchemaContext
54
+ ? React.useContext(DRFReactBySchemaContext) as DRFReactBySchemaContextType
55
+ : { serverEndPoint: null };
56
+ if (!serverEndPoint) {
57
+ return (
58
+ <>
59
+ {children}
60
+ </>
61
+ );
62
+ }
63
+
64
+ const [usuaria, setUsuaria] = useState<Item | null>(null);
65
+ const [optionsAC, setOptionsAC] = useReducer(reducer, {});
66
+ const initialPageForm:PageFormType = {
67
+ id: '',
68
+ schema: null,
69
+ initialValues: null,
70
+ validationSchema: null
71
+ };
72
+ const [pageForm, setPageForm] = useReducer(reducer, initialPageForm);
73
+ const editModel = useRef<Item>({});
74
+ const jsonSchemaFormRef = useRef<any>(null);
75
+
76
+ useEffect(() => {
77
+ setUsuaria(null);
78
+ isLoggedIn(serverEndPoint).then(usuaria => {
79
+ setUsuaria(usuaria || { erro: 'token inválido' });
80
+ });
81
+ }, []);
82
+
83
+ useEffect(() => {
84
+ setPageForm(initialPageForm);
85
+ }, []);
86
+
87
+ const onTriggerSnackBar = ({ msg, severity = 'info' }:SnackBarType) => {
88
+ setSnackBar({
89
+ open: true,
90
+ msg,
91
+ severity
92
+ });
93
+ };
94
+
95
+ const loadSinglePageData = async ({
96
+ model,
97
+ objId,
98
+ objTitleField = 'nome',
99
+ optionsACModels,
100
+ basePath = '/',
101
+ formPath = null,
102
+ extraValidators = {}
103
+ }: LoadSinglePageDataProps) => {
104
+ setLoading(true);
105
+ if (objId === 'novo') {
106
+ objId = getTmpId();
107
+ }
108
+
109
+ const object = await getGenericModel({
110
+ model,
111
+ serverEndPoint,
112
+ id: isTmpId(objId) ? null : objId
113
+ });
114
+
115
+ if (object === false) {
116
+ setPageForm({ schema: false, id: '' });
117
+ console.log('Houve um erro ao tentar carregar os dados!');
118
+ return false;
119
+ }
120
+
121
+ setLoading(false);
122
+
123
+ populateOptionsAC(optionsACModels);
124
+
125
+ const values = populateInitialValues({
126
+ model,
127
+ id: objId,
128
+ extraValidators,
129
+ ...object
130
+ });
131
+
132
+ return values;
133
+ };
134
+
135
+ const onSubmit = async (
136
+ model:string,
137
+ id:Id,
138
+ data:Item,
139
+ e:React.SyntheticEvent<HTMLButtonElement, SubmitEvent>
140
+ ) => {
141
+ setLoading(true);
142
+ const response = await updateDataBySchema({
143
+ model,
144
+ modelObjectId: id,
145
+ serverEndPoint,
146
+ data,
147
+ schema: pageForm.schema
148
+ });
149
+ setLoading(false);
150
+ if (!['number', 'string'].includes(typeof response)) {
151
+ onTriggerSnackBar({
152
+ msg: 'Houve um problema ao salvar seus dados! Por favor, entre em contato',
153
+ severity: 'error'
154
+ });
155
+ console.log({
156
+ msg: 'Error saving model',
157
+ errors: response,
158
+ data
159
+ });
160
+ return false;
161
+ }
162
+
163
+ onTriggerSnackBar({
164
+ msg: (id)
165
+ ? 'Dados atualizados com sucesso!'
166
+ : 'Criado com sucesso!'
167
+ });
168
+
169
+ return response as Id;
170
+ };
171
+
172
+ const populateOptionsAC = (optionsACModels:string[]) => {
173
+ for (const model of optionsACModels) {
174
+ getAutoComplete({ model, serverEndPoint }).then(options => {
175
+ setOptionsAC({ [model]: options });
176
+ });
177
+ }
178
+ };
179
+
180
+ interface PopulateInitialValuesProps {
181
+ model: string;
182
+ id: Id;
183
+ data: Item;
184
+ schema: SchemaType;
185
+ extraValidators: Item;
186
+ isEditModel?: boolean;
187
+ };
188
+ const populateInitialValues = ({
189
+ model,
190
+ id,
191
+ isEditModel,
192
+ extraValidators,
193
+ ...object
194
+ }:PopulateInitialValuesProps) => {
195
+ const values = populateValues(object);
196
+ const yupSchema = buildGenericYupValidationSchema({ ...object, data: values, extraValidators });
197
+ setPageForm({
198
+ model,
199
+ id,
200
+ schema: object.schema,
201
+ initialValues: values,
202
+ validationSchema: yupSchema
203
+ });
204
+ return values;
205
+ };
206
+
207
+ const onEditModel = ({
208
+ fieldKey,
209
+ index,
210
+ model,
211
+ id,
212
+ labelKey,
213
+ setValue,
214
+ getValues
215
+ }: OnEditModelType) => {
216
+ setDialog({
217
+ open: true,
218
+ loading: true
219
+ });
220
+ getJSONSchema({ model, serverEndPoint, id }).then(data => {
221
+ const jsonSchemaSubmit = async (e:React.SyntheticEvent<HTMLElement, SubmitEvent>) => {
222
+ jsonSchemaFormRef.current.onSubmit(e);
223
+ return true;
224
+ };
225
+ setDialog({
226
+ loading: false,
227
+ title: 'Editar',
228
+ Body: <DialogJSONSchemaForm
229
+ jsonSchemaFormRef = {jsonSchemaFormRef}
230
+ schema = {data.serializer.schema}
231
+ uiSchema = {data.serializer.uiSchema}
232
+ formData = {data.formData}
233
+ onSubmit = {onEditModelSave}
234
+ />,
235
+ Actions: <DialogActions
236
+ setDialog = {setDialog}
237
+ handleSave = {jsonSchemaSubmit}
238
+ />
239
+ } as DialogType);
240
+ editModel.current = {
241
+ fieldKey,
242
+ index,
243
+ model,
244
+ id,
245
+ labelKey,
246
+ setValue,
247
+ getValues
248
+ };
249
+ });
250
+ };
251
+
252
+ const onEditModelSave = async ({ formData }:{ formData: Item }) => {
253
+ setDialog({ open: false });
254
+ setLoading(true);
255
+ const {
256
+ fieldKey,
257
+ index,
258
+ model,
259
+ id,
260
+ labelKey,
261
+ setValue,
262
+ getValues
263
+ } = editModel.current;
264
+ const newModelId = await createOrUpdateJSONSchema({
265
+ model,
266
+ serverEndPoint,
267
+ id,
268
+ formData
269
+ });
270
+ if (newModelId.errors) {
271
+ console.log(newModelId.errors);
272
+ onTriggerSnackBar({
273
+ msg: 'Houve um problema ao salvar a alteração! Por favor, entre em contato.',
274
+ severity: 'error'
275
+ });
276
+ return;
277
+ }
278
+ onTriggerSnackBar({
279
+ msg: 'Alterações salvas com sucesso!',
280
+ severity: 'info'
281
+ });
282
+ const targetKey = (fieldKey && index >= 0)
283
+ ? `${fieldKey}.${index}.${model}`
284
+ : model;
285
+ const newValue = {
286
+ ...getValues(targetKey),
287
+ ...formData,
288
+ label: formData[labelKey]
289
+ };
290
+ setValue(targetKey, newValue);
291
+ populateOptionsAC([model]);
292
+ setLoading(false);
293
+ };
294
+
295
+ const onDeleteModel = (model:string, id:Id, onSuccess:()=>void | null) => {
296
+ setDialog({
297
+ open: true,
298
+ loading: false,
299
+ title: 'Apagar',
300
+ Body: 'Tem certeza de que deseja apagar este item?',
301
+ Actions: <DialogActions
302
+ setDialog = {setDialog}
303
+ handleSave = {(e:React.SyntheticEvent) => {
304
+ return onDeleteModelSave(model, id, onSuccess);
305
+ }}
306
+ btnConfirm = "Sim, apagar"
307
+ />
308
+ });
309
+ };
310
+
311
+ const onDeleteModelSave = async (model:string, id:Id, onSuccess:()=>void | null) => {
312
+ setDialog({ open: false });
313
+ setLoading(true);
314
+ const ret = await deleteData(model, serverEndPoint, id);
315
+ if (ret !== false) {
316
+ onTriggerSnackBar({
317
+ msg: 'Apagado com com sucesso!',
318
+ severity: 'info'
319
+ });
320
+ if (onSuccess !== null) {
321
+ onSuccess();
322
+ }
323
+ return true;
324
+ }
325
+
326
+ setLoading(false);
327
+ onTriggerSnackBar({
328
+ msg: 'Houve um problema ao remover o item! Por favor, entre em contato.',
329
+ severity: 'error'
330
+ });
331
+ return false;
332
+ };
333
+
334
+ const onEditRelatedModelSave = async ({
335
+ model,
336
+ id,
337
+ relatedModel,
338
+ relatedModelId,
339
+ newRow,
340
+ schema,
341
+ onlyAddExisting
342
+ }:OnEditRelatedModelType) => {
343
+ const updateUrl = `${model}/${id}/${relatedModel}`;
344
+ if (onlyAddExisting) {
345
+ const response = await addExistingRelatedModel({
346
+ model,
347
+ id,
348
+ serverEndPoint,
349
+ data: {
350
+ onlyAddExisting: {
351
+ key: relatedModel,
352
+ value: newRow.id_to_add
353
+ }
354
+ }
355
+ });
356
+ if (Object.prototype.hasOwnProperty.call(response, 'errors')) {
357
+ console.log(response);
358
+ onTriggerSnackBar({
359
+ msg: 'Houve um problema ao salvar a alteração! Por favor, entre em contato.',
360
+ severity: 'error'
361
+ });
362
+ return false;
363
+ }
364
+ onTriggerSnackBar({
365
+ msg: 'Alterações salvas com sucesso!',
366
+ severity: 'info'
367
+ });
368
+ const object = await getGenericModel({
369
+ model,
370
+ id,
371
+ serverEndPoint,
372
+ relatedModel,
373
+ relatedModelId: newRow.id_to_add
374
+ });
375
+ return object;
376
+ }
377
+ // This is important for related data
378
+ if (schema[model] && !newRow[model]) {
379
+ newRow[model] = id;
380
+ }
381
+ const response = await updateDataBySchema({
382
+ model: relatedModel,
383
+ modelObjectId: newRow.id,
384
+ serverEndPoint,
385
+ data: newRow,
386
+ schema,
387
+ path: updateUrl
388
+ });
389
+ if (response && !Object.prototype.hasOwnProperty.call(response, 'errors')) {
390
+ onTriggerSnackBar({
391
+ msg: 'Alterações salvas com sucesso!',
392
+ severity: 'info'
393
+ });
394
+ return response as Id;
395
+ }
396
+ onTriggerSnackBar({
397
+ msg: 'Não foi possível salvar os dados. Confira os erros.',
398
+ severity: 'error'
399
+ });
400
+ return false;
401
+ };
402
+
403
+ const onDeleteRelatedModel = async ({
404
+ model,
405
+ id,
406
+ relatedModel,
407
+ relatedModelId
408
+ }:OnDeleteRelatedModelType) => {
409
+ const deleteUrl = `${model}/${id}/${relatedModel}`;
410
+ const response = await deleteData(deleteUrl, serverEndPoint, relatedModelId);
411
+ if (response) {
412
+ onTriggerSnackBar({
413
+ msg: 'Alterações salvas com sucesso!',
414
+ severity: 'info'
415
+ });
416
+ return response;
417
+ }
418
+ onTriggerSnackBar({
419
+ msg: 'Houve um problema ao remover o item! Por favor, entre em contato.',
420
+ severity: 'error'
421
+ });
422
+ return false;
423
+ };
424
+
425
+ return (
426
+ <APIWrapperContext.Provider
427
+ value = {{
428
+ usuaria,
429
+ onSubmit,
430
+ loadSinglePageData,
431
+ handleLoading,
432
+ optionsACState: [optionsAC, setOptionsAC],
433
+ pageFormState: [pageForm, setPageForm],
434
+ onEditModel,
435
+ onDeleteModel,
436
+ onEditRelatedModelSave,
437
+ onDeleteRelatedModel,
438
+ onTriggerSnackBar,
439
+ setDialog
440
+ }}
441
+ >
442
+ {children}
443
+ </APIWrapperContext.Provider>
444
+ );
445
+ }
446
+
447
+ export default React.memo(APIWrapper);