dce-reactkit 3.3.6 → 3.4.0-beta.1

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.
Files changed (33) hide show
  1. package/dist/cjs/index.js +37520 -379
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +10 -0
  4. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +33 -0
  5. package/dist/cjs/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +8 -0
  6. package/dist/cjs/types/components/DBEntryManagerPanel/index.d.ts +25 -0
  7. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +8 -0
  8. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +49 -0
  9. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryFieldType.d.ts +12 -0
  10. package/dist/cjs/types/helpers/addDBEditorEndpoints.d.ts +40 -0
  11. package/dist/cjs/types/index.d.ts +6 -1
  12. package/dist/esm/index.js +37694 -574
  13. package/dist/esm/index.js.map +1 -1
  14. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +10 -0
  15. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +33 -0
  16. package/dist/esm/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +8 -0
  17. package/dist/esm/types/components/DBEntryManagerPanel/index.d.ts +25 -0
  18. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +8 -0
  19. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +49 -0
  20. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryFieldType.d.ts +12 -0
  21. package/dist/esm/types/helpers/addDBEditorEndpoints.d.ts +40 -0
  22. package/dist/esm/types/index.d.ts +6 -1
  23. package/dist/index.d.ts +166 -35
  24. package/package.json +8 -3
  25. package/src/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.tsx +290 -0
  26. package/src/components/DBEntryManagerPanel/AddOrEditDBEntry/index.tsx +699 -0
  27. package/src/components/DBEntryManagerPanel/helpers/generateEndpointPath.ts +15 -0
  28. package/src/components/DBEntryManagerPanel/index.tsx +511 -0
  29. package/src/components/DBEntryManagerPanel/types/DBEntry.ts +7 -0
  30. package/src/components/DBEntryManagerPanel/types/DBEntryField.ts +94 -0
  31. package/src/components/DBEntryManagerPanel/types/DBEntryFieldType.ts +18 -0
  32. package/src/helpers/addDBEditorEndpoints.ts +121 -0
  33. package/src/index.ts +11 -1
