admin_lsac 1.5.0 → 2.0.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.
package/.eslintrc.cjs CHANGED
@@ -6,7 +6,7 @@ module.exports = {
6
6
  'plugin:@typescript-eslint/recommended',
7
7
  'plugin:react-hooks/recommended',
8
8
  ],
9
- ignorePatterns: ['dist', '.eslintrc.cjs', 'src/testSchemas', 'admin_lsac.d.ts'],
9
+ ignorePatterns: ['dist', '.eslintrc.cjs', 'server'],
10
10
  parser: '@typescript-eslint/parser',
11
11
  plugins: ['react-refresh'],
12
12
  rules: {
@@ -14,5 +14,7 @@ module.exports = {
14
14
  'warn',
15
15
  { allowConstantExport: true },
16
16
  ],
17
+ '@typescript-eslint/no-explicit-any': 'off',
18
+ '@typescript-eslint/no-unused-vars': 'off',
17
19
  },
18
20
  }
package/README.md CHANGED
@@ -4,25 +4,25 @@ For configuring your own admin panel, follow the next instructions.
4
4
 
5
5
  ## How to install it?
6
6
 
7
- ### `npm install admin_lsac`
7
+ - `npm install admin_lsac`
8
8
 
9
9
  This 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.
10
10
 
11
11
  ## What do you need to import?
12
12
 
13
- ### `import { ChakraProvider } from '@chakra-ui/react'`
13
+ - `import { ChakraProvider } from '@chakra-ui/react'`
14
14
 
15
- ### `import { pageToUrl } from 'admin_lsac'`
15
+ - `import { pageToUrl } from 'admin_lsac'`
16
16
 
17
- ### `import { AdminPage } from 'admin_lsac'`
17
+ - `import { AdminPage } from 'admin_lsac'`
18
18
 
19
19
  You can import these in App.js / App.ts or wherever your routes to the pages are located.
20
20
 
21
- ### `import { PageSchema } from 'admin_lsac'`
21
+ - `import { PageSchema } from 'admin_lsac'`
22
22
 
23
23
  If your project is TypeScript-based, you need to use the line above as well.
24
24
 
25
- - Import the component from above where you want to write your schemas. (See below for details about schemas)
25
+ Import the component from above where you want to write your schemas! (See below for details about schemas)
26
26
 
27
27
  ## How to add routes to the admin panel's pages?
28
28
 
