admin_lsac 2.0.24 → 2.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +321 -87
- package/dist/esm/src/components/AdminPage.js +17 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,24 +4,22 @@ For configuring your own admin panel, follow the next instructions.
|
|
|
4
4
|
|
|
5
5
|
## How to install it?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The following command will download and install the specified package and its dependencies into your project's node_modules directory, making it available for use in your project.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- `npm install admin_lsac`
|
|
10
10
|
|
|
11
11
|
## What do you need to import?
|
|
12
12
|
|
|
13
|
+
You can import these in App.js / App.ts or wherever your routes to the pages are located.
|
|
14
|
+
|
|
13
15
|
- `import { pageToUrl } from 'admin_lsac'`
|
|
14
16
|
|
|
15
17
|
- `import { AdminPage } from 'admin_lsac'`
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
If your project is TypeScript-based, you need to use the line from below as well. Import the component where you want to write your schemas. (See below for details about schemas)
|
|
18
20
|
|
|
19
21
|
- `import { PageSchema } from 'admin_lsac'`
|
|
20
22
|
|
|
21
|
-
If your project is TypeScript-based, you need to use the line above as well.
|
|
22
|
-
|
|
23
|
-
Import the component from above where you want to write your schemas! (See below for details about schemas)
|
|
24
|
-
|
|
25
23
|
## How to add routes to the admin panel's pages?
|
|
26
24
|
|
|
27
25
|
```
|
|
@@ -68,7 +66,7 @@ export interface SimpleField {
|
|
|
68
66
|
name: string;
|
|
69
67
|
label: string;
|
|
70
68
|
type: 'string' | 'number' | 'file' | 'date' | 'datetime-local' | 'time';
|
|
71
|
-
validationSchema
|
|
69
|
+
validationSchema?: any;
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
export interface Option {
|
|
@@ -104,13 +102,13 @@ export type FormField = SimpleField | DropdownField | ObjectField | ArrayField;
|
|
|
104
102
|
export interface Action {
|
|
105
103
|
name: string;
|
|
106
104
|
fields?: FormField[];
|
|
107
|
-
onSubmit: (obj1
|
|
105
|
+
onSubmit: (obj1?: any, obj2?: any, obj3?: any) => Promise<any>;
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
export interface RowAction {
|
|
111
109
|
name: string;
|
|
112
110
|
fields?: FormField[];
|
|
113
|
-
initialise?: (
|
|
111
|
+
initialise?: (rowId: any) => Promise<any>;
|
|
114
112
|
onSubmit: (obj1: any, obj2?: any, obj3?: any) => Promise<any>;
|
|
115
113
|
}
|
|
116
114
|
|
|
@@ -135,7 +133,7 @@ What do the fields of `PageSchema` refer to?
|
|
|
135
133
|
- getRequest = this is a field containg the function that will retrieve all the entries from one table in the database
|
|
136
134
|
- tableFields = these are the 'definitions' of the displayed table's columns
|
|
137
135
|
|
|
138
|
-
The operations for the rowActions and actions will generally have a form to complete before executing it. There are 4 types of inputs for the form part:
|
|
136
|
+
The operations for the rowActions and actions will generally (not mandatory) have a form to complete before executing it. There are 4 types of inputs for the form part:
|
|
139
137
|
|
|
140
138
|
- simpleField = simple data like numbers, strings, files and dates
|
|
141
139
|
- dropdownField = enable the user to choose an option from a predefined list
|
|
@@ -145,129 +143,365 @@ The operations for the rowActions and actions will generally have a form to comp
|
|
|
145
143
|
#### Schema example
|
|
146
144
|
|
|
147
145
|
```
|
|
148
|
-
import
|
|
149
|
-
import
|
|
150
|
-
|
|
146
|
+
import React from 'react';
|
|
147
|
+
import axios from 'axios';
|
|
148
|
+
import * as Yup from 'yup';
|
|
149
|
+
import { PageSchema } from '../schema';
|
|
150
|
+
|
|
151
|
+
const domain = 'http://localhost:3001';
|
|
152
|
+
|
|
153
|
+
// Please try to modularize the code for a schema though
|
|
151
154
|
|
|
152
|
-
const
|
|
153
|
-
name:
|
|
155
|
+
export const coursesPage: PageSchema = {
|
|
156
|
+
name: 'Courses',
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
// 1. Data retrieval: fetch all courses from backend
|
|
159
|
+
getRequest: async () => {
|
|
160
|
+
const res = await axios.get(`${domain}/courses`);
|
|
161
|
+
return res.data; // returns an array of course objects
|
|
158
162
|
},
|
|
159
163
|
|
|
160
|
-
|
|
164
|
+
// 2. Table fields: define columns for the courses table
|
|
165
|
+
tableFields: [
|
|
161
166
|
{
|
|
162
|
-
name:
|
|
163
|
-
//
|
|
164
|
-
access: (obj: any) => obj.id,
|
|
167
|
+
name: 'Course ID',
|
|
168
|
+
// The ID should be first column to allow rowActions to reference it (if rowActions needed)
|
|
169
|
+
access: (obj: any) => obj.id,
|
|
165
170
|
},
|
|
166
171
|
{
|
|
167
|
-
name:
|
|
172
|
+
name: 'Name',
|
|
168
173
|
access: (obj: any) => obj.name,
|
|
169
174
|
},
|
|
170
175
|
{
|
|
171
|
-
name:
|
|
172
|
-
access: (obj: any) =>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
name: 'Level',
|
|
177
|
+
access: (obj: any) => obj.level,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: 'Credits',
|
|
181
|
+
access: (obj: any) => obj.credits,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'Start Date',
|
|
185
|
+
access: (obj: any) => (obj.startDate ? new Date(obj.startDate).toLocaleDateString() : 'N/A'),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'Instructor',
|
|
189
|
+
// Display instructor name (assuming obj.instructor has { name, email })
|
|
190
|
+
access: (obj: any) => (obj.instructor ? obj.instructor.name : 'N/A'),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: 'Course Image',
|
|
194
|
+
// Use React.createElement to render an image
|
|
195
|
+
access: (obj: any) =>
|
|
196
|
+
obj.coverImage
|
|
197
|
+
? React.createElement('img', {
|
|
198
|
+
src: `${domain}${obj.coverImage}`,
|
|
199
|
+
alt: 'Cover Image',
|
|
200
|
+
style: { width: '100px' },
|
|
201
|
+
})
|
|
202
|
+
: 'No Image',
|
|
180
203
|
},
|
|
181
204
|
],
|
|
182
205
|
|
|
206
|
+
// 3. Global actions (top-level page actions)
|
|
183
207
|
actions: [
|
|
184
208
|
{
|
|
185
|
-
name:
|
|
209
|
+
name: 'Ping Server',
|
|
210
|
+
// No form, no arguments: simple request to '/ping'
|
|
211
|
+
onSubmit: async () => {
|
|
212
|
+
const res = await axios.get(`${domain}/courses/ping`);
|
|
213
|
+
return res.data;
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
{
|
|
218
|
+
name: 'Create Course',
|
|
219
|
+
// Form with one argument (formValues) on submit
|
|
186
220
|
fields: [
|
|
187
221
|
{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
222
|
+
// Course Name
|
|
223
|
+
name: 'name',
|
|
224
|
+
label: 'Course Name',
|
|
225
|
+
type: 'string',
|
|
226
|
+
validationSchema: Yup.string().required('Name is required'),
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
// Level (Undergraduate/Graduate dropdown)
|
|
230
|
+
name: 'level',
|
|
231
|
+
label: 'Level',
|
|
232
|
+
type: 'dropdown',
|
|
233
|
+
validationSchema: Yup.string().required('Level is required'),
|
|
234
|
+
getOptions: async () => [
|
|
235
|
+
{ value: 'Undergraduate', display: 'Undergraduate' },
|
|
236
|
+
{ value: 'Graduate', display: 'Graduate' },
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
// Credits
|
|
241
|
+
name: 'credits',
|
|
242
|
+
label: 'Credits',
|
|
243
|
+
type: 'number',
|
|
244
|
+
validationSchema: Yup.number().required('Credits are required'),
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
// Start Date
|
|
248
|
+
name: 'startDate',
|
|
249
|
+
label: 'Start Date',
|
|
250
|
+
type: 'date',
|
|
251
|
+
validationSchema: Yup.date().required('Start date is required'),
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
// Instructor (object with name and email)
|
|
255
|
+
name: 'instructor',
|
|
256
|
+
label: 'Instructor',
|
|
257
|
+
type: 'object',
|
|
258
|
+
fields: [
|
|
259
|
+
{
|
|
260
|
+
name: 'name',
|
|
261
|
+
label: 'Instructor Name',
|
|
262
|
+
type: 'string',
|
|
263
|
+
validationSchema: Yup.string().required('Instructor name is required'),
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'email',
|
|
267
|
+
label: 'Instructor Email',
|
|
268
|
+
type: 'string',
|
|
269
|
+
validationSchema: Yup.string()
|
|
270
|
+
.email('Invalid email')
|
|
271
|
+
.required('Instructor email is required'),
|
|
272
|
+
},
|
|
273
|
+
],
|
|
192
274
|
},
|
|
193
275
|
{
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
276
|
+
// Schedule (array of sessions with date and topic)
|
|
277
|
+
name: 'schedule',
|
|
278
|
+
label: 'Schedule',
|
|
279
|
+
type: 'array',
|
|
197
280
|
element: {
|
|
198
|
-
name:
|
|
199
|
-
label:
|
|
200
|
-
type:
|
|
281
|
+
name: '', // no specific name for array elements
|
|
282
|
+
label: '', // (fields below define each session)
|
|
283
|
+
type: 'object',
|
|
201
284
|
fields: [
|
|
202
285
|
{
|
|
203
|
-
name:
|
|
204
|
-
label:
|
|
205
|
-
type:
|
|
206
|
-
validationSchema: Yup.
|
|
286
|
+
name: 'date',
|
|
287
|
+
label: 'Date',
|
|
288
|
+
type: 'date',
|
|
289
|
+
validationSchema: Yup.date().required('Session date is required'),
|
|
207
290
|
},
|
|
208
291
|
{
|
|
209
|
-
name:
|
|
210
|
-
label:
|
|
211
|
-
type:
|
|
212
|
-
|
|
213
|
-
getOptions: async () => [
|
|
214
|
-
{
|
|
215
|
-
value: "OPEN",
|
|
216
|
-
display: "Open",
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
value: "SINGLE",
|
|
220
|
-
display: "Single",
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
value: "MULTIPLE",
|
|
224
|
-
display: "Multiple",
|
|
225
|
-
},
|
|
226
|
-
],
|
|
292
|
+
name: 'topic',
|
|
293
|
+
label: 'Topic',
|
|
294
|
+
type: 'string',
|
|
295
|
+
validationSchema: Yup.string().required('Session topic is required'),
|
|
227
296
|
},
|
|
228
297
|
],
|
|
229
298
|
},
|
|
230
299
|
},
|
|
300
|
+
{
|
|
301
|
+
// Cover Image (file upload)
|
|
302
|
+
name: 'coverImage',
|
|
303
|
+
label: 'Cover Image',
|
|
304
|
+
type: 'file',
|
|
305
|
+
validationSchema: Yup.mixed().required('Cover image is required'),
|
|
306
|
+
},
|
|
231
307
|
],
|
|
232
|
-
onSubmit: async (formValues: any) => {
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
308
|
+
onSubmit: async (formValues: any) => {
|
|
309
|
+
// Create a new course
|
|
310
|
+
const data = new FormData();
|
|
311
|
+
Object.entries(formValues).forEach(([k, v]) => {
|
|
312
|
+
if (k === 'coverImage') {
|
|
313
|
+
if (v instanceof File) data.append('coverImage', v);
|
|
314
|
+
} else if (k === 'schedule') {
|
|
315
|
+
data.append('schedule', JSON.stringify(v));
|
|
316
|
+
} else if (k === 'instructor') {
|
|
317
|
+
const instructor = v as { name: string; email: string };
|
|
318
|
+
data.append('instructor[name]', instructor.name);
|
|
319
|
+
data.append('instructor[email]', instructor.email);
|
|
320
|
+
} else {
|
|
321
|
+
data.append(k, v as any);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
await axios.post(`${domain}/courses`, data, {
|
|
326
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
327
|
+
});
|
|
328
|
+
},
|
|
238
329
|
},
|
|
239
330
|
],
|
|
240
331
|
|
|
332
|
+
// 4. Row-specific actions (actions for each course row)
|
|
241
333
|
rowActions: [
|
|
242
334
|
{
|
|
243
|
-
name:
|
|
244
|
-
|
|
245
|
-
|
|
335
|
+
name: 'Delete Course',
|
|
336
|
+
// No form; onSubmit uses one argument (rowId) to delete that course
|
|
337
|
+
onSubmit: async (courseId: number) => {
|
|
338
|
+
const res = await axios.delete(`${domain}/courses/${courseId}`);
|
|
339
|
+
return res.data;
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
{
|
|
344
|
+
name: 'Archive Course',
|
|
345
|
+
// No form; onSubmit uses two arguments (rowId and rowObject) to archive
|
|
346
|
+
onSubmit: async (courseId: number, course: any) => {
|
|
347
|
+
console.log(course); // you can do whatever you want with the course information
|
|
348
|
+
const res = await axios.patch(`${domain}/courses/${courseId}/archive`);
|
|
349
|
+
return res.data;
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
{
|
|
354
|
+
name: 'Edit Basic Info',
|
|
355
|
+
// Form (name, level, credits) with two arguments onSubmit (formValues, rowId)
|
|
356
|
+
fields: [
|
|
357
|
+
{
|
|
358
|
+
name: 'name',
|
|
359
|
+
label: 'Course Name',
|
|
360
|
+
type: 'string',
|
|
361
|
+
validationSchema: Yup.string().required('Name is required'),
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: 'level',
|
|
365
|
+
label: 'Level',
|
|
366
|
+
type: 'dropdown',
|
|
367
|
+
validationSchema: Yup.string().required('Level is required'),
|
|
368
|
+
getOptions: async () => [
|
|
369
|
+
{ value: 'Undergraduate', display: 'Undergraduate' },
|
|
370
|
+
{ value: 'Graduate', display: 'Graduate' },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: 'credits',
|
|
375
|
+
label: 'Credits',
|
|
376
|
+
type: 'number',
|
|
377
|
+
validationSchema: Yup.number().required('Credits are required'),
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
onSubmit: async (formValues: any, courseId: number) => {
|
|
381
|
+
// Update course basic info
|
|
382
|
+
const res = await axios.patch(`${domain}/courses/${courseId}`, formValues);
|
|
246
383
|
return res.data;
|
|
247
384
|
},
|
|
248
385
|
},
|
|
386
|
+
|
|
249
387
|
{
|
|
250
|
-
name:
|
|
388
|
+
name: 'Edit Full Course',
|
|
389
|
+
// Form (all course fields) with three arguments onSubmit (formValues, rowId, rowObject)
|
|
251
390
|
fields: [
|
|
252
391
|
{
|
|
253
|
-
name:
|
|
254
|
-
label:
|
|
255
|
-
type:
|
|
256
|
-
validationSchema:
|
|
392
|
+
name: 'name',
|
|
393
|
+
label: 'Course Name',
|
|
394
|
+
type: 'string',
|
|
395
|
+
validationSchema: Yup.string().required('Name is required'),
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: 'level',
|
|
399
|
+
label: 'Level',
|
|
400
|
+
type: 'dropdown',
|
|
401
|
+
validationSchema: Yup.string().required('Level is required'),
|
|
402
|
+
getOptions: async () => [
|
|
403
|
+
{ value: 'Undergraduate', display: 'Undergraduate' },
|
|
404
|
+
{ value: 'Graduate', display: 'Graduate' },
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
name: 'credits',
|
|
409
|
+
label: 'Credits',
|
|
410
|
+
type: 'number',
|
|
411
|
+
validationSchema: Yup.number().required('Credits are required'),
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: 'startDate',
|
|
415
|
+
label: 'Start Date',
|
|
416
|
+
type: 'date',
|
|
417
|
+
validationSchema: Yup.date().required('Start date is required'),
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'instructor',
|
|
421
|
+
label: 'Instructor',
|
|
422
|
+
type: 'object',
|
|
423
|
+
fields: [
|
|
424
|
+
{
|
|
425
|
+
name: 'name',
|
|
426
|
+
label: 'Instructor Name',
|
|
427
|
+
type: 'string',
|
|
428
|
+
validationSchema: Yup.string().required('Instructor name is required'),
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
name: 'email',
|
|
432
|
+
label: 'Instructor Email',
|
|
433
|
+
type: 'string',
|
|
434
|
+
validationSchema: Yup.string()
|
|
435
|
+
.email('Invalid email')
|
|
436
|
+
.required('Instructor email is required'),
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: 'schedule',
|
|
442
|
+
label: 'Schedule',
|
|
443
|
+
type: 'array',
|
|
444
|
+
element: {
|
|
445
|
+
name: '',
|
|
446
|
+
label: '',
|
|
447
|
+
type: 'object',
|
|
448
|
+
fields: [
|
|
449
|
+
{
|
|
450
|
+
name: 'date',
|
|
451
|
+
label: 'Date',
|
|
452
|
+
type: 'date',
|
|
453
|
+
validationSchema: Yup.date().required('Session date is required'),
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
name: 'topic',
|
|
457
|
+
label: 'Topic',
|
|
458
|
+
type: 'string',
|
|
459
|
+
validationSchema: Yup.string().required('Session topic is required'),
|
|
460
|
+
},
|
|
461
|
+
],
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: 'coverImage',
|
|
466
|
+
label: 'Cover Image',
|
|
467
|
+
type: 'file',
|
|
468
|
+
validationSchema: Yup.mixed().required('Cover image is required'),
|
|
257
469
|
},
|
|
258
470
|
],
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
return
|
|
471
|
+
// Use initialise to fetch current course data and pre-fill the form
|
|
472
|
+
initialise: async (courseId: any) => {
|
|
473
|
+
const res = await axios.get(`${domain}/courses/${courseId}`);
|
|
474
|
+
return res.data; // return course object to populate the form
|
|
475
|
+
},
|
|
476
|
+
onSubmit: async (formValues: any, courseId: number, course: any) => {
|
|
477
|
+
// Update full course details
|
|
478
|
+
// Please note that you can include "initialise" and not the "rowObject" (or vice versa)
|
|
479
|
+
console.log(course); // you can do whatever you want with the course information
|
|
480
|
+
const data = new FormData();
|
|
481
|
+
|
|
482
|
+
data.append('name', formValues.name);
|
|
483
|
+
data.append('level', formValues.level);
|
|
484
|
+
data.append('credits', formValues.credits);
|
|
485
|
+
data.append('startDate', formValues.startDate);
|
|
486
|
+
|
|
487
|
+
data.append('instructor[name]', formValues.instructor.name);
|
|
488
|
+
data.append('instructor[email]', formValues.instructor.email);
|
|
489
|
+
|
|
490
|
+
data.append('schedule', JSON.stringify(formValues.schedule));
|
|
491
|
+
|
|
492
|
+
if (formValues.coverImage) {
|
|
493
|
+
data.append('coverImage', formValues.coverImage);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
await axios.patch(`${domain}/courses/${courseId}`, data, {
|
|
497
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
498
|
+
});
|
|
263
499
|
},
|
|
264
500
|
},
|
|
265
501
|
],
|
|
266
|
-
}
|
|
502
|
+
};
|
|
267
503
|
```
|
|
268
504
|
|
|
269
|
-
Please note that the schema above is not related to any entity, and the fields of PageSchema do not necessarily have any relation between them. These are just random examples to teach you how to create your own schema.
|
|
270
|
-
|
|
271
505
|
#### An array of schemas must be defined as below:
|
|
272
506
|
|
|
273
507
|
```
|
|
@@ -8,8 +8,8 @@ import { MaterialReactTable } from 'material-react-table';
|
|
|
8
8
|
import { mkConfig, generateCsv, download } from 'export-to-csv';
|
|
9
9
|
import Swal from 'sweetalert2';
|
|
10
10
|
import MenuItem from '@mui/material/MenuItem';
|
|
11
|
-
import { io } from 'socket.io-client';
|
|
12
|
-
import { newSocket } from '../utils/websockets';
|
|
11
|
+
// import { io } from 'socket.io-client';
|
|
12
|
+
// import { newSocket } from '../utils/websockets';
|
|
13
13
|
export function pageToUrl(page) {
|
|
14
14
|
return `${page.name.toLowerCase().replace(' ', '_')}`;
|
|
15
15
|
}
|
|
@@ -59,24 +59,27 @@ export function AdminPage({ pages, selectedPage, basePath, apiURL = '', }) {
|
|
|
59
59
|
const [rowId, setRowId] = useState();
|
|
60
60
|
const [rowObject, setRowObject] = useState([]);
|
|
61
61
|
const [refetch, setRefetch] = useState(false);
|
|
62
|
-
const [socket, setSocket] = useState(io);
|
|
63
|
-
newSocket(setSocket, apiURL);
|
|
62
|
+
// const [socket, setSocket] = useState(io);
|
|
63
|
+
// newSocket(setSocket, apiURL);
|
|
64
|
+
console.log(apiURL);
|
|
64
65
|
useEffect(() => {
|
|
65
66
|
selectedPage.getRequest().then((resArray) => {
|
|
66
67
|
setData(resArray);
|
|
67
68
|
setRefetch(false);
|
|
68
69
|
});
|
|
69
70
|
}, [refetch]); // Do not remove 'refetch' from here !!!
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
71
|
+
// useEffect(() => {
|
|
72
|
+
// socket.on('updateData', (message) => {
|
|
73
|
+
// console.log('Message emitted from socket: ' + message);
|
|
74
|
+
// setRefetch(true);
|
|
75
|
+
// const rowActionsMenu = document.querySelector(
|
|
76
|
+
// '.MuiPaper-root.MuiPopover-paper.MuiMenu-paper',
|
|
77
|
+
// );
|
|
78
|
+
// if (rowActionsMenu) {
|
|
79
|
+
// rowActionsMenu.remove();
|
|
80
|
+
// }
|
|
81
|
+
// });
|
|
82
|
+
// }, [socket, selectedPage]);
|
|
80
83
|
useEffect(() => {
|
|
81
84
|
setDisplayData(data.map((row) => selectedPage.tableFields.map((field) => field.access(row))));
|
|
82
85
|
}, [data]);
|