@@ -0,0 +1,699 @@
1
+ /**
2
+ * Panel for adding a DBEntry to the database
3
+ * @author Yuen Ler Chow
4
+ */
5
+
6
+ // Import React
7
+ import React, { useReducer } from 'react';
8
+
9
+ // Import FontAwesome
10
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
11
+ import { faSave } from '@fortawesome/free-solid-svg-icons';
12
+
13
+ // Import dce-reactkit
14
+ import {
15
+ CheckboxButton,
16
+ LoadingSpinner,
17
+ RadioButton,
18
+ ButtonInputGroup,
19
+ alert,
20
+ showFatalError,
21
+ visitServerEndpoint,
22
+ } from 'dce-reactkit';
23
+
24
+ // Import other types
25
+ import DBEntry from '../types/DBEntry';
26
+ import DBEntryField from '../types/DBEntryField';
27
+ import DBEntryFieldType from '../types/DBEntryFieldType';
28
+
29
+ // Import other components
30
+ import CreatableMultiselect from './CreatableMultiselect';
31
+
32
+ /*------------------------------------------------------------------------*/
33
+ /* -------------------------------- Types ------------------------------- */
34
+ /*------------------------------------------------------------------------*/
35
+
36
+ // Props definition
37
+ type Props = {
38
+ /**
39
+ * Handler for when the user finishes adding the DBEntry
40
+ * (if no DBEntry is returned, process was cancelled)
41
+ * @param DBEntry the DBEntry that was just created
42
+ */
43
+ onFinished: (dbEntry?: DBEntry) => void,
44
+ /**
45
+ * Function to validate the DBEntry before saving
46
+ * @param dbEntry
47
+ */
48
+ validateEntry?: (dbEntry: DBEntry) => Promise<void>,
49
+ /**
50
+ * Function to modify the DBEntry before saving
51
+ * @param dbEntry
52
+ * @returns the modified DBEntry
53
+ */
54
+ modifyEntry?: (dbEntry: DBEntry) => DBEntry,
55
+ // The fields needed to create a new DBEntry
56
+ entryFields: DBEntryField[],
57
+ // The DBEntry to edit (if any)
58
+ dbEntryToEdit?: DBEntry,
59
+ // The unique object key of the DBEntry
60
+ idPropName: string,
61
+ // Server endpoint path to save the DBEntry
62
+ saveEndpointPath: string,
63
+ // All entries in the database
64
+ entries: DBEntry[],
65
+ };
66
+
67
+ /*------------------------------------------------------------------------*/
68
+ /* -------------------------------- Style ------------------------------- */
69
+ /*------------------------------------------------------------------------*/
70
+
71
+ const style = `
72
+ .AddOrEditDBEntry-input-label {
73
+ min-width: 7rem;
74
+ }
75
+ `;
76
+
77
+ /*------------------------------------------------------------------------*/
78
+ /* -------------------------------- State ------------------------------- */
79
+ /*------------------------------------------------------------------------*/
80
+
81
+ /* -------- State Definition -------- */
82
+
83
+ type State = {
84
+ // The DBEntry's current state
85
+ entry: DBEntry,
86
+ // True if currently saving
87
+ saving: boolean,
88
+ };
89
+
90
+ /* ------------- Actions ------------ */
91
+
92
+ // Types of actions
93
+ enum ActionType {
94
+ // Update the DBEntry
95
+ UpdateDBEntry = 'UpdateDBEntry',
96
+ // Start the save spinner
97
+ StartSave = 'StartSave',
98
+ }
99
+
100
+ // Action definitions
101
+ type Action = (
102
+ | {
103
+ // Action type
104
+ type: ActionType.UpdateDBEntry,
105
+ // New state of the DBEntry
106
+ dbEntry: DBEntry,
107
+ }
108
+ | {
109
+ // Action type
110
+ type: (
111
+ | ActionType.StartSave
112
+ ),
113
+ }
114
+ );
115
+
116
+ /**
117
+ * Reducer that executes actions
118
+ * @author Yuen Ler Chow
119
+ * @param state current state
120
+ * @param action action to execute
121
+ */
122
+ const reducer = (state: State, action: Action): State => {
123
+ switch (action.type) {
124
+ case ActionType.UpdateDBEntry: {
125
+ return {
126
+ ...state,
127
+ entry: action.dbEntry,
128
+ };
129
+ }
130
+ case ActionType.StartSave: {
131
+ return {
132
+ ...state,
133
+ saving: true,
134
+ };
135
+ }
136
+ default: {
137
+ return state;
138
+ }
139
+ }
140
+ };
141
+
142
+ /*------------------------------------------------------------------------*/
143
+ /* ------------------------------ Component ----------------------------- */
144
+ /*------------------------------------------------------------------------*/
145
+
146
+ const AddOrEditDBEntry: React.FC<Props> = (props) => {
147
+ /*------------------------------------------------------------------------*/
148
+ /* -------------------------------- Setup ------------------------------- */
149
+ /*------------------------------------------------------------------------*/
150
+
151
+ /* -------------- Props ------------- */
152
+
153
+ // Destructure all props
154
+ const {
155
+ onFinished,
156
+ entryFields,
157
+ dbEntryToEdit,
158
+ validateEntry,
159
+ modifyEntry,
160
+ idPropName,
161
+ saveEndpointPath,
162
+ entries,
163
+ } = props;
164
+
165
+ /* -------------- State ------------- */
166
+
167
+ // Initial state
168
+ const initialState: State = {
169
+ entry: dbEntryToEdit || {},
170
+ saving: false,
171
+ };
172
+
173
+ // Initialize state
174
+ const [state, dispatch] = useReducer(reducer, initialState);
175
+
176
+ // Destructure common state
177
+ const {
178
+ entry,
179
+ saving,
180
+ } = state;
181
+
182
+ /*------------------------------------------------------------------------*/
183
+ /* ------------------------- Component Functions ------------------------ */
184
+ /*------------------------------------------------------------------------*/
185
+
186
+ /**
187
+ * Save changes to the DBEntry and then finish
188
+ * @author Yuen Ler Chow
189
+ */
190
+ const save = async () => {
191
+ // Start the save loading indicator
192
+ dispatch({ type: ActionType.StartSave });
193
+
194
+ // add all default values to the entry
195
+ entryFields.forEach((field) => {
196
+ if (field.defaultValue && !entry[field.objectKey]) {
197
+ entry[field.objectKey] = field.defaultValue;
198
+ }
199
+ });
200
+
201
+ const modifiedEntry = modifyEntry ? modifyEntry(entry) : entry;
202
+
203
+ // Send to server
204
+ try {
205
+ await visitServerEndpoint({
206
+ path: saveEndpointPath,
207
+ method: 'POST',
208
+ params: {
209
+ item: JSON.stringify(modifiedEntry),
210
+ },
211
+ });
212
+
213
+ // Finish
214
+ onFinished(entry);
215
+ } catch (err) {
216
+ return showFatalError(err);
217
+ }
218
+ };
219
+
220
+ /**
221
+ * Cancel and return without saving
222
+ * @author Gabe Abrams
223
+ */
224
+ const cancel = () => {
225
+ onFinished(undefined);
226
+ };
227
+
228
+ /*------------------------------------------------------------------------*/
229
+ /* ------------------------------- Render ------------------------------- */
230
+ /*------------------------------------------------------------------------*/
231
+
232
+ /*----------------------------------------*/
233
+ /* ---------------- Views --------------- */
234
+ /*----------------------------------------*/
235
+
236
+ // Body
237
+ let body: React.ReactNode;
238
+
239
+ /* ------------- Loading ------------ */
240
+
241
+ if (saving) {
242
+ body = (
243
+ <LoadingSpinner />
244
+ );
245
+ }
246
+
247
+ /* -------------- Form -------------- */
248
+
249
+ // If not saving, validate what the user has entered
250
+ if (!saving) {
251
+ // Validation error if there is one
252
+ let validationError: string | undefined = undefined;
253
+
254
+ // Validate each field
255
+ for (let i = 0; i < entryFields.length; i += 1) {
256
+ const field = entryFields[i];
257
+ const value = entry[field.objectKey];
258
+
259
+ // Check if required field is empty
260
+ if (field.required && !value) {
261
+ validationError = `Please fill in the ${field.label} field`;
262
+ break;
263
+ }
264
+
265
+ // Check if unique field is unique
266
+ if (field.objectKey === idPropName) {
267
+ if (entries.find((e) => { return e[idPropName] === value; })) {
268
+ validationError = `An item with the ${field.label} ${value} already exists. ${field.label} must be unique.`;
269
+ break;
270
+ }
271
+ }
272
+
273
+ // If they have entered a value for the field, check if it is valid
274
+ if (value) {
275
+ // String validation
276
+ if (field.type === DBEntryFieldType.String) {
277
+ if (
278
+ // Minimum length requirement is defined
279
+ field.minNumChars
280
+ // Value is too short
281
+ && value.length < field.minNumChars
282
+ ) {
283
+ validationError = `${field.label} must be at least ${field.minNumChars} character${field.minNumChars === 1 ? '' : 's'} long`;
284
+ } else if (
285
+ // Maximum length requirement is defined
286
+ field.maxNumChars
287
+ // Value is too long
288
+ && value.length > field.maxNumChars
289
+ ) {
290
+ validationError = `${field.label} must be at most ${field.maxNumChars} character${field.maxNumChars === 1 ? '' : 's'} long`;
291
+ }
292
+ // Number validation
293
+ } else if (field.type === DBEntryFieldType.Number) {
294
+ if (
295
+ // Minimum value requirement is defined
296
+ field.minNumber
297
+ // Value is too small
298
+ && value < field.minNumber
299
+ ) {
300
+ validationError = `${field.label} must be at least ${field.minNumber}`;
301
+ } else if (
302
+ // Maximum value requirement is defined
303
+ field.maxNumber
304
+ // Value is too large
305
+ && value > field.maxNumber
306
+ ) {
307
+ validationError = `${field.label} must be at most ${field.maxNumber}`;
308
+ }
309
+ } else if (
310
+ field.type === DBEntryFieldType.StringArray
311
+ || field.type === DBEntryFieldType.NumberArray
312
+ ) {
313
+ // String and Number Array validation
314
+ if (
315
+ // Minimum number of elements requirement is defined
316
+ field.minNumElements
317
+ // Value has too few elements
318
+ && value.length < field.minNumElements
319
+ ) {
320
+ validationError = `${field.label} must have at least ${field.minNumElements} value${field.minNumElements === 1 ? '' : 's'}`;
321
+ } else if (
322
+ // Maximum number of elements requirement is defined
323
+ field.maxNumElements
324
+ // Value has too many elements
325
+ && value.length > field.maxNumElements
326
+ ) {
327
+ validationError = `${field.label} must have at most ${field.maxNumElements} value${field.maxNumElements === 1 ? '' : 's'}`;
328
+ } else if (field.type === DBEntryFieldType.NumberArray) {
329
+ // Number Array validation
330
+ for (let j = 0; j < value.length; j += 1) {
331
+ if (
332
+ // Minimum value requirement is defined
333
+ field.minNumber
334
+ // Value is too small
335
+ && value[j] < field.minNumber
336
+ ) {
337
+ validationError = `${field.label} values must be at least ${field.minNumber}`;
338
+ break;
339
+ } else if (
340
+ // Maximum value requirement is defined
341
+ field.maxNumber
342
+ // Value is too large
343
+ && value[j] > field.maxNumber
344
+ ) {
345
+ validationError = `${field.label} values must be at most ${field.maxNumber}`;
346
+ break;
347
+ }
348
+ }
349
+ }
350
+ }
351
+ }
352
+ if (validationError) {
353
+ break;
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Render a single entry field
359
+ * @author Yuen Ler Chow
360
+ * @param field the entry field to render
361
+ * @param disabled true if the field should be disabled
362
+ */
363
+ const renderEntryField = (field: DBEntryField, disabled: boolean) => {
364
+ if (field.type === DBEntryFieldType.String) {
365
+ if (field.choices) {
366
+ return (
367
+ <div
368
+ key={field.objectKey}
369
+ className="mb-2"
370
+ >
371
+ <div className="input-group"
372
+ style={{
373
+ pointerEvents: (disabled ? 'none' : 'auto'),
374
+ }}
375
+ >
376
+ <ButtonInputGroup
377
+ label={field.label}
378
+ >
379
+ {
380
+ field.choices.map((choice) => {
381
+ return (
382
+ <RadioButton
383
+ key={choice.value}
384
+ text={choice.title}
385
+ selected={entry[field.objectKey] === choice.value}
386
+ onSelected={() => {
387
+ entry[field.objectKey] = choice.value;
388
+ dispatch({
389
+ type: ActionType.UpdateDBEntry,
390
+ dbEntry: entry,
391
+ });
392
+ }}
393
+ ariaLabel={choice.title}
394
+ />
395
+ );
396
+ })
397
+ }
398
+ </ButtonInputGroup>
399
+ </div>
400
+ </div>
401
+ );
402
+ }
403
+
404
+ return (
405
+ <div
406
+ className="mb-2"
407
+ key={field.objectKey}
408
+ >
409
+ <div className="input-group">
410
+ <span
411
+ className="AddOrEditDBEntry-input-label input-group-text"
412
+ >
413
+ {field.label}
414
+ </span>
415
+ <input
416
+ disabled={disabled}
417
+ type="text"
418
+ className="form-control"
419
+ placeholder={field.placeholder}
420
+ aria-describedby="AddOrEditDBEntry-form-name-label"
421
+ value={entry[field.objectKey] || ''}
422
+ onChange={(e) => {
423
+ entry[field.objectKey] = (
424
+ e.target.value
425
+ );
426
+ dispatch({
427
+ type: ActionType.UpdateDBEntry,
428
+ dbEntry: entry,
429
+ });
430
+ }}
431
+ />
432
+ </div>
433
+ </div>
434
+ );
435
+ }
436
+
437
+ if (field.type === DBEntryFieldType.Number) {
438
+ return (
439
+ <div
440
+ key={field.objectKey}
441
+ className="mb-2"
442
+ >
443
+ <div className="input-group">
444
+ <span
445
+ className="AddOrEditDBEntry-input-label input-group-text"
446
+ >
447
+ {field.label}
448
+ </span>
449
+ <input
450
+ type="text"
451
+ className="form-control"
452
+ placeholder={field.placeholder}
453
+ aria-describedby="AddOrEditDBEntry-form-name-label"
454
+ value={entry[field.objectKey] || ''}
455
+ disabled={disabled}
456
+ onChange={(e) => {
457
+ entry[field.objectKey] = (
458
+ e.target.value
459
+ .replace(/[^0-9]/g, '')
460
+ );
461
+ dispatch({
462
+ type: ActionType.UpdateDBEntry,
463
+ dbEntry: entry,
464
+ });
465
+ }}
466
+ />
467
+ </div>
468
+ </div>
469
+ );
470
+ }
471
+
472
+ if (field.type === DBEntryFieldType.StringArray) {
473
+ if (field.choices) {
474
+ return (
475
+ <div
476
+ key={field.objectKey}
477
+ className="mb-2"
478
+ >
479
+ <div className="input-group"
480
+ style={{
481
+ pointerEvents: (disabled ? 'none' : 'auto'),
482
+ }}
483
+ >
484
+ <ButtonInputGroup
485
+ label={field.label}
486
+ >
487
+ {
488
+ field.choices.map((choice) => {
489
+ return (
490
+ <CheckboxButton
491
+ key={choice.value}
492
+ text={choice.title}
493
+ checked={entry[field.objectKey] && entry[field.objectKey].includes(choice.value)}
494
+ onChanged={(checked) => {
495
+ if (checked) {
496
+ // Initialize array if it doesn't exist
497
+ if (!entry[field.objectKey]) {
498
+ entry[field.objectKey] = [];
499
+ }
500
+
501
+ // Add value to array
502
+ entry[field.objectKey].push(choice.value);
503
+ } else {
504
+ // Remove value from array
505
+ entry[field.objectKey] = (
506
+ entry[field.objectKey]
507
+ .filter((val: string) => {
508
+ return val !== choice.value;
509
+ })
510
+ );
511
+ }
512
+
513
+ // Save
514
+ dispatch({
515
+ type: ActionType.UpdateDBEntry,
516
+ dbEntry: entry,
517
+ });
518
+ }}
519
+ ariaLabel={choice.title}
520
+ />
521
+ );
522
+ })
523
+ }
524
+ </ButtonInputGroup>
525
+ </div>
526
+ </div>
527
+ );
528
+ }
529
+
530
+ // Flexible (no specific choices for this field)
531
+ return (
532
+ <div
533
+ key={field.objectKey}
534
+ className="mb-2"
535
+ >
536
+ <div className="input-group">
537
+ <span
538
+ className="AddOrEditDBEntry-input-label input-group-text"
539
+ >
540
+ {field.label}
541
+ </span>
542
+ <div className="flex-grow-1">
543
+ <CreatableMultiselect
544
+ disabled={disabled}
545
+ type={DBEntryFieldType.StringArray}
546
+ values={entry[field.objectKey] || []}
547
+ onChange={(values) => {
548
+ // Update entry and save
549
+ entry[field.objectKey] = values;
550
+ dispatch({
551
+ type: ActionType.UpdateDBEntry,
552
+ dbEntry: entry,
553
+ });
554
+ }}
555
+ />
556
+ </div>
557
+ </div>
558
+ </div>
559
+ );
560
+ }
561
+
562
+ if (field.type === DBEntryFieldType.NumberArray) {
563
+ return (
564
+ <div
565
+ key={field.objectKey}
566
+ className="mb-2"
567
+ >
568
+ <div className="input-group">
569
+ <span
570
+ className="AddOrEditDBEntry-input-label input-group-text"
571
+ >
572
+ {field.label}
573
+ </span>
574
+ <div className="flex-grow-1">
575
+ <CreatableMultiselect
576
+ disabled={disabled}
577
+ type={DBEntryFieldType.NumberArray}
578
+ values={entry[field.objectKey] || []}
579
+ onChange={(values) => {
580
+ entry[field.objectKey] = values;
581
+ dispatch({
582
+ type: ActionType.UpdateDBEntry,
583
+ dbEntry: entry,
584
+ });
585
+ }}
586
+ />
587
+ </div>
588
+ </div>
589
+ </div>
590
+ );
591
+ }
592
+
593
+ if (field.type == DBEntryFieldType.Object) {
594
+ return (
595
+ <div
596
+ key={field.objectKey}
597
+ className="mb-2"
598
+ >
599
+ <div className="input-group">
600
+ {/* Label */}
601
+ <span
602
+ className="AddOrEditDBEntry-input-label input-group-text"
603
+ >
604
+ {field.label}
605
+ </span>
606
+ {/* Add each subfield */}
607
+ {
608
+ field.subfields.map((subfield: DBEntryField) => {
609
+ return renderEntryField(subfield, disabled);
610
+ })
611
+ }
612
+ </div>
613
+ </div>
614
+ );
615
+ }
616
+
617
+ // This should never happen
618
+ return null;
619
+ }
620
+
621
+ // UI
622
+ body = (
623
+ <div>
624
+ {/* Entry fields */}
625
+ {
626
+ entryFields.map((field: DBEntryField) => {
627
+ const disabled = (idPropName === field.objectKey && dbEntryToEdit !== undefined)
628
+ || (field.lockAfterCreation !== undefined && dbEntryToEdit !== undefined);
629
+ return renderEntryField(field, disabled);
630
+ })
631
+ }
632
+
633
+ {/* Buttons */}
634
+ <div className="text-center mt-2">
635
+ <button
636
+ type="button"
637
+ id="AddOrEditDBEntry-save-changes-button"
638
+ className="btn btn-primary btn-lg me-1"
639
+ aria-label="Save changes"
640
+ onClick={async () => {
641
+ if (validationError) {
642
+ return alert(
643
+ 'Please fix the following error',
644
+ validationError,
645
+ );
646
+ }
647
+ if (validateEntry) {
648
+ try {
649
+ validateEntry(entry);
650
+ } catch (error) {
651
+ return alert(
652
+ 'Please fix the following error',
653
+ String(error),
654
+ );
655
+ }
656
+ }
657
+ save();
658
+ }}
659
+ >
660
+ <FontAwesomeIcon
661
+ icon={faSave}
662
+ className="me-1"
663
+ />
664
+ Save
665
+ </button>
666
+ <button
667
+ type="button"
668
+ id="AddOrEditDBEntry-cancel-button"
669
+ className="btn btn-secondary btn-lg me-1"
670
+ aria-label="save changes"
671
+ onClick={cancel}
672
+ >
673
+ Cancel
674
+ </button>
675
+ </div>
676
+ </div >
677
+ );
678
+ }
679
+
680
+ /*----------------------------------------*/
681
+ /* --------------- Main UI -------------- */
682
+ /*----------------------------------------*/
683
+
684
+ return (
685
+ <div className="alert alert-light text-black">
686
+ <style>
687
+ {style}
688
+ </style>
689
+ {body}
690
+ </div>
691
+ );
692
+ };
693
+
694
+ /*------------------------------------------------------------------------*/
695
+ /* ------------------------------- Wrap Up ------------------------------ */
696
+ /*------------------------------------------------------------------------*/
697
+
698
+ // Export component
699
+ export default AddOrEditDBEntry;
@@ -0,0 +1,15 @@
1
+
2
+ /**
3
+ * Generates the endpoint path for the given collection name
4
+ * @author Yuen Ler Chow
5
+ * @param collectionName the name of the collection
6
+ * @param [adminsOnly] true if the endpoint is for admins only
7
+ */
8
+ const generateEndpointPath = (collectionName: string, adminsOnly?: boolean) => {
9
+ // Determine prefix based on whether the endpoint is for admins only
10
+ const userPath = adminsOnly ? 'admin' : 'ttm';
11
+
12
+ // Return the endpoint path
13
+ return `/api/${userPath}/dce-reactkit/dbeditor/${collectionName}`;
14
+ };
15
+ export default generateEndpointPath;