@@ -125,6 +125,162 @@ export interface RowAction {
125
125
 
126
126
  A page schema is based on these interfaces, and it describes how one table of your admin panel would need to be structured to accomplish what the user needs to do regarding an entity. (i.e. users, teams, companies, quizzes)
127
127
 
128
+ The most important interface is `PageSchema`, as it is at the top of the relations between all these interfaces.
129
+
130
+ What do the fields of `PageSchema` refer to?
131
+
132
+ - name = name of the table
133
+ - actions = these are operations that can affect all entries in the table (like updating all or some of the entries in the table) or operations that envolve creating new entries (one by one)
134
+ - rowActions = these are operations that can affect just one entry/row (like updating or deleting an entry)
135
+ - getRequest = this is a field containg the function that will retrieve all the entries from one table in the database
136
+ - tableFields = these are the 'definitions' of the displayed table's columns
137
+
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:
139
+
140
+ - simpleField = simple data like numbers, strings or files
141
+ - dropdownField = enable the user to choose an option from a predefined list
142
+ - arrayField = arrays of data
143
+ - objectField = an object containing more fields/inputs, or even other objects (some cool recursion)
144
+
145
+ #### Schema example
146
+
147
+ ```
148
+ const domain = "http://localhost:3001"; // dev mode
149
+
150
+ // helper function
151
+ const getAuth = () => {
152
+ // return a token or whatever :)
153
+ };
154
+
155
+ const companies: PageSchema = {
156
+ name: "Companies",
157
+
158
+ getRequest: async () => { // retrieve all entries from the database
159
+ const res = await axios.get(domain + "/something", {
160
+ headers: getAuth(),
161
+ });
162
+ return res.data;
163
+ },
164
+
165
+ tableFields: [ // the columns displayed on the page
166
+ {
167
+ name: "Company ID", // the ID must be displayed (and as first column),
168
+ // if you would like to use rowActions ⚠️
169
+ access: (obj: any) => obj.id, // obj.field_name
170
+ },
171
+ {
172
+ name: "Name",
173
+ access: (obj: any) => obj.name,
174
+ },
175
+ {
176
+ name: "Logo",
177
+ access: (obj: any) => // you can have even more complex functions
178
+ obj.logoUrl
179
+ ? React.createElement("img", {
180
+ src: obj.logoUrl,
181
+ alt: "ERROR",
182
+ style: { width: "100px" },
183
+ })
184
+ : "No Image Available",
185
+ },
186
+ ],
187
+
188
+ actions: [
189
+ {
190
+ name: "Create New Quiz",
191
+ fields: [
192
+ {
193
+ name: "name",
194
+ label: "Quiz Name",
195
+ type: "string", // for every FormField, type must be specified
196
+ validationSchema: Yup.string().required(),
197
+ },
198
+ {
199
+ name: "questions",
200
+ label: "Questions",
201
+ type: "array",
202
+ element: {
203
+ name: "",
204
+ label: "",
205
+ type: "object",
206
+ fields: [
207
+ {
208
+ name: "text",
209
+ label: "Question Text",
210
+ type: "string",
211
+ validationSchema: Yup.string().required(),
212
+ },
213
+ {
214
+ name: "type",
215
+ label: "Question Type",
216
+ type: "dropdown",
217
+ getOptions: async () => [
218
+ {
219
+ value: "OPEN",
220
+ display: "Open",
221
+ },
222
+ {
223
+ value: "SINGLE",
224
+ display: "Single",
225
+ },
226
+ {
227
+ value: "MULTIPLE",
228
+ display: "Multiple",
229
+ },
230
+ ],
231
+ },
232
+ ],
233
+ },
234
+ },
235
+ ],
236
+ onSubmit: async (formValues: any) => { // onSubmit function can also be complex
237
+ // for actions, onSubmit will always have one param (formValues - you can change the name though)
238
+ // process formVaues as you wish
239
+
240
+ // Nevertheless, submitting the actual data is the most important thing
241
+ const result = await axios.post(domain + "/something", formValues, {
242
+ headers: getAuth(),
243
+ });
244
+
245
+ return result.data;
246
+ }
247
+ },
248
+ ],
249
+
250
+ rowActions: [
251
+ {
252
+ name: "Delete Event - Variant 1", // without form
253
+ onSubmit: async (eventId: number) => { // onSubmit has only param, the row's ID
254
+ const res = await axios.delete(
255
+ domain + "/something/" + eventId
256
+ );
257
+ return res.data;
258
+ },
259
+ },
260
+ {
261
+ name: "Delete Event - Variant 2", // with form
262
+ fields: [
263
+ {
264
+ name: "input",
265
+ label: "Mock Field",
266
+ type: "string",
267
+ validationSchema: "",
268
+ },
269
+ ],
270
+ onSubmit: async (formValues: any, eventId: number) => { // onSubmit has two params
271
+ // the first param - formValues, while the second is the row's ID
272
+ const res = await axios.delete(
273
+ domain + "/something/" + eventId
274
+ );
275
+ return res.data;
276
+ },
277
+ },
278
+ ],
279
+ }
280
+ ```
281
+
282
+ 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 schemas.
283
+
128
284
  #### An array of schemas must be defined as below:
129
285
 
130
286
  ```
@@ -1,6 +1,6 @@
1
- import { PageSchema } from "../schema";
1
+ import { PageSchema } from '../schema';
2
2
  export declare function pageToUrl(page: PageSchema): string;
3
- export declare function AdminPage({ pages, selectedPage, basePath, apiURL }: {
3
+ export declare function AdminPage({ pages, selectedPage, basePath, apiURL, }: {
4
4
  pages: PageSchema[];
5
5
  selectedPage: PageSchema;
6
6
  basePath: string;
@@ -1,22 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
3
- import { ChakraProvider } from "@chakra-ui/react";
4
- import { Button, Modal, ModalHeader, ModalBody, useDisclosure, ModalOverlay, ModalContent, ModalCloseButton, Box, Stack, } from "@chakra-ui/react";
5
- import { GenericForm } from "./GenericForm";
6
- import { ThemeProvider } from "@emotion/react";
7
- import { createTheme } from "@mui/material/styles";
8
- import { MaterialReactTable } from "material-react-table";
9
- import { mkConfig, generateCsv, download } from "export-to-csv";
10
- import Swal from "sweetalert2";
11
- import MenuItem from "@mui/material/MenuItem";
12
- import { io } from "socket.io-client";
13
- import { newSocket } from "../utils/websockets";
2
+ import { useEffect, useState } from 'react';
3
+ import { ChakraProvider } from '@chakra-ui/react';
4
+ import { Button, Modal, ModalHeader, ModalBody, useDisclosure, ModalOverlay, ModalContent, ModalCloseButton, Box, Stack, } from '@chakra-ui/react';
5
+ import { GenericForm } from './GenericForm';
6
+ import { ThemeProvider } from '@emotion/react';
7
+ import { createTheme } from '@mui/material/styles';
8
+ import { MaterialReactTable } from 'material-react-table';
9
+ import { mkConfig, generateCsv, download } from 'export-to-csv';
10
+ import Swal from 'sweetalert2';
11
+ import MenuItem from '@mui/material/MenuItem';
12
+ import { io } from 'socket.io-client';
13
+ import { newSocket } from '../utils/websockets';
14
14
  export function pageToUrl(page) {
15
- return `${page.name.toLowerCase().replace(" ", "_")}`;
15
+ return `${page.name.toLowerCase().replace(' ', '_')}`;
16
16
  }
17
- function Header({ pages, data, basePath, }) {
17
+ function Header({ pages, data, basePath }) {
18
18
  return (_jsx(Box, { background: "blue.50", padding: 1, children: _jsxs(Stack, { margin: 3, direction: "row", justifyContent: "space-between", alignItems: "center", children: [_jsx(Stack, { margin: 4, gap: 10, direction: "row", alignItems: "center", children: pages.map((p) => (_jsx(Box, { as: "a", href: `${basePath}/${pageToUrl(p)}`, children: p.name }))) }), _jsx(Stack, { direction: "row", children: _jsx(Button, { colorScheme: "red", onClick: () => {
19
- const filename = prompt("Enter filename:");
19
+ const filename = prompt('Enter filename:');
20
20
  if (filename)
21
21
  exportToCSV(data, filename);
22
22
  }, children: "Export Data" }) })] }) }));
@@ -25,10 +25,10 @@ function exportToCSV(data, filename) {
25
25
  const formatImageData = (obj) => {
26
26
  const formattedObj = {};
27
27
  for (const key in obj) {
28
- if (typeof obj[key] !== "object") {
28
+ if (typeof obj[key] !== 'object') {
29
29
  formattedObj[key] = obj[key];
30
30
  }
31
- else if (typeof obj[key] === "object" && obj[key] != null) {
31
+ else if (typeof obj[key] === 'object' && obj[key] != null) {
32
32
  Object.keys(obj[key]).forEach((k) => {
33
33
  formattedObj[`${key}.${k}`] = obj[key][k];
34
34
  });
@@ -47,12 +47,12 @@ function exportToCSV(data, filename) {
47
47
  }
48
48
  else {
49
49
  Swal.fire({
50
- title: "Error while exporting CSV!",
51
- text: "There is no data to export.",
50
+ title: 'Error while exporting CSV!',
51
+ text: 'There is no data to export.',
52
52
  });
53
53
  }
54
54
  }
55
- export function AdminPage({ pages, selectedPage, basePath, apiURL = '' }) {
55
+ export function AdminPage({ pages, selectedPage, basePath, apiURL = '', }) {
56
56
  const { isOpen, onOpen, onClose } = useDisclosure();
57
57
  const [selectedAction, setSelectedAction] = useState({});
58
58
  const [data, setData] = useState([]);
@@ -68,10 +68,10 @@ export function AdminPage({ pages, selectedPage, basePath, apiURL = '' }) {
68
68
  });
69
69
  }, [refetch]); // Do not remove 'refetch' from here !!!
70
70
  useEffect(() => {
71
- socket.on("updateData", (message) => {
72
- console.log("Message emitted from socket: " + message);
71
+ socket.on('updateData', (message) => {
72
+ console.log('Message emitted from socket: ' + message);
73
73
  setRefetch(true);
74
- const rowActionsMenu = document.querySelector(".MuiPaper-root.MuiPopover-paper.MuiMenu-paper");
74
+ const rowActionsMenu = document.querySelector('.MuiPaper-root.MuiPopover-paper.MuiMenu-paper');
75
75
  if (rowActionsMenu) {
76
76
  rowActionsMenu.remove();
77
77
  }
@@ -83,7 +83,7 @@ export function AdminPage({ pages, selectedPage, basePath, apiURL = '' }) {
83
83
  return (_jsxs(_Fragment, { children: [_jsx(Header, { pages: pages, data: data, basePath: basePath }), _jsx(ThemeProvider, { theme: createTheme(), children: _jsx(MaterialReactTable, { columns: selectedPage.tableFields.map((field, index) => ({
84
84
  accessorFn: (row) => row[index],
85
85
  header: field.name,
86
- })), data: displayData, muiTableContainerProps: { sx: { maxHeight: "70vh" } }, enableColumnResizing: true, enableColumnPinning: true, enableGlobalFilterModes: true, enablePagination: true, paginationDisplayMode: "pages", enableRowVirtualization: true, rowVirtualizerOptions: { overscan: 20 }, renderTopToolbarCustomActions: () => (_jsx(ChakraProvider, { children: _jsx(Stack, { margin: 0, padding: 3, direction: "row", children: selectedPage.actions.map((action) => (_jsx(Button, { colorScheme: "blue", onClick: () => {
86
+ })), data: displayData, muiTableContainerProps: { sx: { maxHeight: '70vh' } }, enableColumnResizing: true, enableColumnPinning: true, enableGlobalFilterModes: true, enablePagination: true, paginationDisplayMode: "pages", enableRowVirtualization: true, rowVirtualizerOptions: { overscan: 20 }, renderTopToolbarCustomActions: () => (_jsx(ChakraProvider, { children: _jsx(Stack, { margin: 0, padding: 3, direction: "row", children: selectedPage.actions.map((action) => (_jsx(Button, { colorScheme: "blue", onClick: () => {
87
87
  setSelectedAction(action);
88
88
  onOpen();
89
89
  }, children: action.name }))) }) })), enableRowActions: true, renderRowActionMenuItems: (obj) => {
@@ -91,12 +91,12 @@ export function AdminPage({ pages, selectedPage, basePath, apiURL = '' }) {
91
91
  setSelectedAction(rowAction);
92
92
  setRowId(obj.row.original[0]);
93
93
  onOpen();
94
- const rowActionsMenu = document.querySelector(".MuiPaper-root.MuiPopover-paper.MuiMenu-paper");
94
+ const rowActionsMenu = document.querySelector('.MuiPaper-root.MuiPopover-paper.MuiMenu-paper');
95
95
  if (rowActionsMenu) {
96
96
  rowActionsMenu.remove();
97
97
  }
98
- }, children: rowAction.name + " " + obj.row.original[0] })));
99
- } }) }), _jsxs(Modal, { size: "6xl", isOpen: isOpen, onClose: onClose, children: [_jsx(ModalOverlay, {}), _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: selectedAction.name }), _jsx(ModalCloseButton, {}), _jsxs(ModalBody, { children: [selectedAction.fields && selectedAction.fields?.length > 0 ? (_jsx(GenericForm, { action: selectedAction, onClose: onClose, rowId: rowId })) : (_jsx(Button, { colorScheme: "blue", mr: 3, onClick: () => {
98
+ }, children: rowAction.name + ' ' + obj.row.original[0] })));
99
+ } }) }), _jsxs(Modal, { size: '6xl', isOpen: isOpen, onClose: onClose, children: [_jsx(ModalOverlay, {}), _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: selectedAction.name }), _jsx(ModalCloseButton, {}), _jsxs(ModalBody, { children: [selectedAction.fields && selectedAction.fields?.length > 0 ? (_jsx(GenericForm, { action: selectedAction, onClose: onClose, rowId: rowId })) : (_jsx(Button, { colorScheme: "blue", mr: 3, onClick: () => {
100
100
  selectedAction.onSubmit(rowId);
101
101
  onClose();
102
102
  }, children: "Confirm Action" })), _jsx(Button, { colorScheme: "red", mr: 3, onClick: onClose, children: "Close" })] })] })] })] }));
@@ -1,4 +1,4 @@
1
- import { Action, RowAction } from "../schema";
1
+ import { Action, RowAction } from '../schema';
2
2
  interface GenericFormProps {
3
3
  action: Action | RowAction;
4
4
  onClose?: () => void;
@@ -1,41 +1,39 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Box, Button, FormControl, FormErrorMessage, FormLabel, Input, Select, } from "@chakra-ui/react";
3
- import { Field, Form, Formik, FieldArray, getIn } from "formik";
4
- import * as Yup from "yup";
5
- import Swal from "sweetalert2";
6
- import { useEffect, useState } from "react";
2
+ import { Box, Button, FormControl, FormErrorMessage, FormLabel, Input, Select, } from '@chakra-ui/react';
3
+ import { Field, Form, Formik, FieldArray, getIn } from 'formik';
4
+ import * as Yup from 'yup';
5
+ import Swal from 'sweetalert2';
6
+ import { useEffect, useState } from 'react';
7
7
  function parseValidation(fields) {
8
8
  if (!fields) {
9
9
  return {};
10
10
  }
11
11
  return fields.reduce((acc, field) => {
12
- if (field.type !== "dropdown" &&
13
- field.type !== "object" &&
14
- field.type !== "array") {
12
+ if (field.type !== 'dropdown' && field.type !== 'object' && field.type !== 'array') {
15
13
  acc[field.name] = field.validationSchema;
16
14
  }
17
- else if (field.type === "array") {
18
- if (field.element.type === "dropdown") {
15
+ else if (field.type === 'array') {
16
+ if (field.element.type === 'dropdown') {
19
17
  acc[field.name] = Yup.array().of(Yup.string().required());
20
18
  }
21
- else if (field.element.type === "object") {
19
+ else if (field.element.type === 'object') {
22
20
  acc[field.name] = Yup.array().of(Yup.object(parseValidation(field.element.fields)));
23
21
  }
24
22
  else {
25
23
  acc[field.name] = Yup.array().of(field.element.validationSchema);
26
24
  }
27
25
  }
28
- else if (field.type === "object") {
26
+ else if (field.type === 'object') {
29
27
  acc[field.name] = Yup.object(parseValidation(field.fields));
30
28
  }
31
- if (field.type === "dropdown") {
29
+ if (field.type === 'dropdown') {
32
30
  acc[field.name] = Yup.string().required();
33
31
  }
34
32
  return acc;
35
33
  }, {});
36
34
  }
37
35
  function generateSingleField(formfield, fieldName, key) {
38
- return (_jsx(Field, { name: fieldName, children: ({ field, form }) => (_jsxs(FormControl, { isInvalid: getIn(form.touched, fieldName) && getIn(form.errors, fieldName), children: [_jsx(FormLabel, { marginTop: 2, children: formfield.label }), formfield.type === "string" || formfield.type === "number" ? (_jsx(Input, { ...field, type: formfield.type === "number" ? "number" : "text", placeholder: "" })) : formfield.type === "file" ? (_jsx(Input, { type: "file", name: fieldName, onChange: (event) => {
36
+ return (_jsx(Field, { name: fieldName, children: ({ field, form }) => (_jsxs(FormControl, { isInvalid: getIn(form.touched, fieldName) && getIn(form.errors, fieldName), children: [_jsx(FormLabel, { marginTop: 2, children: formfield.label }), formfield.type === 'string' || formfield.type === 'number' ? (_jsx(Input, { ...field, type: formfield.type === 'number' ? 'number' : 'text', placeholder: "" })) : formfield.type === 'file' ? (_jsx(Input, { type: "file", name: fieldName, onChange: (event) => {
39
37
  if (event.currentTarget.files != null) {
40
38
  form.setFieldValue(fieldName, event.currentTarget.files[0]);
41
39
  }
@@ -46,18 +44,18 @@ function parseFields(fields, previous) {
46
44
  return [];
47
45
  }
48
46
  const computedFields = fields.map((formfield, key) => {
49
- let fieldName = previous !== undefined ? previous + "." + formfield.name : formfield.name;
50
- if (formfield.type === "object") {
47
+ const fieldName = previous !== undefined ? previous + '.' + formfield.name : formfield.name;
48
+ if (formfield.type === 'object') {
51
49
  const objectFields = parseFields(formfield.fields, fieldName);
52
50
  return _jsx(FormControl, { children: objectFields }, fieldName);
53
51
  }
54
- else if (formfield.type === "array") {
52
+ else if (formfield.type === 'array') {
55
53
  return (_jsx(FieldArray, { name: fieldName, children: ({ remove, push, form }) => (_jsxs("div", { children: [_jsx(FormLabel, { marginTop: 2, children: formfield.label }), getIn(form.values, fieldName).length > 0 &&
56
- getIn(form.values, fieldName).map((_, index) => (_jsxs(Box, { paddingLeft: 10, children: [_jsx("h4", { children: _jsx("b", { children: `${fieldName}.${index}` }) }), _jsx(Box, { paddingLeft: 10, children: formfield.element.type === "object"
54
+ getIn(form.values, fieldName).map((_, index) => (_jsxs(Box, { paddingLeft: 10, children: [_jsx("h4", { children: _jsx("b", { children: `${fieldName}.${index}` }) }), _jsx(Box, { paddingLeft: 10, children: formfield.element.type === 'object'
57
55
  ? parseFields(formfield.element.fields, `${fieldName}.${index}`)
58
56
  : generateSingleField(formfield.element, `${fieldName}.${index}`, key) }), _jsxs(Button, { type: "button", colorScheme: "red", marginY: 2, onClick: () => remove(index), children: ["Remove ", `${fieldName}.${index}`] })] }))), _jsxs(Button, { type: "button", marginY: 2, colorScheme: "blue", onClick: () => {
59
57
  let value = undefined;
60
- if (formfield.element.type === "object") {
58
+ if (formfield.element.type === 'object') {
61
59
  value = getCustomInitialValues(formfield.element.fields);
62
60
  }
63
61
  else {
@@ -73,18 +71,18 @@ function parseFields(fields, previous) {
73
71
  return computedFields;
74
72
  }
75
73
  function getCustomInitialValues(fields) {
76
- let obj = {};
74
+ const obj = {};
77
75
  if (!fields) {
78
76
  return obj;
79
77
  }
80
78
  fields.forEach((field) => {
81
- if (field.type === "array")
79
+ if (field.type === 'array')
82
80
  obj[field.name] = [];
83
- else if (field.type === "object")
81
+ else if (field.type === 'object')
84
82
  obj[field.name] = getCustomInitialValues(field.fields);
85
- else if (field.type === "string")
86
- obj[field.name] = "";
87
- else if (field.type === "number")
83
+ else if (field.type === 'string')
84
+ obj[field.name] = '';
85
+ else if (field.type === 'number')
88
86
  obj[field.name] = 0;
89
87
  else
90
88
  obj[field.name] = null;
@@ -104,11 +102,11 @@ async function setOptions(fields) {
104
102
  return;
105
103
  }
106
104
  const promises = fields.map(async (field) => {
107
- if (field.type === "dropdown")
105
+ if (field.type === 'dropdown')
108
106
  field.options = await field.getOptions();
109
- else if (field.type === "array")
107
+ else if (field.type === 'array')
110
108
  await setOptions([field.element]);
111
- else if (field.type === "object")
109
+ else if (field.type === 'object')
112
110
  await setOptions(field.fields);
113
111
  });
114
112
  await Promise.all(promises);
@@ -137,14 +135,14 @@ export function GenericForm({ action, onClose, rowId }) {
137
135
  await action.onSubmit(values);
138
136
  if (onClose)
139
137
  onClose();
140
- Swal.fire("Ok");
138
+ Swal.fire('Ok');
141
139
  }
142
140
  catch (e) {
143
141
  if (onClose)
144
142
  onClose();
145
143
  const err = e.request.response;
146
144
  Swal.fire({
147
- text: "Error: " + err,
145
+ text: 'Error: ' + err,
148
146
  });
149
147
  }
150
148
  }, children: ({ isSubmitting }) => (_jsxs(Form, { children: [formFields, _jsx(Button, { mt: 4, colorScheme: "teal", isLoading: isSubmitting, type: "submit", children: "Submit" }), _jsx(Button, { mt: 4, colorScheme: "teal", type: "reset", children: "Initialise Form" })] })) }) }));
@@ -4,4 +4,4 @@ import ReactDOM from 'react-dom/client';
4
4
  import App from './App';
5
5
  import { event } from './testSchemas/event';
6
6
  import './index.css';
7
- ReactDOM.createRoot(document.getElementById('root')).render(_jsx(React.StrictMode, { children: _jsx(App, { pages: [event], basePath: '' }) }));
7
+ ReactDOM.createRoot(document.getElementById('root')).render(_jsx(React.StrictMode, { children: _jsx(App, { pages: [event], basePath: "" }) }));
@@ -6,7 +6,7 @@ export interface TableField {
6
6
  export interface SimpleField {
7
7
  name: string;
8
8
  label: string;
9
- type: "string" | "number" | "file";
9
+ type: 'string' | 'number' | 'file';
10
10
  validationSchema: any;
11
11
  }
12
12
  export interface Option {
@@ -16,20 +16,20 @@ export interface Option {
16
16
  export interface DropdownField {
17
17
  name: string;
18
18
  label: string;
19
- type: "dropdown";
19
+ type: 'dropdown';
20
20
  options?: Option[] | undefined;
21
21
  getOptions: () => Promise<Option[]>;
22
22
  }
23
23
  export interface ObjectField {
24
24
  name: string;
25
25
  label: string;
26
- type: "object";
26
+ type: 'object';
27
27
  fields: FormField[];
28
28
  }
29
29
  export interface ArrayField {
30
30
  name: string;
31
31
  label: string;
32
- type: "array";
32
+ type: 'array';
33
33
  element: Exclude<FormField, ArrayField>;
34
34
  }
35
35
  export type FormField = SimpleField | DropdownField | ObjectField | ArrayField;
@@ -1,9 +1,9 @@
1
- import io from "socket.io-client";
2
- import { useEffect } from "react";
1
+ import io from 'socket.io-client';
2
+ import { useEffect } from 'react';
3
3
  const Socket = (setSocket, apiURL) => {
4
4
  useEffect(() => {
5
5
  const socketRef = io(apiURL, {
6
- transports: ["websocket"],
6
+ transports: ['websocket'],
7
7
  });
8
8
  setSocket(socketRef);
9
9
  return () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "admin_lsac",
3
3
  "private": false,
4
- "version": "1.5.0",
4
+ "version": "2.0.0",
5
5
  "description": "Generic Admin Panel created for storing events' data",
6
6
  "scripts": {
7
7
  "dev": "vite",
package/vite.config.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react-swc'
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react-swc';
3
3
 
4
4
  // https://vitejs.dev/config/
5
5
  export default defineConfig({
6
6
  plugins: [react()],
7
- })
7
+ });